
深度学习推荐模型翻车5次后,我才从特征交叉里揪出真凶去年我从后端转 AI 做推荐系统,第一件事就是把协同过滤当成万能药。看了点机器学习入门的资料,照着写了几百行 Python,用户相似度矩阵算了两天,结果上线召回率只有 0.28。当时还以为再加一个加权规则就能救回来,直到线上用户在冷启动阶段拿到的全是「热门兜底」,点击率比随机还低。领导说试试深度学习。我一头扎进 Neural Collaborative Filtering,以为加几层 DNN 就能翻身--结果连续翻车 5 次:训练集 AUC 飙到 0.96,线上直接跌到 0.51,AB 测试差点把推荐流搞成事故。后来老老实实把深度学习基础这门课从头啃了一遍,才搞懂特征交叉里到底藏了多少坑。要是早一点系统学完深度学习基础里的 Embedding 初始化、特征交互与过拟合诊断,我那个被驳回 3 轮的架构方案至少能少走两个月弯路。协同过滤很美,但工业数据一上就原形毕露我最初把问题想得太简单:用户评分矩阵做 SVD,缺省值用平均值填充,然后算 item-based 相似度。这套流程在机器学习基础的环境里跑得很溜,甚至跑出了 0.75 的离线召回率。可是一挂上真实日志数据,用户行为有 90% 以上是隐式反馈(点击、停留、跳过),评分只有不到 3%。稀疏度高达 99.8%,SVD 分解后的向量几乎都坍缩到同一个方向。当时我还不懂什么是「数据漂移」和「隐式反馈的置信度加权」,傻傻地把点击当成评分 1.0、曝光未点击当成 0.0,导致模型疯狂偏好头部内容。后来我翻出机器学习基础课程里关于特征工程的章节,才意识到自己跳过了最重要的一步:行为序列转特征。如果能早点把曝光时长、完播率、同位置竞争等信息做成稠密特征,协同过滤至少还能多撑一阵。机器学习基础里那个用 Amazon SageMaker Data Wrangler 做特征处理的动手实验,直接展示了如何把分散的日志表合成一张训练宽表--我当时要是真的跟做一遍,就不会把几百 GB 的日志扔在那儿发了霉。5 次深度学习翻车记录:从过拟合到线上崩塌我的第一次翻车是把 user_id 和 item_id 的 Embedding 直接拼接,后面接 3 层全连接,用 BCE 损失训练。训练到第 10 个 epoch,验证集 loss 不降反升,我还以为是 batch size 太小。深度学习基础课程后来告诉我,这种「双塔 MLP」结构在缺少交叉特征时极容易过拟合 ID 空间,尤其当用户行为总次数少于 50 时,Embedding 向量的梯度更新几乎全是噪声。第二次我加了 Dropout,但把 keep_prob 设成了 0.3,结果训练集 AUC 变成 0.61--欠拟合。第三次我干脆搬出 Wide Deep 结构,用 FM 做 wide 侧,deep 侧接 4 层网络,但 wide 侧的阶数只设到 2,完全没捕捉到多值特征的组合效应。第四次我尝试用 DIN 做注意力池化,但因为没对候选 item 的 Embedding 做 L2 归一化,注意力权重被长尾物品的模长绑架。第五次翻车最致命:我把所有能想到的特征全扔进 deep 侧,包括 800 维的多热编码历史序列,然后指望模型自己去学交叉。训练时间拖到 6 小时一轮,线上推理延迟超过 200ms,AB 测试期间推荐流直接被降级。# 第五次翻车的模型定义片段(PyTorch) class FifthCrash(nn.Module): def __init__(self, user_num, item_num, feat_dim, hidden[256,128,64]): super().__init__() self.user_emb nn.Embedding(user_num, 32) self.item_emb nn.Embedding(item_num, 32) self.fc1 nn.Linear(32*2 feat_dim, hidden[0]) self.fc2 nn.Linear(hidden[0], hidden[1]) self.fc3 nn.Linear(hidden[1], hidden[2]) self.out nn.Linear(hidden[2], 1) def forward(self, uid, iid, feats): u self.user_emb(uid) i self.item_emb(iid) x torch.cat([u, i, feats], dim1) # 直接拼接,无交叉特征 x F.relu(self.fc1(x)) x F.relu(self.fc2(x)) x F.relu(self.fc3(x)) return torch.sigmoid(self.out(x))这段代码没有显式特征交叉,Embedding 维度固定 32 毫无依据,特征拼接顺序也会影响梯度回传的对称性。深度学习基础课程里花了整整一章讲特征交叉的设计范式,从 FM 的隐向量点积到 DCN 的 Cross Network,把每种交叉的参数量和适应场景都画成了决策树,直接帮我避开了后续的架构盲试。深度学习基础课三节课解决了我半年的困惑硬着头皮开始补深度学习基础时,我其实没太大期待。但这门课的第一节就直接击中了我的痛点:为什么隐式反馈不能直接当二分类做?原因在于正样本置信度远高于负样本(未点击可能只是没曝光到位),需要用加权损失或负采样策略。听完这节,我马上把 BCE 改成了 weighted BCE,正样本权重设为 5.0,验证集 AUC 从 0.54 跳到了 0.62,线上点击率提升了 8%。第二节课讲到 Embedding 初始化的尺度。之前我全用默认的 N(0,1),导致向量模长波动剧烈。深度学习基础给出的经验是:对于 ID 类特征,Embedding 维度 d 在 sqrt( 特征基数 ) 附近选取,初始化用 uniform(-1/sqrt(d), 1/sqrt(d)),可以稳定前期训练。我照着改,前 3 个 epoch 的 loss 不再爆炸。第三节课是关于特征交叉的深入解析--这是我之前所有翻车的根因。深度学习基础课程里对比了 DCN v2 的 Cross Network 与 AutoInt 的自注意力交叉,点明了一个关键:多值特征的交叉不能只靠简单拼接,需要先池化聚合或构建交互序列。我于是把用户最近 20 次点击物品的 Embedding 通过 Attention 池化后,再与候选物品 Embedding 做哈达玛积作为交叉项。# 改进后的特征交叉模块 class FeatCross(nn.Module): def __init__(self, emb_dim): super().__init__() self.attn nn.Linear(emb_dim * 2, 1) self.cross nn.Linear(emb_dim, emb_dim) def forward(self, seq_emb, target_emb): # seq_emb: (batch, seq_len, emb_dim); target_emb: (batch, emb_dim) target_expand target_emb.unsqueeze(1).expand_as(seq_emb) attn_in torch.cat([seq_emb, target_expand], dim-1) attn_w F.softmax(self.attn(attn_in), dim1) # (batch, seq_len, 1) pooled torch.sum(attn_w * seq_emb, dim1) # (batch, emb_dim) crossed pooled * self.cross(target_emb) # 哈达玛积交叉 return crossed加上这个模块后,线下 AUC 从 0.68 拉到 0.73,线上延迟从 200ms 降到 45ms。我这才明白,深度学习基础里那套「结构选择→特征设计→训练策略」的流水线思维,比看十篇论文都管用。如果没有这门课把 Embedding 初始化、特征交叉和负采样串成一条线,我可能还在瞎试第 6 版网络结构。线上 AB 测试惊魂:冷启动和生成式 AI 救场模型训练完,上线 AB 测试第一天,实验组的点击率反而低了 12%。我吓出一身冷汗,赶紧拉出日志看分群:新用户(历史行为 5 次)的点击率暴跌了 30%,老用户却涨了 15%。问题是新用户的序列特征几乎为空,Attention 池化后向量趋近零,模型直接把推荐结果坍缩成全局热门。我在人工智能入门课程里看到过冷启动的三种解法:基于内容特征的回归、人口统计学聚类、以及用生成式 AI 做画像扩充。当时我选了最后一种:对行为稀疏的用户,先用他们仅有的 1~2 个点击物品的描述文本,调用大模型生成 5 个语义相似物品的元数据,然后把这些物品的 ID 当作伪历史序列填入模型输入。这种方式让新用户的推荐多样性提升了 40%,点击率恢复到对照组水平。生成式AI 课程里有一节专门讲如何用 prompt 约束生成结果的领域属性,我把那个模板改了三行就接进了 pipeline,省掉了单独训练内容模型的时间。冷启动方案不是一拍脑袋就干的,人工智能入门课程里的案例对比了不同方案在电商与内容场景下的延迟和覆盖率,帮我快速排除了需要实时更新用户画像的聚类方案,选了最适合当时架构的生成式扩充。学完后我把整个推荐链路重写了一遍现在这套推荐系统已经稳定跑了四个月,线上平均点击率提升 26%,P99 延迟从 320ms 降到 78ms。回过头看,如果当初没有死磕深度学习基础,我可能至今还在用协同过滤硬扛,或者被那些花哨的模型名字带偏。深度学习基础课程里面那套「诊断→设计→验证」的思路,已经内化成我日常写 AB 方案的本能。下面这张表记录了我从协同过滤到深度学习的核心指标变化,每一个拐点都对应一门课的关键知识点:阶段模型召回率/点击率延迟关键知识来源初始协同过滤0.2812ms机器学习入门第1次迭代MLPID0.15(点击率)22ms-第5次翻车WideDeep全家桶0.13(点击率)210ms-学习后第1版加权交叉网络8%(点击率)45ms深度学习基础冷启动优化生成式序列扩充40%(多样性)78ms人工智能入门、生成式AI# 最终模型训练入口的关键配置 config { user_emb_dim: int(np.sqrt(user_cardinality)), # 来自深度学习基础的建议 item_emb_dim: int(np.sqrt(item_cardinality)), seq_len: 20, hidden_units: [128, 64], pos_weight: 5.0, # 隐式反馈加权 init: uniform_scale, use_bn: True, dropout: 0.2 }这段配置里的几乎每一项,都对应着深度学习基础课程中一个动手实验的输出。特别是 pos_weight 的取值,课程里给出了基于正负样本比例的计算公式,我改了一个参数就直接把离线评估的 NDCG 从 0.34 提到了 0.52。给同样处境的人三条实操建议先补深度学习基础,再碰模型架构。协同过滤的瓶颈不是代码问题,是特征表达能力的问题。深度学习基础课把 Embedding、交叉、过拟合、评估指标串成了一个闭环,比漫无目的地读论文高效五倍。如果你还在纠结用 DeepFM 还是 xDeepFM,不如先去这门课里把特征交叉的设计范式吃透。特征工程不可跳过,即使转深度学习。机器学习基础里的特征处理实验,能让你少写 300 行垃圾特征提取代码。我在把日志合成训练表这一步卡了 10 天,最后用 SageMaker Data Wrangler 的可视化流水线 2 天就跑通了。冷启动别硬编码兜底规则。人工智能入门课里对比了多种冷启动策略的成本曲线,生成式AI 那一节的图像生成冷启动案例直接启发了我的伪序列填充。看完后你会意识到,规则堆得越多维护成本越高,而生成式扩充能随着物品库的增长自动适应。最后多说一句:如果你正在从后端或者数据分析转推荐方向,AWS深度学习 上的系列实验环境能帮你跳过环境配置的坑,直接上手神经协同过滤的完整训练流程,连 GPU 实例都预配好了。回头想想,我要是早点系统学完深度学习基础,那 5 次翻车至少能少 3 次。