八、OpenAI之微调(Fine-tuning Two)

258 阅读13分钟

7 使用微调模型

当训练成功时,将看到fine_tuned_model字段中填充了检索训练详细信息时的模型名称。现在,可以在Chat Completions(适用于gpt-3.5-turbo)或遗留的Completions API(适用于babbage-002和davincii -002)中指定此模型作为参数,并使用Playground向其发出请求。 当训练完成后,模型就可以用来用作推理。在某些案例中,当使用模型处理请求,可能要花费几分钟。如果请求模型超时或未找到,可能模型还在加载中。可稍等几分钟后在试:

from openai import OpenAI
client = OpenAI()

completion = client.chat.completions.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)

8 使用检查点微调模型

除了在每个微调模型训练完成后产生一个最终的模型外,OpenAI还会在每个训练周期结束后创建一个完整模型的检查点。这些检查点本身就是完整的,能被使用到补全和聊天补全的端点中。这些检查点非常有用,因为它本质上可以为你提供一个在过拟合之前的微调版本。 怎样访问这些检查点:

  1. 在训练成功结束后,你可以通过查询训练状态进行成功与否验证
  2. 在微调训练结束后,你可以使用微调训练的ID来查询检查点的端来访问模型检查点列表

对于每一个检查点对象,你会看到用模型检查点的名字来填充fine_tuned_model_checkpoint.你可以像使用最终模型一样来使用此模型。

{
    "object": "fine_tuning.job.checkpoint",
    "id": "ftckpt_zc4Q7MP6XxulcVzj4MZdwsAB",
    "created_at": 1519129973,
    "fine_tuned_model_checkpoint": "ft:gpt-3.5-turbo-0125:my-org:custom-suffix:96olL566:ckpt-step-2000",
    "metrics": {
        "full_valid_loss": 0.134,
        "full_valid_mean_token_accuracy": 0.874
    },
    "fine_tuning_job_id": "ftjob-abc123",
    "step_number": 2000
}

每个检查点特有的:

  • step_number: 检查点被创建的步(其中每个epoch是训练集的步数除以批大小)
  • metrics: 一个对象,其中包含在创建检查点时的步骤中用于微调作业的指标 目前,只有作业的最后3个epoch的检查点被保存并可供使用。

9 分析微调模型

在整个训练过程中我们提供以下训练指标:

  • 训练的损失
  • 训练token的准确率
  • 验证的损失
  • 验证token的准确率 验证损失和验证token的准确率计算方式不同,前者是在每一步中用小批量的数据计算,后者是在每个epoch结束时的完全验证分割上。完全的验证损失和token的准确率指标是跟踪你的模型表现力最准确的指标。这些统计数据旨在提供一个完整的检查,以确保训练顺利进行(损失下降,token准确率上升)。当一个微调正在训练时,你可以查看事件对象中一些有用的指标:
{
    "object": "fine_tuning.job.event",
    "id": "ftevent-abc-123",
    "created_at": 1693582679,
    "level": "info",
    "message": "Step 300/300: training loss=0.15, validation loss=0.27, full validation loss=0.40",
    "data": {
        "step": 300,
        "train_loss": 0.14991648495197296,
        "valid_loss": 0.26569826706596045,
        "total_steps": 300,
        "full_valid_loss": 0.4032616495084362,
        "train_mean_token_accuracy": 0.9444444179534912,
        "valid_mean_token_accuracy": 0.9565217391304348,
        "full_valid_mean_token_accuracy": 0.9089635854341737
    },
    "type": "metrics"
}

在一个微调工作成之后,您还可以通过查询一个微调工作、从result_files中提取一个文件ID,然后检索该文件内容,来查看有关训练过程的指标。每个结果CSV文件都有以下列:step、train_loss、train_accuracy、valid_loss和valid_mean_token_accuracy。

step,train_loss,train_accuracy,valid_loss,valid_mean_token_accuracy
1,1.52347,0.0,,
2,0.57719,0.0,,
3,3.63525,0.0,,
4,1.72257,0.0,,
5,1.52379,0.0,,

虽然度量标准可以提供帮助,但是评估来自微调模型的样本可以提供最相关的模型质量感觉。我们建议在测试集上从基本模型和微调模型生成样本,并并排比较样本。理想情况下,测试集应该包括您可能在生产用例中发送给模型的输入的完整分布。如果手动评估太耗时,可以考虑使用我们的eval库来自动化未来的评估。

迭代数据质量 如果微调结果不如预期,考虑下边几种方式调整训练数据集:

  • 针对目标遗留的问题收集样本 如果模型在某些方面仍然不擅长,添加训练样例,直接向模型展示如何正确地做这些方面
  • 仔细检查已有样本的问题 如果您的模型有语法、逻辑或样式问题,请检查您的数据是否有相同的问题。例如,如果模型现在说“我将为你安排这个会议”(当它不应该这样做的时候),看看现有的例子是否教会模型说它可以做它不能做的新事情
  • 考虑数据的平衡和多样性 如果数据中60%的助理回答说“我不能回答这个问题”,但在推理时间只有5%的回答应该这么说,你可能会得到过多的拒绝
  • 确保你的训练样本包含你需要得到的反馈的所有信息 如果我们希望模型根据用户的个人特征来赞美他们,并且一个训练示例包括对之前对话中没有发现的特征的辅助赞美,那么模型可能会学习产生幻觉信息
  • 查看训练样本的一致性 如果多人创建训练数据,那么模型的性能很可能会受到人与人之间的一致/一致性水平的限制。例如,在文本提取任务中,如果人们只同意提取的片段的70%,那么模型可能无法做得比这更好
  • 确保你所有的训练样本符合推理所需的格式

迭代数据数量 一旦你对发布的样本质量满意,可以考虑增加训练样本的数量。这有助于模型更好的学习任务,特别是边缘案例。每增加一倍训练样本,我们期待有相同的改进。你可以粗略的估计增加数据集的增益通过下列内容:

  • 在当前数据集上微调
  • 在当前一半的数据集上微调
  • 观察两次微调的差距 通常你必须做出一个衡量,一个小批量高质量的数据集通常比一个大批低质量的数据集高效的多。

迭代超参数 我们允许你指定下面的超参:

  • 训练周期
  • 多个学习率
  • 数据批大小 我们推荐你在最初的训练中不要指定任何的超参,允许我们基于你的数据集选择默认的超参,如果你发现下面的情况可作调整:
  • 如果模型没有像预期的那样遵循训练数据,则将epoch的数量增加1或2
  • 如果模型的多样性低于预期,则将epoch的数量减少1或2
  • 如果模型表现出没有收敛,增加学习率倍数 你可以像下面设置超参数:
from openai import OpenAI
client = OpenAI()

client.fine_tuning.jobs.create(
  training_file="file-abc123", 
  model="gpt-3.5-turbo", 
  hyperparameters={
    "n_epochs":2
  }
)

10 微调模型例子

现在我们已经探索了一些微调的基本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的SDKs来完成,示例如下:

from openai import OpenAI
client = OpenAI()

file = client.files.create(
  file=open("marv.jsonl", "rb"),
  purpose="fine-tune"
)

client.fine_tuning.jobs.create(
  training_file=file.id,
  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的SDKs来完成,示例如下:

from openai import OpenAI
client = OpenAI()

file = client.files.create(
  file=open("sports-context.jsonl", "rb"),
  purpose="fine-tune"
)

client.fine_tuning.jobs.create(
  training_file=file.id,
  model="gpt-3.5-turbo"
)

一旦你训练完成就可以开始使用微调模型了,如下:

completion = client.chat.completions.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"
}

函数调用 function_call和functions已经被弃用,转而使用工具,然而,微调API此时仍然需要遗留格式。

11 微调集成

OpenAI为您提供了通过我们的集成框架将您的微调工作与第三方集成的能力。集成框架通常允许你追踪工作的阶段、状态、指标、超参数和其它关联工作的第3方系统信息。您还可以使用集成来触发第三方系统中基于作业状态变化的操作。目前,唯一支持的集成是权重和偏差,但很快就会有更多的集成。

权重和偏差集成 权重和偏差(W&B)对于追踪机器学习实验是一个常用的工具。你可以使用OpenAI集成框架的W&B追踪你的微调工作的W&B,框架会自动记录指标、超参数和指定的W&B项目的其他与工作相关的信息 用W&B整合你的微调工作,你需要做到:

  1. 向OpenAI提供您的权重和偏差帐户的身份验证凭证
  2. 当创建新的微调工作时配置W&B框架

通过OpenAI验证您的权重和偏差帐户 身份验证是通过向OpenAI提交有效的W&B API密钥来完成的。目前,只能通过账号面板完成,且只能是管理员账号。我们的W&B API密钥将加密存储在OpenAI中,并允许OpenAI在您的微调作业运行时代表您向W&B发布指标和元数据。在没有首先使用WandB验证OpenAI组织的情况下,试图在微调作业中启用W&B集成将导致错误。 在这里插入图片描述

启用权重和偏差集成 在创建新的微调作业时,您可以通过在作业创建请求的集成字段下包含一个新的“wandb”集成来启用W&B集成。这个集成允许您指定您希望新创建的W&B运行显示在下面的W&B项目。 下面是在创建新的微调作业时如何启用W&B集成的示例:

curl -X POST \\
    -H "Content-Type: application/json" \\
    -H "Authorization: Bearer $OPENAI_API_KEY" \\
    -d '{
    "model": "gpt-3.5-turbo-0125",
    "training_file": "file-ABC123",
    "validation_file": "file-DEF456",
    "integrations": [
        {
            "type": "wandb",
            "wandb": {
                "project": "custom-wandb-project",
                "tags": ["project:tag", "lineage"]
            }
        }
    ]
}' https://api.openai.com/v1/fine_tuning/jobs

默认情况下,运行ID和运行显示名是您的微调作业的ID(例如ftjob-abc123)。您可以通过在wandb对象中包含“name”字段来定制运行的显示名称。您还可以在wandb对象中包含一个“tags”字段,以便向W&B Run添加标签(标签必须是<= 64个字符串,最多有50个标签)。

有时,显式地将W&B实体设置为与运行相关联是很方便的。您可以通过在wandb对象中包含一个“entity”字段来实现这一点。如果不包含“entity”字段,则W&B实体将默认为与您之前注册的API密钥关联的默认W&B实体。

集成的完整规范可以在我们的微调作业创建文档中找到。 在权重和偏差中查看你的微调工作 创建启用了W&B集成的微调作业后,可以导航到作业创建请求中指定的W&B项目,从而在W&B中查看该作业。您的运行应该位于URL: wandb.ai/&lt;WANDB-E…

您应该看到一个新的运行,其中包含您在作业创建请求中指定的名称和标记。运行配置将包含相关的作业元数据,例如:

模型:你正在微调的模型 training_file:训练文件ID validation_file:验证文件的ID hyperparameters:作业使用的超参数(例如n_epochs, learning_rate, batch_size) seed:作业使用的随机种子 同样,OpenAI也会设置一些默认的标签,让你更容易搜索和过滤。这些标签将以“openai/”为前缀,并将包括:

openai/fine-tuning:标记,让您知道这次运行是一个微调工作 openai/ft-abc123:微调作业的ID openai/gpt-3.5-turbo-0125 ':您正在微调的模型 OpenAI微调作业生成的W&B运行示例如下: 在这里插入图片描述 微调作业的每个步骤的指标将被记录到W&B运行中。这些指标与微调作业事件对象中提供的指标相同,也与您可以通过OpenAI微调仪表板查看的指标相同。您可以使用W&B的可视化工具来跟踪您的微调作业的进度,并将其与您运行的其他微调作业进行比较。 记录到W&B运行的指标示例如下: 在这里插入图片描述