模型微调

一、模型微调到底是什么

简单来说,模型微调就是让一个已经博学多才的“通才”,通过针对性的“岗前培训”,变成精通某个领域的“专家”

  • 预训练模型(通才大厨):就像一位精通全球菜系的米其林大厨,他掌握了所有的基础知识和烹饪技巧,但未必了解你餐厅的特色。
  • 微调(岗前培训):你想开一家川菜馆,于是让这位大厨用三个月时间,专门学习川菜的食材、调料和烹饪手法。
  • 微调后的模型(川菜大师):最终,他不仅保留了原有的厨艺基础,更能做出一手地道的麻婆豆腐,成为了川菜领域的专家 。

这个过程直接调整模型的“大脑”(参数),让学到的技能内化为模型自身的能力。相比于RAG(它更像是让大厨在做菜时随时翻阅菜谱),微调后的模型在推理时速度更快,且能深度掌握某种特定的风格或知识 。

二、 核心技术:LoRA——四两拨千斤的微调利器

你可能会担心,重新训练一个包含几十亿甚至上千亿参数的大模型,得需要多强大的计算资源?这正是LoRA(低秩自适应) 技术大显身手的地方。

它的核心思想非常巧妙,我们可以继续用“川菜大厨”的比喻来理解

  • 全量微调:相当于让大厨忘掉过去的一些习惯,全身心地重新学习川菜的每一个步骤。效果最好,但成本极高,需要强大的算力支持。
  • LoRA微调:我们不动大厨已经固化的核心“厨艺”(预训练权重),而是给他一个轻量级的“川菜秘方贴纸”(低秩矩阵)。这张贴纸只记录了川菜的关键调整点,比如“多加花椒”、“牛油比例提升”。大厨在做川菜时,只需要在关键步骤上参考这张贴纸即可 。

这样做的好处是巨大的:

  • 显存占用低:可训练的参数通常只有不到1%,让在消费级显卡(如RTX 4090)上微调大模型成为可能。

  • 训练速度快:大幅缩短了训练时间。

  • 模型性能高:在绝大多数任务上,效果可以媲美全量微调。

QLoRA 则是LoRA的进阶版,它先把基础模型“压缩”(量化)到4位精度,再应用LoRA,进一步降低了硬件门槛。

三、 具体如何实现

理解了原理,我们来看看如何上手。

你完全不需要从零开始写复杂的训练代码。这里有两条清晰的路径:

路径一:使用云端服务(最简单、快速上手)

这是最省心的方式,你只需要准备好数据,在云平台上点点鼠标,就能完成微调。例如华为云的ModelArts Studio,流程大致如下 :

  • 准备数据:整理好你的训练集(如客户问答对、特定风格的文本等)。

  • 选择模型:在平台界面选择你想要微调的基础模型,例如盘古大模型。

  • 配置任务:选择“微调”训练类型,并可以灵活选择“全量微调”或“LoRA微调” 。然后设置一些基本参数,如:

    • 学习率:决定模型参数更新的幅度,通常设为很小的值如 2e-5

    • 训练轮数:整个数据集被训练的遍数,通常设为 3 以避免过拟合。

    • 数据批量大小:每次处理的数据量,根据你的资源情况设定。

  • 启动训练:提交任务,等待训练完成。过程中可以观察损失值(Loss) 曲线,它应该呈下降趋势,代表模型在有效学习。

  • 部署使用:训练完成后,平台会自动生成一个微调后的模型版本,你可以像调用普通API一样,通过PHP代码来使用这个专属模型。

路径二:使用本地开源工具(更灵活、适合动手实践)

如果你想在自己的电脑上体验整个过程,Ollama + Python是一个非常棒的组合,它让微调变得异常简单 。步骤如下:

1. 安装Ollama

参考另一篇 Ollama搭建本地

我们选择一个轻量级模型,普通电脑也能流畅运行

ollama pull llama2

2. 准备微调数据

微调的核心是数据。我们将创建一个非常简单的数据集,让模型学习用莎士比亚的风格回答问题。

2.1 创建项目目录 在合适的位置新建一个文件夹:

mkdir ollama-finetune-demo
cd ollama-finetune-demo

2.2 创建Python虚拟环境

# 创建虚拟环境
python -m venv .venv

# 激活虚拟环境
# Windows:
.venv\Scripts\activate
# macOS/Linux:
source .venv/bin/activate

2.3 安装必要的Python库

pip install pandas datasets huggingface_hub

2.4 创建微调数据文件 创建一个名为 data.jsonl 的文件(JSON Lines格式),内容如下

{"prompt": "Write a poem about the sun:", "completion": "Hark! The golden eye of heaven doth rise, to paint the world with hues of paradise."}
{"prompt": "What is love?", "completion": "Love is a smoke raised with the fume of sighs; being purged, a fire sparkling in lovers' eyes."}
{"prompt": "Describe the sea.", "completion": "The vasty deep, a restless field of salt and sorrow, where waves do dance upon the morrow."}
{"prompt": "What is the meaning of life?", "completion": "Life's but a walking shadow, a poor player that struts and frets his hour upon the stage."}
{"prompt": "Write about friendship.", "completion": "A friend is one that knows you as thou art, and yet doth love thee for thy very heart."}
{"prompt": "How to write good code?", "completion": "Hark, good coder! Let thy functions be but small, and name them true, lest confusion fall."}
{"prompt": "What is time?", "completion": "Time is the clock that counts our mortal hours, a thief that steals our youth's most precious flowers."}
{"prompt": "Tell me about AI.", "completion": "Artificial minds, of silicon and light, that learn and think with all their might."}

关键点:这是"指令-回复"对,模型将学习:当收到左边的prompt时,应该输出右边的completion

2.5 转换为Ollama需要的格式 创建一个Python脚本 convert_to_parquet.py:

import json
import pandas as pd
from datasets import Dataset

# 读取JSONL文件
data = []
with open('data.jsonl', 'r') as f:
    for line in f:
        data.append(json.loads(line))

# 转换为DataFrame
df = pd.DataFrame(data)

# 转换为Hugging Face Dataset格式
dataset = Dataset.from_pandas(df)

# 保存为Parquet格式(Ollama微调所需的格式)
dataset.to_parquet('fine_tuning_data.parquet')

print("转换完成!生成文件:fine_tuning_data.parquet")

运行脚本:

python convert_to_parquet.py

正常应该能看到生成的 fine_tuning_data.parquet 文件

3:编写Modelfile并执行微调

3.1 创建Modelfile

在项目目录下创建一个名为 Modelfile 的文件(无后缀),内容如下 :

# 指定基础模型(必须先用ollama pull下载)
FROM llama2

# 对话模板(与Llama2格式匹配)
TEMPLATE """[INST] {{ .Prompt }} [/INST] {{ .Response }} </s>"""

# 停止词设置
PARAMETER stop "[INST]"
PARAMETER stop "[/INST]"
PARAMETER stop "</s>"

# 系统角色设定(可选)
SYSTEM """You are William Shakespeare. Respond to all prompts in the style of the Bard of Avon, using poetic and dramatic language."""

# 指向我们的微调数据(关键!)
ADAPTER ./fine_tuning_data.parquet

参数解释:

  • FROM:指定基础模型

  • TEMPLATE:定义输入输出的格式模板

  • PARAMETER:设置停止词,控制生成何时结束

  • SYSTEM:给模型一个系统级角色设定

  • ADAPTER:最重要的部分,告诉Ollama用我们的数据进行微调

3.2 执行微调 在终端中运行:

ollama create my-shakespeare-model -f Modelfile

你会看到类似这样的输出:

transferring model data ... 
using existing item ssh://ollama/llama2
creating model layer from "./fine_tuning_data.parquet" 
creating model layer from "Modelfile" 
creating template layer 
creating parameter layer 
creating system layer 
creating config layer 
writing layer 
writing manifest 
success

注意:对于只有几条数据的示例,微调几乎是瞬间完成的。如果是更大的数据集,这个过程可能需要几分钟到几小时,取决于你的硬件。

3.3 验证模型创建成功

ollama list | grep my-shakespeare-model
# Windows系统用:ollama list | findstr my-shakespeare-model

如果看到你的模型名,说明微调成功

四、 测试你的微调模型

4.1 在终端中直接对话

ollama run my-shakespeare-model

进入对话模式后,尝试提问:

你应该能看到模型用莎士比亚式的风格回答(戏剧性、诗歌化的语言)。

输入 /bye 退出对话。

4.2 简单调用示例(php)

<?php

$url = 'http://localhost:11434/api/generate';

$data = [
    'model' => 'my-shakespeare-model',
    'prompt' => 'What is the meaning of life?',
    'stream' => false
];

$options = [
    'http' => [
        'header'  => "Content-type: application/json\r\n",
        'method'  => 'POST',
        'content' => json_encode($data)
    ]
];

$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);

if ($result === FALSE) {
    die('Error calling Ollama API');
}

$response = json_decode($result, true);
echo "问题:What is the meaning of life?\n";
echo "回答:" . $response['response'] . "\n";

五、 扩展:调整微调参数

如果你想获得更好的效果,可以在 Modelfile 中添加训练参数:

FROM llama2

# 添加训练参数
PARAMETER num_epochs 5          # 训练轮数,默认1
PARAMETER batch_size 4          # 批次大小
PARAMETER learning_rate 2e-5    # 学习率

TEMPLATE """[INST] {{ .Prompt }} [/INST] {{ .Response }} </s>"""
PARAMETER stop "[INST]"
PARAMETER stop "[/INST]"

SYSTEM """You are William Shakespeare."""

ADAPTER ./fine_tuning_data.parquet

参数说明:

  • num_epochs:数据被训练的遍数,越大模型学习越充分,但可能过拟合

  • learning_rate:学习率,通常 1e-5 到 5e-5 之间

  • batch_size:每次处理的样本数,根据显存调整