LLaMA-Factory MoE模型微调实战:3 步跑通 30B-A3B,不再爆显存
【免费下载链接】LlamaFactoryUnified Efficient Fine-Tuning of 100+ LLMs & VLMs (ACL 2024)项目地址: https://gitcode.com/GitHub_Trending/ll/LlamaFactory
做 LLaMA-Factory MoE 训练,最先撞上的坑有两个:训练一启动就 CUDA out of memory,或者跑几百步后 loss 突然飙高。这两个问题的本质都不是显存预算不够——MoE 训练比稠密模型多出两件必须做的事:切分专家权重、约束路由器。本文把从 clone 仓库到出 loss 曲线的完整流程走一遍,参数名全部可以直接粘贴,不讲空洞原理。
这篇文章适合谁
- 你准备对 Mixtral、Qwen3-30B-A3B、GLM-4-MoE 这类主流 MoE 做 SFT 或 LoRA,硬件是多卡 GPU 或昇腾 NPU,看这篇。
- 你微调的是稠密模型,或者要从头预训练 200B 级 MoE,这篇不覆盖。
- 环境已经搭好、卡在配置调不通,直接跳到「配置详解」和「排错速查」两节。
🚀 先跑起来:3 条命令启动 LLaMA-Factory MoE 训练
先出结果,后讲原理。装环境、验证、切 MoE 配置,三步走完。
1. 克隆并安装
git clone --depth 1 https://gitcode.com/GitHub_Trending/ll/LLaMA-Factory cd LLaMA-Factory pip install -e .Python 要求 ≥ 3.11(见pyproject.toml的 requires-python)。CUDA 机器先装对应版本的 torch;NPU 机器额外执行pip install -r requirements/npu.txt。装完运行llamafactory-cli help,能列出 train / chat / export 三条子命令,说明环境注册正常——这一步不碰 GPU,专门用来提前暴露安装问题。
2. 先用稠密小模型验证环境
单张 24GB 卡装不下 Qwen3-30B-A3B 的全部 30B 参数,所以第一枪别开在 MoE 上。用仓库内置的稠密演示配置快速跑通:
llamafactory-cli train examples/train_lora/qwen3_lora_sft.yamlloss 曲线正常下降(该配置开启plot_loss: true,曲线图会存进 output_dir)就说明数据管线、tokenizer、LoRA 注入这条链路都通了。演示数据集identity和alpaca_en_demo在data/dataset_info.json里已默认注册,不用自己准备任何数据。
3. 换成 MoE 配置,一条命令开训
把第三节给出的配置保存为examples/train_lora/qwen3_moe_lora_sft.yaml,然后 8 卡这样启动:
llamafactory-cli train examples/train_lora/qwen3_moe_lora_sft.yaml \ --deepspeed examples/deepspeed/ds_z3_config.json--deepspeed挂上 ZeRO-3 是关键动作:MoE 的显存大头在专家权重上,不切分的话单卡根本放不下。
🧠 理解背后的为什么:显存省在「激活少」,不省在「参数少」
MoE 把每层 FFN 拆成 N 个专家,路由器(router)让每个 token 只挑 top-k 个专家计算。Qwen3-30B-A3B 有 128 个专家、top-8,每 token 实际激活约 3.3B;Mixtral 8x7B 是 8 选 2,激活约 12.9B。
但训练和推理的账不一样:所有专家权重都得在显存里,没被选中的专家也要走反向传播,否则参数被遗忘、路由逐渐塌缩到少数几个专家。所以 MoE 微调要解决两件事:用切分策略(ZeRO-3 / FSDP2 / 专家并行)把专家权重摊到多卡,再用辅助损失压住路由器的负载失衡。
| 形态 | 总参数 | 每 token 激活 | 决定显存 | 决定计算量 |
|---|---|---|---|---|
| 稠密 7B | 7B | 7B | 7B | 7B |
| Mixtral 8x7B | 46.7B | ~12.9B(8 选 2) | 46.7B | ~12.9B |
| Qwen3-30B-A3B | 30.7B | ~3.3B(128 选 8) | 30.7B | ~3.3B |
一句话总结:显存和 checkpoint 体积按 30B 算,前反向速度按 3B 算。这就是 MoE「显存效率」的全部真相,也解释了为什么 LoRA 调参思路可以沿用,但分布式策略必须换。
⚙️ 配置详解:6 个参数决定 MoE 训练稳不稳
以 Qwen3-30B-A3B 的 8 卡 LoRA SFT 为例,核心参数与调优方向如下:
| 参数 | 控制什么 | 建议值 | 调偏了怎么改 |
|---|---|---|---|
moe_aux_loss_coef | 专家负载均衡辅助损失的权重,LLaMA-Factory 自动写进模型路由配置 | 0.005–0.01 | loss 抖动、个别专家霸占:提到 0.01;曲线毛刺太大:降到 0.001 |
finetuning_type+lora_target | 哪些权重矩阵可训练 | lora_target: all | 只调 q/v 投影会让专家权重完全冻结,领域适配有限——改成 all |
lora_rank | 低秩适配器秩 | 8–16 | 欠拟合:升到 32;显存紧张:降到 8 |
learning_rate | 步长 | 1.0e-4 | loss 尖峰:降到 5e-5 并配warmup_ratio: 0.1 |
per_device_train_batch_size/gradient_accumulation_steps | 单卡批次与等效批次 | 1 / 8 | OOM:batch 保持 1、accum 加大;吞吐低:先加 batch 再减 accum |
cutoff_len | 最大序列长度 | 2048 | 长文本被截断:提到 4096,显存近似线性增长 |
分布式策略(--deepspeed或 accelerate 配置) | 专家权重怎么在多卡间切分 | CUDA 用 ds_z3;NPU 用 FSDP2 | 加载卡死:换 FSDP2,并核对num_processes等于卡数 |
可直接使用的配置片段(15 行以内):
model_name_or_path: Qwen/Qwen3-30B-A3B-Instruct-2507 moe_aux_loss_coef: 0.01 stage: sft do_train: true finetuning_type: lora lora_rank: 16 lora_target: all dataset: identity, alpaca_en_demo template: qwen3_nothink cutoff_len: 2048 per_device_train_batch_size: 1 gradient_accumulation_steps: 8 learning_rate: 1.0e-4 bf16: true两个容易踩的点。第一,moe_aux_loss_coef只对可训练模型生效:configure_moe()在推理或冻结场景会直接跳过,别拿它排查推理问题。第二,它写入的字段名各厂商不同——Qwen、Mixtral 系写router_aux_loss_coef,DeepSeek 系写aux_loss_alpha,这块在 src/llamafactory/model/model_utils/moe.py 里按 model_type 自动分发,你只管填一个值。走 Megatron 全参路线时,另加moe_grouped_gemm: true与moe_token_dispatcher_type: alltoall,完整参照 examples/megatron/qwen3_moe_full.yaml。
🎯 按场景选方案:4 种硬件组合 4 条路
按你的目标对号入座,每行都给出配置入口:
| 你的目标 | 推荐方案 | 配置位置 |
|---|---|---|
| 8×A800/H100 做 MoE LoRA SFT(Qwen3-30B-A3B / Mixtral) | DeepSpeed ZeRO-3,MoE 块自动注册为 leaf 模块 | examples/deepspeed/ds_z3_config.json |
| 昇腾 NPU 多卡 LoRA | accelerate launch+ FSDP2 | examples/ascend/qwen3_5moe_lora_sft_fsdp2.yaml |
| 235B 级 MoE、显存受限的单机 LoRA | ktransformers CPU offload,专家权重存 int8/int4 | examples/ktransformers/train_lora/qwen3moe_lora_sft_kt.yaml |
| 8×78GB 全参微调 | Megatron:专家并行 EP=2 + 流水线 4 + 分组 GEMM | examples/megatron/qwen3_moe_full.yaml |
NPU 场景命令形态固定,直接照抄:
accelerate launch --config_file examples/accelerate/fsdp2_config_qwen35_moe.yaml \ src/train.py examples/ascend/qwen3_5moe_lora_sft_fsdp2.yamlexamples/accelerate/fsdp2_config_qwen35_moe.yaml里fsdp_transformer_layer_cls_to_wrap已按Qwen3_5MoeDecoderLayer配好,改卡数只需同步num_processes。ktransformers 那条路适合显存最紧张的场合:示例对 Qwen3-235B-A22B 开启use_kt: true,不活跃的专家 offload 到 CPU,再配examples/ktransformers/accelerate/fsdp2_kt_int8.yaml这类量化权重配置。注意 Megatron 全参示例里learning_rate是 3e-6,比 LoRA 的 1e-4 低 30 倍以上,照抄配置时别把学习率也抄串。
🩺 排错速查:MoE 训练跑飞时先查这张表
先看 loss 曲线再对表:plot_loss: true打开后,曲线图在 output_dir 里,专家负载失衡的典型表现是 loss 高频抖动或长期偏高。
| 症状 | 常见原因 | 一行修复 |
|---|---|---|
| 启动即 OOM | ZeRO 等级不够,30B 专家权重没切分 | 命令追加--deepspeed examples/deepspeed/ds_z3_config.json |
| 跑几百步后 OOM | 长序列激活累积、batch 过大 | cutoff_len降到 2048,batch 设 1、gradient_accumulation_steps: 8补量 |
| loss 抖动、个别专家激活量长期霸榜 | 路由辅助损失未开或系数过小 | 配置里写moe_aux_loss_coef: 0.01重跑 |
| ZeRO-3 训练明显慢于同规模稠密模型 | 专家块被逐个子模块切分,通信开销大 | 确认版本含add_z3_leaf_module(整个专家模块整体跳过分片),升级到最新代码 |
| Megatron 全参训练吞吐低 | 专家 GEMM 未分组、token 分发低效 | 开moe_grouped_gemm: true且moe_token_dispatcher_type: alltoall |
| FSDP2 启动卡死 | num_processes与卡数不符 | 改examples/accelerate/fsdp2_config_qwen35_moe.yaml里的num_processes为实际卡数 |
✅ 开训前速查清单
- 确认模型 model_type 在
moe.py支持列表内(mixtral、qwen2_moe、qwen3_moe、llama4、olmoe 等),不在列表的要手动确认路由字段写入 moe_aux_loss_coef落在 0.005–0.01 区间,且训练模式才生效- LoRA 用
lora_target: all,让专家权重参与训练 - 多卡:CUDA 挂 ds_z3,NPU 用 FSDP2 配置,
num_processes等于卡数 - 先跑
max_steps: 50验证 loss 下降,再放长训练
核心资源路径:
- src/llamafactory/model/model_utils/moe.py:MoE 路由配置与 ZeRO-3 leaf 模块注册
- examples/deepspeed/ds_z3_config.json:ZeRO-3 分布式配置
- examples/accelerate/fsdp2_config_qwen35_moe.yaml:FSDP2 MoE 分布式配置
- examples/megatron/qwen3_moe_full.yaml:MoE 全参微调参照配置
【免费下载链接】LlamaFactoryUnified Efficient Fine-Tuning of 100+ LLMs & VLMs (ACL 2024)项目地址: https://gitcode.com/GitHub_Trending/ll/LlamaFactory
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考