资讯动态

大模型训练省显存8招:从MoE到LoRA,全面降低参数量

发布时间:2026/10/23 5:29:07 来源:尧图企业网站定制
最近把 DeepSeek 的技术报告翻出来认真啃了一遍一边看一边回忆起自己以前做模型训练时踩过的坑。大模型训练这个圈子大家嘴上聊的是效果、刷榜其实背地里最头疼的永远是两件事显存不够用训练太烧钱。这两件事绕来绕去最后都会回到同一个核心问题——参数量。老彭这次就顺着 DeepSeek 论文里的技术路线结合自己实测的经验把降低大模型训练参数量的方法整理成了 8 招按“架构级、训练级、工程级”三个梯度归好类。不管你是在做预训练、微调、还是想把已经训好的大模型压缩成小模型这篇文章里的思路和避坑点都值得参考。1. 先说清楚降低参数量到底降的是什么很多朋友一听“降低参数量”第一反应是“把模型变小”。这个理解不能说错但在实际训练里“参数量”这四个字背后其实藏着好几份不同的账。不先把账算清楚后面所有优化手段都会用错地方。1.1 大模型训练里一份参数有四份账训练一个模型时显存里并不是只放着“模型权重”这一份数据。至少要有四份东西同时在吃内存模型自身的参数也就是权重矩阵本身这是大家最熟悉的一份。梯度反向传播时算出来的梯度张量结构跟参数一一对应。优化器状态用 Adam 系优化器的话每个参数还额外带一份一阶动量m和二阶动量v这两份的大小跟模型参数一样大。前向过程中的中间激活值每条样本过网络时每一层输出的激活值虽然不算“参数”但长序列训练下它占的显存往往比参数还大。我举个具体数字大家就有概念了。假设你训练一个 70 亿参数的模型用 Adam 混合精度模型参数FP16 副本约 14GBFP32 主副本约 28GB加起来 42GB。梯度约 14GB按 FP16 算。优化器状态一阶动量 二阶动量各一份 FP3228GB × 2 56GB。光这三项就奔着 100GB 去了还没算激活值。这就是为什么很多人单卡跑 7B 模型连 OOM 的报错都来不及看。所以“降低训练参数量”这个目标实际上可以拆成三种降低模型结构里的总参数量让模型文件本身变小。降低训练时需要更新的可训练参数量让优化器状态和梯度变小。降低训练时的显存参数占用让单卡跑得动更多参数。这三种诉求对应的方法完全不同。下面这 8 招我按这个逻辑分了三个梯队。第 1 到第 3 招是从架构上砍参数第 4 到第 6 招是从训练策略上省参数第 7 到第 8 招是从工程上榨显存。1.2 总参数量 vs 参与计算的激活参数量还有一对概念必须分清楚总参数量和激活参数量。总参数量好理解就是模型文件里存了多少个权重。但模型前向推理时并不是每个参数都会参与计算。比如后面要讲的 MoE混合专家结构模型总参数量可能有几百 B但每个 token 只激活其中一小部分专家。真正参与这次计算的参数才是决定算力消耗的关键。DeepSeek 论文里反复强调的效率优化本质上就是在压低“激活参数量”和“训练总开销”的比值而不是单纯追求总参数量变小。理解了这两个概念再看后面的招数思路会清晰很多。2. 架构级降参直接在模型结构上砍这一梯队的方法最彻底因为是从模型底层结构上去减少或复用参数。改动一旦定了后面训练和部署都跟着受益。2.1 第1招MoE 稀疏激活把专家切细MoE 的核心思想是不要用一个巨大的稠密网络去处理所有 token而是准备一堆“专家”子网络每个 token 只路由给其中排名靠前的几个专家处理。MoE 不是新东西但 DeepSeek 论文里有一个细节值得单独拿出来讲专家粒度。传统 MoE 的专家通常是一整个大 FFN 模块每个专家内部的知识高度混杂。你让一个专家既懂代码又懂古诗它的参数利用率其实很低。DeepSeek 的做法是把专家切得更细让每个专家专注的“知识面”更窄。同时再加几个“共享专家”确保每个 token 都能拿到一份通用的基础处理能力。这样做的好处直接体现在训练开销上总参数量变多了但因为每个 token 只激活少量细粒度专家激活参数量反而比同等容量的稠密模型低很多。训练时的 FLOPs 跟着激活参数量走于是同样的训练数据量和 batch sizeMoE 结构的模型实际计算开销更小。实操中你要注意 3 个坑路由崩溃routing collapse训练初期如果负载均衡不做约束几乎所有 token 都涌向同一个专家其他专家闲置模型退化。解决办法是加辅助负载均衡损失但系数不能太大太大会把专家的专业性破坏掉。专家容量capacity设置每个专家能处理的 token 数量有上限设得太小丢 token设得太大等于没做稀疏。一般建议从 1.0~1.25 的容量因子起步慢慢调。细粒度不代表“越细越好”专家切得太碎路由选择和参数调度开销会反超收益。我实测下来专家维度在 64~128 之间是一个比较划算的范围。MoE 适合的场景很明确你想拥有超大模型的容量但训练预算只够中等稠密模型的开销。需要注意的是MoE 的显存优势在训练阶段如果你最后要部署推理总参数量大反而会让加载变慢需要配合后面讲的量化手段。2.2 第2招低秩压缩注意力把 KV 冗余砍掉Transformer 里 Attention 模块是参数量和计算量的大头尤其长序列训练时KV Cache缓存每一层的 Key 和 Value 张量会吃掉海量显存。标准多头注意力里每个 head 都要存一份完整的 K 和 V序列一长缓存以平方级别增长。DeepSeek 系论文里非常关键的一个设计就是把 KV 先压缩到低维潜空间再在这个潜空间里做注意力。这就是通常说的多头潜在注意力MLA思路。这个思路的本质是低秩分解既然 K、V 矩阵里有大量冗余信息那就用一个低秩投影把它们压缩成更短的向量。每个 token 只需要缓存这份低维潜向量而不是完整的一串 K 和 V。序列越长省得越多。有朋友问过我“压缩之后注意力表达会不会变弱”这个问题要分两面看。低秩压缩确实会丢掉一部分高频细节所以论文里特意把位置编码的处理单独拆出来跟低秩压缩解耦避免位置信息在压缩过程中被抹掉。实际效果是在支持长上下文的任务上显存占用大幅下降模型能力并没有明显退步。如果你不想从头改注意力结构也可以把低秩分解当作一个“事后优化”手段对已经训好的模型做 SVD奇异值分解把大的权重矩阵拆成两个小矩阵相乘然后微调恢复。比如一个 1024×1024 的矩阵用 128 的秩近似成 1024×128 128×1024参数量直接砍到四分之一。实操建议潜向量维度一般取原始维度的 1/4 到 1/8低于 1/8 后掉点会比较明显。低秩压缩后的层建议跟着一起训练让模型自己学会适应压缩带来的信息瓶颈不要压缩完直接部署。长上下文场景收益最大短文本任务收益有限别盲目上。2.3 第3招跨层参数共享一套参数跑所有层Transformer 的每一层都有自己独立的权重如果让所有层共用同一组权重模型参数量直接除以层数。这个思路的代表工作是某经典小参数模型它把主干网络的所有层共享一组参数最终用很小的参数量达到了当时不错的效果。跨层共享的好处是立竿见影的参数量骤降、显存占用骤降、部署文件变小。但它有一个明显的副作用——深层网络本应逐层抽象出不同层次的特征共享参数后这个能力会被削弱模型表达能力下降。所以共享参数的模型通常需要训练更久才能收敛到同等水平。如果全量共享太激进可以考虑几个变体分组共享比如每 2 层或每 3 层共享一组参数在压缩和表达能力之间折中。只共享部分子层比如共享 Attention 权重但保持 FFN 独立或者反过来。周期性共享每隔几层用一个循环结构类似 RNN 的思路。实操中我比较推荐从分组共享入手而不是一上来就全共享。全共享模型的收敛速度会慢很多训练总步数可能需要翻倍最后省下的训练成本可能又被额外的训练步数吃回去得不偿失。另外注意跨层共享对训练稳定性有影响学习率建议比普通 Transformer 调低 20%~30%否则深层梯度容易异常波动。3. 训练级降参让模型少学一点多余的东西架构级方法适合从零设计模型。但更多时候你手里已经有一个现成的大模型底座需要的只是“用更少的可训练参数达到接近的效果”或者“把大模型浓缩成一个小模型”。这时候就要用训练策略层面的手段。3.1 第4招知识蒸馏让大模型带出小模型这是最直观的一招不去从头训一个小模型而是让一个大模型当“老师”小模型当“学生”学生模仿老师的输出。蒸馏的关键在于“软标签”。老师模型给出的不是硬性的 A/B/C 答案而是一组概率分布。比如“这张图是猫”的概率 0.7、是狗的概率 0.2、是狐狸的概率 0.1这组分布里包含了老师对样本的理解——狗长得像猫是因为都有耳朵狐狸比狗更像猫是因为体型相近。学生模型学着拟合这个分布能接触到比硬标签丰富得多的监督信息。实际做蒸馏时有几个超参需要特别小心温度 TT 越大概率分布越平滑学生能学到更多细粒度关系T 太小就退化成硬标签。一般 2~8 之间比较常用。KL 损失权重软标签损失和真实标签损失的配比常用 0.5 起步逐步调。数据分布不要只拿老师训过的数据蒸馏要混一些新鲜的真实数据否则学生只会复制老师的偏见。DeepSeek 系列论文里有一个特别值得参考的做法不只用老师的最终输出做蒸馏而是把老师生成的完整推理链一步步的中间思考过程拿来当训练样本。学生学习的不只是答案而是“怎么想到答案”的路径。这个思路对推理类任务的效果提升非常明显。我当时看完就照着这个思路做了一个小规模实验同样参数量的小模型加了推理链蒸馏的版本在逻辑推理任务上的效果明显高出一截。3.2 第5招结构化剪枝加继续训练瘦身之后要复健剪枝的思路是“先训大再变小”在大模型训练完成后把贡献不大的参数删掉得到一个参数量小得多的模型然后再做短时间的继续训练恢复性能。剪枝分非结构化剪枝和结构化剪枝。非结构化剪枝是把权重矩阵里接近 0 的元素置零矩阵形状不变省的是计算稀疏度但显存和推理加速有限。结构化剪枝则是直接删掉一整行、一整列、整个 head 或整层网络参数文件才会真正变小。怎么判断哪些部分可以剪三种主流依据权重幅值绝对值小的权重对输出影响小优先剪。最简单但不算准。梯度敏感度计算每个参数对 loss 的敏感程度敏感度低的优先剪。比幅值更可靠但计算开销大。激活统计看每个 head / 通道在真实数据上的激活频率长期处于“低激活”状态的组件优先剪。我的个人经验是光看幅值剪效果偏差最大因为有些幅值小的参数在反向传播中作用很大用梯度信息辅助判断最靠谱但要注意梯度噪声最好在多个 batch 上求平均。剪枝之后一定要继续训练这个环节我习惯叫“复健”。复健时要把握三个关键点学习率策略剪完一个阶段后把学习率回退到初始阶段的 1/10 左右再按余弦退火走完。分阶段剪不要一次性剪掉 50% 参数而是每轮剪 10%~20%复健几天再剪下一轮这样每个阶段模型都能缓慢适应。配合蒸馏如果手里有剪枝前的大模型复健时让它当老师效果比单纯用真实标签训练稳定得多。需要提醒的是剪枝本身并不能降低训练阶段的成本——你是在大模型训完或者训练中途才动手的。它的真正价值在于你只需要训一次大模型就能得到好几个不同规格的小模型省下的是一次次从零训练小模型的钱。3.3 第6招冻结主干只训练关键参数如果你只是想在一个已经训好的大模型上做下游任务微调全量更新所有参数其实是件很划不来的事。几十 B、上百 B 的参数光是把优化器状态存下来显存就爆了。参数高效微调PEFT的思路就是冻结绝大部分主干参数只训练一小撮精心挑选的参数。这套思路里最有代表性的就是低秩适配LoRA了。LoRA 的基本做法是原始权重矩阵保持不变在旁边插入两个小矩阵 A 和 B用它们的乘积去模拟权重的变化量。训练时只更新 A 和 B原始权重完全冻结。A 和 B 的维度从一个很小的秩开始比如 8、16、32。假设原始矩阵是 4096×4096LoRA 用秩 16 的话新增参数量只有 4096×16 16×4096 ≈ 13 万相比原来的 1600 多万几乎可以忽略不计。这套方法的效果是有理论底子的预训练大模型本身已经学到了非常强的通用特征下游任务通常只需要在低维子空间里做少量调整。你不需要重新教会它语言只需要让它适配一个特定任务的输出风格。实操中几个容易吃亏的点初始化矩阵 A 用随机高斯初始化矩阵 B 初始化为全零这样才能保证训练刚开始时 LoRA 分支不影响原模型输出。学习率冻结主干模型后可训练参数的量级变小了学习率通常可以比全量微调大一个数量级但要从 1e-4 左右起步去试。秩的选择不是越大越好我自己试下来很多任务秩 16~32 就够用往上加到 128 收益有限反而增加过拟合风险。混合策略如果数据分布跟预训练差异很大单靠冻结主干可能不够。这时候可以只冻结前几层放开最后几层全量微调或者把 LoRA 和部分层更新混着用。这一招的本质是“降低可训练参数量”优化器状态和梯度的显存开销会大幅下降。比如全量微调一个 7B 模型可能需要 60GB 以上的显存用 LoRA 之后十几 GB 就能跑起来还是非常有吸引力的。4. 工程级降参把显存里的参数副本榨干第三梯队的方法不改变模型结构也不改变训练逻辑而是从工程实现层面减少训练时驻留在显存里的参数副本。适合那些模型结构已经定了、但又想硬塞进有限显存里的场景。4.1 第7招低精度表示用 FP8/BF16 给参数减负这是最直接的“省显存”手段用更少比特去表示同一个参数。全精度训练早期普遍用 FP32一个参数占 4 字节7B 模型光参数就 28GB单卡完全没法玩。混合精度训练把模型副本改成 FP162 字节或 BF162 字节同时保留一份 FP32 的“主副本”用于参数更新内存占用立刻减半。关键问题是FP16 和 BF16 怎么选FP16 的精度更高但它的数值范围有限训练大模型时激活值和梯度的动态范围很容易超出边界导致溢出loss 突然变 NaN。BF16 的尾数精度低但动态范围跟 FP32 几乎一样宽不会溢出——大模型训练里“不溢出”往往比“更精确”重要得多。所以我个人在大模型训练里优先选 BF16 而不是 FP16。再进一步就是 FP8 了。把前向传播里的激活和权重压到 FP8反向传播里的权重和梯度也压到 FP8只在优化器更新时保持高精度。这个方案能省一半显存但实现细节极其敏感。我的建议是FP8 训练不要盲冲。如果你没有专门的底层优化经验先跑通 BF16 双副本训练再考虑 FP8而且初期最好只在某些敏感度低的层启用 FP8让模型稳定后再逐步推广。还有一个工程技巧常常被忽略优化器里的 Adam 状态也可以做低精度。普通 Adam 的 m 和 v 都是 FP32一进一出就是 8 字节/参数。用带有误差补偿的 8-bit 优化器可以把优化器状态降到 1~2 字节/参数代价是偶尔出现精度损失但配合误差反馈机制效果基本等同 FP32。不同精度方案的内存占用对比方案模型权重梯度Adam优化器状态每参数总占用FP32全精度4B4B8B16BFP16/BF16混合精度2B4B主副本2B8B约13B去掉主副本复用后实测更少BF168-bit Adam2B4B主副本2B2B约7BFP88-bit Adam1B4B主副本1B2B约6B表格里的“每参数总占用”是粗算实际还要算上激活值的临时显存但优化方向已经很明确了。4.2 第8招优化器状态瘦身与分片让单卡参数变小如果说低精度是把“每个参数吃多少字节”压下来分片技术解决的是另一个维度单卡上到底要放“多少个参数”。还是回到前面那个 7B 模型用 Adam BF16 混合精度训练光参数和优化器状态的显存需求就已经接近 70GB。单卡放不下怎么办最朴素的想法是拆开多张卡每张卡只放一部分参数、梯度和优化器状态。这就是 ZeRO 系列分片技术在做的事。ZeRO 按阶段划分ZeRO-1把优化器状态切分到各卡每卡只维护自己负责的那部分参数的 m 和 v。ZeRO-2优化器状态 梯度都切分。ZeRO-3优化器状态、梯度、模型参数全部切分前向传播需要用到哪层参数哪层就临时从别的卡拉过来。配合 Offload 机制还能把暂时用不到的参数状态挪到 CPU 内存或 NVMe 硬盘里。这样单卡显存占用会被压得特别低代价是卡间通信变多、训练速度下降。很多朋友对“分片”有个误解觉得“参数变小了训练变便宜了”。分片并没有减少总参数量也没有减少总计算量它只是把显存压力从“单卡扛”变成了“多卡分摊”该烧的卡还是得烧只是从“一张大卡”换成了“多张小卡”。这一点在选方案之前必须想清楚。配套的还有两个常用手段梯度累积小 batch 攒够多次再统一更新参数能模拟大 batch 的稳定性顺便减少前向/反向的显存峰值。激活重算Activation Checkpointing不缓存所有层的中间激活反向传播时临时重算用算力换显存。长序列训练里这个技巧往往能省下比参数本身更大的显存。工程级的招数组合起来最极限的情况是模型参数用 BF16、优化器用 8-bit 低精度、ZeRO-3 全分片 CPU Offload、激活全重算最终把单卡显存占用压到只剩一个很小的“驻留参数量”。代价是训练时间明显拉长属于典型的“用时间换资源”。5. 这8招怎么组合使用实操顺序与避坑速查前面 8 招单独看都成立但真正到项目里很少人会只用一招。不同训练阶段适合的手段完全不同组合顺序也很有讲究。5.1 不同阶段的组合建议我做项目时一般这样分从零开始预训练一个大模型以架构级为主、工程级兜底。先在结构上用 MoE 或低秩压缩把“激活参数量”降下来再用 BF16/FP8 ZeRO 分片把显存塞进现有卡群。路线是架构定容量精度和分片定能不能跑。在已有大模型上做下游微调只需要第 4、6 招。LoRA 冻结主干解决显存问题如果微调数据质量高再叠一层蒸馏用小模型把老师的能力沉淀下来。已经训好一个超大模型想部署成小规格走第 4、5 招。先蒸馏出一个中等规格模型再结构化剪枝逐步瘦身剪几轮复健几轮最后配合量化部署。组合推荐矩阵场景首选招数辅助招数不推荐从零预训练大模型第1招MoE、第2招低秩压缩第7招低精度、第8招分片第4招蒸馏没有老师微调已有底座第6招冻结主干第3招跨层共享若可改结构第5招剪枝破坏预训练特征大模型变小模型第4招蒸馏、第5招剪枝第7招量化第1招MoE部署加载仍是大体量显存极度紧张第8招分片Offload第7招低精度无全都要上5.2 我踩过的坑和排查思路第 1 招 MoE 的路由崩溃症状是训练若干 step 后某个专家被激活的频率变成 0。排查时先看辅助负载均衡损失是否正常下降再看 TopK 路由的 logits 是不是出现极大值导致 softmax 饱和。我一般先降低专家容量因子、加大负载均衡损失的权重还是不行就检查学习率MoE 的训练通常需要比稠密模型更低的学习率。第 4 招蒸馏时温度过高T 太大软标签的分布会过于平滑学生模型学到的是“什么都像一点点”的模糊知识下游任务指标不升反降。排查时首看 KL 损失曲线如果 KL loss 一直压不下去就把 T 往小调。经验值是先从 4 开始看指标变化再上下浮动。第 5 招剪枝后 loss 爆炸最常见的原因是一次剪太多。剪枝后模型输出分布剧烈偏移紧接着用大学习率复健loss 不炸才怪。正确做法是剪完一个阶段后先把学习率降到原 1/10跑几百个 step 观察 loss 稳定性稳定后再逐步恢复。第 7 招 FP8 训练 loss spikeFP8 的损失缩放loss scaling策略必须比 FP16 更保守。我习惯把初始 scale 设到 FP16 的数倍然后每检测到一次溢出就把 scale 减半连续若干步不溢出再加回这个循环跑稳之后基本不会再 timestep 式爆 loss。第 6 招冻结主干微调时验证集过拟合这个坑很多人中招。LoRA 可训练参数少模型容量有限训练集上 loss 降到很低、验证集指标却不动。这时不一定要加参数可以先降学习率、加早停、把训练轮数压到原来的 60% 试试实在不行再考虑把秩往上提一点。5.3 一张速查表直接抄招数核心思路省的是什么主要代价/风险推荐场景1. MoE稀疏激活细粒度专家稀疏路由激活参数量、训练算力总参数大、路由易崩溃从零预训练超大容量模型2. 低秩压缩注意力KV压进低维潜空间KV缓存、注意力参数压缩过度会损失表达长上下文的预训练/微调3. 跨层参数共享多层共用一套权重模型总参数量表达能力下降、收敛变慢参数极度受限的部署4. 知识蒸馏大模型带小模型小模型的训练/推理成本依赖老师的质量已有大模型需要小模型5. 结构化剪枝复健删除冗余结构再训练模型实际参数量训练成本不降、恢复训练需要时间大模型后处理/多规格出口6. 冻结主干LoRA只训低秩增量可训练参数量、优化器状态容量有限难学全新能力底座微调、下游任务适配7. 低精度表示FP8/BF168-bit优化器参数内存占用loss溢出、精度损失一切显存紧张的训练8. 优化器分片/Offload参数状态多卡分摊单卡显存占用通信开销大、速度变慢单卡放不下模型时这 8 招我每招都单独测试过也在不同项目里交叉组合过。我的体感是大模型训练里的“省参数”更像是一种权衡艺术你永远不可能一边把所有成本维度全部压到最低一边还指望效果一分不掉。真正靠谱的做法是设定一个明确目标——到底是要省显存、省训练时长、还是省最终部署体积——然后围绕这个目标选两到三个招数组合而不是一次把 8 招全部压上去。每新增一个优化手段就多一组需要维护的超参数和潜在风险项目越到后期这种复杂度往往会比显存问题更让人头疼。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑