虽然通过批处理管道或流式转换预计算特征在服务延迟和一致性方面提供了显著优势,但在某些情况下,需要正好在请求预测时进行特征计算。这种方法,被称为按需特征计算(有时也称“即时”特征),能提供最高的时效性和情境相关性,但同时也会引入其特有的架构和性能考量。
按需计算不同于标准的特征存储模式,在该模式下,特征会预先计算并存储以便快速获取。相反,特征值是作为推理请求处理循环的一部分动态生成的。这通常涉及调用特定的计算逻辑,该逻辑使用仅在请求时可用的数据,可能还会结合从在线存储或其他低延迟源获取的数据。
何时考虑按需计算
该技术尤其适用于预计算不可行或不理想的特定情况:
- 超动态特征: 反映最新交互或状态的特征,即使是微批流式更新也存在过高的延迟。例如,计算当前会话中“用户上次点击以来的时间”,该时间会随每次交互而变化。
- 请求上下文特定特征: 本质上依赖于传入请求负载细节的计算。示例包括计算用户搜索查询嵌入(来自请求)与候选物品嵌入(可能从在线存储或向量数据库获取)之间的相似度。
- 庞大、稀疏的特征空间: 潜在特征空间庞大,但对于任何单个预测,仅需要很小一部分的情况。为数百万用户和物品预计算所有可能的的用户-物品交互特征,由于存储和计算成本通常不切实际。按需计算只针对当前请求相关的交互。
- 特征开发: 为尝试新的特征想法提供更快的途径,这些想法依赖请求时数据,且无需立即构建可扩展的预计算管道。
- 复杂的关系逻辑: 需要基于请求的特定上下文,对多个实体进行连接或查找的特征,对所有可能性进行预计算可能困难或效率低下。
架构实现
集成按需计算需要仔细考量逻辑所在位置及其数据依赖。
涉及按需特征计算以及从在线存储获取的预计算特征的预测请求数据流。
常见的实现模式包括:
- 嵌入式逻辑: 计算代码(例如,Python函数)直接在模型服务应用进程中运行。这种方式更简单,但会使特征逻辑与服务代码紧密耦合,并随服务实例一同扩展。
- 专用微服务: 计算逻辑封装在独立的微服务中。服务应用向该服务发出网络调用。这促进了解耦和独立扩展,但会增加网络延迟。
- 特征存储钩子(进阶): 某些平台可能允许定义与特征定义关联的函数,这些函数由特征服务层本身执行,但这不那么常见且具有平台特异性。
无论采用何种模式,计算逻辑通常需要访问:
- 来自传入请求负载的数据。
- 实体标识符(例如,
user_id,item_id),以便可能获取基础特征。
- 从在线存储获取的预计算特征。
- 来自外部源(如会话数据库或缓存)的实时上下文。
固有的权衡
选择按需计算需要在其优势和显著缺点之间进行权衡:
优势:
- 最高时效性: 特征反映请求时可用的最新状态。
- 上下文相关性: 支持与特定请求参数紧密关联的特征。
- 减少预计算负担: 避免了对稀疏访问特征可能带来的庞大存储和计算开销。
缺点:
- 增加服务延迟: 这是首要考量。特征计算直接增加了每个预测请求关键路径上的处理时间。毫秒级在在线系统中非常重要。
- 更高的推理成本: 推理端需要更多的计算资源(CPU、内存)。
- 实现复杂性: 在服务路径中管理计算逻辑、其依赖关系和错误处理会增加系统复杂性。
- 一致性挑战(训练/服务偏差): 在历史训练数据生成过程中,复制精确的按需计算逻辑及其所需的实时数据上下文是众所周知的难题。这是潜在在线/离线偏差的主要来源。确保本应涉及按需特征的训练数据集的时间点正确性,需要仔细模拟或记录。
- 调试难题: 按需逻辑中的问题在服务时显现,使得它们比离线管道中的问题更难诊断,离线管道中可以在部署前检查计算值。
确保一致性和性能
缓解这些缺点,尤其是延迟和一致性,非常重要:
- 一致性: 最佳做法是使用完全相同的代码路径(函数或服务)用于在线计算和离线训练数据生成。这通常要求设计计算逻辑使其在离线运行时能接受历史上下文数据。在线服务期间的大量日志记录也可以帮助离线复现计算,如果直接代码重用不可行的话。
- 性能:
- 优化计算: 确保按需逻辑高效运行。分析并优化关键代码路径。
- 缓存: 积极缓存按需计算的结果,尤其是在输入在短时间内可能重复的情况下(例如,按用户会话ID缓存计算出的特征几秒钟或几分钟)。
- 资源配置: 为服务实例或专用计算微服务分配足够的CPU和内存资源。
- 选择性应用: 谨慎使用按需计算,仅适用于收益明显大于延迟和复杂性成本的特征。对于稳定或不常变化的特征,优先选择预计算。
按需特征计算是进阶特征工程工具箱中的强大工具,支持高度相关、实时的特征。然而,必须审慎应用它,并清晰认识其对服务延迟、系统复杂性以及维持训练和服务环境之间一致性的重大挑战。在将其集成到您的特征存储架构之前,请仔细分析权衡。