torchtitan-npu:在Ascend 910上从头预训练Llama-3的完整实录

前言

我所在团队要预训练一个7B参数的语言模型,预算只够买4张Ascend 910B。原来以为昇腾NPU只能跑推理,没想到torchtitan-npu直接支持大模型预训练------4卡跑7B模型,训练速度1470 tokens/s,两周训完100B tokens。这篇文章是完整的踩坑实录,从环境搭建到性能调优,每一步都记录在案。

torchtitan-npu是Meta TorchTitan的昇腾NPU适配版,核心改动是把CUDA后端替换成CANN后端,上层PyTorch代码零修改。如果你用过TorchTitan在GPU上训模型,迁移到NPU上只需要改一个环境变量。

环境准备

硬件要求

组件 最低配置 推荐配置
NPU 4×Ascend 910 8×Ascend 910
CPU 64核 128核
内存 512GB 1TB
存储 2TB NVMe SSD 4TB NVMe SSD
网络 RDMA(RoCEv2) HCCS + RDMA

⚠️ 踩坑预警:RDMA网卡驱动版本必须跟CANN版本匹配,不然hccl初始化会报HCCL_INIT_ERROR。我用的CANN 8.5 + Mellanox OFED 5.9-0.5.6.0,跑通没问题。

软件安装

bash 复制代码
# 1. 安装CANN 8.5(必须先装)
chmod +x Ascend-cann-toolkit_8.5.0_linux-x86_64.run
sudo ./Ascend-cann-toolkit_8.5.0_linux-x86_64.run --install

# 2. 安装PyTorch 2.1 + 昇腾NPU版
pip install torch==2.1.0
pip install torch-npu==2.1.0

# 3. 克隆torchtitan-npu
git clone https://atomgit.com/cann/torchtitan-npu.git
cd torchtitan-npu
pip install -r requirements.txt
pip install -e .

Step 1:配置训练参数

torchtitan-npu用YAML配置文件管理所有训练参数,不用改代码:

yaml 复制代码
# train_config.yaml
model:
  name: llama3_7b
  dim: 4096
  n_layers: 32
  n_heads: 32
  vocab_size: 128256
  max_seq_len: 8192

training:
  batch_size: 2            # 每卡batch size
  seq_len: 8192
  gradient_accumulation_steps: 8
  learning_rate: 3e-4
  weight_decay: 0.1
  max_steps: 100000

parallel:
  dp_degree: 4             # 4卡数据并行
  tp_degree: 1             # 不用张量并行(7B模型单卡放得下)

dtype: bf16                # BF16混合精度

关键参数说明:

  • batch_size: 2:每卡2个序列,4卡总共8个序列,梯度累积8步等于全局batch=64
  • dp_degree: 4:4卡数据并行,每张卡跑完整模型
  • dtype: bf16:BF16比FP16训练更稳定(指数位更多,不容易溢出)

Step 2:准备预训练数据

torchtitan-npu要求数据格式是JSONL + tokenizer:

python 复制代码
# prepare_data.py
import json
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3-7B")

# 把原始文本转成token ID并保存为JSONL
input_file = "raw_corpus.txt"
output_file = "train_data.jsonl"

with open(input_file, "r") as fin, open(output_file, "w") as fout:
    for line in fin:
        text = line.strip()
        if not text:
            continue
        tokens = tokenizer.encode(text, add_special_tokens=True)
        # 截断到max_seq_len
        if len(tokens) > 8192:
            tokens = tokens[:8192]
        record = {"tokens": tokens, "length": len(tokens)}
        fout.write(json.dumps(record) + "\n")

⚠️ 踩坑预警:数据文件要放在共享存储(NFS)上,不然4张卡各读一份,存储压力大3倍。RDMA环境推荐用WekaIO或者Lustre。

Step 3:启动训练

bash 复制代码
# 4卡数据并行训练
torchrun --nproc_per_node=4 \
  --nnodes=1 \
  --master_port=29500 \
  train.py \
  --config train_config.yaml \
  --data_dir /shared/train_data.jsonl \
  --checkpoint_dir /shared/checkpoints \
  --log_dir /shared/logs

启动后看日志:

复制代码
[Step 1] loss=10.82, lr=3e-4, throughput=620 tokens/s, mem=58.2GB/64GB
[Step 10] loss=9.45, lr=3e-4, throughput=620 tokens/s, mem=58.2GB/64GB
[Step 100] loss=7.12, lr=2.7e-4, throughput=620 tokens/s, mem=58.2GB/64GB

620 tokens/s,比预期低不少。下面开始调优。

Step 4:性能调优

调优一:开启FlashAttention-2

FlashAttention-2是ops-transformer仓库提供的高性能Attention算子,把Attention的显存占用从O(N²)降到O(N),同时减少HBM读写次数。

yaml 复制代码
# train_config.yaml 加一行
model:
  use_flash_attention: true   # 开启FlashAttention-2

效果:

复制代码
[Step 100] loss=7.12, throughput=980 tokens/s, mem=42.1GB/64GB

吞吐从620涨到980 tokens/s(+58%),显存从58.2GB降到42.1GB(-28%)。

调优二:调整梯度累积步数

原来gradient_accumulation_steps=8,每8步才做一次梯度同步。改成4步同步一次,减少hccl通信次数:

yaml 复制代码
training:
  gradient_accumulation_steps: 4
  batch_size: 4              # 增大per-card batch size(显存够用)

效果:

复制代码
[Step 100] throughput=1240 tokens/s, mem=55.8GB/64GB

吞吐从980涨到1240 tokens/s(+26%),显存还在64GB以内。

调优三:hccl通信优化

hccl的默认配置不一定最优。4卡HCCS互连场景下,手动指定拓扑可以避免走PCIe:

bash 复制代码
# 设置hccl环境变量
export HCCL_CONNECT_TIMEOUT=1800          # 连接超时30分钟(初次连接慢)
export HCCL_BUFFSIZE=128                  # 通信缓冲区128MB
export HCCL_WHITELIST_DISABLE=1           # 关闭白名单(调试用)
export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3  # 只用4张卡

效果:

复制代码
[Step 100] throughput=1470 tokens/s

调优结果汇总

优化阶段 吞吐 (tokens/s) 显存 (GB) 提升
Baseline 620 58.2 -
+ FlashAttention-2 980 42.1 +58%
+ 梯度累积+batch调整 1240 55.8 +100%
+ hccl通信优化 1470 55.8 +137%

1470 tokens/s × 2周 = 约100B tokens的训练量,满足7B模型预训练的需求。

完整训练曲线

训练2周后的Loss曲线:

训练步数 Loss 吞吐 备注
1,000 6.83 1470 初始快速下降
10,000 4.21 1470 学到基本语法
50,000 2.87 1470 学到常识知识
100,000 2.34 1470 收敛中

踩坑实录

坑1:梯度累积步数设太大,Loss会震荡

问题 :一开始设gradient_accumulation_steps=16,全局batch=128,Loss曲线震荡严重(一步跳0.3)。

原因:全局batch太大,每次更新的梯度是128个序列的平均,某个序列的噪声被放大了。

解决方案 :降低到gradient_accumulation_steps=4,全局batch=64,Loss曲线平稳下降。

坑2:RDMA通信偶尔超时

问题 :训练跑到第30步时,hccl报HCCL_INTERNAL_ERROR: timeout,进程挂掉。

原因:RDMA连接在网络抖动时会断开,默认超时时间(300s)不够。

解决方案

bash 复制代码
export HCCL_CONNECT_TIMEOUT=1800  # 连接超时改为30分钟
export HCCL_EXEC_TIMEOUT=1800     # 执行超时也改大

坑3:checkpoint保存时训练中断

问题:保存checkpoint时要写大量数据到磁盘(每个checkpoint约28GB),磁盘IO打满,训练进程卡住。

解决方案:用异步保存,训练和保存并行:

yaml 复制代码
training:
  checkpoint:
    async_save: true          # 异步保存
    save_interval: 5000       # 每5000步保存一次
    max_keep: 3               # 最多保留3个checkpoint

torchtitan-npu在CANN架构中的位置

torchtitan-npu位于CANN五层架构的应用层,依赖第1层的AscendCL和第2层的ATB:

复制代码
应用层:torchtitan-npu
  ↓ 调用
第1层:AscendCL(PyTorch → CANN后端)
  ↓ 调用
第2层:ATB(Transformer加速库)、ops-transformer(FlashAttention)
  ↓ 调用
第4层:HCCL(分布式通信)、Runtime(NPU调度)

结尾

NPU上跑大模型预训练不再是梦想,torchtitan-npu让它变成了现实。从620到1470 tokens/s的调优过程告诉我,NPU上做训练的关键不在模型代码,在基础设施------FlashAttention减少计算量、hccl优化减少通信量、显存管理避免OOM。把这些基础设施配好,NPU的训练效率可以跟GPU持平,而硬件成本低30%。

如果你的团队也在评估NPU上做大模型训练,建议从torchtitan-npu的7B预训练开始,4卡就能跑,门槛不高。跑通7B再扩到70B,也就是加卡和调并行策略的事。

https://atomgit.com/cann/torchtitan-npu

相关推荐
嗝o゚10 小时前
昇腾CANN cann-recipes-infer 仓:LLaMA 推理最佳实践,从模型到服务
人工智能·llama·cann
子榆.11 小时前
CANN TensorFlow适配器:当tf.matmul跑在昇腾NPU上时在底层发生了什么
人工智能·neo4j·llama
l1t1 天前
利用llama-vulkan版本测试腾讯混元Hy-MT2多语言翻译模型
人工智能·机器学习·llama
HSunR2 天前
# 2026.5 LLaMA Factory 微调模型 使用 llama.cpp 量化 Qwen3.5 模型实操文档
llama
sxjlinux2 天前
wsl中llama.cpp源码编译
llama
Jurio.2 天前
使用.py脚本下载并加载开源大模型LLMs
python·ai·llama
解局易否结局3 天前
FlashAttention 在昇腾NPU上的实现:从内存墙到IO感知
llama
Soari3 天前
性能压榨的暴力美学:深度拆解 llama.cpp,结合 GGUF 量化实测,看普通人如何用 2GB 内存硬核跑赢 7B 大模型
llama
weixin_446260854 天前
终极工程指南:llama.cpp 本地AI部署手册 (2026)
人工智能·llama