写在文前:没想到最后也屈服于 AI 了,在各种资料和 Gemini 的帮助下完成了一次微调和部署流程
项目目标:基于 Qwen2.5-7B-Instruct 模型,使用 PsyQA 数据集微调一个具备共情能力的心理咨询 AI,并量化部署到 Ollama。
硬件环境:NVIDIA 5090 32G + 100G 可用磁盘空间
基座模型:Qwen/Qwen2.5-7B-Instruct
第一阶段:环境与数据准备
1. 环境搭建
推荐使用 Conda 创建独立环境,防止依赖冲突。
Bash
# 1. 创建并激活虚拟环境
conda create -n qwen_finetune python=3.10 -y
conda activate qwen_finetune
# 2. 克隆 LLaMA-Factory
git clone --depth 1 https://github.com/hiyouga/LLAMA-Factory.git
cd LLAMA-Factory
# 3. 安装核心依赖
pip install -e ".[torch,metrics]" -i https://pypi.tuna.tsinghua.edu.cn/simple
# 4. 安装加速库 (Flash Attention 2)
# 注意:这步极易报错,确保 CUDA 版本与 Torch 匹配
pip install flash-attn --no-build-isolation
2. 数据处理与清洗
将 HF 格式转换为 LLaMA-Factory 支持的 Alpaca/JSONL 格式。
脚本:preprocess_psyqa.py
Python
import json
from datasets import load_dataset
def format_psyqa(output_file):
print("正在加载数据集 lsy641/PsyQA ...")
try:
# 建议先下载到本地 /root/autodl-tmp/data/ 避免网络中断
dataset = load_dataset("lsy641/PsyQA", split="train")
except Exception as e:
print(f"加载失败: {e}")
return
print(f"原始数据量: {len(dataset)}")
formatted_data = []
system_prompt = "你是一位共情能力强、专业的心理咨询师。请根据求助者的描述,给出温暖、建设性的建议。"
for item in dataset:
question = item.get('description', '') or item.get('question', '')
answer = item.get('answer', '')
# 简单清洗
if len(question) < 10 or len(answer) < 10:
continue
formatted_data.append({
"instruction": system_prompt,
"input": question,
"output": answer
})
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(formatted_data, f, ensure_ascii=False, indent=2)
print(f"✅ 处理完成!有效数据: {len(formatted_data)} 条。保存至: {output_file}")
if __name__ == "__main__":
# 确保 data 目录存在
import os
os.makedirs("data", exist_ok=True)
format_psyqa("data/psyqa_formatted.json")
生成文本样例:
{
"instruction": "你是一位共情能力强、专业的心理咨询师。请根据求助者的描述,给出温暖、建设性的建议。",
"input": "我想实现自己的目标,但是心灵匮乏,没有能量,所以行动力很低心灵能量如何补?",
"output": "楼主你好呀,给你温暖的抱抱~在你的问题描述中,你能够感知到自己是一个有目标的人,但是你却缺乏【能量】,这能量更学术一点的来说,就是动机。给我们做出行为反应的更多的就是我们的动机,当我们的动机越强烈越明确的时候,我们就能够越高效的、迅速的做出行为反应。或许你需要去寻找这个目标对你来说的意义,你为什么渴望有这样的一个目标?在这你还需要去完善你的行动,可能你有很强烈的需求去促进你的行为,但是可能在时间的安排上,你会耽误一些。可以试着给自己进行一个规划,通过一个大的目标来分解为小目标,进而制定一个适合自己的计划,通过细分能够更好地促进自己行为的发生。祝好~。"
}
3. 注册数据集
LLaMA-Factory 必须在 dataset_info.json 中注册数据才能识别。编辑 LLAMA-Factory/data/dataset_info.json,在文件末尾(大括号内)添加:
JSON
"psyqa": {
"file_name": "psyqa_formatted.json",
"columns": {
"prompt": "instruction",
"query": "input",
"response": "output"
}
}
第二阶段:LoRA 微调 (SFT)
1. 启动训练
建议保存为 run_train.sh 并运行。
- ⚠️ 显存注意:如果你显存小于 24GB,请调低
per_device_train_batch_size为 1,并调高gradient_accumulation_steps。
#!/bin/bash
CUDA_VISIBLE_DEVICES=0 llamafactory-cli train \
--stage sft \
--do_train \
--model_name_or_path Qwen/Qwen2.5-7B-Instruct \
--dataset psyqa \
--dataset_dir ./data \
--template qwen \
--finetuning_type lora \
--lora_target all \
--output_dir saves/Qwen2.5-7B-PsyQA/lora/sft \
--overwrite_output_dir \
--per_device_train_batch_size 2 \
--gradient_accumulation_steps 8 \
--lr_scheduler_type cosine \
--logging_steps 10 \
--save_steps 500 \
--learning_rate 1e-4 \
--num_train_epochs 3.0 \
--max_samples 10000 \
--max_grad_norm 1.0 \
--lora_rank 32 \
--lora_alpha 64 \
--lora_dropout 0.1 \
--plot_loss \
--bf16 \
--gradient_checkpointing
第三阶段:验证与合并
1. 快速对话测试 (Check LoRA)
验证 Adapter 是否有效。
llamafactory-cli chat \
--model_name_or_path Qwen/Qwen2.5-7B-Instruct \
--adapter_name_or_path saves/Qwen2.5-7B-PsyQA/lora/sft \
--template qwen \
--finetuning_type lora
2. 模型合并 (Merge)
将 LoRA 权重合入基座,生成完整模型。 ⚠️ 路径注意:请根据实际下载位置调整 /root/autodl-tmp/...。
# 确保在 LLAMA-Factory 目录下
llamafactory-cli export \
--model_name_or_path Qwen/Qwen2.5-7B-Instruct \
--adapter_name_or_path ./saves/Qwen2.5-7B-PsyQA/lora/sft \
--template qwen \
--finetuning_type lora \
--export_dir /root/autodl-tmp/Qwen2.5-7B-PsyQA-Merged \
--export_size 5 \
--export_device cpu
第四阶段:GGUF 量化与部署 (AutoDL -> 本地)
1. 编译 llama.cpp
修复点:针对 AutoDL 环境,需安装 cmake 和 libcurl。
cd /root/autodl-tmp
git clone --depth=1 https://github.com/ggerganov/llama.cpp.git
cd llama.cpp
# 安装依赖防止编译报错
apt-get update && apt-get install -y cmake libcurl4-openssl-dev
# 使用 CMake 编译 (生成工具在 build/bin 下)
mkdir build && cd build
cmake ..
cmake --build . --config Release -j $(nproc)
2. 格式转换 (HF -> GGUF FP16)
⚠️ 空间预警:此步需要约 35GB 空闲空间。
# 回到 llama.cpp 根目录
cd /root/autodl-tmp/llama.cpp
# 执行转换 (使用绝对路径)
python convert_hf_to_gguf.py /root/autodl-tmp/Qwen2.5-7B-PsyQA-Merged/ \
--outfile Qwen2.5-7B-PsyQA-f16.gguf \
--outtype f16
3. 模型量化 (FP16 -> Q4_K_M)
将 14GB 的模型压缩至 5GB,适合本地运行。
# 注意工具路径在 build/bin
./build/bin/llama-quantize Qwen2.5-7B-PsyQA-f16.gguf Qwen2.5-7B-PsyQA-q4_k_m.gguf Q4_K_M
4. 备份到 Hugging Face (推荐)
防止 AutoDL 数据丢失。需先在 HF 申请 Write 权限 Token。
pip install huggingface_hub
huggingface-cli login # 输入 Token
huggingface-cli upload 你的HF用户名/Qwen2.5-7B-PsyQA \
/root/autodl-tmp/llama.cpp/Qwen2.5-7B-PsyQA-q4_k_m.gguf \
Qwen2.5-7B-PsyQA-q4_k_m.gguf
第五阶段:本地 Ollama 运行
1. 编写 Modelfile
在本地电脑(存放 GGUF 的目录)新建文件 Modelfile:
FROM ./Qwen2.5-7B-PsyQA-q4_k_m.gguf
TEMPLATE """{{ if .System }}<|im_start|>system
{{ .System }}<|im_end|>
{{ end }}{{ if .Prompt }}<|im_start|>user
{{ .Prompt }}<|im_end|>
{{ end }}<|im_start|>assistant
"""
SYSTEM "你是一位专业的心理咨询师,擅长共情、倾听。请先接纳用户情绪,再给出建议。"
PARAMETER temperature 0.7
PARAMETER num_ctx 4096
2. 导入与运行
# 导入
ollama create psyqa -f Modelfile
# 运行
ollama run psyqa
Comments | NOTHING