Qwen2.5是通义千问大模型系列2024年9月发布,参数量从0.5B到72B不等的多个基础模型和指令微调模型。相比Qwen2,Qwen2.5主要带来以下提升:
本案例包含指令精调的3B参数Qwen2.5模型,具有以下技术特征:
• 类型:因果语言模型
• 训练阶段:预训练+后训练
• 架构:采用RoPE位置编码、SwiGLU激活函数、RMSNorm层标准化、带注意力QKV偏置及词嵌入绑定的Transformer结构
• 参数量:3.09B(非嵌入参数量2.77B)
• 层数:36
• 注意力头配置(分组查询注意力):查询头16个,键值头2个
• 上下文长度:完整支持32,768 tokens,生成长度8,192 tokens
模型huggingface链接:Qwen2.5-3B-Instruct
本案例使用昇腾A3机器上,基于MindspeedLLM 框架完成Qwen2.5-3B-Instruct模型基于业务数据集的SFT训练实践。
Qwen2.5-3B-Instruct在业务数据集上的全参微调训练与评测使用到的软件以及硬件环境如下:
| 硬件名称 | 配置信息 | 备注 |
|---|---|---|
| 机器型号 | A3 超节点 | |
| 测试集群 | 8卡Pod | 单机 |
| 软件 | 版本 | 部署方式 |
|---|---|---|
| Driver | AscendHDK 25.2.0 | 宿主机 |
| Firmware | AscendHDK 25.2.0 | 宿主机 |
| Python | 3.10.18 | 容器 |
| CANN | 8.2.RC1 | 容器 |
| Torch | 2.6.0 | 容器 |
| Torch_npu | 2.6.0 | 容器 |
| MindSpeed | 2.1.0_core_r0.8.0 | 容器 |
| MindSpeed-LLM | 2.1.0 | 容器 |
| Megatron-LM | core_r0.8.0 | 容器 |
| Docker镜像OS | Ubuntu 20.04.6 | / |
MindspeedLLM 镜像已发布,使用方法请参考:昇腾训练镜像构建指导 中 MindSpeed-LLM镜像章节。
业务数据集是ShareGPT风格数据,因此采用ShareGPT风格数据集处理方法进行预处理。
业务当前提供数据集预处理脚本如下:
# 业务数据集预处理
source /usr/local/Ascend/ascend-toolkit/set_env.sh
cd /usr/local/Ascend/llm-train/MindSpeed-LLM
datapath=***
mkdir ${datapath}/train_data_10k
python ./preprocess_data.py \
--input ${datapath}/train_data_10k.jsonl \
--tokenizer-name-or-path /data/***/Qwen2.5-3B-Instruct \
--output-prefix ${datapath}/train_data_10k/train_data_10k \
--workers 4 \
--log-interval 1000 \
--tokenizer-type PretrainedFromHF \
--handler-name SharegptStyleInstructionHandler \
--prompt-type qwen \
--map-keys '{"messages":"messages", "tags":{"role_tag": "role","content_tag": "content","user_tag": "user","assistant_tag": "assistant","system_tag": "system"}}'关键参数说明:
--input(必须):描述: 输入数据文件的路径,通常是一个jsonl(每行一个JSON对象)文件。
示例:
--input /path/to/data.jsonl
--tokenizer-name-or-path(必须):描述: 用于分词器的预训练模型的名称或路径。可以是Hugging Face模型仓库的ID,也可以是本地包含tokenizer文件的目录。
示例:
--tokenizer-name-or-path Qwen/Qwen1.5-7B或者--tokenizer-name-or-path /path/to/tokenizer
--output-prefix(必须):描述: 输出文件的前缀。预处理后的数据会被保存为多个文件(例如,后缀为.bin和.idx),这个参数指定这些文件的前缀路径。
示例:
--output-prefix /path/to/output/preprocessed_data
--workers(可选,默认值可能为1):描述: 指定数据预处理时使用的进程数(多进程)。更多的进程数可以加快处理速度。
示例:
--workers 4
--log-interval(可选,默认值可能为100):描述: 控制日志打印的频率,例如每处理1000条数据打印一次进度日志。
示例:
--log-interval 1000
--tokenizer-type(必须):描述: 指定tokenizer的类型。这里使用
PretrainedFromHF,表示使用Hugging Face的预训练tokenizer。示例:
--tokenizer-type PretrainedFromHF
--handler-name(必须):描述: 指定数据处理器(handler)的类名。这里使用
SharegptStyleInstructionHandler,这是专门为类似ShareGPT格式(对话格式)的指令数据设计的处理器。该处理器会按照指令模板格式化数据。示例:
--handler-name SharegptStyleInstructionHandler
--prompt-type(必须):描述: 指定提示模板类型。不同的提示模板对应不同的格式化方式。这里指定为
qwen,表示使用Qwen模型所要求的提示格式。示例:
--prompt-type qwen
--map-keys(必须):描述: 一个JSON字符串,用于将输入数据中的字段映射到处理器所需的字段。这个参数允许我们自定义输入JSON中的键名,使得处理器能够正确获取角色、内容等信息。
格式: 一个JSON字典,其中至少包括:
"messages": 输入数据中对话列表的键名(通常是一个列表,包含多个对话回合)
"tags": 一个嵌套字典,用于指定在对话回合中每个字段的键名,例如角色(role)、内容(content)等,以及用户、助手和系统角色的标签。
示例:
--map-keys '{"messages":"messages", "tags":{"role_tag":"role", "content_tag":"content", "user_tag":"user", "assistant_tag":"assistant", "system_tag":"system"}}'说明:在这个例子中,输入数据中对话列表的键名为"messages"。在每一个对话回合中,角色字段的键名为"role",内容字段的键名为"content",而用户、助手和系统消息则分别用"user"、"assistant"和"system"来标识(这些标签用于区分消息发送者)。
注意:由于
--map-keys参数是一个JSON字符串,所以需要用单引号括起来(在shell中),并且确保内部双引号被正确转义或保留(这里使用的是JSON字符串,所以内部用双引号)。
数据预处理脚本会将数据按照相应的数据风格进行解析,并且根据prompt-type所对应的模板构建成为prompt,再转化为token后保存到.bin .idx 文件中。下图是解析后的文件示例。

从HuggingFace下载模型权重Qen2.5-3B-Instruct,下载方式参考HF镜像站,其他模型下载可参考Dense模型、MOE模型和SSM模型文档中对应模型的下载链接。下载完成效果如下:

随着大规模预训练模型的广泛应用,不同的训练框架和硬件平台之间的适配性问题逐渐显现。专有训练框架如MindSpeed-LLM通常采用定制的并行化策略(例如Tensor Parallelism、Pipeline Parallelism)以应对大规模模型训练中的内存和计算瓶颈。随着训练需求和硬件的变化,模型参数的切分策略也需进行相应的调整。然而,跨框架的权重转换往往面临格式不兼容和切分策略不同等挑战。权重转换旨在促进大规模预训练模型在不同训练框架之间的无缝迁移与评估,解决框架间权重格式不兼容及切分策略差异等问题,从而增强模型迁移的灵活性和可扩展性,支持更广泛的应用场景和业务需求。
权重转换实现了 HuggingFace 权重到 Megatron-LM 格式的转换,支持多种并行策略(如张量并行、流水并行等),确保转换后可以在 MindSpeed-LLM 框架下继续训练和推理。
当前采用TP=2,PP=1进行权重切分。权重切分具体代码如下:
# 切换MindspeedLLM路径
cd /src/train25.1.0/MindSpeed-LLM
source /usr/local/Ascend/ascend-toolkit/set_env.sh
echo "============== start convert_ckpt ================"
# 设置需要的权重转换参数
python convert_ckpt.py \
--use-mcore-models \
--model-type GPT \
--load-model-type hf \
--save-model-type mg \
--target-tensor-parallel-size 2 \
--target-pipeline-parallel-size 1 \
--add-qkv-bias \
--load-dir /data/***/Qwen2.5-3B-Instruct/ \
--save-dir /data/private/models_mg/Qwen2.5-3B-Instruct_tp2_pp1/ \
--tokenizer-model /data/***/Qwen2.5-3B-Instruct/tokenizer.json \
--model-type-hf llama2 \
--params-dtype bf16| 参数 | 说明 | 可选/必选 |
|---|---|---|
| --target-tensor-parallel-size | TP 切分数量,默认为 1 | 必选 |
| --target-pipeline-parallel-size | PP 切分数量,默认为 1 | 必选 |
| --num-layer-list | 动态PP划分,通过列表指定每个PP Stage的层数,默认为None | 可选 |
| --num-layers-per-virtual-pipeline-stage | VPP划分,指定VPP的每个Stage层数,默认为None | 可选 |
| --target-expert-model-parallel-size | 专家并行,指定专家并行卡数,默认为1 | 可选 |
| --noop-layers | 自定义空层操作,指定在模型某层增加空层,转换后层数为原huggingface模型层数+空层数,默认为None | 可选 |
| --use-mcore-models | 转换为Megatron-Mcore权重,若不指定,则默认转换为Megatron-Legacy权重 | 可选 |
| --model-type-hf | huggingface模型类别,默认为llama2,参考注意 2 | 可选 |
| --tokenizer-model | 需要指明到具体的分词器模型文件,如 tokenizer.model、tokenizer.json、qwen.tiktoken、None等,具体取决于huggingface中词表文件的格式形式 | 必选 |
| --params-dtype | 指定权重转换后的权重精度模式,默认为fp16,如果源格式文件为bf16,则需要对应设置为bf16,影响推理或评估结果 | 必选 |
注意:
VPP和动态PP划分只能二选一
目前支持的模型见 model_cfg.json中“model_mappings”下包含的模型。
关键参数说明:
qwen2.5模型这里的--model-type-hf需要设置为:llama2。参考目前支持的模型 model_cfg.json中“model_mappings”下包含的模型参数映射关系。
执行结果如下:

全参官方参考链接: 大模型指令微调
#!/bin/bash
# 脚本名:/data/private/scripts/llm/qwen25-3b-instruct/tune_qwen25_3b_4k_full_ptd.sh
cd /src/train25.1.0/MindSpeed-LLM
source /usr/local/Ascend/ascend-toolkit/set_env.sh
export HCCL_CONNECT_TIMEOUT=1200
export CUDA_DEVICE_MAX_CONNECTIONS=1
export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
NPUS_PER_NODE=16
MASTER_ADDR=localhost
MASTER_PORT=2901
NNODES=1
NODE_RANK=0
WORLD_SIZE=$(($NPUS_PER_NODE*$NNODES))
mkdir -p /data/private/outputs/llm/qwen2.5-3b-instruct/logs
echo "============== start train ================"
# please fill these path configurations
CKPT_LOAD_DIR="/data/private/models_mg/Qwen2.5-3B-Instruct_tp2_pp1/"
CKPT_SAVE_DIR="/data/private/models_mg/ckpt/Qwen2.5-3B-Instruct_tp2_pp1/"
DATA_PATH=""
TOKENIZER_PATH="/data/***/Qwen2.5-3B-Instruct"
tensorboard_dir="/data/private/outputs/llm/qwen2.5-3b-instruct/logs/tensorboard_dir/full"
train_log_path="/data/private/outputs/llm/qwen2.5-3b-instruct/logs/tune_mcore_qwen25_3b_full_tp2_pp1_train.log"
TP=2
PP=1
MBS=8
GBS=128
SEQ_LEN=2048
TRAIN_ITERS=400
DISTRIBUTED_ARGS="
--nproc_per_node $NPUS_PER_NODE \
--nnodes $NNODES \
--node_rank $NODE_RANK \
--master_addr $MASTER_ADDR \
--master_port $MASTER_PORT
"
GPT_ARGS="
--finetune \
--stage sft \
--is-instruction-dataset \
--tokenizer-not-use-fast \
--prompt-type qwen \
--variable-seq-lengths \
--use-mcore-models \
--tensor-model-parallel-size ${TP} \
--pipeline-model-parallel-size ${PP} \
--num-layers 36 \
--hidden-size 2048 \
--ffn-hidden-size 11008 \
--num-attention-heads 16 \
--group-query-attention \
--num-query-groups 2 \
--tokenizer-type PretrainedFromHF \
--tokenizer-name-or-path ${TOKENIZER_PATH} \
--seq-length ${SEQ_LEN} \
--max-position-embeddings ${SEQ_LEN} \
--micro-batch-size ${MBS} \
--global-batch-size ${GBS} \
--make-vocab-size-divisible-by 1 \
--padded-vocab-size 151936 \
--rotary-base 1000000 \
--train-iters ${TRAIN_ITERS} \
--lr 1.0e-5 \
--weight-decay 0.0 \
--lr-decay-style cosine \
--clip-grad 1.0 \
--adam-beta1 0.9 \
--adam-beta2 0.999 \
--add-qkv-bias \
--disable-bias-linear \
--attention-dropout 0.0 \
--init-method-std 0.02 \
--hidden-dropout 0.0 \
--position-embedding-type rope \
--normalization RMSNorm \
--norm-epsilon 1e-06 \
--swiglu \
--use-flash-attn \
--use-rotary-position-embeddings \
--no-masked-softmax-fusion \
--attention-softmax-in-fp32 \
--initial-loss-scale 4096 \
--no-gradient-accumulation-fusion \
--no-load-optim \
--no-load-rng \
--seed 42 \
--bf16\
--tensorboard-dir $tensorboard_dir \
"
DATA_ARGS="
--data-path $DATA_PATH \
--split 100,0,0
"
OUTPUT_ARGS="
--log-interval 1 \
--save-interval 2000 \
--eval-interval 2000 \
--eval-iters 0 \
"
torchrun $DISTRIBUTED_ARGS posttrain_gpt.py \
$GPT_ARGS \
$DATA_ARGS \
$OUTPUT_ARGS \
--distributed-backend nccl \
--load ${CKPT_LOAD_DIR} \
--save ${CKPT_SAVE_DIR} \
2>&1 | tee $train_log_pathcd ***/MindSpeed-LLM
bash /data/private/scripts/llm/qwen25-3b-instruct/tune_qwen25_3b_4k_full_ptd.sh如下图所示,loss曲线正常下降。

NPU设备上业务数据集评分结果如下图所示,精度满足客户需求。
