Wide & Deep:记忆能力与泛化能力的联合训练

FreeGuideOnline 最新 2026-06-23

Wide & Deep 模型:记忆与泛化的协同学习

在现代推荐系统与搜索排序场景中,模型通常需要同时具备两种关键能力:记忆能力泛化能力。记忆能力让模型记住历史数据中频繁出现的特征组合,直接利用已有知识;泛化能力则使模型能够推断出从未见过的特征组合,发现新的行为模式。Wide & Deep 模型由 Google 于 2016 年提出,其核心思想正是将擅长记忆的线性模型(Wide 部分)与擅长泛化的深度神经网络(Deep 部分)进行联合训练,在同一个框架内平衡两者优势,从而实现比单一模型更优的预测效果。


1. 为什么需要记忆与泛化

在进入模型结构之前,我们需要先理解记忆与泛化在实际应用中的含义。

  • 记忆能力
    指的是直接利用历史数据中强关联规则的能力。例如,如果用户安装了应用 A,并且历史数据表明“安装应用 A”和“安装应用 B”高度共现,那么模型应该“记住”这一规则:当用户安装应用 A 时,直接推荐应用 B。这类规则往往是稀疏且高价值的特征组合,传统逻辑回归或宽线性模型非常擅长捕捉。

  • 泛化能力
    指的是从大量特征中学习到低维稠密表示,并将这种表示迁移到未见过的特征组合上去。例如,通过用户人口属性、历史行为序列等学习到一个用户偏好向量,即使该用户从未接触过某个应用,模型也能基于用户和应用的嵌入相似度给出合理推荐。深度神经网络是泛化的天然工具。

单独使用宽线性模型,泛化不足,容易过拟合稀有特征;单独使用深度模型,可能对某些强规则记忆不充分,导致过度泛化而给出不靠谱的推荐。Wide & Deep 模型正是要将两个模块结合到一个端到端的训练过程中。


2. 模型架构总览

Wide & Deep 的整体架构如下图所示(用文字描述其结构):

原始特征
   ├── 交叉特征(如组合特征交叉积) ────────────────► Wide 部分(线性模型)
   │
   └── 稀疏特征(类别特征等)→ 嵌入层 → 拼接 → 隐藏层 → Deep 部分(DNN)
                              │
                              └─────────────► 联合输出层(Sigmoid)

最终预测由 Wide 和 Deep 两部分的结果相加后通过激活函数得到。

Wide 部分形式上可以看作一个广义线性模型:

[ y_{wide} = w^T x + b ]

Deep 部分是一个前馈神经网络,最后一层的输出为 (a^{(l_f)})。

最终的联合预测为:

[ P(Y=1|\mathbf{x}) = \sigma( w_{wide}^T [x, \phi(x)] + w_{deep}^T a^{(l_f)} + b ) ]

其中 (\phi(x)) 表示原始特征的交叉积变换(交叉特征),(a^{(l_f)}) 是 Deep 部分最后一层的激活值,(\sigma) 是 Sigmoid 函数。所有参数联合训练,优化同一目标函数。


3. Wide 部分:记忆的引擎

3.1 线性模型基础

Wide 部分本质上是一个广义线性模型,输入包括原始特征以及人工设计的特征交叉。交叉特征用于捕捉特征间的交互,尤其适合记忆那些低频但决定性的组合。

3.2 交叉积变换

交叉积变换(Cross-Product Transformation)将两个或多个类别特征组合成新的二进制特征:

[ \phi_k(\mathbf{x}) = \prod_{i=1}^{d} x_i^{c_{ki}}, \quad c_{ki} \in {0, 1} ]

例如,特征“用户所在城市=北京”与“当前时间=深夜”的交叉积,只有在两个条件同时成立时该特征才为 1。这能直接记住“北京深夜”场景下的特定行为模式。

在实现时,通常使用 tf.feature_column.crossed_column 来构建这类组合特征。Wide 部分使用 FTRL(Follow-the-Regularized-Leader)优化器加上 L1 正则化,可以产生稀疏解,自动剔除无用的交叉特征,保证记忆的高效性。


4. Deep 部分:泛化的引擎

4.1 嵌入层

Deep 部分接收的通常是高维稀疏的类别特征(如用户 ID、物品 ID、标签等)。首先通过嵌入层将每个稀疏特征映射为一个低维稠密向量。例如:

  • 用户 ID 特征,词汇量 1,000,000,嵌入维度 32 → 得到长度为 32 的向量。
  • 物品分类特征,词汇量 1,000,嵌入维度 8 → 得到长度为 8 的向量。

这些嵌入向量被拼接(concatenate)成一个长向量,作为后续隐藏层的输入。

4.2 深层前馈网络

拼接后的向量被送入多个全连接层,每层通常使用 ReLU 作为激活函数:

[ a^{(l+1)} = f(W^{(l)} a^{(l)} + b^{(l)}) ]

层数和每层神经元个数是超参数,可根据数据规模调整。更深的结构有助于捕捉特征间复杂、非线性的高阶交互,从而获得泛化能力。

4.3 避免过拟合

Deep 部分容易过拟合,尤其是在样本量不足以支撑深层网络时。常用策略包括:

  • Dropout
  • L2 正则化
  • Batch Normalization
  • 早停(Early Stopping)

这些技巧可帮助模型在训练时稳定收敛并提升泛化效果。


5. 联合训练:端到端的协同

5.1 联合训练与集成学习的区别

需要特别注意,Wide & Deep 是联合训练而非集成学习。集成学习中,各个模型独立训练,最后在推理时融合预测结果。而联合训练中,Wide 和 Deep 部分的参数是同时优化一个统一的损失函数,误差会反向传播到两个部分各自的参数上。这允许 Deep 部分在学习泛化表示时,能够“感知”到 Wide 部分已经记忆的规则,从而进行自适应调整;反之亦然。

5.2 预测与损失函数

最终的预测值由两部分相加后经过 Sigmoid 得到,适用于二分类任务(如点击率预估)。损失函数通常为对数损失(二元交叉熵):

[ \mathcal{L} = -\frac{1}{N}\sum_{i=1}^{N} [y_i \log(\hat{y}_i) + (1-y_i) \log(1-\hat{y}_i)] ]

其中 (\hat{y}_i) 是模型输出的预测概率。

5.3 优化器选择

  • Wide 部分:通常采用 FTRL 结合 L1 正则化,以保持稀疏性和较好的记忆能力。
  • Deep 部分:常使用 AdaGrad、Adam 等自适应学习率优化器,确保深度模型稳定且较快的收敛。

在 TensorFlow 中,可以利用 tf.estimator.DNNLinearCombinedClassifier 直接搭建 Wide & Deep 联合模型,并分别指定两个部分的优化器。


6. 实践中的设计要点

6.1 特征选择与交叉

  • Wide 特征:选择那些业务含义明确、强耦合的特征进行交叉,如“用户已安装应用” × “当前展示应用类别”。避免盲目全量交叉,可能导致特征爆炸。
  • Deep 特征:主要使用类别特征和高基数特征,通过嵌入学习连续表示。连续特征可以经过分桶后作为类别特征输入,也可以直接作为数值特征输入 DNN(需归一化)。

6.2 嵌入维度设定

嵌入维度的选择需要平衡信息编码能力和计算开销。经验规则:

[ \text{嵌入维度} \approx \sqrt[4]{ \text{词汇量大小} } ]

但实际应用中,维度在 8 到 128 之间较常见,可根据验证集效果微调。

6.3 冷启动与实时更新

Wide 部分的记忆能力对冷启动有一定帮助:新上架的物品若与某些强特征关联,Wide 部分可以通过交叉特征直接给出保守预测。但深度模型的嵌入学习需要足够的样本。工业实践中通常配合在线学习或增量更新,不断刷新 Wide 部分的交叉权重和 Deep 部分的嵌入向量。


7. 代码示意(简化版)

以下使用 TensorFlow 2.x 的 Keras 风格,示意如何构建 Wide & Deep 模型:

import tensorflow as tf

# 输入定义
wide_input = tf.keras.layers.Input(shape=(num_wide_features,), name='wide_input')
deep_input = tf.keras.layers.Input(shape=(num_deep_categorical_features,), name='deep_input')

# Deep 部分:嵌入层 + flatten + 隐藏层
embedding_layers = []
for i, vocab_size in enumerate(deep_feature_vocab_sizes):
    embedding = tf.keras.layers.Embedding(input_dim=vocab_size, output_dim=embed_dim)(deep_input[:, i])
    embedding_layers.append(embedding)

deep_stack = tf.keras.layers.Concatenate()(embedding_layers)
deep_flatten = tf.keras.layers.Flatten()(deep_stack)

for units in [256, 128, 64]:
    deep_flatten = tf.keras.layers.Dense(units, activation='relu')(deep_flatten)

# Wide 部分:线性层(直接连接 wide_input)
wide_output = tf.keras.layers.Dense(1)(wide_input)

# 联合
deep_output = tf.keras.layers.Dense(1)(deep_flatten)
merged = tf.keras.layers.Add()([wide_output, deep_output])
output = tf.keras.layers.Activation('sigmoid')(merged)

model = tf.keras.Model(inputs=[wide_input, deep_input], outputs=output)

model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

在真实项目中,需将数据预处理为 Wide 部分(已经交叉特征化)和 Deep 部分(类别特征下标)分别输入。


8. 优势与应用场景

Wide & Deep 模型问世后迅速成为点击率预估、应用推荐、搜索排序等场景的基准模型。其优势可以总结为:

  • 平衡记忆与泛化:既不会忘记强规则,又能探索长尾需求。
  • 端到端训练:结构清晰,易于工程化部署。
  • 可解释性兼顾:Wide 部分的权重可直接反映特征组合的重要性。
  • 易于扩展:后续工作如 DeepFM、DCN 等都在此思路基础上进行了改进。

掌握 Wide & Deep 模型,是理解现代推荐系统如何融合传统特征工程与深度学习表征的关键一步。通过亲自在实践中调整 Wide 交叉特征和 Deep 网络结构,你将逐渐体会到“记忆”与“泛化”两个维度如何相互补充,同时也为学习更复杂的多任务、多模态模型打下坚实基础。