☰
拆解昇腾950DT NPU微架构:千卡训练MFU、互连与长稳调优
2026/10/23 1:15:38 网站建设 项目流程

聊昇腾950DT的NPU微架构,我一般不建议从规格表上那行算力数字开始看。这几年做大模型训练的人都有个共同体会:纸面峰值和实际每秒能跑多少 token,中间隔着的不是百分之十几的差距,而是一整套微架构、存储层级、互连拓扑和软件栈的配合问题。950DT 这个型号的定位很有意思,它没有走“通用加速卡”的路子,而是明确朝着千卡级超节点、大模型训练这两个方向去设计。换句话说,它的很多架构取舍,是为了服务“几万张卡连成一台机器”这件事,而不是为了让单卡在跑分软件上好看。

这篇内容我打算把这块芯片从计算核心、存储层级、互连设计、长稳工程到上手调优,一层层拆开讲。适合两类人看:一类是正在做训练集群选型、需要判断这类专用 NPU 到底适不适合自己业务的工程师;另一类是已经上手、但发现 MFU 上不去、通信时间吃掉一半、训练动不动挂掉的调优同学。文中涉及的具体参数我会尽量标明是“公开信息的量级”还是“按同类架构推演的示意”,涉及计算的都给公式,你可以代入自己的模型规模重算一遍。

1. 训练一步的时间都花在哪:先算清楚再谈架构

在拆微架构之前,得先把“一步训练”这件事的时间账算清楚。不然看到任何架构设计都会觉得有道理,也都会觉得没必要。大模型训练的每步耗时基本可以拆成三段:计算、访存、通信。理论上后两者能和计算重叠,实际上重叠率能做到多少,直接决定了这块芯片的真实利用率。

1.1 用 FLOPs 和通信量把一步训练量化出来

训练一步的计算量有个经典估算式:前向大约 2ND,反向大约 4ND,合计6ND,其中 N 是参数量,D 是这一步处理的 token 总数。举个示意的例子:一个 100B 参数的模型,单步 global batch 处理 4M token,那么单步计算量约等于 6 × 1e11 × 4e6 = 2.4e18 FLOPs。

接下来算时间。假设单卡 BF16 稠密算力的有效值是 400 TFLOPS(这是示意值,实际以官方规格为准),集群规模 1000 卡,实测 MFU 打到 40%,那么集群有效算力是 1000 × 400e12 × 0.4 = 1.6e17 FLOPS。单步计算时间 = 2.4e18 / 1.6e17 ≈ 15 秒。

这个 15 秒就是你的基准线。后面所有优化,本质都是在跟这个数字较劲。如果你的实测单步是 30 秒,那说明有一半时间没用在有效计算上,要么在等数据搬运,要么在等通信,要么在等某个慢节点。

1.2 三堵墙:显存、通信、功耗,谁也躲不掉

显存墙是最先撞上的。按混合精度训练的常规配置,每个参数要占的字节数大致是:BF16 参数 2 字节、BF16 梯度 2 字节、FP32 主权重 4 字节、Adam 的一阶二阶动量各 4 字节,合计 16 字节/参数。100B 参数就是 1.6TB,这还没算激活值和临时缓冲。所以千卡训练必然要做参数分片,把优化器状态、梯度、参数切到不同卡上——这就是各种零冗余优化器方案存在的理由。专用 NPU 在这一点上能不能省事,取决于它的片上存储和 HBM 配比,以及分片之后集合通信的开销。

通信墙的账也好算。数据并行下的一次全归约,通信量约等于 2 × 参数量 × (N-1)/N,N 大时近似 2S。100B 参数、BF16 就是 200GB 量级的通信量。如果跨节点带宽是每卡 400Gbps,也就是 50GB/s,1000 卡聚合带宽做全归约,理论下限也要几秒。这时候你就明白,为什么这类芯片要把几百张卡塞进一个高速互连域里——不是为了炫技,是为了让这 200GB 少走几跳。

功耗墙常被忽略。单机柜能提供的功率是有限的,单卡功耗降不下来,能塞进一个机柜的卡数就上不去,互连域规模就受限。专用架构在能效上的优势,往往比峰值算力优势更实在。

1.3 专用化换来的东西,和要还的债

950DT 这类训练专用 NPU 的设计逻辑,本质是拿通用性换三样东西:单位功耗的矩阵算力、更大更密的互连域、以及针对训练流程的定制数据通路。代价也很明确——算子覆盖面、框架适配度、调试工具链的成熟度,都需要时间补齐。

我见过不少团队踩的第一个坑就是:拿一个在通用 GPU 上跑得很顺的模型直接迁过来,发现某个自定义算子没有高效实现,图编译器把它拆成了一堆小算子,性能直接掉一半。这跟芯片好坏无关,是生态债。判断要不要用,得先把自己模型里的算子清单拉出来,逐个确认覆盖情况,重点看 attention 变体、归一化、位置编码、MoE 的路由这些非标准件。

2. 计算核心拆解:矩阵引擎、精度档位与那些“配角”单元

微架构层面,训练芯片的计算核心通常由矩阵引擎、向量单元、标量单元和特殊函数单元组成。大模型训练里 90% 以上的 FLOPs 由矩阵引擎贡献,但剩下那不到 10% 的算子,经常是实际吞吐的瓶颈所在。这一节把这几块拆开讲。

2.1 矩阵引擎的数据流:三种驻留方式怎么选

矩阵乘单元的组织方式,业内主流是脉动阵列或者类似的二维乘加阵列。关键是数据流的选择:权重驻留、输出驻留、还是输入驻留。三者的差别在于哪一份数据被反复复用、哪一份需要频繁搬运。

大模型训练的场景比较特殊:权重的生命周期跨越整个训练过程,激活值是每步新生成的,而且 batch 维度通常很大。所以权重驻留、激活流式输入的组合,在“大 batch、大矩阵”的稠密训练里复用率最高。但到了 decode 阶段或者小 batch 场景,矩阵形状变成“瘦高型”,这时输出驻留反而更划算。好的硬件会让这几种模式都能配,由编译器根据形状选;差的硬件只有一种模式,遇到不匹配的形状就掉到峰值的三成。

实操上有个判断方法:拿你模型里最耗时的几个矩阵乘,把 M/N/K 三个维度打印出来,看看是不是长期落在某个固定区间。如果 K 特别小(比如 MoE 的单专家矩阵),那矩阵引擎的效率天然上不去,得靠算子融合或者批处理来凑。

2.2 精度档位:FP8 能用在哪儿,绝不能用在哪儿

训练里的精度不是一刀切,常见的分层是:前向和反向的矩阵乘用 FP8 或 BF16,累加用 FP32,主权重和优化器状态用 FP32,归一化和 softmax 这类数值敏感的算子保持高精度。

FP8 能不能用,取决于三件事。第一是动态范围,FP8 的指数位少,梯度里的小值容易下溢,需要配合缩放因子;第二是误差累积,几百层堆下来,误差会被放大,得靠周期性高精度重算或者随机舍入来压;第三是哪些层不能用,LayerNorm、softmax、残差相加、loss 计算这几处,实测下来降精度的收益极小、风险极大,不值得动。

我在实际调优中的体会是:FP8 的收益主要来自矩阵乘吞吐翻倍和显存带宽压力减半,如果你的模型卡在访存上,收益会比卡在算力上更明显。但一开始别全量开,先选几个不敏感的 block 试,用 loss 曲线和梯度范数做对比,稳定后再扩大范围。

2.3 向量与特殊函数单元:被低估的瓶颈

attention 里的 softmax 包含 exp、求和、除法,这些都在向量和特殊函数单元上跑。矩阵引擎再快,这几个单元跟不上,流水线照样空转。一个常见的现象是:单看矩阵乘利用率是 70%,但整层 attention 只有 40%,中间 30% 就丢在这些逐元素运算和规约上。

解决办法有两个方向。一是硬件侧提高向量单元和矩阵单元的配比,让两边的吞吐匹配;二是软件侧做算子融合,把 softmax 拆散塞进矩阵乘的空隙里,跟数据搬运重叠。前者你改不了,后者是调优的重点。判断一个平台好不好用,看它的编程模型能不能让你方便地写出这种融合——如果只能调用现成算子,遇到非标准 attention 就只能干瞪眼。

3. 存储层级:MFU 的天花板往往卡在搬运上

算力翻倍容易,带宽翻倍难。这是所有加速器共同的困境。950DT 这种面向千卡训练的设计,存储层级的配置思路值得单独讲一节,因为大部分人的性能问题最后都归到这里。

3.1 用算术强度先判断一个算子卡在哪

Roofline 模型的逻辑很简单:一个算子的算术强度 = 计算量 / 访存量,单位是 FLOP/Byte。把它和硬件的“算力/带宽”比值一比,就知道是计算受限还是访存受限。

举个具体的例子。一个 M=4096、N=4096、K=4096 的矩阵乘,计算量是 2MNK ≈ 1.37e11 FLOPs。访存量在理想分块下约等于 (MK + KN + MN) × 2 字节 ≈ 1e8 字节。算术强度约 1370 FLOP/Byte。这个值远高于一般加速器的算力带宽比(通常在几百的量级),所以大矩阵乘是典型的计算受限,放心堆算力。

但如果是 M=1 的矩阵向量乘(decode 阶段的典型形状),计算量降到 2NK ≈ 3.3e7,访存量还是 3.3e7 字节量级,算术强度只有 1 左右。这种就是彻头彻尾的访存受限,算力再高也没用,瓶颈全在 HBM 带宽上。所以同一块芯片,prefill 和 decode 的性能表现能差出好几倍,这是架构决定的,不是调优能逆转的。

3.2 算子融合:把中间结果按在片上

片上 SRAM 的带宽比 HBM 高一个数量级,延迟低两个数量级。所以任何能把中间结果留在片上、不写回 HBM 的优化,收益都很直接。

以 MLP 层为例,标准实现是:矩阵乘1 → 写回 HBM → 读出来做激活 → 写回 → 读出来做矩阵乘2。中间两次往返白烧带宽。融合之后,矩阵乘1的输出直接留在片上,激活在片上做完,直接喂给矩阵乘2。省下的访存量大致等于 hidden 维度乘 batch token 数乘 2 字节乘 2 次。

attention 那边更典型。标准的 QK^T → softmax → 乘 V,中间那个 N×N 的注意力矩阵是访存大户,序列长度一上去就爆。分块计算、把 softmax 的规约拆成在线更新的做法,能把这块中间结果的驻留压到片上,这就是各种高效 attention 实现的核心思路。950DT 这类芯片能不能跑好长序列,很大程度上看它的片上缓冲够不够大、编译器会不会自动做这个分块。

3.3 实测定位:怎么看懂一份性能剖析

工具给出的指标很多,但真正有用的就几个:矩阵引擎利用率、向量单元利用率、HBM 读写带宽占比、流水线停顿原因。我的习惯是先看停顿原因,再看利用率。

如果停顿原因里“等待操作数”占大头,说明是访存瓶颈,往融合和分块方向查;如果“等待流水线”占大头,说明计算单元之间配比不匹配,得看是不是某个单元成了瓶颈;如果各项利用率都不高但也没有明显停顿,那大概率是调度粒度太细,kernel 启动开销吃掉了时间。

还有一个容易被忽略的点:小算子碎片化。图编译之后如果生成几百个小 kernel,每个只跑几微秒,启动开销和同步开销加起来能占到两三成。这时候该做的是算子融合或者图优化,而不是继续调单个 kernel 的参数。

4. 千卡超节点:拓扑决定了并行策略的上限

“超节点”这个词这两年出现频率很高,本质是把传统上跨机柜的互连,收缩到一个更大的高速域里。为什么这么做,得从集合通信的延迟和跳数说起。

4.1 把“机柜”做成“一台机器”到底解决了什么

传统集群里,一张卡到另一张卡如果跨了机柜,要经过网卡、交换机、多级跳转,单次通信延迟在几十微秒量级。而张量并行这种策略,每层都要做全归约或者全收集,通信频率极高,延迟直接叠加到每层耗时里。层数一多,这部分开销能吃掉三成以上的时间。

超节点的思路是把几百张卡放进一个统一的高速互连域,跳数降到一两跳,延迟压到微秒级甚至更低。这样张量并行的通信开销才可能被计算掩盖住。代价是互连成本高、布线复杂、故障域变大。所以这类设计适合的是“模型大到必须用张量并行才能放下”的场景,小模型用不上,反而浪费。

拓扑形态上,全互联、胖树、多维环形各有取舍。全互联的度数和成本随规模平方增长,通常只在小范围内做;胖树扩展性好但收敛比会带来带宽争抢;多维环形成本可控,但跳数随维度增加。你不需要记住具体用哪种,只需要知道一件事:你的并行策略要和拓扑的分层对齐。

4.2 并行策略必须跟着拓扑走

这是最容易出问题的地方。常见做法是:把通信最频繁的张量并行放在域内,把通信频率低的数据并行放在跨域,流水并行按层切分放在中间层。专家并行比较特殊,它的全对全通信对拓扑最敏感,路由不均衡时会出现热点链路。

给个量化的判断方法。假设域内带宽是 B1,跨域带宽是 B2,张量并行每层的通信量是 V,那么每层通信时间约等于 V/B1。如果 V/B1 大于该层的计算时间,张量并行度就不能再往上加了——加了也是纯等待。这个临界点可以算出来,不用猜。

我见过一个典型的错误配置:为了省显存把张量并行开到 8,但这 8 张卡跨了两个域,结果每层通信时间翻了三倍,整体吞吐反而比张量并行 4 更低。显存是省下来了,训练速度掉一半,这笔账不划算。

4.3 集合通信的实测与参数调整

调通信有个基本原则:先测裸带宽,再测业务。用现成的带宽测试工具跑一遍全归约、全收集、全对全,拿到不同消息大小下的实际带宽和延迟曲线。你会发现小于某个阈值的小消息,延迟基本是固定的,带宽利用率极低。这就引出了分桶策略:把多个小消息打包成一个大消息再发,减少通信次数。

分桶大小要试。桶太小,次数多延迟高;桶太大,显存占用高、首包等待时间长,流水线填不满。一般从几 MB 开始试,观察单步时间的变化。并发流数量也要试,太少打不满带宽,太多会互相争抢。

还有个实操细节:通信和计算的重叠要靠流水线切分。把一个大矩阵乘切成若干块,算完一块就触发这一块的通信,让后面的计算和前面的通信同时进行。这个切分粒度同样要试,切太细调度开销大,切太粗重叠不上。

5. 长稳训练:千卡规模下,故障是常态不是意外

单卡跑一天不出错很常见,一千张卡跑一个月不出错基本不可能。这不是质量问题是概率问题,必须从架构和流程两个层面去设计容错。

5.1 先把故障概率算出来,别靠感觉

假设单卡的年度故障率是 5%(这是个示意值,实际取决于批次、散热、负载),换算成 MTBF 大约是 17.5 万小时。1000 张卡并联,集群的整体 MTBF 掉到 175 小时左右,也就是平均一周多就要出一次硬件故障。如果算上网络、存储、电源,这个数字还要再降。

这个算术的意义在于:你必须按“故障随时会发生”来设计训练流程,而不是按“不出故障”来设计。具体落地就是三件事:检查点要频繁且异步,不能阻塞训练;故障后要能快速定位到具体哪张卡,而不是重启一遍碰运气;重启后的恢复要能续上,不能从头再来。

检查点的频率有个权衡。假设单次检查点耗时 T_ckpt,故障平均间隔 T_fail,那么检查点的开销占比约等于 T_ckpt / T_interval,而故障导致的重算损失约等于 T_interval / 2。两者相加求最小,就能算出最优间隔。这个公式不用精确,但思路要有:不是越频繁越好。

5.2 慢节点的定位链路:从现象到具体卡

慢节点比坏节点更恶心。坏节点会直接报错,慢节点只是让整个集群等它,你看到的现象是单步时间波动、利用率上不去,但没有任何报错。

排查链路我一般是这么走的。第一步,看单步时间的分布,如果呈现明显的双峰或者长尾,确认存在慢节点。第二步,开启逐卡计时,找出拖后腿的那几张。第三步,对这些卡单独跑基准测试,区分是硬件问题还是负载不均。第四步,如果是硬件问题,看是降频、ECC 报错还是链路误码。

负载不均也常被误判成慢节点。比如数据并行下某些卡的 batch 里序列特别长,或者专家并行下某些卡分到的 token 特别多,都会表现为“这张卡慢”。这时候该调的是负载均衡策略,不是换卡。

有个土办法很有效:在训练循环里加一个全归约的耗时打点,每 N 步输出一次各卡的到达时间差。差值超过阈值就记日志。这个开销极小,但能把问题暴露在前面。

5.3 静默数据错误:最难查的那一类

比慢节点更隐蔽的是计算结果悄悄错了但不报错。表现是 loss 曲线突然抖一下,然后恢复,或者干脆缓慢发散,你以为是学习率的问题,其实是某次矩阵乘算错了。

检测手段有几层。最轻的是监控 loss 和梯度范数的异常突刺,设个阈值报警。中等的是定期做参数校验,比如每隔若干步把某几层的参数哈希做一次跨卡比对。最重的是端到端复算,代价太大,一般不做。

写入侧的防护也重要。矩阵乘的累加如果用了低精度,误差会随 K 维度累积,K 很大时要考虑分段累加或者周期性升精度。这个在长序列、大 hidden 的场景下尤其要注意。

6. 从跑通到跑快:一条可复现的调优路径

前面讲的是原理,这一节讲怎么落地。我不打算给一套“万能配置”,因为模型差异太大,给了也是误导。我给的是路径和判断依据,你照着走一遍,大概能知道自己的瓶颈在哪。

6.1 环境准备里最容易漏掉的几件事

驱动和固件版本要对齐,这个不用多说,但很多人忽略了集群内版本一致性——一张卡的固件版本和别人不一样,可能出现莫名其妙的通信超时。上集群前先跑一遍版本巡检脚本,把驱动、固件、通信库、编译器版本全部拉平。

然后是拓扑感知。确认你的进程绑定和网卡绑定是否按拓扑分配,跨 NUMA 访问会让带宽掉一截。这个检查很简单,跑一个纯带宽测试,如果实测只有理论值的六七成,八成是绑核或者 NUMA 的问题。

最后是基准测试的建立。在跑真实模型之前,先跑三个基准:纯矩阵乘的算力测试、纯拷贝的带宽测试、纯通信的集合通信测试。这三个数字记下来,后面所有异常都能拿来对照。

6.2 一个 attention 层的调优过程

假设你的模型里 attention 层占了 40% 的时间,想优化它。步骤大致是这样。

先做单算子剖析,拿到矩阵乘、softmax、数据搬运各占多少。如果矩阵乘占 70% 以上,那说明形状还行,重点看融合;如果 softmax 和搬运占了大头,那重点在分块和片上驻留。

然后确认分块参数。序列长度、头维度、batch 这三个数决定了分块策略。头维度如果是 128 这种规整值,矩阵引擎效率最高;如果是 96 或者 80,可能需要补齐到 128,浪费一点算力换规整。序列长度不是 2 的幂时,padding 的浪费要算清楚,有时候换一种分块方式能省 20%。

接着是精度。QK^T 用 FP8 还是 BF16,要看数值稳定性。实测下来,QK^T 用低精度、PV 用高精度,是相对稳妥的组合,但也要看具体模型。判断标准是训练几百步后 loss 曲线有没有偏离基线,偏了就退回。

最后是重叠。把 attention 的计算和数据搬运、通信做流水,这一层能再抠出百分之十几。但要小心,重叠会增加寄存器压力,压得太狠反而会降频拖慢整体。

6.3 常见问题速查

现象大概率原因排查动作
单步时间波动超过 20%慢节点或负载不均逐卡计时,看长尾分布
矩阵引擎利用率低于 50%算子形状不匹配或碎片化打印 kernel 列表,找小算子
通信占比超过 30%并行策略与拓扑不匹配检查张量并行是否跨域
loss 偶发突刺低精度累积误差或静默错误降精度档位,开哈希校验
显存刚好够但频繁 OOM碎片化而非总量不足调整分片策略,预分配缓冲
集群规模上去后吞吐反降集合通信争抢或路由不均衡测不同消息大小的带宽曲线

这张表我能列的还有很多,但核心逻辑就一条:先定位是哪一类资源成了瓶颈,再对症下药。算力、带宽、通信、显存,四者必有其一。用排除法,比盲目调参快得多。

最后说点个人体会。这类专用训练芯片的价值,从来不在单卡的跑分上,而在“一千张卡连起来之后,有效算力还剩多少”。选型的时候,别只看峰值,要看在你的模型、你的并行策略、你的运维能力下,能稳定跑出多少 MFU。有些平台单卡很强但集群一上规模就散架,有些平台单卡一般但千卡线性度很好,后者在真实训练里往往更划算。还有一个容易忽略的点:调试工具的成熟度。一个能让你在半小时内定位到具体哪张卡、哪个 kernel 出问题的工具链,长期看比多 10% 的算力更值钱。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询