- 作者:韩信子 @ShowMeAI,Joan@腾讯
- 地址:http://www.showmeai.tech/arti…
- 申明:版权所有,转载请分割平台与作者并注明出处
双塔模型是举荐、搜寻、广告等多个畛域的算法实现中最罕用和经典的构造,理论各公司利用时,双塔构造中的每个塔会做构造降级,用 CTR 预估中的新网络结构代替全连贯 DNN,本期看到的是腾讯浏览器团队的举荐场景下,奇妙并联 CTR 模型利用于双塔的计划。
一图读懂全文
实现代码
文中波及到的 DCN / FM / DeepFM / FFM / CIN(xDeepFM) 等 CTR 预估办法实现,请返回 GitHub 进行查看:https://github.com/ShowMeAI-H…
论文下载 & 数据集下载
相干数据请在公众号(AI 算法研究所)回复 『举荐与 CTR 数据集』,获取下载链接。
CTR 预估中的多任务多指标建模的大厂技术实现,欢送查看同系列相干文章
- 《多指标优化及利用(含代码实现)》 http://www.showmeai.tech/arti…
- 《爱奇艺短视频举荐业务中的多指标优化实际》 http://www.showmeai.tech/arti…
一、双塔模型构造
1.1 模型构造介绍
双塔模型广泛应用于举荐、搜寻、广告等多个畛域的召回和排序阶段,模型构造如下所示:
双塔模型构造中,左侧是 User 塔,右侧是 Item 塔,对应的,咱们也能够将特色拆分为两大类:
- User 相干特色 :用户根本信息、群体统计属性以及交互过的 Item 序列等;
- Item 相干特色 :Item 根本信息、属性信息等。
如果有上下文特色(Context feature)能够放入用户侧塔。
最后版本的构造中,这两个塔两头都是经典的 DNN 模型(即全连接结构),从特色 Embedding 通过若干层 MLP 隐层,两个塔别离输入 User Embedding 和 Item Embedding 编码。
在训练过程中,User Embedding 和 Item Embedding 做内积或者 Cosine 类似度计算,使得以后 User 和正例 Item 在 Embedding 空间更靠近,和负例 Item 在 Embedding 空间间隔拉远。损失函数则可用规范穿插熵损失(将问题当作一个分类问题),或者采纳 BPR 或者 Hinge Loss(将问题当作一个示意学习问题)。
1.2 双塔模型优缺点
双塔模型 长处 很显著:
- 构造清晰。别离对 User 和 Item 建模学习之后,再交互实现预估
- 训练实现之后,线上 inference 过程高效,性能优良。在线 serving 阶段,Item 向量是事后计算好的,可依据变动特色计算一次 User 向量,再计算内积或者 cosine 即可。
双塔模型也存在 毛病 :
- 原始的双塔模型构造,特色受限,无奈应用穿插特色。
- 模型结构限制下,User 和 Item 是离开构建,只能通过最初的内积来交互,不利于 User-Item 交互的学习。
1.3 双塔模型的优化
腾讯信息流团队(QQ 浏览器小说举荐场景) 基于以上限度对双塔模型构造进行优化,加强模型构造与成果上,获得了不错的收益,具体做法为:
- 把双塔构造中的 DNN 简略构造,替换无效 CTR 模块(MLP、DCN、FM、FFM、CIN)的"并联"构造,充分利用不同构造的特色穿插劣势,拓宽模型的"宽度"来缓解双塔内积的瓶颈;
- 应用 LR 学习"并联"的多个双塔的权重,LR 权重最终融入到 User Embedding 中,使得最终的模型依然放弃的内积模式。
二、并联双塔模型构造
并联的双塔模型能够分总分为三层: 输出层、表示层和匹配层 。对应图中的 3 个档次,别离的解决和操作如下。
2.1 输出层(Input Layer)
腾讯 QQ 浏览器小说场景下有以下两大类特色:
- User 特色 :用户 id、用户画像(年龄、性别、城市)、行为序列(点击、浏览、珍藏)、内部行为(浏览器资讯、腾讯视频等);
- Item 特色 :小说内容特色(小说 id、分类、标签等)、统计类特色等;
将 User 和 Item 特色都通过离散化后映射成 Feature Embedding,不便在表示层进行网络构建。
2.2 表示层(Representation Layer)
- 对输出利用深度神经网络 CTR 模块(MLP、DCN、FM、CIN 等)进行学习,不同的模块能够以不同形式学习输出层 feature 的交融和交互。
- 对不同模块学习的表征,构建并联构造用于匹配层计算。
- 表示层的 User-User 和 Item-Item 的特色交互(塔内信息穿插)在本塔分支就能够做到,而 User-Item 的特色交互只能通过下层操作实现。
2.3 匹配层(Matching Layer)
- 将表示层失去的 User 和 Item 向量,依照不同并联模型别离进行 hadamard 积,拼接后再通过 LR 进行后果交融计算最初 score。
- 在线 serving 阶段 LR 的每一维的权重可事后交融到 User Embedding 里,从而放弃在线打分依然是内积操作。
三、双塔的表示层构造 -MLP/DCN 构造
双塔内个别都会应用 MLP 构造(多层全连贯),腾讯 QQ 浏览器团队还引入了 DCN 中的 Cross Network 构造用于显式的结构高阶特色交互,参考的构造是 Google 论文改进版 DCN-Mix。
3.1 DCN 构造
DCN 的特点是引入 Cross Network 这种穿插网络结构,提取穿插组合特色,防止传统机器学习中的人工手造特色的过程,网络结构简略复杂度可控,随深度减少取得多阶穿插特色。
DCN 模型具体构造如上图:
- 底层是 Embedding layer 并对 Embedding 做了 stack。
- 下层是并行的 Cross Network 和 Deep Network。
- 头部是 Combination Layer 把 Cross Network 和 Deep Network 的后果 stack 失去 Output。
3.2 优化的 DCN-V2 构造引入
Google 在 DCN 的根底上提出改进版 DCN-Mix/DCN-V2,针对 Cross Network 进行了改良,咱们次要关注 Cross Network 的计算形式变更:
3.2.1 原始 Cross Network 计算形式
原始计算公式下,通过多层计算,能够显式地学习到高维的特色交互,存在的问题是被证实最终的 $k$ 阶交互后果 $x_{k}$ 等于 $x_{0}$ 和一个标量的乘积(但不同的 $x_{0}$ 这个标量不同,$x_{0}$ 和 $x_{k}$ 并不是线性关系),这个计算形式下 Cross Network 的表白受限。
3.2.2 改进版 Cross Network 计算形式
Google 改进版的 DCN-Mix 做的解决如下:
- W 由向量变更为矩阵,更大的参数量带来了更强的表达能力(理论 W 矩阵也能够进行矩阵合成)。
- 变更特色交互方式:不再应用外积,利用哈达玛积 (Hadamard product)。
3.2.3 DCN-V2 代码参考
DCN-v2 的代码实现和 ctr 利用案例能够参考 Google 官网实现 (https://github.com/tensorflow…)
其中外围的改良后的 deep cross layer 代码如下:
class Cross(tf.keras.layers.Layer):
"""Cross Layer in Deep & Cross Network to learn explicit feature interactions.
A layer that creates explicit and bounded-degree feature interactions
efficiently. The `call` method accepts `inputs` as a tuple of size 2
tensors. The first input `x0` is the base layer that contains the original
features (usually the embedding layer); the second input `xi` is the output
of the previous `Cross` layer in the stack, i.e., the i-th `Cross`
layer. For the first `Cross` layer in the stack, x0 = xi.
The output is x_{i+1} = x0 .* (W * xi + bias + diag_scale * xi) + xi,
where .* designates elementwise multiplication, W could be a full-rank
matrix, or a low-rank matrix U*V to reduce the computational cost, and
diag_scale increases the diagonal of W to improve training stability (especially for the low-rank case).
References:
1. [R. Wang et al.](https://arxiv.org/pdf/2008.13535.pdf)
See Eq. (1) for full-rank and Eq. (2) for low-rank version.
2. [R. Wang et al.](https://arxiv.org/pdf/1708.05123.pdf)
Example:
# python
# after embedding layer in a functional model:
input = tf.keras.Input(shape=(None,), name='index', dtype=tf.int64)
x0 = tf.keras.layers.Embedding(input_dim=32, output_dim=6)
x1 = Cross()(x0, x0)
x2 = Cross()(x0, x1)
logits = tf.keras.layers.Dense(units=10)(x2)
model = tf.keras.Model(input, logits)
Args:
projection_dim: project dimension to reduce the computational cost.
Default is `None` such that a full (`input_dim` by `input_dim`) matrix
W is used. If enabled, a low-rank matrix W = U*V will be used, where U
is of size `input_dim` by `projection_dim` and V is of size
`projection_dim` by `input_dim`. `projection_dim` need to be smaller
than `input_dim`/2 to improve the model efficiency. In practice, we've
observed that `projection_dim` = d/4 consistently preserved the
accuracy of a full-rank version.
diag_scale: a non-negative float used to increase the diagonal of the
kernel W by `diag_scale`, that is, W + diag_scale * I, where I is an
identity matrix.
use_bias: whether to add a bias term for this layer. If set to False,
no bias term will be used.
kernel_initializer: Initializer to use on the kernel matrix.
bias_initializer: Initializer to use on the bias vector.
kernel_regularizer: Regularizer to use on the kernel matrix.
bias_regularizer: Regularizer to use on bias vector.
Input shape: A tuple of 2 (batch_size, `input_dim`) dimensional inputs.
Output shape: A single (batch_size, `input_dim`) dimensional output.
"""
def __init__(
self,
projection_dim: Optional[int] = None,
diag_scale: Optional[float] = 0.0,
use_bias: bool = True,
kernel_initializer: Union[Text, tf.keras.initializers.Initializer] = "truncated_normal",
bias_initializer: Union[Text,
tf.keras.initializers.Initializer] = "zeros",
kernel_regularizer: Union[Text, None,
tf.keras.regularizers.Regularizer] = None,
bias_regularizer: Union[Text, None,
tf.keras.regularizers.Regularizer] = None,
**kwargs):
super(Cross, self).__init__(**kwargs)
self._projection_dim = projection_dim
self._diag_scale = diag_scale
self._use_bias = use_bias
self._kernel_initializer = tf.keras.initializers.get(kernel_initializer)
self._bias_initializer = tf.keras.initializers.get(bias_initializer)
self._kernel_regularizer = tf.keras.regularizers.get(kernel_regularizer)
self._bias_regularizer = tf.keras.regularizers.get(bias_regularizer)
self._input_dim = None
self._supports_masking = True
if self._diag_scale < 0:
raise ValueError("`diag_scale` should be non-negative. Got `diag_scale` = {}".format(self._diag_scale))
def build(self, input_shape):
last_dim = input_shape[-1]
if self._projection_dim is None:
self._dense = tf.keras.layers.Dense(
last_dim,
kernel_initializer=self._kernel_initializer,
bias_initializer=self._bias_initializer,
kernel_regularizer=self._kernel_regularizer,
bias_regularizer=self._bias_regularizer,
use_bias=self._use_bias,
)
else:
self._dense_u = tf.keras.layers.Dense(
self._projection_dim,
kernel_initializer=self._kernel_initializer,
kernel_regularizer=self._kernel_regularizer,
use_bias=False,
)
self._dense_v = tf.keras.layers.Dense(
last_dim,
kernel_initializer=self._kernel_initializer,
bias_initializer=self._bias_initializer,
kernel_regularizer=self._kernel_regularizer,
bias_regularizer=self._bias_regularizer,
use_bias=self._use_bias,
)
self.built = True
def call(self, x0: tf.Tensor, x: Optional[tf.Tensor] = None) -> tf.Tensor:
"""Computes the feature cross.
Args:
x0: The input tensor
x: Optional second input tensor. If provided, the layer will compute
crosses between x0 and x; if not provided, the layer will compute
crosses between x0 and itself.
Returns:
Tensor of crosses.
"""
if not self.built:
self.build(x0.shape)
if x is None:
x = x0
if x0.shape[-1] != x.shape[-1]:
raise ValueError("`x0` and `x` dimension mismatch! Got `x0` dimension {}, and x"
"dimension {}. This case is not supported yet.".format(x0.shape[-1], x.shape[-1]))
if self._projection_dim is None:
prod_output = self._dense(x)
else:
prod_output = self._dense_v(self._dense_u(x))
if self._diag_scale:
prod_output = prod_output + self._diag_scale * x
return x0 * prod_output + x
def get_config(self):
config = {
"projection_dim":
self._projection_dim,
"diag_scale":
self._diag_scale,
"use_bias":
self._use_bias,
"kernel_initializer":
tf.keras.initializers.serialize(self._kernel_initializer),
"bias_initializer":
tf.keras.initializers.serialize(self._bias_initializer),
"kernel_regularizer":
tf.keras.regularizers.serialize(self._kernel_regularizer),
"bias_regularizer":
tf.keras.regularizers.serialize(self._bias_regularizer),
}
base_config = super(Cross, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
四、双塔的表示层构造 – FM/FFM/CIN 构造
另一类在 CTR 预估中罕用的构造是 FM 系列的构造,典型的模型包含 FM、FFM、DeepFM、xDeepFM,他们非凡的建模形式也能开掘无效的信息,腾讯 QQ 浏览器团队的最终模型上,也应用了上述模型的子结构。
上文提到的 MLP 和 DCN 的特色交互穿插,无奈显式指定某些特色交互,而 FM 系列模型中的 FM / FFM / CIN 构造能够对特色粒度的交互做显式操作,且从计算公式上看,它们都具备很好的内积模式,从能不便间接地实现双塔建模 User-Item 的特色粒度的交互。
4.1 FM 构造引入
$$
y = \omega_{0}+\sum_{i=1}^{n} \omega_{i} x_{i}+\sum_{i=1}^{n-1} \sum_{j=i+1}^{n}<v_{i}, v_{j}>x_{i} x_{j}
$$
FM 是 CTR 预估中最常见的模型构造,它通过矩阵合成的办法构建特色的二阶交互,计算公式上体现为特征向量 \(v_{i} \) 和 \(v_{j} \) 的两两内积操作再求和(在深度学习里能够看做特色 Embedding 的组对内积),通过内积运算分配率能够转换成求和再内积的模式。
$$
\begin{array}{c}
y=\sum_{i} \sum_{j}\left\langle V_{i}, V_{j}\right\rangle=\left\langle\sum_{i} V_{i}, \sum_{j} V_{j}\right\rangle \\
i \in \text {user fea,} \quad j \in \text {item fea}
\end{array}
$$
在腾讯 QQ 浏览器团队小说举荐场景中,只思考 User-Item 的交互(因为 User 外部或者 Item 外部的特色二阶交互上文提到的模型已捕捉到),如上公式所示,\(i \)$$ 是 User 侧的特色,\(j \) 是 Item 侧的特色,通过内积计算分配率的转换,User-Item 的二阶特色交互也能够转化为 User、Item 特征向量先求和(神经网络中体现为 sum pooling)再做内积,很不便能够转为双塔构造解决。
4.2 FFM 构造引入
FFM 模型是 FM 的降级版本,相比 FM,它多了 field 的概念,FFM 把雷同性质的特色归于同一个 field,构建的隐向量不仅与特色相干,也与 field 相干,最终的特色交互能够在不同的隐向量空间,进而晋升辨别能力增强成果,FFM 也能够通过一些办法转换成双塔内积的构造。
$$
y(\mathbf{x})=w_{0}+\sum_{i=1}^{n} w_{i} x_{i}+\sum_{i=1}^{n} \sum_{j=i+1}^{n}\left\langle\mathbf{v}_{i f_{j}}, \mathbf{v}_{j f_{i}}\right\rangle x_{i} x_{j}
$$
一个转换的例子如下:
img10.png
User 有 2 个特色 field、Item 有 3 个特色 field,图中任意 2 个特色交互都有独立的 Embedding 向量。依据 FFM 公式,计算 User-Item 的二阶交互,须要将所有的内积计算出来并求和。
img11.png
咱们将 User、Item 的特色 Embedding 做从新排序,再进行拼接,能够把 FFM 也转换成双塔内积模式。FFM 内的 User-User 和 Item-Item 都在塔内,所以咱们可事后算好放入一阶项里。
img12.png
腾讯 QQ 浏览器团队实际利用中发现:利用 FFM 的双塔,训练数据上 AUC 晋升显著,但参数量的减少带来了重大的过拟合,且上述结构调整后双塔的宽度极宽(可能达到万级别),对性能效率影响较大,进一步尝试的优化形式如下:
- 人工筛选参加 FFM 训练特色交互的 User 和 Item 特色 field,管制双塔宽度(1000 左右)。
- 调整 FFM 的 Embedding 参数初始化形式(靠近 0)及学习率(升高)。
最终成果不是很现实,因而团队理论线上并未应用 FFM。
4.3 CIN 构造引入
后面提到的 FM 和 FFM 能实现二阶特色交互,而 xDeepFM 模型中提出的 CIN 构造能够实现更高阶的特色交互(比方 User-User-Item、User-User-Item-Item、User-Item-Item 等 3 阶),腾讯 QQ 浏览器团队尝试了两种用法把 CIN 利用在双塔构造中:
4.3.1 CIN(User) * CIN(Item)
双塔每个塔内生成 User、Item 的本身多阶 CIN 后果,再别离 sum pooling 生成 User/Item 向量,而后 User 与 Item 向量内积
依据分配率,咱们对 sum pooling 再内积的公式进行拆解,会发现这个计算形式外部其实曾经实现了 User-Item 的多阶交互:
$$
\begin{array}{c}
\left(U^{1}+U^{2}+U^{3}\right) *\left(I^{1}+I^{2}+I^{3}\right) \\
U^{1} I^{1}+U^{1} I^{2}+U^{1} I^{3}+U^{2} I^{1}+U^{2} I^{2}+U^{2} I^{3}+U^{3} I^{1}+U^{3} I^{2}+U^{3} I^{3}
\end{array}
$$
这个用法实现过程也比较简单,针对双塔构造,在两侧塔内做 CIN 生成各阶后果,再对后果做 sumpooling,最初相似 FM 原理通过内积实现 User-Item 的各阶交互。
这个解决形式有肯定的毛病:生成的 User-Item 二阶及以上的特色交互,有着和 FM 相似的局限性(例 U1 是由 User 侧提供的多个特色 sumpooling 所得后果,U1 与 Item 侧的后果内积计算,受限于 sum pooling 的计算,每个 User 特色在这里重要度就变成一样的了)。
4.3.2 CIN(CIN(User),CIN(Item) )
第 2 种解决形式是:双塔每侧塔内生成 User、Item 的多阶 CIN 后果后,对 User、Item 的 CIN 后果再次两两应用 CIN 显式交互(而非 sum pooling 后计算内积),并转成双塔内积,如下图所示:
下图为 CIN 计算的公式示意,多个卷积后果做 sum pooling 后模式放弃不变(两两 hadamard 积加权求和)
CIN 的模式和 FFM 相似,同样能够通过 『重新排列 + 拼接』 操作转换成双塔内积模式,生成的双塔宽度也十分大(万级别),但与 FFM 不同的是:CIN 的所有特色交互,底层应用的 feature Embedding 是共享的,而 FFM 对每个二阶交互都有独立的 Embedding。因而腾讯 QQ 浏览器团队的实际尝试中根本没有呈现过拟合问题,试验成果上第②种形式第①种用法略好。
五、腾讯业务成果
以下为腾讯 QQ 浏览器小说举荐业务上的办法试验成果(比照各种单 CTR 模型和并联双塔构造):
5.1 团队给出的一些剖析如下
- CIN2 在单构造的双塔模型中的成果是最好的,其次是 DCN 和 CIN1 的双塔构造;
- 并联的双塔构造相比于繁多的双塔构造在成果上也有显著晋升;
- 并联计划二应用了 CIN2 的构造,双塔宽度达到了 2 万 +,对线上 serving 的性能有肯定的挑战,综合思考成果和部署效率能够抉择并联双塔计划一。
5.2 团队给出的一些训练细节和教训
- 思考到 FM/FFM/CIN 等构造的计算复杂度,都只在精选特色子集下面训练,选取维度更高的 category 特色为主,比方用户 id、行为历史 id、小说 id、标签 id 等,还有大量统计特色,User 侧、Item 侧大略各选了不到 20 个特色 field;
- 并联的各双塔构造,各模型不共享底层 feature Embedding,别离训练本人的 Embedding;
- feature Embedding 维度抉择,MLP/DCN 对 category 特色维度为 16,非 category 特色维度是 32
- FM/FFM/CIN 的 feature Embedding 维度对立为 32。
六、腾讯团队试验成果
在小说举荐场景的粗排阶段上线了 A/B Test 试验,实验组的点击率、浏览转化率模型应用了『并联双塔计划一』,对照组为『MLP 双塔模型』,如下图所示,有显著的业务指标晋升:
- 点击率 +6.8752%
- 浏览转化率 +6.2250%
- 加书转化率 +6.5775%
- 浏览时长 +3.3796%
七、相干代码实现参考
实现代码
文中波及到的 DCN / FM / DeepFM / FFM / CIN(xDeepFM) 等 CTR 预估办法实现 ,请返回 GitHub 进行查看:https://github.com/ShowMeAI-H…
论文下载 & 数据集下载
相干数据请在公众号(AI 算法研究所)回复 『举荐与 CTR 数据集』,获取下载链接。
八、参考文献
- [1] Huang, Po-Sen, et al. “Learning deep structured semantic models for web search using clickthrough data.” Proceedings of the 22nd ACM international conference on Information & Knowledge Management. 2013.
- [2] S. Rendle,“Factorization machines,”in Proceedings of IEEE International Conference on Data Mining (ICDM), pp. 995–1000, 2010.
- [3] Yuchin Juan, et al. “Field-aware Factorization Machines for CTR Prediction.” Proceedings of the 10th ACM Conference on Recommender SystemsSeptember 2016 Pages 43–
- [4] Jianxun Lian, et al. “xDeepFM: Combining Explicit and Implicit Feature Interactions for Recommender Systems” Proceedings of the 24th ACM SIGKDD International Conference on Knowledge Discovery & Data MiningJuly 2018 Pages 1754–1763
- [5] Ruoxi Wang, et al. “Deep & Cross Network for Ad Click Predictions” Proceedings of the ADKDD’17August 2017 Article No.: 12Pages 1–
- [6] Wang, Ruoxi, et al. “DCN V2: Improved Deep & Cross Network and Practical Lessons for Webscale Learning to Rank Systems” In Proceedings of the Web Conference 2021 (WWW ’21); doi:10.1145/3442381.3450078
材料下载
实现代码
文中波及到的 DCN / FM / DeepFM / FFM / CIN(xDeepFM) 等 CTR 预估办法实现,请返回 GitHub 进行查看:https://github.com/ShowMeAI-H…
论文下载 & 数据集下载
相干数据请在公众号(AI 算法研究所)回复『举荐与 CTR 数据集』,获取下载链接。
CTR 预估中的多任务多指标建模的大厂技术实现,欢送查看同系列相干文章:
- 《多指标优化及利用(含代码实现)》http://www.showmeai.tech/arti…
- 《爱奇艺短视频举荐业务中的多指标优化实际》http://www.showmeai.tech/arti…