基于LLaMA-Factory对GLM-4-9B进行LoRA微调
在大模型落地场景日益丰富的今天,如何以较低成本让通用语言模型适配垂直领域,成为许多团队面临的核心挑战。直接全参数微调动辄需要数张A100显卡,而LoRA这类高效参数微调技术的出现,彻底改变了这一局面——它让我们能在单卡甚至消费级GPU上完成高质量的模型定制。
本文将以GLM-4-9B为例,带你走完从环境搭建到模型部署的完整微调闭环。我们将使用开源框架LLaMA-Factory,通过其强大的多模态支持和简洁的配置体系,实现对千亿级别中文大模型的快速指令微调(SFT),最终产出一个具备特定风格或专业知识的定制化对话模型。
环境准备:轻量安装,开箱即用
LLaMA-Factory 是目前最活跃的大模型微调集成工具之一,不仅支持 LLaMA、Qwen、ChatGLM 等主流架构,还统一了训练接口,提供命令行与 WebUI 双模式操作体验。相比手动拼接 Hugging Face 组件,它可以显著降低工程复杂度。
以下是在 Ubuntu 20.04+ 系统上的标准部署流程:
# 升级 pip 并设置清华源加速依赖下载 python -m pip install --upgrade pip pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple # 克隆项目并进入目录 git clone --depth 1 https://github.com/hiyouga/LLaMA-Factory.git cd LLaMA-Factory # 安装核心依赖(含 PyTorch、Transformers、PEFT 等) pip install -e ".[torch,metrics]"✅说明:
--e表示“可编辑安装”,便于后续调试源码;
-[torch,metrics]自动包含深度学习框架及评估库;
- 若使用 GPU,请确保已正确安装 CUDA ≥ 11.8 和 cuDNN,推荐 PyTorch ≥ 2.0。
若希望使用图形界面管理训练任务,可额外安装 WebUI 模块:
pip install -e ".[webui]"启动服务后即可通过浏览器访问:
python src/webui.py --port 7860 --host 0.0.0.0打开http://<your-server-ip>:7860,你将看到一个功能完整的可视化微调平台:上传数据、选择模型、调整参数、实时监控 loss 曲线……整个过程无需写一行代码。
模型获取:本地化加载 GLM-4-9B
GLM-4 系列由智谱 AI 发布,是当前中文语境下表现最强的语言模型之一。其中glm-4-9b-chat在推理、代码生成和多轮对话方面尤为出色,适合做领域适配的基础底座。
我们通过 ModelScope 平台将其下载至本地:
创建download.py文件:
from modelscope.hub.snapshot_download import snapshot_download model_dir = snapshot_download( 'ZhipuAI/glm-4-9b-chat', cache_dir='/root/models', # 建议修改为实际路径 revision='master' ) print(f"模型已下载至: {model_dir}")执行命令开始下载:
python download.py📌注意事项:
- 模型体积约14GB,建议预留至少 20GB 存储空间;
- 下载时间取决于网络带宽,通常需 10–30 分钟;
- 后续如采用 QLoRA 微调,也可考虑 INT4 量化版本以进一步压缩资源占用。
数据构建:标准化与清洗的艺术
数据质量直接决定微调效果上限。LLaMA-Factory 支持多种输入格式,但最常用的是Alpaca 格式,适用于指令监督微调(SFT)任务。
Alpaca 数据结构详解
每条样本包含如下字段:
| 字段 | 是否必填 | 说明 |
|---|---|---|
instruction | ✅ 必填 | 用户的核心请求 |
input | ❌ 选填 | 上下文补充信息 |
output | ✅ 必填 | 期望的模型回复 |
system | ❌ 选填 | 系统提示词,用于设定角色 |
history | ❌ 选填 | 多轮对话历史,格式为[["用户问", "模型答"], ...] |
示例 JSON 片段:
[ { "instruction": "解释什么是机器学习", "input": "", "output": "机器学习是人工智能的一个分支...", "system": "你是一位资深AI讲师", "history": [ ["你好", "您好!有什么我可以帮助您的?"] ] } ]单轮数据转换脚本
假设已有原始数据文件raw_data.json,结构如下:
[ {"prompt": "写一首关于春天的诗", "completion": "春风拂面花自开..."} ]我们需要将其规范化并清除干扰内容:
import json import re file_name = "raw_data.json" system_prompt = "你是一个富有创造力的语言模型" with open(f"./data/{file_name}", 'r', encoding='utf-8') as f: raw_data = json.load(f) converted = [] for item in raw_data: output_text = item["completion"] # 清洗特殊符号 output_text = output_text.replace("🐳", "").replace("✅", "") # 移除可能引发自我认知混乱的内容 if '我是' in output_text and 'AI助手' not in output_text: intro_pattern = r"^[\u4e00-\u9fa5]{2,10}[::\s]" # 匹配“名字:”类开头 output_text = re.sub(intro_pattern, "", output_text).strip() converted.append({ "instruction": item["prompt"], "input": "", "output": output_text, "system": system_prompt, "history": [] }) with open("./data/alpaca_single.json", "w", encoding="utf-8") as f: json.dump(converted, f, ensure_ascii=False, indent=4) print("✅ 单轮数据转换完成:alpaca_single.json")多轮对话处理策略
对于客服日志、聊天记录等多轮数据,应保留上下文作为history,仅将最后一轮作为当前训练目标:
import json from tqdm import tqdm file_name = "multi_turn_conversations.json" system_prompt = "你是一名耐心且专业的客服代表" with open(f"./data/{file_name}", 'r', encoding='utf-8') as f: conversations = json.load(f) processed = [] for conv in tqdm(conversations): turns = conv['turns'] # 假设格式为 [{'user': '', 'bot': ''}, ...] history = [] for turn in turns[:-1]: history.append([turn['user'], turn['bot']]) last_turn = turns[-1] processed.append({ "instruction": last_turn['user'], "input": "", "output": last_turn['bot'], "system": system_prompt, "history": history }) with open("./data/alpaca_multi.json", "w", encoding="utf-8") as f: json.dump(processed, f, ensure_ascii=False, indent=4) print("✅ 多轮数据转换完成:alpaca_multi.json")数据集合并与注册
将多个来源的数据整合为单一文件更利于管理:
import json merged = [] dataset_files = [ "alpaca_single.json", "alpaca_multi.json", "domain_knowledge_qa.json" ] for fname in dataset_files: with open(f"./data/{fname}", 'r', encoding='utf-8') as f: data = json.load(f) merged.extend(data) with open("./data/merged_glm4_ft.json", "w", encoding="utf-8") as f: json.dump(merged, f, ensure_ascii=False, indent=4) print("✅ 数据集合并完成:merged_glm4_ft.json")最后,在LLaMA-Factory/data/dataset_info.json中注册新数据集:
{ "custom_glm4_ft": { "file_name": "/path/to/LLaMA-Factory/data/merged_glm4_ft.json" } }⚠️ 注意填写绝对路径,否则训练时会报错找不到文件。
LoRA 微调:高效适配的关键配置
LoRA 的核心思想是冻结原模型权重,在 Transformer 层中注入低秩矩阵来学习增量更新。这种方式既能保留预训练知识,又能大幅减少可训练参数数量(通常仅为原模型的 0.1%~1%)。
在项目根目录创建配置文件lora_glm4_sft.yaml:
### model model_name_or_path: /root/models/ZhipuAI/glm-4-9b-chat ### method stage: sft do_train: true finetuning_type: lora lora_target: all # 应用于所有线性层(Wq, Wk, Wv, Wo 等) lora_rank: 64 # LoRA 矩阵秩 lora_alpha: 128 # 缩放系数,一般为 rank 的 2 倍 lora_dropout: 0.05 # Dropout 防止过拟合 ### dataset dataset: custom_glm4_ft template: glm4 # 使用 GLM 官方模板解析输入 cutoff_len: 2048 # 最大序列长度 max_samples: 5000 # 调试时限制样本数 overwrite_cache: true preprocessing_num_workers: 8 ### output output_dir: saves/glm4-lora-ft/checkpoint logging_steps: 10 save_strategy: epoch # 每个 epoch 保存一次 plot_loss: true # 绘制损失曲线 overwrite_output_dir: true ### training per_device_train_batch_size: 1 gradient_accumulation_steps: 8 learning_rate: 1e-4 num_train_epochs: 5 lr_scheduler_type: cosine # 余弦退火学习率 warmup_ratio: 0.1 fp16: true # 启用混合精度训练 bf16: false ### eval do_eval: true val_size: 0.1 # 自动划分 10% 作为验证集 per_device_eval_batch_size: 1 eval_strategy: epoch evaluation_strategy: epoch📌关键参数解读:
-lora_target: all:覆盖注意力模块中的所有投影层,提升适配能力;
-lora_rank=64:经验表明,对于 9B 级别模型,rank=64 能较好平衡性能与资源消耗;
-gradient_accumulation_steps=8:等效 batch size 达到 8,缓解小 batch 导致的梯度不稳定问题;
-fp16: true:混合精度训练能显著降低显存占用,单卡 A10/A100 即可运行。
开始训练:
cd LLaMA-Factory llamafactory-cli train lora_glm4_sft.yaml训练过程中终端会实时输出 loss 变化,并自动保存 checkpoint 至指定目录。
模型导出:合并适配器为独立模型
训练完成后,LoRA 权重只是附加的增量矩阵,无法独立推理。必须将其与原始模型合并(Merge)成一个完整的模型才能部署。
创建导出配置文件export_glm4_lora.yaml:
### model model_name_or_path: /root/models/ZhipuAI/glm-4-9b-chat adapter_name_or_path: saves/glm4-lora-ft/checkpoint template: glm4 finetuning_type: lora ### export export_dir: models/CustomGLM-4-9B-Chat-Lora export_size: 2 # 分块导出,每块约 2GB export_device: cpu # 推荐 CPU 导出,避免显存溢出 export_legacy_format: false # 使用 safetensors 格式更安全执行合并命令:
llamafactory-cli export export_glm4_lora.yaml完成后,models/CustomGLM-4-9B-Chat-Lora目录将包含:
- 合并后的模型权重(model.safetensors)
- tokenizer 配置文件
- 模型结构定义(config.json)
该模型可直接用于 Hugging Face Transformers 加载,或封装为 API 服务对外提供。
推理验证:测试你的定制模型
编写简单脚本验证模型输出是否符合预期:
from transformers import AutoTokenizer, AutoModelForCausalLM import torch tokenizer = AutoTokenizer.from_pretrained("models/CustomGLM-4-9B-Chat-Lora", trust_remote_code=True) model = AutoModelForCausalLM.from_pretrained( "models/CustomGLM-4-9B-Chat-Lora", device_map="auto", torch_dtype=torch.float16, trust_remote_code=True ) query = "请介绍你自己" inputs = tokenizer.apply_chat_template( [{"role": "user", "content": query}], return_tensors="pt" ).to(model.device) outputs = model.generate(inputs, max_new_tokens=200) response = tokenizer.decode(outputs[0], skip_special_tokens=True) print(response)运行后应能看到带有你设定角色特征的回答,例如:“我是一个经过专业训练的语言模型,擅长……”。
进阶优化方向
1. 显存不足?试试 QLoRA
如果你只有 24GB 显存的消费卡(如 RTX 3090/4090),可以改用QLoRA + 4-bit 量化:
finetuning_type: q_lora quantization_bit: 4QLoRA 在 LoRA 基础上引入了 NF4 量化和分页优化器,可在极低资源下完成高质量微调。
2. 提升训练效率:多卡并行
利用 DeepSpeed 或 FSDP 实现分布式训练:
torchrun --nproc_per_node=2 src/train_bash.py lora_glm4_sft.yaml双卡并行可将训练时间缩短近一半,尤其适合大规模数据集场景。
3. 图形化操作:WebUI 全流程管理
LLaMA-Factory 的 WebUI 不仅支持参数配置,还能:
- 拖拽上传数据集
- 实时查看 GPU 利用率与 loss 曲线
- 对比不同实验结果
- 一键导出模型
非常适合非技术人员协作参与模型开发。
4. 效果评估:建立量化指标体系
除了人工判断,建议加入自动化评估环节:
- 使用 ROUGE、BLEU 计算生成文本相似度
- 构建分类测试集评估准确率
- 设计 prompt 测试集对比微调前后响应一致性
这些都能帮助你客观衡量模型改进程度。
如今,打造专属大模型不再是巨头专属的能力。借助像 LLama-Factory 这样高度集成的开源工具,哪怕只有一张消费级显卡,也能在几天内完成一次高质量的领域适配训练。这种 democratization of AI 的趋势,正在真正推动智能应用的百花齐放。
不妨现在就动手尝试,把你积累的知识、风格或业务逻辑注入到 GLM-4 中,让它成为你手中的“超级助手”。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考