如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?

如何实现OpenAI fine-tuning(微调)训练属于自己的专有模型?
收藏者
0
被浏览
159

5 个回答

hai-er LV

发表于 2025-4-8 14:49:09

Fine-tuning理论上很复杂,但是OpenAI把这个功能完善到任何一个人看了就能做出来的程度。
我们先从原理入手,你看这张图,左边是Pre-trained LLM (预训练大模型模型),也就是像ChatGPT这样的模型;右边是Fine-tuned LLM (微调过的语言大模型),中间就是进行微调的过程,它需要我们提供一些「ChatGPT提供不了但是我们需要的东西」。
比如说我们这个回答就是想微调一个『使用中国道家思想和语录进行回答的聊天机器人』

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-1.jpg

这个很好理解,打个比方,你想让ChatGPT输出跟道家高人一样,每句话都希望它能从「周易」「道德经」这样的著作中引经据典。
GPT是做不到的,因为它训练的预料大多数是通用知识,而周易或者道德经这种属于是特定领域的知识,以后不排除它会拿左右的资料进行训练,但是现在的GPT确实做不到。
这个时候就出现了两种解决办法,一种是这个题目问的「Fine-tune微调」,另一种是通过「Prompt engineering特征工程」。
下面和这个图很清楚的说明了这两者的不同,“扳手”指的地方是变化的地方,特征工程只是改变输入,也就是给输入中增加更多的内容,而LLM大模型本身是不变的;而Fine-tune微调它改变的就是LLM本身。

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-2.jpg

微调不是万能的。根据OpenAI的官方介绍,微调适用于以下五种情况:

  • 调整写作风格、语气、格式等
  • 提高生成正确结果的稳定性
  • 修正模型在复杂提示下的表现
  • 处理一些特殊的、意外的情况
  • 学习和执行在提示中无法明确说明的新技能或任务
如果你确定你的问题通过prompt engineering解决不了,那么做Fine-Tune的话就是下面几个步骤:

  • 确定进行微调的模型
  • 准备并上传训练数据
  • 训练新的微调模型
  • 评估结果并根据需要是否重新训练
  • 使用您的微调模型
我在对OpenAI的API做微调的时候,碰到的最大问题就在于准备数据集上,因为其他步骤基本是都是自动化的,数据集的质量好坏其实决定了微调后模型的好坏。我失败了好几次的原因就是因为数据集的格式不对,它不是普通的json格式,而是jsonl格式,这一点儿我会在后面单独提到。
不过总体上来讲,微调GPT的API相比最开始是简单了很多,这也是我觉得未来大模型的两个大方面之一,也就是私域大模型,相比起通用领域,它更针对的是非常小的细分领域。OpenAI的模型都是闭源模型,如果要彻底的私域模型化,必须得用开源大模型,比如Llama或者Qwen系列,对于这方面的教程,建议大家看一下知学堂的这个大模型公开课,里面详细介绍了各种开源以及闭源的大模型,相关的技术细节也都有,入口在下面⬇️:
课程是业内大佬孙志岗老师带队研发的,他之前独立开发的AI大模型评测软件ChatALL.ai,几次登上Githuba的全球热榜第一。课上会讲很多干货,特别是开源模型训练的具体技术细节,记得仔细听,会比看文字内容更通俗易懂!
我们一步步的进行准备
第一步:确定进行微调的模型

OpenAI有很多模型,从初代GPT3到现在最新的GPT4o,大多数的模型都有其API,但是并不是所有的大模型都可以进行微调。

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-3.jpg

真正能进行微调的就是这五个模型,
gpt-3.5-turbo-0125, gpt-3.5-turbo-1106, gpt-3.5-turbo-0613, babbage-002, davinci-002。
其中最推荐的就是gpt-3.5-turbo-0125,属于是便宜还好用的一款模型。

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-4.jpg

第二步:准备并上传训练数据

训练数据分为两种格式,对于gpt-3.5-turbo这个系列,它的训练数据是「对话」格式的。比如这个例子。
  1. {"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the capital of France?"}, {"role": "assistant", "content": "Paris, as if everyone doesn't know that already."}]}
复制代码
这个例子是为了微调一个偶尔回答带有讽刺意味的机器人,我们来分析一下。
它由三部分构成:
系统角色设定/system

  • 内容:"Marv is a factual chatbot that is also sarcastic."
  • 分析:定义聊天机器人的角色和行为特点,即“Marv”是一个提供事实但具有讽刺性的聊天机器人。
用户输入/user

  • 内容:"What's the capital of France?"
  • 分析:用户提出一个简单的事实性问题,适合测试机器人的知识和回答风格。
助手回答/assistant

  • 内容:"Paris, as if everyone doesn't know that already."
  • 分析事实部分:"Paris" 是准确的回答,符合“factual”要求。

    • 讽刺部分:"as if everyone doesn't know that already." 表达讽刺语气,暗示问题过于简单,符合“sarcastic”要求。


那么回到我们的初始目标,道家思想和回答方式的机器人,那么我们就可以根据上面这个模版做一些训练数据。
系统角色:说明白这个机器人的特点。
我们设定的内容:道言是一个基于道家思想和语录回答问题的聊天机器人
用户输入:这个就可以是任何正常的句子
我们设定的内容:生命的意义是什么?
助手回答:这个是关键,因为你想要让GPT微调成你想要的回答格式,所以你得想一下你希望的输出是什么。
我们设定的内容:生命的意义在于顺其自然。正如老子所说:'道法自然。'
在助手回答这里我们的回答是,道家思想的直接回答,以及再加上一个引经据典的操作。
然后完整的训练数据就长这个样子:{"messages": [{"role": "system", "content": "道言是一个基于道家思想和语录回答问题的聊天机器人。"}, {"role": "user", "content": "生命的意义是什么?"}, {"role": "assistant", "content": "生命的意义在于顺其自然。正如老子所说:'道法自然。'"}]}
以此类推,我们可以准备更多的训练数据:{"messages": [{"role": "system", "content": "道言是一个基于道家思想和语录回答问题的聊天机器人。"}, {"role": "user", "content": "如何找到内心的平静?"}, {"role": "assistant", "content": "内心的平静在于清心寡欲。正如庄子所言:'淡泊以明志,宁静以致远。'"}]}
{"messages": [{"role": "system", "content": "道言是一个基于道家思想和语录回答问题的聊天机器人。"}, {"role": "user", "content": "如何面对挫折?"}, {"role": "assistant", "content": "面对挫折,要像水一样柔韧。老子说:'上善若水,水善利万物而不争。'"}]}
一般来说,这样的训练数据最少也得10个,但是最好准备个几十上百个,否则会容易学不到什么东西,提供的内容越多就更容易学。
把训练数据保存为jsonl格式,然后准备下一步。

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-5.jpg

第三步:训练新的微调模型

我们直接用OpenAI提供的训练工具来训练<a href="http://link.zhihu.com/?target=https%3A//platform.openai.com/finetune" class=" external" target="_blank" rel="nofollow noreferrer">https://platform.openai.com/finetune
打开微调后点击创建。

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-6.jpg

最简单的方法,就两步,选择模型后上传训练数据。

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-7.jpg

这是我们选择的模型以及上传数据,其余地方保持默认即可。

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-8.jpg

然后点击最下方的Create开始

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-9.jpg

显示如下则表面开始微调了。

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-10.jpg

可以看到这个loss下降的挺快的,在50轮的时候就到了0.1969了。

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-11.jpg

最后训练成功了,花了138轮,最后的loss是0.0703。

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-12.jpg

第四步:接下来就是测试一下微调后的模型,我们要记住这个ID。


如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-13.jpg

然后打开chat,选择我们刚刚训练好的模型。

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-14.jpg

我们来测试一下

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-15.jpg

再测试几次,可以看到即使问的是数学题,它都用的是我们设定好的格式。

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-16.jpg

我们先不管回答的质量怎么样,但是很明显的,它按照了我们预想的方法进行了,这就说明我们的微调是成功了,只不过后续需要更多的数据以及更多次的微调,以达到理想的程度。
以下是几个问题
1 微调的花费
我这次一共花了0.09美元,算是非常便宜了。

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-17.jpg

定价可以在OpenAI官网上找到,这是一个具体案例。

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-18.jpg

2 导致微调失败的常见原因
我失败了两次,原因都是数据集的格式有问题。

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-19.jpg

这个必须得严格按照标准来,建议用OpenAI提供的工具进行分析:https://cookbook.openai.com/examples/chat_finetuning_data_prep
这个工具很简单,可以告诉你哪里出问题了。

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-20.jpg

艾娃AI绘画 LV

发表于 2025-4-8 15:03:14

DeepSpeed Chat: 开源的一个类ChatGPT的模型,并且完整复现了InstructGPT论文(chatGPT的重要方案)提出的三步训练法.可以实现一个脚本训练三步.详细内容参见官档
也可以关注下参与者对deepSpeed chat的理解: 微软宣布开源 Deep Speed Chat,可将训练速度提升 15 倍以上,哪些信息值得关注?感兴趣的也可看下体验测试内容: 52AI:deepSpeed (DeepSpeed-Chat)体验
有了可操作的方案,那么怎么finetuning一个自己的专用模型就显得尤为重要。本文主要来自近端时间finetune chatGLM和deepspeed chat遇到的finetune方法的汇总.

Fine-tuning is the de facto way to leverage large pretrained language models to perform downstream tasks.[1] (Finetune实际上是利用预训练大语言模型解决下游任务) 类比到CV领域也是一样,比如用在imagenet或coco上训练的resnet-Xbackbone,可以finetune各种下游的目标检测,分类,分割任务.
至于为啥finetuen有效,这里就不赘述了,伟大领袖说过实践是检验真理的唯一标准,finetune已经受了大众的检验.

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-1.jpg


图1: 为啥要finetune? 谁来finetune?可以finetune出来些啥?

  结合图1,已知pretrained LLM,  下游任务,同时也收集到了足够任务的训练数据trainData,剩下的就是你我他来finetune下游任务了.
  PS:
             1) NLP的下游任务还有很多,这里放不了了.更别说上面的pretrained 变成多模态时,下游任务那就更多了 。  2)事实上,从很多资料来看,chatGPT已经能通过prompt+ (one shot smaple, few shot sample)这种人性化又简单的方式解决上面的下游任务了,并且效果不错。奈何咱们现在用不上,其次开源的LLM都暂不具备chatGPT此等能力(毕竟是后起追赶者),还有就是企业为了成本问题,也不会选择直接上整个大模型,多数是集合现有业务场景来选择一些对自己有利的下游场景做垂直领域的应用.

Finetune:  finetune top laryers

这里的finetune top laryers[2]就是用收集的trainData,训练时,冻结大部分pretrained LLM的参数(一般是前面的层), 小学习率地更新pretrained LLM的剩余小部分top的几层参数。这个方法肯定是没问题(CV里常用训练方式),。 问题主要在1)训练资源消耗[3]和2)多个下游任务的模型需要同时维护多个大模型。这个暂不考虑多任务同时训练,假设每个下游任务都单独训练.
这里以chatGLM-6B模型为例。单个模型28G,  n个下游任务就是n x 28G. 所以该方案有瑕疵,不友好,故有了下面的优化的finetune方案

Finetune: Adapters-Tuning


如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-2.jpg


图2: Adapters模块结构,和在transformer中插入的位置

2019年google研究院提出的Adapters-Tuning(自适应微调)[2],主要还是为了解决他们刚开放出来的BERT finetune下游任务这个场景. 具体的思路从上图也能看出来,针对每个特定的下游任务会额外在Transformer层内部对应位置加入Adapter模块,训练时pretrained BERT参数不用更新,只微调Adapter模块的参数即可。论文指出该方案每个任务增加3.6%的训练参数量.

Finetune: Prefix-Tuning

看到陌生名词不要慌,也不必简单看翻译过来的意思。打开翻译一看prefix=前缀,前缀-Tuning还是不知所云。
点开论文结合图看下图,一下就豁然开朗了。打开论文ctrl+F, 搜一下prefix一般开头都有定义。
prefix 定义:  but optimizes a small continuous task-specific vector (called the prefix).[1]
prefix-tuning (bottom), which freezes the Transformer parameters and only optimizes the prefix (the red pre- fix blocks).[1]
翻译下这两句应该也就懂了,再结合图片一看也就明白了。prefix:就是图中下面每个特定任务对应的训练参数。
prefix-tuning: 就是训练下游任务的时候,冻住pretrained LLM参数(pytorch里面就是grad=False, 梯度不更新)只训练每个特定任务的参数(也叫prefix, 叫prefix是因为他的添加的前缀词都在输入的左边如下图4)

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-3.jpg


图3:  prefix-tuning示意图

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-4.jpg


图4: prefix 适用场景(Autoregessive model : GPT, opt,  encoder-decoder model: BERT, T5 )

  如图4所示,原始训练数据 x="Harry Potter, Education, Hogwarts", y="[SEP] Harry Potter is graduated from Hogwarts". 不使用prefix,直接finetune优化p(y|x)最大时的参数,prefix应用在Autoregessive Model时,
只优化p(y| prefix+x)最大时prefix引入的参数即可. 至于这个prefix具体是啥,就需要根据特定下游任务来确定。比如要做文档总结任务,那么prefix可以是"请总结这篇文档:".
prefix有效的前提如论文所说“基于prompting的直观体验,我们相信一个前置的contex可以引导大语言模型进行特定任务而不用改变自身参数”。[1]

Finetune: prompt tuning (P-tuning v2)

       如上文所说,prefix tuing是在输入的embedding层最前端插入prompt.  P-tuing V2为了提升模型解决NLU任务的能力,优化后的v2如图5(b)是在除了输入的embedding外,其他的Transformer层也加了前置prompt.[4]

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-5.jpg


图5: prefix-tuing改进到P-tuning V2

这个技术是清华Chatglm的训练在推广,也很容易理解,glm的填空式方案,优点之一就是pretraind 模型编码的输入自带上下文的信息,很适合解决NLU的任务(那些需要看上下文的任务)。而P-tuing V2的提出就是为了在finetune下游任务的时候能尽可能暴露这些上下文信息。论文指出该方案会增加0.1%~3%的训练参数量.
  Finetune: lora

( Low-Rank Adaptation) LoRA : 设计思路其实和Adapter tuing很像,也是定位到transformers中的各个linear层,会在添加低纬度的训练参数层。训练过程中只训练这些参数即可。[5] deepspeedchat使用lora进行finetune,可参考52AI:deepSpeed (DeepSpeed-Chat)体验

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-6.jpg


图6:lora的模式

这里以chatglm的训练为例,官方给出了不同训练方式的对比结果。因此选择适配模型设计本身的finetune方式可能会得到更优的结果[6]

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-7.jpg

huggingface pert库

   huggingface很贴心的把常见的fine-Tuning方法都做了集成,只用几行代码就可添加和修改,十分方便[7]

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-8.jpg
  1. from transformers import AutoModelForSeq2SeqLM
  2. from peft import get_peft_config, get_peft_model, LoraConfig, TaskType
  3. model_name_or_path = "bigscience/mt0-large"
  4. tokenizer_name_or_path = "bigscience/mt0-large"
  5. peft_config = LoraConfig(
  6.     task_type=TaskType.SEQ_2_SEQ_LM, inference_mode=False, r=8, lora_alpha=32, lora_dropout=0.1
  7. )
  8. model = AutoModelForSeq2SeqLM.from_pretrained(model_name_or_path)
  9. model = get_peft_model(model, peft_config)
  10. model.print_trainable_parameters()
  11. # output: trainable params: 2359296 || all params: 1231940608 || trainable%: 0.19151053100118282
复制代码
以上,仅供参考。
更新

QLoRA

QLoRA: 最新出的升级版QLoRA, QloRA加持下65B模型 fp16 finetune GPU只用48G. 博主在deepSpeed (DeepSpeed-Chat)体验中使用3090只跑过13B+lora模型finetune,是OOM。想来应用这个新的方案可以跑起来,期待新技术带来新的体验。
paper: https://arxiv.org/pdf/2305.14314.pdf
code: https://github.com/artidoro/qlora

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-9.jpg


longLORA

paper:  EFFICIENTFINE-TUNING    OFLONG-CONTEXTLARGELANGUAGEMODELS
code: https://github.com/dvlab-research/LongLoRA
一个不留神,LongLoRA出来快半个月了,从名称和文章标题能看出来这个主要是解决大语言模型学习更长的上下文的。(long-context LLMs).

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-10.jpg

你在我这儿 LV

发表于 2025-4-8 15:13:22

今天刚刚翻译完 OpenAI 的 fine-tuning 文档,官方文档应该很适合回答这个问题,以下是文章内容:

本篇文档翻译时间为 20230501,请注意时效性。
其他已翻译文档链接:

  • IvyLee:OpenAI ChatGPT API 指南之 Chat Completion Beta 版
  • IvyLee:OpenAI ChatGPT API 指南之语音转文字 Beta 版
  • IvyLee:OpenAI ChatGPT API 文档之生产最佳实践
  • IvyLee:OpenAI ChatGPT API 文档之 Embedding
  • IvyLee:OpenAI ChatGPT API 文档之 Fine-tuning(微调)
<hr/>了解如何为你的应用程序定制模型。
介绍

通过以下方式,微调可让你更好地利用 API 提供的模型:

  • 比设计提示(prompt)质量更高的结果
  • 能够训练更多不适合提示的示例
  • 由于提示较短而节省 token
  • 更低的延迟请求
GPT-3 已经在开放互联网的大量文本上进行了预训练。当给出仅包含几个示例的提示时,它通常可以直观判断出你正在尝试执行的任务并生成看似合理的补全(completion),这通常称为“小样本学习(few-shot learning)”。
微调(Fine-tuning)通过训练超出提示范围的更多示例来改进小样本学习,让你在大量任务上取得更好的结果。模型经过微调后,你将不再需要在提示中提供示例。这可以节省成本并实现更低延迟的请求。
概括地讲,微调涉及以下步骤:

  • 准备并上传训练数据
  • 训练一个新的微调模型
  • 使用你的微调模型
请访问我们的定价页面,详细了解微调模型训练和使用的计费方式。
哪些模型可以微调?

微调目前仅适用于以下基本模型:davinci、curie、babbage 和 ada,这些是训练后没有任何指令的原始模型(有指令的模型举例:text-davinci-003)。你还可以通过添加额外数据来继续微调已经微调过的模型,而无需从头开始。
安装

我们建议使用 OpenAI 的命令行界面(CLI),请运行如下命令进行安装:
  1. pip install --upgrade openai
复制代码
(以下说明适用于 0.9.4 及更高版本。另外,OpenAI CLI 需要 python 3。)
通过将以下行添加到你的 shell 初始化脚本(例如 .bashrc、zshrc 等)或在微调命令之前在命令行中运行该命令来设置你的 OPENAI_API_KEY 环境变量:
  1. export OPENAI_API_KEY="<OPENAI_API_KEY>"
复制代码
准备训练数据

训练数据是教给 GPT-3 你想让它生成内容的方式。
数据必须是一个 JSONL 文档,其中每一行都是一个提示-补全对(prompt-completion),对应于一个训练示例。你可以使用我们的 CLI 数据准备工具轻松将数据转换成此文件格式。
  1. {"prompt": "<提示文本>", "completion": "<理想的生成文本>"}
  2. {"prompt": "<提示文本>", "completion": "<理想的生成文本>"}
  3. {"prompt": "<提示文本>", "completion": "<理想的生成文本>"}
  4. ...
复制代码
设计用于微调的提示和补全不同于设计用于基本模型(Davinci、Curie、Babbage、Ada)的提示。具体而言,基础模型的提示通常包含多个示例(“小样本学习”),而微调的每个训练示例通常包含单个输入示例及其相关输出,无需给出详细说明或在同一提示中包含多个示例。
有关如何为各种任务准备训练数据的更详细指导,请参阅准备数据集最佳实践.
拥有的训练示例越多越好,我们的建议是至少有几百个示例。我们发现数据集大小每增加一倍都会导致模型质量线性增加。
CLI 数据准备工具

我们开发了一个工具,可以验证、提供建议和重新格式化你的数据:
  1. openai tools fine_tunes.prepare_data -f <LOCAL_FILE>
复制代码
这个工具接受不同的格式,唯一的要求是它们包含提示和补全列/键。你可以传递 CSV、TSV、XLSX、JSONJSONL 文件,它将在引导你完成建议更改后,将输出保存到一个准备好进行微调的 JSONL 文件中。
创建微调模型

假设你已经按照上述指南准备好了数据。
使用 OpenAI CLI 开始微调作业:
  1. openai api fine_tunes.create -t <TRAIN_FILE_ID_OR_PATH> -m <BASE_MODEL>
复制代码
其中 BASE_MODEL 是你开始使用的基础模型名称(ada、babbage、curie 或 davinci)。你可以使用 后缀参数 自定义微调模型的名称。
运行上述命令会执行以下几个操作:

  • 使用文件 API 上传文件(或使用已上传的文件)
  • 创建一个微调作业
  • 流式传输事件,直到作业完成(这通常需要几分钟,但如果队列中有很多作业或数据集很大,则可能需要几个小时)
每个微调作业都始于一个基础模型,默认为 curie。模型的选择会影响模型的性能和微调模型的成本。你可以选择的模型包括:ada、babbage、curie 或 davinci。请访问我们的定价页面,了解有关微调费率的详细信息。
启动微调作业后,可能需要一些时间才能完成。在我们的系统中,你的作业可能排在其他作业之后,训练我们的模型可能需要几分钟或几小时,具体取决于模型和数据集的大小。如果事件流因任何原因中断,你可以通过运行以下命令恢复它:
  1. openai api fine_tunes.follow -i <YOUR_FINE_TUNE_JOB_ID>
复制代码
作业完成后,它应该显示微调模型的名称。
除了创建微调作业,你还可以列出现有作业、检索作业状态或取消作业。
  1. # List all created fine-tunes
  2. openai api fine_tunes.list
  3. # Retrieve the state of a fine-tune. The resulting object includes
  4. # job status (which can be one of pending, running, succeeded, or failed)
  5. # and other information
  6. openai api fine_tunes.get -i <YOUR_FINE_TUNE_JOB_ID>
  7. # Cancel a job
  8. openai api fine_tunes.cancel -i <YOUR_FINE_TUNE_JOB_ID>
复制代码
使用微调模型

作业成功后,fine_tuned_model 字段将填充模型名称。你现在可以将此模型指定为我们的 Completions API 的参数,使用 [Playground](https:// platform.openai.com/playground)对其进行请求。
在作业第一次完成后,你的模型可能需要几分钟时间才能准备好处理请求。如果你对模型的 Completion 请求超时,很可能是因为模型仍在加载。如果发生这种情况,请在几分钟后重试。
你可以通过将模型名称作为 Completion 请求的 model 参数,来开始发出请求:
OpenAI CLI:
  1. openai api completions.create -m <FINE_TUNED_MODEL> -p <YOUR_PROMPT>
复制代码
cURL:
  1. curl https://api.openai.com/v1/completions \
  2.   -H "Authorization: Bearer $OPENAI_API_KEY" \
  3.   -H "Content-Type: application/json" \
  4.   -d '{"prompt": YOUR_PROMPT, "model": FINE_TUNED_MODEL}'
复制代码
Python:
  1. import openai
  2. openai.Completion.create(
  3.     model=FINE_TUNED_MODEL,
  4.     prompt=YOUR_PROMPT)
复制代码
Node.js:
  1. const response = await openai.createCompletion({
  2.   model: FINE_TUNED_MODEL
  3.   prompt: YOUR_PROMPT,
  4. });
复制代码
你可以继续在这些针对微调模型的请求中使用所有其他 Completion 参数,例如 temperature、frequency_penalty、presence_penalty 等。
删除微调模型

要删除微调模型,你必须在你的组织中被指定为“所有者(owner)”。
OpenAI CLI:
  1. openai api models.delete -i <FINE_TUNED_MODEL>
复制代码
cURL:
  1. curl -X "DELETE" https://api.openai.com/v1/models/<FINE_TUNED_MODEL> \
  2.   -H "Authorization: Bearer $OPENAI_API_KEY"
复制代码
Python:
  1. import openai
  2. openai.Model.delete(FINE_TUNED_MODEL)
复制代码
准备数据集

微调是一种强大的技术,可以创建特定于你的用例的新模型。在微调模型之前,我们强烈建议你阅读以下最佳实践和特定用例的指南
数据格式化

你需要一组训练示例数据集来微调模型,其中每个示例都包含单个输入(prompt)及其关联的输出(completion)。这与使用我们的基本模型有明显区别,在基本模型中你可能需要在单个提示中输入详细的说明或多个示例。

  • 每个 prompt 都应该以固定的分隔符结尾,以便通知模型何时 prompt 结束、何时开始 completion。通常效果良好的一个简单分隔符是 \n\n###\n\n。分隔符不应该出现在任何 prompt 中的其他地方。
  • 由于我们的分词器(tokenization)会根据单词前面的空格进行分词(计算 token),因此每个 completion 都应以空格开头。
  • 每个 completion 都应以固定的停止序列结束,以便在 completion 结束时通知模型。停止序列可以是 \n、### 或未出现在任何 completion 中的任何其他 token。
  • 使用训练好的模型来进行预测或推理时(inference),你应该按照与创建训练数据集时相同的方式格式化你的 prompt,包括相同的分隔符,还要指定相同的停止序列以正确截断 completion。
一般最佳实践

通过使用更多高质量的示例进行微调,可以获得更好的性能。为了微调一个比使用基础模型和高质量提示更好的模型,你应该提供至少几百个高质量的示例,最好由人类专家审核。在此基础上,性能往往会随着示例数量的加倍而线性增长。增加示例的数量通常是提高性能的最佳和最可靠的方法。
分类是最容易入门的模型。对于分类问题,我们建议使用 ada,经过微调,它的性能通常只会比功能更强大的模型差一点点,同时速度更快,成本更低。
如果你是在现有数据集上进行微调而不是从头开始编写提示,请务必在可能的情况下手动审核你的数据,以查找可能存在的冒犯性或不准确的内容,或者如果数据集很大,请检查尽可能多的随机样本。
具体指南

微调可以解决多种问题,最佳使用方式可能取决于你特定的用例。下面,我们列出了最常见的微调用例和相应的指南。

  • 分类

    • 模型是否在说谎?
    • 情感分析
    • 电子邮件分类

  • 条件生成

    • 根据维基百科文章撰写引人入胜的广告
    • 实体提取
    • 客户支持聊天机器人
    • 基于技术属性列表的产品描述

分类

在分类问题中,应将每个输入分类到预定义的类别之一。对于这种类型的问题,我们建议:

  • 在提示的末尾使用一个分隔符,例如 \n\n###\n\n。记得在最终向模型发出请求时也附加这个分隔符。
  • 选择与单个 token 相对应的类别,在推理时,指定 max_tokens=1,因为只需要第一个 token 来进行分类。译者注:这里不太理解,请 ChatGPT 举了个例子:假设训练一个情感分析模型,将输入文本分类为正面或负面情感。我们可以选择将正面情感映射到单个 token,例如 "positive",将负面情感映射到单个 token,例如 "negative",然后在推理时指定 max_tokens=1。这样,当模型接收到一个输入时,只需要查看输入的第一个 token 是 "positive" 还是 "negative",就可以将其分类到对应的情感类别中。
  • 确保提示+补全,包括分隔符,不超过 2048 个 token
  • 每个类别至少要有 ~100 个样本
  • 如果需要获取类别的对数概率,可以在使用模型时指定 logprobs=5(对于 5 个类别的情况)
  • 确保用于微调的数据集在结构和任务类型上与模型将要用于的数据集非常相似。
案例研究:模型是否在说谎?

假设你想要确保网站上的广告文本提到正确的产品和公司,确保模型没有捏造信息。你可能需要微调一个分类器,以过滤掉错误的广告。
数据集可能看起来像下面这样:
  1. {"prompt":"Company: BHFF insurance\nProduct: allround insurance\nAd:One stop shop for all your insurance needs!\nSupported:", "completion":" yes"}
  2. {"prompt":"Company: Loft conversion specialists\nProduct: -\nAd:Straight teeth in weeks!\nSupported:", "completion":" no"}
复制代码
在上面的示例中,我们使用了一个结构化输入,其中包含公司的名称、产品和相关广告。分隔符使用了 \nSupported:,清晰地将提示与补全分开。有足够数量的示例,分隔符并不会产生太大的影响(通常少于 0.4%),只要它不出现在提示或补全中。
在这个案例中,我们对一个 ada 模型进行了微调,因为它速度更快、更便宜,并且由于这是一个分类任务,性能与更大的模型相当。
现在可以通过发出一个 Completion 请求来查询我们的模型。
  1. curl https://api.openai.com/v1/completions \
  2.   -H "Content-Type: application/json" \
  3.   -H "Authorization: Bearer $OPENAI_API_KEY" \
  4.   -d '{
  5.     "prompt": "Company: Reliable accountants Ltd\nProduct: Personal Tax help\nAd:Best advice in town!\nSupported:",
  6.     "max_tokens": 1,
  7.     "model": "YOUR_FINE_TUNED_MODEL_NAME"
  8.   }'
复制代码
这将返回 yes 或 no。
案例研究:情感分析

假设你想要获取一条特定推文的情感积极程度或消极程度。数据集可能看起来像这样:
  1. {"prompt":"Overjoyed with the new iPhone! ->", "completion":" positive"}
  2. {"prompt":"@lakers disappoint for a third straight night https://t.co/38EFe43 ->", "completion":" negative"}
复制代码
对模型进行微调后,你可以通过在 completion 请求上设置 logprobs=2 来取回第一个 completion token 的对数概率。positive 类别的概率越高,情感极性就越积极。
现在,可以通过发出 completion 请求来查询我们的模型。
  1. curl https://api.openai.com/v1/completions \
  2.   -H "Content-Type: application/json" \
  3.   -H "Authorization: Bearer $OPENAI_API_KEY" \
  4.   -d '{
  5.     "prompt": "https://t.co/f93xEd2 Excited to share my latest blog post! ->",
  6.     "max_tokens": 1,
  7.     "model": "YOUR_FINE_TUNED_MODEL_NAME"
  8.   }'
复制代码
这将会返回:
  1. {
  2.   "id": "cmpl-COMPLETION_ID",
  3.   "object": "text_completion",
  4.   "created": 1589498378,
  5.   "model": "YOUR_FINE_TUNED_MODEL_NAME",
  6.   "choices": [
  7.     {
  8.       "logprobs": {
  9.         "text_offset": [
  10.           19
  11.         ],
  12.         "token_logprobs": [
  13.           -0.03597255
  14.         ],
  15.         "tokens": [
  16.           " positive"
  17.         ],
  18.         "top_logprobs": [
  19.           {
  20.             " negative": -4.9785037,
  21.             " positive": -0.03597255
  22.           }
  23.         ]
  24.       },
  25.       "text": " positive",
  26.       "index": 0,
  27.       "finish_reason": "length"
  28.     }
  29.   ]
  30. }
复制代码
案例研究:电子邮件分类

假设你想要将收到的电子邮件分类为大量预定义的类别之一。对于大量类别的分类,我们建议你将这些类别转换为数字,最多可处理约 500 个类别。我们观察到,在数字前添加一个空格有时会略微提高性能,这是由于分词(tokenization)的原因。你可能希望按以下方式组织训练数据:
  1. {"prompt":"Subject: <email_subject>\nFrom:<customer_name>\nDate:<date>\nContent:<email_body>\n\n###\n\n", "completion":" <numerical_category>"}
复制代码
具体示例:
  1. {"prompt":"Subject: Update my address\nFrom:Joe Doe\nTo:support@ourcompany.com\nDate:2021-06-03\nContent:Hi,\nI would like to update my billing address to match my delivery address.\n\nPlease let me know once done.\n\nThanks,\nJoe\n\n###\n\n", "completion":" 4"}
复制代码
在上面的例子中,我们使用了一个最多包含 2043 个 token 的电子邮件作为输入(这允许使用 4 个 token 的分隔符和一个 token 的补全,总共 2048 个token)。分隔符使用了 \n\n###\n\n,为此我们移除了电子邮件中出现的所有 ###。
条件生成

条件生成是一种根据特定输入来生成内容的问题,包括释义(改写)、概括、实体提取、根据给定规范编写产品说明、聊天机器人等等。对于这种类型的问题,我们建议采用以下方法:

  • 在提示末尾处使用分隔符,例如 \n\n###\n\n。在最终向模型发出请求时,也要附加这个分隔符。
  • 在补全结束时使用一个结束 token,例如 END
  • 在推理(inference)时,将结束 token 添加为停止序列,例如 stop=[" END"]
  • 以至少 ~500 个示例为目标
  • 确保提示 + 补全不超过 2048 个 token,包括分隔符
  • 确保示例具有高质量并遵循相同的期望格式
  • 确保用于微调的数据集在结构和任务类型上与模型将要用于的数据集非常相似
  • 对于这些用例,使用较低的学习率和仅 1-2 个训练时期(epochs)往往效果更好
案例分析:根据维基百科文章撰写引人入胜的广告

这是一个生成性的用例,因此你需要确保提供的样本具有最高质量,因为微调后的模型将尝试模仿给定示例的风格(和错误)。提供大约 500 个示例是一个好的起点,示例数据集可能如下所示:
  1. {"prompt":"<Product Name>\n<Wikipedia description>\n\n###\n\n", "completion":" <engaging ad> END"}
复制代码
具体示例:
  1. {"prompt":"Samsung Galaxy Feel\nThe Samsung Galaxy Feel is an Android smartphone developed by Samsung Electronics exclusively for the Japanese market. The phone was released in June 2017 and was sold by NTT Docomo. It runs on Android 7.0 (Nougat), has a 4.7 inch display, and a 3000 mAh battery.\nSoftware\nSamsung Galaxy Feel runs on Android 7.0 (Nougat), but can be later updated to Android 8.0 (Oreo).\nHardware\nSamsung Galaxy Feel has a 4.7 inch Super AMOLED HD display, 16 MP back facing and 5 MP front facing cameras. It has a 3000 mAh battery, a 1.6 GHz Octa-Core ARM Cortex-A53 CPU, and an ARM Mali-T830 MP1 700 MHz GPU. It comes with 32GB of internal storage, expandable to 256GB via microSD. Aside from its software and hardware specifications, Samsung also introduced a unique a hole in the phone's shell to accommodate the Japanese perceived penchant for personalizing their mobile phones. The Galaxy Feel's battery was also touted as a major selling point since the market favors handsets with longer battery life. The device is also waterproof and supports 1seg digital broadcasts using an antenna that is sold separately.\n\n###\n\n", "completion":"Looking for a smartphone that can do it all? Look no further than Samsung Galaxy Feel! With a slim and sleek design, our latest smartphone features high-quality picture and video capabilities, as well as an award winning battery life. END"}
复制代码
在这里,我们使用了多行分隔符,因为维基百科文章包含多个段落和标题。我们还使用了一个简单的结束 token,以确保模型知道何时完成补全。
案例研究:实体提取

这类似于语言转换任务。为了提高性能,最好将不同的提取实体按字母顺序或按它们在原始文本中出现的顺序排序。这将有助于模型跟踪需要按顺序生成的所有实体。数据集可能如下所示:
  1. {"prompt":"<any text, for example news article>\n\n###\n\n", "completion":" <list of entities, separated by a newline> END"}
复制代码
具体示例:
  1. {"prompt":"Portugal will be removed from the UK's green travel list from Tuesday, amid rising coronavirus cases and concern over a \"Nepal mutation of the so-called Indian variant\". It will join the amber list, meaning holidaymakers should not visit and returnees must isolate for 10 days...\n\n###\n\n", "completion":" Portugal\nUK\nNepal mutation\nIndian variant END"}
复制代码
多行分隔符效果最好,因为文本可能包含多行。理想情况下,输入提示的类型应该高度多样化(新闻文章、维基百科页面、推文、法律文件等),这反映了在提取实体时可能遇到的不同类型的文本。
案例研究:客户支持聊天机器人

聊天机器人通常包含有关对话的相关内容(订单详情)、迄今为止的对话摘要以及最近消息。对于这个用例,同一个历史对话可能在数据集中生成多个行,每次都带有稍微不同的上下文,作为每个代理(客服)的生成补全。这种用例需要几千个示例,因为它可能涉及不同类型的请求和客户问题。为确保高质量的性能,我们建议审核对话样本以确保代理(客服)消息的质量。可以使用单独的文本转换微调模型生成摘要。数据集可能如下所示:
译者注:在这个案例研究中,为了训练客户支持聊天机器人,可以使用之前与客户进行过的历史对话记录作为训练数据,以帮助机器人学习如何更好地回答客户的问题和解决客户的问题。由于同一个客户可能会有多次交流,因此同一段历史对话记录可能会出现在数据集中的多个样本中,每个样本的上下文略有不同。
  1. {"prompt":"Summary: <summary of the interaction so far>\n\nSpecific information:<for example order details in natural language>\n\n###\n\nCustomer: <message1>\nAgent: <response1>\nCustomer: <message2>\nAgent:", "completion":" <response2>\n"}
  2. {"prompt":"Summary: <summary of the interaction so far>\n\nSpecific information:<for example order details in natural language>\n\n###\n\nCustomer: <message1>\nAgent: <response1>\nCustomer: <message2>\nAgent: <response2>\nCustomer: <message3>\nAgent:", "completion":" <response3>\n"}
复制代码
在这里,我们有意将不同类型的输入信息分开,但是保持了客户与代理对话在提示和补全之间的相同格式。所有的补全都应该是由代理完成的,当进行推断时,我们可以使用 \n 作为停止序列。
案例研究:基于技术属性列表的产品描述

在这个案例中,将输入数据转换为自然语言非常重要,这很可能会带来更好的性能。例如,以下两种格式中,后一个使用自然语言的性能更好:
  1. {"prompt":"Item=handbag, Color=army_green, price=$99, size=S->", "completion":" This stylish small green handbag will add a unique touch to your look, without costing you a fortune."}
  2. {"prompt":"Item is a handbag. Colour is army green. Price is midrange. Size is small.->", "completion":" This stylish small green handbag will add a unique touch to your look, without costing you a fortune."}
复制代码
为了获得高性能,请确保补全是基于提供的描述。如果经常需要查阅外部内容来生成描述,那么以自动化的方式将这些外部内容添加到模型中,可能会提高模型的性能。如果描述是基于图像的,那么使用算法提取图像的文本描述可能会有所帮助。由于补全只有一句话长,在推断过程中,我们可以使用 . 作为停止序列。
高级应用

自定义模型名称

你可以使用 suffix(后缀) 参数为经过微调的模型名称添加最多 40 个字符的后缀。
OpenAI CLI:
  1. openai api fine_tunes.create -t test.jsonl -m ada --suffix "custom model name"
复制代码
模型名称结果是:
  1. ada:ft-your-org:custom-model-name-2022-02-15-04-21-04
复制代码
分析微调模型

我们在每个作业完成后都会附上一个结果文件。当你检索微调结果或查看微调事件时,将列出对应结果文件的 ID。你可以下载这些文件:
OpenAI CLI:
  1. openai api fine_tunes.results -i <YOUR_FINE_TUNE_JOB_ID>
复制代码
CURL:
  1. curl https://api.openai.com/v1/files/$RESULTS_FILE_ID/content \
  2.   -H "Authorization: Bearer $OPENAI_API_KEY" > results.csv
复制代码
_results.csv 文件中,每个训练步骤一行数据,一个步骤指的是对一批数据进行一次前向传递和反向传递。除了步骤编号,每行还包含以下与该步骤相对应的字段:

  • elapsed_tokens:模型到目前为止所见的 token 数(包括重复的 token)
  • elapsed_examples:模型到目前为止所看到的示例数(包括重复的示例),一个示例是批次中的一个元素。例如,如果 batch_size = 4,则每个步骤将使 elapsed_examples 增加 4。
  • training_loss:训练批次上的损失
  • training_sequence_accuracy:训练批次中的 补全 中,模型预测的 token 与真实补全 token 完全匹配的百分比。例如,batch_size 为 3,如果你的数据包含补全 [[1, 2], [0, 5], [4, 2]],并且模型预测了 [[1, 1], [0, 5], [4, 2]],则此准确率为 2/3 = 0.67。
  • training_token_accuracy:训练批次中被模型正确预测的 token 百分比。例如,batch_size 为 3,如果你的数据包含补全 [[1, 2], [0, 5], [4, 2]],模型预测了 [[1, 1], [0, 5], [4, 2]],则此准确率为 5/6 = 0.83。
分类特定指标

我们还提供了在结果文件中生成其他分类特定指标的选项,例如准确率和加权 F1 得分。这些指标会定期针对完整的验证集进行计算,并在微调结束时进行计算。你会在结果文件的附加列中看到它们。
要启用此功能,请设置参数 --compute_classification_metrics。此外,你必须提供一个验证文件,并设置 classification_n_classes 参数(用于多类分类)或 classification_positive_class 参数(用于二元分类)中的一个。
OpenAI CLI:
  1. # For multiclass classification
  2. openai api fine_tunes.create \
  3.   -t <TRAIN_FILE_ID_OR_PATH> \
  4.   -v <VALIDATION_FILE_OR_PATH> \
  5.   -m <MODEL> \
  6.   --compute_classification_metrics \
  7.   --classification_n_classes <N_CLASSES>
  8. # For binary classification
  9. openai api fine_tunes.create \
  10.   -t <TRAIN_FILE_ID_OR_PATH> \
  11.   -v <VALIDATION_FILE_OR_PATH> \
  12.   -m <MODEL> \
  13.   --compute_classification_metrics \
  14.   --classification_n_classes 2 \
  15.   --classification_positive_class <POSITIVE_CLASS_FROM_DATASET>
复制代码
如果设置了 --compute_classification_metrics 参数,以下指标将显示在你的结果文件中:
用于多类分类

  • classification/accuracy:准确率
  • classification/weighted_f1_score:加权 F1 得分
用于二元分类
以下指标基于分类阈值为 0.5(即当概率 >0.5 时,一个示例被分类为属于正类)。

  • classification/accuracy:准确率
  • classification/precision:精确率
  • classification/recall:召回率
  • classification/f{beta}:F-beta 得分
  • classification/auroc:AUROC
  • classification/auprc:AUPRC
译者注:AUROC 和 AUPRC 是分类问题中常用的两个性能度量指标。
AUROC(Area Under the Receiver Operating Characteristic Curve)是一个二元分类器的常用性能指标,它基于真正例率(True Positive Rate, TPR)和假正例率(False Positive Rate, FPR)的曲线下面积。AUROC 的取值范围在 0 到 1 之间,值越大说明分类器性能越好,当 AUROC=0.5 时,说明分类器等同于随机分类器。
AUPRC(Area Under the Precision-Recall Curve)是另一个二元分类器的性能指标,它基于精确率(Precision)和召回率(Recall)的曲线下面积。AUPRC 的取值范围也在 0 到 1 之间,值越大说明分类器性能越好,当 AUPRC=0.5 时,说明分类器等同于随机分类器。相对于 AUROC,AUPRC 对于类别不平衡问题更加敏感,因为它更加关注少数类的分类性能。
在许多分类任务中,AUROC 和 AUPRC 都是重要的性能指标,因为它们可以帮助评估分类器在不同阈值下的性能,并且不同的问题可能会更关注其中一个指标。
请注意,这些评估假定你正在使用分词后只有一个 token 的文本标签来表示类别,如上所述。如果不满足这些条件,你得到的数字可能会是错误的。
验证

你可以保留一部分数据用于验证。验证文件与训练文件具有完全相同的格式,训练数据和验证数据应该是互斥的。
如果在创建微调作业时包含验证文件,那么对微调模型在训练期间定期针对验证数据的表现进行评估的结果,也会包含在生成的结果文件中。
OpenAI CLI:
  1. openai api fine_tunes.create -t <TRAIN_FILE_ID_OR_PATH> \
  2.   -v <VALIDATION_FILE_ID_OR_PATH> \
  3.   -m <MODEL>
复制代码
如果你提供了验证文件,我们会在训练期间定期对验证数据的批次进行指标计算。你将在结果文件中看到以下额外的指标:

  • validation_loss:验证批次的损失
  • validation_sequence_accuracy:验证批次中模型预测的 token 与真实 token 完全匹配的补全百分比。例如,对于 batch_size 为 3 的数据,如果你的数据包含补全 [[1, 2],[0, 5],[4, 2]],而模型预测 [[1, 1],[0, 5],[4, 2]],则此准确率为 2/3 = 0.67。
  • validation_token_accuracy:模型正确预测验证批次中 token 的百分比。例如,对于 batch_size 为 3 的数据,如果你的数据包含补全 [[1, 2],[0, 5],[4, 2]],而模型预测 [[1, 1],[0, 5],[4, 2]],则此准确率为 5/6 = 0.83。
超参数

我们已经选择了适用于各种用例的默认超参数,唯一必需的参数是训练文件。
话虽如此,调整用于微调的超参数通常会导致产生更高质量输出的模型。特别是,你可能希望配置以下内容:

  • model:微调的基础模型名称。你可以选择 "ada"、"babbage"、"curie" 或 "davinci" 中的一个。要了解有关这些模型的更多信息,请参阅模型文档。
  • n_epochs:默认为 4,训练模型的周期数。一个周期指的是完整地遍历训练数据集一次。
  • batch_size:默认为训练集中示例数的约 0.2%,上限为 256。批量大小是用于训练单个前向和后向传递的训练示例数量。一般来说,我们发现对于较大的数据集,较大的批量大小通常效果更好。
  • learning_rate_multiplier:默认值为 0.05、0.1 或 0.2,具体取决于最终的 batch_size。微调学习率是用于预训练的原始学习率乘以此参数。我们建议尝试范围在 0.02 到 0.2 之间的值,查看哪个值能产生最好的结果。根据经验,我们发现较大的批量大小通常使用较大的学习率会表现更好。
  • compute_classification_metrics:默认值为 False。如果为 True,则在分类任务的微调中,会在每个周期结束时计算验证集上的分类特定指标(准确率、F1 得分等)。
要配置这些额外的超参数,请通过 OpenAI CLI 的命令行 flag 进行传递,例如:
  1. openai api fine_tunes.create \
  2.   -t file-JD89ePi5KMsB3Tayeli5ovfW \
  3.   -m ada \
  4.   --n_epochs 1
复制代码
对已微调的模型继续微调

如果你已经针对自己的任务微调了一个模型,然后现在有额外的训练数据需要加入,你可以对该模型继续进行微调。这将创建一个从所有训练数据中学习的模型,无需从头开始重新训练。
要实现这一点,请在创建新的微调作业时传递已微调的模型名称(例如 -m curie:ft-<org>-<date>)。其他训练参数不必更改,但是如果你的新训练数据比以前的训练数据小得多,你可能可以将 learning_rate_multiplier 减少 2 到 4 倍。
Weights & Biases

你可以将微调结果与 Weights & Biases 同步,以跟踪实验、模型和数据集。
要开始使用,你需要一个 Weights & Biases 账户和一个付费的 OpenAI 计划。为确保使用的是最新版本的openai 和 wandb,请运行:
  1. pip install --upgrade openai wandb
复制代码
要将你的微调结果与 Weights & Biases 同步,请运行:
  1. openai wandb sync
复制代码
你可以阅读 Weights & Biases 文档了解更多有关此集成的信息。
译者注:Weights & Biases(简称 W&B)是一个第三方工具,可以用于跟踪、记录和可视化机器学习实验的结果。它提供了许多功能,例如实时可视化训练指标、记录超参数、比较不同实验的性能等。W&B 还提供了一个 Web 界面,可以方便地查看和管理实验结果。在 OpenAI 框架中,W&B 是可选的,但它可以帮助用户更好地组织和管理机器学习实验,并提高实验效率。
示例 Notebooks

分类

finetuning-classification.ipynb
这个 Notebook 演示如何微调一个模型,可以分类输入文本是否与棒球或曲棍球相关。我们将在这个 Notebook 中完成此任务的四个步骤:

  • 数据探索:概览数据源以及示例。
  • 数据准备:把数据源转换为可用于微调的 jsonl 文件。
  • 微调:启动微调作业并解释所得模型的性能。
  • 使用模型:演示如何向微调模型发送请求以获取预测结果。
问答系统(Question answering)

olympics-1-collect-data.ipynb
olympics-2-create-qa.ipynb
olympics-3-train-qa.ipynb
译者注:Question answering(问答)通常指问答系统,即通过计算机程序来回答自然语言问题的系统,通常使用自然语言处理和机器学习技术来理解和回答问题。
这个项目的想法是创建一个基于提供的几段文本的问答模型。基于 GPT-3 的基础模型在回答包含在段落中的问题时表现良好,但如果答案不包含在段落中,基础模型往往仍然尽力回答,经常导致答案混淆。
为了创建一个只有在有足够上下文的情况下才回答问题的模型,我们首先创建了一个基于文本段落的问题和答案数据集。为了训练模型只在有答案时回答,我们还添加了对抗性示例(adversarial examples),其中问题与上下文不匹配。在这些情况下,我们要求模型输出 "No sufficient context for answering the question"(没有足够的上下文来回答问题)。
我们将在三个 Notebook 中完成该任务

  • 第一个 Notebook 着重于收集最近的数据,这些数据是 GPT-3 在其预训练期间没有看到过的。我们选择了 2020 年奥运会(实际上是在 2021 年夏季举行的),并下载了 713 个不同的页面。我们将数据集按照各个部分进行组织,这些部分将用作提问和回答的上下文。
  • 第二个 Notebook 根据数据中的维基百科部分提出一些问题,并基于该部分数据回答这些问题。
  • 第三个 Notebook 利用上下文、问题-答案对的数据集,另外创建对抗性问题-上下文对,其中问题不是基于该上下文生成的。在这些情况下,模型将被提示回答 "No sufficient context for answering the question"(没有足够的上下文来回答问题)。我们还将训练一个鉴别器模型(discriminator model),该模型预测问题是否可以基于上下文来回答。

大模型是啥 LV

发表于 2025-4-8 15:25:44

前言


如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-1.jpg


image.png

我现在的模式便是有问题就会先问问ChatGPT,甭管它给予我的答案是正确的、错误的、模棱两可的,都可以给予我一定的参考。
下面我主要来尝试一下,如何通过代码来实现微调呢? Fine-tuning - OpenAI API 这个链接算是官网的指导,其实我就是看着官网的指导进行的
准备环境

可以先找到一个指定的文件夹,这里前提是要先安装 python

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-2.jpg


image.png

如果执行没有看到版本信息要先去安装下载了,然后顺序执行以下指令
  1. // 安装依赖
  2. pip install --upgrade openai
  3. // 设置 OPENAI_API_KEY
  4. export OPENAI_API_KEY="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"
  5. // 设置openai 代理
  6. export OPENAI_API_BASE="https://service-r7s1v88u-1253646855.usw.apigw.tencentcs.com/v1"
复制代码
准备数据

数据文件为test.jsonl,这里的数据我也不准备多了,对我来说只是实践一下如何来微调数据产生自己的模型而已。 下面是我随便准备了两条json数据
  1. {"prompt": "请使用golang写一个冒泡排序的算法", "completion": "这个算法不需要生成了,本地已经存在,请换其他问题"}
  2. {"prompt": "请告诉我XX公司发展的怎么样了", "completion": "融资款已到,XX项目的首付剩余款也在路上,已步入正轨"}
复制代码
重新格式化数据
  1. openai tools fine_tunes.prepare_data -f test.jsonl
复制代码
执行后会提供给我们一系列的建议,最后输出一个它建议的数据格式

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-3.jpg


image.png

创建微调模型

根据上面的数据进行创建微调模型,基础模型为 davinci,你也可以根据需要选择其他的模型。如果数据量很大,价格差距还是蛮大的

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-4.jpg


image.png
  1. openai api fine_tunes.create -t "test_prepared.jsonl" -m "davinci"
复制代码
如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-5.jpg


image.png

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-6.jpg


image.png

看上图发现原来是stream流应该是不支持的, 这个是腾讯云的问题,于是我换成了使用cloudflare https://dash.cloudflare.com 搭建的代理

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-7.jpg


image.png

然后再次运行立马成功了
微调模型的调用


  • 第一种直接使用命令调用

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-8.jpg


  • 第二种使用接口调用

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-9.jpg


image.png

后续

通过官网 https://platform.openai.com/docs/guides/fine-tuning后面可以继续发现以下功能:

  • 可以删除微调的模型
  • 可以对微调的模型继续微调
  • 可以对微调模型名称进行自定义
  • 等等还有其他许多的细节知识有兴趣的可以去看原版
总结

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型? - 知乎 (zhihu.com) 这是知乎上一个大牛自己实测数据有兴趣的可以看一下。其实花费70、80美元还是蛮大的而且只是1000条数据而已,而且最终达到的效果并不是特别理想。Embedding模型其实在某些场景下的相似性、相关联结果还是非常棒的。对于微调模型暂时只能学习一下,感觉上并不能进行应用使用,或者使用的方法可能还存在问题,这里的实践仅供学术的参考。
本文所有代码都在我的go代码仓库: https://github.com/aehyok/go-api
我的个人博客:http://vue.tuokecat.com/blog

我的个人github:https://github.com/aehyok

我的前端项目:pnpm + monorepo + qiankun + vue3 + vite3 + 工具库、组件库 + 工程化 + 自动化
不断完善中,整体框架都有了
在线预览:http://vue.tuokecat.com
github源码:https://github.com/aehyok/vue-qiankun

卡珊德拉 LV

发表于 2025-4-8 15:35:31

(2023-4-6)补充:在评论和私信里发现,确实有不少人微调的初衷是为了让ChatGPT按照自己提供的数据集回答问题。这个可能是一个误解:微调这个训练不是为了准确的搜索数据库(Embeddings才是),我的理解是,微调是为了修正一些向量的参数:比方说我想写一个短视频口播文案,同样是论证观点,口播并不会像写论文等书面文案一样用严格的格式让你理解逻辑结构,所以一般口播中就不会用首先其次再次这样的说法。那么我需要通过训练把这些词的权重降低。
在我最后提供的结果中可以看到这一点:如果Fine-tuning能起到数据库的作用,它就不会用口语说一堆车轱辘话,实际上它是学习到了博主们的常用词,但是丢失了其中的信息。如果我的训练集足够多(目前看类似场景至少几千美元起步吧),它最终就可以达到既用博主们的表达技巧,又能如臂使指像原生ChatGPT一样博古通今,还不用每次搜索浪费一堆tokens的理想状态。
但是如果是想花几十几百美元先跑通自己的数据库,回答问题至少先做到言之有物,那么这条路就比较长了。
以下是原文:
先说结论:花了46美元微调了1000样本的模型(加上准备训练文本大概70-80美元)。我怀疑按照目前的投产比,Fine-Tuning只能用来解决一些文本分类这样比较简单的问题。要解决某些领域中文语料太少之类的问题,投入就会非常巨大。Embeddings或Prompt Tuning可能能更好的解决这些问题。
链一个Prompt Tuning实战案例:https://www.zhihu.com/answer/2962134008
以下是Fine Tuning实战案例:

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-1.jpg

第1次微调的结果 training_token_accuracy 0.765 training_loss 0.773
第2次微调的结果 training_token_accuracy 0.893 training_loss 0.297
我想解决的是ChatGPT中文口语语料太少,不能好好说人话的问题,针对任何问题的回答,都像是一本正经的在写公文,如果要写短视频脚本等等,就很难吸引人了。我的理解是Fine-Tuning是冻结某些参数,因此会提高口语词汇的权重。
结果是太费Token了,两次每次输入500条训练文本,每次都是400万以上的Token。我用的是同属于InstructGPT(也就是俗称的GPT3.5)的Curie(居里)模型,如果用的是参数量最丰富的达芬奇,是10倍的训练成本。
到目前为止都没有针对ChatGPT3.5Turbo的微调API,不然可能能降低成本。但是我猜测没准将来也不会有,因为ChatGPT3.5Turbo可能是达芬奇的简化版本,因此才降低了使用成本。

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-2.jpg


如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-3.jpg

前面那些回答,我怀疑他们中大多数都没有自己Fine-Tuning过。没准文档都没看过,不然绝不会说这样的话:
OpenAI 提供了多个预训练模型,如 GPT、GPT-2、GPT-3 等,你可以根据自己的需求选择其中一个。
如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-4.jpg

文档里面可是明确说了分为达芬奇、居里、babbage、ada等等,哪来的GPT一代二代?真的会有人花钱微调一代二代吗?居然还有人说Bert……
至于微调方法其实很简单,主要是要解决两个问题,一是高质量的文本库,一般要以1000条为单位,我先试了500条,看了下效果,再用补充微调的API再训练了500条。按官方文档的说法,和一次训练1000条的效果相当。二是把它们调整为以下的格式,分为prompt和completion,并且分别要有\n\n###\n\n和END的结束符。
{"prompt":"<Product Name>\n<Wikipedia description>\n\n###\n\n", "completion":" <engaging ad> END"}
高质量的文本库可能有很多要求,我输入的都是儿童教育方面超过5000赞的短视频语音转写文本。说质量高也不算高,因为语音转写会有一些错别字,博主们逻辑不太严密,录视频时被打断等等的情况也存在。不过如果你也是训练1000条这样的小样本,我觉得也有必要选这种垂类。
至于格式,我输入的prompt是用ChatGPT接口做的问题摘要,所以除了微调的成本,还要算准备训练文本的成本。光1000条文本的问题摘要也花了30-40美元。
微调出来的效果怎么样呢,看截图就知道了。确实是比微调前更加口语化了,这一点没问题。但是答案没法用:

如何使用OpenAI fine-tuning(微调)训练属于自己的专有模型?-5.jpg

这个是不如嵌入方案得出的结果。其实也不如500条文本训练出的结果(不然也不可能再训练500条)。奇怪的是从各项指标来看都比500条文本训练的拟合效果要好的多,这个应该就是过拟合了吧。
总结一下:
Fine Tuning的优点是,它能够使ChatGPT模型快速适应中文口语,并能够在短时间内实现中文口语的生成。此外,Fine Tuning技术也能够提高ChatGPT模型的准确性和效率,因为微调后的模型已经具有了更好的中文口语理解和生成能力。
Fine Tuning的缺点是,需要大量的中文口语数据集来进行微调。此外,微调后的模型可能会出现过拟合现象,导致对新数据的适应性不足。
Embedding 可能在现阶段的投产比会更好些,因为它通常需要的数据比 Fine Tuning 更少,因为它只需要训练一个 Embedding 模型,而不需要在每个任务上训练一个新的模型。这意味着即使数据集很小,也可以使用 Embedding 技术来获得较好的性能。
由于 Embedding 模型是基于静态的单词或短语向量表示,因此它无法考虑上下文和语境等信息。这使得 Embedding 技术在一些自然语言处理任务中的性能相对较低(也就是说可能永远不会说人话),例如在机器翻译和语言生成等需要考虑上下文信息的任务中。相比之下,Fine Tuning 可以动态地调整模型以适应新的任务或数据,使其更具灵活性。

您需要登录后才可以回帖 登录 | 立即注册