CANN 平台 Qwen3.6-27B 微调实战:基于 MindSpeed-MM 的全参 SFT 与 LoRA-SFT 完整指南
【免费下载链接】cann-recipes-train本项目针对LLM与多模态模型训练业务中的典型模型、加速算法,提供基于CANN平台的优化样例项目地址: https://gitcode.com/cann/cann-recipes-train
本文是 cann-recipes-train 仓库中 Qwen3.6-27B SFT 使用指南(对应中文版)的深度展开版。文章以该指南为核心骨架,完整继承其全部操作步骤与命令,并结合仓库内的补丁源码、三套 YAML 配置、数据生成工具与实践报告,从"怎么跑"延伸到"为什么这么设计",帮助你在 Atlas A3 NPU(16 die、CANN 9.0.0)上完整复现 Qwen3.6-27B 的监督微调(SFT)流程。
核心导读:本文介绍如何在昇腾 CANN 平台上,基于 MindSpeed-MM(FSDP2 训练框架)对 Qwen3.6-27B 执行监督微调,覆盖三种典型方案——packing 全参 SFT(64K 上下文打包训练)、unpacking 全参 SFT(per-sample loss)与 LoRA SFT(参数高效微调)。读完本文,你将掌握:代码获取与补丁应用、CANN/Python 环境搭建、HF 权重到 DCP 格式转换、JSONL 数据生成与格式转换、三套配置文件的逐项参数含义、NPU 空闲调度式后台训练,以及 DCP checkpoint 批量转回 Hugging Face 格式的完整闭环,并理解仓库补丁在 epoch 训练调度、LoRA 初始化保存、checkpoint dtype 等底层能力上的工程化增强。
一、方案背景与示例环境
Qwen3.6-27B 是包含视觉编码器(visual)与语言模型(language_model)的多模态基础模型,其语言模型部分包含混合线性注意力架构(Full Attention + Gated DeltaNet,即 GDN)。基于 MindSpeed-MM 训练时,官方示例默认冻结视觉模块,仅训练语言模型,因此指南所称"全参"指语言模型部分的全参数训练。
示例环境与版本信息:
| 项目 | 值 |
|---|---|
| CANN | 9.0.0 |
| 硬件 | Atlas A3 NPU,16 die |
| 训练框架 | MindSpeed-MM(固定 commitaaed711fd4750857f104e8d832766ed915ff9ef0+ 仓库补丁) |
| 目标模型 | Qwen3.6-27B(Hugging Face 格式) |
该方案的完整实践背景与评测结果见仓库内的实践报告:该报告基于同一批训练代码,面向 cann-bench 的 AscendC 算子生成任务,报告了全参 SFT、LoRA-SFT 等阶段在 Level 1/Level 2 任务上的 PASS@5、AVG@5 指标,可作为训练效果的上游参考。
二、获取代码:拉取 MindSpeed-MM 并应用仓库补丁
仓库为 MindSpeed-MM 提供了针对 Qwen3.6-27B SFT 的完整适配补丁 mindspeed-mm.patch。在工作目录执行以下命令:
git clone https://gitcode.com/Ascend/MindSpeed-MM.git cd MindSpeed-MM git checkout aaed711fd4750857f104e8d832766ed915ff9ef0 git apply --check ../mindspeed-mm.patch git apply ../mindspeed-mm.patch要点说明:
- 后续所有命令均在
MindSpeed-MM根目录执行; - 若补丁文件不在上级目录,请将
../mindspeed-mm.patch替换为其实际路径; git apply --check用于预检补丁能否干净应用,建议先执行再正式应用;- 该补丁基于基线 commit 生成,共涉及 31 个文件(13 个新增、18 个修改),覆盖训练调度、LoRA、checkpoint、数据处理、启动脚本与测试等 8 大模块(详见补丁说明与本文第六节)。
三、环境安装
3.1 配置 CANN 环境
请先按照昇腾软件安装指南完成驱动、固件以及 CANN Toolkit 的安装。本示例使用CANN 9.0.0。确认 CANN 环境变量已生效,例如按实际安装路径执行:
source /usr/local/Ascend/cann/set_env.sh3.2 配置 Python 环境
推荐使用 Conda 管理 Python 包:
conda create -n qw36-sft python=3.11 -y conda activate qw36-sft bash scripts/install.sh --msid eb10b92 pip install transformers==5.2.0 accelerate==1.2.0 pip install triton-ascend==3.2.1 \ --extra-index-url https://mirrors.huaweicloud.com/ascend/repos/pypi # 如果出现 ModuleNotFoundError: No module named 'pkg_resources',请使用低版本的 setuptools pip install setuptools==81.0.0版本配套经验(来自补丁说明对启动脚本的补充):
setuptools需低于82.0.0;triton-ascend与 CANN 版本强相关:CANN 8.5.0 使用triton-ascend==3.2.0,CANN 9.0.0 使用triton-ascend==3.2.1;- LoRA-SFT 在实践报告中的软件组合为 PyTorch 2.7.1、torch-npu 2.7.1、Transformers 5.2.0、PEFT 0.7.1、Triton-ascend 3.2.1,可作参考。
四、初始模型下载与 DCP 格式转换
4.1 下载模型
从 ModelScope 或 Hugging Face 下载 Qwen3.6-27B(Hugging Face 格式),放置到以下目录(目录名必须与配置文件保持一致):
MindSpeed-MM/ckpt/hf_path/Qwen3.6-27B/该目录应包含模型权重、配置文件与 tokenizer 相关文件,例如config.json、*.safetensors、tokenizer.json等。
4.2 转换为 DCP 格式
示例配置启用了init_model_with_meta_device(meta device 初始化),因此训练前必须先将 Hugging Face 权重转换为 DCP(Distributed Checkpoint)格式:
bash cvt_ckpt_hf2dcp.sh脚本使用固定输入/输出路径(如需修改请修改脚本本身):
输入:ckpt/hf_path/Qwen3.6-27B 输出:ckpt/dcp_path/Qwen3.6-27B转换完成后,输出目录应包含release/与latest_checkpointed_iteration.txt。配置文件中的training.load应指向ckpt/dcp_path/Qwen3.6-27B,不要直接指向release/子目录。
从补丁源码看,该脚本基于 MindSpeed-MM 的mm-convert Qwen35Converter hf_to_dcp命令实现(见补丁中新增的cvt_ckpt_hf2dcp.sh),与 Qwen3.6-27B 的模型结构(含 GDN 混合注意力)对应的转换器绑定。
五、数据准备与转换
5.1 下载原始数据
数据集下载地址:https://link.gitcode.com/i/a9a8ecefe9df55812d245c9a1981765d(该讨论贴开放了部分训练数据,与实践报告中第 8 章的"开放数据实验"对应)。
5.2 使用 data_generator 生成数据集
使用仓库提供的 data_generator 生成数据集,生成过程中会调用仓库提供的 prompt_generator 生成 prompt:
python path-to-data_generator/generate_data.py \ --source-root path-to-data \ --output-dir path-to-generated-data \ --filter-ops exp foreach_addcdiv_scalar foreach_norm gelu masked_scale mish sigmoid swi_glu \ apply_adam_w apply_rotary_pos_emb arg_max cross_entropy_loss cummin dynamic_quant gather gcd \ grid_sampler_3d group_norm maximum resize_bilinear rms_norm scatter softmax unsorted_segment_sum \ --clean从 generate_data.py 的源码结构看,其工作机制为:
- 以每个算子的
<op>/desc目录(含cases.yaml、desc.md、golden.py、proto.yaml)作为 prompt 输入,以<op>/src(或src_N)目录中的op_kernel/*_kernel.cpp、*_launch.h、op_plugin/*_plugin.cpp、CMakeLists.txt作为标准答案,构造"任务描述 → 完整 AscendC 交付件"的训练对; - prompt 类型为
md-code-block-oneshot(带 one-shot 示例,默认示例为sqrt),输出类型为md-code-block; --filter-ops用于排除指定算子(支持归一化算子名与数字副本匹配,如op_2);--clean会先清理inputs、outputs、jsonl、manifests、intermediate等自有输出目录;--with-thinking可在答案前附上thinking.md中的思维链;- 生成的 JSONL 文件为
jsonl/md-code-block-oneshot.jsonl,每条记录采用instruction/input/output格式(instruction为空字符串,input为 prompt,output为标准答案)。
5.3 JSONL 输入格式约定
本项目的数据处理脚本接收 JSONL 文件,每行必须是一个 JSON 对象,支持以下任一格式:
{"instruction": "任务描述", "input": "任务内容", "output": "答案"}或:
{"prompt": "任务内容", "response": "答案"}字段规则:
instruction/input/output格式要求包含input与output字段;当instruction非空时,会与input以换行拼接;prompt/response格式要求两个字段同时存在;- 使用仓库 data_generator 生成的数据集是上述第一种格式。
5.4 放置 JSONL 文件
在 MindSpeed-MM 根目录创建数据目录并放入训练数据:
mkdir -p data/jsonl data/json默认示例需要以下两个文件:
data/jsonl/ops-data.jsonl data/jsonl/sampled-data.jsonl文件名可以调整,但需同步修改 YAML 配置中的data.dataset_param.basic_parameters.dataset。
5.5 转换为训练 JSON
执行批量转换:
bash cvt_data_format_jsonl2json.sh \ 'data/jsonl/*.jsonl' \ 'data/json/*.json'转换后的文件写入data/json/,并被示例配置中的./data/json/*.json自动读取。脚本会逐行校验 JSON 语法、对象类型以及必需字段;输入存在错误时直接报错,请修正后重新执行。
该脚本由补丁新增(对应补丁说明第 4 点),其内部逻辑(可见补丁内嵌的 Python 实现)值得注意:
- 支持单文件与 glob 批量两种模式;批量模式下,输入 glob 静态根目录下的层级结构会映射到输出根目录;
- 统一生成
messages(user/assistant 两轮对话)结构,并附带空的images列表,供 Qwen3.6 的多模态数据管线直接消费; instruction非空时与input用换行拼接为 user 内容;prompt/response则直接映射为 user/assistant 内容;- 仓库补丁还配套了单元测试
tests/ut/test_cvt_data_format_jsonl2json.py,覆盖两种格式的转换结果与缺失字段报错场景,可作为脚本行为的权威参考。
六、三套训练配置详解
将仓库提供的三个配置文件放置到MindSpeed-MM/examples/qwen3_6目录下:
packing 全参 SFT 配置 examples/qwen3_6/qwen3_6_27B_config_packing64k_gbs2.yaml unpacking 全参 SFT 配置 examples/qwen3_6/qwen3_6_27B_config_gbs16.yaml unpacking LoRA SFT 配置 examples/qwen3_6/qwen3_6_27B_config_LoRA_gbs8.yaml训练前请确认配置中的以下路径与本地目录一致:
| 配置项 | 含义 |
|---|---|
data.dataset_param.preprocess_parameters.model_name_or_path | 原始 Hugging Face 模型目录 |
data.dataset_param.basic_parameters.dataset | 转换后的 JSON 数据 |
model.model_name_or_path | 原始 Hugging Face 模型目录 |
training.load | 转换后的 DCP 目录 |
training.save | 训练输出目录 |
6.1 三套配置的共同基础
对照仓库中的 packing 配置、unpacking 配置 与 LoRA 配置,三套配置共享以下结构:
并行策略(parallel)
parallel: fully_shard_parallel_size: auto # FSDP2 全分片并行,自动推断 fsdp_plan: apply_modules: # 分片范围;开启 prefetch 时勿随意改动顺序 - model.visual - model.visual.blocks.{*} - model.language_model - model.language_model.embed_tokens - model.language_model.layers.{*} - lm_head param_dtype: bf16 # 参数 BF16 reduce_dtype: fp32 # 梯度归约 FP32 ulysses_parallel_size: 8 # Ulysses 序列并行(CP);开启时需配合 flash_attention_2配置注释明确要求:开启 ulysses-cp 时,须将 model 的
attn_implementation设置为flash_attention_2。
数据相关(data)
data: dataset_param: dataset_type: huggingface attr: images: null messages: messages role_tag: role content_tag: content user_tag: user assistant_tag: assistant preprocess_parameters: model_name_or_path: &HF_MODEL_LOAD_PATH ./ckpt/hf_path/Qwen3.6-27B # 替换为原始 hf 权重 use_fast_tokenizer: true split_special_tokens: false image_max_pixels: 262144 image_min_pixels: 1024 video_max_pixels: 16384 video_min_pixels: 0 video_fps: 2.0 video_maxlen: 64 basic_parameters: cutoff_len: 65536 # 上下文长度 64K template: qwen3_6_nothink # 无 thinking 模板 enable_thinking: false train_on_prompt: false mask_history: false dataset_dir: ./data dataset: &DATASET_PATH - "./data/json/*.json" # 转换后的 JSON 数据 cache_dir: ./cache_dir/ overwrite_cache: false preprocessing_batch_size: 1000 preprocessing_num_workers: 16 max_samples: null dataloader_param: pin_memory: true shuffle: true dataloader_mode: sampler drop_last: true sampler_type: BaseRandomBatchSampler # 项目自定义 sampler num_workers: 8 collate_param: model_name: qwen3vl ignore_pad_token_for_loss: true enable_preload: false模型与优化特性(model/features)
model: model_id: qwen3_5 model_name_or_path: *HF_MODEL_LOAD_PATH trust_remote_code: true attn_implementation: flash_attention_2 freeze: - model.visual # 冻结视觉模块 gdn_implementation: triton # GDN 融合算子用 triton causal_conv1d_implementation: triton # 因果卷积实现(LoRA 配置为 eager) features: loss_cfg: loss_type: per_token_loss # packing 配置;unpacking 配置为 per_sample_loss router_aux_loss_coef: 0.0 recompute: true # 激活重计算 recompute_plan: apply_modules: - model.visual.blocks.{*} - model.language_model.layers.{*} enable_chunk_loss: true # chunk loss,降低激活峰值 chunkloss_plan: apply_module: lm_head chunk_size: 1024 enable_activation_offload: true # 激活 offload activation_offload_plan: apply_modules: - model.visual.blocks.{*} - model.language_model.layers.{*}训练配置(training)——三套配置的差异点
| 配置项 | packing 全参 | unpacking 全参 | LoRA |
|---|---|---|---|
micro_batch_size | 1 | 1 | 1 |
gradient_accumulation_steps | 1 | 8 | 4 |
| global batch size(推算) | 2 | 16 | 8 |
lr | 1.0e-5 | 1.0e-5 | 1.0e-4(LoRA 适配器用更高学习率) |
lr_warmup_ratio | 0.1 | 0.1 | 0.05 |
lr_decay_style | cosine | cosine | cosine |
weight_decay | 0 | 0 | 0 |
train_epochs | 3 | 3 | 5 |
clip_grad | 0.0(不裁剪) | 0.0 | 1.0 |
save_interval | 1(epoch 模式) | 1 | 1 |
loss_type | per_token_loss | per_sample_loss | default |
causal_conv1d_implementation | triton | eager | eager |
输出目录save | ./outputs/packing64k-gbs2 | ./outputs/gbs16 | ./outputs/LoRA-gbs8 |
三套配置均包含以下公共训练项:
training: seed: 42 init_model_with_meta_device: true # meta 设备初始化,需预转换 DCP 权重 optimizer: adamw adam_fused: true no_load_optim: true # 不加载优化器状态(如需加载请删除) no_load_rng: true no_save_optim: true # 不保存优化器状态(如需保存请删除) no_save_rng: true save_dtype: bf16 # checkpoint 保存为 BF16 use_deter_comp: false plugin: - mindspeed_mm/fsdp/models/qwen3_5 - mindspeed_mm/fsdp/data/datasets/huggingface
no_load_optim/no_load_rng/no_save_optim/no_save_rng四个开关的含义:从 Qwen3.6-27B release checkpoint 加载权重,但不加载/不保存优化器与随机数状态(实践报告中的初始状态约定与此一致)。若需断点续训并恢复优化器状态,须相应调整。
6.2 packing 与 unpacking 的差异解读
- packing 全参配置(qwen3_6_27B_config_packing64k_gbs2.yaml):
packing: true,将多个样本打包进 64K 上下文,loss_type: per_token_loss,并启用shuffle_before_packing: true(seed 42,打包前全局打乱数据,提升长序列打包质量)。这是实践报告 4.4 节中训练效率更优的方案(3 个 epoch 耗时约为 unpacking 的 2/3); - unpacking 全参配置(qwen3_6_27B_config_gbs16.yaml):
packing: false,样本不打包,loss_type: per_sample_loss,global batch size 16; - LoRA 配置(qwen3_6_27B_config_LoRA_gbs8.yaml):
packing: false,global batch size 8,训练 5 个 epoch。
6.3 LoRA 配置详解
LoRA 配置位于training.lora下,完整配置如下(来自仓库 LoRA 配置文件):
training: lora: enable: true rank: 256 alpha: 512 target_modules: # 标准注意力层 - "model.language_model.layers.{*}.self_attn.q_proj" - "model.language_model.layers.{*}.self_attn.k_proj" - "model.language_model.layers.{*}.self_attn.v_proj" - "model.language_model.layers.{*}.self_attn.o_proj" # MLP 层 - "model.language_model.layers.{*}.mlp.gate_proj" - "model.language_model.layers.{*}.mlp.up_proj" - "model.language_model.layers.{*}.mlp.down_proj" dropout: 0.05 init_lora_weights: true pretrained_lora_path: null参数说明(结合补丁说明与补丁中lora_args.py的定义):
rank:低秩矩阵的秩(实践报告中对比过 64/128/256,rank 256 综合表现最好);alpha:缩放系数,LoRA 权重更新为W' = W + (alpha/r)·B·A(实践报告固定alpha/r = 2);target_modules:LoRA 注入范围——标准自注意力层的 q/k/v/o projection 与 MLP 的 gate/up/down projection,不包含 GDN(Gated DeltaNet)线性注意力层。实践报告第 5.4 节指出,将 GDN 的in_proj_z、in_proj_b、in_proj_a纳入 target modules 后,不同 rank 的模型均出现明显能力坍塌,因此主实验不训练这些模块;dropout:LoRA 层 dropout 比例;init_lora_weights:权重初始化方式(True/False/"gaussian",meta device 流程下其他字符串初始化方法会被拒绝);pretrained_lora_path:预训练 LoRA 权重路径(可选,支持.safetensors与.pt/.bin)。
七、启动训练
7.1 启动全参 SFT
启动后台训练(默认使用 16 张 NPU):
# 使用 packing 配置 bash run_train_nohup.sh \ examples/qwen3_6/qwen3_6_27B_config_packing64k_gbs2.yaml # 使用 unpacking 配置 bash run_train_nohup.sh \ examples/qwen3_6/qwen3_6_27B_config_gbs16.yaml7.2 启动 LoRA SFT
bash run_train_nohup.sh \ examples/qwen3_6/qwen3_6_27B_config_LoRA_gbs8.yaml7.3 启动脚本的工作机制
run_train_nohup.sh与配套的scripts/wait_for_npu_idle.sh由补丁新增(对应补丁说明第 6 点),其工作流为:
- 参数校验:接收配置文件与可选 NPU 数量(默认 16),校验 NPU 数量为正整数、
ASCEND_RT_VISIBLE_DEVICES设备列表无重复且数量一致; - 读取输出目录:通过内嵌 Python 从 YAML 读取
training.save,据此推断 DCP→HF 后处理的目标目录(${save}-hf); - 等待 NPU 空闲:
wait_for_npu_idle.sh通过npu-smi info轮询物理 NPU 显存占用,所有目标设备空闲后才启动训练。可用环境变量控制:IDLE_MEMORY_THRESHOLD_MB(默认 4000):空闲判定阈值;CHECK_INTERVAL_SECONDS(默认 300):轮询间隔;QUERY_TIMEOUT_SECONDS(默认 30):单次npu-smi查询超时;NPU_DEVICE_IDS/EXPECTED_NPU_COUNT:指定设备与期望数量;
- 后台训练:
nohup启动examples/qwen3_6/finetune_qwen3_6_27B.sh,在logs/下写入 PID 文件与 workflow 日志; - 成功后处理:训练成功结束后自动执行后处理——全参 SFT 执行 DCP→HF 转换,LoRA SFT 执行 adapter 合并;训练失败时不会执行后处理。
8 卡训练示例(来自补丁中run_qwen36_sft.sh的注释):
export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 EXPECTED_NPU_COUNT=8 bash run_train_nohup.sh path/to/config.yaml 8底层训练脚本finetune_qwen3_6_27B.sh的增强点(补丁第 6 点):
NPUS_PER_NODE、MASTER_ADDR、MASTER_PORT均可通过环境变量配置并做合法性校验;- 未设置
MASTER_PORT时使用torchrun --standalone自动选择空闲端口;设置后使用静态 rendezvous; - 从命令行接收 YAML 配置路径,不再写死配置文件;日志文件名包含配置名;
- 使用
pipefail检测训练失败并返回非零状态,保留训练耗时与吞吐统计; - 默认不再自动 source 固定路径的 CANN 环境脚本,需按实际环境手动配置。
八、Checkpoint 后处理
8.1 批量转换 DCP 到 HF
以 packing 全参 SFT 配置为例,训练输出默认位于./outputs/packing64k-gbs2。训练流程正常结束时自动完成格式转换;如需手动将所有 iteration 的 DCP checkpoint 转换为 Hugging Face 格式:
bash cvt_ckpt_dcp2hf_batch.sh \ ./outputs/packing64k-gbs2 \ ./outputs/packing64k-gbs2-hf \ examples/qwen3_6/qwen3_6_27B_config_packing64k_gbs2.yaml脚本行为:
- 遍历输入目录下的
iter_*(纯数字迭代号)目录,将每个结果写入带对应 iteration 后缀的输出目录(如packing64k-gbs2-hf_iter_000010); - 默认从
ckpt/hf_path/Qwen3.6-27B读取 tokenizer 等文件——DCP→HF 转换后会自动从原始 HF 目录复制存在的 tokenizer 相关文件(tokenizer.json、tokenizer_config.json、chat_template.jinja、vocab.json、merges.txt、special_tokens_map.json等),并在复制成功后更新输出目录权限(补丁中qwen3_5.py的_copy_origin_tokenizer_assets逻辑); - 处理 DCP
iter_*目录期间会保护并在退出时恢复latest_checkpointed_iteration.txt(临时备份 + trap 恢复); - 发现
lora_adapter_iteration_*.safetensors文件时,从 YAML 读取基座模型路径、LoRA alpha 与 rank 并校验,然后调用merge_lora_safetensors_to_base.py合并。
8.2 转换单个 DCP checkpoint
bash cvt_ckpt_dcp2hf.sh \ ./outputs/packing64k-gbs2-iter_000010 \ ./outputs/packing64k-gbs2/iter_0000108.3 预览转换计划(Dry Run)
如需预览批处理脚本将处理哪些 checkpoint 而不实际转换:
CHECKPOINT_POSTPROCESS_DRY_RUN=1 bash cvt_ckpt_dcp2hf_batch.sh \ ./outputs/packing64k-gbs2 \ ./outputs/packing64k-gbs2-hf \ examples/qwen3_6/qwen3_6_27B_config_packing64k_gbs2.yaml8.4 LoRA 合并的补充控制
针对 LoRA adapter 的合并,批处理脚本还支持:
LORA_MERGE_DEVICE=cpu|npu:选择 CPU 或 NPU 上执行合并(默认npu);- 合并结果写入
${dcp_dir}-merged-hf-iter-${iteration}目录; - 合并前会校验 YAML 中
model.model_name_or_path存在、training.lora.alpha与training.lora.rank均为正整数。
九、补丁能力深度解读:8 大功能模块
mindspeed-mm.patch 与补丁说明将适配能力归纳为 8 大模块,本节结合补丁源码逐项解读其设计意图,帮助你理解示例配置背后框架层面的支撑。
9.1 FSDP2 按 epoch 训练
涉及mindspeed_mm/fsdp/train/epoch_schedule.py(新增)、trainer.py、train_engine.py、training_args.py等。
核心逻辑(epoch_schedule.py中三个纯函数):
get_epoch_micro_batches(dataloader):返回每个 epoch 的 micro-batch 数。普通 PyTorch DataLoader 直接取len();项目的BaseRandomBatchSampler暴露total_samples/last_batch_size/micro_batch_times_data_parallel_size三个记账属性,按"有效样本数(排除不完整尾 batch)÷ 全局 micro-batch 大小"归一化计算;resolve_epoch_schedule(...):把 epoch 配置换算为总 iteration 与精确保存 iteration。epoch 边界按ceil(epoch × micro_batches_per_epoch / gradient_accumulation_steps)向上取整到跨过边界的第一个 optimizer step,避免因数据量或梯度累积不能整除而出现 checkpoint 漂移;同时校验空数据集、非法 epoch、非法save_interval、每 epoch micro-batch 数小于梯度累积步数等异常;checkpoint_is_due(...):epoch 模式按保存点集合判定,iteration 模式保持iteration % save_interval == 0的原语义。
对用户的影响:
- 设置
train_epochs时,train_iters会被覆盖,save_interval自动按"epoch 数"解读(如配置中的save_interval: 1即每个 epoch 保存一次); - 未设置
train_epochs时保持按 optimizer step 的原有语义; - 字段名是
train_epochs,不是train_epoches——框架会对拼写错误显式报错; - 按 epoch 续训时应保持数据集长度、梯度累积步数与并行配置不变,否则 checkpoint 的 iteration 与 dataloader epoch 位置无法对应;
- FunASR 的 split-based dataloader 不支持通用
train_epochs,继续使用其专用的max_epochs与train_iters; - 训练结束时避免重复保存刚刚在同一 iteration 保存过的 checkpoint(
train_engine.py中的last_saved_iteration去重)。
9.2 LoRA 初始化和保存逻辑
涉及mindspeed_mm/fsdp/utils/lora_utils.py、lora_args.py、trainer.py、train_engine.py。
- 新增
is_pure_lora_training():要求存在可训练参数且所有可训练参数名都属于 LoRA adapter,才判定为纯 LoRA 训练; - 新增
initialize_lora_weights_after_materialization():解决 meta device 初始化后经to_empty()导致 LoRA 权重未真正初始化的问题。流程为:先 materialize 参数 → 再初始化基座权重 → 最后按 PEFT 语义重新初始化 LoRA adapter;即使后续加载基座 checkpoint,也不会留下未初始化的 adapter 存储; init_lora_weights支持True/False/"gaussian"三种方式,其他依赖实权重的方法(如"pissa")在该 meta 流程中会被拒绝(配套单测tests/ut/test_lora_utils.py覆盖该拒绝路径);- 新增
training.lora.save_full_model(默认false):- 纯 LoRA 训练默认只保存
lora_adapter_iteration_xxx.safetensors(adapter-only checkpoint); - 如果存在解冻的非 LoRA 参数(如
lm_head),仍自动保存完整模型 checkpoint,防止这些权重丢失; - 设置
save_full_model: true时额外保存包含完整模型状态的 DCP,默认 adapter-only 行为不变;
- 纯 LoRA 训练默认只保存
- 断点续训语义:adapter-only checkpoint 可通过
pretrained_lora_path加载,但不会恢复优化器、学习率调度器与 RNG 状态;严格断点续训需save_full_model: true,保存时no_save_optim/no_save_rng为false,恢复时no_load_optim/no_load_rng为false,load指向上次保存的完整 checkpoint。
9.3 Checkpoint 保存 dtype
涉及dcp_checkpointer.py、training_args.py、train_engine.py。
- 新增
training.save_dtype,支持fp16/bf16/fp32;未设置时保持原有保存 dtype; - 保存模型 state dict 时递归转换浮点 tensor 的 dtype(
_cast_floating_tensors); - 只影响完整模型 checkpoint 保存,不改变训练过程中的参数 dtype,也不改变 adapter-only 文件的保存逻辑;
- FunASR 保存逻辑同步支持该参数。
9.4 数据处理和 SFT packing
涉及mindspeed_mm/fsdp/data/data_utils/func_utils/convert.py、qwen2vl_dataset.py、cvt_data_format_jsonl2json.sh。
- 新增
shuffle_before_packing(默认关闭)与shuffle_before_packing_seed(默认 42):在 Qwen2VL/Hugging Face 数据集路径下,仅当stage=sft、启用 packing、离线预处理且数据集非 streaming 时生效;shuffle 顺序为数据对齐后、tokenize/packing 前; - 启用该选项但前置条件冲突(streaming 数据集或
preprocess_on_fly=true)时显式报错,而不是执行近似 shuffle; - 新增 JSONL→JSON 转换工具(即 cvt_data_format_jsonl2json.sh 对应功能 配套脚本),支持两种输入格式、单文件与 glob 批量、逐行校验并生成统一
messages结构(详见 5.5 节)。
9.5 Qwen3.5 checkpoint 转换
涉及checkpoint/vlm_model/converters/qwen3_5.py、cvt_ckpt_dcp2hf.sh、cvt_ckpt_dcp2hf_batch.sh、cvt_ckpt_hf2dcp.sh。
- Qwen3.5 DCP→HF 后自动从原始 HF 目录复制 tokenizer 相关文件(
tokenizer.json、tokenizer_config.json、chat_template.jinja、vocab.json等)并修正权限; - 新增 HF→DCP、DCP→HF 快捷脚本与批量处理脚本(详见第八节)。
9.6 训练启动和 NPU 调度脚本
新增run_qwen36_sft.sh、run_train_nohup.sh、scripts/wait_for_npu_idle.sh,实现 NPU 空闲等待、后台训练、失败检测与成功后处理联动(详见 7.3 节)。
9.7 示例文档与测试配套
examples/qwen3_6/README.md补充了 clone 地址、triton-ascend版本提示、train_iters/train_epochs/save_interval配置示例及train_epoches拼写提示;.gitignore新增ckpt、outputs、data、logs、tmp等目录;- 新增/修改单元测试覆盖:
train_epoches拼写校验、epoch schedule 换算与 checkpoint 边界(tests/ut_fsdp/test_epoch_training.py)、LoRA 纯训练判断与 meta 初始化(tests/ut/test_lora_utils.py、tests/ut_fsdp/train/test_trainer_meta_lora.py)、adapter-only/完整/混合保存分支(tests/ut/test_train_engine_lora_save.py)、JSONL 转换两种格式(tests/ut/test_cvt_data_format_jsonl2json.py)、SFT packing 前 shuffle 开关与前置条件(tests/ut_fsdp/test_qwen2vl_dataset.py)。
十、训练效果参考与实践验证
训练效果属于实践层面的验证结果,详见仓库内实践报告(以下数据均出自该报告,标注其适用条件):
- 全参 SFT(thinking 推理):cann-bench Level 1 PASS@5 从基模的 12.7 提升至67.3,AVG@5 从 4.1 提升至45.5;Level 2 PASS@5/AVG@5 为 28.2/10.2;
- LoRA-SFT(rank 256,epoch 4 checkpoint):Level 1 thinking 模式 54.55/34.03;no-thinking 模式 59.89/31.84;
- 资源对比:全参 SFT 峰值显存约 46 GiB/卡、3 epochs 约 3.7 h;LoRA-SFT 约 27 GiB/卡、5 epochs 约 4.5 h,且可在 8 die 上完成训练;
- packing vs unpacking:per_token_loss + packing 的训练效率显著更高(3 个 epoch 耗时约为 unpacking 的 2/3),两类 loss 在开启 thinking 推理时结果接近。
实践报告还指出:仅使用开放数据(550 条)进行 MindSpeed-MM 全参 SFT(thinking 推理),Level 1 达 51.4/24.8,说明仓库公开的数据讨论贴已足以复现基本的 AscendC 交付格式与部分算子模式学习。评测存在抽样噪声,较小分差不宜视为稳定优势。
下图展示了 MindSpeed-MM 框架下 packing(per_token_loss)与 unpacking(per_sample_loss)两类全参 SFT 实验的训练曲线(图片来自实践报告):
两组实验的 epoch 平均 training loss 均持续下降;由于 loss 聚合方式不同(per-token vs per-sample),绝对数值不宜横向比较,仅用于判断各自运行的纵向趋势。由于clip_grad=0.0,训练中出现的 grad norm 尖峰未被显式裁剪。
十一、常见问题与注意事项
ModuleNotFoundError: No module named 'pkg_resources':安装低版本setuptools(如setuptools==81.0.0,需低于 82.0.0);triton-ascend版本不匹配:CANN 8.5.0 用 3.2.0,CANN 9.0.0 用 3.2.1;安装命令需带--extra-index-url https://mirrors.huaweicloud.com/ascend/repos/pypi;train_epoches拼写错误:字段名是train_epochs,框架会显式报错拒绝;training.load指向错误:必须指向 DCP 根目录ckpt/dcp_path/Qwen3.6-27B(含release/与latest_checkpointed_iteration.txt),不要指向release/子目录;shuffle_before_packing前置条件:仅当stage=sft+packing=true+ 离线预处理 + 非 streaming 数据集时生效;streaming 或preprocess_on_fly=true会显式报错;- 流式/IterableDataset 不支持按 epoch 训练:请继续使用
train_iters; - LoRA meta 初始化限制:
init_lora_weights在 meta device 流程下仅支持True/False/"gaussian"; - 严格断点续训:adapter-only checkpoint 不携带优化器/RNG 状态,需
save_full_model: true并按要求调整no_save_*/no_load_*开关; - 后处理仅在训练成功时执行:
run_train_nohup.sh通过pipefail检测训练失败,失败时跳过 checkpoint 转换/LoRA 合并。
小结
本文以Qwen3.6-27B SFT 使用指南为骨架,完整覆盖了从代码获取、环境搭建、权重转换、数据准备、三套配置训练到 checkpoint 后处理的全部实操步骤,并结合mindspeed-mm.patch源码与补丁说明深入解读了 epoch 训练调度、LoRA 初始化与保存、checkpoint dtype、SFT packing 洗牌等底层机制,最后以实践报告的评测结果作为训练效果的参考依据。仓库内还提供了数据生成工具、prompt 生成工具与三套可直接运行的 YAML 配置,开发者可据此快速复现全参 SFT 与 LoRA-SFT 实验,或在现有配置基础上调整数据、超参与并行策略开展进一步探索。
【免费下载链接】cann-recipes-train本项目针对LLM与多模态模型训练业务中的典型模型、加速算法,提供基于CANN平台的优化样例项目地址: https://gitcode.com/cann/cann-recipes-train
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考