DSSM:深度结构化语义模型 ======================== 虽然FM在数学上优雅地实现了向量分解,但它本质上仍是线性模型,对于复杂的非线性用户-物品关系表达能力有限。深度结构化语义模型(Deep Structured Semantic Model, DSSM) :cite:`huang2013learning` 的出现,将双塔模型的表达能力推向了新的高度——通过深度神经网络替代线性变换,实现了更强的特征学习和表示能力。其核心思想是通过深度神经网络将用户和物品映射到共同的语义空间中,通过向量间的相似度计算来衡量匹配程度。 .. _dssm_architecture: .. figure:: ../../img/dssm_architecture.svg :width: 300px DSSM双塔架构 推荐中的双塔架构 ---------------- 在推荐系统中,DSSM的架构包括两个核心部分:用户塔和物品塔,每个塔都是独立的DNN结构。用户特征(如历史行为、人口统计学信息等)经过用户塔处理后输出用户Embedding,物品特征(如ID、类别、属性等)经过物品塔处理后输出物品Embedding。两个Embedding的维度必须保持一致,以便进行后续的相似度计算。 相比FM的线性组合,DSSM的深度结构能够使用户侧和物品侧的特征各自在塔内进行复杂的非线性变换,但两塔之间的交互仅在最终的内积计算时发生。这种设计带来了显著的工程优势——物品向量可以离线预计算,用户向量可以实时计算,然后通过高效的ANN检索完成召回。 多分类训练范式 -------------- DSSM将召回任务视为一个极端多分类问题,将物料库中的所有物品看作不同的类别。模型的目标是最大化用户对正样本物品的预测概率: .. math:: P(y|x,\theta) = \frac{e^{s(x,y)}}{\sum_{j\in M}e^{s(x,y_j)}} 这里\ :math:`s(x,y)`\ 表示用户\ :math:`x`\ 和物品\ :math:`y`\ 的相似度分数,\ :math:`P(y|x,\theta)`\ 表示匹配概率,\ :math:`M`\ 表示整个物料库。由于物料库规模庞大,直接计算这个Softmax在计算上不可行,因此实际训练时采用负采样技术,为每个正样本采样一定数量的负样本来近似计算。 双塔模型的细节 -------------- 除了相对简单的模型结构外,双塔模型在实际应用中的一些关键细节同样值得深入探讨。这些细节往往决定了模型的最终效果,:cite:`yi2019sampling` 等研究对此进行了分析。 **向量归一化**\ :对用户塔和物品塔输出的Embedding进行L2归一化: .. math:: u \leftarrow \frac{u}{||u||_2}, \quad v \leftarrow \frac{v}{||v||_2} 归一化的核心作用是解决向量点积的非度量性问题。原始的向量点积不满足三角不等式,可能导致“距离”计算的不一致性。例如,对于三个点\ :math:`A=(10,0)`\ 、\ :math:`B=(0,10)`\ 、\ :math:`C=(11,0)`\ ,使用点积计算会得到\ :math:`\text{dist}(A,B) < \text{dist}(A,C)`\ ,但这与直观的几何距离不符。 通过归一化,向量点积被转化为欧式距离的度量形式。对于归一化向量\ :math:`u`\ 和\ :math:`v`\ ,它们的欧式距离为: .. math:: ||u - v|| = \sqrt{2-2\langle u,v \rangle} 这种转换的关键意义在于\ **训练与检索的一致性**\ :模型训练时使用的相似度计算(归一化后的点积)与线上ANN检索系统使用的距离度量(欧式距离)本质上是等价的。这确保了离线训练学到的向量关系能够在线上检索中得到正确体现,避免了训练-服务不一致的问题。 **温度系数调节**\ :在归一化后的向量计算内积后,除以温度系数\ :math:`\tau`\ : .. math:: s(u,v) = \frac{\langle u,v \rangle}{\tau} 这里的温度系数\ :math:`\tau`\ 看起来是个简单的除法操作,但实际上它对模型的训练效果有着深远的影响。从数学角度来看,温度系数本质上是在缩放logits,进而改变Softmax函数的输出分布形状。当我们设置\ :math:`\tau < 1`\ 时,相似度的差异会被放大,这意味着模型会对高分样本给出更高的概率,预测变得更加“确定”;相反,当\ :math:`\tau > 1`\ 时,分布会变得更加平滑,模型的预测也更加保守。 代码实践 -------- DSSM的实现核心在于构建独立的用户塔和物品塔,每个塔都是一个深度神经网络: .. raw:: latex \diilbookstyleinputcell .. code:: python # 拼接用户侧和物品侧特征 user_feature = concat_group_embedding( group_embedding_feature_dict, "user", axis=1, flatten=True ) # B x (N*D) item_feature = concat_group_embedding( group_embedding_feature_dict, "item", axis=1, flatten=True ) # B x (N*D) # 构建用户塔和物品塔(深度神经网络) user_tower = DNNs( units=dnn_units, activation="tanh", dropout_rate=dropout_rate, use_bn=True )(user_feature) item_tower = DNNs( units=dnn_units, activation="tanh", dropout_rate=dropout_rate, use_bn=True )(item_feature) 关键的向量归一化和相似度计算: .. raw:: latex \diilbookstyleinputcell .. code:: python # L2归一化:确保训练与检索的一致性 user_embedding = tf.keras.layers.Lambda(lambda x: tf.nn.l2_normalize(x, axis=1))( user_tower ) item_embedding = tf.keras.layers.Lambda(lambda x: tf.nn.l2_normalize(x, axis=1))( item_tower ) # 计算余弦相似度(归一化向量的点积) cosine_similarity = tf.keras.layers.Dot(axes=1)([user_embedding, item_embedding]) 这种设计使得用户和物品的表示完全独立,支持离线预计算物品向量并存储在ANN索引中,实现毫秒级的召回响应。 下面训练DSSM并评估召回效果。 .. raw:: latex \diilbookstyleinputcell .. code:: python from funrec import run_experiment run_experiment('dssm')