↓ 跳过正文
  1. Posts/

推荐模型不只是一次 Forward:回看排序模型的 Serving 架构

·1572 字·4 分钟

之前在腾讯做过一个面向推荐场景的深度学习框架(内部叫「无量」),我当时负责其中 Serving 相关的工作。后来和朋友聊起,有人问我:把一个推荐模型部署上线,是不是就是加载模型文件,然后来一个请求做一次 forward?

我发现这个问题很难用一句话回答。如果顺着数学公式去理解,推理确实就是一次 forward;但在真实的工程环境里,特别是推荐排序场景下,真实的执行路径要复杂得多。

当时的 embedding 占据了模型的大部分空间,单次请求却只会访问其中少量参数。为了处理这种访问模式,我们引入了远程存储、本地缓存和压缩,forward 之前也就多出了一段参数读取的路径。

一种过度简化的直觉
#

顺着普通的神经网络经验,最自然的 心智模型 可能长这样:

1model weights
2     ↓
3   load
4     ↓
5   input
6     ↓
7  forward
8     ↓
9  output

但这套模型真正在线上跑起来时,实际路径是这样的:

排序模型 Serving 架构

模型参数太大,无法全部按普通 dense model 的方式加载到本地。

巨大的稀疏参数空间与 Sparse Access
#

推荐模型里最占地方的是 embedding,整个 embedding table 往往非常巨大。

但单次请求对 embedding 的访问是稀疏的。

整个 embedding table 虽然很大,但对于某一个特定的请求来说,它真正需要访问的 embedding 只是这片巨大 parameter space 中的极小一部分:

1Huge Embedding Table
2        │
3        │ current request
4        ▼
5     key_17
6     key_42
7     key_891
8     ...

只读取请求用到的 embedding,就不需要在每个 Serving 节点放下整个 embedding table。

在当时的架构里,两类参数采用了不同的处理方式:

  • Sparse Parameters (Embedding):变成了基于 key 的远程数据检索(remote lookup)。
  • Dense Parameters:变成了本地的 TensorFlow 模型推理(local dense computation)。

Remote Lookup 与本地热点缓存
#

当时我们把这部分参数放进远程服务。Serving 会根据请求里的 sparse key,通过 RPC 跨网络从 Ronda Cache 去获取对应的 embedding。

这解决了“放不下”的问题,但跨网络带来了新的麻烦:如果每一个 key 的查询都去跑一次 RPC,请求的 latency、网络带宽消耗以及后端的 backend load 都会爆炸。

推荐流量里有一部分 key 会被频繁重复访问。

于是我们在 embedding lookup 发生前,又垫了一层 Local Hot-Key Cache。

1              ┌── Local Hot-Key Cache
2Embedding Key ┤
3              └── Ronda Cache

命中本地缓存的 key 不需要再发起远程查询,既减少请求等待,也减轻后端负载。

用计算换数据:Embedding 压缩与 On-demand Restore
#

在当时的系统里,我们在 Ronda Cache 存储侧对 Embedding 做了 FP16 和 INT8 压缩。

在这条路径上,压缩收益会体现在参数存储、网络传输和缓存几个环节。

但这种压缩不是免费的。为了让后端的 TensorFlow dense model 继续推理,这些 FP16/INT8 的数据取回来之后,必须恢复成 FP32。这会带来额外的计算开销。

所以真正的执行路径更像是一种 On-demand Restore(按需恢复):

1compressed embedding space
2           ↓
3      lookup required keys
4           ↓
5    obtain required vectors
6           ↓
7 restore these vectors to FP32
8           ↓
9       model computation

因为单个请求只访问极小一部分 keys,系统就只为当前真正被消费的数据支付恢复成本。

省下存储和传输开销之后,请求路径上多了格式转换。转换本身也可能拖慢推理,当时遇到的性能问题记录在 CPU Serving 的压缩优化里。

启动时还要配置线程
#

在我们的架构里,服务层是基于腾讯内部 RPC 框架 tRPC 开发的,启动时会从内部配置中心(七彩石)拉取一套 runtime configuration。

这套配置里,包含了一些直接影响 TensorFlow runtime 执行行为的参数,比如:

  • intra_op_thread_num:控制一个 TensorFlow op 内部执行时可使用的线程并行度。
  • inter_op_thread_num:控制不同、可以独立执行的 TensorFlow ops 之间的并发执行程度。

同一个模型 graph,线程配置不同,op 的并行执行方式也会变化。排查 Serving 耗时时,除了模型本身,还要看这些 runtime 配置。

回到 Serving 的执行路径
#

这套系统里,一次 forward 之前还有 embedding lookup、缓存查询和格式恢复;模型加载之后还有 runtime 的线程配置。只测 TensorFlow graph 的耗时,会漏掉这些开销。

对我来说,回看这套架构最有用的地方,是把每个组件重新放回请求经过的路径上:它持有什么数据,减少了哪一次访问,又把成本转移到了哪里。这样才方便继续判断该优化模型计算,还是参数读取。

相关文章

【推荐系统】Toward the Next Generation of Recommender Systems: A Survey of the State-of-the-Art and Possible Extensions

·1797 字·4 分钟
迫于生计,从今天开始学习推荐系统相关的内容,先来读一篇推荐系统领域的综述 Toward the next generation of recommender systems: a survey of the state-of-the-art and possible extensions 由于目前的工作其实偏向推荐系统的 serving、训练的开发,因此这些 paper 可能都是粗读,也不会把 paper 中的内容逐句翻译,而是找出我认为最为重要的一些概念加以记录。

推荐系统之 LFM (Latent Factor Model) 隐因子模型 学习笔记

起因是被 assign 了一个新的任务……要死。 参考资料: 推荐系统学习笔记之三 LFM (Latent Factor Model) 隐因子模型 + SVD (singular value decomposition) 奇异值分解 基于矩阵分解的隐因子模型 实时推荐系统的三种方式 先说下我的理解。 隐因子模型(LFM)是一种推荐算法,“隐”可以理解成用户喜欢某个 item 的间接原因。

tensorflow input pipline 学习笔记

·2065 字·5 分钟
参考资料: tf_doc_Reading data TENSORFLOW INPUT PIPELINE EXAMPLE tensorflow:理解tensorflow中的输入管道 第二个参考资料是第一个的翻译版本,翻译的水平一般,建议看原文,不是很长。 下面是我挑了文章中重点的部分+自己的理解。 TL;DR; # 一个适用于不是很大的数据集的pipeline input 的例子。

tensorflow 合并模型

·1696 字·4 分钟
在这里存个备份,还有些问题没有解决。 raise ValueError(“GraphDef cannot be larger than 2GB.”) 记录一些思路好了。现在是没有生成.meta文件,爆掉应该是因为所有的变量都加载到了默认图里。 也就是说我处理完checkpoint 0 之后开始处理checkpoint1,但是checkpoint0的那些变量还是存在的…所以越来越多?

tensorflow checkpoint 学习笔记

·513 字·2 分钟
参考资料: What is the TensorFlow checkpoint meta file? TensorFlow: Restoring variables from from multiple checkpoints 合并模型的时候发现.meta一直在累加,而其他数据文件没有改变。因此来探究一下checkpoint的几个文件的含义。 This file contains a serialized MetaGraphDef protocol buffer. The MetaGraphDef is designed as a serialization format that includes all of the information required to restore a training or inference process (including the GraphDef that describes the dataflow, and additional annotations that describe the variables, input pipelines, and other relevant information). For example, the MetaGraphDef is used by TensorFlow Serving to start an inference service based on your trained model. We are investigating other tools that could use the MetaGraphDef for training.