SFT对大语言模型的作用

15 阅读8分钟

1. SFT的作用

如果没有 SFT(监督微调),你面对的不是一个“助手”,而是一个“复读机”或者“复印机”。 举个例子,假如你给一个仅经过预训练(Base Model)的模型发指令:

你的输入: “请帮我写一首关于红豆的诗。”

❌ 没有 SFT 的模型可能会这样回答:

  • 情况 A(自动续写): “请帮我写一首关于绿豆的诗。请帮我写一首关于黄豆的诗。” (因为它觉得你在玩排比句,它在模仿你的文本模式继续往下排。)

  • 情况 B(补全考卷):“答:红豆生南国,春来发几枝。愿君多采撷,此物最相思。二、填空题:本诗的作者是____。” (它在互联网上看过太多试卷,以为你是在做考题,于是自动补全了后面的填空。)

  • 情况 C(胡言乱语): “红豆的价格在 2023 年波动较大,主要产区位于黑龙江……” (它只是在根据‘红豆’这个关键词提取它脑子里的统计概率知识,完全不理会‘写诗’这个指令。)

✅ 经过 SFT 后的模型会这样回答:

“红豆生南国,春来发几枝……”(或者是它原创的一首诗)。

  • Base Model(无 SFT): 它的逻辑是“根据你给的上文,后面最可能出现的词是什么?”。如果你给它一个问题,它可能觉得后面应该出现另一个问题。
  • SFT Model: 它的逻辑是“用户给了我一个指令,我应该按照‘问答模式’给出答案”。

2. SFT训练

2.1 SFT 训练的本质是什么?

SFT 的本质是 “分布偏移”。将模型从“海量知识的概率模拟”转换为“特定交互模式的指令遵循”。

  • 预训练阶段,模型学习的是“整个互联网的概率分布”(包括废话、错话、排比句)。

  • SFT 阶段,模型被强制限定在“高质量回复的分布”里。

1. 概率分布的“强行纠偏”

a. 预训练本质:学习“世界的语言模型

学习互联网上所有文本的概率分布。在互联网上,指令后面往往跟着的是更多的讨论、重复的问题或广告。

在海量无标注数据上进行的预训练,其目标是让模型学习并模拟互联网文本的整体概率分布。这时,模型学会的是“如何让一段文本看起来合理、合乎语法和常识”,但其行为模式是无目的的续写。例如,给定提示“请解释一下人工智能”,模型可能会续写成“请解释一下人工智能是否会在未来取代人类工作?”因为它学习到的分布是“解释人工智能”后面经常跟着讨论其影响

b. SFT 本质:塑造“助手的语言模型

通过人类提供的“正确示范”,强行改变模型预测下一个词的概率。它告诉模型:当出现“指令”这种特定的模式时,后续文本的概率分布必须坍缩到“答案”上。

SFT则使用高质量的“指令-回答”对数据,将模型的语言生成分布强行修正并聚焦到一个特定且有用的子集上——即“高质量助手的回答分布”。它通过一个简单的机制实现:在训练时,只计算模型输出的“回答”部分与标准答案之间的损失,而忽略“指令”部分的损失(称为Loss Masking)。这相当于不断告诉模型:“当看到这种指令模式时,你后续文本的概率分布必须无限逼近我们提供的高质量答案。”

2. 从“续写”到“对齐”

• 续写(Completion): 只要逻辑自洽,后面写什么都行。

• 对齐(Alignment): 必须符合人类的意图。

SFT 的本质是建立一种契约:让模型理解“对话”这种特定场景的逻辑规则。它并不产生新知识,而是激活模型在预训练阶段已经学到、但不知道如何按需输出的知识。

a. 激活而非注入知识

模型在训练过程中,本质上不是在背诵具体的问答对,而是在学习“如何理解指令”。

SFT的核心目标不是向模型注入新的世界知识(这些知识主要在预训练阶段获得),而是教会模型如何根据指令,调动和组织其已有的知识,并以人类期望的格式进行输出。这就像一个博学的学者,预训练让他掌握了知识,而SFT则教会他如何成为一名优秀的讲师,能清晰、有条理地回应学生的问题。

b. 格式化与指令遵循

即使你问了一个 SFT 数据集中没有的问题,因为模型在 SFT 过程中已经理解了“理解意图 -> 提取知识 -> 组织语言”的这种工作流程,它也能照葫芦画瓢给出像样的回复。

为了实现这一点,SFT数据会被处理成特定的对话格式,包含如 <|im_start|>user、<|im_end|>等特殊标记。这些标记作为“场景信号”,帮助模型识别对话的轮次、角色和边界,从而学习到“对话”这一特定任务的交互规则和输出格式。

2.2 SFT训练流程

SFT 的训练过程就是“命题作文”+“标准答案”。它的核心流程分为以下三步:

1. 准备“人类精选”数据集

这是最关键的一步。开发者会找成百上千个专业的标注员(人类),编写数万条高质量的“指令-回复”对。

  • 指令 (Prompt): “请帮我写一段 Python 排序代码。”
  • 答案 (Response): def quick_sort(arr): ...(这是由专家写出的、完美的、符合格式要求的回答)。

这些数据涵盖了各种场景:翻译、创意写作、代码编写、逻辑推理等。

2. 初始化模型

我们会把那个“博学但混沌”的预训练模型 (Base Model) 搬过来。它虽然懂很多词汇,但现在我们要把它全身的“经脉”按照上面的标准答案重新梳理。

3. 有监督的学习(训练过程)

把第一步准备好的数据集喂给模型,模型会开始玩一个“猜字游戏”,但这次有标准答案在旁边盯着:

  1. 输入指令: 把“请帮我写一段 Python 代码”喂给模型。
  2. 模型预测: 模型可能会吐出“Python 是一门...”
  3. 计算误差 (Loss): 训练算法会对比:模型吐出的内容与人类给的标准答案差了多少。
  4. 调整权重 (Backpropagation): 如果模型猜错了,算法就通过“反向传播”微调模型内部的参数,告诉它:“下次不许这么写,要往标准答案那个方向靠!”。如果模型猜对了,就加强这个连接。

3. 训练数据集格式

3.1 提示-完成格式 (Prompt-Completion)

这是最基础的格式,适用于输入是单段文本、输出是其延续或转换的任务。

{"prompt": "翻译成法语: 'Hello, world!'", "completion": "Bonjour le monde!"}
{"prompt": "总结以下文本: [长文本输入]...", "completion": "[简洁摘要]..."}

训练期间,prompt 和 completion 通常会被连接起来,有时会带有一个分隔符标记,模型学习预测属于 completion 的标记。

3.2 指令微调格式 (Instruction Format)

为了明确训练模型遵循指令,数据集通常会进一步细分输入,将指令本身与它应操作的任何特定输入数据分开。这有助于模型更好地泛化到新指令。

{"instruction": "识别主要情感。", "input": "这部电影太棒了!", "output": "积极"}
{"instruction": "写一个关于勇敢骑士的短篇故事。", "input": "", "output": "吉迪恩爵士调整了头盔,山谷中回荡着巨龙的咆哮声……"}
{"instruction": "提取电子邮件地址。", "input": "请通过 info@example.com 或 support@example.org 联系我们。", "output": "info@example.com, support@example.org"}

• instruction: 具体的任务描述。

• input: 任务的可选补充背景信息(若不需要可为空字符串)。

• output: 期望模型生成的标准答案。

为模型准备这些数据时,这些字段通常使用预定义模板组合成单个提示字符串。例如:

以下是描述任务的指令,以及提供更多背景信息的输入。请编写一个适当的回复来完成请求。

### 指令:
{instruction}

### 输入:
{input}

### 回复:
{output}

模型随后被训练生成### 回复:后面的文本。具体模板结构可以不同,但数据集内部的一致性很重要。

3.3 对话格式 (Chat/ShareGPT Format)

用于训练聊天模型或助手时,数据需要表示多轮对话。这通常被结构为回合列表,每个回合都有指定角色(例如,user、assistant、system)。

{"messages": [
  {"role": "system", "content": "你是一个乐于助人的助手。"},
  {"role": "user", "content": "法国的首都是哪里?"},
  {"role": "assistant", "content": "法国的首都是巴黎。"}
]}
{"messages": [
  {"role": "user", "content": "编写一个计算阶乘的 Python 函数。"},
  {"role": "assistant", "content": "```python\ndef factorial(n):\n  if n == 0:\n    return 1\n  else:\n    return n * factorial(n-1)\n```"}
]}

为 SFT 处理这种格式需要将对话历史序列化为单个线性序列。这通常需要特殊标记来划分回合和角色。例如,模型可能期望格式化的输入,例如:<|im_start|>system\nYou are...<|im_end|>\n<|im_start|>user\nWhat is...?<|im_end|>\n<|im_start|>assistant\nThe capital is...<|im_end|>. 模型随后被训练只预测对应assistant消息的标记。