🔗 Source link: mp.weixin.qq.com/s?__biz=Mj.…
原创 鹤啸九天 鹤啸九天 2023-08-29 22:42 发表于 北京
引言
GPT 3.5-4一个模型对接所有业务,难免力不从心,如何定制自己的 ChatGPT / GPT-4 ?
(1)GPT 3.5 微调API发布
8月22日,OpenAI宣布用户可以对ChatGPT(GPT-3.5 Turbo)微调,特定任务上,定制模型可以趋近甚至超过GPT-4。
初版 GPT-3 基础模型(ada、babbage、curie 和 davinci)微调 2024 年 1 月 4 日正式关闭。 babbage-002 和 davinci-002 作为替代方案,用户可将其用作基础模型或微调模型。
同时,秋季将开放GPT-4的微调。
用户终于可以用上自己的专属ChatGPT了。
什么是微调?
微调英文名 finetune,属于NLP里术语,对应NLP的第三、四范式时代
NLP四大范式
-
第一范式: **非神经网络时代的完全监督学习 **( 特征工程 )。需要大量任务相关的训练数据,通过特征工程和算法,代表算法是朴素贝叶斯Naïve Bayes、支持向量机SVM、逻辑回归LR等;
-
第二范式: **基于神经网络的完全监督学习 **( 架构工程 )。也需要大量任务相关的训练数据,通过深度学习方法,自动获取特征(表示学习)进行端到端分类学习;
-
第三范式: **预训练,精调范式 **( 目标工程 ):当前使用比较多的 预训练+微调范式 ,通过预训练的方式(比如掩码语言模型Masked Language Model)来学习海量的语言学知识,然后下游使用少量的任务相关的数据对预训练模型进行微调即可完成相关任务;
-
第四范式: **预训练,提示,预测范式 **( Prompt工程 ):当前进入了Prompt Learning提示学习的新范式,使用Few-shot或者Zero-shot即可完成下游任务。
微调
(Fine-tuning)通过训练超出提示范围的更多示例来改进 小样本学习 ,在大量任务上取得更好的结果。模型经过微调后,不再需要在提示中提供示例,进而节省成本并实现更低延迟的请求。
微调可让更好地利用 API 提供的模型:
- 比设计提示(prompt)质量更高的结果
- 能够训练更多不适合提示的示例
- 由于提示较短而节省 token
- 更低的延迟请求
微调涉基本步骤:
- 准备并上传训练数据
- 训练一个新微调模型
- 使用微调模型
GPT-3.5 微调有什么用
开发者通过监督微调实现 个性化定制 ,适配各自业务场景,显著提高模型性能
-
① **更加可控 **:更好的遵循指令,如 精简回复、以特定语言风格。(不必再在prompt中强调用某种语言)
-
② **输出格式更可靠 **:微调提升了模型回复的一致性,适用于要求特定格式输出的情形(代码补全/组合API调用/json输出)
-
③ **角色更稳定 **:微调让模型输出更加贴合某种角色,如 企业品牌代言人
除了性能提升,微调还能缩短 prompt 长度,同时保持效果。
GPT-3.5-Turbo 微调版能处理 4k tokens(之前GPT-3微调模型的两倍). 早期测试发现: 通过监督指令微调,prompt长度最多缩减 90%,api调用加速,成本削减 。
GPT 的“微调”与 Llama2 之类 的微调不同, 不会调整网络的 所有权重 ,只是 会调整网络 小部分 。 代价是 OpenAI 微调的成本较低,但功能也没有“真正的”微调强大。
(2)微调实践
微调步骤
官方介绍,微调基本流程分4步
- ① Prepare your data **准备语料 **:用户按要求准备语料格式
- ② Upload files **上传文件 **:通过api上传语料到OpenAI服务器( 需要key ),完成后找到对应的文件id
- ③ Create a fine-tuning job **启动微调任务 **:启动微调任务,需要用户指定模型(一般是gpt-3.5-turbo-0613)、文件名(服务端名称, 非原始文件名 ),训练完成后会邮件通知 模型名 。
- ④ Use a fine-tuned model **使用微调模型 **:切换 新模型名 ,正常调用即可
精简图解如下:
官方shell命令
未来会提供UI交互方式,持续提升用户体验。
Python版本
对于程序员,当然更习惯代码调用,Python版本如下:
① 数据处理
将jsonl格式(每行都是json串的文本文件)的数据(question, answer两个字段)转换为OpenAI要求的格式
# 数据处理
import json
import random
def transform_jsonl(input_file_path, output_file_path):
entries = []
with open(input_file_path, 'r') as file:
for line in file:
entry = json.loads(line)
entries.append(entry)
# 随机抽取100个条目
#sampled_entries = random.sample(entries, 100)
sampled_entries = random.sample(entries, 10) # 至少10条数据
with open(output_file_path, 'w') as outfile:
for entry in sampled_entries:
messages = []
messages.append({"role": "system", "content": "You are an assistant"})
user_message = {"role": "user", "content": entry["questions"]}
assistant_message = {"role": "assistant", "content": entry["answers"]}
messages.extend([user_message, assistant_message])
result = {"messages": messages}
json.dump(result, outfile, ensure_ascii=False)
outfile.write('n')
input_file_path = '~/test_datasets.jsonl' # 请替换为您的输入JSONL文件路径
output_file_path = '~/tmp.jsonl' # 请替换为您想要保存的输出JSONL文件路径
transform_jsonl(input_file_path, output_file_path)
数据示例:
输入: {"questions": "做了腰间盘穿丁手术后,用盐泡脚可以吗", "answers": "问题分析:你好:你是由于身体出现了一些局部的腰部损伤这种情况应该进行调整的一般术后泡脚是可以的,不用担心。意见建议:治疗方案:你可以不知后注意休息,避免劳累过度就可以这种调整方法也可以住进你身体的一些嗯调理的啊!"}
输出: {"messages": [{"role": "system", "content": "You are an assistant that occasionally misspells words"}, {"role": "user", "content": "由于一次事故造成了左耳的残疾听力不是很好需要佩戴助听器戴上的效果还不错能和人正常交流但是最近一个月助听器里面总是有杂音影响了使用效果。耳聋佩戴的助听器有杂音怎么办?()"}, {"role": "assistant", "content": "你好您所谓的杂音也有可能是听到的环境声音好的助听器对噪音是有压缩的出现这种情况是可以调试解决的如果是一般的助听器因为环境声音也同时放大了可能会觉得比较吵您的问题最好是到助听器店让专业的验配师帮您处理"}]}
② 上传文件
# 上传至OpenAI
import requests
import openai
OPENAI_API_KEY='***'
url = "https://api.openai.com/v1/files"
headers = {
"Authorization": f"Bearer {OPENAI_API_KEY}"
}
payload = {
"purpose": "fine-tune",
}
print('数据路径: ', output_file_path)
files = {
"file": open(output_file_path, "rb")
}
response = requests.post(url, headers=headers, data=payload, files=files)
print(response)
print('上传的文件信息: ', openai.File.list())
执行完毕后返回 文件列表
上传的文件信息: {
"object": "list",
"data": [
{
"object": "file",
"id": "file-***",
"purpose": "fine-tune",
"filename": "tmp.jsonl",
"bytes": 5769,
"created_at": 1693304216,
"status": "uploaded",
"status_details": null
},
{
"object": "file",
"id": "file-****",
"purpose": "fine-tune",
"filename": "tmp.jsonl",
"bytes": 1496,
"created_at": 1693303804,
"status": "processed",
"status_details": null
}
]
}
从中找到 本次上传文件 位置,如下标0, 或1
③ 启动微调任务
模型选择
# 启动微调
import requests
OPENAI_API_KEY="sk-***"
url = "https://api.openai.com/v1/fine_tuning/jobs"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {OPENAI_API_KEY}"
}
data = {
#"training_file": "file-XXXXXXXXXXX",
"training_file": openai.File.list()['data'][1]['id'],
"model": "gpt-3.5-turbo-0613"
}
response = requests.post(url, headers=headers, json=data)
print(response.text)
终端返回
{"object":"fine_tuning.job","id":"ftjob-***","model":"gpt-3.5-turbo-0613","created_at":1693304550,"finished_at":null,"fine_tuned_model":null,"organization_id":"org-LMrR8ZVsnE2MLQNXje4rARHo","result_files":[],"status":"created","validation_file":null,"training_file":"file-bPzn6eE00cvR3xNqb8lau6QN","hyperparameters":{"n_epochs":10},"trained_tokens":null}
稍等片刻后,查看个人邮箱,记录新模型名
④ 使用微调模型
看下新模型效果
# 调用模型
import requests
url = "https://api.openai.com/v1/chat/completions"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {OPENAI_API_KEY}"
}
# 从邮件里提取模型名称
new_model = 'ft:gpt-3.5-turbo-0613:***'
data = {
"model": new_model,
"messages": [
{
"role": "system",
"content": "You are an assistant"
},
{
"role": "user",
"content": "我在体检是正常的,但是去献血医生最是说我的血压高,不能献。血压是130、80这是为什么呢?"
}
]
}
response = requests.post(url, headers=headers, json=data)
print(response.text)
返回结果
{
"id": "chatcmpl-****",
"object": "chat.completion",
"created": 1693305795,
"model": "ft:gpt-3.5-turbo-0613:***",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "可能的原因如下: 1、在献血时会有一些紧张,紧张会使血压升高。有的人可能并不是很紧张,但献血起码是一个小手术。 2、在献血之前会对献血者进行初检,其中就包括血压测量。如果血压较高,就不准献血。 3、在献血后有可能会感到血压低,因为抽取的是血浆,造成血容量减低,心排血量减少,以后体中的血压降落。 4、如果一直测得较高,就是高血压,应引诱病院。"
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 73,
"completion_tokens": 219,
"total_tokens": 292
}
}
简单微调过后不用写prompt也能让gpt-3.5-turbo-0613有更加专业的回复
(3)价值分析
问题
上传的数据会被滥用吗 ?
- 官方:传入传出微调API的所有数据归客户所有,任何组织(包括OpenAI)都不能用来训练模型
微调花钱多吗
微调成本分为两个部分:初始 **训练 **成本与 **使用 **成本:
-
训练:0.008 美元/1K tokens
-
使用成本
比如,gpt-3.5-turbo 微调作业中包含 10 万个 token 的训练文件。经过 3 个 epoch 训练轮次,预计成本为 2.40 美元。
这次微调实践花费
-
**10条 **数据(289个汉字, **5769 **个字节),花费 0.16 刀; 按照 0.008 单价算,大概训练了3轮
-
微调一次果然费用陡增。
各模型费用对比总结如下:
Model | Base Models-Input | Base Models-Output | Fine-tuned Models-Training | Fine-tuned Models-Input | Fine-tuned Models-Output |
---|---|---|---|---|---|
babbage-002 | 0.0004 | 0.0004 | 0.0004 | 0.0016 | 0.0016 |
davinci-002 | 0.002 | 0.002 | 0.006 | 0.012 | 0.012 |
gpt-3.5-turbo-4k | 0.0015 | 0.002 | 0.008 | 0.012 | 0.016 |
gpt-3.5-turbo-16k | 0.003 | 0.004 | 秋季发布 | – | – |
gpt-4-8k | 0.03 | 0.06 | 秋季发布 | – | – |
gpt-4-32k | 0.06 | 0.12 | 秋季发布 | – | – |
注
-
单位 $/1k tokens
-
官方收费指南
什么时候用微调?
-
微调的 GPT 3.5 Turbo 生成成本是基本模型生成成本的 **8 倍 **,因此最好处于 OpenAI 提到的“将提示大小减少 90%”的范围内,才能从中获得成本效益。
-
另外,这只是部分参数微调,非全参数,如果有更多领域数据,更灵活的需求,建议使用开源模型(详见 ChatGPT复现: 三步走+大模型进化图谱 )
(4)附录
参考:
- OpenAI官方资讯:openai.com/blog/gpt-3-…
- openai 3.5微调实战:github.com/LearnPrompt…