![]()
2018年前后,如果你去问任何一个训练大语言模型的工程师"你用Dropout吗",得到的答案大概率是摇头。
这事儿说起来挺讽刺的。Dropout这个技术在2012年由Hinton提出的时候,简直是深度学习圈子里的救命稻草,几乎所有卷积神经网络、早期的Transformer都靠它防止过拟合。但随着GPT-3、LLaMA这些动辄几十亿参数的大模型登场,Dropout却在训练配方里悄悄消失了。PaLM只在微调阶段用它,LLaMA系列干脆连提都不提。业内甚至有种共识:数据量大到模型一辈子只见一遍(也就是"单epoch"训练),根本不存在过拟合的风险,加Dropout纯属画蛇添足,甚至会拖累性能。
但Cerebras这个团队不信邪。他们做了一件挺硬核的事:跑了超过2400次训练实验,模型从2.71亿参数一路做到82亿参数,数据量最高跑到1600亿token,专门去验证一个问题——层级Dropout(Layer Dropout,也叫随机深度)到底还能不能用,以及该怎么用。
结果他们发现,之前所有说"Dropout在大模型上没用甚至有害"的结论,可能都建立在错误的实验配置上。配置对了,Dropout不仅不拖后腿,反而能让模型训练省下25%的算力,同时精度不降反升,还顺带解锁了一堆推理加速的黑科技。
这篇论文的标题就很直白:《别扔掉Dropout》。
层级Dropout到底在干什么
先搞清楚一件事:这里说的Dropout,不是Hinton最早提出的那种"随机把某些神经元清零"的经典版本,而是层级Dropout(Layer Dropout),也叫随机深度(Stochastic Depth)。
层级Dropout*:训练时随机跳过整个Transformer层(而不是零星几个神经元),让模型在每次前向传播时有效深度都不一样,训练完之后模型对"少几层照样能跑"这件事会有天然的抵抗力。
这个区别很关键。普通的神经元级Dropout是把某个神经元的输出乘以0,但计算图里那个神经元该算的乘法加法一分都不会少,GPU照样得把它跑一遍,只是结果被扔掉了。这就好比你雇了个工人,让他做完活儿再把成果扔进垃圾桶,工资照付,时间照花,只是最后没留下东西。
层级Dropout不一样。它跳过的是整层网络,如果一个样本被标记为"跳过第5层",那第5层对这个样本的计算压根就不会执行,不是算完再丢,是根本不算。这意味着层级Dropout能实打实地省下计算量,丢弃比例接近多少,训练算力就能省下多少,是真金白银的加速,不是纸面上的正则化技巧。
这也是为什么论文作者觉得这事儿值得死磕:如果层级Dropout真能在不损失精度的前提下省算力,那对于每次训练要烧掉几百万美元电费的大模型公司来说,这就是白捡的钱。
为什么之前的研究总说Dropout没用
论文里有个说法很直接:很多论文报告的"Dropout导致性能下降",可能根本不是Dropout本身的问题,而是配套的训练超参数没调对。
这就好比你去评价一辆手动挡车"开起来很顿挫",结果人家是因为你离合器和油门配合不当,车本身其实很流畅。层级Dropout引入之后,模型的"有效深度"变了,原来给28层模型调好的学习率、批次大小、权重衰减,未必适合一个训练时随机变成22层、25层的模型。
Cerebras团队做的第一件事,就是把这个变量死死摁住:先把超参数调到最优,再去比较有没有Dropout、用什么样的Dropout配置。这是个笨办法,但也是唯一靠谱的办法。
这里有个技术细节值得展开讲讲,就是缩放因子(Scaling Factor)的选择问题。
缩放因子*:在Dropout过程中,为了让训练时(随机丢弃)和推理时(全部保留)的输出数值范围保持一致,需要对留下来的部分做一个数值补偿,这个补偿系数就叫缩放因子。
标准PyTorch库里,普通Dropout用的缩放规则是1除以保留概率。但层级Dropout这个领域比较野,不同论文用的规则五花八门:最早的随机深度论文用一种,DINOv2用另一种,Meta的fairseq和torchtune又用了别的方式,论文作者甚至吐槽说,很多论文压根不写清楚自己用的是哪种缩放,得去翻源代码才能搞明白。
Cerebras的做法是引入一个叫"最大残差流更新"的设计准则去验证哪种缩放方式最稳。他们做了一个叫"坐标检查"的实验:观察不同网络深度密度下,激活值的数值大小变不变。结果很清楚,如果缩放因子设为1(也就是不做任何补偿),激活值会随着丢弃率变化而剧烈波动,必须针对每个丢弃率单独调参;但如果把缩放因子设为1除以层密度,激活值在各种丢弃率下都能保持稳定,最优的学习率、权重衰减、批次大小几乎不用变。
这就好比你在不同水深的泳池里游泳,水越深浮力越大,如果每次换泳池都要重新适应换气节奏,那太折腾了。但如果有个统一的换算规则能把不同深度的浮力差异抵消掉,你就能用同一套游泳姿势应对所有泳池。缩放因子干的就是这个抵消的活儿,它确保了不管丢弃率是10%还是80%,训练时的"感受"是一致的,这样调好的超参数才能直接搬到别的丢弃率上用,不用每次重新炼一遍。
细粒度之争:哪里丢、怎么丢
层级Dropout听起来简单,一"丢"了之,但实际操作起来至少有三个维度的选择:丢什么、怎么分配、按什么频率丢。
先说"丢什么"这个维度。一个Transformer层其实包含两个子模块:注意力模块(Attention)和前馈网络模块(FFN)。你可以选择让这两个模块各自独立决定要不要被丢弃(论文称之为子层Dropout),也可以强制它们要丢一起丢、要留一起留(论文称之为层Dropout)。
DINOv2用的是前者,LayerDrop和LayerSkip用的是后者。Cerebras的实验结果很干脆:整层一起丢的效果更好。在2.71亿参数模型上,子层Dropout的验证损失比整层Dropout高了差不多0.4个百分点。
这个结果乍一听有点反直觉,通常我们会觉得粒度越细,控制越精细,效果应该越好。但论文给出的一个可能解释是:注意力模块和前馈网络模块其实是"配合作战"的,注意力负责在token之间搬运信息,前馈网络负责对搬来的信息做加工处理,如果只丢了注意力却留了前馈网络,前馈网络处理的就是一堆"没被重新组织过的原始信息",这种错配反而会伤害学习效果。这就好比一道菜的"洗菜"和"炒菜"两道工序,你可以选择某一顿饭完全不做这道菜(整层跳过),但你不能说"这顿饭我们只洗菜不炒菜",半成品的菜谁也不想吃。
再说"怎么分配"的维度,也就是丢弃率在不同层之间该怎么设置。论文提出了三种典型分布方式。
均匀分布*:所有层用同一个丢弃率,简单粗暴。
递增分布(ILD)*:丢弃率从第一层的0一路线性涨到最后一层的最大值,越靠近输出层,被丢的概率越高。
交替分布(ALD)*:只在偶数层(或奇数层)上设置丢弃率,其余层完全不丢。
论文的结论是:在同等的算力预算下(也就是省下同样比例的训练算力),非均匀分布(递增或交替)都比均匀分布更好,而且随着模型变大,递增分布的优势会越来越明显,交替分布的优势反而会缩小。
为什么递增分布更合理?论文提出了一种解释:模型的浅层通常在做一些底层的、通用的特征提取工作,这些工作对整个模型至关重要,不能随便丢;而深层更多是在做一些精修和微调,容错空间更大。这就像盖房子,地基和承重墙(浅层)绝对不能省工序,但室内装修的细节打磨(深层)即便某一遍没做到位,房子照样能住,顶多是美观度差点意思。把丢弃的风险集中分配到深层,是一种更聪明的资源调度。
时间维度上的博弈:递减比递增更好
除了空间上"在哪一层丢",还有一个时间维度的问题:丢弃率该在整个训练过程中保持不变,还是应该随着训练推进发生变化?
论文测试了三种时间调度方案:恒定不变、从0线性递增到最大值、从最大值线性递减到0。
结果相当明确:递减调度全面胜出,在所有测试的模型规模(2.71亿、5.03亿、9.06亿参数)上都是如此。更惊人的是,在5%算力节省的场景下,"递增层分布+递减时间调度"这套组合拳的验证损失,居然比完全不用Dropout的密集基线模型还要低。
这是整篇论文里最反直觉的发现。它意味着:用更少的训练算力,反而能训出更好的模型。这听起来违背常理,因为一般我们认为算力和效果是正相关的,烧的电越多,模型应该越强。但这个实验结果说明,恰当的正则化和恰当的"训练难度曲线"设计,能让模型用更少的计算走到更好的地方。
论文作者给出了一个挺有意思的解释框架:训练刚开始时用高丢弃率,相当于给模型制造了大量噪声,逼着它在参数空间里做更充分的探索(减少偏差);随着训练推进丢弃率逐渐降低,模型开始稳定地收敛到一个好的解(减少方差)。
这套逻辑其实可以类比成学骑自行车。刚学的时候,教练可能会故意让你在不平整的场地上练习,让你适应各种颠簸和失衡的情况,这个阶段"路况差"(对应高丢弃率)恰恰能帮你建立更强健的平衡感。等技术熟练了,再换到平整的马路上骑(对应低丢弃率),你能更快地找到最优的骑行节奏。如果一开始就在完美的路面上学,遇到一点点石子路可能就会摔倒,模型也是一样,全程零噪声训练出来的模型,看起来收敛得又快又稳,但抗干扰能力反而更差。
另外一个视角是把它理解成一种"模型渐进式生长"。模型的有效深度(Effective Depth)在训练早期比较浅,随着丢弃率下降逐渐变深,这跟传统的"先训小模型再逐步扩容"的模型生长策略有异曲同工之妙,只不过层级Dropout做到了这一点还不需要重新初始化任何权重,完全是"免费"获得的。
训练完之后,模型多了哪些超能力
前面讲的都是训练阶段的收益,省算力、甚至精度反超。但这篇论文真正让人眼前一亮的部分,其实是训练完之后模型获得的"零样本弹性"。
先说早退(Early Exit)。
早退*:模型在推理时不跑完全部层数,而是在中间某一层直接接嵌入层的输出送去做预测,跳过后面所有层,从而节省推理时间。
一个完全没用过层级Dropout训练的模型,如果你强行让它在推理时早退一层,损失会立刻爆炸式上升。但一个用层级Dropout训练过的模型,早退好几层损失都还能保持在可控范围。这个差异非常直观:因为训练过程中模型本来就经常"被迫"用不完整的层数去完成任务,它已经习惯了这种"残缺",所以推理时你临时砍掉几层,它不会懵。
这就好比一个演员,如果平时排练的时候台词、走位、灯光配合都严丝合缝一次不差,那么演出当天万一有个环节出岔子(比如某个灯光没打上),他大概率会慌。但如果排练时导演故意时不时抽掉几个环节,让演员适应"计划外情况",那真正上台时哪怕出点意外,演员也能顺势接住,戏照样演得下去。层级Dropout训练做的正是这种"故意制造排练事故"的工作。
再说层跳跃(Layer Skipping)。
这个和早退不同,早退是砍掉最后一截,层跳跃是可以砍掉中间任意几层,跳过之后再无缝衔接。论文发现均匀分布或递增分布训练出来的模型早退表现好,但对付这种中间跳跃的情况就没那么擅长;反倒是交替分布(ALD)在这方面表现更突出,因为它训练时本来就习惯了"每隔一层就可能消失"这种模式,所以中间挖空几层它也扛得住。这里出现了一个有意思的权衡:ALD擅长层跳跃但不擅长早退,ILD正好相反。这提示我们,没有一种配置是万能的,得看你实际部署时更需要哪种弹性。
第三个应用是早退适配器(Early Exit Adapter),这个来自另一篇叫Balcony的研究框架。
早退适配器*:冻结预训练好的模型主干,只在若干中间层后面插入额外的小模块(适配器),用知识蒸馏的方式训练这些适配器,让模型在浅层就能输出接近最终层质量的预测结果。
Cerebras发现,用层级Dropout预训练过的模型,即便后续加了这些适配器进行微调,早退表现依然全面碾压没用过Dropout的模型。而且丢弃率越高的模型,给适配器训练提供的"起点"越好,这说明层级Dropout赋予的结构弹性是一种持久的、深入模型骨子里的特性,不是靠后期打补丁能完全复制的。
最后一个,也是最实用的一个,是自投机解码(Self-Speculative Decoding)。
自投机解码*:用同一个模型的部分层充当"草稿模型"快速生成候选词,再用完整模型并行验证这些候选词是否可靠,通过减少昂贵的完整前向传播次数来加速推理,整个过程不损失任何生成质量。
论文用了一种叫"Draft & Verify"的方法,配合遗传算法、爬山算法、模拟退火等多种搜索策略去找最优的"草稿层子集"。结果显示:没用过Dropout训练的模型几乎榨不出什么加速(1.01到1.06倍),但用了0.4丢弃率训练的模型能拿到1.35到1.43倍的实打实加速。这个差距相当悬殊,同样是想找一个"够快又够准"的层子集去做草稿,没Dropout训练过的模型压根就没有这样的子集存在,而Dropout训练过的模型天生就带着一堆现成的候选答案。
这就像是让一个团队里随便抽调几个人组成"快速反应小组"去处理紧急任务。如果平时团队成员从来没有互相代班、跨岗位协作的经历,临时拼凑的小组很可能配合生疏,出错率高,最后还得让主力团队返工重做,反而更慢。但如果平时训练时就有意识地让员工轮岗代班(对应层级Dropout),公司随时能拉出一个靠谱的应急小组顶上,救急效率自然高得多。
大模型上的"压力测试":越大越能扛
前面的实验大多集中在3亿到9亿参数的规模,Cerebras团队接着把这套方法推向了更大的模型:18亿、39亿,甚至82亿参数,并且用上了相当激进的丢弃率,分别是0.6、0.8、0.99。
0.99是什么概念?意味着训练到中途,某一层有99%的概率会被完全跳过。这已经不是"偶尔偷个懒"了,简直是"几乎全年无休地摸鱼"。
但结果出人意料:82亿参数模型用0.99的最大丢弃率训练,累计节省了25%的训练算力,验证损失是1.663,比同规模没用Dropout的模型表现还要好(对照组39亿模型不用Dropout是1.732)。更夸张的是层跳跃测试:39亿参数的密集基线模型如果被强行跳过交替层,损失会飙升到6.446,几乎相当于胡言乱语;而用0.8丢弃率训练的同规模模型,跳过交替层损失只有2.129,几乎没受什么影响。自投机解码的加速比也达到了1.54倍。
论文观察到一个规律:模型越大,对高丢弃率的容忍度越强。作者据此推测,未来更大规模的模型会展现出更强的鲁棒性,Dropout带来的收益也会随之放大。这背后的直觉也不难理解:一个参数量巨大的模型本身就存在相当程度的冗余,随便丢掉一部分能力,剩下的部分依然绰绰有余去完成任务;但一个本来就很紧凑的小模型,容错空间有限,稍微丢点东西就伤筋动骨。这跟一支足球队人员配置的逻辑类似,如果你只有11个首发球员,随便伤一个都可能影响整场比赛的战术执行;但如果你有30人的大名单,个别球员缺阵,替补上来依然能维持战斗力。
这篇论文还没来得及做的事
论文的作者也挺坦诚,列了一堆还没验证的开放问题。
比如超参数迁移这件事,在丢弃率不太激进的情况下(比如0.1到0.4),学习率和权重衰减基本不用调,但到了0.6以上这种激进程度,最优超参数其实还是发生了偏移,论文说这块的迁移规则还有优化空间。
再比如,这次实验只验证了整个Transformer层级别的丢弃,注意力头级别或者神经元级别是不是也有类似的结构弹性效果,还是未知数。
还有和其他"弹性架构"方法的对比,比如Mixture-of-Depths这种通过路由机制动态分配计算量的方法,跟层级Dropout这种"训练时随机、推理时固定"的思路相比,孰优孰劣,论文没有涉及。
以及最大丢弃率的"最优解"到底怎么根据模型规模和数据量去推算,目前还没有一套成熟的缩放定律。
写在后面
读完这篇论文,最让我意外的其实不是那些漂亮的加速数字,而是那个"5%算力节省却打败密集基线"的实验结果。这说明我们对"算力投入等于模型质量"这件事的理解可能一直有点简单粗暴。
有个细节我反复琢磨了很久:论文提到不同框架对层级Dropout的缩放因子实现方式五花八门,有些甚至连文档里都不写清楚,得去翻源代码才能确认。这其实暴露了一个挺常见的问题,同一个概念的名字(层级Dropout)在不同团队手里可能是完全不同的实现,大家各自为战、互不参照,结果导致领域内积累了一堆相互矛盾的"经验教训",谁也说服不了谁。Cerebras这次做的很大一部分工作,其实是在做"考古"和"正本清源",先把历史上散落各处的实现方式全部翻出来对齐,才能谈得上公平比较。
这让我想到一个更大的问题:深度学习领域里,有多少"某某技术已被证明无效"的结论,其实只是"某某技术在某个特定超参数组合下表现不佳"?超参数空间太大了,一篇论文能穷举的组合终究有限,一旦某个技术在早期尝试中效果不好,很容易被贴上"过时"的标签,然后很少有人愿意花几千次实验的成本去重新验证它是不是真的没用,还是只是没被用对。
这篇论文某种程度上是在提醒我们:技术的兴衰,有时候不完全是技术本身的问题。
Q&A
Q1:层级Dropout和普通的Dropout有什么区别?
A:普通Dropout是随机清零个别神经元,计算量并不会减少;层级Dropout是随机跳过整个Transformer层,被跳过的层完全不参与计算,因此能实打实地节省训练算力,同时让模型具备"缺几层也能正常工作"的能力。
Q2:为什么之前大模型训练都不用Dropout了?
A:业内普遍认为大模型训练数据量巨大,模型一辈子只看一遍数据,不存在传统意义上的过拟合,加上此前一些研究发现随意加入Dropout会拖累性能,所以GPT-3之后的很多模型逐渐放弃了这个技术,但这篇论文发现问题出在超参数没调对,配置得当反而能提升效果。
Q3:用层级Dropout训练的模型能带来哪些实际好处?
A:训练阶段最多可节省25%的算力且精度不降反升;推理阶段可以支持早退、跳过中间层、自投机解码等多种加速手段,实测在82亿参数模型上自投机解码能拿到1.55倍的速度提升,而且完全不损失生成质量。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.