环境搭建
在开源大模型领域,Qwen 系列凭借强大的中文能力和友好的协议受到广泛欢迎。然而,直接使用基座模型往往无法满足特定业务场景的需求,需要通过微调来注入领域知识。微调后的模型如何高效部署?GGUF 格式是目前 llama.cpp 等推理后端广泛支持的格式,具有跨平台、内存映射等优点。
我们在一台 Linux 服务器上操作,安装了 Conda 用于环境隔离。需要准备以下组件:
- Python 3.10
- LLaMA-Factory(用于微调)
- llama.cpp(用于格式转换)
- transformers、peft、accelerate 等依赖库
1. 创建 Conda 环境
conda create -n llama_factory python=3.10 -y
conda activate llama_factory
2. 安装 LLaMA-Factory
LLaMA-Factory 是一个高效的微调框架,支持多种模型和算法。我们通过源码安装:
git clone https://github.com/hiyouga/LLaMA-Factory.git
cd LLaMA-Factory
pip install -e ".[torch,metrics]"
安装过程中如果遇到依赖冲突,可适当调整 transformers 版本,但建议保持最新。
3. 安装 llama.cpp
git clone https://github.com/ggerganov/llama.cpp.git
cd llama.cpp
pip install -r requirements.txt
注意:转换脚本 convert_hf_to_gguf.py 依赖 transformers,需要保证其版本兼容。
使用 LLaMA-Factory 微调 Qwen2.5-7B-Instruct
以 Qwen2.5-7B-Instruct 为基座,使用自定义数据集进行指令微调。假设数据已准备为 JSON 格式,每条包含 instruction 和 output 字段。
1. 准备数据
将数据集放在 LLaMA-Factory/data 目录下,并创建数据集配置文件 dataset_info.json,示例如下:
{
"my_dataset": {
"file_name": "my_dataset.json",
"columns": {
"prompt": "instruction",
"response": "output"
}
}
}
2. 配置微调参数
LLaMA-Factory 支持通过命令行或 YAML 文件配置。这里我们使用命令行进行 LoRA 微调:
CUDA_VISIBLE_DEVICES=0 python src/train_bash.py \
--stage sft \
--model_name_or_path Qwen/Qwen2.5-7B-Instruct \
--dataset my_dataset \
--dataset_dir ./data \
--finetuning_type lora \
--lora_target q_proj,v_proj \
--output_dir ./output/qwen2.5-lora \
--overwrite_cache \
--per_device_train_batch_size 4 \
--gradient_accumulation_steps 4 \
--lr_scheduler_type cosine \
--logging_steps 10 \
--save_steps 500 \
--learning_rate 1e-4 \
--num_train_epochs 3 \
--fp16
训练完成后,微调的 LoRA 权重保存在 ./output/qwen2.5-lora 目录中。
3. 合并 LoRA 权重
如果希望得到一个完整的 HuggingFace 格式模型(而非仅 LoRA 适配器),可以使用 export_model.py 脚本合并:
python src/export_model.py \
--model_name_or_path Qwen/Qwen2.5-7B-Instruct \
--adapter_name_or_path ./output/qwen2.5-lora \
--template default \
--finetuning_type lora \
--export_dir ./output/qwen2.5-merged
合并后的完整模型将保存在 ./output/qwen2.5-merged 中,包含所有必要的配置文件、分词器和权重文件。
将微调后的模型转换为 GGUF 格式
1. 准备转换环境
为了转换,我们需要一个独立的 conda 环境,以免与 LLaMA-Factory 的依赖冲突。创建一个新环境并安装必要工具:
conda create -n llama.cpp python=3.10 -y
conda activate llama.cpp
pip install torch transformers sentencepiece protobuf
2. 执行转换命令
进入 llama.cpp 目录,执行转换命令(假设合并后的模型位于 /mnt/workspace/output/qwen2.5-merged):
cd /path/to/llama.cpp
python convert_hf_to_gguf.py /mnt/workspace/output/qwen2.5-merged \
--outtype f16 \
--verbose \
--outfile /mnt/workspace/qwen2.5-7B-instruct.gguf
3. 遇到的经典错误及解决
在执行上述命令时,可能会遇到转换脚本加载 tokenizer.json 文件时的解析错误。转换脚本运行时会输出大量权重映射信息,这里省略中间过程,直接展示关键报错:
Traceback (most recent call last):
...
raise FileNotFoundError(f"File not found: {tokenizer_path}")
FileNotFoundError: File not found: /mnt/workspace/.cache/modelscope/models/Qwen/Qwen2.5-7B-Instruct-lora/tokenizer.model
...
Exception: data did not match any variant of untagged enum ModelWrapper
该错误通常由两个原因引起:
- tokenizer.json 文件损坏:可能是下载不完整或微调过程中被意外修改。
- transformers 版本不兼容:某些较新的 tokenizer.json 格式需要特定版本的 transformers 才能正确解析。
经过排查,发现是 transformers 版本问题。当前环境中的 transformers 为旧版(如 4.36.0),而 Qwen2.5 的 tokenizer 需要更新版本支持。我们通过强制安装 transformers==4.45.0 解决了问题:
pip install --force-reinstall transformers==4.45.0
重新运行转换命令,成功导出 GGUF 文件!
注意:如果模型目录中的 tokenizer.json 确实损坏,可以从 HuggingFace 官方仓库重新下载覆盖。
4. 验证转换结果
转换完成后,检查输出文件:
ls -lh /mnt/workspace/qwen2.5-7B-instruct.gguf
可以使用 llama.cpp 提供的简单测试工具验证模型加载:
./main -m /mnt/workspace/qwen2.5-7B-instruct.gguf -p "你好,请介绍一下你自己。" -n 100
如果正常输出,说明转换成功。
总结
通过实践,完成了以下工作:
- 使用 LLaMA-Factory 对 Qwen2.5-7B-Instruct 进行了 LoRA 微调,并合并为完整模型。
- 利用 llama.cpp 的转换工具将微调后的模型转换为 GGUF 格式,以便高效部署。
- 解决了转换过程中遇到的 tokenizer.json 解析错误,关键在于确保 transformers 版本与模型兼容。
关键点总结:
- 版本兼容性:转换脚本对 transformers 版本敏感,建议使用较新稳定版(如 4.45.0)。
- 文件完整性:微调后务必检查 tokenizer.json 是否完好,必要时从官方源补充。
- 路径命名:转换命令中的输出文件名建议与模型对应,避免混淆。
- GGUF 格式的模型可以轻松在 llama.cpp、Ollama、LM Studio 等推理后端运行,极大地方便了本地部署。
