训练一个 671B 参数的大模型要花多少钱?这个数字在过去几年里被炒成了某种军备竞赛的入场券,动辄上亿美元。DeepSeek-V3 给出的答案是 558 万美元——按 H800 每小时 2 美元的租金折算,完整训练只用了 278.8 万 GPU 小时。这账不是靠抠出来的,而是算法和系统两头一起压出来的。这篇把技术报告里的成本结构和它背后的几个机制拆一遍。

成本结构先看清楚

先纠正一个流传很广的错误说法:V3 不是「1024 块 GPU」训出来的。报告写得很清楚,训练集群是 2048 块 NVIDIA H800。成本的拆分也白纸黑字列在 Table 1 里,我把它写成一段能直接跑的小脚本,方便随时复算:

# DeepSeek-V3 训练成本账(报告 Table 1,假设 H800 租金 $2/GPU 小时)
stages = {
    "预训练": 2_664_000,   # H800 GPU 小时
    "上下文扩展": 119_000,
    "后训练": 5_000,
}
price = 2  # 美元 / GPU 小时
total = sum(stages.values())
print(f"总 GPU 小时: {total:,}")                       # 2,788,000
print(f"总成本: ${total * price / 1e6:.3f}M")          # $5.576M
for name, hours in stages.items():
    print(f"{name}: ${hours * price / 1e6:.3f}M")

几个数字值得单独拎出来:预训练 14.8 万亿 token,占掉 266.4 万 GPU 小时,也就是 532.8 万美元的大头;每训 1 万亿 token 只要 18 万 GPU 小时,在 2048 块 H800 上约等于 3.7 天,所以预训练不到两个月就完成。整个训练过程没有发生过不可恢复的 loss 尖峰,也没有做任何回滚——这一点对成本也很关键,因为大模型训练里最贵的往往不是算力,而是训到一半崩了重来。V3 的这套稳定性,本身就省掉了一笔看不见的「重跑钱」。

算法侧:让每个 token 都便宜

成本能压下来,第一层是算法让「算同样的东西」需要的资源变少。V3 的三个关键设计,本质都在省。

第一个是 MoE 的稀疏激活。671B 是总参数,但每个 token 只激活 37B。具体结构是每个 MoE 层有 1 个共享专家加 256 个路由专家,每个 token 激活其中 8 个路由专家加那个共享专家。也就是说,模型「很大」是为了容量,但推理和训练时「只动一小部分」是为了速度。路由怎么选、怎么保证负载均衡,报告里用的是无辅助损失方案——不往 loss 里加惩罚项,而是给每个专家一个可调的 bias,只用它来影响路由、不参与梯度:

# DeepSeekMoE 的 top-k 路由 + 无辅助损失负载均衡
def route_token(hidden, expert_bias, top_k=8):
    # 专家得分 = 门控 logits + 动态 bias;bias 只改路由,不回传梯度
    scores = gate_logits(hidden) + expert_bias
    top_ids = topk(scores, top_k)
    return top_ids, softmax(scores[top_ids])

def adjust_bias(expert_bias, load, target):
    # 过载的专家调低 bias,欠载的调高,让负载逐步趋于均匀
    return expert_bias + 1e-3 * (target - load)

第二个是 MLA(多头潜在注意力)。标准多头注意力里,每个 token 每头都要存一套 K 和 V,KV cache 随序列长度线性膨胀,是长上下文推理显存的主要来源。MLA 的思路是把 K、V 压成一个低秩的潜向量,推理时再上投影还原,显存占用就砍下来了:

# MLA 对比标准 MHA 的 KV cache 占用(示意)
def kv_cache_mha(seq, heads, head_dim, dtype=2):
    return seq * heads * head_dim * 2 * dtype   # 每头存 K 和 V

def kv_cache_mla(seq, latent_dim, dtype=2):
    return seq * latent_dim * dtype              # 只存一个低秩潜向量

seq = 4096
print(f"MHA: {kv_cache_mha(seq, 32, 128) / 1e6:.1f} MB")
print(f"MLA: {kv_cache_mla(seq, 512) / 1e6:.1f} MB")

第三个是多 Token 预测(MTP)。常规训练每次只预测下一个 token,V3 加了一个 MTP 模块,让模型同时预测后续多个 token,同等算力下数据的利用效率更高。这三个设计放到一起,才让「671B 参数」和「37B 激活」这两个悬殊的数字能同时成立——大而不笨。

系统侧:把算力利用率顶满

算法省的是「量」,系统省的是「利用率」。V3 在系统层最狠的一招是全流程 FP8 混合精度训练——不是只在前向用 FP8 做做样子,而是把激活、权重、梯度都量化到 FP8,再配细粒度的量化和累加精度提升,把单卡的有效算力拉上去。配合 DualPipe 流水线并行,让前向和反向、通信和计算互相重叠,2048 块卡的空转时间被压到很低。跨节点的 MoE all-to-all 通信也单独做了优化,用 NVLink 加 IB 双路走,让「每 token 只激活 8 个专家」这个稀疏性在分布式层面真正兑现成速度,而不是被通信吃掉。少了这一层,算法侧省出来的 token 效率,会被 2048 块卡之间互相等来等去给吐回去。

这套账的边界

有两个地方必须说清楚,否则很容易被误读。第一,558 万美元只覆盖官方训练的正式成本,报告明确说它不包括架构搜索、算法消融、数据处理这些前期研究的开销——换句话说,这是「复现一次」的成本,不是「从零研发」的总投入。第二,无辅助损失的负载均衡不是免费午餐,它换来的是 loss 不被惩罚项污染,但代价是要靠 bias 的动态调整去维持均衡,调整节奏不对就可能出现专家负载漂移。对想自建大模型的团队,真正能抄的不是「用 2048 块 H800」这个数字,而是「算法和系统两头一起省」的这套思路:先看算法能不能把 token 算便宜,再看系统能不能把利用率顶满,最后再谈堆多少卡。