大模型微调框架怎么选?四大主流方案对比与实战避坑指南

发布时间:2026/10/16 8:17:34
大模型微调框架怎么选?四大主流方案对比与实战避坑指南 聊到大模型微调绕不开的就是框架选择。我前前后后折腾过 PEFT、DeepSpeed、LLaMA-Factory、Axolotl 这四套主流方案最开始以为“选个最流行的准没错”结果在两张小显存卡上跑了两天发现框架的分布式策略和低秩适配互相打架显存反而飙到爆。后来把每一套都摸了一遍才总结出比较理性的选型逻辑。这篇文章就给你讲讲这四大框架分别适合什么人、什么任务、什么硬件以及我在实际切换中踩过的坑帮你少走弯路。不管你是刚接触微调的小白还是已经在调包的老手这篇文章的核心就一句话框架没有绝对的好坏只有是否匹配你的显存、任务类型和实验管理方式。下面进入正题。1. 选框架前先想清楚的三件事1.1 你的卡到底有多大显存决定框架边界很多人一上来就问“哪个框架最好”其实第一个问题应该是“你的显存有多大”。微调的开销主要由四个部分构成模型权重、梯度、优化器状态和激活值。以 7B 模型为例fp16 精度下光权重就要约 14GB加上 AdamW 优化器状态权重一阶动量二阶动量全量微调大概要 14GB 权重 14GB 梯度 28GB 优化器 至少 56GB 显存这还没算激活值。所以单张 24GB 卡想全量微调 7B基本是痴心妄想。低秩适配LoRA的出现就是为了解决这个问题。LoRA 只训练额外的低秩矩阵参数量通常不到模型的 0.1%1%所以梯度和优化器状态可以忽略不计。如果再用 4bit 量化7B 模型权重压到约 3.54GB一张 8GB 卡也能塞进去跑。这就是显存决定的框架边界显存 ≤ 8GB只能走 QLoRA 小 batch框架选择基本被锁死显存 16GB24GB可以跑 7B QLoRA甚至可以试 7B 全量微调配合内存优化显存 48GB 以上就能考虑 Deepspeed ZeRO-Offload 或单卡全量微调小模型了。我在 8GB 卡上跑过 7B 对话模型的 QLoRA显存占用在 7.2GB 左右波动batch size 只能设为 1再靠梯度累积凑有效 batch。如果你有两张卡且支持 NVLink多卡方案会让选择更宽裕但代价是配置复杂度上升。1.2 你要微调的是对话、指令还是领域能力第二个要厘清的是任务类型。同样是“微调”对话模型Chat和指令模型Instruction和领域预训练Domain Continual Pretraining对数据流程的要求差别很大。对话模型需要多轮对话模板训练时每个会话要拼成一大段 token框架必须处理好“对话模板”和“损失掩码”。做不好就会出现 loss 不降或生成重复的问题。指令模型采用 instruction / input / output 三字段格式模板相对简单各框架基本内置支持。领域预训练数据往往是长文本或半结构化文档要考虑分块、随机采样、遮蔽 token 等需要非常灵活的数据加载器。LLaMA-Factory 这类平台封装得比较死自定义数据流反而难受不如直接用 PEFT Transformers 自己写循环。如果目标是做一个客服机器人、角色扮演助手这类对话产品我会优先选 LLaMA-Factory它内置了多种对话模板几乎开箱即用。如果目标是教模型“读懂某种行业报告”我更偏向 PEFT Transformers 或者 Axolotl因为可以自由控制数据分块逻辑。1.3 之后谁会跑这份代码也很关键同样的训练任务研究者、工程团队和业务同学的操作习惯完全不同。我见过有人把微调脚本写成了一个上千行的 Python 文件换一个人就不知道怎么改最后只好推倒重来。如果是一个长期维护的项目参与的人更多需要实验可复现那 Axolotl 的 YAML 配置就是最好的“实验说明书”一份配置对应一个实验如果只是临时验证一个想法赶紧跑通趁着热乎劲看结果那 LLaMA-Factory 的命令行是最快的如果后续要部署上线需要插入自定义推理逻辑、回调函数或评估指标那 PEFT Transformers 的原生 Trainer 更透明改起来不别扭。想清楚这三件事其实框架选择的大方向已经定了。接下来我们看看四大框架各自的画像。2. 四大主流框架画像不是越复杂越好2.1 PEFT Transformers最灵活的手工套装PEFTParameter Efficient Fine-Tuning是社区里非常成熟的一套参数高效微调库里面实现了 LoRA、QLoRA、P-Tuning、Prefix Tuning 等多种方法。它本身不是一个完整训练框架而是配合 Transformers 的 Trainer 使用。你可以把它想象成一组“高级乐高零件”所有的组合都由你自己决定。典型流程是加载一个基座模型用LoraConfig配置好低秩矩阵的参数用get_peft_model()把它变成可训练模型然后交给Trainer。因为所有步骤都在明面上你想改数据采样器、自定义 loss、调整梯度累积逻辑都非常方便。它的缺点也很明显——所有东西都要自己拼。新手容易遇到目标模块名写错、分词器 padding 方向不对、生成时 repeat_penalty 没加等问题。但只要你能熟练使用 PEFT后面看其它框架都会觉得很轻松因为它们底层大多也是调用的 PEFT。2.2 DeepSpeed显存不够时的外挂腿DeepSpeed 本身不是“微调框架”而是一个深度学习优化引擎核心卖点是 ZeROZero Redundancy Optimizer。ZeRO 的理念是把冗余数据分片到不同显卡上Stage 1 分片优化器状态Stage 2 分片梯度Stage 3 把模型参数、梯度、优化器状态全部打散到多张卡上需要时再聚合。它还可以把优化器状态/参数 offload 到 CPU 内存让显存压力转嫁给内存。在只有单卡但模型超过显存的情况下DeepSpeed 的 Stage2 CPU Offload 能帮你在单卡上“硬啃”一个原本放不下的模型。在多卡场景下它几乎是大模型全量微调绕不开的底座。但 DeepSpeed 配置比较繁琐和量化微调结合时最容易翻车。我后来总结出一个规律能用 PEFT 解决的显存问题就不要先引入 DeepSpeed只有当模型真的塞不进去时再把它当作“外挂腿”装上。2.3 LLaMA-Factory全家桶式集成平台LLaMA-Factory 是近两年大模型微调圈子里非常热门的集成平台。它内置了模型下载、数据集注册、SFT/DPO/PPO/RM 等多种训练方法以及 LoRA、QLoRA、全量微调等训练策略还附带 WebUI 界面。对新手来说简直是“乱杀级”工具。它的核心优势是数据格式和模型模板高度标准化。你用一条命令就能启动训练llamafactory-cli train \ --model_name_or_path Qwen/Qwen2-7B-Instruct \ --stage sft \ --template qwen \ --dataset alpaca_zh_demo \ --finetuning_type lora \ --output_dir output用过几次之后你会发现平台把“加载 tokenizer、应用模板、算注意力掩码”这些脏活全部包掉了。但副作用是封装的“黑盒”会让人忽略底层原理一旦出现 loss 不降、样本拼接错误等问题排查起来反而更费劲。2.4 AxolotlYAML 驱动的实验管理神器Axolotl 是一个进阶封装本质还是基于 Transformers 和 PEFT但把所有训练参数塞进一份 YAML 配置文件里。启动训练的命令只有一句话accelerate launch -m axolotl.cli.train configs/experiment.yml实验参数、模型名称、数据集、LoRA 配置、优化器、学习率调度器、甚至 DeepSpeed 配置全部写在一个文件里。这样做的好处是实验可复现性极强A 同学给 B 同学一个 yaml 文件B 同学同一环境下一跑结果完全一致。对于需要做大量对比实验的实验室或比赛团队这是最舒服的管理方式。它的劣势是版本兼容和更新速度让人头疼。几个月不更新旧配置文件就可能跑不起来。因此用 Axolotl 一定要锁定版本最好用 Docker 镜像或 requirements 全量锁文件。顺带提一句社区还经常提到 Unsloth。严格来说它不是一个“独立微调框架”更像是一个加速插件能在不改变模型接口的前提下把训练速度和显存占用优化几个档次。我后面会再展开。3. 逐个框架的实操细节与适用边界3.1 PEFT Transformers手工微调的完整流程下面是一个最简洁的 QLoRA 微调片段我用它跑通过不少 7B 模型。先统一说明这里假设你已经有数据集dataset每条数据是instruction、output字段并且已经完成 tokenizer 处理。import torch from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments, Trainer from peft import LoraConfig, get_peft_model from datasets import Dataset model_name your-base-model tokenizer AutoTokenizer.from_pretrained(model_name, trust_remote_codeTrue) if tokenizer.pad_token is None: tokenizer.pad_token tokenizer.eos_token # 4bit 量化基础模型 model AutoModelForCausalLM.from_pretrained( model_name, load_in_4bitTrue, torch_dtypetorch.bfloat16, device_mapauto, trust_remote_codeTrue, ) # LoRA 配置 lora_config LoraConfig( r8, lora_alpha16, target_modules[q_proj, k_proj, v_proj, o_proj], lora_dropout0.05, biasnone, task_typeCAUSAL_LM, ) model get_peft_model(model, lora_config) model.print_trainable_parameters() training_args TrainingArguments( output_dir./output, per_device_train_batch_size1, gradient_accumulation_steps8, num_train_epochs3, logging_steps10, save_steps100, learning_rate2e-4, fp16True, gradient_checkpointingTrue, ) trainer Trainer( modelmodel, argstraining_args, train_datasetDataset.from_list(dataset), tokenizertokenizer, ) trainer.train()这里有几个要点target_modules 必须和实际模型匹配。某些模型比如部分中文模型把注意力矩阵模块命名为q_proj、k_proj、v_proj、o_proj但另一些模型可能叫self_attn.q_proj或者根本没有q_proj。建议打印 model.named_parameters() 检查模块名后再填。4bit 量化必须配合load_in_4bitTrue并且需要设备支持 bnb。如果环境里没有 bitsandbytes这个代码会直接报错。gradient_checkpointing 能省大量显存但会略微降低速度。8GB 卡上几乎是必开。这套流程适合你愿意花半天时间理解每个参数含义的场景。一旦跑通后续换模型、改 loss 都很顺畅。3.2 DeepSpeed配置文件到底怎么写才不翻车DeepSpeed 的用法是在 Transformers 的 TrainingArguments 里指定一个 json 配置文件。下面是我常用的 Stage2 CPU Offload 配置适合 13B 模型在 24G 单卡或两张 24G 卡上训练{ train_batch_size: auto, train_micro_batch_size_per_gpu: auto, gradient_accumulation_steps: auto, zero_optimization: { stage: 2, offload_optimizer: { device: cpu, pin_memory: true }, overlap_comm: true, allgather_partitions: true, reduce_scatter: true }, fp16: { enabled: auto, loss_scale: 0, loss_scale_window: 1000, initial_scale_power: 16 } }然后在 TrainingArguments 里加一个参数training_args TrainingArguments( output_dir./output, deepspeedds_config.json, per_device_train_batch_size1, gradient_accumulation_steps8, fp16True, )关键字段解释zero_optimization.stageZeRO 的阶段。stage2 把优化器状态分片推荐单卡或多卡场景stage3 连模型参数都分片一般在多卡大规模全量微调时使用。offload_optimizer把优化器状态塞到 CPU 内存。这是“硬啃”大模型的核心开关代价是训练速度会明显慢但显存占用能降一大截。train_batch_size、train_micro_batch_size_per_gpu、gradient_accumulation_steps一般填auto让 Transformers 接管避免两边数值冲突。我踩过最深的坑是直接用 stage3 QLoRA结果单卡显存不降反升。原因是 QLoRA 权重本身是 4bit 量化而 stage3 默认按“完整参数分片”的语义去管理状态两者叠加产生大量临时缓冲区。如果你的主打方案是 LoRA/QLoRA优先用 stage2只有全量微调才值得上 stage3。3.3 LLaMA-Factory一条命令跑通 SFTLLaMA-Factory 的使用方式简单很多。你需要把自定义数据集在data/dataset_info.json里注册例如{ my_chat_data: { file_name: my_chat_data.json, formatting: sharegpt, columns: { messages: conversations } } }然后启动训练llamafactory-cli train \ --model_name_or_path your/model \ --stage sft \ --template chatml \ --dataset my_chat_data \ --finetuning_type lora \ --max_length 1536 \ --per_device_train_batch_size 1 \ --gradient_accumulation_steps 8 \ --learning_rate 2e-4 \ --output_dir output/my_lora重点提醒--template必须和模型匹配。比如 Qwen 官方推荐qwen百川模型推荐baichuan部分通用模型推荐chatml。模板不匹配tokenizer 拼接出来的训练样本是错的loss 还照样降但你最终生成效果会一塌糊涂。数据集格式别搞混。alpaca 格式是指令-输入-输出三字段sharegpt 格式是多轮对话 messages你注册的数据类型和实际 json 内容必须一致。首次建议先用官方 demo 数据集跑一次再做数据替换这样可以隔离框架问题和数据问题。LLaMA-Factory 还提供了可视化界面。很多人喜欢用 UI 点点点但我更推荐命令行因为更容易纳入版本控制和自动化流水线。3.4 Axolotl用一份 YAML 把实验锁进保险箱Axolotl 的配置自由度很高可以直接在 YAML 里描述绝大部分训练设置。下面是一个典型的最小配置base_model: your/model model_type: AutoModelForCausalLM tokenizer_type: AutoTokenizer load_in_8bit: false load_in_4bit: true strict: false datasets: - path: your_dataset.json type: alpaca lora_r: 8 lora_alpha: 16 lora_dropout: 0.05 lora_target_modules: - q_proj - k_proj - v_proj - o_proj training: micro_batch_size: 1 gradient_accumulation_steps: 8 num_epochs: 3 optimizer: paged_adamw_8bit learning_rate: 2e-4 lr_scheduler: cosine gradient_checkpointing: true deepspeed: deepspeed_config.jsonAxolotl 最好的地方是你可以把整个实验的物理环境、超参、数据路径全部记录在配置里。换机器跑时只要重构环境并执行同一条加速启动命令结果不会漂移。正因为如此做对比实验时Axolotl 是我优先级比较高的选择。使用 Axolotl 一定记住版本锁定很重要。Axolotl 的迭代很频繁旧配置跑不出新结果是常见事。强烈建议在同一个 Docker 镜像里安装好固定版本并导出pip freeze。加载本地数据集时路径写相对路径或绝对路径都行但若是跨机器路径一致性会坑死人建议统一参考路径。遇到奇怪的显存错误先去检查micro_batch_size和gradient_accumulation_steps别一上来就怀疑算法有 bug。4. 选择决策与实战推演4.1 一张资源配置对照表我整理了一张自己在选型时会看的表覆盖从 8GB 单卡到多卡高显存环境硬件条件推荐方案不推荐的理由单卡 8GBQLoRA LLaMA-Factory 或 PEFT全量微调直接没法跑DeepSpeed 单卡无天然优势单卡 16GB7B QLoRA / 小模型全量微调13B QLoRA 会非常紧张激活值容易 OOM单卡 24GB7B 全量LoRA13B QLoRA offload13B 全量微调还是太勉强双卡 24GB7B 全量 DeepSpeed stage213B QLoRAstage3 在大 batch 下通信开销大多卡 48GB13B 全量/继续预训练用 DeepSpeed stage3只跑 LoRA 会浪费算力这张表的原则是先用显存估算“能不能”再用目标任务判断“该不该”最后用团队习惯决定“怎么选”。4.2 案例一一张 8GB 卡把通用对话模型调成客服语气这是一个非常常见的小白场景。我的建议是直接用 LLaMA-Factory QLoRA因为数据格式、模板、训练命令都被简化了。具体做法选择 7B 或更小的开源对话模型最好用官方推荐的 chat 版准备 5002000 条客服对话样本采用 sharegpt 格式注册数据集修改 template 字段为模型对应模板训练时设置per_device_train_batch_size1, gradient_accumulation_steps8, max_length1024。实际跑下来7B QLoRA 在 8GB 卡上的训练速度大约每 step 0.82 秒几百条训练样本的 epoch 也就几十分钟。效果要看数据质量如果数据里有大量重复话术模型会变得啰嗦最好训练前先做一下去重和重排。4.3 案例二多张高显存卡想对底座模型做领域继续预训练如果目标是用一大批领域文档继续预训练把模型的“世界知识”往某个方向掰一掰那么 LLama-Factory 这类封装平台就不太合适。我更倾向用 PEFT Transformers DeepSpeed stage3。这里原因有三领域继续预训练通常需要自定义数据切分逻辑比如按段落切、按标题切、按句子数切这些逻辑塞进标准数据集类里会很别扭你希望保留更多原始模型表示通常用全量微调或较大 r 值 LoRA而不是只能改下游任务的轻量适配你可能需要在训练过程中周期性评估模型在领域测试集上的 loss而自定义评估函数在 Trainer 里比在框架里好写。实现时用 Transformers Trainer 自带的train_dataset和data_collator就能完成。加上 DeepSpeed 的 ZeRO stage3 与 Flatten/FlashAttention 等优化技巧可以在不牺牲精度的情况下应对大规模语料。4.4 案例三快速对比多个实验需要严格复现我参加过不少需要横向对比方法的评测这种场景下 Axolotl 是最合适的。每个实验一个 yaml跑完留下配置文件和 log最后汇总成表格排查模型效果差异时极其方便。但要注意对比实验最怕“环境漂移”。可能你第一天用 torch 2.1 跑 A 模型第三天升级 torch 后跑 B 模型数值精度就变了导致不可比。解决办法是固定一个 Docker 镜像所有实验都在同一镜像里跑。如果团队不用 Docker至少用 conda 环境 pip freeze requirements.txt。5. 踩坑记录框架切换时最容易翻车的四个瞬间5.1 PEFT 与 DeepSpeed 的显存手拉手问题第一次尝试 PEFT DeepSpeed stage3 时我记得很清楚单卡显存监测直接从 6GB 跳到 15GB然后 OOM。明明 LoRA 训练的参数只有那么点为什么显存还爆了后来查源码和 profile 才明白DeepSpeed stage3 的分片粒度是“完整模型参数”它会为每个参数维护元数据和分布式通信缓冲区。LoRA 本身是小参数但和量化基座叠加时片段化的内存布局会让 stage3 做冗余的全量 gather造成显存峰值暴涨。解决办法如果只是单卡或双卡DeepSpeed 用 stage2 从来不要碰 stage3如果多卡且非用 stage3 不可关掉offload_optimizer使用原生混合精度并预留更多显存 buffer先用 100 样本跑一个 step监测每张卡的峰值显存再决定是否继续。5.2 LLaMA-Factory 数据集格式不对loss 死活不降曾有人拿着一个“多轮对话”数据集注册时 in dataset_info.json 写成了formatting: alpaca而 json 内容是 sharegpt 的conversations多轮字段。跑起来后 loss 一直 1.1 左右波动最后生成的内容几乎全是重复的“嗯嗯”。排查过程很痛苦最后逐条打印训练样本才看到tokenizer 到位但 mask 掉了很多本该计算的文本模型只学到了极少部分标记。解决办法先看data/dataset_info.json里注册的formatting到底是 alpaca 还是 sharegpt用脚本打印一条 tokenizer 输出确认 instruction 段是否被忽略训练前跑官方 demo 数据集验证框架无损再换成自己的数据。5.3 Axolotl 的版本不锁结果不可复现有一次我用同一个 yaml一周前训出的 loss 曲线和一周后完全不一样。当时以为是随机种子问题后来发现是 Axolotl 自动升级了底层依赖把 transformer 版本从 4.40 升到了 4.45导致lora_target_modules里有些模块名匹配方式变化实际生效的 LoRA 层也不同。从那以后我再也不敢用 latest 安装。现在习惯是pip install axolotl0.4.0 pip freeze requirements-lock.txt如果有 Docker 环境直接构建镜像后导出 image tag比什么都稳妥。5.4 checkpoint 路径混乱LoRA 权重叠了两次还有一个非常容易阴沟翻船的场景PEFT 训练结束后有人先加载基础模型再加载 LoRA 权重然后又model.load_state_dict(torch.load(pytorch_model.bin))因为保存 checkpoint 时不小心把基础模型权重也保存了结果 LoRA 和完整权重叠加生成效果完全崩坏。建议保存时彻底区分# 正确保存 LoRA model.save_pretrained(lora_weights) # 正确推理加载 base_model AutoModelForCausalLM.from_pretrained(base_model_name, load_in_8bitTrue) model PeftModel.from_pretrained(base_model, lora_weights)永远不要在同一个环境里同时加载两种权重文件。6. 最终建议我的基准组合与下一步扩展如果你问我自己的标准答案我会这么干做研究、对比实验、需要严格复现选 Axolotlyaml 就是你的实验记事本做产品、偏向稳定工程化选 PEFT Transformers用 Trainer 自己控制一切方便后续接入推理和监控赶进度、验证想法、跑对话类微调选 LLaMA-Factory最大化交付效率模型实在太大显存紧张时再引入 DeepSpeedstage2 优先stage3 谨慎。如果训练速度实在让人心急你可以尝试把底层 Trainer 替换成 Unsloth 的版本。不需要改模型接口只要改一个加载方法显存占用能下降 30%50%训练速度提升 25 倍。它不是一个独立框架但可以是 PEFT 流水线里的加速利器。最后分享一个我屡试不爽的小技巧不管选哪个框架拿到配置后千万别直接全量开跑。先准备 10 条以内的小样本设置max_steps2跑通一个 step确认 loss 正常下降并且保存一次 checkpoint验证路径可读写。这一步能帮你省下后面排查环境问题的几个小时。框架选型这种事说到底不是站队而是搞清楚自己的边界和需求后找到一个顺手、可控、能长期维护的组合。希望这篇文章能让你少走一点弯路。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询