Featured image of post 吹过的牛皮要实现 —— 速通小模型微调

吹过的牛皮要实现 —— 速通小模型微调

不小心吹个牛

一两个月前,我对大模型还比较迷信。觉得这模型真厉害,平时遇到啥问题,问它都可以回答个八九不离十。

遂心向往之~

后来也看到有UP主分享:“现在不流行训练自己的小模型了!真实项目中往往都是使用开源大模型+行业数据。”

  • 同事问我:“元芳,你怎么看?”

  • 我回答他,“耳听为虚,眼见为实。我要微调个自己的小模型看看。”

然后,就拖到了现在。。。

本文会分享以下内容

  1. 模型训练工具介绍(LLaMA-Factory)
  2. 在Transformer 架构下模型训练算法(本次使用微调 LoRA)
  3. 从0 开始0花费地训练一套小模型出来
  4. 讨论什么场景下 更适合微调模型

效果展示

咱们老规矩,还是先上效果图——

这个模型的用途是:用户输入任意新闻标题后,它可以进行类型标注。

例如,下面这两个新闻:

用户提问:“新闻分类:真相了?外媒:特朗普想在伊朗“更迭政权””

AI 回答:“国际”

用户提问:“新闻分类:许昕发文感谢队友?从陪练张继科到世界冠军!称霸世界的国乒!”

AI 回答:“体育”

这里的训练数据需要提前准备,格式上是这样的——

可以看出:“人类输入的内容” + “AI回答的内容” 这样一问一答作为一条训练数据

本次训练集300条这样的问答对组成。

我们的预期则是:

用户输入问题A –> “训练后的模型” –> 回答最合适的新闻类型(如:科技、体育、政治。。。)

训练后的模型输出,越接近训练集的结果,就认为这个模型越符合预期。反之,效果就一般。

后续模型测试中会看到,训练不成功的效果长什么样。

下面介绍下 训练AI模型使用到的工具:LLaMA-Factory

它是模型训练工具的一种,适合初学者(无需编写代码)快速上手操作。也是一个开源项目,官方介绍如下:

模型训练基础

如果了解并熟悉Transformer架构和 LoRA算法 或者 希望先上手微调训练,可以跳过本部分,查看后续操作步骤。

有三点关键内容需要提前了解下:基座模型微调方法以及训练参数。不然,后面的操作过程中会有点懵。。。

1. 基座模型

先说 “基座”,顾名思义就是我们的训练是基于一个“底座”的。不是完完全全从0 开始训练一个新模型。

因为训练这个模型的目的只是希望加强它在某一领域的知识和能力,不是取代现有大模型的通用能力。

所以,这个基座模型一般会选择开源模型中效果和开销比较平衡的。

比如这里使用的 DeepSeek-R1-Distill-Qwen-7B ,实测效果比 小规模的DeepSeek-R1-Distill-Qwen-1.5B 好不少。

Q:关于这个名字,怎么既有 DeepSeek又有 Qwen?这么长一串到底啥意思?

A: 这里涉及到开源大模型的命名规范: 机构名/产品系列+技术和知识来源+规模。以“DeepSeek-R1-Distill-Qwen-7B” 为例。分为三个部分:

  • DeepSeek-R1:DeepSeek 下的推理模型(慢思考,善于处理复杂逻辑内容)
  • Distill-Qwen:通过蒸馏(distillation) 通义干问 Qwen2.5 的通用知识
  • 7B:模型参数量70 亿

它结合了 DeepSeek-R1的推理能力 + qwen 的通用知识,资源消耗也不大。

这里我们只关心,相关“行业数据”(新闻)的输出效果。而其他方面的能力在训练后可能会变弱,例如计算能力,写作能力等。

2. 微调方法(LoRA)

这块涉及到 Transformer 架构下的数学矩阵计算

1)模型参数被转化为了数字向量

2)向量的值是一个范围巨大的矩阵。为了方便理解这里以 100*100 的矩阵(全秩矩阵),表示原先的 模型参数量。

3)问题来了:如果按照传统的训练微调(全参数微调)方式,就要训练全秩矩阵中每一个(10000)的值,工程量大 控制起来也复杂。

​ 有人就想出个优化的办法:通过两个小矩阵相乘 [ 100 * 2 ] * [ 2 *100 ] 可以填充全秩矩阵(100 * 100)的每个单元。

所以,LoRA(Low-Rank Adaptation of Large Language Models)方法就是精简训练上图 A B两个小矩阵

与LoRA 类似的训练小参方法,还有 QLoRA、Adapter、P-Tuning。简单了解一下——

3. 训练参数

先看一眼基本的训练参数:

常用来调整的参数 加粗表示下。

  • 训练阶段(stage):常用 SFT(Supervised Fine-Tuning)有监督微调,不常用 DPO(Direct Preference Optimization)和 PPO(Proximal Policy Optimization)
  • 学习率(Learning Rate):决定了模型每次更新时权重改变的幅度。过大可能会错过最优解;过小会学得很慢或陷入局部最优解
  • 训练轮数(Epochs):太少模型会欠拟合(没学好),太大会过拟合(学过头了)
  • 最大梯度范数(Max Gradient Norm):当梯度的值超过这个范围时会被截断,防止梯度爆炸现象
  • 最大样本数(Max Samples):每轮训练中最多使用的样本数
  • 计算类型(Computation Type):在训练时使用的数据类型,常见的有 float32 和float16。在性能和精度之间找平衡
  • 截断长度(Truncation Length):处理长文本时如果太长超过这个阈值的部分会被截断掉,避免内存溢出
  • 批处理大小(Batch Size):由于内存限制,每轮训练我们要将训练集数据分批次送进去,这个批次大小就是 Batch Size
  • 梯度累积(Gradient Accumulation):默认情况下模型会在每个 batch 处理完后进行一次更新一个参数,但你可以通过设置这个梯度累计,让他直到处理完多个小批次的数据后才进行一次更新
  • 验证集比例(Validation Set Proportion):数据集分为训练集和验证集两个部分,训练集用来学习训练,验证集用来验证学习效果如何
  • 学习率调节器(Learning Rate Scheduler):在训练的过程中帮你自动调整优化学习率页面上点击启动训练,或复制命令到终端启动训练

好了,铺垫了这么多。终于可以动手操作了。

模型微调实操

下面就是从0 开始,一步一步 微调我们需要的模型。

相关测试数据和训练后的模型,我放在公众号 【AI 热气球】中,感兴趣的话可以回复1117 获取。

0. 环境准备

既然是训练自然少不了显卡的加速,通常有三种方式:使用大模型提供商的在线微调服务、租用云平台的机器、本地自集成部署。

数据安全方面考虑: 本地自集成部署 > 租用云平台的机器 > 大模型提供商的在线微调服务

成本开销方面考虑: 本地自集成部署 > 租用云平台的机器 > 大模型提供商的在线微调服务

这么一看,优先选择“租用云平台的机器”完成小模型的训练和微调。毕竟我们这里数据不多,一次训练大约1小时左右。

而且,用到的平台“魔塔” 为新用户提供36小时 带24g显卡云主机的使用优惠,还是很划算的。

  • 申请并创建个人魔塔账号(https://modelscope.cn/home),过程中需要登录阿里云帐号

  • 在“我的 Notebook” (https://modelscope.cn/home) 中启动GPU主机—— 版本选择 Ubuntu 22.04 的就行。

  • 点击“查看 Notebook”,进入控制台界面后,点击 “插件”按钮搜索并安装中文语言包。

  • 检查显卡工作正常

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 检查显卡驱动和状态——
root@dsw-1471676-9bf84dfcb-nmxqn: nvidia-smi 
Fri Nov 14 16:06:26 2025       
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 550.127.08             Driver Version: 550.127.08     CUDA Version: 12.4     |
|-----------------------------------------+------------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id          Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Compute M. |
|                                         |                        |               MIG M. |
|=========================================+========================+======================|
|   0  NVIDIA A10                     Off |   00000000:00:09.0 Off |                  Off |
|  0%   26C    P8              9W /  150W |       4MiB /  24564MiB |      0%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+
                                                                                         
+-----------------------------------------------------------------------------------------+
| Processes:                                                                              |
|  GPU   GI   CI        PID   Type   Process name                              GPU Memory |
|        ID   ID                                                               Usage      |
|=========================================================================================|
|  No running processes found                                                             |
+-----------------------------------------------------------------------------------------+
root@dsw-1471676-9bf84dfcb-nmxqn:/mnt/workspace# 

1. llama-factory 工具安装

因为是在云平台上训练模型,云主机关机后除了个人工作目录 /mnt/workspace 下的数据都会被清空、还原。

所以,后续相关操作(安装包下载 测试数据上传 训练模型合并、下载)都是在 /mnt/workspace 这个目录下 。

另外,也为了llama-factory 环境运行依赖的 python 包之间不会冲突。一般建议使用conda 创建虚拟环境。

  • 我们这里 使用更轻量、便捷的社区版 “Miniforge”创建虚拟环境 。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# 进入工作空间
cd /mnt/workspace
# 下载最新的 Miniforge 安装包
wget https://github.com/conda-forge/miniforge/releases/download/25.3.1-0/Miniforge3-25.3.1-0-Linux-x86_64.sh

# 执行安装
bash Miniforge3-25.3.1-0-Linux-x86_64.sh
# 安装过程中,提示选择安装路径,默认为 /root/minigorge3。修改成以下路径:
/mnt/workspace/miniforge3

# 启用 Miniforge 配置和mamba 工具
eval "$(/mnt/workspace/miniforge3/bin/conda shell.bash hook)"
eval "$(mamba shell hook --shell bash)"

# 创建名为“llama-factory”的虚拟环境:
mamba create -n llama-factory python=3.10 (如果下载慢 就多试几次)
# 激活虚拟环境
mamba activate llama-factory

mamba_activate_newvenv

  • 虚拟环境准备好后,正式进入 llama-factory 安装环节:
1
2
3
4
5
6
7
8
9
# 克隆项目
git clone --depth 1 https://github.com/hiyouga/LLaMA-Factory.git

# 进入项目
cd LLaMA-Factory
# 安装项目相关依赖
pip install -r requirements.txt (第一次安装时间较长,大约30分钟)
# 执行安装
pip install -e ".[torch,metrics]"
  • 上述步骤完成,llama-factory 工具就安装好了。先查看下当期版本,后启动web界面
1
2
llamafactory-cli version
llamafactory-cli webui
llama-factory_version

llama-factory_webui

启动成功后,VSCode 会提示 打开一个http页面。

该页面映射刚启动的llama-factory web 服务(http://127.0.0.1:7860)。

  • 打开网页,看到如下页面,表示 llama-factory 已经启动成功了。
llama-factory_startup

2. 基座模型下载

这一步中,需要下载用到的基座模型 DeepSeek-R1-Distill-Qwen-7B

  • 具体操作如下:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 同样需要把模型保存在工作目录 /mnt/workspace 下
mkdir /mnt/workspace/Hugging-Face

# 配置huggingface-hub 下载加速和路径
export HF_ENDPOINT=https://hf-mirror.com
export HF_HOME=/mnt/workspace/Hugging-Face
export HF_HUB_DOWNLOAD_TIMEOUT=30

# huggingface_hub<1.0 时执行下载
# 测试的话可以试试这个小模型
huggingface-cli download --resume-download deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B
# 推荐使用7B这个模型
huggingface-cli download --resume-download deepseek-ai/DeepSeek-R1-Distill-Qwen-7B

如果模型下载速度太慢的话:参考这篇文章<如何快速下载huggingface模型——全方法总结>

https://zhuanlan.zhihu.com/p/663712983?s_r=0

  • 下载完成后, 在指定的目录 /mnt/workspace/Hugging-Face 中可以看到多出一个目录 叫“models–deepseek-ai–DeepSeek-R1-Distill-Qwen-7B”这个就是刚才下载完成的模型。

    然后,复制模型路径,稍候启动参数时需要指明模型具体位置。

1
2
3
4
5
# 复制7b模型位置路径
/mnt/workspace/Hugging-Face/hub/models--deepseek-ai--DeepSeek-R1-Distill-Qwen-7B/snapshots/916b56a44061fd5cd7d6a8fb632557ed4f724f60

# 如果下载了1.5b的模型,路径就是这样的 
/mnt/workspace/Hugging-Face/hub/models--deepseek-ai--DeepSeek-R1-Distill-Qwen-1.5B/snapshots/ad9f0ae0864d7fbcd1cd905e3c6c5b069cc8b562

3. 基座模型运行测试

先测试当前下载的模型加载、执行是否正常:

  • 在已经打开的llama-factory 页面中,语言切换至“zh”,指定“模型名称”和“模型路径”。

  • 然后点击“Chat” – > “加载模型”,提示加载成功后。输入用户 input,查看模型响应:

LLaMA_Factory_running

如上图,表示模型正常响应,可以继续操作。

4. 上传训练数据

训练数据格式有展示过,这里有两个数据文件+配置文件需要上传到 云主机上。

其中 train.json训练用数据,eval.json评估数据。dataset_info.json 为相关配置文件。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# dataset_info.json 配置文件内容:
{
    "train": {
      "file_name": "train.json",
      "formatting": "sharegpt"
    },
    "eval": {
      "file_name": "eval.json",
      "formatting": "sharegpt"
    }
}

# 上传这三个文件到以下目录
/mnt/workspace/LLaMA-Factory/data/example_newsdata

5. 微调模型

模型准备好了,训练数据也有了。"微调方法" 默认就是 lora。这里就可以开始调整微调参数了——

  • 点击“Train” 界面,“训练阶段”中默认是SFT(有监督微调)不用修改。

    数据路径”和 “数据集”选择上一步中的训练数据集“train”。

  • 修改微调相关参数,如:“学习率” -> 5e-4, “训练轮数” -> 10,“梯度累积” -> 4, “LoRA+ 学习率比例” -> 16, “LoRA 作用模块” -> “all”。

news_types_round2
  • 点击“开始”按钮,llama-factory 会加载模型和训练数据 进行训练。

    进行过程中,会有一副关于训练损失和训练步数的关系图。

    不同训练参数和模型,其训练时长不等。这里 20轮训练下来 差不多25分钟左右。

news_types_round1_graph

训练期间 云主机 GPU 发力工作:

llama-factory_training_gpustatus
  • 最终训练好的模型,输出在上面的“输出目录”中。后续可以基于此次训练结果,进行评估和测试。

6. 人工测试

回到 “Chat”界面,加载刚训练得到的模型检查点“train_2025-11-14-17-23-08”。

手动测试下新模型的效果——

news_types_round1_chattest

测试两三次,感觉起来好像还行。模型微调的过程就告一段落了。

但到底新模型效果如何,还是需要数据说话——

新模型评估

我们之前不是准备了 评估数据集 “eval.json” 么,此时派上用场。

  • 点击“Evaluate& Predict” 界面,“数据路径”和 “数据集”选择之前上传的数据集“eval”。
  • 其他评估参数保持默认,点击“开始”按钮。
news_types_round1_evaluate_process
  • 完成后,注意其中 “predict_rouge-1”的分数。这个分值越高,表明新模型生成质量越好。
news_types_round1_evaluate_result

上图中该值为 53.85——说明新模型生成的文本与评估数据(eval.json)在单词级别上有 53.85%的重合

新模型导出

此时新训练出来的模型还在云主机上。我们怎么把它拖到本地呢?

1. 首先导出模型

点击“Export” 界面,“导出设备” -> auto,在“导出目录”中输入模型导出路径后,点击“开始导出”。

llama-factory_export_model

看到“模型导出完成”,代表成功导出了此次训练出来的新模型。

在云主机 VSCode界面中,也可以看到新模型有哪些文件组成——

export_modelfiles

但是,这些模型文件不能直接在本地使用 Ollama 调用。

我们需要用到第二个开源工具——llama.cpp。

2. 使用llama.cpp 工具

使用 llama.cpp 工具,可以将上述模型文件转为 一个 .gguf 格式的文件

而后者,是可以在ollama 平台中加载、运行的。

与传统基于 Python 的 AI 框架(如 PyTorch/TensorFlow)不同,llama.cpp 选择回归底层语言C/C++的实现策略。这种设计使其摆脱了 Python 解释器、CUDA 驱动等重型依赖,通过静态编译生成单一可执行文件,在资源受限环境中展现出独特优势。

这里,同样在云主机中完成转换工作——

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# 在Vscode中新建一个会话终端,并进入工作目录
cd /mnt/workspace

# 克隆项目文件
git clone --depth 1 https://github.com/ggerganov/llama.cpp.git
eval "$(/mnt/workspace/miniforge3/bin/conda shell.bash hook)"

# [Option] 创建名为llama.cpp的新虚拟环境
mamba create -n llama.cpp python=3.10
eval "$(mamba shell hook --shell bash)"
mamba activate llama.cpp

# 安装项目所需依赖包
pip install -r llama.cpp/requirements.txt

# 最后执行格式转换
python3 llama.cpp/convert_hf_to_gguf.py ./export_models/deepseek-r1-1.5b-merged --outfile ./dsr1_1.5b_newstype.gguf

格式转换成功——

1
2
3
4
5

INFO:gguf.gguf_writer:Writing the following files:
INFO:gguf.gguf_writer:dsr1_1.5b_newstype.gguf: n_tensors = 339, total_size = 3.6G
Writing: 100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 3.55G/3.55G [00:56<00:00, 63.3Mbyte/s]
INFO:hf-to-gguf:Model successfully exported to dsr1_1.5b_newstype.gguf

ollama 上运行新模型

  • 下载 dsr1_1.5b_newstype.gguf 文件到本地目录,如 D:\download\export_models 中。

  • 然后,创建一个名为 ModelFile 的配置文件。注意,该文件没有后缀名。

​ 文件中内容如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
FROM ./dsr1_1.5b_newstype.gguf

# set the temperature to 0.7 [higher is more creative, lower is more coherent]
PARAMETER temperature 0.7
PARAMETER top_p 0.8
PARAMETER repeat_penalty 1.05
TEMPLATE """{{ if .System }}<|im_start|>system
{{ .System }}<|im_end|>
{{ end }}{{ if .Prompt }}<|im_start|>user
{{ .Prompt }}<|im_end|>
{{ end }}<|im_start|>assistant
{{ .Response }}<|im_end|>"""
# set the system message
SYSTEM """
You are a news category assistant.
"""
  • 确认本机 ollama 服务正在运行。执行以下命令完成 新模型的导入——
1
ollama create deepseek-r1_1.5b_newstype --file "D:\download\export_models\ModelFile"
导入成功:

ollama_run

  • 后续会很方便在 AI 应用中直接调用这个训练好的模型。

如今,为何不建议自己训练模型

我想有两方面原因:

  1. 现有模型80%~90% 是基于transformer架构的生成式AI,该架构下的AI响应结果严重依赖训练数据,因为模型自己是不会推理的。

    而有用的小模型,需要行业大量的数据。如果数据不够,真实上线时,会放心交给模型自己去猜?

    所以,在数据量不足的前提下,花时间、金钱去训练自己的模型是在找死。

    但是,反过来说,如果自己的数据量充足,这个训练就很有意义了——一定场景下可以实现低成本快速响应

  2. 通用大模型的能力在快速迭代,他们获取数据的广度和成本不是 中小公司可以匹敌的。两者的维度不一样,存在跨维打击的可能

    每人希望看到:今天花了100W得到的模型 视为珍宝,明天就被通用模型超越变成黄花的局面。

    除非,自己领域的数据市面上没有第二家

所以,本质上要看行业数据的情况而定,如果样本足够多,样本足够稳定,才可以考虑微调训练自己的模型。

另外,在关于 微调和 RAG的对比上——

对比维度 模型微调 RAG
核心逻辑 让模型学会新知识或技能,改变其内部参数 为模型提供外部知识,利用其现有能力进行回答
时间成本 长(数据准备、训练、迭代) 短(主要工作是知识库构建)
资金成本 高(训练计算、评估、迭代成本) 低(主要是构建和检索成本)
适用场景 改变模型行为、学习隐性知识(如风格、格式、复杂推理) 查询动态、具体的事实性知识,要求信息溯源
数据需求 需要高质量、大规模的标注数据集,力求覆盖所有场景 按需提供,需要什么知识就准备什么文档
技术门槛 高(需机器学习/深度学习专业知识) 相对较低(更多是工程和数据处理)
迭代与维护 困难(更新知识需重新训练或增量训练) 简单(直接增删改知识库文档即可)
实时性 差,知识固化在模型中,无法感知新信息 好,知识库更新后立即可用
响应速度 生成速度快(推理阶段无需额外检索) 整体响应较慢(需"检索+生成"两个步骤)
可解释性/溯源 差,是"黑盒",无法确认答案来源 好,可以提供引用的原始文档片段
“幻觉"问题 可能基于错误学习产生幻觉 能有效减少幻觉,答案基于提供的事实

=============================================================

最后,推荐一个学习资源——来自极客时间的 课程 <DeepSeek 应用开发实战>。

本文一部分内容,也是参考了这门课程。我自己目前也收益良多。

课程章节感兴趣的朋友,可以免费试看这门课程中任意4个章节内容。

course_outline

geektime_course

Licensed under CC BY-NC-SA 4.0