使用 Loss 对齐工具
我们在 Megatron-Infinigence 训练镜像中预置了 Loss 对齐工具。
该工具位于以下路径:
/root/megatron-infinigence/tools/loss_align/
工具简介
该工具用于分析和排查两次训练过程中 Loss 曲线不一致的原因。该工具的工作原理为:在训练框架中设置预埋点,并通过训练框架相关选项控制模块开关和埋点粒度等级,在训练过程中对数据进行保存,然后执行对比工具加载数据,并按训练流程顺序给出关键节点的输出对比。
optimization 训练 Loss 曲线仍然是下降趋势,但相比于 baseline,呈现出差异逐渐增大的趋势
参数配置
Loss 对齐工具提供了丰富的参数配置选项,分为训练框架相关选项和对比工具相关选项两大类。
训练框架相关选项
--loss-aglin # 开启 Loss 对齐模式
--loss-align-level 0|1|2 # 埋点粒度等级(0-粗粒度(默认)、1-中等粒度、2-细粒度)
--loss-align-save-path <path> # 现场保存路径(没有该目录会新建,已有该目录会覆盖)
--loss-align-check # 是否对埋点数据严格检查(一般用于验证埋点正确性,可不加)
--no-save-model-metadata # 不保存模型结构信息(默认保存)
--no-save-model-params # 不保存模型权重(默认保存)
--no-save-train-hyperparams # 不保存训练超参(默认保存)
--no-save-sample-data # 不保存采样数据(默认保存)
--no-save-forward-output # 不保存前向传播输出(默认保存)
--no-save-loss-output # 不保存损失函数输出(默认保存)
--no-save-backward-output # 不保存反向传播输出(默认保存)
--no-save-optimizer-output # 不保存优化器输出(默认保存)
对比工具相关选项
--loss-aglin-load-path1 # 需要进行 Loss 对比的现场目录一(必填项)
--loss-aglin-load-path2 # 需要进行 Loss 对比的现场目录二(必填项)
--verbose # 是否需要打印 tensor 列表的详细对比
--no-check-model-metadata # 不检查模型结构信息(默认检查)
--no-check-model-params # 不检查模型权重(默认检查)
--no-check-train-hyperparams # 不检查训练超参(默认检查)
--no-check-sample-data # 不检查采样数据(默认检查)
--no-check-forward-output # 不检查前向传播输出(默认检查)
--no-check-loss-output # 不检查损失函数输出(默认检查)
--no-check-backward-output # 不检查反向传播输出(默认检查)
--no-check-optimizer-output # 不检查优化器输出(默认检查)
警告
此工具需要在训练过程中保存大量数据到磁盘,不是在正常训练中使用的,使用该工具时,需要把相关数据维度降低才可用(比如 layer 层数降至 1-2 层等)。
示例一 对比多卡 Dense 模型
Step 1 执行 baseline 训练
cd /root/megatron-infinigence
bash tools/loss_align/examples/llama2.sh
在 /root/megatron-infinigence
会生成 baseline
目录,为该次训练的所保存的要对齐的数据。
Step 2 执行 optimize 训练
以下步骤模拟一个优化改动的场景,修改其中的 LR 超参,并保存到另外一个目录:
vim tools/loss_align/examples/llama2.sh
需要进行以下两处修改:
- 修改
--lr
为0.00016
- 修改
--loss-align-save-path
为/root/megatron-infinigence/optimize
bash tools/loss_align/examples/llama2.sh
在 /root/megatron-infinigence
会生成 optimize
目录。
Step 3 执行对比查看差异
cd /root/megatron-infinigence
python tools/loss_align/compare_loss.py --load-path1 baseline --load-path2 optimize
root@is-dbjkqk3jbo3pyeqg-devmachine-0:~/megatron-infinigence# python tools/loss_align/compare_loss.py --load-path1 baseline --load-path2 optimize
loss_align_load_path1: baseline
loss_align_load_path2: optimize
loss_align_level: 0
train_iters: 1
decoder_layers: 2
world_size: 8
model_metadata (r0): YES
model_metadata (r1): YES
model_metadata (r2): YES
model_metadata (r3): YES
model_metadata (r4): YES
model_metadata (r5): YES
model_metadata (r6): YES
model_metadata (r7): YES
model_init_params (r0): YES, 0
model_init_params (r1): YES, 0
model_init_params (r2): YES, 0
model_init_params (r3): YES, 0
model_init_params (r4): YES, 0
model_init_params (r5): YES, 0
model_init_params (r6): YES, 0
model_init_params (r7): YES, 0
>>> iteration-0
train_hyperparams (r0): NO
{'lr': ([0.00015, 0.00015], [0.00016, 0.00016])}
由于超参 LR 属于两次训练 Loss 一致的先决条件,若其不一致,最终 Loss 必然导致不一致,因此直接退出,显示两次训练脚本中不同的 LR 值(有多个值是因为在优化器中会根据参数类型分为多个组)。
示例二 对比多卡 MoE 模型
Step 1 执行 baseline 训练
cd /root/megatron-infinigence
vim tools/loss_align/examples/mixtral.sh
修改 --loss-align-level
为 2
(细粒度埋点)
bash tools/loss_align/examples/mixtral.sh
在 /root/megatron-infinigence
生成 baseline
目录,为该次训练的所保存的要对齐的数据。
Step 2 执行 optimize 训练
以下步骤模拟一个优化改动的场景,修改 MoE router 中的 softmax 作用位置,并保存到另外一个目录:
vim tools/loss_align/examples/mixtral.sh
需要进行以下两处修改:
- 添加一个选项
--moe-router-pre-softmax
- 修改
--loss-align-save-path
为/root/megatron-infinigence/optimize
bash tools/loss_align/examples/mixtral.sh
在 /root/megatron-infinigence
会生成 optimize
目录。
Step 3 执行对比查看差异
python tools/loss_align/compare_loss.py --load-path1 baseline --load-path2 optimize
root@is-dbjkqk3jbo3pyeqg-devmachine-0:~/megatron-infinigence# python tools/loss_align/compare_loss.py --load-path1 baseline --load-path2 optimize
loss_align_load_path1: baseline
loss_align_load_path2: optimize
loss_align_level: 0
train_iters: 1
decoder_layers: 2
world_size: 8
model_metadata (r0): YES
model_metadata (r1): YES
model_metadata (r2): YES
model_metadata (r3): YES
model_metadata (r4): YES
model_metadata (r5): YES
model_metadata (r6): YES
model_metadata (r7): YES
model_init_params (r0): YES, 0
model_init_params (r1): YES, 0
model_init_params (r2): YES, 0
model_init_params (r3): YES, 0
model_init_params (r4): YES, 0
model_init_params (r5): YES, 0
model_init_params (r6): YES, 0
model_init_params (r7): YES, 0
>>> iteration-0
train_hyperparams (r0): YES
train_hyperparams (r1): YES
train_hyperparams (r2): YES
train_hyperparams (r3): YES
train_hyperparams (r4): YES
train_hyperparams (r5): YES
train_hyperparams (r6): YES
train_hyperparams (r7): YES
sample_data r0: YES, 0
sample_data r1: YES, 0
sample_data r2: YES, 0
sample_data r3: YES, 0
sample_data r4: YES, 0
sample_data r5: YES, 0
sample_data r6: YES, 0
sample_data r7: YES, 0
forward_output (r0): NO, 1e-1
forward_output (r1): NO, 1e-1
forward_output (r2): NO, 1e-1
forward_output (r3): NO, 1e-1
forward_output (r4): NO, 1e0
forward_output (r5): NO, 1e0
forward_output (r6): NO, 1e0
forward_output (r7): NO, 1e0
loss_output (r4): NO, 1e-2
loss_output (r5): NO, 1e-2
loss_output (r6): NO, 1e-2
loss_output (r7): NO, 1e-2
optimizer_output (updated_params): NO, 1e-4
optimizer_output (norms): NO, 1e-1
结果显示,前向输出存在不一致,rank0-rank3 均为 1e-1 级误差,rank4-rank7 均为 1e0 级误差。
Step 4 详细对比分析
为进一步分析问题,可添加 --verbose
参数查看所有模块的详细输出对比,以确定具体的问题模块:
python tools/loss_align/compare_loss.py --load-path1 baseline --load-path2 optimize --verbose
forward_output (r0): NO, 1e0
+--------------------------------------------------+-------+------------------+---------------+----------+----------+
| key | level | shape | dtype | same_hash| diff_order|
+--------------------------------------------------+-------+------------------+---------------+----------+----------+
| [GAS-0] embed_out | 1 | (512, 1, 1024) | torch.bfloat16| True | 0 |
| [GAS-0] [L-0] input_norm_out | 1 | (512, 1, 1024) | torch.bfloat16| True | 0 |
| [GAS-0] [L-0] attn_qkv_out | 2 | (1024, 1, 8, 64) | torch.bfloat16| True | 0 |
| [GAS-0] [L-0] attn_qkv_k_out | 2 | (1024, 1, 8, 64) | torch.bfloat16| True | 0 |
| [GAS-0] [L-0] attn_qkv_v_out | 2 | (1024, 1, 8, 64) | torch.bfloat16| True | 0 |
| [GAS-0] [L-0] attn_rope_q_out | 2 | (1024, 1, 8, 64) | torch.bfloat16| True | 0 |
| [GAS-0] [L-0] attn_rope_k_out | 2 | (1024, 1, 8, 64) | torch.bfloat16| True | 0 |
| [GAS-0] [L-0] attn_core_out | 2 | (1024, 1, 512) | torch.bfloat16| True | 0 |
| [GAS-0] [L-0] attn_proj_out | 2 | (512, 1, 1024) | torch.bfloat16| True | 0 |
| [GAS-0] [L-0] attn_out | 0 | (512, 1, 1024) | torch.bfloat16| True | 0 |
| [GAS-0] [L-0] premlo_norm_out | 1 | (512, 1, 1024) | torch.bfloat16| True | 0 |
| [GAS-0] [L-0] MoE_router_probs_out | 1 | (1024, 2) | torch.bfloat16| False | 1e-1 |
| [GAS-0] [L-0] MoE_router_indices_out | 1 | (1024, 2) | torch.int64 | False | 1e0 |
结果显示,在 MoE router 的两个输出中首次出现不一致,误差等级分别为 1e-1 和 1e0,表明 router 模块存在差异(图中 GAS-x 为梯度累积次数,L-x 为层数),与之前设置的 --moe-router-pre-softmax
参数相关。