GLM-5.2 在 MindSpore TransFormer 动态图迁移与 GPU/NPU 精度对齐工作报告
作者:昇腾实战派
知识地图:https://blog.csdn.net/Lumos_Lovegood/article/details/161601003
背景概述
随着大模型训练场景的多样化发展,模型需要在不同硬件平台上保持一致的训练精度。本工作旨在将 GLM-5.2 模型结构接入 MindFormers PyNative 框架,并以 GPU 上的 Megatron-LM 为参考基准,验证 Ascend NPU 与 NVIDIA GPU 在单卡训练场景下的精度一致性。通过系统化的对齐流程,确保模型在不同硬件平台上的训练行为可复现、可预期,为后续多卡扩展和实际应用奠定基础。
4 层 mini GLM-5.2 到 1B 级 GLM-5.2 单卡精度对齐,不包含
hidden_size=6144的 8 卡任务。
1. 工作目标
本工作的目标是将 GLM-5.2 结构接入 MindFormers PyNative,并以 GPU Megatron-LM 为参考,验证 Ascend NPU 与 NVIDIA GPU 的训练精度是否一致。
对齐时重点检查两个指标:
loss:模型预测结果与训练目标之间的误差。grad_norm:所有参数梯度的整体大小,反映反向传播和参数更新是否一致。
误差统一定义为:
每步误差 = NPU - GPU
ME = 所有训练步误差的平均值
最终采用的判定目标为:
| 指标 | 目标 |
|---|---|
| loss | abs(ME) < 0.001 |
| grad_norm | abs(ME) < 0.01 |
2. 总体流程
MindFormers PyNative 构建 GLM-5.2
↓
mini 模型依次验证 Transformer、DSA、MoE、MTP
↓
NPU 训练 base model 并保存权重
↓
将权重统一转换为 BF16
↓
将 BF16 权重转换为 Megatron-LM 可加载格式
↓
NPU 与 GPU 加载同源权重、读取同源数据
↓
分别训练并比较 loss、grad_norm
使用同源权重和同源数据,是为了确保曲线差异来自框架或算子实现,而不是随机初始化或样本不同。
3. 第一阶段:mini GLM-5.2
3.1 目的
先使用较小配置打通完整训练链路,降低定位问题的成本。该模型用于代码和精度验证,不代表正式 GLM-5.2 的模型规模。
3.2 配置
| 项目 | 配置 |
|---|---|
| Transformer 层数 | 4 |
| hidden size | 128 |
| vocabulary size | 128 |
| sequence length | 16 |
| 模型结构 | DSA + MoE + MTP |
| DSA top-k | 2048 |
| MoE top-k | 2 |
| 参数类型 | BF16 |
| 优化器 | AdamW |
| 学习率 | 1e-5 |
| 最终训练步数 | 200 |
3.3 最初 10 步基线
早期版本已经能够在 NPU 和 GPU 上运行,但两端尚未完成精度对齐。下图记录了当时的真实 loss 和 grad_norm,是后续排错的起点。


初期 10 步结果:
| 指标 | 平均绝对差 | 最大绝对差 |
|---|---|---|
| loss | 0.023860 | 0.047647 |
| grad_norm | 0.274454 | 0.950350 |
这组数据没有达到对齐目标,主要用于证明“代码能运行”不等于“训练精度已经对齐”。
3.4 主要问题与修改
| 问题 | 修改 | 作用 |
|---|---|---|
| NPU 与 GPU 的 Attention 输出维度解释不同 | FA 输出展平前显式恢复维度顺序 | 保证输出投影读取相同的向量排列 |
| routed expert W1 权重方向不同 | 转换时对 W1 转置 | 对齐 MoE 专家线性层 |
| shared expert FC1 的 SwiGLU 排列不同 | 将交错排列转换为 Megatron 的前后分块排列 | 对齐 gate/up 两部分权重 |
| GPU 未完整加载 router 状态 | 增加 expert_bias 映射 | GPU 权重加载达到 127/127 |
| 两端 TopK expert 顺序不同 | NPU TopK 按 expert 编号排序 | 固定相同的专家选择顺序 |
| AdamW 与 BF16 写回细节不同 | GPU 对齐 NPU 更新公式,并按 BF16 写回参数 | 减少多步训练后的参数漂移 |
| Attention scale 不一致 | GPU 恢复 k_channels、v_channels | 两端统一使用 1/sqrt(192) 缩放 |
关键权重转换示例:
# routed expert W1:修正权重方向
converted[target_key] = value.T.copy()
# shared expert FC1:从交错布局转为 [gate; up]
row_index = np.concatenate([
np.arange(0, row_count, 2),
np.arange(1, row_count, 2),
])
converted[target_key] = value[row_index]
3.5 mini 最终结果
使用相同输入文件和相同初始 BF16 权重,在 NPU MindFormers 与 GPU Megatron-LM 上训练 200 步。
输入文件 SHA256 均为:
5b207e7d346155bbb1e3e3309a2a32fdbd4b3a176f39137e3603c6d03249225f
该值是文件指纹。两端指纹相同,说明输入文件内容完全一致。
| 指标 | ME | max error | min error | 结果 |
|---|---|---|---|---|
| loss | +0.0002275813 | +0.0025243759 | -0.0009393692 | 通过 |
| grad_norm | +0.0050740123 | +0.6322510242 | -0.6356949806 | 通过 |
mini 模型完成了 DSA、MoE、MTP 全链路的单卡精度验证,为扩大模型规模提供了可用基线。
4. 第二阶段:1B 级 GLM-5.2
4.1 目的
mini 模型通过后,将模型扩大到 1B 级测试配置,并恢复正常词表、较长序列和更完整的层数,验证误差在更接近实际训练的条件下是否仍可控。
4.2 配置
| 项目 | 配置 |
|---|---|
| Transformer 层数 | 24 |
| hidden size | 1024 |
| attention heads | 32 |
| vocabulary size | 154880 |
| sequence length | 1024 |
| FFN hidden size | 2048 |
| 前置 Dense 层数 | 3 |
| DSA / MLA | 开启 |
| DSA index heads / top-k | 32 / 1024 |
| routed / shared experts | 8 / 1 |
| experts per token | 2 |
| MTP 层数 / loss scale | 1 / 0.3 |
| 参数与计算类型 | BF16 |
| 学习率 | 1e-5 |
4.3 同源权重和数据
本阶段不再让两端分别随机初始化,采用以下流程:
- NPU PyNative 先训练 10 步,保存 base model。
- 将 base model 转换为统一 BF16 权重。
- 将 BF16 权重转换为 Megatron-LM 权重。
- NPU 加载 BF16 权重,GPU 加载转换后的同源权重。
- 两端读取同一个 1000 步 next-token 数据文件。
数据文件 SHA256:
30145a6260875f713e7dd81f4af121f7c0e4ba0da0c391644d3e751f83adcfd6
4.4 扩大模型后发现的问题
Dense FFN 权重布局
NPU FC1 按 [gate0, up0, gate1, up1, ...] 交错保存;Megatron 按 [全部 gate, 全部 up] 保存。转换时增加去交错操作:
if op == "deinterleave_glu_rows":
rows = value.shape[0]
order = np.concatenate((
np.arange(0, rows, 2),
np.arange(1, rows, 2),
))
return value[order].copy()
GPU 激活函数
GPU 只开启了 GLU,但未显式指定 SiLU,Megatron 实际使用 GELU;NPU GLM-5.2 使用 SiLU。修复为:
import torch.nn.functional as F
cfg = MLATransformerConfig(
gated_linear_unit=True,
activation_func=F.silu,
)
修复后,第 1 步 grad_norm 差值由约 -0.194 降到 -0.00539,20 步 grad_norm ME 由 -0.14080 降到 -0.00296。
稀疏 DSA 的确定性
NPU 原生稀疏 DSA 的 TopK 和部分并行算子存在非确定性。正式实验固定 TopK 顺序并开启确定性计算:
ms.set_context(
mode=ms.PYNATIVE_MODE,
device_target="Ascend",
deterministic="ON",
)
4.5 1B 最终曲线
以下为同源权重、同源数据、确定性模式下的 1000 步结果。红线为 NPU MindFormers,绿线为 GPU Megatron-LM。


误差图采用 NPU - GPU,保留正负号:


4.6 1B 最终结果
| 指标 | ME | max error | min error | 结果 |
|---|---|---|---|---|
| loss | -0.0001127071 | +0.0078821182 | -0.0082559586 | 通过 |
| grad_norm | -0.0092500153 | +0.4218254089 | -0.4344191551 | 通过 |
| mtp1_loss | +0.0000002556 | +0.0017435551 | -0.0014431477 | 对齐 |
| load_balancing_loss | +0.0000028539 | +0.0047043562 | -0.0040243268 | 对齐 |
结果说明:
- NPU 与 GPU 的 loss 曲线基本重合,1000 步 loss ME 满足目标。
- grad_norm 单步会出现正负波动,但平均误差仍小于 0.01。
- MTP loss 和 MoE load balancing loss 同时保持较小平均误差,说明主损失之外的辅助训练分支也已接入并对齐。
5. 阶段结果汇总
| 阶段 | 规模 | 步数 | loss ME | grad_norm ME | 结论 |
|---|---|---|---|---|---|
| mini 最终实验 | 4 层,hidden 128 | 200 | +0.0002275813 | +0.0050740123 | 通过 |
| 1B 最终实验 | 24 层,hidden 1024 | 1000 | -0.0001127071 | -0.0092500153 | 通过 |
6. 结论
本工作已完成以下内容:
- 在 MindFormers PyNative 中打通 GLM-5.2 的 Transformer、DSA、MoE、MTP 训练链路。
- 建立 NPU base model 到 BF16、再到 Megatron-LM 权重的转换流程。
- 找到并修复 Attention、MoE、SwiGLU、激活函数、优化器和确定性计算等差异。
- 完成 mini 模型 200 步与 1B 级模型 1000 步单卡 GPU/NPU 精度对齐。
- 最终 1B 实验满足
|loss ME| < 0.001、|grad_norm ME| < 0.01。
当前结论只适用于本报告中的单卡、hidden_size=1024 及以下实验。hidden_size=6144 的多卡任务需要单独完成 GPU/NPU 训练和误差统计,不能直接沿用本报告的数值结论。
鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。
更多推荐
所有评论(0)