
简介DeepSeek-V3技术报告PDF面向大模型研究者、算法工程师及希望深入理解混合专家架构的开发者系统呈现671B总参数、每token激活37B的MoE语言模型设计思路与实验结论。报告围绕多头潜在注意力MLA、无辅助损失负载均衡的DeepSeekMoE、多token预测训练目标展开涵盖14.8万亿高质量token预训练、监督微调与强化学习全流程并涉及FP8混合精度训练、DualPipe计算通信重叠等工程细节。资源含1个PDF文件包体约1.81MB便于随查随用正文给出MMLU-Pro、GPQA-Diamond、MATH 500、AIME 2024、Codeforces与SWE-bench等基准对比以及与开源、闭源模型的性能差距分析同时披露2.788M H800 GPU小时的训练开销和全程无损失尖峰、无回滚的稳定性记录。目前已有481人学习适合需要复现思路、撰写综述或做架构选型参考的读者。1. 671B 参数只激活 37BDeepSeek-V3 技术报告里最该先读的三件事2048 张 H800 跑完一次 671B 参数模型的预训练账单是 5.328M 美元整个预训练阶段 2664K GPU 小时折算下来每处理 1T token 只要 180K H800 GPU 小时也就是 3.7 天。这组数字来自 DeepSeek-V3 技术报告的成本表比 Figure 1 里那堆柱状图更值得先看因为它意味着有人把 MoE 训练的通信、精度、显存三块硬骨头同时啃下来了。多数人打开这份 PDF 的动作是直奔基准分数MMLU 88.5、MMLU-Pro 75.9、GPQA 59.1然后关掉。但真正能搬到自己项目里的东西在第二、三章MLA 怎么把 KV 缓存压到低维潜变量、无辅助损失负载均衡怎么用一个偏置项顶掉辅助损失、FP8 分块量化在什么颗粒度上算缩放因子才不至于把训练跑崩。这三件事分别对应推理显存、训练稳定性和算力成本正好是 MoE 落地最容易卡住的地方。这份材料的定位是工程向技术报告不是教程读者画像很清楚做推理部署、训推框架、或者在自研模型里考虑上 MoE 的工程师。下面几章按架构、训练工程、预训练、后训练的顺序拆最后落回怎么把这份 PDF 本身变成可检索、可对照的数据源。2. MLA 潜变量压缩与 DeepSeekMoE 路由671B 参数怎么只激活 37B总参数 671B、每 token 激活 37B这个比例不是靠单纯堆专家堆出来的而是两套结构配合的结果注意力侧用 MLA 把 KV 缓存压下去FFN 侧用细粒度专家加共享专家把参数摊开但只算一小部分。分开看这两块再合起来看路由参数账才算得清。2.1 Multi-head Latent Attention缓存的是潜变量而不是 K/V标准多头注意力在解码时每层每 token 都要缓存完整的 K 和 V序列一长KV 缓存直接吃掉大半显存。MLA 的做法是先把隐状态投影成一个低维潜变量推理时只缓存这个潜变量需要 K、V 时再用上投影矩阵还原。由于上投影矩阵可以和注意力的投影矩阵合并权重吸收这条还原路径并不会在每一步解码上额外加算力省的是显存和带宽。位置编码这里有个容易忽略的细节RoPE 对位置敏感没法直接塞进被压缩的潜变量里所以 MLA 走了解耦方案额外保留一个很小的 RoPE 维度单独做旋转再拼回 K 上。以 DeepSeek-V2 公开的实现为准KV 潜变量维度取 512、每个 head 的解耦 RoPE 维度取 64V3 沿用同一套设计。def kv_cache_bytes(tokens, layers, heads, head_dim, dtype_bytes, latent_dim512, rope_dim64): 粗略估算两种注意力在推理时的 KV 缓存占用字节 # 标准 MHAK 和 V 都要按 head 全量缓存 mha tokens * layers * heads * head_dim * 2 * dtype_bytes # MLA只缓存潜变量外加解耦 RoPE 那一小段 K mla tokens * layers * (latent_dim rope_dim) * dtype_bytes return mha, mla # 按 61 层、128 个 head、head_dim128、BF162 字节算一个 128K 序列 mha, mla kv_cache_bytes(128 * 1024, 61, 128, 128, 2) print(fMHA {mha / 2**30:.1f} GiB MLA {mla / 2**30:.1f} GiB 比值 {mha / mla:.1f}x)这段代码只算量级layers、heads、head_dim换成自己模型的配置即可latent_dim和rope_dim保持 MLA 的两个压缩维度。跑出来的比值通常在两位数这也是长上下文部署敢把序列开大的前提——同样的卡MLA 能把 batch 开得更大。要注意的是这里没算上投影矩阵的显存和算子开销实际收益会略低于纯公式估算。2.2 DeepSeekMoE细粒度专家加共享专家MoE 层把原来一个大 FFN 拆成很多个小专家每个 token 只走其中 top-K 个。DeepSeekMoE 的两个改动是把专家切得更细专家数量多、单个专家的中间维度小以及固定保留一个共享专家常驻计算。细粒度带来的是组合空间变大专家更容易分化出领域特征共享专家负责兜住所有 token 都要用的通用知识减少路由专家在通用模式上的重复学习。路由打分是理解后面均衡策略的前提token 的隐状态和专家向量做内积得到亲和度加上偏置项后取 top-K被选中的专家按归一化权重加权求和。关键在于偏置项只参与「选谁」不参与「选完以后权重是多少」所以它不会改变前向数值的语义只是改变选择行为。组件关键设计直接收益注意力MLA 潜变量压缩加解耦 RoPEKV 缓存降到潜变量量级FFN细粒度路由专家加共享专家总参 671B激活 37B路由无辅助损失偏置均衡不牺牲语言建模目标训练目标多 token 预测MTP评测提升且可做推测解码2.3 无辅助损失的负载均衡怎么用偏置项替代惩罚项传统 MoE 靠辅助损失把负载推向均衡代价是这个 loss 和语言建模目标打架——模型为了让专家用得平均会牺牲一部分表达质量。V3 的方案是给每个专家挂一个偏置b_i只在 top-K 选择时加到亲和度上然后按训练步动态调整某个专家过载就减偏置欠载就加偏置。整个过程没有额外的 loss 项均衡通过参数更新间接实现。def update_expert_bias(expert_load, bias, gamma1e-3): expert_load: 本步每个路由专家实际收到的 token 数 bias: 每个专家的路由偏置初始为 0只参与 top-K 选择 gamma: 更新步长越大收敛越快但越容易在均衡点附近抖动 target expert_load.mean() for i in range(len(bias)): if expert_load[i] target: bias[i] - gamma # 过载降低被选中的概率 else: bias[i] gamma # 欠载提高被选中的概率 return biasgamma是这里唯一的调参点报告口径下它对应「偏置更新速度」。取值偏大专家负载会在目标值上下反复横跳取值偏小均衡要跑很久才收敛。实际工程里还会配一个权重很小的序列级辅助损失兜底防止单条序列内部出现极端倾斜。附录里对比了基于辅助损失和基于偏置两类模型的专家特化模式结论是偏置方案下专家的领域分化更明显这也印证了去掉辅助损失确实释放了表达空间。2.4 多 token 预测一个额外训练目标顺带换来推测解码MTP 让模型在每个位置不只预测下一个 token而是并行预测后续若干个 token这些预测头共享主干。报告给出的观察是它在评测基准上带来提升另一个附带好处是这些额外预测头可以直接当推测解码的草稿模型用推理时先用它们猜一串 token再由主模型验证命中就省下一次前向。做部署的人可以把它理解成「训练阶段顺手训了个小 draft」不需要额外维护第二套模型。2.5 批量级和序列级均衡的差别这两种均衡的差别在统计范围批量级看整个 batch 里各专家的累计负载序列级看每条序列内部的负载分布后者在短序列上会放大约束。报告在这一节的结论偏向批量级理由是约束范围放宽后专家更容易形成特化而不会因为要照顾每条序列的均匀性被迫泛化。换到自己的训练代码里这个选择对应的就是负载统计的归约维度——沿 token 维归约还是沿 batch 维再归约一次。3. FP8 分块量化与 DualPipe把 2788K GPU 小时压下来的训练工程架构决定了参数量怎么摊训练工程决定这些参数能不能在合理成本内训完。DeepSeek-V3 在 14.8T token 上完成预训练没有出现不可恢复的 loss spike也没有回滚同时把 FP8 训练首次验证到了这个规模这两件事放在一起看说明低精度训练的关键不在「敢不敢用 FP8」而在缩放因子怎么算、哪些算子必须留高精度。3.1 FP8 混合精度分块缩放与精度保护路径FP8 的表示范围窄如果整个张量共用一个缩放因子张量内部的离群值会直接把其他数值挤到精度之外。V3 采用的是细粒度分块量化激活按每 token 每 128 个通道一组算缩放因子权重按 128×128 的块算缩放因子块内取绝对值最大值再折算。分块越细离群值的影响范围越小量化误差越可控。import torch def quant_fp8_blockwise(x, block128, eps1e-8, fp8_max448.0): 按最后一维分块量化到 FP8(E4M3)返回量化值与逐块缩放因子 t, c x.shape # x: [tokens, channels] pad (block - c % block) % block xp torch.nn.functional.pad(x, (0, pad)) if pad else x xb xp.view(t, -1, block) amax xb.abs().amax(dim-1, keepdimTrue).clamp(mineps) scale fp8_max / amax # 每块独立缩放防离群值污染 xq (xb * scale).to(torch.float8_e4m3fn) return xq, scale # 反量化xq.float() / scale x torch.randn(4096, 7168) * torch.rand(4096, 1) # 模拟通道间量级差异 xq, s quant_fp8_blockwise(x, block128) err ((xq.float() / s).view(4096, -1)[:, :7168] - x).abs().mean() print(f平均绝对误差 {err:.5f})block对应报告里的分块粒度改小精度更好但缩放因子数量上升、元数据开销变大fp8_max448是 E4M3 的取值上限换格式要同步改。除了分块量化还有两条精度保护线LayerNorm、softmax、MoE 门控这类对数值范围敏感的算子保留 BF16FP32累加路径用高精度累加器避免低精度下多次相加的误差累积。附录里做了 FP8 与 BF16 的对照消融损失曲线的相对差异被压在一个很小的区间内这是它敢在大规模上用的依据。3.2 DualPipe让前向、反向和 all-to-all 互相遮挡MoE 训练的通信大头是跨节点的 all-to-all——token 要被送到它选中的专家所在设备算完再送回来。DualPipe 的思路是把一个 batch 切成若干 chunk前向和反向交错排布并让流水线两端同时有活干从而压掉流水线气泡。报告里的关键论断是只要计算与通信的比例保持恒定模型继续放大时跨节点细粒度专家的 all-to-all 开销可以接近被完全隐藏。落到实际部署网络层的配置直接决定能不能吃到这个收益。我一般会在启动脚本里显式指定 RDMA 网卡和通信算法避免 NCCL 自己挑错路径export NCCL_IB_HCAmlx5_0,mlx5_1 # 指定参与 RDMA 的网卡多卡机器别省略 export NCCL_NET_GDR_LEVELPHB # GPU 直通网卡减少一次主机内存拷贝 export NCCL_NSOCKS_PERTHREAD4 # 每线程 socket 数跨节点 all-to-all 常用 export NCCL_SOCKET_NTHREADS2 # 主机侧线程数 export CUDA_DEVICE_MAX_CONNECTIONS1 # 单连接保证通信与计算在同流上排队节点内走 NVLink、跨节点走 InfiniBand 是硬性前提NCCL_IB_HCA写错会出现「能跑但极慢」的典型症状用nccl-tests里的 all-to-all 打一遍带宽就能定位。chunk 数量、micro-batch 大小、warmup 步数是 DualPipe 侧的主要旋钮chunk 太大会退回气泡太小则每段计算不够长遮挡不住通信。3.3 显存压缩不开张量并行也要训得下去报告明确提到通过精细的显存优化训练 V3 时不需要代价高昂的张量并行。省掉 TP 的直接好处是少了一整套层内通信跨节点 all-to-all 的拓扑也更干净。常见做法是重计算激活值不存全量反向时重算、优化器状态分片与卸载、参数和梯度分片。实际调优顺序建议是先测激活峰值确定重计算粒度再看优化器状态占了多少最后才考虑卸载——卸载换来的显存往往要用通信还回去。3.4 训练成本拆解阶段H800 GPU 小时成本按 $2/卡时预训练2664K$5.328M上下文扩展119K$0.238M后训练5K$0.01M合计2788K$5.576M这张表只覆盖正式训练不含前期架构、算法和数据的消融实验成本换算成本时别把它当成项目总预算。真正值得抄的思路是预训练和后训练的算力比例后训练只花了 5K GPU 小时说明预训练阶段把能力底座打厚后面的对齐成本可以压得很低。4. 14.8T token 预训练与 32K 到 128K 的长上下文扩展预训练阶段的信息在报告里相对克制但几个关键选择值得拿出来对照数据规模 14.8T token、两阶段上下文扩展、超参配置以及整段训练没有出现不可恢复的 loss spike。这几项组合起来才是「稳定跑完」的原因。4.1 数据构建规模之外的过滤与配比14.8T token 的描述是「多样且高质量」报告没有给出完整配比表但从消融章节反复强调代码与数学能力可以反推代码、数学、多语言这几类数据在采样权重上是被刻意加强的。工程上可复用的做法是分层采样——先按领域分桶再在桶内按质量分档设置采样概率最后对同一文档做多轮去重精确去重加近似去重。质量过滤常见的是分类器打分加启发式规则两条线并行规则负责剔除格式异常和重复模板分类器负责挡掉低信息密度文本。超参类别关注点调整方向学习率调度warmup 步数与衰减曲线warmup 过短易在早期出现梯度尖峰批量大小随训练推进逐步放大放大步长与学习率需要同步序列长度预训练期相对短后期再扩先短后长避免早期算力浪费MTP 权重额外预测头的 loss 权重权重过高会挤压主任务专家偏置步长均衡收敛速度与批量大小匹配避免抖动4.2 长上下文扩展两阶段从 32K 到 128KV3 的长上下文是分两步做的先把最大长度扩到 32K再进一步扩到 128K。分阶段的意义在于让模型先在中等长度上适应位置编码的变化再往更长推直接用 128K 一步到位容易在早期把注意力分布打散。扩展时的常规手段是调整 RoPE 的旋转基频或做插值同时在数据侧提高长文档的采样比例否则模型见不到足够的长距离依赖样本。# 两阶段扩展的启动示例先 32K收敛后再切 128K不要跳步 python train.py \ --model_name deepseek_v3_base \ --seq_len 32768 \ # 第一阶段长度 --rope_scaling yarn \ # 旋转基频缩放方式 --rope_factor 4 \ # 与目标长度的比例匹配 --data_mix long_doc:0.3,code:0.3,general:0.4 \ --init_from pretrain_ckpt # 第二阶段加载上一阶段权重长度再翻两番学习率相应调低 python train.py --model_name deepseek_v3_base --seq_len 131072 \ --rope_factor 16 --lr_scale 0.3 --init_from ctx32k_ckptrope_factor要与目标长度成比例lr_scale在第二阶段调低是为了避免破坏已经学好的中距离依赖data_mix里长文档的占比在第二阶段要继续提高。验证扩展是否成功别只看 loss跑一遍「大海捞针」式的检索任务看模型在 64K、96K 位置上的召回是否掉得厉害掉得多说明位置外推没吃透。4.3 训练稳定性loss spike 怎么定位报告强调整个训练过程没有出现不可恢复的 loss spike也没有回滚。这背后是 FP8 缩放因子保护、路由不引入额外抖动、数据质量过滤共同作用的结果。真遇到 spike 时我一般按这个顺序排查先看梯度范数是不是突增再看是不是某个数据分片进来时集中出现然后检查各专家的负载极值有没有被顶到几倍均值最后才怀疑 FP8 的缩放因子出现溢出。顺序错了容易在数据质量上白耗时间。5. SFT、GRPO 与 R1 蒸馏后训练阶段的推理能力搬运后训练只花了 5K GPU 小时却把基准表现从基座推到了能跟头部闭源模型掰手腕的位置靠的是三件事的组合高质量 SFT 数据、GRPO 强化学习、以及从 R1 系列蒸馏长链推理能力。这三块是有先后依赖的顺序换掉效果会明显打折。5.1 监督微调数据长度和风格一起管SFT 阶段除了堆数据量报告特意提到要维持模型精度与生成长度之间的平衡。这条约束在实践里对应的是数据侧的长度分布控制如果 SFT 数据里长回答占绝对多数模型会养成「不管问什么都长篇大论」的习惯推理成本上升而准确率未必提高。常见做法是按任务类型设定长度区间对超长样本做裁剪或重写同时在训练配置里加上长度相关的采样权重。5.2 GRPO不要 critic 的组内相对优势GRPO 的核心是去掉价值网络用同一 prompt 下采样出的多条回答的组内统计量当基线。奖励高的回答被正强化低的自然后退优势值用组内均值和标准差归一化得到这样就不需要额外训一个 critic 来估状态价值。import torch def grpo_advantage(rewards, group_size16): rewards: 同一 prompt 采样 group_size 条回答得到的奖励列表 返回每条回答的相对优势组内归一化无需 critic r torch.tensor(rewards, dtypetorch.float32) assert r.numel() group_size adv (r - r.mean()) / (r.std(unbiasedFalse) 1e-6) return adv print(grpo_advantage([0.2, 0.9, 0.5, 0.4] * 4)) # 组内拉开差距才有效group_size是关键超参太小组内均值和方差估计噪声大优势信号不稳太大采样成本线性上升。工程上还要配策略比裁剪区间和 KL 惩罚系数前者防止单步更新跨度过大后者防止模型跑离参考模型太远。奖励侧由奖励模型给出V3 的奖励模型是在偏好数据上训出来的报告也提到它可以反过来当作生成式奖励模型使用。5.3 从 R1 蒸馏把验证与反思模式搬进标准模型后训练里最有意思的一步是从 R1 系列的长链推理模型蒸馏推理能力。做法不是复制 CoT 的啰嗦形式而是把 R1 的验证和反思模式提取出来融进 V3 的回答里——也就是说模型学会的是「给出答案后回验一遍」这种行为模式而不是把推理过程全部铺开。同时还要控制输出风格和长度避免蒸馏之后回答变得冗长。落到流水线里就是用 R1 生成大量带验证、反思轨迹的样本过滤掉错误轨迹后混入 SFT 数据再交给 RL 阶段做偏好对齐。评测维度代表基准观察到的位置知识MMLU 88.5 / MMLU-Pro 75.9 / GPQA 59.1开源模型中最强接近头部闭源事实性SimpleQA / ChineseSimpleQA中文事实性优于对照的闭源模型数学MATH-500 / AIME 2024非长链推理模型中领先代码Codeforces / SWE-bench Verified竞赛类编程表现突出5.4 DeepSeek-V3 作为生成式奖励模型与自奖励报告里有一节专门讲 V3 自己当生成式奖励模型的评估结果以及自奖励机制。思路是用模型对候选回答打分、再把打分结果反过来当训练信号减少对独立奖励模型的依赖。这条路的风险是奖励会被模型自身的偏好带偏所以实践中通常会和外部奖励信号混合使用并定期用人工标注集做校准检查。6. 用 Python 解析这份 PDF把基准数据提取成可对照的结构化表格这份技术报告是双栏排版表格和公式混排直接pdftotext出来的顺序会乱掉Figure 1 那种图形化柱状图的数值更是根本提不出来。我的做法是先用块坐标重建阅读顺序再做数值抽取最后把结果落成 CSV方便和自己跑出来的评测结果逐项对表。import fitz # PyMuPDF import re, csv PAT re.compile(r^\s*(\d{2,3}\.\d)\s*$) # 独立成行的两位/三位分数 rows [] with fitz.open(DeepSeek-V3 Technical Report.pdf) as doc: for pno in range(len(doc)): page doc[pno] blocks page.get_text(blocks) # 每块带 x0,y0,x1,y1 坐标 mid page.rect.width / 2 # 双栏分界 left sorted([b for b in blocks if b[0] mid], keylambda b: b[1]) right sorted([b for b in blocks if b[0] mid], keylambda b: b[1]) text \n.join(b[4] for b in left right) for line in text.splitlines(): if PAT.match(line): rows.append({page: pno 1, score: float(line)}) with open(v3_scores.csv, w, newline, encodingutf-8) as f: w csv.DictWriter(f, fieldnames[page, score]) w.writeheader(); w.writerows(rows) print(f提取到 {len(rows)} 个候选数值)坐标排序是这段代码的关键blocks返回的是无序文本块先按 x 坐标切成左右两栏再各自按 y 坐标排序拼出来的顺序才和阅读顺序一致。正则只捞独立成行的数字是为了避开正文里夹杂的百分比和年份噪声代价是会漏掉表格里带单位的数值——那些通常得交给表格提取工具。抽出来的分数不要直接信第一遍至少人工核三处因为 PDF 里同一个数字可能同时出现在正文和图表标题中。工具适合场景注意点PyMuPDF文本块、坐标、页面对象表格结构要自己按坐标还原pdfplumber规则表格可调线框检测跨页表格需手动拼接camelot有明确线框的表格依赖 Ghostscript环境成本高如果目的是做本地知识库检索别把整份 PDF 一次性切成固定长度片段公式页和参考文献页会污染召回结果。更稳的做法是先按章节标题切分把公式密集的页面单独标记检索时对这类片段降低权重。做完这一步再把报告里的基准分数和自己跑出来的推理结果放进同一张表差异项逐个回查配置——序列长度、量化方式、采样参数通常问题就出在这三处中的某一处。本文还有配套的精品资源点击获取