ChatGPT是“大力出奇迹”的经典表现,大模型给ChatGPT带来了惊人的智能,但是要训练这样的大模型,可是十分烧钱的,根据OpenAI给出的数据,1700亿参数的Davinci模型从头训练一遍,大概需要耗时3个月,耗资150万美元。那我们普通人或者小公司面对这个高门槛,对自定义模型是不是就完全没有希望了呢?其实除了从头训练一个模型,我们还可以选择基于一个基础模型进行训练,这样,我们可以往里添加自己的个性化数据,最终得到一个领域增强的个性化模型,这个技术被OpenAI称为Fine-tuning。
个性化模型有什么用?我们知道,OpenAI给的模型(如Davinci、Curie、gpt-3.5-turbo)都是通用化模型,而现代社会的行业和知识如此之庞大,每个领域都有自己细分的专业知识,比如,我们知道ChatGPT的一个典型应用场景就是智能客服,但同样是客服,保险领域的客服和淘宝店铺的客服需要面对的客户和需要解答的问题就完全不一样,想要给出更好的答案,我们就需要打磨自己的个性化模型。
OpenAI的Fine-tuning技术基于预训练模型,通过在小规模任务上对该模型进行微调来快速适应具体的任务。其核心原理是将预训练模型的权重进行微调,以适应新任务的输入和输出。
Fine-tuning一般包括以下步骤:
Fine-tuning的优点在于它可以让我们快速获得针对特定任务的高质量模型,而无需从头开始训练模型。同时,由于Fine-tuning仅更新了部分权重,并且大多数权重已经在预训练阶段得到了很好的优化,因此Fine-tuning相对于从头开始训练模型而言,需要的训练时间和计算资源都要少得多。
这里,我想到了一个点子,知识星球的粉丝群问答不就是最好的例子么,一问一答,刚刚好对应上,比如齐俊杰的投资理财粉丝群,如果把最近一个月的问答数据作为训练数据,看看结果如何,可能会是个比较有意思的事情。
我们需要将需要训练的数据准备为jsonl格式,这种格式的特点就是每一行都是json的格式(关于什么是json,参考这里)如下
{"prompt": "", "completion": ""}
{"prompt": "", "completion": ""}
比如,我的训练数据为dataset.jsonl
,里面的问答大概有2500行,对于fine-tuning来说,数据量不能太少,少于100条数据的话,训练出来的模型质量应该好不了:
{"prompt": "医药和消费有什么基金推荐的", "completion": "医药可以看看工银前沿的赵蓓,她挺均衡的,对于这个行业我了解不多,你还可以看看医药100指数,消费挺多的,消费50也挺好。"}
{"prompt": "请教一下老师,恒生科技第一大持仓股是快手。而快手是亏损最大的互联网企业。似乎齐老师也说过不看好快手,会不会影响恒生科技持仓。", "completion": "如果你要是能选股,确实不应该买指数。从指数选择的角度来说。中概互联我们更看好一些。但他跟恒生科技的相关度其实很高"}
{"prompt": "想问一下国投瑞银这边基金公司和綦缚鹏的风格实力怎么样", "completion": "他风格不是很固定。最近在偏向周期。(个人观点,不作为投资建议)"}
其中,prompt是问题,completion是答案。
我们都知道,在机器学习领域,Python语言是主力(参考这里),在OpenAI也不例外,我们需要先安装Python语言环境,安装这一步省略不讲了。安装完毕后,需要使用python自带的pip
工具安装OpenAI提供的训练工具
pip install --upgrade openai
同时,因为需要跟OpenAI的平台进行交互,所以,我们需要OPENAI_API_KEY,这个是需要注册的,且要收费
export OPENAI_API_KEY=""
openai tools fine_tunes.prepare_data -f dataset.jsonl
该指令会帮我们优化训练数据,该指令运行过程中会问我们几个问题,主要是给prompt添加了固定的后缀,比如”->”,给completion添加了开头的空格和结尾的换行符,如下
{"prompt":"医药和消费有什么基金推荐的 ->","completion":" 医药可以看看工银前沿的赵蓓,她挺均衡的,对于这个行业我了解不多,你还可以看看医药100指数,消费挺多的,消费50也挺好。\n"}
{"prompt":"请教一下老师,恒生科技第一大持仓股是快手。而快手是亏损最大的互联网企业。似乎齐老师也说过不看好快手,会不会影响恒生科技持仓。 ->","completion":" 如果你要是能选股,确实不应该买指数。从指数选择的角度来说。中概互联我们更看好一些。但他跟恒生科技的相关度其实很高\n"}
{"prompt":"想问一下国投瑞银这边基金公司和綦缚鹏的风格实力怎么样 ->","completion":" 他风格不是很固定。最近在偏向周期。(个人观点,不作为投资建议)\n"}
准备好的数据文件是dataset_prepared.jsonl
。
我们准备好数据后,就要提交到OpenAI的平台上进行训练了,此时需要提供数据文件dataset_prepared.jsonl和模型,目前OpenAI支持的BASE_MODEL有4个(参考这里),是Davinci、Curie、Ada、Babbage,从左到有,价格分别是从贵到便宜,性能是从好到一般。如果想知道每个模型的效果,可以同时基于2个BASE_MODEL进行训练,最后比较效果。这次考虑到训练成本,先用Curie作为BASE_MODEL训练。
openai api fine_tunes.create -t dataset_prepared.jsonl -m curie
耗时大概30分钟以上。训练的进度可以通过下面这个命令获取,ft-SSIJ4DsHFfp9LEtuHWyQcn5B这个是fine-tuning的job ID,是上面create命令会给出的。
openai api fine_tunes.follow -i ft-SSIJ4DsHFfp9LEtuHWyQcn5B
这里有个小技巧,如果训练数据集较大,不用每次提交训练任务都要把数据重新上传一遍,可以直接使用之前已经上传的数据,使用方法如下
openai api fine_tunes.create -t file-WSkHmtSfBLORMAhEoEVyBDO4 -m curie
这个file-WSkHmtSfBLORMAhEoEVyBDO4
是之前上传完文件后通过下面的命令得到的
(.venv) ➜ openai api files.list
{
"data": [
{
"bytes": 620175,
"created_at": 1680619086,
"filename": "dataset_prepared.jsonl",
"id": "file-WSkHmtSfBLORMAhEoEVyBDO4",
"object": "file",
"purpose": "fine-tune",
"status": "processed",
"status_details": null
},
],
"object": "list"
}
查看fine-tuning任务的详细信息
(.venv) ➜ openai api fine_tunes.list
{
"data": [
{
"created_at": 1680619087,
"fine_tuned_model": "curie:ft-personal-2023-04-04-15-28-34",
"hyperparams": {
"batch_size": 2,
"learning_rate_multiplier": 0.1,
"n_epochs": 4,
"prompt_loss_weight": 0.01
},
"id": "ft-SSIJ4DsHFfp9LEtuHWyQcn5B",
"model": "curie",
"object": "fine-tune",
"organization_id": "org-WTfVkVyUtqWdmv711ZZWHw7T",
"result_files": [
{
"bytes": 225243,
"created_at": 1680622115,
"filename": "compiled_results.csv",
"id": "file-RfmMXqxf94DhsxLN2jfATCTW",
"object": "file",
"purpose": "fine-tune-results",
"status": "processed",
"status_details": null
}
],
"status": "succeeded",
"training_files": [
{
"bytes": 620175,
"created_at": 1680619086,
"filename": "dataset_prepared.jsonl",
"id": "file-WSkHmtSfBLORMAhEoEVyBDO4",
"object": "file",
"purpose": "fine-tune",
"status": "processed",
"status_details": null
}
],
"updated_at": 1680622115,
"validation_files": []
},
],
"object": "list"
}
(.venv) ➜ openai api fine_tunes.follow -i ft-SSIJ4DsHFfp9LEtuHWyQcn5B
[2023-04-04 22:38:07] Created fine-tune: ft-SSIJ4DsHFfp9LEtuHWyQcn5B
[2023-04-04 22:46:52] Fine-tune costs $4.89
[2023-04-04 22:46:53] Fine-tune enqueued. Queue number: 5
[2023-04-04 22:47:38] Fine-tune is in the queue. Queue number: 4
[2023-04-04 22:50:08] Fine-tune is in the queue. Queue number: 3
[2023-04-04 22:50:15] Fine-tune is in the queue. Queue number: 2
[2023-04-04 22:54:51] Fine-tune is in the queue. Queue number: 1
[2023-04-04 22:57:26] Fine-tune is in the queue. Queue number: 0
[2023-04-04 22:57:50] Fine-tune started
[2023-04-04 23:06:11] Completed epoch 1/4
[2023-04-04 23:20:51] Completed epoch 3/4
[2023-04-04 23:28:34] Uploaded model: curie:ft-personal-2023-04-04-15-28-34
[2023-04-04 23:28:35] Uploaded result file: file-RfmMXqxf94DhsxLN2jfATCTW
[2023-04-04 23:28:35] Fine-tune succeeded
Job complete! Status: succeeded
Try out your fine-tuned model:
openai api completions.create -m curie:ft-personal-2023-04-04-15-28-34 -p
模型训练完毕,得到的自定义模型是”curie:ft-personal-2023-04-04-15-28-34”, 排队花了20分钟,训练花了30分钟,耗费资金大概4.89美元,2500条数据,还是不便宜的。
下面我们用新模型进行提问
(.venv) ➜ openai api completions.create -m "curie:ft-personal-2023-04-04-15-28-34" -p "医药和消费有什么基金推荐的 ->"
》医药和消费有什么基金推荐的 -> 消费和医药比%
可惜,给出的答案比较差,我们查看训练的结果数据,我们训练的最终目的是希望损失函数的结果最小,即training_loss值最小,且使得training_sequence_accuracy和training_token_accuracy值最大,但从下面的数据看,training_loss最小才0.06372293254171614,training_sequence_accuracy为0.5,training_token_accuracy最高也才0.9166666666666666,且表现得很不稳定,从这也就印证了为什么问答的效果并不好。
(.venv) ➜ openai api fine_tunes.results -i "ft-SSIJ4DsHFfp9LEtuHWyQcn5B"
step,elapsed_tokens,elapsed_examples,training_loss,training_sequence_accuracy,training_token_accuracy
1,482,2,0.45391547040630686,0.0,0.5755395683453237
2,980,4,0.6011948533307662,0.0,0.6086956521739131
3,1334,6,0.5914613516018767,0.0,0.528
4,1640,8,0.41827734171512065,0.0,0.5526315789473685
5,2618,10,0.5738252286081992,0.0,0.6934673366834171
6,3148,12,0.32921856693228024,0.0,0.639344262295082
7,3550,14,0.5036230062589969,0.0,0.5983606557377049
3855,2231118,7710,0.06739243882282422,0.0,0.9139784946236559
......
......
省略了中间的几千行内容
......
......
3856,2231616,7712,0.16957119258711775,0.0,0.8467153284671532
3857,2232082,7714,0.2004900809357239,0.5,0.808
3858,2232276,7716,0.08515305384741474,0.0,0.8518518518518519
3859,2232678,7718,0.19010555123939107,0.0,0.8529411764705882
3860,2233608,7720,0.057206735256356465,0.0,0.8762886597938144
3861,2234074,7722,0.2355557036819172,0.0,0.7916666666666666
3862,2234396,7724,0.14572308102632223,0.0,0.905511811023622
3863,2235182,7726,0.13363321007470183,0.0,0.8378378378378378
3864,2235488,7728,0.09592527983439035,0.5,0.9166666666666666
3865,2236002,7730,0.06372293254171614,0.0,0.8909090909090909
那好,下一步就是要定位到具体的问题,然后进行调优,这个就要放到下一篇文章再讲了。
在这篇文章里讲述了模型微调fine-tuning的基本概念和原理,还有利用OpenAI的工具训练自有模型的快捷方法。整体来说,快速入门还是比较简单的,要把模型调好还是要花不少时间和资金成本的,上面的演示的curie还不是最贵的基础模型,最贵的是davinci模型,还要贵10倍。