ms-swift Megatron-SWIFT 实战:DeepSeek-V4 微调训练、精度对齐与 FP8/vLLM 部署全流程
【免费下载链接】swiftUse PEFT or Full-parameter to CPT/SFT/DPO/GRPO 600+ LLMs (Qwen3.6, DeepSeek-V4, GLM-5.1, InternLM3, Llama4, ...) and 300+ MLLMs (Qwen3-VL, Qwen3-Omni, InternVL3.5, Ovis2.5, GLM4.5v, Gemma4, Llava, Phi4, ...) (AAAI 2025).项目地址: https://gitcode.com/GitHub_Trending/swift1/swift
本文基于 ms-swift 官方最佳实践文档 deepseek-v4.md,完整讲解如何在 Megatron-SWIFT 中完成 DeepSeek-V4 模型的 SFT/LoRA 微调与强化学习训练(含 MTP、FP8 特性),覆盖训练前的环境装配、transformers 与 Megatron 双引擎 forward 精度对齐验证、BF16/FP8 训练参数配置、量化导出到 vLLM 推理部署的完整链路。读完本文,你可以按图索骥地在单机 8 卡乃至 64 卡集群上复现 DeepSeek-V4 的 LoRA/全参数训练,并产可在 vLLM 上线的 FP8 权重。
1. 版本前提与环境装配
Megatron-SWIFT 已支持 DeepSeek-V4 的微调与 RL 训练,特性包括MTP(Multi-Token Prediction)与FP8训练。需要特别注意两个前置约束:
- FP4 blockwise 训练暂不支持。加载 FP4 权重时,框架会自动将其转换为 FP8/BF16,因此文档中所有训练脚本实际以 FP8/BF16 数值精度运行;
- 必须使用特定分支组合:Megatron-Core 的
dev分支,配合mcore-bridge与ms-swift的main分支。
官方给出的安装命令如下(文档注明 Megatron-LM 在 commitfd1121b8ff7e3a4f83a28d35aed172d7bc0260e1下完成过测试,可用固定 commit 代替dev分支安装以保证可复现性):
pip install git+https://github.com/NVIDIA/Megatron-LM.git@dev pip install git+https://github.com/modelscope/mcore-bridge.git pip install git+https://github.com/modelscope/ms-swift.git # Megatron-LM 在该 commit hash 下经过测试验证 # pip install git+https://github.com/NVIDIA/Megatron-LM.git@fd1121b8ff7e3a4f83a28d35aed172d7bc0260e1安装后,训练/导出相关的megatron命令行入口定义于 setup.py 的console_scripts中:megatron=swift.cli._megatron.main:cli_main。其中megatron sft最终调用 sft.py 中的megatron_sft_main(),megatron export调用 export.py 中的megatron_export_main()。Megatron 相关依赖另见 requirements/megatron.txt。
1.1 仓库中已注册的 DeepSeek-V4 模型
从 swift/model/models/deepseek.py 的模型注册代码看,当前仓库已内置以下 DeepSeek-V4 权重组,architectures 为DeepseekV4ForCausalLM,默认对话模板为deepseek_v4(-0731/-0813版本组使用deepseek_v4_flash模板):
deepseek-ai/DeepSeek-V4-Flash、deepseek-ai/DeepSeek-V4-Flash-Basedeepseek-ai/DeepSeek-V4-Pro、deepseek-ai/DeepSeek-V4-Pro-Basedeepseek-ai/DeepSeek-V4-Flash-0731、deepseek-ai/DeepSeek-V4-Pro-0813
本文的训练示例以DeepSeek-V4-Flash(对话版)与DeepSeek-V4-Flash-Base(基座版)为主。
2. 训练前的精度对齐验证
在进入正式训练之前,官方文档强烈建议先做一次transformers 与 Megatron 两条推理路径的 forward 精度对齐测试。对于 DeepSeek-V4 这类采用稀疏注意力(DSA)变体与混合 dense/MoE 结构的模型,权重转换(Hugging Face safetensors → Megatron-Core 格式)涉及大量重排与量化反量化,任何一处 key 映射错位都会在训练初期表现为 loss 异常。
2.1 解除 FP32 对齐测试的限制
对齐测试需要以 FP32 精度前向。文档指出需注释掉 Megatron-LMdev分支中megatron/core/transformer/experimental_attention_variant/dsa.py文件第 41~43 行(该位置为 DSA 注意力路径中阻碍 FP32 前向的语句)。修改的是你本地安装的 Megatron-LM 源码,不影响 ms-swift 仓库本身。
2.2 构造 4 层 mini 模型
为加速对齐测试,官方脚本会把原始权重裁剪为只含前 4 个 transformer 层的 mini 模型。脚本基于mcore_bridge.utils提供的SafetensorLazyLoader、Fp8Dequantizer、StreamingSafetensorSaver三个工具类实现,要点如下:
SafetensorLazyLoader懒加载 safetensors,配合下方 monkey patch 后的_open_file支持按需懒下载(文件不在本地时回落到model_file_download逐文件拉取到tmp/目录);- 遍历 state_dict 时丢弃
layers.下索引>= 4的张量,只保留前 4 层; - 丢弃所有
.scale量化 scale 张量;对存在对应.scale的.weight(即 FP8 量化权重),用Fp8Dequantizer.convert(...)反量化并转成 BF16; - 最终通过
StreamingSafetensorSaver流式写回模型目录。
完整脚本(与文档一致):
import os import torch from modelscope.hub.file_download import model_file_download from safetensors.torch import safe_open from swift import safe_snapshot_download from mcore_bridge.utils import Fp8Dequantizer, SafetensorLazyLoader, StreamingSafetensorSaver model_id = 'deepseek-ai/DeepSeek-V4-Flash-Base' # 部分模型前几层是 dense、其余是 MoE;按实际结构设置该值 model_dir = safe_snapshot_download(model_id, download_model=False) loader = SafetensorLazyLoader(model_dir) state_dict = loader.get_state_dict() saver = StreamingSafetensorSaver(save_dir=model_dir) fp8_dequantizer = Fp8Dequantizer() # 用于把 fp8 权重转换为 bf16 def _open_file(self, filename: str): if filename not in self._file_handles: file_path = os.path.join(self.hf_model_dir, filename) tmp_dir = os.path.join(self.hf_model_dir, 'tmp') if not os.path.exists(file_path): file_path = os.path.join(tmp_dir, filename) if not os.path.exists(file_path): file_path = model_file_download( model_id=model_id, file_path=filename, local_dir=tmp_dir, ) self._file_handles[filename] = safe_open(file_path, framework='pt') return self._file_handles[filename] SafetensorLazyLoader._open_file = _open_file # monkey patch(懒下载) new_state_dict = {} for k, v in state_dict.items(): if k.startswith('layers.'): idx = int(k[len('layers.'):].split('.', 1)[0]) if idx >= 4: continue if k.endswith('.scale'): continue elif k.endswith('.weight'): weight_scale_inv = k.replace('.weight', '.scale') if weight_scale_inv in state_dict: v = fp8_dequantizer.convert(v.load(), state_dict[weight_scale_inv].load()).to(torch.bfloat16) new_state_dict[k] = v if isinstance(v, torch.Tensor) else v.load() for k, v in new_state_dict.items(): saver.add_tensor(k, v) saver.finalize()裁剪完成后需要同步修改config.json:
num_hidden_layers改为4;compress_ratios改为[0, 0, 4, 128, 0];- 删除
quantization_config字段(mini 模型以 BF16 运行,与对齐测试的 FP32 前向保持一致)。
2.3 运行对齐测试
创建test.py,以 4 卡并行运行(CUDA_VISIBLE_DEVICES=0,1,2,3 torchrun --nproc_per_node=4 test.py),并行拓扑刻意设置为 PP=2、EP=2 的组合,同时覆盖 pipeline 切分(pipeline_model_parallel_layout)与 MTP 层的权重转换:
import os os.environ['SWIFT_TEST_CONVERT_PRECISION'] = '1' from swift.megatron import MegatronExportArguments, megatron_export_main from swift import safe_snapshot_download model_id = 'deepseek-ai/DeepSeek-V4-Flash-Base' model_dir = safe_snapshot_download(model_id, download_model=False) if __name__ == '__main__': megatron_export_main( MegatronExportArguments( model=model_dir, to_mcore=True, attention_backend='flash', tensor_model_parallel_size=1, pipeline_model_parallel_layout='Et*3|t*1mL', pipeline_model_parallel_size=2, expert_model_parallel_size=2, mtp_num_layers=1, test_convert_precision=True, ))pipeline_model_parallel_layout与mtp_num_layers两个参数定义于 megatron_args.py,其中 layout 字符串由PipelineParallelLayerLayout.get_num_stages_from_str解析,其阶段数必须能被pipeline_model_parallel_size整除(见 参数校验逻辑)。
在源码层面,该测试的落点是 convert.py:导出流程会读取环境变量SWIFT_TEST_CONVERT_PRECISION(这也是test.py中os.environ注入的原因),并在权重转换完成后调用 convert_utils.py 中的test_convert_precision()。该函数以训练模板对同一批样例分别编码,先令 Hugging Face 模型以 FP32 前向(CPU offload 上下文)得到 logits,再令 Megatron 模型前向,逐层比对输出——当看到文档给出的对齐通过截图结果时,即说明 HF 与 Megatron 两条路径数值一致,可以进入正式训练。
需要注意 convert_utils.py 中的显式约束:FP8 模型不支持 convert_precision 测试(会直接抛出ValueError),因此对齐验证必须在未开启 FP8 的 BF16 mini 模型上完成,这也解释了第 2.2 节中“删除quantization_config、FP8 权重反量化为 BF16”的必要性。
3. BF16 LoRA 训练
验证对齐通过后,即可启动 LoRA SFT。官方给出的 BF16 精度脚本会在训练结束后同时产出LoRA 增量权重与Merge-LoRA 后的 BF16 完整权重。单机 8 卡完整命令如下:
PYTORCH_CUDA_ALLOC_CONF='expandable_segments:True' \ NPROC_PER_NODE=8 \ CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 \ megatron sft \ --model deepseek-ai/DeepSeek-V4-Flash \ --save_safetensors true \ --dataset 'AI-ModelScope/alpaca-gpt4-data-zh#1000' \ 'AI-ModelScope/alpaca-gpt4-data-en#1000' \ 'swift/self-cognition#1000' \ --model_author swift \ --model_name swift-robot \ --merge_lora true \ --load_from_cache_file true \ --add_non_thinking_prefix true \ --loss_scale ignore_empty_think \ --split_dataset_ratio 0.01 \ --tuner_type lora \ --lora_rank 16 \ --lora_alpha 32 \ --tensor_model_parallel_size 1 \ --expert_model_parallel_size 8 \ --micro_batch_size 4 \ --global_batch_size 32 \ --padding_free false \ --group_by_length true \ --recompute_granularity full \ --recompute_method uniform \ --recompute_num_layers 1 \ --moe_permute_fusion true \ --moe_grouped_gemm true \ --moe_shared_expert_overlap true \ --moe_aux_loss_coeff 1e-3 \ --num_train_epochs 1 \ --finetune true \ --cross_entropy_loss_fusion true \ --lr 1e-4 \ --lr_warmup_fraction 0.05 \ --min_lr 1e-5 \ --output_dir megatron_output/DeepSeek-V4-Flash \ --eval_steps 200 \ --save_steps 200 \ --max_length 4096 \ --dataloader_num_workers 8 \ --dataset_num_proc 8 \ --no_save_optim true \ --no_save_rng true \ --sequence_parallel true \ --mtp_num_layers 1 \ --attention_backend flash关键参数按功能分组解读:
| 参数组 | 参数 | 说明 |
|---|---|---|
| 数据与思考模型适配 | --dataset ...#1000、--split_dataset_ratio 0.01 | 三个数据集各采样 1000 条,1% 切分作验证集;#1000为 ms-swift 数据集采样语法 |
--add_non_thinking_prefix、--loss_scale ignore_empty_think | 针对 DeepSeek-V4 思考(thinking)机制:前缀标记非思考回复,loss 计算时忽略空思考内容 | |
--model_author、--model_name | 配合 self-cognition 数据集注入模型自我认知(作者/名称) | |
| 调优器 | --tuner_type lora、--lora_rank 16、--lora_alpha 32 | LoRA rank 16、alpha 32;--merge_lora true使训练结束后额外产出合并后的 BF16 完整权重 |
--no_save_optim、--no_save_rng | 微调场景无需保存优化器/RNG 状态,减小 checkpoint 体积 | |
| 并行策略 | --tensor_model_parallel_size 1、--expert_model_parallel_size 8 | TP=1(当前暂不支持 TP,见第 4 节),8 卡全部用于专家并行;--sequence_parallel true降低序列维显存 |
--mtp_num_layers 1 | 开启 1 层 MTP(Multi-Token Prediction)联合训练 | |
| 批与序列 | --micro_batch_size 4、--global_batch_size 32 | 8 卡下全局批 = 4×8,梯度累积 1 |
--max_length 4096、--padding_free false、--group_by_length true | 单条最大 4096 token;关闭 padding-free 后按长度分桶减少 padding 浪费 | |
| 显存优化 | --recompute_granularity full、--recompute_method uniform、--recompute_num_layers 1 | 全重计算且每 1 层重算一次,用算力换显存 |
PYTORCH_CUDA_ALLOC_CONF='expandable_segments:True' | PyTorch 可扩展内存段,缓解碎片化 | |
| MoE 优化 | --moe_permute_fusion、--moe_grouped_gemm、--moe_shared_expert_overlap | 路由 permute 融合、分组 GEMM、共享专家通信重叠 |
--moe_aux_loss_coeff 1e-3 | MoE 负载均衡辅助 loss 系数 | |
| 数值/其他 | --cross_entropy_loss_fusion true、--attention_backend flash | 融合 CE loss;flash 注意力后端 |
--lr 1e-4、--lr_warmup_fraction 0.05、--min_lr 1e-5 | LoRA 典型学习率区间(1e-5~1e-4);--finetune true以微调语义初始化优化器 |
训练完成后,产出位于megatron_output/DeepSeek-V4-Flash/vx-xxx/下:既有checkpoint-xxx(LoRA 增量),也有checkpoint-xxx-merged(合并后 BF16 权重),可直接用于后续推理(见第 6 节)。官方文档同时给出了该配置的显存占用截图与训练 loss 曲线,可参考原文档 deepseek-v4.md 中的插图作为复现对照。
4. 进阶配置:PP 切分、全参数训练与 Packing/CP
文档在 LoRA 章节后给出了四条重要的边界与进阶提示,逐条对应源码中的参数语义:
4.1 流水线并行(PP)必须显式给出 layout
启用 PP 时除--pipeline_model_parallel_size外还需设置pipeline_model_parallel_layout(该参数为Optional[str],默认为空,见 megatron_args.py)。文档示例:
--pipeline_model_parallel_size 2 \ --pipeline_model_parallel_layout 'Et*22|t*21mL' \layout 语法以|分隔各 pipeline 阶段,t表示 transformer 层、E表示嵌入层、m表示 MTP 层、末尾L为输出(logit/loss)阶段;t*22表示该阶段连续放置 22 个 transformer 层。以 8 卡 64 层规模的 Flash 模型为例,2 阶段 layoutEt*22|t*21mL即把 43 个 transformer 层按 22/21 分摊到两个 stage,并把 MTP 与输出头放在第二级。
4.2 全参数训练(64 卡参考配置)
全参数训练同样受支持,但需要调低学习率并提高并行度。官方 64 卡示例的差异化参数:
--lr 1e-5 \ --min_lr 1e-6 \ --tensor_model_parallel_size 1 \ --expert_model_parallel_size 8 \ --pipeline_model_parallel_size 8 \ --pipeline_model_parallel_layout Et*5|t*5|t*6|t*6|t*6|t*5|t*5|t*5mL \即 EP=8 × PP=8 = 64 卡,layout 将 44 个 transformer 层在 8 个阶段间做 5/5/6/6/6/5/5/5 的非均匀切分(结合 MTP 与输出头共 45 个单元位),学习率从 LoRA 的 1e-4 降一个数量级至 1e-5。
4.3 Packing / 上下文并行(CP)
Packing 与 CP 的支持依赖mcore-bridge/ms-swift的main分支(对应上游 PR:ms-swift#9705 与 mcore-bridge#140)。若使用 CP,需额外设置:
--sequence_packing_scheduler dp_balanced \ --cp_partition_mode contiguous \前者让 packed 序列在各 DP rank 间按长度均衡分配,后者指定 CP 的切分模式。
4.4 TP 支持现状
当前版本暂不支持张量并行(TP),需等待 Megatron-Core 上游支持——这正是示例中--tensor_model_parallel_size 1的原因,也解释了为何 64 卡全参数方案采用 EP×PP 的并行组合而非引入 TP。
5. FP8 训练与量化导出
5.1 开启 FP8 训练
追加以下三个参数即可开启 FP8 训练,并将最终权重保存为 FP8:
--fp8_recipe blockwise \ --fp8_format e4m3 \ --fp8_param_gather true \fp8_recipe blockwise:采用块级(blockwise)缩放方案,与 DeepSeek-V4 原生 FP8 权重的量化粒度对齐;fp8_format e4m3:权重数值格式取 e4m3;fp8_param_gather true:参数收集阶段保留 FP8 数值。
官方推荐 FP8 走全参数训练。若确实要 LoRA + FP8 组合,必须遵守 examples/megatron/fp8/lora.sh 头部注释所述约束:FP8 精度有限,LoRA delta 直接合并进 FP8 底模会被舍入为 0,因此要设置--merge_lora false只保存 LoRA 权重,之后基于 BF16 权重执行 Merge-LoRA;该示例中的megatron export --adapters ...流程(BF16 底模 +--merge_lora true)即为标准做法。
5.2 训练后量化导出 FP8 权重
对已合并的 BF16 checkpoint,可用megatron export做离线量化,产出 vLLM 可加载的 FP8 权重(文档特别提示:对 LoRA 增量做此量化会丢失增量信息,此处仅为链路示例;生产建议直接采用 5.1 节的 FP8 全参数训练并导出 FP8 权重):
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 \ NPROC_PER_NODE=8 \ megatron export \ --model megatron_output/DeepSeek-V4-Flash/vx-xxx/checkpoint-xxx-merged \ --output_dir megatron_output/DeepSeek-V4-Flash/vx-xxx/checkpoint-xxx-merged-FP8 \ --to_hf true \ --fp8_recipe blockwise \ --fp8_format e4m3 \ --fp8_param_gather true \ --mtp_num_layers 1 \ --expert_model_parallel_size 8其中--to_hf true表示导出为 Hugging Face safetensors 格式;--mtp_num_layers 1、--expert_model_parallel_size 8必须与训练时的权重布局保持一致,否则 Megatron 侧的权重切分/重排无法正确对应。
6. 训练后推理与 vLLM 部署
6.1 transformers 后端快速验证
训练产物(合并后 BF16 权重)可直接用 ms-swift 推理入口验证,无需量化:
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 \ swift infer \ --model megatron_output/DeepSeek-V4-Flash/vx-xxx/checkpoint-xxx-merged \ --infer_backend transformers \ --enable_thinking false \ --max_new_tokens 2048--enable_thinking false关闭思考模式,便于快速得到直接答案;文档中给出的推理结果截图可作为输出形态对照(self-cognition 数据集注入后,模型会自称swift-robot)。
6.2 vLLM 上线(FP4/FP8 权重)
文档给出 vLLM 部署的四个注意事项:
- vLLM 侧需参考官方针对 DeepSeek-V4-Flash 的 recipe 文档,且要求FP4/FP8 精度权重(即 5.2 节导出的产物);
- 必须复制原始的
config.json并修改expert_dtype字段(与训练后 config 保持一致)。原因是 transformers 的config.save_pretrained写出的文件与原文件存在差异,vLLM 不兼容保存后的文件,因此要以原始文件为底本仅补expert_dtype; - 若遇到 tilelang 相关报错,可参考上游 issue(ms-swift#9494);
- mcore-bridge 针对 DeepSeek-V4 FP8 的修复见其上游 PR(mcore-bridge#133),升级 mcore-bridge main 分支可规避。
vLLM 启动命令(8 卡 TP + 专家并行,含 DeepSeek-V4 专属 tokenizer/parser 配置):
vllm serve megatron_output/DeepSeek-V4-Flash/vx-xxx/checkpoint-xxx-merged-FP8 \ --trust-remote-code \ --kv-cache-dtype fp8 \ --block-size 256 \ --enable-expert-parallel \ --tensor-parallel-size 8 \ --max-model-len 8192 \ --tokenizer-mode deepseek_v4 \ --tool-call-parser deepseek_v4 \ --enable-auto-tool-choice \ --reasoning-parser deepseek_v4其中--kv-cache-dtype fp8与 FP8 权重配套;--tokenizer-mode deepseek_v4、--tool-call-parser deepseek_v4、--reasoning-parser deepseek_v4分别启用 DeepSeek-V4 分词器、自动工具调用与推理内容解析,--enable-auto-tool-choice使服务默认开启工具选择能力。
7. 小结与仓库索引
整条链路可以概括为:分支装配(Megatron-Core dev + mcore-bridge/ms-swift main)→ FP32 精度对齐验证(4 层 mini 模型 +test_convert_precision)→ BF16 LoRA 训练(EP=8,MTP=1)→ 按需 FP8 全参数训练/离线量化 → transformers 验证 + vLLM FP8 部署。关键能力边界:TP 暂不支持、FP4 blockwise 训练不支持(加载时自动转 FP8/BF16)、LoRA+FP8 需走 BF16 底模合并。
主要仓库索引,便于按图索骥深入源码:
- 模型注册:swift/model/models/deepseek.py
- CLI 入口:swift/cli/_megatron/sft.py、swift/cli/_megatron/export.py、setup.py
- 精度对齐实现:swift/megatron/utils/convert_utils.py、swift/megatron/convert.py
- 并行参数定义与校验:swift/megatron/arguments/megatron_args.py、layout 校验
- FP8 LoRA 参考脚本:examples/megatron/fp8/lora.sh
- 原文档(含显存/loss/对齐/推理截图):docs/source_en/BestPractices/deepseek-v4.md
【免费下载链接】swiftUse PEFT or Full-parameter to CPT/SFT/DPO/GRPO 600+ LLMs (Qwen3.6, DeepSeek-V4, GLM-5.1, InternLM3, Llama4, ...) and 300+ MLLMs (Qwen3-VL, Qwen3-Omni, InternVL3.5, Ovis2.5, GLM4.5v, Gemma4, Llava, Phi4, ...) (AAAI 2025).项目地址: https://gitcode.com/GitHub_Trending/swift1/swift
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考