7月18日发布的新模型GPT-4o-mini有着超越GPT-3.5、接近GPT-4的性能,且价格只用GPT-3.5的一半,响应速度也是全系列模型最快的。OpenAI于今天正式开放了GPT-4o-mini的微调接口,在2024年9月23日前,每天有2M token免费额度。
不是Llama 3.1 405B玩不起,而是GPT-4o-mini更有性价比。
1 微调适用场景
对于一般的简单任务,只需要编写提示词(Prompting),模型就能很好地完成。如果任务比较复杂,可以尝试使用思维链(Chain of Thought)将复杂任务分解为多个步骤,并逐步推理。但对于需要高精度和一致性输出的任务,就需要进行微调(Fine-tuning)。
下面的表格对比了这三种办法的优缺点以及应用场景。
| 方法 |
优点 |
缺点 |
应用场景 |
| 微调 |
提供高质量结果 |
需要大量时间和资源来准备和训练数据 |
需要稳定、可靠和高质量的输出 |
|
适用于复杂任务和特定领域的定制 |
反馈循环较慢,训练成本高 |
改进模型在特定任务或领域的性能 |
|
节省Token,降低延迟 |
有深度学习基础知识作为门槛 |
任务需要高精度或独特的风格、语气、格式时 |
| 提示词 |
快速迭代和测试 |
依赖于提示词的设计质量 |
常见任务的快速原型和测试 |
|
适合初始探索和一般任务 |
对复杂任务可能不够准确 |
需要灵活调整模型输出时 |
|
无需额外数据准备和训练资源 |
|
不适合大量示例和复杂逻辑的任务 |
| 思维链 |
提供分步骤逻辑和推理 |
增加了提示的复杂性和长度 |
处理需要推理和逻辑步骤的任务 |
|
改善复杂任务的性能 |
增加了Token使用量和延迟 |
涉及多步骤解决问题的场景 |
|
易于结合多种策略和工具 |
对非常复杂的任务可能仍不够 |
需要明确逻辑流程和分步执行时 |
NFL定理告诉我们,没有哪种方法能适用于所有场景,这里也是一样,微调也不一定就比另外两种方法更好。但可以明确的是,微调适用于那些“难以描述的任务”,比如一种风格和语气。此外,这三种方法也并不是水火不容,微调模型使用精心设计的提示词、甚至结合思维链,说不定能达到更好的结果。
只是简单地写一篇文章或段落,提示词就够了。但一篇博客文章,如果考虑SEO的话,就会有很多细节,例如核心关键词出现频率等。这些细节大模型不一定能尽数理解,且作为用户也不一定能很好地在提示词中进行描述。因此撰写一篇这样的博客文章就可以使用微调。
2 准备数据
数据需要以jsonl的格式组织,每一行是一个json。例如:
1
2
3
|
{"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."}]}
|
也可以在多轮对话中设置权重,weight取0表示让模型规避这种回答。
1
2
3
|
{"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", "weight": 0}, {"role": "user", "content": "Can you be more sarcastic?"}, {"role": "assistant", "content": "Paris, as if everyone doesn't know that already.", "weight": 1}]}
{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who wrote 'Romeo and Juliet'?"}, {"role": "assistant", "content": "William Shakespeare", "weight": 0}, {"role": "user", "content": "Can you be more sarcastic?"}, {"role": "assistant", "content": "Oh, just some guy named William Shakespeare. Ever heard of him?", "weight": 1}]}
{"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": "384,400 kilometers", "weight": 0}, {"role": "user", "content": "Can you be more sarcastic?"}, {"role": "assistant", "content": "Around 384,400 kilometers. Give or take a few, like that really matters.", "weight": 1}]}
|
当然,处理数据是最耗时的,这里也可以直接使用我制作的数据集。该数据集用于对大模型进行微调,来源于对 reads.alibaba.com 网站中13个分类领域的3000+个页面的抓取,开源的不只有处理后的数据,也有原始数据以及爬虫代码。
将准备好的数据上传,记录返回的文件ID.
1
2
3
4
5
6
7
|
from openai import OpenAI
client = OpenAI()
client.files.create(
file=open("all_filter_2120.jsonl", "rb"),
purpose="fine-tune"
)
|
3 微调模型
准备好数据、验证无误、确认token成本后,即可创建微调任务
1
2
3
4
5
6
7
|
from openai import OpenAI
client = OpenAI()
client.fine_tuning.jobs.create(
training_file="file-zWptPbsD37ZnemssjpsK6CnF",
model="gpt-4o-mini"
)
|
这一步更详细的参数配置可以参考官方API文档。

上面这两步也可以在UI界面快速完成,提交任务后,也可以在UI界面实时查看进度和损失变化。

4 调用模型
通过下面的代码查询微调任务状态,作业成功后,就能看到fine_tuned_model字段填充了模型的名称。记下此名称,就可以进行调用了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
from openai import OpenAI
client = OpenAI()
# 查询微调任务列表
client.fine_tuning.jobs.list(limit=10)
# 查询微调任务详情
client.fine_tuning.jobs.retrieve("ftjob-gvP0VB7RlWcF3QHdQrEVf49Y")
# 取消任务
client.fine_tuning.jobs.cancel("ftjob-gvP0VB7RlWcF3QHdQrEVf49Y")
# 查看任务中的日志
client.fine_tuning.jobs.list_events(fine_tuning_job_id="ftjob-gvP0VB7RlWcF3QHdQrEVf49Y", limit=10)
# 删除微调模型
client.models.delete("ft:gpt-3.5-turbo:acemeco:suffix:abc123")
|
调用方式跟官方的模型是一样的,只需要修改一个模型名称就可以了,例如:
1
2
3
4
5
6
7
8
9
10
11
|
from openai import OpenAI
client = OpenAI()
completion = client.chat.completions.create(
model="ft:gpt-4o-mini-2024-07-18:personal:0724:9oMH6S7A",
messages=[
{"role": "system", "content": "Please write an SEO article of no less than 800 words based on the title I gave you, including at least 4 subtitles by HTML format. Do not include the <h1> , <body> tag. Do not include the <html> tag in the start and end of the content. Directly start with the content."},
{"role": "user", "content": f"title:{task.title},core keyword:{task.coreKeywords},related keyword:{task.relatedKeywords}"}
]
)
print(completion.choices[0].message)
|
5 评估结果
训练过程中有两个指标可供参考,分别是损失值和Token准确率,官方解释如下:
验证损失和验证Token准确率通过两种不同的方式计算——在每一步期间的一个小批量数据上计算,以及在每个Epoch结束时的整个验证集上计算。整个验证损失和整个验证Token准确率指标是追踪模型总体性能的最准确指标。这些统计数据旨在提供一个合理性检查,以确保训练顺利进行(损失应该减少,Token准确率应该增加)。
但指标毕竟只是参考,实际效果还是要自己评估。微调后的模型至少有以下提升:
- 文章篇幅增长20%
- 文章结构更接近训练的数据
- 不会再出现格式错误(如markdown格式、添加css等)
以"What is the Difference Between a Mural and a Mosaic?“为题生成的文章如下:

6 参考文章