在昇腾 NPU 上用 DeepSpeed ZeRO-2 微调大模型:Qwen2.5-7B 训练实战
cann-recipes-train 是昇腾 CANN 开源社区的大模型训练仓库,专门展示如何在昇腾 NPU 上跑通主流大模型的预训练和微调流程。推理:加载别人已经训练好的模型,直接用预训练:从零开始训练,需要大量数据、算力、时间微调(Fine-tuning):在预训练模型基础上,用少量数据微调这篇文章讲微调——在昇腾 NPU 上用 LoRA + QLoRA 技术微调 Qwen2.5-7B,让它学
前言
cann-recipes-train 是昇腾 CANN 开源社区的大模型训练仓库,专门展示如何在昇腾 NPU 上跑通主流大模型的预训练和微调流程。
预训练(Pre-training)和推理(Inference)的区别:
- 推理:加载别人已经训练好的模型,直接用
- 预训练:从零开始训练,需要大量数据、算力、时间
- 微调(Fine-tuning):在预训练模型基础上,用少量数据微调
这篇文章讲微调——在昇腾 NPU 上用 LoRA + QLoRA 技术微调 Qwen2.5-7B,让它学会特定任务(比如写代码、对话、摘要等)。
选微调的原因是:从零预训练需要成百上千张卡,普通团队玩不起,但微调几张卡就能跑,是更实际的选择。
仓库地址:https://atomgit.com/cann/cann-recipes-train
环境要求
硬件
- Atlas 300T Pro(训练卡,单卡)或 Atlas 800(8 卡)
- 全量微调 Qwen2.5-7B 需要约 140GB 显存,建议 Atlas 800(8 × 64GB = 512GB)
- LoRA 微调约需 20GB 显存,Atlas 300T Pro 可跑
- QLoRA(int4 量化)约需 10GB 显存,Atlas 300I Pro 可跑
软件
CANN Toolkit 8.0+ # 必须
Python 3.10+ # 推荐 3.10
PyTorch 2.1.0+ # 基础框架
torch-npu 2.1.0+ # 昇腾 NPU 后端
transformers 4.36+ # 模型加载
accelerate 0.25+ # 分布式训练
peft 0.7+ # LoRA/QLoRA 框架(关键依赖)
deepspeed 0.12+ # 分布式训练框架
datasets 2.16+ # 数据集加载
第一步:安装依赖
创建独立环境
conda create -n cann-train python=3.10 -y
conda activate cann-train
# 基础依赖
pip install torch==2.1.0 torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
pip install torch-npu==2.1.0
# 训练相关依赖
pip install transformers==4.36.0 accelerate==0.25.0
pip install peft==0.7.0 deepspeed==0.12.0 datasets==2.16.0
pip install tensorboard peft bitsandbytes # bitsandbytes 用于 QLoRA 量化
克隆 cann-recipes-train
git clone https://atomgit.com/cann/cann-recipes-train.git
cd cann-recipes-train
pip install -e .
⚠️ 坑 1:DeepSpeed 报 NCCL 初始化失败。
DeepSpeed 默认用 NCCL(NVIDIA 的通信库),但昇腾 NPU 用的是 HCCL(昇腾的通信库)。需要手动配置:
# 设置 DeepSpeed 使用 HCCL
export NCCL_DEBUG=INFO
export DS_ACCELERATOR=npu # 关键:告诉 DeepSpeed 用 NPU
# 或者在代码里指定
ds_config = {
"train_batch_size": "auto",
"gradient_accumulation_steps": "auto",
"accelerator": {
"backend": "npu" # 指定用 NPU
}
}
验证安装
# test_env.py
import torch
import torch_npu
import deepspeed
import peft
from transformers import AutoModel
print(f"✅ torch: {torch.__version__}")
print(f"✅ torch-npu: {torch_npu.__version__}")
print(f"✅ DeepSpeed: {deepspeed.__version__}")
print(f"✅ PEFT: {peft.__version__}")
print(f"✅ NPU 可用: {torch.npu.is_available()}")
# 简单测试:创建一个 NPU 上的张量
x = torch.randn(100, 100).npu()
print(f"✅ NPU 张量创建成功: {x.device}")
运行:
python test_env.py
如果所有检查都通过,环境安装成功。
第二步:准备训练数据
微调需要准备一个高质量的数据集,格式是 JSONL(每行一个 JSON)。
数据格式
{"messages": [
{"role": "system", "content": "你是一个代码助手,专门回答编程问题。"},
{"role": "user", "content": "用 Python 写一个斐波那契数列函数"},
{"role": "assistant", "content": "以下是斐波那契数列的 Python 实现:\n\n```python\ndef fibonacci(n):\n if n <= 0:\n return []\n elif n == 1:\n return [0]\n elif n == 2:\n return [0, 1]\n else:\n fib = [0, 1]\n for i in range(2, n):\n fib.append(fib[i-1] + fib[i-2])\n return fib\n\n# 示例\nprint(fibonacci(10)) # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]\n```"}
]}
每个样本是一个 JSON,包含 messages 数组,数组里按顺序放 system/user/assistant 的对话。
数据集来源
方式 A:用公开数据集(推荐新手)
from datasets import load_dataset
# 加载 alpaca 数据集(斯坦福的指令微调数据集)
dataset = load_dataset("yahma/alpaca-cleaned")
print(dataset)
# 查看一个样本
print(dataset["train"][0])
方式 B:用自定义数据集
把自己的对话数据转成 JSONL 格式:
import json
# 假设原始数据是 CSV 格式
import pandas as pd
df = pd.read_csv("my_conversations.csv")
# 转成 JSONL
with open("train.jsonl", "w", encoding="utf-8") as f:
for _, row in df.iterrows():
sample = {
"messages": [
{"role": "system", "content": "你是一个有帮助的助手。"},
{"role": "user", "content": row["question"]},
{"role": "assistant", "content": row["answer"]}
]
}
f.write(json.dumps(sample, ensure_ascii=False) + "\n")
print(f"转换完成,共 {len(df)} 条数据")
数据预处理
训练前要处理数据(tokenize、转格式):
from transformers import AutoTokenizer
from datasets import load_dataset
# 加载 tokenizer
tokenizer = AutoTokenizer.from_pretrained(
"Qwen/Qwen2.5-7B-Instruct",
trust_remote_code=True
)
# 加载数据
dataset = load_dataset("json", data_files="train.jsonl", split="train")
# Tokenize 函数
def tokenize(example):
# 把 messages 转成文本
text = tokenizer.apply_chat_template(
example["messages"],
tokenize=False,
add_generation_prompt=False
)
# tokenize
result = tokenizer(
text,
truncation=True,
max_length=2048,
padding="max_length",
return_tensors=None
)
# labels 就是 input_ids(语言模型的目标)
result["labels"] = result["input_ids"].copy()
return result
# 处理数据集
tokenized_dataset = dataset.map(
tokenize,
remove_columns=dataset.column_names,
num_proc=8 # 多进程加速
)
# 保存
tokenized_dataset.save_to_disk("./data/train_tokenized")
print(f"处理完成,共 {len(tokenized_dataset)} 条数据")
⚠️ 坑 2:tokenize 报 “Unknown token” 或 tokenizer 不对齐"。
Qwen2.5 的 tokenizer 用特殊的 template 处理对话,如果 template 用错了,模型输出会乱码。
检查 tokenizer 是否有 chat template:
tokenizer = AutoTokenizer.from_pretrained(
"Qwen/Qwen2.5-7B-Instruct",
trust_remote_code=True
)
# 检查是否有 chat template
print(tokenizer.chat_template)
# 如果输出 None,说明没加载成功,需要指定 trust_remote_code=True
第三步:配置训练
LoRA 微调配置
LoRA(Low-Rank Adaptation)是一种参数高效微调技术,只训练少量参数(通常是原模型的 0.1-1%),大大降低显存占用。
# lora_config.py
from peft import LoraConfig, get_peft_model, TaskType
# LoRA 配置
lora_config = LoraConfig(
task_type=TaskType.CAUSAL_LM, # 因果语言模型
r=16, # LoRA 秩,越大效果越好但参数越多
lora_alpha=32, # LoRA 缩放因子,通常是 r 的 2 倍
lora_dropout=0.05, # dropout,防止过拟合
target_modules=[ # 要加 LoRA 的模块
"q_proj", "k_proj", "v_proj", # Attention 的 QKV 投影
"o_proj", # Attention 的输出投影
"gate_proj", "up_proj", "down_proj" # FFN 层
],
bias="none", # 不训练 bias
)
print("LoRA 配置:")
print(f" 秩 r: {lora_config.r}")
print(f" 可训练参数: {lora_config.lora_alpha / lora_config.r * 100:.1f}%")
DeepSpeed 配置
DeepSpeed ZeRO(Zero Redundancy Optimizer)是一种分布式训练技术,把优化器状态、梯度、参数分片到多张卡上,大幅降低显存占用。
// ds_config.json
{
"zero_optimization": {
"stage": 2,
"offload_optimizer": {
"device": "cpu",
"pin_memory": true
},
"offload_param": {
"device": "cpu",
"pin_memory": true
},
"allgather_partitions": true,
"allgather_bucket_size": 5e7,
"overlap_comm": true,
"reduce_scatter": true,
"reduce_bucket_size": 5e7,
"contiguous_gradients": true
},
"gradient_accumulation_steps": 4,
"gradient_clipping": 1.0,
"steps_per_print": 10,
"train_batch_size": "auto",
"train_micro_batch_size_per_gpu": "auto",
"wall_clock_breakdown": false
}
ZeRO-2 在 8 张 Atlas 800 上可以把 Qwen2.5-7B 的全量微调显存从 512GB 降到 ~200GB。
完整训练脚本
# train_qwen_lora.py
import os
import torch
import torch_npu
import deepspeed
from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments
from peft import LoraConfig, get_peft_model, TaskType
from datasets import load_from_disk
from deepspeed import DeepSpeedConfig
# 配置 DeepSpeed
ds_config = DeepSpeedConfig("ds_config.json")
# 加载模型
model_path = "./models/Qwen2.5-7B"
tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
# 加载模型到 NPU
model = AutoModelForCausalLM.from_pretrained(
model_path,
torch_dtype=torch.float16,
device_map="npu:0",
trust_remote_code=True
)
# 应用 LoRA
lora_config = LoraConfig(
task_type=TaskType.CAUSAL_LM,
r=16,
lora_alpha=32,
lora_dropout=0.05,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "gate_proj", "up_proj", "down_proj"],
bias="none",
)
model = get_peft_model(model, lora_config)
model.print_t
...(truncated)...
鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。
更多推荐



所有评论(0)