llama-factory导出gemma-3模型踩坑全解析:从显存不足到路径冲突的12个修复方案
2026/9/10 0:52:18 网站建设 项目流程

我在实际用 llama-factory 微调 gemma-3-12b-instruct 时,遇到过最折腾的一步不是训练本身,而是最后那个“导出模型”。训练流程走通、loss 降得挺漂亮、checkpoint 也正常保存,但一点导出按钮,各种报错就冒出来了:有说显存不够的,有提示找不到文件的,还有导出完模型根本加载不了的。这篇文章就把我排查的经验完整梳理一遍,希望能帮你少走弯路。

1. 问题背景:微调顺利完成,导出却反复失败

先说下我的环境:Ubuntu 22.04,单卡 RTX 4090 24G,CUDA 12.1,llama-factory 当时用的版本是 0.9.x,transformers 4.46 左右。微调方式用的 QLoRA(4bit 量化基础模型 + LoRA adapter),训练数据是几万条指令数据,batch size 调得比较小,训练过程大概一个多小时跑完,checkpoint 正常生成在saves/gemma-3-12b-instruct/lora/train_2025xxxx/目录下。

训练完成后我想把 LoRA adapter 合并回基础模型,导出成一个完整的、可以直接部署的 FP16 模型文件,方便后续用 vLLM 或者转成 GGUF 给 Ollama 用。结果在 llama-factory 的 Web UI 里点击“导出模型”后,界面提示“Export failed”,但日志只给了一行简短的报错,后面没有更多信息。这类导不出、导出后不可用的问题,我先后遇到了至少 5 种不同的情况,查了很多资料才逐个解决。

在开始排查前,我建议你先明确一件事:模型微调完成 ≠ 模型部署就绪。llama-factory 默认保存的 LoRA adapter 只是一个很小的增量权重,必须和基础模型合并,才能得到一个可以在各个推理框架中直接使用的标准模型。导出的本质就是“合并权重 + 重新保存”。这个过程中任何一个环节不匹配,都会导致失败。

2. 理解 llama-factory 导出模型的底层逻辑

2.1 导出的本质是什么

我们用 LoRA/QLoRA 微调时,训练过程并不会修改基础模型的原始权重,而是在模型的部分层旁边加了一些低秩矩阵(即 adapter)。llama-factory 保存的 checkpoint 里只包含了这些 adapter 参数,以及训练时的配置信息。以 gemma-3-12b-instruct 为例,完整 FP16 权重大概需要 24GB 存储空间,而 LoRA adapter 通常只有几百 MB。

导出模型的作用,就是把 adapter 和基础模型合并起来,生成一个完整的模型文件。llama-factory 底层调用的核心逻辑大致是:

  1. 加载基础模型(根据你填写的模型名称或路径);
  2. 加载 LoRA checkpoint,把 adapter 权重加到基础模型的对应参数上;
  3. 将合并后的模型保存到指定目录,同时保存 tokenizer、config 等文件。

如果你使用的是 QLoRA(即基础模型是 4bit 量化加载的),合并逻辑会更复杂一些。llama-factory 需要先把 4bit 权重反量化回半精度或全精度,再执行合并,所以我后面会重点强调显存问题。

2.2 llama-factory 提供哪些导出能力

在 Web UI 中,导出入口在顶部导航栏的“工具” -> “导出模型”,核心参数包括:

  • 模型名称:必须是基础模型,即微调前你选择的那个模型,不要选成 checkpoint 路径。
  • 适配器路径(checkpoint 路径):选择你训练保存的 adapter 目录。
  • 导出目录:合并后新模型的存放位置,必须是一个不存在的空目录(或者不存在)。
  • 导出格式:huggingface 格式、vLLM 格式、GGUF 格式等。
  • 导出量化等级:可选择 none(保持原精度)、8bit、4bit 等,即导出后的模型是否量化。
  • max_shard_size:分片大小,默认 2GB,一般不需要改。

命令行对应的导出命令大致如下(llama-factory 0.9.x 版本):

llamafactory-cli export \ --model_name_or_path /path/to/gemma-3-12b-instruct \ --adapter_name_or_path /path/to/saves/gemma-3-12b-instruct/lora/train_2025xxxx \ --template gemma \ --finetuning_type lora \ --export_dir /path/to/exported_model \ --export_size 2 \ --export_quantization_bit 4 \ --export_device auto

如果你不使用命令行,也可以直接在 Web UI 上操作,但命令行能输出更详细的堆栈信息,排查问题会方便很多,这一点我后面会反复提到。

3. 核心原因排查:12 个高频错误逐一分析

3.1 显存不足:最典型的“训练能过,导出却 OOM”

这是我在 24G 显存的 4090 上遇到的第一个拦路虎。训练时 QLoRA 把基础模型压到 4bit,显存占用大约只有 8GB 左右;但导出时要把 12B 参数全部加载回来做合并,FP16 精度下光模型权重就需要 24GB 显存,再加上优化器状态、临时变量等,24G 显存通常是不够的。

你可能会想,训练时用了 4bit 加载,导出时也勾选 4bit 量化导出不就行了?实际上,导出时的 4bit 量化是合并完成后再量化,中间过程仍然需要先以 FP16 或 BF16 精度加载完整模型。如果你显存不够,有几种可行方案:

  • 方案 A:让模型加载到 CPU 上进行合并。llama-factory 的导出命令有一个--export_device参数,可以设置为cpu。这样合并过程在内存中进行,显存完全不受限制。缺点是速度慢,12B 模型合并可能要多等十几分钟,但只要内存大于 32GB,基本都能跑完。
  • 方案 B:换一台显存更大的机器,只做导出这一步。训练可以在小显存机器上完成,导出可以拷贝 checkpoint 到云服务器或朋友的机器上执行,不一定非要同一台机器。
  • 方案 C:直接改为 LoRA(非 QLoRA)微调。如果你显存足够大(至少 24G 以上),可以考虑直接以 FP16 精度微调,导出的合并过程相对轻量。但这条只适合显存充足的情况。

我个人建议优先尝试方案 A。导出是一次性操作,慢一点没关系,关键是稳定。

3.2 基础模型路径与训练时不一致

llama-factory 导出时会根据你填的“模型名称”加载一个基础模型,然后在此基础上合并 adapter。如果你训练时用的模型是某个 Hugging Face 仓库(如google/gemma-3-12b-it),导出时却选择了本地另一个路径,或者本地缓存不完整,就会出现结构不匹配的报错,常见的表现是:

KeyError: 'model.layers.0.self_attn.q_proj.lora_A.weight'

或者提示某个共享层不存在。这时候的排查思路很直接:导出时选择的模型路径必须和训练时完全一致。你可以到saves/gemma-3-12b-instruct/lora/train_2025xxxx/目录下查看adapter_config.json,里面会记录base_model_name_or_path字段,这就是训练时用的基础模型路径。导出时原样填回即可。

3.3 checkpoint 路径选择错误

这个听起来很低级,但很容易搞混。llama-factory 保存 checkpoint 的目录结构通常是:

saves/ └── gemma-3-12b-instruct/ └── lora/ └── train_2025xxxx/ ├── adapter_config.json ├── adapter_model.safetensors └── training_args.bin

正确的 adapter_path 应该指向train_2025xxxx这一层,而不是 lora 这一层,更不是 saves 这一层。如果你选到了外层目录,llama-factory 会找不到adapter_config.json。此外,如果目录下同时存在adapter_model.safetensorsadapter_model.bin,优先选 safetensors 格式,速度快且更安全。

3.4 导出目录已经存在且非空

llama-factory 在导出时如果发现目标目录已存在且包含文件,通常会直接报错,提示“Export directory is not empty”。这个设计是为了防止覆盖原有模型。解决办法很简单:换一个全新目录,或者手动删掉旧目录里的文件。别抱着侥幸心理试图让它直接覆盖,实测大概率会报错。

3.5 llama-factory 或 transformers 版本太旧,导致 gemma-3 兼容性问题

gemma-3 是相对较新的模型,老版本的 transformers 或 llama-factory 可能缺少对应的模型结构。具体表现是,加载基础模型时报 key 不匹配,或者在合并时出现 schema 错误。

我的建议是,如果你要微调 gemma-3 系列,务必把 llama-factory 升级到较新的版本,同时更新 transformers、peft、accelerate、tokenizers 等核心依赖。可以在项目虚拟环境里执行:

pip install -U llama-factory transformers peft accelerate tokenizers

注意,升级前最好看一下你训练时记录的依赖版本,避免 checkpoint 和旧版本产生的中间文件冲突。我遇到过一次使用旧版 transformers 加载新版模型权重,报错提示Some weights of Gemma3ForCausalLM were not initialized,把所有相关库升到最新后问题才消失。

3.6 磁盘空间不足导致导出中断

12B 模型在 FP16 下大小约 24GB,如果你导出为 8bit 或 4bit 量化版本,文件会小一些,但合并过程中会生成临时文件,也需要一定的磁盘空间。如果你在训练时保存了多个 checkpoint,磁盘可能已经占了不少。导出失败后我查看dmesg才发现是磁盘写满导致的。

建议在导出前用df -h检查目标磁盘的剩余空间,至少保留 30GB 以上。如果你的 checkpoint 数量很多,也可以考虑先删除中间 checkpoint,只保留最终版本。

3.7 Gemma 系列分词器加载异常

gemma-3 的分词器有一些特殊逻辑,在某些旧版本 transformers 下,tokenizer 加载会出现参数解析错误,或者导出的 tokenizer_config.json 信息不完整。表现是导出时没报错,但导出的模型在推理时提示 tokenizer 无法加载。

解决方法是:升级 transformers 到最新版本。如果升级后仍然异常,可以手动从基础模型目录复制tokenizer.modeltokenizer.jsontokenizer_config.json到导出目录覆盖相关文件。这通常能解决大部分 tokenizer 兼容性问题。

3.8 微调时添加了自定义 token,但导出时未处理

如果你在微调时使用了自定义数据集,里面包含特殊 token(比如<|begin|><|end|>),llama-factory 可能已经帮你扩展了词表大小,合并后的模型 embedding 维度也随之改变。但如果导出时没有把带扩展词表的 tokenizer 一起导出,推理时 embedding 矩阵和 tokenizer 就对不上,典型报错是:

RuntimeError: Error(s) in loading state_dict for Gemma3ForCausalLM: size mismatch for model.embed_tokens.weight: copying a param with shape torch.Size([30000, 2304]) from checkpoint, the shape in current model is torch.Size([256000, 2304]).

这种情况需要在导出后,特别检查导出的tokenizer_config.jsonadded_tokens.json是否存在。如果缺失,可以从训练 checkpoint 目录找回,或者用transformersAutoTokenizer加载后再次保存。

3.9 导出 GGUF 格式时缺依赖或网络异常

如果你尝试直接从 llama-factory 导出 GGUF 格式,它需要调用 llama.cpp 的转换脚本。这个过程中经常因为以下原因失败:

  • 本地没有安装llama-cpp-python或相关转换工具;
  • 转换时需要下载一些组件,但网络不通,或下载源很慢;
  • GGUF 转换脚本对 gemma-3 这类较新模型支持不完善。

我的建议是:先用 llama-factory 导出成 Hugging Face 格式,再手动用 llama.cpp 的 convert_hf_to_gguf.py 脚本转成 GGUF。这样虽然步骤多一些,但每一步都更容易排查。网上好多教程默认“一键导出 GGUF”,其实在 gemma-3 这种新模型上并不一定可靠。

3.10 显存碎片化导致的内存分配失败

有时候你明确看了显存,发现总占用并不高,但导出依然报CUDA out of memory。这可能是显存碎片化导致的。特别是在长时间训练过程中,PyTorch 的缓存分配器可能保留了大量不连续的内存块,导致后续无法分配整块连续显存。

处理办法:重启程序或者重启终端,清空 CUDA 缓存。如果你用的是 Web UI,重启 llama-factory 服务,再重新打开页面导出。别小看这一步,我实测能解决不少“看起来显存明明够,却报 OOM”的情况。

3.11 导出后模型加载时提示 config 缺失

这种问题是导出过程其实成功了,但导出的目录里缺少关键的配置文件。可能原因是你手动挪动过文件,或者导出过程中断。检查导出目录是否包含以下关键文件:

  • config.json
  • generation_config.json
  • tokenizer.modeltokenizer.jsontokenizer_config.json
  • .safetensors结尾的模型分片文件
  • model.safetensors.index.json(如果分片保存)

如果缺文件,最直接的办法是从基础模型目录中复制缺失的 config 和 tokenizer 文件,但要注意 config 里的vocab_size等字段必须与合并后的权重匹配。如果只有模型权重文件缺失,那就需要重新导出。

3.12 Windows 路径过长或存在特殊字符

如果你在 Windows 下操作,模型路径过长(尤其是有多层嵌套目录)或者包含中文、空格、特殊符号,可能会导致文件读写失败。这个问题的隐蔽性很强,因为报错信息往往不直接指向路径,而是一堆莫名其妙的 python 异常。

解决方法是:把整个工作目录放在一个简短、纯英文的路径下,比如D:\llm\llama-factory。导出目录也尽量用短路径,避免使用桌面这类带空格的位置。

4. 实操排查流程:教你一步步定位问题

4.1 先看完整日志,别只看 Web UI 的报错提示

Web UI 的报错信息比较简略,通常只显示Export failed,不告诉你真正原因。所以我强烈建议你用命令行方式执行导出。第一步可以先跑一个“空转测试”,把 adapter 指向一个最小 checkpoint 或者直接不指定 adapter,看看基础导出流程是否能通:

llamafactory-cli export \ --model_name_or_path /path/to/gemma-3-12b-instruct \ --export_dir /tmp/test_export \ --template gemma

如果这一步成功,说明基础模型路径、磁盘空间、依赖库版本都没有问题。如果这一步就报错,那问题大概率出在环境或基础模型本身,而不是你的微调结果。

4.2 确认训练时的 adapter_config.json 内容

打开你训练的 checkpoint 目录下的adapter_config.json,重点看三个字段:

{ "base_model_name_or_path": "google/gemma-3-12b-it", "r": 16, "lora_alpha": 32, "target_modules": ["q_proj", "k_proj", "v_proj", "o_proj"] }

其中base_model_name_or_path是你导出时必须填的基础模型路径。如果模型路径是 Hugging Face 仓库名,但本地没有缓存,llama-factory 启动时会尝试联网下载,如果网络受限就会失败。可以把基础模型先下载到本地,再把路径改成本地目录。

4.3 逐步缩小范围:先排除 adapter 的问题

如果能成功导出基础模型,下一步再带上 adapter 执行合并导出:

llamafactory-cli export \ --model_name_or_path /path/to/gemma-3-12b-instruct \ --adapter_name_or_path /path/to/saves/gemma-3-12b-instruct/lora/train_2025xxxx \ --template gemma \ --finetuning_type lora \ --export_dir /path/to/exported_model

如果这一步报错,注意读一下堆栈信息中是否提到了某个具体层。比如KeyError: 'base_model.model.model.layers.0.self_attn.q_proj.lora_A.weight',这通常说明 adapter 里的权重和基础模型的层结构对不上,原因可能是基础模型路径选错,或者微调时使用了非标准target_modules

4.4 显存不足时的操作顺序

在 24G 显存机器上导出 12B 模型,我建议的顺序是:

  1. 先尝试直接导出,观察是否报 OOM;
  2. 如果 OOM,修改命令行参数:
llamafactory-cli export \ --model_name_or_path /path/to/gemma-3-12b-instruct \ --adapter_name_or_path /path/to/saves/gemma-3-12b-instruct/lora/train_2025xxxx \ --template gemma \ --finetuning_type lora \ --export_dir /path/to/exported_model \ --export_device cpu
  1. 如果 CPU 合并内存也不够(32GB 内存可能会爆),可以考虑用--export_quantization_bit 4减少导出后模型大小,但合并过程仍然需要加载 FP16 权重,因此内存需求依然很大。

4.5 常见问题速查表

症状可能原因解决思路
报 CUDA out of memory显存不足或碎片化换 CPU 导出、重启清缓存、换大显存机器
提示 adapter 文件不存在checkpoint 路径选错检查 adapter_config.json 所在目录
KeyError 权重维度不匹配基础模型路径不一致检查 adapater_config 中的 base_model_name_or_path
导出目录已存在目标目录非空换新目录或清理旧文件
导出时无法下载依赖网络受限提前下载依赖包,或手动安装
导出后 tokenizer 无法加载transformers 版本过旧升级 transformers 或手动补全 tokenizer 文件
导出后 embedding 尺寸不匹配自定义 token 未正确保存检查 added_tokens.json 并同步合并
GGUF 导出卡住或失败llama.cpp 工具链不完整先导出 HF 格式,再手动转 GGUF
Some weights were not initialized本地模型文件不完整重新下载模型,使用与训练一致的版本
导出过程中断后目录残缺磁盘满或进程被杀清理空间,重新导出到新目录

5. 实战记录:我遇到的 3 个具体问题

5.1 问题一:24G 显存下直接 OOM

第一次导出,我在 Web UI 里填好参数,点击导出,界面很快报错。查看完整日志,定位到关键行:

torch.OutOfMemoryError: CUDA out of memory. Tried to allocate 24.00 GiB

这个很好理解,12B 模型 FP16 权重就要 24GB,4090 显存全部给它都不够。我当时的解决办法是改用命令行,加上--export_device cpu,然后把--export_dir指向了一个剩余空间 100GB 的机械硬盘。合并过程大概跑了 20 分钟,顺利结束。合并完成之后,我再次启动一个 Python 脚本验证模型能否正常加载和聊天:

from transformers import AutoModelForCausalLM, AutoTokenizer model_path = "/path/to/exported_model" tokenizer = AutoTokenizer.from_pretrained(model_path) model = AutoModelForCausalLM.from_pretrained(model_path, device_map="auto", torch_dtype="auto")

模型正常加载,能生成回复。这条路走通了。

5.2 问题二:导出时提示找不到model.embed_tokens相关权重

第二次,我在另一台 40G 显存的机器上做实验,这次没有 OOM,但出现了新的报错:

KeyError: 'base_model.model.model.embed_tokens.weight'

排查过程比较折腾。我先检查了 adapter_config.json,发现基础模型路径指向的是一个临时路径/tmp/gemma-3-12b-it,而当前机器上并没有这个目录。训练时我用的是 Hugging Face 缓存,训练结束后缓存被清理过,再次导出时 llama-factory 解析不到对应的本地模型文件,导致 layer 结构错位。

解决办法是:重新把google/gemma-3-12b-it下载到本地指定目录,然后用--model_name_or_path指向这个完整目录,同时保持 adapter_config.json 不变。导出成功。你如果也遇到这种问题,可以用huggingface-climodelscope先把模型完整拉到本地:

huggingface-cli download google/gemma-3-12b-it --local-dir /data/models/gemma-3-12b-it

再执行导出命令,基础模型路径改成/data/models/gemma-3-12b-it即可。

5.3 问题三:导出成功后,推理平台加载仍然报错

有一次导出过程完全正常,模型目录文件齐全,但用 FastAPI + transformers 加载时一直报错:tokenizer_config.json: file not found。我检查后发现,导出目录里确实没有 tokenizer_config.json,只有 tokenizer.model。

原因是我在 Web UI 中选了一个比较旧版本的 llama-factory,导出逻辑里对 gemma-3 的 tokenizer 处理不完整。解决办法有两种:

  • 直接从基础模型目录复制tokenizer_config.jsontokenizer.json到导出目录;
  • 或者在导出时勾选“包含 tokenizer”一类的选项(不同版本叫法略有差异),保证 tokenizer 文件被完整保存。

手动复制文件的方式最直接:

cp /path/to/gemma-3-12b-it/tokenizer* /path/to/exported_model/

注意,如果基础模型和导出模型词表维度不一致,直接复制 tokenizer 可能会导致 embedding 对应关系错位。但 gemma-3 系列大多数微调不扩展词表,复制后可以正常使用。如果你加了自定义 token,就需要同步修改tokenizer_config.json中对应字段,并确认added_tokens.json存在且正确。

6. 不同推理框架下的导出策略选择

6.1 使用 Hugging Face transformers 推理

最简单的方案,直接使用上述导出的标准 Hugging Face 格式模型目录,配合AutoModelForCausalLM加载即可。这种方式灵活性高,适合二次开发、调试和测试。但缺点是显存占用较大,且推理并发性能不如 vLLM。

6.2 使用 vLLM 推理

vLLM 对模型格式要求比较严格,通常要求是完整的 Hugging Face 格式,且最好有统一的config.json。你可以直接用我上面导出的 HF 格式模型目录作为 vLLM 的模型输入:

vllm serve /path/to/exported_model \ --served-model-name gemma-3-12b-it \ --tensor-parallel-size 2

如果你的导出过程中使用了--export_quantization_bit 4或 8bit,vLLM 加载时要注意指定对应的量化方式,在 llama-factory 中直接导出 vLLM 格式,它也会存入 HF 格式,因此一般不需要额外转换。

6.3 使用 Ollama / llama.cpp 推理

Ollama 需要 GGUF 格式的模型。建议先用 llama-factory 导出 HF 格式,再手动使用 llama.cpp 的转换脚本:

git clone https://github.com/ggerganov/llama.cpp cd llama.cpp pip install -r requirements.txt python convert_hf_to_gguf.py /path/to/exported_model \ --outfile /path/to/gemma-3-12b-it.gguf \ --outtype f16

转换完成后,再写一个 Modelfile 给 Ollama 使用。这个过程比“一键导出”多几步,但每一步都能看到实际的中间结果,方便排查问题。

6.4 量化导出时的额外提醒

如果你打算导出 4bit 量化模型,优先考虑使用--export_quantization_bit 4,实际上底层调用的可能是 GPTQ 或 AWQ,需要额外安装auto-gptqautoawq库。如果没有安装,导出会失败。在导出前可以先确认这些依赖是否已经装好:

pip install auto-gptq

注意,gemma-3 这种新模型在 GPTQ 量化时偶尔会出现层名不匹配的问题,遇到这种情况建议升级 auto-gptq 到最新版本。

7. 几点避坑心得

  • 训练前就规划好导出方案。如果你知道自己最终要部署到 Ollama 或 vLLM,训练时就尽量使用稳定的基础模型路径,最好把模型先拉到本地,避免每次导出都面临路径不一致的问题。
  • 不要同时在训练进程存活的机器上用同一块 GPU 做导出。即使显存够,也可能因为共用 GPU 显存或内存而出现意外。
  • 导出的模型一定要单独验证。导出成功不等于模型可用。最少要跑一次完整的生成测试,确认输出的回复质量和格式正常。我遇到过导出后基础对话没问题,但多轮对话模板错乱的情况,原因就是模板参数没有正确传进去。
  • 保留一个“最小可复现”的环境变量。把导出的命令行脚本保存成一个.sh文件,放到项目目录里,方便下次一键执行。在排查问题时,这个脚本也能帮你快速复现 bug。
  • 关注 llama-factory 官方更新和 issue。新版对 gemma-3 这类新模型的支持会持续优化,遇到问题先去 issue 里搜一下,往往能找到官方回复或临时 workaround。

从整体来看,导出问题虽然烦人,但只要把“基础模型路径、adapter 路径、显存/内存、依赖版本”这四个关键点逐一确认,大部分问题都能在 10 分钟内定位。如果你也卡在导出这一步,建议先按第 4 节的流程走一遍日志排查,少走弯路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询