
我们一起聊聊大模型 SFT 有监督微调教程
开源地址:https://github.com/JieShenAI/csdn/tree/main/25/02/SFT
train.ipynb
:模型有监督微调的代码infer.ipynb
: 模型训练完成后,进行推理的代码\
预训练与有监督微调对比
两者的训练数据,大部分都一模一样,维度在 label 部分,SFT 需要把指令部分的 label 设置为-100。
自定义数据集
因为 tokenizer 对文本进行encode的时候,并不是一个词一个token,会出现多个词对应一个token的情况。为了确定指令部分的token长度,单独对指令部分的文本计算一次的encode。然后使用切片 label[:, :instruct_len] = -100
把指令部分的 label 设置为 -100 不计算 loss。
查看第一个数据:
输出:
输出:
输出:
DataCollatorForSFTDataset
下面是使用 pad_sequence
对 tensor 进行填充的一个示例。batch 放在第一个维度,用 0 进行填充,在右边进行填充。
输出:
使用 pad_sequence
在 DataCollatorForSFTDataset中,对 tensor 进行拼接与填充。
注意: 在返回的字典中,要用 labels
而不是 label
。
验证一下,DataCollatorForSFTDataset
的效果:
模型训练
processing_class
是新参数名,使用旧参数名也可以:
查看模型训练的结果:
保存训练完成的模型:
模型推理
看一下模型有监督微调的效果。对比一下,预训练与有监督微调,模型在进行推理的时候的区别:
- 预训练的模型,对于输入的文本都可以继续续写出原文;
- 有监督微调,只能根据指令写出对应的答案;无法根据指令的前半部分,写出指令的后半部分:
instruct + label 作为指令部分,label 是指令的答案。若SFT微调后的大模型,输入 instruct + label 能得到 label,说明模型微调有效。当给SFT微调后的大模型输入instruct,模型应该输出label中的文本,但不能输出input的文本,就能说明label设置为-100,没有计算指令部分loss。
部分输出结果:
模型能够根据指令,完成诗歌下半部分的写作。
部分输出:
大模型只能输出 label中的文本,模型不能输出 input中的诗歌: 哪吒降世,意气飞扬。逆天改命,破障冲霄。
这说明模型没有学到用户指令部分的文本,这符合我们的预期。
本文转载自AI悠闲区,作者:AI悠闲区
