微调
了解如何为您的应用程序自定义模型。
简介
本指南针对新的OpenAI微调API的用户。如果您是旧版微调用户,请参阅我们的旧版微调指南。
微调允许您通过以下方式从API中获得的模型中获得更多价值:
-
比提示产生更高质量的结果
-
能够在更多的示例上进行训练,而不仅仅是提示中可以容纳的示例
-
由于提示更短,可以节省代币
-
更低延迟的请求
GPT模型已经在大量文本上进行了预训练。 为了有效地使用这些模型,我们在提示中包含说明,有时还包括几个示例。 使用演示来展示如何执行任务通常称为“few-shot学习”。
微调通过在比提示中可以容纳的更多示例上进行训练来改进 few-shot 学习,让您可以在大量任务上实现更好的结果。 一旦模型完成了微调,您就不需要在提示中提供那么多示例了。 这可以节省成本并实现更低延迟的请求。
在高层次上,微调涉及以下步骤:
-
准备并上传训练数据
-
训练新的微调模型
-
使用您的微调模型
请访问我们的定价页面以了解有关微调模型训练和使用的计费方式的更多信息。
可以微调哪些模型?
我们正在努力为GPT-4启用微调功能,预计今年晚些时候会推出此功能。
目前以下模型支持微调:
-
gpt-3.5-turbo-0613
(推荐) -
babbage-002
-
davinci-002
我们预计对大多数用户来说,gpt-3.5-turbo
在结果和易用性方面将是正确的模型,除非您正在迁移旧的微调模型。
何时使用微调
微调GPT模型可以使它们在特定应用中更出色,但它需要仔细投入时间和精力。我们建议您首先尝试通过提示工程、提示链(将复杂任务拆分为多个提示)和函数调用来获得良好的结果,主要原因如下:
-
对于许多任务,我们的模型在一开始可能似乎表现不佳,但通过更好的提示,我们可以取得更好的结果,可能不需要微调
-
与微调相比,提示和其他策略的迭代反馈循环要快得多,后者需要创建数据集和运行培训作业
-
在仍需要微调的情况下,最初的提示工程工作并不会被浪费 - 我们通常会在微调数据中看到最佳结果(或将提示链/工具使用与微调相结合)
我们的 GPT 最佳实践指南提供了一些在不进行微调的情况下获得更好性能的最有效策略和策略的背景。您可能会发现在我们的沙箱中快速迭代提示很有帮助。
常见使用案例
微调可以改进结果的一些常见用例:
-
设置样式、语气、格式或其他定性方面
-
提高产生所需输出的可靠性
-
纠正无法遵循复杂提示的失败
-
以特定方式处理许多边缘情况
-
执行新的难以在提示中阐述的技能或任务
思考这些情况的一种高层方法是,展示要比讲解更容易。在接下来的章节中,我们将探索如何为微调设置数据以及微调相对于基线模型如何改进性能的各种示例。
另一种微调有效的场景是通过使用更短的提示来减少成本和/或延迟,而不损害质量。如果您可以用GPT-4获得良好的结果,通过在GPT-4完成功能上进行微调,您通常可以使用微调的gpt-3.5-turbo
模型达到类似的质量,可能还使用缩短的指令提示。
准备数据集
一旦确定微调是正确的解决方案(即,您已尽可能优化了提示,并且模型仍存在问题),则需要为训练模型准备数据。您应该创建一组各种演示对话,这些对话与生产中的推断时要求模型响应的对话类似。
数据集中的每个示例都应该是与我们的Chat 完成 API 相同格式的对话,特别是消息列表,其中每个消息都有一个角色、内容和可选名称。至少有些培训示例应直接针对模型的建模行为与期望不符的情况,并且数据中提供的助手消息应该是您希望模型提供的理想响应。
示例格式
在此示例中,我们的目标是创建一个有时给出讽刺回答的聊天机器人,以下是我们可以为数据集创建的三个培训示例(对话):
{"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."}]}
{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who wrote 'Romeo and Juliet'?"}, {"role": "assistant", "content": "Oh, just some guy named William Shakespeare. Ever heard of him?"}]}
{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "How far is the Moon from Earth?"}, {"role": "assistant", "content": "Around 384,400 kilometers. Give or take a few, like that really matters."}]}
我们目前不支持函数调用示例,但正在努力支持这一功能。
对话聊天格式是对gpt-3.5-turbo
进行微调所必需的。 对于babbage-002
和davinci-002
,您可以遵循旧版微调中使用的提示完成对格式,如下所示。
{"prompt": "<prompt text>", "completion": "<ideal generated text>"}
{"prompt": "<prompt text>", "completion": "<ideal generated text>"}
{"prompt": "<prompt text>", "completion": "<ideal generated text>"}
制作提示
我们通常建议采用您发现在微调之前对模型工作最好的一组说明和提示,并将其包含在每个培训示例中。这应该使您能够达到最优秀和最普遍的结果,特别是如果您的数据量相对较少(例如低于一百个)。
如果您希望缩短每个示例中重复的说明或提示以节省成本,请记住,模型的行为可能与包含这些说明一样,在推理时可能很难让模型忽略这些“烘焙”说明。
完全是通过演示学习而没有指导说明,可能需要更多的培训示例才能获得良好的结果。
示例数建议
要微调模型,您需要至少提供10个示例。我们通常会看到从gpt-3.5-turbo
的50到100个精心设计的演示中进行微调可以明显改进,但具体数量因确切的用例而大不相同。
我们建议从50个精心设计的演示开始,看看模型在微调后是否显示出改进的迹象。在某些情况下,这可能就足够了,但即使模型还不适合投入生产,明显的改进也是一个良好的信号,表明提供更多数据将继续改进模型。没有改进表明您可能需要重新考虑如何为模型设置任务或重组数据,然后再扩展到有限的示例集之外。
训练和测试划分
收集初始数据集后,我们建议将其拆分为训练和测试部分。将包含训练和测试文件的作业提交进行微调时,我们将在整个培训过程中提供两者的统计信息。这些统计信息将是您的初步信号,表明模型正在改进的程度。此外,尽早构建测试集将对确保您能够通过在测试集上生成样本来评估模型训练后非常有用。
令牌限制
每个培训示例被限制为4096个令牌。比这更长的示例在训练时将被截断为前4096个令牌。为确保整个训练示例都在上下文中,请考虑检查消息内容中的总令牌计数是否少于4000。每个文件当前限制为50 MB。
您可以使用我们的令牌计数笔记本从OpenAI cookbook计算令牌计数。
估计成本
为了估计微调作业的成本,请参阅定价页面了解每1000个令牌的成本细节。要估计特定微调作业的成本,请使用以下公式:
每1000个令牌的基本成本 x 输入文件中的令牌数 x 训练的周期数
对于经过3个周期训练的具有10万个令牌的培训文件,预计成本约为2.40美元。
检查数据格式
在编译数据集并在创建微调作业之前,检查数据格式非常重要。为此,我们创建了一个简单的Python脚本,您可以使用它来查找潜在错误、查看令牌计数并估计微调作业的成本。
数据格式脚本
一旦验证了数据,文件就需要上传以便在微调作业中使用:
openai.File.create(
file=open("mydata.jsonl", "rb"),
purpose='fine-tune'
)
创建微调模型
确保数据集的数量和结构正确后,并上传了文件,下一步是创建微调作业。
使用OpenAI SDK启动微调作业:
import os
import openai
openai.api_key = os.getenv("OPENAI_API_KEY")
openai.FineTuningJob.create(training_file="file-abc123", model="gpt-3.5-turbo")
model
是您要开始的模型名称(gpt-3.5-turbo
、babbage-002
或davinci-002
)。您可以使用后缀参数自定义微调模型的名称。
开始微调作业后,完成可能需要一些时间。您的作业可能排在我们系统中的其他作业后面,根据模型和数据集大小,训练模型可能需要几分钟或几小时。 模型培训完成后,创建微调作业的用户将收到电子邮件确认。
除了创建微调作业之外,您还可以列出现有作业、检索作业状态或取消作业。
# 列出10个微调作业
openai.FineTuningJob.list(limit=10)
# 检索微调状态
openai.FineTuningJob.retrieve("ft-abc123")
# 取消作业
openai.FineTuningJob.cancel("ft-abc123")
# 从微调作业列出最多10个事件
openai.FineTuningJob.list_events(id="ft-abc123", limit=10)
# 删除微调模型(必须是创建模型的组织的所有者)
import openai
openai.Model.delete("ft-abc123")
使用微调模型
当作业成功时,在检索作业详细信息时,您会看到fine_tuned_model
字段填充了模型名称。 现在,您可以在Chat 完成(用于 gpt-3.5-turbo
)或旧版完成功能 API(用于babbage-002
和davinci-002
)中指定此模型作为参数,并使用沙箱对其进行请求。
完成作业后,该模型应该可以立即用于推理。 在某些情况下,模型准备好处理请求可能需要几分钟时间。 如果对模型的请求超时或找不到模型名称,这很可能是因为您的模型仍在加载中。 如果出现这种情况,请过几分钟后重试。
import os
import openai
openai.api_key = os.getenv("OPENAI_API_KEY")
completion = openai.ChatCompletion.create(
model="ft:gpt-3.5-turbo:my-org:custom_suffix:id",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Hello!"}
]
)
print(completion.choices[0].message)
您可以通过如上所示以及我们的 GPT 指南中所示传入模型名称来发出请求。
分析微调模型
我们提供了在培训过程中计算的以下培训指标:训练损失、训练令牌准确性、测试损失和测试令牌准确性。这些统计数据旨在提供参考,以验证培训是否顺利进行(损失应减少,令牌准确性应增加)。
但是,我们认为从微调模型中生成样本对模型质量的感知最为相关。 我们建议在测试集上从基础模型和微调模型生成样本,并将样本并排比较。 测试集应该理想情况下包括您可能在推理时发送给模型的全部输入分布。 如果手动评估过于耗时,请考虑使用我们的 Evals 库来了解如何使用GPT-4进行评估。
迭代数据质量
如果微调作业的结果不如预期,请考虑调整培训数据集的以下方法:
-
收集示例以针对剩余问题
- 如果模型在某些方面仍不出色,请添加直接展示模型如何正确执行这些方面的培训示例
-
仔细检查现有示例中的问题
- 如果您的模型具有语法、逻辑或风格问题,请检查数据中是否存在任何相同的问题。例如,如果模型现在说“我会为您安排这次会议”(但不应该说它可以做的新事情),请查看是否有现有示例教模型说它可以做一些它无法做的事情
-
考虑数据的平衡性和多样性
- 如果数据中的60%的助手响应都说“我不能回答这个问题”,但在推理时只有5%的响应应该这样说,您可能会获得过剩的拒绝
-
确保您的培训示例包含生成响应所需的所有信息
- 如果我们希望模型根据他们的个人特征来夸奖用户,并且培训示例包含对先前对话中未找到的特征的助手赞美,则模型可能会输出幻觉信息。
-
查看培训示例中的协议/一致性
- 如果多个人创建了培训数据,模型性能将受到人与人之间协议/一致性水平的限制。例如,在文本提取任务中,如果人们只针对70%的提取片段达成一致,模型很可能无法做得更好。
-
确保所有培训示例的格式与预期的推理格式相同
迭代数据数量
一旦您对示例的质量和分布感到满意,可以考虑扩大培训示例的数量。这通常有助于模型更好地学习任务,特别是在可能的“边缘案例”方面。我们预计每次将培训数据量加倍,都会获得类似的质量提升。您可以通过以下粗略方法估计增加培训数据量的预期质量收益:
-
在当前数据集上进行微调
-
在当前数据集的一半上进行微调
-
比较这两者之间的质量差距
一般来说,如果您必须在质量和数量之间作出选择,较少的高质量数据通常比大量的低质量数据更有效。
迭代超参数
我们允许您指定微调模型的周期数。我们建议首先进行培训,不指定周期数,允许我们根据数据集大小为您选择默认值,然后在观察到以下情况时进行调整:
- 如果模型没有像预期的那样遵循培训数据,请将周期数增加1或2
- 这更常见于存在单一理想完成(或一组相似的理想完成)的任务。一些示例包括分类、实体提取或结构化解析。这些通常是您可以针对参考答案计算最终精度指标的任务。
- 如果模型的多样性比预期的要小,请将周期数减少1或2
- 这更常见于存在广泛可能的良好完成的任务。
微调示例
现在我们已经探讨了微调API的基础知识,让我们看看几个不同用例的微调生命周期。
风格和语气
在此示例中,我们将探索如何构建微调模型,以超越提示所能实现的方式遵循特定的风格和语气指导。
首先,我们创建一组消息示例,显示模型应做什么,在这种情况下是拼写错误的单词。
{"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."}]}
{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who wrote 'Romeo and Juliet'?"}, {"role": "assistant", "content": "Oh, just some guy named William Shakespeare. Ever heard of him?"}]}
{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "How far is the Moon from Earth?"}, {"role": "assistant", "content": "Around 384,400 kilometers. Give or take a few, like that really matters."}]}
如果您想要遵循并自己创建微调模型,您至少需要10个示例。
在获取可能改进模型的数据后,下一步是检查数据是否满足所有格式要求。
现在我们已经格式化并验证了数据,最后一步培训是启动作业以创建微调模型。您可以通过OpenAI CLI或我们的一个SDK完成此操作,如下所示:
openai.File.create(file=open("marv.jsonl", "rb"), purpose='fine-tune')
openai.FineTuningJob.create(training_file="file-abc123", model="gpt-3.5-turbo")
训练作业完成后,您将能够使用微调模型。
结构化输出
另一种非常适合微调的用例是让模型提供有关体育新闻标题的结构化信息:
{"messages": [{"role": "system", "content": "Given a sports headline, provide the following fields in a JSON dict, where applicable: "player" (full name)", "team", "sport", and "gender".},{"role": "user", "content": "Sources: Colts grant RB Taylor OK to seek trade"},
{"role": "assistant", "content": "{"player": "Jonathan Taylor", "team": "Colts", "sport": "football", "gender": "male" }"},]}
{"messages": [{"role": "system", "content": "Given a sports headline, provide the following fields in a JSON dict, where applicable: "player" (full name)", "team", "sport", and "gender".},{"role": "user", "content": "OSU 'split down middle' on starting QB battle"},
{"role": "assistant", "content": "{"player": null, "team": "OSU", "sport": "football", "gender": null }"},]}
如果您要遵循并自己创建微调模型,您至少需要10个示例。
在获取可能改进模型的数据之后,下一步是检查数据是否满足所有格式要求。
现在我们已经格式化并验证了数据,最后一步培训是启动作业以创建微调模型。您可以通过OpenAI CLI或我们的一个SDK完成此操作,如下所示:
openai.File.create(file=open("sports-context.jsonl", "rb"), purpose='fine-tune')
openai.FineTuningJob.create(training_file="file-abc123", model="gpt-3.5-turbo")
训练作业完成后,您将能够使用微调模型并发出如下请求:
import os
import openai
openai.api_key = os.getenv("OPENAI_API_KEY")
completion = openai.ChatCompletion.create(
model="ft:gpt-3.5-turbo:my-org:custom_suffix:id",
messages=[
{"role": "system", "content": "Given a sports headline, provide the following fields in a JSON dict, where applicable: player (full name), team, sport, and gender"},
{"role": "user", "content": "Richardson wins 100m at worlds to cap comeback"}
]
)
print(completion.choices[0].message)
根据格式化的培训数据,响应应如下所示:
{"player": "Sha'Carri Richardson", "team": null", "sport": "track and field", "gender": "female"}
旧版模型迁移
对于从/v1/fine-tunes
迁移到更新的/v1/fine_tuning/jobs
API和较新模型的用户,您可以期望注意到的主要区别是更新的API。保留了旧版提示完成对格式,以确保顺利过渡到更新的babbage-002
和davinci-002
模型。新模型将支持带有4k个令牌上下文的微调,并且知识截止日期为2021年9月。
对于大多数任务,您应该期望从gpt-3.5-turbo
获得比从GPT基本模型获得更好的性能。
常见问题
我应该使用微调还是带检索的嵌入?
检索的嵌入最适合需要具有相关上下文和信息的大型文档数据库的情况。
默认情况下,OpenAI的模型经过训练,可作为有用的通用助手。微调可用于创建专门针对特定用途的模型,并展示特定的内在行为模式。检索策略可用于在生成响应之前为模型提供相关上下文,从而为模型提供新信息。检索策略不是微调的替代方法,实际上两者可以互为补充。
我什么时候可以微调GPT-4或GPT-3.5-Turbo-16k?
我们计划在今年晚些时候发布对这两种模型的微调支持。
我如何知道微调后的模型实际上比基础模型好?
我们建议在测试聊天对话集上从基础模型和微调模型生成样本,并并排比较这些样本。 对于更全面地评估,请考虑使用 OpenAI评估框架根据您的具体用例创建评估。
我可以继续微调已经微调过的模型吗?
不,我们目前不支持在作业完成后继续微调过程。我们计划在不久的将来支持这一功能。
我如何估计微调模型的成本?
请参阅上述估计成本部分。
新的微调端点是否仍然与Weights&Biases集成以跟踪指标?
不,我们目前不支持此集成,但正在努力在不久的将来启用它。
我可以同时运行多少个微调作业?
有关最新的信息,请参阅我们的速率限制指南。