微调GPT-4o-Mini生成博客文章

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文档

OpenAI 微调UI

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

OpenAI 微调过程日志

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 参考文章

Buy me a coffee~
Tim 支付宝支付宝
Tim 贝宝贝宝
Tim 微信微信
0%