SENet与GateNet深度解析:推荐系统特征建模的演进与实战
特征建模在推荐系统中的核心价值
推荐系统的本质是解决信息过载问题,而特征建模则是这个过程中的关键环节。在工业级推荐系统中,特征往往呈现出海量、高维且极度稀疏的特点。以微博推荐系统为例,用户行为数据中超过80%的特征出现频率不足5次,但传统方法仍为这些低频特征分配与高频特征相同的Embedding维度,这直接导致两个严重问题:
- 模型参数膨胀:特征Embedding层通常占据推荐模型总参数量的90%以上
- 噪声特征干扰:大量低频特征的噪声信号会淹没真正有效的特征信号
# 典型推荐模型参数分布示例 total_params = 20e8 # 20亿参数 embedding_params = 18.7e8 # Embedding层参数 mlp_params = 1.3e8 # MLP层参数 print(f"Embedding层占比: {embedding_params/total_params:.1%}") # 输出93.5%提示:在Criteo数据集上的实验表明,当Embedding size超过30时,未做特征选择的模型AUC指标会下降0.5-1.2%,而引入特征选择的模型则能保持稳定上升
特征建模的三大技术方向
1. 卡门槛:动态特征选择
核心思想:在特征Embedding层与上层网络之间加入可学习的门控系统,动态判断每个特征的重要性并分配权重。这类似于高考分数线机制,只有达到一定重要性的特征才能进入后续计算。
| 技术方案 | 参数量 | 计算复杂度 | 适用场景 |
|---|---|---|---|
| SENet | 低 | O(n) | 精排模型 |
| GateNet | 中 | O(n^2) | 复杂交叉 |
| ContextNet | 高 | O(n^2) | 序列建模 |
2. 挤水分:变长Embedding分配
传统方法为所有特征分配相同长度的Embedding,这显然不合理。更优策略应为:
- 高频特征:分配较长Embedding(如64维)
- 低频特征:分配较短Embedding(如8维)
# 变长Embedding实现示例 class AdaptiveEmbedding(nn.Module): def __init__(self, vocab_sizes, dims): super().__init__() self.embeddings = nn.ModuleList([ nn.Embedding(vocab_size, dim) for vocab_size, dim in zip(vocab_sizes, dims) ]) def forward(self, inputs): return torch.cat([ emb(inputs[:,i]) for i, emb in enumerate(self.embeddings) ], dim=1)3. 补营养:特征表达增强
对于无法简单丢弃的低频特征,可通过两种方式提升其表达质量:
- 内功修炼:使用对比学习等技术让模型从数据中自行挖掘深层模式
- 外部借力:通过多任务学习共享其他任务学到的特征表达
SENet:计算机视觉启发的特征选择方案
SENet(Squeeze-and-Excitation Network)最初由Momenta团队提出用于图像分类,其核心创新在于:
- Squeeze阶段:将每个特征域的Embedding压缩为单个标量(通常采用均值池化)
- Excitation阶段:通过两层MLP学习特征重要性权重
- Reweight阶段:将学习到的权重与原始Embedding相乘
FiBiNet模型中的SENet变体:
- 输入:100个特征域,每个域Embedding维度为32
- 中间层:压缩到16维再扩展回100维
- 输出:100个0-1之间的重要性权重
注意:原始SENet使用ReLU激活函数会导致约30%的特征权重直接归零,这在推荐场景可能过于激进。实践中可改用Sigmoid保留更多特征信息
GateNet:门控机制的全面升级
GateNet由新浪微博团队提出,将门控机制系统性地应用于推荐系统的各个层级:
1. Embedding层门控
- Bit-wise模式:为Embedding向量的每个元素分配独立权重
- Vector-wise模式:整个Embedding向量共享一个权重
参数共享策略对比:
| 策略 | 参数量 | AUC增益 | 训练速度 |
|---|---|---|---|
| Field Private | 高 | +1.2% | 慢 |
| Field Sharing | 低 | +0.6% | 快 |
2. 隐藏层门控
在MLP的隐藏层之间插入门控单元,公式表示为: $$ a^{(l)} = g^{(l)} \odot (W^{(l)}h^{(l-1)} + b^{(l)}) $$ 其中门控值$g^{(l)}$由下层激活$h^{(l-1)}$经独立网络计算得到
3. 实战经验
在电商推荐场景中的观察:
- 对于用户行为序列,GateNet比SENet带来更显著的提升(+1.8% vs +1.2%)
- 门控激活函数选择:Embedding层用Tanh,隐藏层用Sigmoid效果最佳
- 同时使用Embedding和隐藏层门控时,需将学习率降低30%-50%以避免震荡
技术对比与选型指南
SENet vs GateNet核心差异
| 维度 | SENet | GateNet |
|---|---|---|
| 设计初衷 | 特征选择 | 信息流控制 |
| 计算粒度 | Field-level | Bit-level |
| 参数共享 | 强制共享 | 可配置 |
| 位置灵活性 | 仅Embedding层 | 任意网络层 |
| 计算开销 | 低 | 中高 |
选型决策树
- 数据特性:
- 特征域少且稳定 → SENet
- 特征域多且变化大 → GateNet
- 系统约束:
- 延迟敏感 → SENet
- 效果优先 → GateNet
- 特征类型:
- 结构化特征 → SENet
- 序列行为 → GateNet
# 混合使用示例 class HybridModel(nn.Module): def __init__(self, num_features, emb_dim): super().__init__() self.senet = SENetLayer(num_features) self.embedding = nn.EmbeddingBag(num_features, emb_dim) self.gate_mlp = nn.Sequential( nn.Linear(emb_dim, emb_dim//2), nn.Sigmoid() ) def forward(self, x): weights = self.senet(x) weighted_x = x * weights emb = self.embedding(weighted_x) gate = self.gate_mlp(emb) return emb * gate前沿发展与工程实践
1. 动态门控技术
最新研究显示,将门控决策从静态学习改为基于实例动态生成,可进一步提升效果:
- 计算开销增加15%,但AUC提升0.3-0.5%
- 关键实现:将门控网络的输入扩展为实例特征+全局统计量
2. 门控机制的可解释性
通过分析门控权重分布,可发现业务中的关键特征:
- 电商场景:价格敏感度权重与促销活动强相关
- 内容推荐:时效性特征权重在热点事件期间显著升高
3. 部署优化技巧
- 量化压缩:将门控网络参数量化为INT8,几乎无损效果
- 提前计算:对于非序列特征,门控权重可离线预计算
- 稀疏化:对低于阈值的门控输出直接置零,提升计算效率
在实际AB测试中,合理配置的GateNet模型相比基线DNN模型,在微博信息流场景实现了:
- 点击率提升2.1%
- 用户停留时长增加3.4%
- 模型体积减少18%(通过特征过滤)