ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

给推荐系统开混合精度,它先把用户性别搞反了

给推荐系统开混合精度,它先把用户性别搞反了 给推荐系统开混合精度,它先把用户性别搞反了上个月我在给推荐系统升级深度学习模型时,GPU 显存直接爆掉--我们那个 7B 参数的序列推荐模型,单卡 24GB 连 batch_size2 都跑不起来。为了不耽误发版,我连夜翻技术帖,把混合精度、梯度检查点、CPU offload 全叠上,第二天模型终于启动了。结果上线首日,推荐系统的男女性别推荐准确率直接倒挂:女装被推给男用户的比例从平时的 5% 飙到 23%。后来我补了一门AWS深度学习的课才搞明白,混合精度里的损失缩放机制如果设置不当,会把稀疏特征的梯度冲成噪声,而推荐系统里几乎全是高基数稀疏特征。这一跤摔得结实,但也逼我彻底吃透了大模型在推荐系统里省显存的四件套。如果你也在用大模型做推荐,或者正被显存卡脖子,下面这些血泪教训和课程经验或许能帮你少交几个月学费。为什么我要在推荐系统里塞进一个 7B 模型我们团队负责的推荐系统原来基于 LightGBM 双塔召回,效果已经不错,但对用户长序列兴趣建模总是抓不住。CTR 预估对比如短视频这类场景,用户兴趣漂移快,必须用更深的时序模型。所以我才决定把推荐系统的排序层换成一个预训练的 7B 因果语言模型,再用交互行为做微调。但现实马上扇了我一耳光:推荐系统的训练数据动辄几十亿条交互,7B 模型的参数量加上 Adam 优化器状态,单卡根本塞不下。我被迫开始研究各种显存优化技巧,打算先跑通一个小规模实验再去申请多卡。于是就有了下面这些技术试错。四个显存节省技巧:我依次把它们塞进推荐系统我先用单张 A10(24GB)尝试,目标是至少让 batch_size8 跑起来。参考了一些博客,列了四招:混合精度训练(AMP):将大部分计算转成 FP16,只在关键路径保留 FP32,理论能省 40% 显存。梯度检查点(Gradient Checkpointing):在前向传播时不保存部分中间激活,反向时重新计算,用时间换空间。CPU Offload:把优化器状态或部分参数从 GPU 搬到 CPU 内存,比如把 Adam 的动量缓冲区放在主机上。小 batch 梯度累积:减小 per-step batch,通过累积多个步骤再更新参数,用虚拟大 batch 来维持收敛稳定。这些技巧单独用都有文档,但一起塞进推荐系统时,问题开始连环爆。踩坑实录:每个技巧都藏着意想不到的副作用混合精度把稀疏特征梯度冲没了最先出问题的是 AMP。我用了 PyTorch 自带的torch.cuda.amp,把推荐系统的forward过程包在autocast里,然后加了GradScaler。训练损失曲线正常下降,我还挺高兴。# 混合精度训练代码片段(第一版) scaler torch.cuda.amp.GradScaler() for batch in dataloader: with torch.cuda.amp.autocast(): outputs model(batch[input_ids], batch[user_features]) loss outputs.loss scaler.scale(loss).backward() scaler.step(optimizer) scaler.update()但上线后一看混淆矩阵,问题严重了。推荐系统对用户性别的区分度大幅下降,男用户的女装点击率异常飙升。回查发现,GradScaler的默认参数在遇到推荐系统中大量稀疏 user/item embedding 的梯度时,会因为 loss scale 倍率过大发生梯度下溢--这些 embedding 的梯度本来值小,被 scale 抬高后又被backward转回 FP16 截断,更新时直接变成 0。也就是模型根本没学到用户性别这类关键特征。后来我去翻了深度学习入门的课程,里面专门有一节讲 AMP 的数值稳定性,才搞清楚GradScaler的init_scale和growth_interval对稀疏特征矩阵的影响有多大。课程里还给出了推荐系统中使用混合精度的最佳初始 scale 值,照着改完,性别特征总算“看”得见了。这个课程对想入坑大模型微调的推荐系统工程师来说,简直是把坑一个个标好了再让你跳,省心太多。梯度检查点拖垮了训练,我还以为是数据加载慢第二个上的梯度检查点。我直接在 HuggingFaceTrainer里把gradient_checkpointingTrue打开,显存确实省了不少,可推荐系统的单个 epoch 训练时间从 40 分钟暴增到 3 小时。我开始怀疑是 CPU 数据加载慢,折腾了两天DataLoader的num_workers和prefetch_factor,没什么改善。# 梯度检查点开启方式 from transformers import AutoModelForCausalLM model AutoModelForCausalLM.from_pretrained(...) model.gradient_checkpointing_enable() # 训练循环中自动重计算后来在机器学习基础的课程里看到“计算图与反向传播”那块才恍然大悟:推荐系统的用户序列长度远超 NLP 平均长度,我们在每个 checkpoint 区域都会触发重计算,序列越长,重计算代价越大。正确的做法是只对深层 transformer block 启用检查点,而把嵌入层和输出头排除在外。改完后训练时间回到 1 小时以内。机器学习基础知识的这种原理讲解,正好补上了我们这些转行工程师的欠账。CPU offload 把 embedding 表搞丢了版本CPU offload 省显存最明显,因为我们推荐系统里用户和物品的 embedding 表很大。我用 DeepSpeed ZeRO-Offload 把优化器状态放到了 CPU 内存,显存确实释放了 15GB。但训练到一半,模型开始输出随机乱码,推荐结果完全不可用。# DeepSpeed ZeRO-Offload 配置片段 { zero_optimization: { stage: 2, offload_optimizer: { device: cpu, pin_memory: True }, allgather_partitions: True, reduce_scatter: True } }排查发现是 CPU-GPU 数据传输时,embedding 的权重更新因为pin_memory配置错乱,某个 step 的梯度写了旧地址,导致 embedding 参数版本错位。这部分在机器学习管道的课程里正好有讲到分布式训练的数据一致性,学完我才意识到,推荐系统这种参数量极大的模型,做 offload 一定要加 checksum 验证,否则线上就是灾难。这门深度学习入门课帮我串起了所有碎片四个技巧的坑分别踩完后,我发现自己还是头痛医头。刚好同事推荐了 AWS 的深度学习入门课程,花了两周把神经网络基础、优化器原理、分布式训练系统地撸了一遍,之前那些零散的显存技巧一下子串了起来。混合精度不只是一个开关,要理解 FP32 master weight、loss scaling 的数学含义;深度学习入门里用简单的反向传播例子把 FP16 截断误差演算得明明白白。梯度检查点的核心是计算图划分,学会看模型的compute_graph才知道哪里该切;深度学习基础这部分讲得特别直观。CPU offload 要配数据预取和同步机制,不能光靠 DeepSpeed 默认配置;AWS深度学习课程里对分布式策略的讲解,让我能按推荐系统的数据规模挑对方案。最关键的是,学完课程后我重新审视了推荐系统的特征工程--把用户历史序列做哈希压缩,减少 embedding 参数量,再结合上面四个技巧,batch_size 从 2 提到 16,显存只用了 18GB,而推荐系统离线评测的 AUC 没掉反升了 3 个百分点。最终方案与上线效果现在这个基于 7B 模型的推荐系统已经在灰度跑了半个月。用四个技巧的最终组合是:技巧配置要点显存节省对推荐系统的隐藏要求混合精度amp GradScaler, init_scale2^12, growth_interval500~35%稀疏特征需单独处理,避免下溢梯度检查点仅 transformer block,排除 embed/output~30%长序列场景需限制 checkpoint 段数CPU offloadZeRO-Stage2, 仅 offload 优化器,加 emb checksum~50%需要高速 CPU-GPU 互联,推荐 PCIe 4.0小 batch累积per_batch2, accumulation_steps8虚拟 batch16需要配合线性 warmup 和略高的学习率经过两周观察,推荐系统的点击率提升了 12%,而女性用户被误推男装的比例降回了正常水平。补上这些基础知识后,我甚至能自己改GradScaler的源码来适配我们特殊的特征工程流程了,这在踩坑之前想都不敢想。给做推荐系统也省显存的同学的建议别像我一样先把所有技巧一把梭。推荐系统的稀疏特征对精度敏感,至少要单独验证混合精度效果,最好先补深度学习入门的原理再动手。显存不够时,先砍模型参数量(蒸馏/剪枝),再加优化技巧。推荐系统的延迟要求往往比 NLP 更严,大模型推理成本会随 QPS 暴涨。特征工程是省显存的第一个关口。推荐系统里用户/物品 ID 用 hash trick 压缩到 1M 以下 embedding 维度,比后面加 offload 省事得多,也不会引入数值问题。机器学习管道课程里有标准的特征预处理流水线,值得搬过来直接套。监控指标别只看损失。必须给推荐系统上线前过一遍混淆矩阵、分群 AUC,否则混合精度下的数值漂移会静默腐蚀线上效果。学完至少一门系统性的课程再碰大模型。我的经历证明,碎片化看博客救不了急。AWS深度学习这类课程把 AMP、检查点、分布式都拆成可复现的实验,学完至少不会犯我今天这种性别搞反的错。CPU offload 别随意开启。除非确定 PCIe 带宽足够且做了数据校验,否则推荐系统的高频 embedding 更新可能让你 debug 到怀疑人生。梯度检查点选层有讲究。推荐系统的序列模型通常 input embedding 和 position encoding 计算量大,不要在那层加检查点,否则训练慢到没法迭代。回头看,那个性别搞反的线上事故如果发生在重要推荐场景,足以造成业务事故。还好只是内部实验。从那以后,每次新技巧上线前,我都会先跑一次数据预处理的校验流程,这是从机器学习入门课里学来的习惯--无论模型多酷炫,数据质量和数值稳定性才是推荐系统的生命线。如果你也在拿大模型折腾推荐,不妨先把这些基础打牢,省下的不只是显存,还有上线后数不清的回滚和道歉。
返回列表