Qwen 昇腾 NPU 微调实战:基于 mindformers 的 7B/14B 全流程指南
Qwen 昇腾 NPU 微调实战:基于 mindformers 的 7B/14B 全流程指南
本文是 Qwen(通义千问)系列大模型在昇腾(Ascend)910A/B NPU 上完成微调的实操指南。文中基于当前仓库 recipes/finetune/ascend/README.md 的官方流程,结合仓库内 ascend-support 辅助脚本,完整覆盖「环境准备 → 模型下载与权重转换 → 训练数据预处理 → 分布式训练 → 权重合并 → 推理验证」的端到端闭环。读完本文,你将能够在昇腾 NPU 集群上独立复现 Qwen-7B / Qwen-14B 的微调训练,并对 mindformers 训练管线中的关键参数与底层机制有清晰认识。
适用范围与前提
本方案面向以下场景与约束:
- 硬件:昇腾 910A / 910B 系列 NPU(即 Ascend 910A/B),通过
/dev/davinci*设备节点接入容器。 - 模型:当前官方验证支持 Qwen 7B 与 Qwen 14B 的微调和推理;本文以 Qwen-7B-Chat 为例展开。
- 软件栈:基于阿里云 PAI 提供的 llm-inference 预构建镜像(内含 mindformers 框架),因此训练管线整体运行在 MindSpore 生态上,而非 PyTorch + CUDA。
- 训练范式:mindformers 的多卡并行微调(8 NPU),以 chat 模型为对象进行指令微调。
说明:更详细、更新版本的 mindformers 昇腾用法可参考 mindformers 官方文档中
research/qwen目录的说明;本文以本仓库固定版本的实际命令为准。
整体流程概览
整个微调链路可以划分为七个环节,与官方文档步骤一一对应:
- 启动带昇腾驱动的 Docker 镜像(打通 NPU 设备与驱动映射);
- 下载官方模型(ModelScope)并转换为 mindformers 的 ckpt 权重格式;
- 准备训练数据:原始 JSON → 对话格式 JSON → Mindrecord 二进制格式;
- 生成 RANK_TABLE_FILE,声明 8 卡 NPU 的拓扑关系;
- 以
run_qwen.py启动 8 卡分布式微调; - 合并多卡训练产出的分片权重;
- 用微调后的权重进行推理验证。
下面按步骤逐一展开,并补充源码级参数说明。
第一步:启动 Docker 镜像(打通 NPU 环境)
手动启动方式
昇腾设备无法在容器内热插拔,因此容器启动时必须把 NPU 设备、驱动、监控工具逐一映射进去。官方给出的完整命令如下:
ImageID=pai-image-manage-registry.cn-wulanchabu.cr.aliyuncs.com/pai/llm-inference:qwen_v23.0.rc3
docker run -it -u root --ipc=host \
--device=/dev/davinci0 \
--device=/dev/davinci1 \
--device=/dev/davinci2 \
--device=/dev/davinci3 \
--device=/dev/davinci4 \
--device=/dev/davinci5 \
--device=/dev/davinci6 \
--device=/dev/davinci7 \
--device=/dev/davinci_manager \
--device=/dev/devmm_svm \
--device=/dev/hisi_hdc \
-v /usr/local/Ascend/driver:/usr/local/Ascend/driver \
-v /usr/local/Ascend/add-ons/:/usr/local/Ascend/add-ons/ \
-v /usr/local/bin/npu-smi:/usr/local/bin/npu-smi \
-v /usr/local/sbin/npu-smi:/usr/local/sbin/npu-smi \
-v /etc/ascend_install.info:/etc/ascend_install.info \
-v /var/log/npu/:/usr/slog \
-v /etc/hccn.conf:/etc/hccn.conf \
${ImageID} /bin/bash
各挂载项的作用归纳如下:
| 参数 | 作用 |
|---|---|
--device=/dev/davinci0..7 |
映射 8 个 NPU 计算设备,对应微调所需的 8 卡资源 |
--device=/dev/davinci_manager |
昇腾设备管理接口(Device Manager) |
--device=/dev/devmm_svm |
设备内存管理(SVM)节点 |
--device=/dev/hisi_hdc |
昇腾 Host-Device 通信通道(HDC) |
/usr/local/Ascend/driver |
昇腾驱动库,容器内算子执行依赖 |
/usr/local/Ascend/add-ons/ |
驱动附加组件 |
/usr/local/bin/npu-smi 等 |
NPU 状态监控工具 npu-smi |
/etc/ascend_install.info |
昇腾软件安装信息文件 |
/var/log/npu/ → /usr/slog |
NPU 运行日志目录映射 |
/etc/hccn.conf |
HCCN(华为集合通信库)配置,多卡通信依赖 |
使用仓库内置脚本快速启动
除了手动拼写上述长命令,本仓库在 ascend-support/docker_qwen.sh 中封装了一个等价脚本(该脚本面向推理场景,镜像为 qwenllm/qwen-mindspore:v23.0.RC3),用法如下:
cd /path/to/Qwen/ascend-support
# 下载模型到本地目录,例如 /path/to/Qwen-7B-Chat
CHECKPOINT_PATH=/path/to/Qwen-7B-Chat
# 启动 docker 容器
bash docker_qwen.sh -c ${CHECKPOINT_PATH}
脚本支持的参数:
-i / --image:指定镜像名,默认qwenllm/qwen-mindspore:v23.0.RC3;-c / --checkpoint:宿主机构模型权重目录,默认挂载到容器内/data/qwen/models/Qwen-7B-Chat;-n / --name:容器名,默认qwen-mindspore;-h:打印用法。
从脚本实现可以看出,它同样映射了全部 8 个 davinci 设备与驱动文件,与官方微调镜像的设备映射逻辑一致,可作为快速验证环境连通性的入口。
第二步:下载官方模型并转换权重
通过 ModelScope 下载模型
在容器内进入 mindformers 代码目录后,使用 ModelScope SDK 将 Qwen-7B-Chat 权重与代码下载到本地:
cd mindformers
python3 -c "from modelscope.hub.snapshot_download import snapshot_download; snapshot_download('Qwen/Qwen-7B-Chat', cache_dir='.', revision='master')"
下载完成后,模型目录下会包含权重文件、qwen.tiktoken 分词词表以及模型代码文件。qwen.tiktoken 是 Qwen 基于 tiktoken 的分词器词表,在后续数据预处理与微调启动时都需要显式指定(详见第三步与第五步)。
将 HuggingFace/ModelScope 权重转换为 ckpt
mindformers 的并行训练格式与 Transformers 的权重组织方式不同,必须先用官方转换脚本完成格式迁移:
python research/qwen/convert_weight.py \
--torch_ckpt_dir Qwen/Qwen-7B-Chat \
--mindspore_ckpt_path qwen-7b-chat.ckpt
mkdir -vp load_checkpoint/rank_0
mv qwen-7b-chat.ckpt load_checkpoint/rank_0/
要点说明:
--torch_ckpt_dir指向第一步下载的原始模型目录;--mindspore_ckpt_path指定转换后 ckpt 的输出路径;- 转换产物必须放置到
load_checkpoint/rank_0/目录下,这是 mindformers 微调启动时加载预训练权重的默认约定路径; - 若在 ascend-support/README.md 描述的推理容器中执行,对应命令为
python3 /data/qwen/mindformers/research/qwen/convert_weight.py,转换结果输出在${CHECKPOINT_PATH}/qwen-7b-chat.ckpt。
第三步:准备训练数据(JSON → Mindrecord)
mindformers 的 run_qwen.py 训练入口直接消费 Mindrecord 二进制格式,因此原始对话数据需要经过两次转换。
3.1 下载演示数据集
官方提供了一份精简的 Alpaca 指令数据用于跑通流程:
wget -c https://pai-vision-data-hz.oss-cn-zhangjiakou.aliyuncs.com/alpaca_data_min.json
3.2 转换为对话(conversation)格式
python research/qwen/alpaca_converter.py \
--data_path alpaca_data_min.json \
--output_path alpaca-data-conversation_min.json
该脚本把 Alpaca 的 instruction / input / output 三字段结构重排为多轮对话列表,使其符合 Qwen ChatML 对话模板的训练习惯。
3.3 生成 Mindrecord 数据
python research/qwen/qwen_preprocess.py \
--input_glob alpaca-data-conversation_min.json \
--model_file Qwen/Qwen-7B-Chat/qwen.tiktoken \
--seq_length 1024 \
--output_file alpaca_min.mindrecord
关键参数:
--model_file:必须指向模型目录中的qwen.tiktoken,保证切词与模型训练时一致(Qwen 分词器基于 tiktoken,与 SentencePiece 系分词器有本质区别,微调时对特殊 token 的处理需要格外注意,可参考仓库 tokenization_note.md 的说明);--seq_length 1024:单样本截断/补齐的目标序列长度,实际训练时需根据显存与业务数据长度权衡;--output_file:产出的 Mindrecord 文件路径,将直接传给微调命令的--train_data。
第四步:生成 RANK_TABLE_FILE(8 卡拓扑)
mindformers 多卡并行依赖 RANK_TABLE_FILE 描述设备拓扑与 rank 映射。使用仓库自带的 hccl_tools.py 一键生成 8 卡配置:
# generate RANK_TABLE_FILE with 8 npu
python mindformers/tools/hccl_tools.py --device_num "[0,8)"
--device_num "[0,8)"表示取物理设备编号 0~7 共 8 张 NPU;- 生成物通常为形如
hccl_8p_*.json的文件,微调启动时需将其路径替换到命令中的RANK_TABLE_FILE位置(见下一步)。
第五步:启动 8 卡分布式微调
官方微调命令
export MS_ASCEND_CHECK_OVERFLOW_MODE=INFNAN_MODE
bash research/run_singlenode.sh "python3 research/qwen/run_qwen.py \
--config research/qwen/run_qwen_7b.yaml \
--load_checkpoint /mindformers/research/qwen/load_checkpoint \
--vocab_file Qwen/Qwen-7B-Chat/qwen.tiktoken \
--use_parallel True \
--run_mode finetune \
--auto_trans_ckpt True \
--train_data alpaca_min.mindrecord" \
RANK_TABLE_FILE [0,8] 8
参数逐项解读
| 参数 | 含义与取值 |
|---|---|
MS_ASCEND_CHECK_OVERFLOW_MODE=INFNAN_MODE |
昇腾环境变量:开启 InfNaN 溢出检测模式,训练出现梯度溢出时打印告警,便于定位 |
--config research/qwen/run_qwen_7b.yaml |
模型结构、优化器、学习率、训练步数等超参的 YAML 配置文件;微调 14B 时替换为对应的 run_qwen_14b.yaml |
--load_checkpoint .../load_checkpoint |
预训练权重所在目录,即第二步中放置 rank_0/checkpoint... 的 load_checkpoint 目录 |
--vocab_file |
tiktoken 词表路径,须与第三步预处理时使用的一致 |
--use_parallel True |
开启分布式并行训练,配合 RANK_TABLE_FILE 使用 |
--run_mode finetune |
运行模式:训练为 finetune,推理为 predict |
--auto_trans_ckpt True |
自动完成权重切分:将单份预训练 ckpt 按并行策略自动转换为各 rank 的分片,免去手工拆分 |
--train_data alpaca_min.mindrecord |
第三步产出的 Mindrecord 训练数据 |
RANK_TABLE_FILE [0,8] 8 |
run_singlenode.sh 的入参:分别指定拓扑文件、使用的设备区间(0~7)与进程数(8) |
关于 run_singlenode.sh:它是 mindformers 提供的单机多卡启动封装,内部会依据 RANK_TABLE_FILE 为每个 rank 设置 RANK_ID、DEVICE_ID 等环境变量,并依次拉起 8 个训练进程。若直接裸跑,等价于为每个 NPU 进程设置好环境后分别执行 run_qwen.py。
环境变量层面的一点提醒
与 PyTorch 微调脚本(仓库根目录 finetune.py 配合 DeepSpeed/FSDP 运行于 CUDA 环境)不同,本步骤属于 MindSpore 生态,参数体系完全不同——例如不设 --use_lora / --q_lora / --deepspeed 这类 PyTorch 侧参数,而是由 YAML 配置驱动训练行为。跨生态迁移时不要混淆两套入口。
第六步:合并模型权重
8 卡并行训练结束后,每个 rank 只保存自己负责的参数分片,需要先重命名再合并为完整权重。
6.1 重命名分片文件
cd output/checkpoint_network
mv rank_0/qwen_rank_0-network.ckpt rank_0/checkpoint_0.ckpt
mv rank_1/qwen_rank_1-network.ckpt rank_1/checkpoint_1.ckpt
mv rank_2/qwen_rank_2-network.ckpt rank_2/checkpoint_2.ckpt
mv rank_3/qwen_rank_3-network.ckpt rank_3/checkpoint_3.ckpt
mv rank_4/qwen_rank_4-network.ckpt rank_4/checkpoint_4.ckpt
mv rank_5/qwen_rank_5-network.ckpt rank_5/checkpoint_5.ckpt
mv rank_6/qwen_rank_6-network.ckpt rank_6/checkpoint_6.ckpt
mv rank_7/qwen_rank_7-network.ckpt rank_7/checkpoint_7.ckpt
cd ../..
注意:上述
mv命令为官方文档给出的原始操作;实际执行时请确认目录结构一致后再进行,避免覆盖已有文件。
6.2 合并为完整权重
python mindformers/tools/transform_ckpt.py \
--src_ckpt_strategy output/strategy \
--src_ckpt_dir output/checkpoint_network \
--dst_ckpt_dir output/merged_model
--src_ckpt_strategy:训练时保存的并行切分策略文件(output/strategy),记录权重与 rank 的映射关系;--src_ckpt_dir:重命名后的分片目录;--dst_ckpt_dir:合并产物的输出目录(output/merged_model),后续推理直接使用其rank_0/checkpoint_0.ckpt。
第七步:推理验证微调结果
合并完成后,使用与训练相同的入口、以 predict 模式加载合并权重进行验证:
python research/qwen/run_qwen.py \
--config research/qwen/run_qwen_7b.yaml \
--predict_data '比较适合深度学习入门的书籍有' \
--run_mode predict \
--load_checkpoint output/merged_model/rank_0/checkpoint_0.ckpt \
--vocab_file Qwen/Qwen-7B-Chat/qwen.tiktoken \
--auto_trans_ckpt False \
--device_id 0
与训练命令的差异点:
--run_mode predict:切换为推理模式;--predict_data:直接以字符串形式传入测试 prompt;--load_checkpoint:指向合并后的rank_0/checkpoint_0.ckpt;--auto_trans_ckpt False:权重已是完整单份,无需再自动切分;--device_id 0:单卡推理,只需指定一张 NPU。
若模型对 prompt 的输出符合微调数据所期望的指令跟随行为(例如回答风格、领域知识明显偏向训练数据),则说明微调链路闭环成功。
附:仓库内的昇腾推理辅助方案
除微调外,本仓库还提供了昇腾环境下的快速推理入口。在 ascend-support/README.md 中给出了与微调共享同一套 mindformers 生态的推理流程:
- 下载官方模型到本地后启动容器(
bash docker_qwen.sh -c ${CHECKPOINT_PATH}); - 在容器内执行
python3 /data/qwen/mindformers/research/qwen/convert_weight.py完成权重转换(输出${CHECKPOINT_PATH}/qwen-7b-chat.ckpt); - 进入
/data/qwen/mindformers/research/qwen,设置PYTHONPATH后执行python3 infer_qwen.py进行推理。
该方案可作为微调前验证环境连通性、或微调后对比效果的辅助手段。
常见问题与注意事项
- 设备映射缺失:容器内报
No device类错误时,优先检查docker run是否完整映射了davinci0~7、davinci_manager、devmm_svm、hisi_hdc等设备节点; - 驱动版本不匹配:容器内昇腾算子无法执行时,核对宿主机
/usr/local/Ascend/driver与镜像要求是否一致; - 权重转换失败:确认
--torch_ckpt_dir指向的目录包含完整的模型代码与权重文件,且revision与模型版本匹配; - 数据格式错误:
qwen_preprocess.py报词表相关错误时,确认--model_file使用的是模型自带的qwen.tiktoken; RANK_TABLE_FILE未替换:第五步命令中的RANK_TABLE_FILE需替换为第四步实际生成的文件路径,否则并行启动会失败;- 多卡权重不完整:合并前务必确认
output/checkpoint_network/rank_0~7八个分片全部存在且命名正确。
相关资源
- 官方微调文档:recipes/finetune/ascend/README.md
- 昇腾推理辅助方案:ascend-support/README.md
- 容器启动脚本:ascend-support/docker_qwen.sh
- Qwen 项目总览与模型列表:README.md(其中 2023.11.30 更新明确说明 Qwen-72B/Qwen-1.8B 发布时同步支持了 Ascend 910 推理,
ascend-support目录即为佐证) - 分词器与微调注意点:tokenization_note.md
- GPU(CUDA)侧的对比微调方案:finetune.py 及 finetune/finetune_ds.sh(PyTorch + DeepSpeed 生态,与昇腾方案互不通用,请勿混用两套参数)