最近正在做毕设,要用医学数据集微调 Qwen3,奈何找了两个开源数据集,微调效果都不是很好,想着学校的服务器闲着也是闲着,既然医学数据集微调的效果不好,为什么不试试猫娘数据集呢

(っ●ω●)っ古人云,铸万象言机,笼天地妙文,其本意所归,唯在猫娘而已。

前期准备

数据集

本文微调选用的猫娘数据集是kxdw2580/catgirl-datasets,当然也可以在Hugging FaceModelScope上搜索“猫娘”、“catgirl”等关键词挑选数据集

又或你也可以和亲友一起,通过角色扮演的方式,自制一个喵喵叫的猫娘数据集

微调平台

本文使用LLaMA Factory作为微调平台,以及llama.cpp对模型进行封装与量化处理

模型选择

使用医学类数据集的时候,考虑到有相当一部分中医相关的文本,因此选择了对中文支持比较好的Qwen3 8B模型,现在更换猫娘数据集后,依然继续使用该模型

写这篇文章的时候,Qwen3.5 都出来了,所以如果显存允许,Qwen3.5 9B也是个不错的选择,本文部分内容就是基于 Qwen3.5 9B 模型截的图

环境搭建

配置虚拟环境

学校服务器上预装好了 Conda,这里用它来配置一个虚拟环境给这次的微调使用

1
2
conda create -n llama_factory
conda activate llama_factory

不使用 Conda 的话,uv 同样好用

安装LLaMA Factory

虽然没有root权限,但好在 LLaMA Factory 是一个纯 Python 项目

考虑到现状,还是尽量找一个 Github 镜像网站 Clone,直接从 Github Clone,不是 443 ERROR 就是慢到怀疑人生

1
2
3
git clone https://github.com/hiyouga/LLaMA-Factory.git
cd LLaMA-Factory
pip install -e .[metrics]

为了防止发生使用 CPU 训练的悲剧,可以在这一步检查下安装的是否是 GPU 版本的 PyTorch

1
2
python -c "import torch; print(torch.cuda.is_available())"
python -c "import torch; print(torch.version.cuda)"

如果分别输出

1
2
False
None

再检查 PyTorch 版本

1
pip show torch

如果输出中没有出现 +cu1xx ,可以确定其是 CPU 版本

pasted-image-1774330663596.webp正确示范

解决方法也简单,卸载 CPU 版本的 PyTorch,重新安装 GPU 版本的 PyTorch;以 CUDA 12.6 版本为例,根据实际情况更改即可

1
2
pip uninstall torch torchvision torchaudio -y
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126

运行LLaMA Factory

倘若用来微调的数据集很大,完全可以考虑用 screen 新建一个会话,确保长时间运行

1
screen -S qwen3

Ctrl + A + D 离开这个会话

重新进入这个会话

1
screen -r qwen3

列出建立的会话

1
screen -ls

学校的服务器上装有七张 NVIDIA GeForce RTX 4090,但不可能全部用来微调一个80亿参量的小模型,此处限制了程序仅使用前两张显卡

1
export CUDA_VISIBLE_DEVICES=0,1

对于 8B 参数量的小模型来说,一张 4090 足够微调了,奈何某实验室负责人非要卡我的root权限,故本人义不容辞的把两张空闲 4090 全占了

限制了显卡后(或者不需要限制,默认使用全部显卡),让我们来启动 Web UI

1
llamafactory-cli webui

在配置没有错误的情况下,命令行会输出访问端口,通常是7860

运行失败了就把报错信息发给AI,让它们帮忙分析一下是哪里没配置好

pasted-image-1774228966149.webpLLaMA Factory Web UI

制作猫娘

下载模型

服务器能直接下载最好,在 LLaMA Factory 中选择想要微调的模型,它就会在微调之前自行下载;在服务器因种种原因不能通过 LLaMA Factory 下载模型的情况下,也可以手动下载模型,然后给定模型文件夹路径

我是使用 modelscope 来手动下载模型的,命令的使用参照 ModelScope 官方给出的文档,其中对下载命令有详细的解释

因为没有服务器 root 权限,所以 modelscope 默认的模型保存文件夹对我来说是没权限写入的,只能指定个有写入权限的文件夹用来保存模型文件

1
modelscope download --model 'Qwen/Qwen3.5-9b' --local_dir 'path/to/dir'

pasted-image-1774231278093.webp下载Qwen3.5 9B模型

也可以用 git clone 来下载模型,下载位置在当前执行命令的路径

1
git clone https://www.modelscope.cn/Qwen/Qwen3.5-9B.git

注册数据集

将数据集上传到 LLaMA-Factory/data 目录下,然后在目录下找到 dataset_info.json 文件,使用 vim 或你喜欢的编辑器打开它,在大括号内部,添加以下配置

1
2
3
"catgirl-common-v2-qwen3": {
"file_name": "common-v2-qwen3.json"
},

我只使用了kxdw2580/catgirl-datasets中的 common-v2-qwen3.json 数据集,对应的只导入了这一个文件,如果希望导入更多数据集,则需要注册相应数据集

选用的数据集如果不是标准 Alpaca 格式,那么可能需要进行映射处理

1
2
3
4
5
6
7
8
"my_chat_data": {
"file_name": "chat_local.json",
"columns": {
"prompt": "instruction",
"query": "input",
"response": "output"
}
}

写入保存后,刷新浏览器,在 数据集 下拉框中,就能找到刚刚导入的数据库了,选中,再点击旁边的 预览数据集 按钮

pasted-image-1774315600492.webp猫娘数据集预览

没有错误的话,在弹出框中可以清晰的看到数据集中的内容,如果没有弹出框/弹出框内容为空/乱码,说明刚才 JSON 里的 columns 映射填错了

某些数据集非常大,可以先从中切出来1000条数据,组成一个小型数据集,看看质量如何

1
2
3
4
5
6
7
8
9
10
11
import json
# 读取原始文件
with open('example.json', 'r', encoding='utf-8') as f:
data = json.load(f)

# 取前 1000 条
small_data = data[:1000]

# 保存为新文件
with open('example_small.json', 'w', encoding='utf-8') as f:
json.dump(small_data, f, ensure_ascii=False, indent=2)

微调设置

在 Web UI 中,有很多选项,在没有特定需求的情况下,大部分不用改动,我改动的只有以下几项

pasted-image-1774240173678.webp

  1. 语言当然是选 zh
  2. 模型路径,如果是手动下载的,那么就要指定文件路径
  3. 微调方法当然选择 lora 了,如果不是,请手动调整为 lora
  4. 对话模版,使用 Qwen3
  5. 学习率看情况,常见的学习率在 1e−43e−4 之间,而对所有模型权重进行全量微调可能需要接近 1e−5 的更低速率,这里使用默认的 5e-5
  6. 截断长度和批处理大小,等显存爆了再说,默认是20482,这里只对批处理大小做了调整,4090遭不住批处理设置为2
  7. 因为是演示用截图,所以数据集为空,但实际微调的时候,一定要选上准备好的数据集

进行微调

确保实验室其他人此时并不需要 GPU 资源,就可以开始创造猫娘了

pasted-image-1774317970623.webp创造猫娘ing~

如果 Loss 曲线平稳下降并逐渐收敛,说明模型正在认真学习如何成为一只猫娘;如果曲线像过山车一样上下乱窜,那可能就要考虑停下来检查一下数据集或者调整下学习率了

pasted-image-1774318049291.webp关注Loss曲线!

在网页上点击 中断,或者在命令行中按 Ctrl+C 都能停止微调,但如果想第二次启动程序进行微调,那么推荐先运行

1
nvitop

看看有没有残留进程占用资源,比如有一个PID为1111111的进程占据着部分资源,那么运行以下命令,杀死它

1
kill -9 1111111

确保可以压榨显卡100%的性能,而不是让残留进程占据资源😈

注意⚠️,不要误杀了他人的进程(如果你有权限的话),否则容易引发实验室血案!

测试

训练完成后,别急着关掉网页,LLaMA Factory提供了即时测试功能

pasted-image-1774318680792.webp训练完成的提示

切到网页上的 Chat 选项,设置检查点路径(如果训练了很多次,那么需要分清现在测试的是哪个版本,一般按照训练时间来给检查点命名)

pasted-image-1774319260923.webp

点击 加载模型,就可以在对话框里和猫娘进行交互

pasted-image-1774318895368.webp

如果她张嘴还是浓浓的AI味,说明模型可能欠拟合,或者需要换个数据集

如果她只会喵喵叫,丧失了正常的逻辑推理能力,那可能是过拟合了,得把 epoch 调小一点或者将学习率再降一降

测试结束后,记得点击 卸载模型,把显存空出来

导出模型

要是测试下来感觉效果不错,接下来就是将微调得到的LoRA权重与模型原始权重进行合并,打包带走猫娘

切换到 Export,导出格式保持默认的 safetensors,选择检查点路径,在导出目录填上保存路径,然后点击 开始导出

pasted-image-1774319540295.webp

模型量化

完整的80亿参量Qwen3模型大概要占用约15GB的显存,对本地电脑来说是个不小的负担;为方便部署在自己的电脑上,可以顺手用llama.cpp对模型进行封装和量化处理

可使用打包好的二进制文件,也可自行拉取源码进行编译,这里我已经编译好了,不再演示编译过程,推荐新手去下载编译好的二进制文件,能省去很多麻烦

安装好 llama.cpp 的依赖,先用其提供的脚本,将模型封装为 GGUF 格式

1
2
3
# 用法:python convert_hf_to_gguf.py [模型路径] --outfile [输出文件名]

python convert_hf_to_gguf.py /home/models/catgirl --outfile /home/models/catgirl/catgirl-fp16.gguf

然后进行量化,如果本地电脑显存足够,或不需要在本地电脑上运行,那么没必要进行这一步

关于大语言模型的量化技术,可以阅读2w字解析量化技术,全网最全的大模型量化技术解析

以下是 4-bit 量化的示例命令

1
2
3
4
# 编译好的工具路径默认在 build/bin 下
# 用法:./build/bin/llama-quantize [输入FP16文件] [输出量化文件] [量化方法]

./build/bin/llama-quantize /home/models/catgirl/catgirl-fp16.gguf /home/models/catgirl/catgirl-q4_k_m.gguf q4_k_m

如果想尝试其他精度,只要替换掉命令最后一部分,以及为了好记,顺便改一下输出文件的后缀名;唯一的例外是 IQ(重要性矩阵)系列,不能通过简单替换来实现,流程相对复杂,本文暂不展开

比如换成 Q8_0 量化

1
./build/bin/llama-quantize /home/models/catgirl/catgirl-fp16.gguf /home/models/catgirl/catgirl-q8_0.gguf q8_0

llama.cpp 经过长期的迭代,支持的量化格式已经非常丰富,除了基础的传统量化(Legacy)和目前主流的 K-quants(K量化),最近还引入了极限压缩的 I-quants(IQ量化,基于重要性矩阵)

可以根据以下表格来选择适合的量化方案

文件大小均以 8B 参数级别模型为基准估算,实际体积可能因具体模型词表大小略有浮动

量化方法 实际位宽 预计文件大小/显存需求 压缩率 损耗 适用场景
FP16 16.00 bit ~16.0 GB 100% 完全无损 (基准) 未压缩的原始半精度浮点,仅建议在显存极度充裕的服务器上打榜或作为二次量化的母盘使用
Q8_0 8.50 bit ~8.5 GB 53% 极近无损 传统 8-bit 量化,几乎等效于 FP16 的表现,适合需要复杂逻辑的场景
Q6_K 6.56 bit ~6.6 GB 41% 微乎其微 K量化系列的高配版,兼顾了速度与极高的回答质量,适合 8GB 显存的显卡
Q5_K_M 5.69 bit ~5.7 GB 35% 极小损耗 M 代表 Medium,相比 Q6 进一步压缩,日常聊天中几乎察觉不到降智,适合强逻辑的 Roleplay
Q5_K_S 5.54 bit ~5.5 GB 34% 极小损耗 S 代表 Small,压缩率较 M 略高,牺牲了一点注意力机制的精度换取空间
Q4_K_M 4.85 bit ~4.8 GB 30% 轻微损耗 默认选择,较高性价比,能把 8B 模型塞进 6G 显存,又能保持上下文连贯性
Q4_K_S 4.36 bit ~4.6 GB 28% 轻微损耗 Q4 级别的极限压缩版,如果显存卡在非常尴尬的边缘,可以尝试
Q4_0 4.50 bit ~4.5 GB 28% 中等损耗 传统的非 K 量化,智商比 Q4_K_M 稍逊一筹,在一些老 CPU 或不支持最新指令集的设备上推理速度较快
Q3_K_L 3.27 bit ~4.3 GB 26% 明显损耗 L 代表 Large,3-bit 量化的最高配,处理复杂逻辑的能力开始下降,但依然可以胜任日常闲聊
Q3_K_M 2.95 bit ~3.9 GB 24% 显著损耗 词汇量开始匮乏,容易出现车轱辘话,仅建议在显存严重受限的设备上使用
Q3_K_S 2.75 bit ~3.6 GB 22% 严重损耗 幻觉大幅增加,几乎丧失逻辑性
Q2_K 2.35 bit ~3.0 GB 18% 灾难性损耗 基本失去上下文推理能力
IQ 系列 1.x-4.x bit ~2.0-4.0 GB <20% 视矩阵而定 利用重要性矩阵(Imatrix)进行极限压缩,可以在 2-bit 下保持 Q3 的智商,转换过程非常复杂,不推荐新手使用

GGUF 后缀命名指南:

  • Q 代表 Quantization(量化)
  • K 代表采用了 K-quants 混合精度算法;其不会简单粗暴地把所有网络层都砍到同一精度,而是保留“关键层”(如 Attention 层)的高精度,压缩“边缘层”,从而在同等体积下让模型更聪明
  • _S / _M / _L:分别代表 Small(激进压缩)、Medium(中等均衡)、Large(保守压缩)

部署猫娘

参考在没有root权限的情况下运行ollama这篇文章

在导出模型文件夹中,会默认生成一个 Modelfile 文件,只需要修改其中的模型文件位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# ollama modelfile auto-generated by llamafactory

FROM ./catgirl-q4_K_M.gguf # 只更改了模型文件路径

TEMPLATE """{{ if .System }}<|im_start|>system
{{ .System }}<|im_end|>
{{ end }}{{ range .Messages }}{{ if eq .Role "user" }}<|im_start|>user
{{ .Content }}<|im_end|>
<|im_start|>assistant
{{ else if eq .Role "assistant" }}{{ .Content }}<|im_end|>
{{ end }}{{ end }}"""

PARAMETER stop "<|im_end|>"
PARAMETER num_ctx 4096

模型名称叫什么都行,只要确保 Modelfile 文件中的设置是正确的

1
2
3
# 用法:ollama create [模型名称] -f [Modelfile文件路径]

ollama create qwen3-catgirl -f Modelfile

pasted-image-1774321574896.webp