deepseek-v3-paper
DeepSeek-V3 Technical Report
摘要全文;正文的模型配置、训练与评测各节没有读
摘要原文:671B 总参数、每个词激活 37B;采用 MLA 与 DeepSeekMoE;无辅助损失的负载均衡策略;多词预测训练目标;14.8T 训练词元。2026-09-07 直接核对摘要。
打开原始来源一题一页 · 技术方法 · 也叫 Mixture of Experts、MoE
把模型里的一层拆成很多个「专家」,每处理一个词只选中其中几个。参数总量可以很大,每个词参与计算的参数量却小得多。
此刻在看:静态解释,这一页的 5 个部分都是这一种。
主张依据 2 类:原始论文、编辑解释。
核实状态:这一页没有需要核实的结论,所以这一维是空的。
表示此刻展示方式,不是准确性等级。
可多选,每种都有实际引用;「本站实验」需有记录。
附范围、时间及必要原因,不等于全页绝对正确。
这一页没有需要核实的结论,所以这一维是空的——不会因为它挂着论文就替它标一个「已核对」。
DeepSeek-V3 总共 6710 亿个参数,论文说处理每个词实际参与计算的只有 370 亿。没被选中的专家这一轮不参与计算,但参数仍然在,通常还要预先加载好。
模型参数越多通常越聪明,但参数越多算得越慢。混合专家把这两件事拆开了:参数总量决定这个模型有多大,每次选中多少决定这一步要过多少参数。(真实的速度还取决于实现、并行方式与通信,参数计数只是其中一项。)
以 DeepSeek-V3 为例,论文里的数字是:总参数 6710 亿,每个词激活 370 亿。按参数计数,它的「体量」是一个 6710 亿的模型,每个词参与计算的参数量却接近一个 370 亿的模型。这两句都是参数账,不是实测的显存或速度。
代价在参数总量。没被选中的专家这一轮不参与计算,但下一个词可能就用到它,所以整份参数通常要预先加载好——具体占多少内存、放在哪(显存、内存、还是按需换入),取决于部署方式,本站没有实测。
这是最容易误解的地方。它们不是按「数学」「写作」「代码」这样分的。分工是训练过程中自己形成的,人看不出规律。所以「哪个专家负责什么」这个问题,通常没有可读的答案。
按暂停会把这一步的文字整段显示出来。这段字本来就是预先写好的,逐字出现只是展示方式,不是模型正在生成。 键盘:焦点在这个实验里时,← → 切换步骤,空格 播放或暂停。
所以「总参数」和「每个词参与计算的参数」是两笔参数账。省下的是每个词要过的参数,不是模型的总参数;实际显存、运算量与延迟这一页没有测。
左边是这一层的专家参数总量,右边是一个 token 选中的那部分。改选中的个数,看这两个数怎么分开。
这两根条都是参数计数,而且只数这一层的专家:专家参数总量 =(路由专家 + 共享专家)× 每个专家的示例参数, 每 token 选中的专家参数量 =(选中的路由专家 + 共享专家)× 同一个示例参数。共享专家每个 token 都选中,所以它一直算在分子里。 每个专家按 20 亿估是这个控件的示例参数,真实模型的专家不一定一样大;两个数都不含注意力、嵌入等非专家层, 所以它们和 DeepSeek-V3 论文里的 6710 亿、370 亿对不上,那两个数是整个模型的。 它们也都不是显存占用、不是运算量、不是延迟:实际要多少显存、算多久,还取决于实现、批大小、并行方式与通信,这个控件一项都没测。 一个 token 不等于一个汉字。默认形状取自论文:256 个路由专家、1 个共享专家、每个 token 选中 8 个; 这个控件要看的是比例怎么随旋钮变,不是复现某个具体模型,也不回答「选几个最好」—— 那还牵涉模型质量与训练方式,这里没有任何证据。
此刻在看:浏览器计算 + 教学脚本——2 个部分各自标着自己的那一种,没有一个徽章能概括整页。
主张依据 3 类:原始论文、本站实验、编辑解释。
部分核对 核实状态:部分核对 · 核于 2026-09-07。
表示此刻展示方式,不是准确性等级。
可多选,每种都有实际引用;「本站实验」需有记录。
附范围、时间及必要原因,不等于全页绝对正确。
这个单元用 DeepSeek-V3 论文里的配置,把「6710 亿参数的模型为什么没那么慢」拆成七步。看完之后,你应该能说出:为什么「总参数」和「每个词参与计算的参数」是两笔不同的账——以及为什么这两笔都还只是参数计数,不等于实际的显存、运算量与延迟。
想自己动手,看这个 跑一个真的路由器,看专家分工有多不均
此刻在看:历史记录展示 + 教学脚本 + 静态解释——3 个部分各自标着自己的那一种,没有一个徽章能概括整页。
主张依据 2 类:本站实验、编辑解释。
作者已逐字核对 核实状态:作者已逐字核对 · 核于 2026-09-08。
表示此刻展示方式,不是准确性等级。
可多选,每种都有实际引用;「本站实验」需有记录。
附范围、时间及必要原因,不等于全页绝对正确。
混合专家的说法是「每个输入只用到几个专家」。听起来很美好。但没人规定它必须选得均匀。如果一小撮专家被反复选中,其余的几乎不干活,那这个结构就白搭了一半——那些专家的参数仍然属于模型,通常要预先加载好,占多少内存取决于部署方式,这一页没有测。这件事到底会不会发生,跑一遍就知道。
说清楚这个脚本量的是什么:它只统计「谁被选中」这一件事。它没有执行任何专家网络,没有训练模型,也没有测吞吐、延迟或显存。
用 DeepSeek-V3 论文里的形状:256 个专家,每个输入选 8 个。路由器给每个专家打分,取分数最高的 8 个。这里的路由器是随机初始化的,没有训练过。
N_EXPERTS = 256
TOP_K = 8
def route(gate, x, bias=None, top_k=TOP_K):
"""给每个专家打分,选分数最高的 top_k 个。
相同分数时的策略是写明的,不依赖排序算法碰巧稳定:
先按分数从高到低,分数完全相同时按专家编号从小到大。
"""
scores = [sum(w * v for w, v in zip(row, x)) for row in gate]
ranked = scores if bias is None else [s + b for s, b in zip(scores, bias)]
order = sorted(range(len(gate)), key=lambda i: (-ranked[i], i))
return order[:top_k] 专家数量和 top-8 这个形状,出自 DeepSeek-V3 论文里讲模型结构的那一节,见页尾来源;本站只核对过那篇论文的摘要,这个形状经转述,未逐字核对。真实模型的路由器是训练出来的,这里没有;所以这一页演示的是「不加干预会不会自己均匀」这个机制,不是任何一个真实模型的实际专家分布。
python3 moe_routing.py 混合专家路由:不加干预的路由器会自己均匀分工吗
配置 256 个路由专家 · 每个输入选 8 个 · 一共 2000 个输入 · 打分维度 16 · 随机种子 0
均衡策略 每 20 个输入调一次偏置,步长 0.02;偏置只影响选谁,不影响加权
选中规则 分数从高到低取前 8 个;分数完全相同时按专家编号从小到大
平均份额 2000 × 8 ÷ 256 = 62.5 次/专家(这是平均数,整数分配不要求谁恰好取到这个数)
这个实验 路由器是随机初始化的,没有训练过
只统计「谁被选中」:没有执行专家网络,没有训练,也没有测吞吐、延迟或显存
均衡用的偏置是按论文思路写的最小实现,不等同论文里的完整算法
换一个种子结果就会变一点,所以下面额外跑了多个种子给出范围
【种子 0 · 不做任何干预】
最忙的专家被选中 257 次 平均份额 62.5 次(4.1 倍)
最闲的专家被选中 0 次
从没被选中的专家 1 个 占 256 个专家的 0.39%
最忙的 10 个专家占了 12.3% 的入选次数 分母 16,000 次 = 2000 × 8
最忙的 64 个(25%)占了 49.3% 均匀分配时应为 25.0%
【种子 0 · 加上最小的负载均衡】
最忙的专家被选中 91 次 平均份额 62.5 次(1.5 倍)
最闲的专家被选中 44 次
从没被选中的专家 0 个 占 256 个专家的 0.00%
最忙的 10 个专家占了 4.9% 的入选次数 分母 16,000 次 = 2000 × 8
最忙的 64 个(25%)占了 28.9% 均匀分配时应为 25.0%
【换 8 个种子(0~7)再跑一遍:固定例是不是特例】
每个种子重新初始化路由器和输入,其余配置不变。下面是这几个种子的最小值 ~ 最大值。
指标 不做任何干预 加上负载均衡
------------------------------------------------------------
最忙专家的入选次数 197 次 ~ 261 次 85 次 ~ 106 次
最闲专家的入选次数 0 次 ~ 1 次 38 次 ~ 44 次
从没被选中的专家 0 个 ~ 5 个 0 个 ~ 0 个
最忙 25% 占的入选次数 49.3% ~ 52.3% 28.8% ~ 29.2%
最忙专家是平均份额的 3.2 倍 ~ 4.2 倍 1.4 倍 ~ 1.7 倍
在这个玩具配置的 8 个种子里,不加干预时最忙的专家拿到 197 ~ 261 次,是平均份额 62.5 次的 3.2 ~ 4.2 倍;
加上这个最小的均衡后落到 85 ~ 106 次。
所以「专家会自己均匀分工」在这个配置下不成立,训练里要专门处理负载均衡。
反过来也要说清楚:不加干预时最忙的 25% 拿到的是 49.3% ~ 52.3%,接近一半,不是「几乎全部」;
8 个种子也只是 8 个样本,不能推广成所有 MoE、所有种子、所有真实模型都会这样。 这段输出实际跑出来: 在哪里跑的:作者本机,arm64 macOS,CPython 3.14.7 你现在打开这一页不会有任何程序被执行。
这 39 行是本页作者在 2026-09-08 用 CPython 3.14.7(arm64 macOS)真实运行得到的,逐字粘贴,一行没删。脚本用固定随机种子、没有任何计时,同一个解释器跑两遍逐字节相同;作者在同一台机器上另外试过 5 个 CPython(3.9.6、3.10.21、3.11.16、3.12.14、3.13.15),这 39 行也逐字节相同。可复现是有边界的:打分那一步是浮点求和,CPython 3.12 起 sum() 改用了补偿求和,同一个输入下 256 个专家里有 158 个的分数末位已经不同,只是这个配置下排序没被这点差异改变;换一种 CPU 架构作者没有试过。`pnpm moe:test` 第 9 组会重跑脚本,和上面这段逐行比对,没有任何掩码。
平均份额是 2000 × 8 ÷ 256 = 62.5 次。实际上最忙的专家被选中 257 次,是平均份额的 4.1 倍;最忙的 64 个(占 256 个专家的 25%)拿走了 49.3% 的入选次数,均匀分配时这一档应该是 25.0%;还有一个专家从头到尾一次都没被选中。
两处容易读歪的地方。一是 62.5 是平均数,不是配额:16,000 次入选分给 256 个专家,整数分配里没有哪个专家必须恰好拿到 62.5 次。二是「从没被选中的专家 1 个」占 256 个的 0.39%,不是 0%——这个脚本按两位小数显示,就是为了不让「少数」看起来像「没有」。在真实模型里,这个专家的参数仍然属于模型,通常要预先加载好;不过这个脚本没有测量任何内存或显存。
给每个专家加一个偏置,只影响「选谁」,不影响加权。谁被选中得多就给它减一点分,谁被冷落就给它加一点分。
if balanced and step % bias_every == 0:
avg = sum(load) / n_experts
for i in range(n_experts):
if load[i] > avg:
bias[i] -= bias_step # 太忙了,降一点分
elif load[i] < avg:
bias[i] += bias_step # 太闲了,加一点分 DeepSeek-V3 论文摘要提到它采用「无辅助损失」的负载均衡策略。这里是按那个思路写的一个最小实现,不等同于论文里的具体做法,也不是复现了 DeepSeek-V3。
同一个种子下,最忙的专家从 257 次降到 91 次,最闲的从 0 次升到 44 次,从没被选中的从 1 个降到 0 个,最忙的 64 个(25%)从拿走 49.3% 降到 28.9%。均匀分配时这一档是 25.0%,所以还没完全铺平,但已经从「四分之一的专家拿走接近一半」变成了「基本铺开」。
只用一个简单的偏置调整就有这么大改善,也说明不做的话问题有多明显。这里比的是同一个种子、同一份输入下的两条路,换个种子两边的绝对值都会变——下一步就换。
一个种子只是一个固定示例。脚本默认接着跑种子 0~7,每个种子重新初始化路由器和输入、其余配置不变,然后报最小值到最大值。不加干预时最忙的专家落在 197~261 次,最忙的 25% 拿走 49.3%~52.3%;加上均衡后最忙的落在 85~106 次,最忙的 25% 落在 28.8%~29.2%。8 个种子的方向一致,幅度有差别。
这里没有拿新种子去挑一个更耸动的结果替换基准。相反,种子 0 的「最忙 25% 拿走 49.3%」正好是 8 个种子里最低的一个(最高的是种子 5 的 52.3%),而它的最忙次数 257 偏在高端(最高是 261)。还有一件事这 8 个样本证明不了:它们都来自同一个玩具配置,不能推广成「所有 MoE、所有种子、所有真实模型都会这样」。
这一页只回答一个很窄的问题:一个随机初始化、没训练过的路由器,会不会自己把输入均匀分给专家。它没有执行任何专家网络,没有训练模型,没有测吞吐、延迟或显存,也没有跑任何真实模型的权重。所有数字都是「被选中的次数」,分母是 2000 × 8 = 16,000 次。
所以看到「最忙的专家被选中 257 次」时,不要读成「它占了 257 份算力」或「它多占了显存」。入选次数、实际运算量、实际显存占用是三笔不同的账,这个脚本只数第一笔。
现在回头看 DeepSeek-V3 论文摘要里那句「首创无辅助损失的负载均衡策略」,就不是一句套话了。在这个玩具实验的 8 个种子里,不加干预的路由器一次都没有自己铺平过,所以负载均衡要被专门设计、专门写进论文。
反过来的话也不要说过头。这里没有证明「少数专家总会吃掉大部分流量」——不加干预时最忙的四分之一拿走的是 49.3%~52.3%,接近一半,不是绝大部分;也没有证明真实的、训练好的 MoE 模型一定会呈现同样的分布。
这一页是「混合专家」的第三级。卡片告诉你它是什么,场景演了一遍一个词怎么用到 8 个专家,这里让你亲眼看到一个没人管的随机路由器会变成什么样。
脚本不需要显卡,不需要装任何东西。默认要跑 8 个种子,作者这台机器上约 8 秒;想快点看结果可以 python3 moe_routing.py --probe-seeds 1,那样就只跑固定例那一个种子。
按 DeepSeek-V3 论文的参数计数,总参数 6710 亿里每个 token 参与计算的约 370 亿。
在 2000 个输入、256 个专家、每个输入选 8 个的玩具实验里,随机初始化的路由器不会自己均匀分工。
路由器给每个专家打分,只选中分数最高的几个,其余的这一轮不参与计算。按 DeepSeek-V3 论文的参数计数:总参数 6710 亿,每个 token 参与计算的约 370 亿,占 5.5%。这是两笔参数账,不是显存与速度的两笔账——实际占多少内存、快多少,取决于实现与部署,这一页没有测。
上面那一栏是整条结论的公共条件;下面每一行另有自己的口径,所以单独摘走一行也带着口径。
| 这个数是什么 | 数值 | 它在什么范围内成立 |
|---|---|---|
| 论文里的总参数 | 6710 亿 | DeepSeek-V3 论文摘要写的 671B 总参数,指整个模型,不是某一层的专家参数 |
| 每个 token 参与计算的参数 | 370 亿 | 论文摘要写的每个词激活 37B;这是参数计数,不是显存占用,也不是运算量或延迟 |
| 参与计算的参数占总参数的比例 | 5.5% | 分子分母都是参数计数,单位都是亿;这一页没有测显存、运算量与延迟
分子 370 ÷ 分母 6710 公式 370 / 6710 * 100 |
在这个固定种子的玩具实验里——随机初始化、没有训练过的路由器,2000 个输入、256 个专家、每个输入选 8 个——不加干预时最忙的专家被选中 257 次,是平均份额 62.5 次的 4.1 倍;加上一个最小的负载均衡后降到 91 次。换 8 个种子重跑,方向都一样:最忙的落在 197~261 次,均衡后落在 85~106 次。这几个数都是入选次数,不是吞吐、延迟或显存。
上面那一栏是整条结论的公共条件;下面每一行另有自己的口径,所以单独摘走一行也带着口径。
| 这个数是什么 | 数值 | 它在什么范围内成立 |
|---|---|---|
| 不加干预时最忙的专家被选中的次数 | 257 次 | 种子 0 的固定例;2000 个输入、每个输入选 8 个,共 16000 次入选分布在 256 个专家上 |
| 平均份额 | 62.5 次 | 2000 × 8 ÷ 256 = 62.5,是平均份额;整数分配不要求哪个专家恰好取到它 公式 2000 * 8 / 256 |
| 最忙的专家相对平均份额的倍数 | 4.1 倍 | 两边都是入选次数,所以这个倍数也是入选次数之比,不是吞吐、延迟或显存之比
分子 257 ÷ 分母 62.5 |
| 加上最小负载均衡后最忙的专家被选中的次数 | 91 次 | 同一个固定例,只多了一个最小的负载均衡;输入与初始 gate 都没变 |
| 换 8 个种子后最忙的专家入选次数范围 | 197~261 次 | 种子 0~7 各跑一遍,不加干预时最忙专家入选次数的最小值到最大值 |
| 换 8 个种子后均衡完最忙的专家入选次数范围 | 85~106 次 | 同样这 8 个种子,加上负载均衡之后的最小值到最大值 |
deepseek-v3-paper
摘要全文;正文的模型配置、训练与评测各节没有读
摘要原文:671B 总参数、每个词激活 37B;采用 MLA 与 DeepSeekMoE;无辅助损失的负载均衡策略;多词预测训练目标;14.8T 训练词元。2026-09-07 直接核对摘要。
打开原始来源