| # Experiment B Performance Tuning |
|
|
| ## 背景 |
|
|
| 本文档基于 `2026-03-31` 对实验 B 当前正式训练的实时观测整理,目标是回答: |
|
|
| 1. 当前系统资源到底卡在哪里 |
| 2. 哪些参数最值得优先调整 |
| 3. 怎样在不破坏现有可跑性的前提下,尽量提升训练速度 |
|
|
| 当前训练实例: |
|
|
| - 训练日志:`runs/logs/tomato-exp-b-attr_20260331-192847.log` |
| - 输出目录:`runs/mid/qwen3_5_35b_a3b_exp_b_attr/v1-20260331-192847` |
| - 当前启动时的关键降载参数: |
| - `DATASET_NUM_PROC=1` |
| - `DATALOADER_NUM_WORKERS=2` |
|
|
| 说明: |
|
|
| - 这两个参数不是为了提速,而是为了绕过上一轮实验 B 在数据映射阶段被 `SIGKILL` 的问题。 |
| - 当前这轮已经成功越过上一轮失败位置,并进入正式 `Train` 阶段。 |
|
|
| ## 实时观测 |
|
|
| ### 1. GPU |
|
|
| 观测时刻的 `nvidia-smi`: |
|
|
| - GPU 显存占用约 `33.9 GiB ~ 35.1 GiB / 49.1 GiB` |
| - GPU 利用率约 `19% ~ 27%` |
| - 功耗约 `95W ~ 115W` |
|
|
| 补充观测: |
|
|
| - `nvidia-smi dmon` 连续采样期间,显存保持高占用,但 `sm` 利用率瞬时值很低。 |
| - 这说明模型已经装载完成,但算力并没有持续吃满。 |
|
|
| 结论: |
|
|
| - 当前不是“显存不够”,而是“显存还有余量,但计算吞吐没有被充分压满”。 |
| - 对 RTX 6000 Ada 来说,当前功耗和利用率都偏保守,明显还有提速空间。 |
|
|
| ### 2. CPU |
|
|
| 观测时刻的系统级 CPU: |
|
|
| - `112` 核机器整体 `idle` 大约 `90%` |
| - `iowait` 约 `1%` |
|
|
| 训练相关进程: |
|
|
| - 4 个主要训练 worker 的单进程 CPU 大约都在 `96%` 左右 |
|
|
| 结论: |
|
|
| - 机器总 CPU 资源非常充足。 |
| - 当前不是整机 CPU 不够,而是训练进程只吃到了少量核,整体 CPU 远未成为上限。 |
|
|
| ### 3. 内存与 Swap |
|
|
| 观测时刻: |
|
|
| - 物理内存总量约 `1.0 TiB` |
| - `available` 约 `867 GiB` |
| - swap `15 GiB` 已满 |
|
|
| 结论: |
|
|
| - 内存容量本身完全不是问题。 |
| - 但 swap 已满说明机器历史上发生过明显的内存换出,这对训练稳定性是个风险信号。 |
| - 上一轮实验 B 在数据映射阶段被 `SIGKILL`,与预处理阶段资源压力过高是吻合的。 |
|
|
| ### 4. 磁盘 I/O |
|
|
| `iostat` 观测结果: |
|
|
| - CPU `iowait` 很低 |
| - NVMe 利用率很低,吞吐量也不高 |
|
|
| 结论: |
|
|
| - 当前不是磁盘带宽瓶颈。 |
| - 训练速度慢,主要不是因为数据文件读不动。 |
|
|
| ### 5. 训练阶段特征 |
|
|
| 从日志看,实验 B 的时间主要消耗在两段: |
|
|
| 1. 数据映射 / tokenization 阶段很长 |
| 2. 进入训练后,GPU 利用率仍偏低 |
|
|
| 同时,日志里还能看到两个重要事实: |
|
|
| - 当前使用的是 `--attention_backend unfused` |
| - 参数对象里实际 `sequence_parallel=False` |
|
|
| 这意味着: |
|
|
| - 训练吞吐已经天然比更激进的 fused/flash 路线慢 |
| - 不能把当前性能预期建立在“高级并行优化已生效”的假设上 |
|
|
| ## 主要瓶颈判断 |
|
|
| 基于当前观测,实验 B 的性能问题优先级大致如下: |
|
|
| 1. 预处理阶段过慢,且并发一高就有稳定性风险 |
| 2. 训练阶段 GPU 显存占用中等,但算力利用率偏低 |
| 3. 当前批大小和重计算策略偏保守,更像“先保跑通”,不是“先榨吞吐” |
| 4. 现有 `unfused` attention backend 本身限制了吞吐上限 |
|
|
| 不是主要瓶颈的项: |
|
|
| - 机器总内存容量 |
| - 磁盘 I/O |
| - 整机 CPU 总量 |
|
|
| ## 提速建议 |
|
|
| 以下建议按优先级排序。 |
|
|
| ### P0:先把“稳定跑通”和“性能调优”分成两套参数 |
|
|
| 当前这轮参数适合保命,不适合作为长期最快配置。 |
|
|
| 建议保留两套启动配置: |
|
|
| - `safe` 配置 |
| - `DATASET_NUM_PROC=1` |
| - `DATALOADER_NUM_WORKERS=2` |
| - `fast` 配置 |
| - 从 `DATASET_NUM_PROC=2` |
| - `DATALOADER_NUM_WORKERS=4` |
| - 开始逐步压测 |
|
|
| 理由: |
|
|
| - 现在最清楚的事实是:预处理并发拉高后,实验 B 曾经直接被系统杀掉。 |
| - 但一味维持 `1/2` 组合,会显著拖慢数据准备。 |
|
|
| 推荐做法: |
|
|
| 1. 先用 `safe` 配置跑通一次完整训练 |
| 2. 再单独开小样本性能压测,把 `dataset_num_proc` 和 `dataloader_num_workers` 逐步抬高 |
| 3. 只要出现明显 swap 抖动或再次 `SIGKILL`,立即回退 |
|
|
| ### P1:把数据缓存预构建为独立步骤 |
|
|
| 当前训练把“数据准备”和“正式训练”绑在同一次进程里,这会让每次重试都重复走长时间 `Map`。 |
|
|
| 建议: |
|
|
| - 增加一个独立的“数据缓存预构建”步骤 |
| - 在正式训练前先把 train/val 数据的 tokenization 和缓存文件准备好 |
| - 正式训练只消费缓存 |
|
|
| 价值: |
|
|
| - 可以把最不稳定、最容易触发 `SIGKILL` 的阶段前置 |
| - 训练重试时不必重复长时间 `Map` |
| - 这通常是当前最容易拿到的真实提速项 |
|
|
| ### P2:优先尝试增大 `MICRO_BATCH_SIZE` |
|
|
| 当前 GPU 显存大约只占到了 `34~35 GiB / 49 GiB`,每卡仍有十几 GiB 余量。 |
|
|
| 建议从小步试探: |
|
|
| - 先试 `MICRO_BATCH_SIZE=5` |
| - 再试 `MICRO_BATCH_SIZE=6` |
| - 同步调整 `GLOBAL_BATCH_SIZE` |
|
|
| 推荐原则: |
|
|
| - 维持梯度累积逻辑清晰 |
| - 每次只改一个量 |
| - 观察显存、step time、是否出现 OOM |
|
|
| 理由: |
|
|
| - 当前显存没打满 |
| - 但 GPU 算力利用率偏低 |
| - 典型原因之一就是每步喂给 GPU 的活太小 |
|
|
| 这是最可能直接提升训练吞吐的参数。 |
|
|
| ### P3:减少重计算强度 |
|
|
| 当前配置: |
|
|
| - `--recompute_granularity full` |
| - `--recompute_method uniform` |
| - `--recompute_num_layers 1` |
|
|
| 在显存还有余量的前提下,建议做对照试验: |
|
|
| - 降低 `recompute` 范围 |
| - 或直接尝试关闭部分重计算 |
|
|
| 理由: |
|
|
| - 重计算本质上是“用时间换显存” |
| - 现在更像是时间更紧,而不是显存更紧 |
|
|
| 建议: |
|
|
| - 先保留当前配置跑通一版 |
| - 之后做一组短跑 benchmark,比对 step time 和显存峰值 |
|
|
| ### P4:检查 `attention backend` |
|
|
| 当前是: |
|
|
| - `--attention_backend unfused` |
|
|
| 这通常意味着: |
|
|
| - 兼容性更稳 |
| - 吞吐更差 |
|
|
| 建议: |
|
|
| - 在不影响稳定性的前提下,继续修复 / 验证更快的 attention backend |
| - 如果后续能恢复到更高效的 fused/flash 路线,训练速度会有明显提升 |
|
|
| 这项的潜在收益很大,但风险也高,所以优先级放在批大小和重计算之后。 |
|
|
| ### P5:重新评估 `expert_model_parallel_size` |
| |
| 当前配置: |
| |
| - `expert_model_parallel_size=4` |
| - `tensor_model_parallel_size=1` |
| - `pipeline_model_parallel_size=1` |
|
|
| 这说明当前主要是 EP 路线。 |
|
|
| 建议: |
|
|
| - 对 `expert_model_parallel_size=4` 和更保守配置做小样本性能对照 |
| - 重点观察 step time、GPU util 和通信开销 |
|
|
| 原因: |
|
|
| - 当前 GPU 利用率不高,可能有一部分时间耗在 MoE 路由和通信上 |
| - 这类瓶颈通常不能只靠加 dataloader 解决 |
|
|
| 这项不建议直接在正式训练上改,先做 benchmark。 |
|
|
| ### P6:处理 swap 已满的问题 |
|
|
| 虽然当前物理内存还很多,但 swap 已满不是健康信号。 |
|
|
| 建议: |
|
|
| - 正式训练前确认没有残留的大进程长期占内存 |
| - 定期清理历史残留的训练/推理进程 |
| - 把“预处理高并发压测”与“正式训练”分开,避免训练时叠加系统脏状态 |
|
|
| 如果后续还出现: |
|
|
| - 数据映射阶段突然变慢 |
| - 训练被 `SIGKILL` |
|
|
| 应优先排查内存换出和宿主机资源保护,而不是先怀疑模型参数。 |
|
|
| ## 推荐调优顺序 |
|
|
| 建议按下面顺序做,不要一次改太多: |
|
|
| 1. 先用当前 `safe` 配置完整跑通实验 B |
| 2. 抽离数据缓存预构建步骤 |
| 3. 压测 `MICRO_BATCH_SIZE=5/6` |
| 4. 压测较轻的 `recompute` 配置 |
| 5. 压测更激进的 dataloader / dataset 并发 |
| 6. 再评估 `attention backend` 和 `expert_model_parallel_size` |
|
|
| ## 最值得先做的三件事 |
|
|
| 如果只做最有收益的三项,优先建议: |
|
|
| 1. 把数据缓存预构建独立出来,避免每次重试都重复长时间 `Map` |
| 2. 增大 `MICRO_BATCH_SIZE`,把剩余显存换成吞吐 |
| 3. 在稳定跑通后,降低重计算强度,减少“用时间换显存” |
|
|
| ## 一句话结论 |
|
|
| 当前实验 B 的主要问题不是机器不够强,而是训练配置仍偏“保守保命型”。 |
|
|
| 这台机器的瓶颈不在磁盘和总内存,当前最值得利用的性能空间主要在: |
|
|
| - 更合理的数据缓存策略 |
| - 更大的 batch |
| - 更少的重计算 |
| - 更高效的 attention backend |
|
|