AI技术-监督微调SFT
监督微调SFT
监督微调的本质是采用少量的高质量的"指令-回答",针对仅有续写功能的Base模型改造成会对话的小助手。因为模型的知识和能力全部依靠预训练,SFT算法可以激发响应指令分布。所以,这个阶段,提示词的质量远远比数量要重要的多,1000条高质量的精选词条远高于一万条参差不齐的词条所产生的效果好。
核心操作
使用ChatTemplate拼接多轮对话
通过LossMask确保模型只进行学习生成回复功能,不去浪费容量来拟合用户提问的分布
Q&A
Q1:SFT的Loss和预训练有什么区别?为什么要Mask掉Prompt部分?
Loss和预训练的目标函数都是NextTokenPrediction的交叉熵,但是SFT算法仅在Response回复部分计算Loss。
具体实现是将Prompt的TokenLabel设置为-100,因为这样就可以让模型不会自发的学习生成用户问题的分布,仅让模型关注于在给定问题下生成回复。
如果不进行Mask的话,模型就会浪费参数容量来拟合用户输入的分布,导致训练集被稀释,严重的可能会造成角色模糊。
Q2:为什么SFT的学习率要比预训练小1-2个数量级?
一般预训练的数据量都是T级别的,需要很大的学习率来快速学习通用的基本知识。但SFT算法的训练数据量比较小,一般就数万条到数百万条并且分布很窄不宽泛,如果学习率比较高,模型就会迅速拟合到SFT的数据上,并冲淡预训练阶段学习掌握到的通用能力,这就会导致灾难性遗忘。因此,SFT学习率通常要比预训练低1到2个数量级,这样就可以采用温和的调整模型行为。
Q3:为什么SFT有时反而会加重模型的"幻觉"?
产生这个问题的主要原因是,如果SFT数据中存在模型在预训练阶段没有接触过的知识,这就相当于告诉模型要在不知道的时候也要给出一个回答,但这个回答肯定是一本正经的胡说八道。因此,SFT的数据尽量落在模型已存在的知识边界内。对于超出边界的问题,SFT数据应该告知模型回答"我不知道",而不是强行胡编乱造答案,否则就会加重幻觉。
SFT算法代码/公式示例
import torch import torch.nn as nn # 假设 input_ids 已通过 Chat Template 拼接完成 labels = input_ids.clone() # 核心:将 prompt (system + user) 部分的 label 设为 -100 prompt_length = len(prompt_tokens) labels[:prompt_length] = -100 # 注意:EOS token 必须保留计算 loss,否则模型学不会停止生成 loss_fct = nn.CrossEntropyLoss(ignore_index=-100) loss = loss_fct(logits.view(-1, vocab_size), labels.view(-1))文章转载自:
AI技术-监督微调SFThttps://mp.weixin.qq.com/s/Mm0Yl2PEKnIp4Wd5Ykc8Yg
