通过


你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

自定义具有微调功能的模型

了解如何为数据集和用例微调 Microsoft Foundry 中的模型。 启用微调功能:

  • 结果质量比从提示设计中获取的质量更高。
  • 能够在超出模型请求上下文限制的示例上进行训练。
  • 由于提示更短而节省令牌。
  • 较低的延迟请求,尤其是在使用较小的模型时。

与少量示例学习相比,微调通过在超过提示容量的更多示例上训练模型来改善模型性能。 由于权重适合你的任务,因此你包含的示例或说明更少。 减少包含的内容会降低每次调用的令牌数,并可能减少成本和延迟。

我们使用低级别适应(LoRA)来微调模型,以降低其复杂性的方式,而不会显著影响其性能。 此方法的工作原理是将原始高排名矩阵近似于排名较低的矩阵。 在监督训练阶段微调较小的重要参数子集,使模型更易于管理和高效。 对于用户来说,它还使培训比其他技术更快、更实惠。

在这篇文章中,你将学会如何:

  • 选择适当的数据集和格式进行微调。
  • 触发微调作业、监视状态并提取结果。
  • 部署和评估微调的模型。
  • 不再需要时,请清理资源。

先决条件

支持的模型

若要检查哪些区域当前支持微调,请参阅 有关模型的文章

你也可以微调以前已微调的模型,格式为 base-model.ft-{jobid}

准备数据

你的训练和验证数据集包含希望模型执行方式的输入和输出示例。

使用的训练和验证数据 必须 格式化为 JSON 行(JSONL)文档。 它还必须采用聊天完成 API 使用的对话格式。

除 JSONL 格式外,训练和验证数据文件必须以 UTF-8 编码并包含字节顺序标记 (BOM)。 每个文件的大小必须小于 512 MB。

建议使用您发现对每个训练示例效果最好的说明和提示。 此方法可帮助你获得最佳结果,尤其是在只有不到一百个示例的情况下。

如果没有准备好现有数据集,可以使用 数据生成 功能创建新的数据集。

示例文件格式

{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who discovered Antarctica?"}, {"role": "assistant", "content": "Some chaps named Fabian Gottlieb von Bellingshausen and Mikhail Lazarev, as if they don't teach that in every school!"}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What is the biggest ocean?"}, {"role": "assistant", "content": "The Pacific Ocean. It's not like it's a small pond or anything."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What is the largest planet?"}, {"role": "assistant", "content": "It's called Jupiter, you might have heard of it...or not."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who painted the Mona Lisa?"}, {"role": "assistant", "content": "Oh, some obscure artist named Leonardo da Vinci. Not that he is famous or anything."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the boiling point of water?"}, {"role": "assistant", "content": "Exciting fact of the day: it's 100 degrees Celsius. Life-changing, isn't it?"}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who wrote 'The Odyssey'?"}, {"role": "assistant", "content": "Oh, just some poet named Homer. Nothing special, really."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What is the largest mammal?"}, {"role": "assistant", "content": "Blue Whale. Quite a big fish isn't it? Oh wait, it's not a fish!"}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the highest mountain peak?"}, {"role": "assistant", "content": "Everest. Brace yourself, it's not a walk in the park."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who invented the telephone?"}, {"role": "assistant", "content": "A guy named Alexander Graham Bell. Bet you didn't guess that one!"}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What is the distance from Earth to the Sun?"}, {"role": "assistant", "content": "About 93 million miles. Just a quick drive, really."}]}

多轮聊天文件格式

还支持在 JSONL 训练文件的单个行中进行多轮对话。 若要跳过对特定助理消息的微调,请添加可选的 weight 键/值对。 目前, weight 可以设置为 01

{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the biggest city in 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}]}

使用视觉的聊天补全

{"messages": [{"role": "user", "content": [{"type": "text", "text": "What's in this image?"}, {"type": "image_url", "image_url": {"url": "https://raw.githubusercontent.com/MicrosoftDocs/azure-ai-docs/main/articles/ai-services/openai/media/how-to/generated-seattle.png"}}]}, {"role": "assistant", "content": "The image appears to be a watercolor painting of a city skyline, featuring tall buildings and a recognizable structure often associated with Seattle, like the Space Needle. The artwork uses soft colors and brushstrokes to create a somewhat abstract and artistic representation of the cityscape."}]}

数据集大小注意事项

训练示例越多越好。 如果没有至少 10 个训练示例,则微调作业不会继续,但这样一小部分不足以显著影响模型响应。 成功微调的最佳做法是提供数百个训练示例(如果不是数千个)。 建议从 50 个精心制作的示例开始。

通常,将数据集大小加倍会促使模型质量呈线性增长。 但请记住,低质量的示例可能会对性能产生负面影响。 如果在没有先筛选出最高质量示例的情况下使用大量内部数据训练模型,你的模型性能可能会低于预期。

创建微调模型

若要微调现有 Foundry 项目中的模型,请执行以下步骤:

  1. 登录到 Foundry 并选择项目。 如果你没有项目,请先创建一个项目

  2. 转到“ 生成>微调 ”页,然后选择右上角的 “微调 ”按钮。

  3. 现在应会看到 微调模型 界面,用于创建新的微调任务。 使用以下部分来帮助配置作业,然后选择 “提交 ”开始训练新的微调模型。

基础模型选择

项目区域可能会限制可用的模型。 选择模型会影响模型的性能和成本。

还可以选择以前经过微调的模型。

自定义方法

支持的自定义方法取决于所选模型:

  • 监督微调 (SFT):在带标签的输入/输出对上训练模型。 最适合大多数场景,包括任务专业化。

  • 直接首选项优化(DPO):将模型与人工首选响应保持一致。 非常适合提高响应质量。

  • 强化微调(RFT):使用模型分级器的奖励信号来优化复杂行为。

注释

本文的其余部分介绍 SFT 方法的步骤。 有关特定于其他自定义方法的说明,请参阅 DPO 指南RFT 指南

训练类型

根据用例和预算选择训练层:

  • 标准:训练发生在当前 Foundry 资源的区域中,并提供数据驻留的保证。 非常适合数据必须驻留在特定区域的工作负载。

  • 全球:通过使用超出当前区域的容量,提供比标准更实惠的定价。 数据和权重被复制到训练发生的区域。 非常适合数据驻留不是限制,并且需要更快队列时间的情况。

  • 开发人员(预览版):使用空闲容量进行培训,可节省大量成本。 没有延迟或 SLA 保证,因此此等级的作业可能会被自动抢占并稍后恢复。 数据驻留也没有保证。 非常适合实验和具有价格敏感性的工作负载。

训练和验证数据

如果 Foundry 项目中存在现有数据集,请为数据源选择现有数据集,然后选择您的数据集。

若要上传新准备的数据集,请选择“上传数据源的新数据集”,然后上传 JSONL 文件。

选择或上传数据文件后,会自动进行验证检查,以确认文件的格式为 JSONL,使用 BOM 在 UTF-8 中编码,且大小小于 512 MB。

可选参数

Suffix

我们建议你提供后缀值,以便更容易区分微调模型的不同迭代。 后缀采用最多 18 个字符的字符串,用于命名生成的微调模型。

Seed

种子控制作业的可重现性。 传入相同的种子和任务参数应产生相同的结果,但在极少数情况下可能会有所不同。 如果未指定种子,则会随机生成一个种子。

超参数

可以为微调作业手动配置超参数,或将其保留为默认值。

以下超参数可用:

Name 类型 DESCRIPTION
batch_size 整数 要用于训练的批大小。 批大小表示用于训练单个前向和后向传递的训练示例的数量。 一般情况下,我们发现较大的批大小往往更适用于较大的数据集。

此属性的默认值和最大值特定于基础模型。 批大小越大意味着模型参数的更新频率越低,但方差越小。 当值设置为 -1时,批大小将计算为训练集中的示例的 0.2%。 最大值为 256.
learning_rate_multiplier Number 用于训练的学习率乘数。 微调学习率是用于预训练的原始学习率乘以此值。

较大的学习率通常在较大的批大小中表现更好。 建议试验范围从 0.020.2 的值,以查看哪个能产生最佳结果。 较小的学习率可以用于避免过度拟合。
n_epochs 整数 训练模型的时期数。 一个时期是指训练数据集的一个完整周期。 如果该值设置为 -1,则根据输入数据动态确定纪元数。

自动部署

重要

对于自动部署,需要 Azure AI 所有者 角色或任何具有该操作的角色 Microsoft.CognitiveServices/accounts/deployments/write

为节省时间,可以为生成的模型启用自动部署。 如果训练成功完成,则会根据所选部署类型部署模型。 部署名称基于为自定义模型生成的唯一名称以及你可能之前提供的可选后缀。

仅 OpenAI 模型支持自动部署。

监视和分析结果

提交微调作业后,表格视图会列出微调作业的所有提交项。 若要查看有关单个结果的详细信息,请打开 “作业详细信息 ”页。

你的作业可能排在系统上的其他作业后面。 训练模型可能需要几分钟到几小时的时间,具体取决于模型和数据集大小。

Metrics

可以通过转到"监视器"选项卡来监控以下指标:

  • train_loss: 训练批次的损失值。 X 轴上的每个训练步代表针对一批训练数据进行的一次前向和后向传递。

  • full_valid_loss:在每个纪元结束时计算的验证损失。 训练正常时,损失应减少。

  • train_mean_token_accuracy:模型在训练批处理中正确预测的令牌的百分比。

    例如,当批量大小设置为3,且数据中包含完成品[[1, 2], [0, 5], [4, 2]]时,如果模型预测为0.83,那么该值将被设置为[[1, 1], [0, 5], [4, 2]](6分之5)。

  • full_valid_mean_token_accuracy: 在每个训练周期结束时计算的有效平均令牌准确率。 训练正常时,标记准确性应增加。

随着时间的推移,损失会减少,而准确度提高。 如果你的训练数据和验证数据出现偏差,可能存在过拟合情况。 尝试使用更少的时期或较小的学习率乘数进行训练。

检查站

每个训练时期完成后,将生成一个检查点。 可以通过转到 检查点 选项卡来查看检查点。

检查点是模型的一种完全可运行版本,可以被部署并用作随后的微调作业的目标模型。 检查点尤其有用,因为它们可能提供过拟合前的快照。 微调作业完成后,可以使用三个最新版本的模型进行部署。 可以通过 REST API 在资源和订阅之间复制检查点。

注释

在训练期间,可以查看指标并根据需要暂停作业。 如果指标不聚合,或者认为模型没有以正确的速度学习,暂停可能会很有用。 暂停训练作业时,安全评估完成后会创建可部署的检查点。 此检查点可用于部署并进行推理,或者您可以恢复任务以将其完成。

暂停操作仅适用于经过至少一个步骤的训练且处于 “正在运行” 状态的任务。 仅 OpenAI 模型支持暂停。

部署微调模型

重要

若要部署模型,您需要 Azure AI 所有者 角色或任何具有该 Microsoft.CognitiveServices/accounts/deployments/write 操作的角色。

如果对微调作业中的指标感到满意,可以通过在详细信息页上选择“ 部署 ”按钮,然后配置部署设置来部署模型。

有关详细信息,请参阅 微调部署指南

使用部署的微调模型

部署优化后的模型后,可以像使用任何其他已部署的模型一样使用它。 你可以在 Foundry 的游乐场中对新的部署进行实验。 还可以使用 REST API 从自己的应用程序调用微调模型。 你甚至可以开始在提示流中使用此新的微调模型来生成你的生成式 AI 应用程序。

注释

对于聊天模型,用于指导微调模型的系统消息(无论是已部署还是在游乐场中可测试)必须与训练时使用的系统消息相同。 如果使用其他系统消息,则模型可能无法按预期执行。

执行连续微调

创建经过微调的模型后,可能需要通过进一步微调以继续改进模型。 持续微调是选择已经微调的模型作为基础模型并在新的训练示例集上进一步对其进行微调的迭代过程。

若要对以前微调的模型执行微调,请使用“ 创建微调模型”中所述的相同过程。 但是,无需指定泛型基础模型的名称,而是指定已微调的模型。 自定义微调模型如下所示 gpt-4o-2024-08-06.ft-d93dda6110004b4da3472d96f4dd4777-ft

仅 OpenAI 模型支持连续微调。

清理资源

当你不再需要微调模型时,可以删除该部署和模型。 如有必要,还可以删除上传到服务的训练和验证文件。

删除微调模型部署

重要

部署自定义模型后,如果部署随时保持非活动状态超过 15 天,则会删除部署。 如果模型部署了 15 天以上,并且连续 15 天期间未进行聊天完成或响应 API 调用,则自定义模型的部署处于 非活动 状态。

删除非活动部署不会删除或影响基础自定义模型。 可以随时重新部署自定义模型。

Azure OpenAI 在 Microsoft Foundry 模型定价中的描述,每个部署的自定义(微调)模型都会产生每小时托管费用,无论是否对模型进行聊天完成或响应 API 调用。 若要详细了解如何使用 Azure OpenAI 规划和管理成本,请参阅 规划和管理 Azure OpenAI 的成本

可以在 Foundry 门户中的 “生成>模型 ”页上删除优化模型的部署。

删除微调后模型

可以在 Foundry 门户中的 “微调 ”页上删除经过微调的模型。 选择要删除的微调模型,然后选择“ 删除”。

注释

如果微调模型具有现有部署,则无法删除它。 必须先 删除模型部署 ,然后才能删除优化后的模型。

先决条件

支持的模型

若要检查哪些区域当前支持微调,请参阅 有关模型的文章

你也可以微调以前已微调的模型,格式为 base-model.ft-{jobid}

审阅 Python SDK 的工作流

花点时间审阅将 Python SDK 与 Azure OpenAI 配合使用的微调工作流:

  1. 准备训练和验证数据。
  2. 选择基础模型。
  3. 上传训练数据。
  4. 训练新的自定义模型。
  5. 检查自定义模型的状态。
  6. 部署供使用的自定义模型。
  7. 使用自定义模型。
  8. (可选)分析自定义模型的性能和拟合度。

准备训练和验证数据

你的训练和验证数据集包含希望模型执行方式的输入和输出示例。

使用的训练和验证数据 必须 格式化为 JSON 行(JSONL)文档。 它还必须采用聊天完成 API 使用的对话格式。

除 JSONL 格式外,训练和验证数据文件必须以 UTF-8 编码并包含字节顺序标记 (BOM)。 每个文件的大小必须小于 512 MB。

如果需要微调 gpt-4o-mini-2024-07-18的分步演练,请参阅 Azure OpenAI 微调教程

示例文件格式

{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who discovered Antarctica?"}, {"role": "assistant", "content": "Some chaps named Fabian Gottlieb von Bellingshausen and Mikhail Lazarev, as if they don't teach that in every school!"}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What is the biggest ocean?"}, {"role": "assistant", "content": "The Pacific Ocean. It's not like it's a small pond or anything."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What is the largest planet?"}, {"role": "assistant", "content": "It's called Jupiter, you might have heard of it...or not."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who painted the Mona Lisa?"}, {"role": "assistant", "content": "Oh, some obscure artist named Leonardo da Vinci. Not that he is famous or anything."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the boiling point of water?"}, {"role": "assistant", "content": "Exciting fact of the day: it's 100 degrees Celsius. Life-changing, isn't it?"}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who wrote 'The Odyssey'?"}, {"role": "assistant", "content": "Oh, just some poet named Homer. Nothing special, really."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What is the largest mammal?"}, {"role": "assistant", "content": "Blue Whale. Quite a big fish, isn't it? Oh wait, it's not a fish!"}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the highest mountain peak?"}, {"role": "assistant", "content": "Everest. Brace yourself, it's not a walk in the park."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who invented the telephone?"}, {"role": "assistant", "content": "A guy named Alexander Graham Bell. Bet you didn't guess that one!"}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What is the distance from Earth to the Sun?"}, {"role": "assistant", "content": "About 93 million miles. Just a quick drive, really."}]}

多轮聊天文件格式

还支持在 JSONL 训练文件的单个行中进行多轮对话。 若要跳过对特定助理消息的微调,请添加可选的 weight 键/值对。 目前, weight 可以设置为 01

{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the capital/major city 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}]}

使用视觉的聊天补全

{"messages": [{"role": "user", "content": [{"type": "text", "text": "What's in this image?"}, {"type": "image_url", "image_url": {"url": "https://raw.githubusercontent.com/MicrosoftDocs/azure-ai-docs/main/articles/ai-services/openai/media/how-to/generated-seattle.png"}}]}, {"role": "assistant", "content": "The image appears to be a watercolor painting of a city skyline, featuring tall buildings and a recognizable structure often associated with Seattle, like the Space Needle. The artwork uses soft colors and brushstrokes to create a somewhat abstract and artistic representation of the cityscape."}]}

创建训练和验证数据集

训练示例越多越好。 如果没有至少 10 个训练示例,则微调作业不会继续,但这样一小部分不足以显著影响模型响应。 成功微调的最佳做法是提供数百个训练示例(如果不是数千个)。

通常,将数据集大小加倍会促使模型质量呈线性增长。 但请记住,低质量的示例可能会对性能产生负面影响。 如果在没有先筛选出最高质量示例的情况下使用大量内部数据训练模型,你的模型性能可能会低于预期。

上传训练数据

下一步是选择现有的已准备训练数据,或在自定义模型时上传要使用的新准备训练数据。 准备好训练数据后,可将文件上传到服务。 可通过两种方式上传训练数据:

对于大型数据文件,建议从 Blob 存储导入。 通过多部分表单上传大型文件时,大型文件可能会变得不稳定,因为请求是原子的,无法重试或恢复。 有关 Blob 存储的详细信息,请参阅 什么是 Azure Blob 存储?

以下 Python 示例使用 Python SDK 上传本地训练和验证文件,并检索返回的文件 ID:

import os
from openai import OpenAI

# Load the OpenAI client
client = OpenAI(
  api_key = os.getenv("AZURE_OPENAI_API_KEY"),  
  base_url="https://YOUR-RESOURCE-NAME.openai.azure.com/openai/v1/"
)

# Upload the training and validation dataset files to Microsoft Foundry with the SDK.
training_file_name = 'training_set.jsonl'
validation_file_name = 'validation_set.jsonl'

training_response = client.files.create(file=open(training_file_name, "rb"), purpose="fine-tune")
validation_response = client.files.create(file=open(validation_file_name, "rb"), purpose="fine-tune")
training_file_id = training_response.id
validation_file_id = validation_response.id

print("Training file ID:", training_file_id)
print("Validation file ID:", validation_file_id)

创建自定义模型

上传训练和验证文件后,即可启动微调作业。

以下 Python 代码演示了如何使用 Python SDK 创建新的微调作业的示例:

response = client.fine_tuning.jobs.create(
    training_file=training_file_id,
    validation_file=validation_file_id,
    model="gpt-4.1-2025-04-14", # Enter the base model name.
    suffix="my-model", # Custom suffix for naming the resulting model. Note that in Microsoft Foundry, the model can't contain dot/period characters.
    seed=105, # Seed parameter controls reproducibility of the fine-tuning job. If you don't specify a seed, one is generated automatically.
    extra_body={ "trainingType": "GlobalStandard" } # Change this value to your preferred training type. Other options are `Standard` and `Developer`.
)

job_id = response.id

# You can use the job ID to monitor the status of the fine-tuning job.
# The fine-tuning job takes some time to start and finish.

print("Job ID:", response.id)
print(response.model_dump_json(indent=2))

注释

建议对训练类型使用全局标准层,因为它可以 节省成本 ,并使用全局容量来加快排队时间。 但是,它会在当前资源区域之外复制数据和权重。 如果需要 数据驻留 ,请使用支持标准层训练的 模型

还可以传递其他可选参数(如超参数)以更好地控制微调过程。 对于初始训练,我们建议使用不存在的自动默认值,而无需指定这些参数。

当前支持的用于监督微调的超参数包括:

Name 类型 DESCRIPTION
batch_size 整数 要用于训练的批大小。 批大小表示用于训练单个前向和后向传递的训练示例的数量。 一般情况下,我们发现较大的批大小往往更适用于较大的数据集。

此属性的默认值和最大值特定于基础模型。 批大小越大意味着模型参数的更新频率越低,但方差越小。
learning_rate_multiplier Number 用于训练的学习率乘数。 微调学习率是用于预训练的原始学习率乘以此值。

较大的学习率通常在较大的批大小中表现更好。 建议试验范围从 0.020.2 的值,以查看哪个能产生最佳结果。 较小的学习率可以用于避免过度拟合。
n_epochs 整数 训练模型的时期数。 一个时期是指训练数据集的一个完整周期。
seed 整数 控制作业可重复性的种子。 传入相同的种子和任务参数应产生相同的结果,但在极少数情况下可能会有所不同。 如果未指定种子,则会为你生成一个种子。

若要使用 OpenAI Python API 的 1.x 版本设置自定义超参数,请将其作为以下内容的一部分 method提供:

client.fine_tuning.jobs.create(
  training_file="file-abc123", 
  model="gpt-4.1-2025-04-14",
  suffix="my-model",
  seed=105,
  method={
    "type": "supervised", # In this case, the job is using supervised fine-tuning.
    "supervised": {
      "hyperparameters": {
        "n_epochs": 2
      }
    }
  },
  extra_body={ "trainingType": "GlobalStandard" }
)

若要了解其他自定义方法支持的超参数,请参阅 直接首选项优化指南强化微调指南

训练类型

根据用例和预算选择训练层:

  • 标准:训练发生在当前 Foundry 资源的区域中,并提供数据驻留的保证。 非常适合数据必须驻留在特定区域的工作负载。

  • 全球:通过使用超出当前区域的容量,提供比标准更实惠的定价。 数据和权重被复制到训练发生的区域。 非常适合数据驻留不是限制,并且需要更快队列时间的情况。

  • 开发人员(预览版):使用空闲容量进行培训,可节省大量成本。 没有延迟或 SLA 保证,因此此等级的作业可能会被自动抢占并稍后恢复。 数据驻留也没有保证。 非常适合实验和具有价格敏感性的工作负载。

import openai
from openai import AzureOpenAI

base_uri = "https://<ACCOUNT-NAME>.services.ai.azure.com"
api_key = "<API-KEY>"
api_version = "2025-04-01-preview"
client = AzureOpenAI(
azure_endpoint=base_uri,
api_key=api_key,
api_version=api_version
)
try:
    client.fine_tuning.jobs.create(
    model="gpt-4.1-mini",
    training_file="<FILE-ID>",
    extra_body={"trainingType": "developerTier"}
    )
except openai.APIConnectionError as e:
    print("The server could not be reached")
    print(e.__cause__) # An underlying exception, likely raised within httpx.
except openai.RateLimitError as e:
    print("A 429 status code was received; we should back off a bit.")
except openai.APIStatusError as e:
    print("Another non-200-range status code was received")
    print(e.status_code)
    print(e.response)
    print(e.body)

检查微调作业状态

response = client.fine_tuning.jobs.retrieve(job_id)

print("Job ID:", response.id)
print("Status:", response.status)
print(response.model_dump_json(indent=2))

列出微调事件

若要检查训练期间生成的单个微调事件,请运行以下命令。 运行命令之前,可能需要使用 pip install openai --upgrade以下命令将 OpenAI 客户端库升级到最新版本。

response = client.fine_tuning.jobs.list_events(fine_tuning_job_id=job_id, limit=10)
print(response.model_dump_json(indent=2))

列出检查点

每个训练时期的完成都会生成一个检查点。 检查点是模型的一种完全可运行版本,可以被部署并用作随后的微调作业的目标模型。 检查点尤其有用,因为它们可能提供过拟合前的快照。

微调作业完成后,可以使用三个最新版本的模型进行部署。 你的微调模型代表最终训练周期的模型。 前两个时期可用作检查点。

可以运行以下命令来检索与单个微调作业关联的检查点列表。 运行命令之前,可能需要使用 pip install openai --upgrade以下命令将 OpenAI 客户端库升级到最新版本。

response = client.fine_tuning.jobs.checkpoints.list(job_id)
print(response.model_dump_json(indent=2))

分析自定义模型

Azure OpenAI 会在完成每个微调作业后附加一个名为 results.csv 的结果文件。 可以使用该结果文件来分析自定义模型的训练和验证性能。 将为每个自定义模型列出结果文件的文件 ID。 可以使用 Python SDK 检索文件 ID 并下载结果文件进行分析。

以下 Python 示例检索附加到自定义模型的微调作业的第一个结果文件的文件 ID。 然后,它使用 Python SDK 将文件下载到当前工作目录进行分析。

# Retrieve the file ID of the first result file from the fine-tuning job
# for the customized model.
response = client.fine_tuning.jobs.retrieve(job_id)
if response.status == 'succeeded':
    result_file_id = response.result_files[0]

retrieve = client.files.retrieve(result_file_id)

# Download the result file.
print(f'Downloading result file: {result_file_id}')

with open(retrieve.filename, "wb") as file:
    result = client.files.content(result_file_id).read()
    file.write(result)

结果文件是一个 CSV 文件,其中包含一个标头行,以及微调作业所执行的每个训练步骤对应的一行。 结果文件包含以下列:

列名称 DESCRIPTION
step 训练步骤数。 一个训练步骤代表针对一批训练数据前向和后向执行的一轮操作。
train_loss 训练批的损失。
train_mean_token_accuracy 模型在训练批次中正确预测的标记百分比。

例如,当批量大小设置为3,且数据中包含完成品[[1, 2], [0, 5], [4, 2]]时,如果模型预测为0.83,那么该值将被设置为[[1, 1], [0, 5], [4, 2]](6分之5)。
valid_loss 验证批的损失。
validation_mean_token_accuracy 验证批次中模型正确预测的令牌百分比。

例如,当批量大小设置为3,且数据中包含完成品[[1, 2], [0, 5], [4, 2]]时,如果模型预测为0.83,那么该值将被设置为[[1, 1], [0, 5], [4, 2]](6分之5)。
full_valid_loss 在每个纪元结束时计算的验证损失。 训练正常时,损失应减少。
full_valid_mean_token_accuracy 在每个纪元结束时计算的有效平均标记准确性。 训练正常时,标记准确性应增加。

还可以在 Microsoft Foundry 门户中以图表形式查看 results.csv 文件中的数据。 为已训练的模型选择链接时,将显示三个图表:丢失、平均令牌准确性和令牌准确性。 如果提供了验证数据,则这两个数据集都显示在同一绘图上。

随着时间的推移,损失会减少,而准确度提高。 如果你的训练数据和验证数据出现偏差,可能存在过拟合情况。 尝试使用更少的时期或较小的学习率乘数进行训练。

部署微调模型

如果对微调作业中的指标感到满意,或者只想继续推理,则必须部署模型。

如果您正在部署以进行进一步验证,可以考虑使用开发人员部署进行 测试

与以前的 SDK 命令不同,必须使用控制平面 API 进行部署。 此任务需要单独的授权、不同的 API 路径和不同的 API 版本。

Variable 定义
token 授权令牌。 可通过多种方式生成授权令牌。 初始测试的最简单方法是从 Azure 门户打开 Azure Cloud Shell。 然后运行 az account get-access-token。 可以将此令牌用作 API 测试的临时授权令牌。 建议将此令牌存储在新的环境变量中。
subscription 关联的 Azure OpenAI 资源的订阅 ID。
resource_group Azure OpenAI 资源的资源组名称。
resource_name Azure OpenAI 资源名称。
model_deployment_name 新微调模型部署的自定义名称。 此名称在聊天完成调用的代码中被引用。
fine_tuned_model 你的微调模型。 请从上一步的微调作业结果中检索此值。 应类似于 gpt-4.1-2025-04-14.ft-b044a9d3cf9c4228b5d393567f693b83。 需要将该值添加到 deploy_data JSON。 或者,可以通过传递以格式 ftchkpt-e559c011ecc04fc68eaa339d8227d02d显示的检查点 ID 来部署检查点。
import json
import os
import requests

token= os.getenv("<TOKEN>") 
subscription = "<YOUR_SUBSCRIPTION_ID>"  
resource_group = "<YOUR_RESOURCE_GROUP_NAME>"
resource_name = "<YOUR_AZURE_OPENAI_RESOURCE_NAME>"
model_deployment_name ="gpt-41-ft" # Custom deployment name that you use to reference the model when making inference calls.

deploy_params = {'api-version': "2024-10-01"} # Control plane API version rather than the data plane API for this call 
deploy_headers = {'Authorization': 'Bearer {}'.format(token), 'Content-Type': 'application/json'}

deploy_data = {
    "sku": {"name": "standard", "capacity": 1}, 
    "properties": {
        "model": {
            "format": "OpenAI",
            "name": <"fine_tuned_model">, # Retrieve this value from the previous call; it looks like gpt-4.1-2025-04-14.ft-b044a9d3cf9c4228b5d393567f693b83
            "version": "1"
        }
    }
}
deploy_data = json.dumps(deploy_data)

request_url = f'https://management.azure.com/subscriptions/{subscription}/resourceGroups/{resource_group}/providers/Microsoft.CognitiveServices/accounts/{resource_name}/deployments/{model_deployment_name}'

print('Creating a new deployment...')

r = requests.put(request_url, params=deploy_params, headers=deploy_headers, data=deploy_data)

print(r)
print(r.reason)
print(r.json())

若要了解跨区域部署以及如何使用已部署的模型,请参阅 使用已部署的微调模型

如果已准备好进行生产部署,或者需要特定的数据驻留需求,请遵循 部署指南

执行连续微调

创建经过微调的模型后,可能需要通过进一步微调以继续改进模型。 持续微调是选择已经微调的模型作为基础模型并在新的训练示例集上进一步对其进行微调的迭代过程。 仅 OpenAI 模型支持连续微调。

若要对以前微调的模型执行微调,请使用“ 创建自定义模型”中所述的相同过程。 但不是指定通用基础模型的名称,而是指定微调模型的 ID。 经过微调的模型的 ID 如下所示 gpt-4.1-2025-04-14.ft-5fd1918ee65d4cd38a5dcf6835066ed7

response = client.fine_tuning.jobs.create(
    training_file=training_file_id,
    validation_file=validation_file_id,
    model="gpt-4.1-2025-04-14.ft-5fd1918ee65d4cd38a5dcf6835066ed7"
)
job_id = response.id

# You can use the job ID to monitor the status of the fine-tuning job.
# The fine-tuning job takes some time to start and finish.

print("Job ID:", response.id)
print("Status:", response.id)
print(response.model_dump_json(indent=2))

我们还建议包含 suffix 参数,以便更轻松地区分微调模型的迭代。 该 suffix 参数采用字符串,并设置为标识微调的模型。 使用 OpenAI Python API,可以将最多 18 个字符的字符串添加到微调模型的名称中。

如果不确定现有微调模型的 ID,可以在 Microsoft Foundry 的 “模型 ”页上找到此信息。 或者,可以使用 REST API 为 Azure OpenAI 资源生成 模型列表

清理部署、自定义模型和训练文件

不再需要自定义模型时,可以删除部署和模型。 如有必要,还可以删除上传到服务的训练和验证文件。

删除模型部署

重要

部署自定义模型后,如果部署随时保持非活动状态超过 15 天,则会删除部署。 如果模型部署了 15 天以上,并且连续 15 天期间未进行聊天完成或响应 API 调用,则自定义模型的部署处于 非活动 状态。

删除非活动部署不会删除或影响基础自定义模型。 可以随时重新部署自定义模型。

Azure OpenAI 在 Microsoft Foundry 模型定价中的描述,每个部署的自定义(微调)模型都会产生每小时托管费用,无论是否对模型进行聊天完成或响应 API 调用。 若要详细了解如何使用 Azure OpenAI 规划和管理成本,请参阅 规划和管理 Azure OpenAI 的成本

可以使用以下任一方法删除自定义模型的部署:

删除自定义模型

可以使用 Foundry 删除自定义模型。

注释

如果自定义模型具有现有部署,则无法删除它。 必须先 删除模型部署 ,然后才能删除自定义模型。

删除训练文件

可以选择性地在 Azure OpenAI 订阅中删除为训练上传的训练和验证文件,以及在训练期间生成的结果文件。 可使用以下方法删除训练、验证和结果文件:

以下 Python 示例使用 Python SDK 删除自定义模型的训练、验证和结果文件:

print('Checking for existing uploaded files.')
results = []

# Get the complete list of uploaded files in your subscription.
files = openai.File.list().data
print(f'Found {len(files)} total uploaded files in the subscription.')

# Enumerate all uploaded files. Extract the IDs for the
# files with file names that match your training dataset file and
# validation dataset file.
for item in files:
    if item["filename"] in [training_file_name, validation_file_name, result_file_name]:
        results.append(item["id"])
print(f'Found {len(results)} already uploaded files that match our files')

# Enumerate the file IDs for your files and delete each file.
print(f'Deleting already uploaded files.')
for id in results:
    openai.File.delete(sid = id)

先决条件

支持的模型

若要检查哪些区域当前支持微调,请参阅 有关模型的文章

你也可以微调以前已微调的模型,格式为 base-model.ft-{jobid}

审阅 REST API 的工作流

花点时间查看有关将 REST API 和 Python 与 Azure OpenAI 配合使用的微调工作流:

  1. 准备训练和验证数据。
  2. 选择基础模型。
  3. 上传训练数据。
  4. 训练新的自定义模型。
  5. 检查自定义模型的状态。
  6. 部署供使用的自定义模型。
  7. 使用自定义模型。
  8. (可选)分析自定义模型的性能和拟合度。

准备训练和验证数据

你的训练和验证数据集包含希望模型执行方式的输入和输出示例。

使用的训练和验证数据 必须 格式化为 JSON 行(JSONL)文档。 它还必须采用聊天完成 API 使用的对话格式。

除 JSONL 格式外,训练和验证数据文件必须以 UTF-8 编码并包含字节顺序标记 (BOM)。 每个文件的大小必须小于 512 MB。

如果需要微调 gpt-4o-mini-2024-07-18的分步演练,请参阅 Azure OpenAI 微调教程

示例文件格式

{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who discovered Antarctica?"}, {"role": "assistant", "content": "Some chaps named Fabian Gottlieb von Bellingshausen and Mikhail Lazarev, as if they don't teach that in every school!"}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What is the biggest ocean?"}, {"role": "assistant", "content": "The Pacific Ocean. It's not like it's a small pond or anything."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What is the largest planet?"}, {"role": "assistant", "content": "It's called Jupiter, you might have heard of it...or not."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who painted the Mona Lisa?"}, {"role": "assistant", "content": "Oh, some obscure artist named Leonardo da Vinci. Not that he is famous or anything."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the boiling point of water?"}, {"role": "assistant", "content": "Exciting fact of the day: it's 100 degrees Celsius. Life-changing, isn't it?"}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who wrote 'The Odyssey'?"}, {"role": "assistant", "content": "Oh, just some poet named Homer. Nothing special, really."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What is the largest mammal?"}, {"role": "assistant", "content": "Blue Whale. Quite a big fish isn't it? Oh wait, it's not a fish!"}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the highest mountain peak?"}, {"role": "assistant", "content": "Everest. Brace yourself, it's not a walk in the park."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who invented the telephone?"}, {"role": "assistant", "content": "A guy named Alexander Graham Bell. Bet you didn't guess that one!"}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What is the distance from Earth to the Sun?"}, {"role": "assistant", "content": "About 93 million miles. Just a quick drive, really."}]}

多轮聊天文件格式

还支持在 JSONL 训练文件的单个行中进行多轮对话。 若要跳过对特定助理消息的微调,请添加可选的 weight 键/值对。 目前, weight 可以设置为 01

{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the capital/major city 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}]}

使用视觉的聊天补全

{"messages": [{"role": "user", "content": [{"type": "text", "text": "What's in this image?"}, {"type": "image_url", "image_url": {"url": "https://raw.githubusercontent.com/MicrosoftDocs/azure-ai-docs/main/articles/ai-services/openai/media/how-to/generated-seattle.png"}}]}, {"role": "assistant", "content": "The image appears to be a watercolor painting of a city skyline, featuring tall buildings and a recognizable structure often associated with Seattle, like the Space Needle. The artwork uses soft colors and brushstrokes to create a somewhat abstract and artistic representation of the cityscape."}]}

创建训练和验证数据集

训练示例越多越好。 如果没有至少 10 个训练示例,则微调作业不会继续,但这样一小部分不足以显著影响模型响应。 成功微调的最佳做法是提供数百个训练示例(如果不是数千个)。

通常,将数据集大小加倍会促使模型质量呈线性增长。 但请记住,低质量的示例可能会对性能产生负面影响。 如果在没有先筛选出最高质量示例的情况下使用大量内部数据训练模型,你的模型性能可能会低于预期。

上传训练数据

下一步是选择现有的已准备训练数据,或在自定义模型时上传要使用的新准备训练数据。 准备好训练数据后,可将文件上传到服务。 可通过两种方式上传训练数据:

对于大型数据文件,建议从 Blob 存储导入。 通过多部分表单上传大型文件时,大型文件可能会变得不稳定,因为请求是原子的,无法重试或恢复。 有关 Blob 存储的详细信息,请参阅 什么是 Azure Blob 存储?

上传训练数据

curl -X POST $AZURE_OPENAI_ENDPOINT/openai/v1/files \
  -H "Content-Type: multipart/form-data" \
  -H "api-key: $AZURE_OPENAI_API_KEY" \
  -F "purpose=fine-tune" \
  -F "file=@C:\\fine-tuning\\training_set.jsonl;type=application/json"

上传验证数据

curl -X POST $AZURE_OPENAI_ENDPOINT/openai/v1/files \
  -H "Content-Type: multipart/form-data" \
  -H "api-key: $AZURE_OPENAI_API_KEY" \
  -F "purpose=fine-tune" \
  -F "file=@C:\\fine-tuning\\validation_set.jsonl;type=application/json"

创建自定义模型

上传训练和验证文件后,即可启动微调作业。 以下代码演示了如何使用 REST API 创建新的微调作业 的示例。

此示例包括传递种子参数。 种子控制作业的可重现性。 传入相同的种子和任务参数应产生相同的结果,但在极少数情况下可能会有所不同。 如果未指定种子,则会为你生成一个种子。

curl -X POST $AZURE_OPENAI_ENDPOINT/openai/v1/fine_tuning/jobs \
  -H "Content-Type: application/json" \
  -H "api-key: $AZURE_OPENAI_API_KEY" \
  -d '{
    "model": "gpt-4.1-2025-04-14",
    "training_file": "<TRAINING_FILE_ID>",
    "validation_file": "<VALIDATION_FILE_ID>",
    "seed": 105
}'

如果要微调支持 全局训练的模型,您可以通过使用 extra_body 命名参数并结合 api-version=2025-04-01-preview 来指定训练类型:

curl -X POST $AZURE_OPENAI_ENDPOINT/openai/fine_tuning/jobs?api-version=2025-04-01-preview \
  -H "Content-Type: application/json" \
  -H "api-key: $AZURE_OPENAI_API_KEY" \
  -d '{
    "model": "gpt-4.1-2025-04-14",
    "training_file": "<TRAINING_FILE_ID>",
    "validation_file": "<VALIDATION_FILE_ID>",
    "seed": 105,
    "trainingType": "globalstandard"
}'

还可以传递其他可选参数(例如超参数),以更好地控制微调过程。 对于初始训练,我们建议使用不存在的自动默认值,而无需指定这些参数。

当前支持的用于监督微调的超参数包括:

Name 类型 DESCRIPTION
batch_size 整数 要用于训练的批大小。 批大小表示用于训练单个前向和后向传递的训练示例的数量。 一般情况下,我们发现较大的批大小往往更适用于较大的数据集。

此属性的默认值和最大值特定于基础模型。 批大小越大意味着模型参数的更新频率越低,但方差越小。
learning_rate_multiplier Number 用于训练的学习率乘数。 微调学习率是用于预训练的原始学习率乘以此值。

较大的学习率通常在较大的批大小中表现更好。 建议试验范围从 0.020.2 的值,以查看哪个能产生最佳结果。 较小的学习率可以用于避免过度拟合。
n_epochs 整数 训练模型的时期数。 一个时期是指训练数据集的一个完整周期。
seed 整数 控制作业可重复性的种子。

若要了解其他自定义方法支持的超参数,请参阅 直接首选项优化指南强化微调指南

选择训练类型

根据用例和预算选择训练层:

  • 标准:训练发生在当前 Foundry 资源的区域中,并提供数据驻留的保证。 非常适合数据必须驻留在特定区域的工作负载。

  • 全球:通过使用超出当前区域的容量,提供比标准更实惠的定价。 数据和权重被复制到训练发生的区域。 非常适合数据驻留不是限制,并且需要更快队列时间的情况。

  • 开发人员(预览版):使用空闲容量进行培训,可节省大量成本。 没有延迟或 SLA 保证,因此此等级的作业可能会被自动抢占并稍后恢复。 也没有数据驻留保证。 非常适合实验和具有价格敏感性的工作负载。

curl -X POST "https://<ACCOUNT-NAME>.openai.azure.com/openai/fine_tuning/jobs?api-version=2025-04-01-preview" -H "Content-Type: application/json" -H "api-key: <API-KEY>" -d "{"model": "gpt-4.1", "training_file": "<FILE_ID>", "hyperparameters": {"prompt_loss_weight": 0.1}, "trainingType": "developerTier"}"

检查自定义模型的状态

启动微调作业后,可能需要一些时间才能完成。 你的作业可能排在系统上的其他作业后面。 训练模型可能需要几分钟或几个小时,具体取决于模型和数据集大小。

以下示例使用 REST API 检查微调作业的状态。 该示例使用上一示例返回的作业 ID 检索有关作业的信息。

curl -X GET $AZURE_OPENAI_ENDPOINT/openai/v1/fine_tuning/jobs/<YOUR-JOB-ID> \
  -H "api-key: $AZURE_OPENAI_API_KEY"

列出微调事件

若要检查训练期间生成的各个微调事件:

curl -X POST $AZURE_OPENAI_ENDPOINT/openai/v1/fine_tuning/jobs/{fine_tuning_job_id}/events \
  -H "Content-Type: application/json" \
  -H "api-key: $AZURE_OPENAI_API_KEY" 

列出检查点

每个训练时期的完成都会生成一个检查点。 检查点是模型的一种完全可运行版本,可以被部署并用作随后的微调作业的目标模型。 检查点尤其有用,因为它们可能提供过拟合前的快照。

微调作业完成后,可以使用三个最新版本的模型进行部署。 你的微调模型代表最终训练周期的模型。 前两个时期可用作检查点。

可以运行以下命令来检索与单个微调作业关联的检查点列表:

curl -X POST $AZURE_OPENAI_ENDPOINT/openai/v1/fine_tuning/jobs/{fine_tuning_job_id}/checkpoints \
  -H "Content-Type: application/json" \
  -H "api-key: $AZURE_OPENAI_API_KEY" 

暂停和恢复

在训练期间,可以查看日志和指标,并根据需要暂停作业。 如果指标不聚合,或者认为模型没有以正确的速度学习,暂停可能会很有用。

训练作业暂停并完成安全评估后,将创建可部署的检查点。 此检查点可用于部署并进行推理,或者您可以恢复任务以将其完成。

暂停操作仅适用于经过至少一个步骤的训练且处于 “正在运行” 状态的任务。

暂停

curl -X POST $AZURE_OPENAI_ENDPOINT/openai/v1/fine_tuning/jobs/{fine_tuning_job_id}/pause \
  -H "Content-Type: application/json" \
  -H "api-key: $AZURE_OPENAI_API_KEY" 

恢复

curl -X POST $AZURE_OPENAI_ENDPOINT/openai/v1/fine_tuning/jobs/{fine_tuning_job_id}/resume \
  -H "Content-Type: application/json" \
  -H "api-key: $AZURE_OPENAI_API_KEY" 

复制模型(预览版)

现在可以将微调后的检查点模型从一个区域复制到另一个区域,跨不同订阅,但需在同一租户内进行。 此过程使用专用 API 来帮助确保高效且安全的传输。 此功能目前仅适用于 API,而不能通过 Foundry 门户使用。

将模型从区域 A 复制到区域 B 后,可以不断微调区域 B 中的模型,并从此位置部署模型。

注释

删除源区域中的模型检查点不会导致在目标区域中删除模型。 若要在复制模型后删除这两个区域中的模型,必须在每个区域中单独部署模型。

先决条件

  • 目标资源或账户应至少存在一个微调作业。
  • 目标资源或帐户不应禁用公共网络访问(至少发送复制请求时)。
  • 如果启动副本的帐户具有访问目标帐户的足够权限,则只能复制到目标帐户。

配置权限

  1. 创建 用户分配的托管标识
  2. 为目标资源或账户上的用户分配的托管身份授予 Azure AI 用户角色。
  3. 将用户分配的托管标识分配给源资源帐户。

复制模型

curl --request POST \
  --url 'https://<aoai-resource>.openai.azure.com/openai/v1/fine_tuning/jobs/<ftjob>/checkpoints/<checkpoint-name>/copy' \
  --header 'Content-Type: application/json' \
  --header 'api-key: <api-key>' \
  --header 'aoai-copy-ft-checkpoints: preview' \
  --data '{
  "destinationResourceId": "<resourceId>",
  "region": "<region>"
}'

由于这是长时间运行的操作,因此通过提供所用调用中的 POST 源帐户检查点 ID 来检查经微调的模型副本的状态。

检查复制状态

curl --request GET \
  --url 'https://<aoai-resource>.openai.azure.com//openai/v1/fine_tuning/jobs/<ftjob>/checkpoints/<checkpoint-name>/copy' \
  --header 'Content-Type: application/json' \
  --header 'api-key: <api-key>' \
  --header 'aoai-copy-ft-checkpoints: preview' 

注释

从源帐户复制检查点时,目标帐户中会保留相同的检查点名称。 确保在目标账户中对微调、部署或其他操作使用完全相同的名称。 此检查点不会显示在 UI 或 list checkpoints API 中。

分析自定义模型

Azure OpenAI 会在完成每个微调作业后附加一个名为 results.csv 的结果文件。 可以使用该结果文件来分析自定义模型的训练和验证性能。 将为每个自定义模型列出结果文件的文件 ID。 可以使用 REST API 检索文件 ID 并下载结果文件进行分析。

以下 Python 示例使用 REST API 检索附加到自定义模型的微调作业的第一个结果文件的文件 ID。 然后,它将文件下载到工作目录进行分析。

curl -X GET "$AZURE_OPENAI_ENDPOINT/openai/v1/fine_tuning/jobs/<JOB_ID>" \
  -H "api-key: $AZURE_OPENAI_API_KEY")
curl -X GET "$AZURE_OPENAI_ENDPOINT/openai/v1/files/<RESULT_FILE_ID>/content" \
    -H "api-key: $AZURE_OPENAI_API_KEY" > <RESULT_FILENAME>

结果文件是一个 CSV 文件,其中包含一个标头行,以及微调作业所执行的每个训练步骤对应的一行。 结果文件包含以下列:

列名称 DESCRIPTION
step 训练步骤数。 一个训练步骤代表针对一批训练数据前向和后向执行的一轮操作。
train_loss 训练批的损失。
train_mean_token_accuracy 模型在训练批次中正确预测的标记百分比。

例如,当批量大小设置为3,且数据中包含完成品[[1, 2], [0, 5], [4, 2]]时,如果模型预测为0.83,那么该值将被设置为[[1, 1], [0, 5], [4, 2]](6分之5)。
valid_loss 验证批的损失。
validation_mean_token_accuracy 验证批次中模型正确预测的令牌百分比。

例如,当批量大小设置为3,且数据中包含完成品[[1, 2], [0, 5], [4, 2]]时,如果模型预测为0.83,那么该值将被设置为[[1, 1], [0, 5], [4, 2]](6分之5)。
full_valid_loss 在每个纪元结束时计算的验证损失。 训练正常时,损失应减少。
full_valid_mean_token_accuracy 在每个纪元结束时计算的有效平均标记准确性。 训练正常时,标记准确性应增加。

还可以在 Foundry 门户中以图表的形式查看 results.csv 文件中的数据。 为已训练的模型选择链接时,将显示三个图表:丢失、平均令牌准确性和令牌准确性。 如果提供了验证数据,则这两个数据集都显示在同一绘图上。

随着时间的推移,损失会减少,而准确度提高。 如果你的训练数据和验证数据出现偏差,可能存在过拟合情况。 尝试使用更少的时期或较小的学习率乘数进行训练。

部署微调模型

如果对微调作业中的指标感到满意,或者只想继续推理,则必须部署模型。

如果您正在部署以进行进一步验证,可以考虑使用开发人员部署进行 测试

如果已准备好进行生产部署,或者需要特定的数据驻留需求,请遵循 部署指南

Variable 定义
token 授权令牌。 可通过多种方式生成授权令牌。 初始测试的最简单方法是从 Azure 门户打开 Azure Cloud Shell。 然后运行 az account get-access-token。 可以将此令牌用作 API 测试的临时授权令牌。 建议将此令牌存储在新的环境变量中。
subscription 关联的 Azure OpenAI 资源的订阅 ID。
resource_group Azure OpenAI 资源的资源组名称。
resource_name Azure OpenAI 资源名称。
model_deployment_name 新微调模型部署的自定义名称。 此名称在聊天完成调用的代码中被引用。
fine_tuned_model 你的微调模型。 请从上一步的微调作业结果中检索此值。 应类似于 gpt-4.1-2025-04-14.ft-b044a9d3cf9c4228b5d393567f693b83。 需要将该值添加到 deploy_data JSON。 或者,可以通过传递以格式 ftchkpt-e559c011ecc04fc68eaa339d8227d02d显示的检查点 ID 来部署检查点。
curl -X POST "https://management.azure.com/subscriptions/<SUBSCRIPTION>/resourceGroups/<RESOURCE_GROUP>/providers/Microsoft.CognitiveServices/accounts/<RESOURCE_NAME>/deployments/<MODEL_DEPLOYMENT_NAME>?api-version=2024-10-21" \
  -H "Authorization: Bearer <TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "sku": {"name": "standard", "capacity": 1},
    "properties": {
        "model": {
            "format": "OpenAI",
            "name": "<FINE_TUNED_MODEL>",
            "version": "1"
        }
    }
}'

若要了解跨区域部署以及如何使用已部署的模型,请参阅 使用已部署的微调模型

执行连续微调

创建经过微调的模型后,可能需要通过进一步微调以继续改进模型。 持续微调是选择已经微调的模型作为基础模型并在新的训练示例集上进一步对其进行微调的迭代过程。 仅 OpenAI 模型支持连续微调。

若要对以前微调的模型执行微调,请使用“ 创建自定义模型”中所述的相同过程。 但不是指定通用基础模型的名称,而是指定微调模型的 ID。 经过微调的模型的 ID 如下所示 gpt-4.1-2025-04-14.ft-5fd1918ee65d4cd38a5dcf6835066ed7

curl -X POST $AZURE_OPENAI_ENDPOINT/openai/v1/fine_tuning/jobs \
  -H "Content-Type: application/json" \
  -H "api-key: $AZURE_OPENAI_API_KEY" \
  -d '{
    "model": "gpt-4.1-2025-04-14.ft-5fd1918ee65d4cd38a5dcf6835066ed7",
    "training_file": "<TRAINING_FILE_ID>",
    "validation_file": "<VALIDATION_FILE_ID>",
    "suffix": "<additional text used to help identify fine-tuned models>"
}'

我们还建议包含 suffix 参数,以便更轻松地区分微调模型的迭代。 该 suffix 参数采用字符串,并设置为标识微调的模型。 后缀最多可以包含 40 个字符(azAZ09-_),这些字符将被添加到您的微调模型的名称中。

如果不确定现有微调模型的 ID,可以在 Foundry 的 “模型 ”页上找到此信息。 或者,可以使用 REST API 为 Azure OpenAI 资源生成 模型列表

清理部署、自定义模型和训练文件

不再需要自定义模型时,可以删除部署和模型。 如有必要,还可以删除上传到服务的训练和验证文件。

删除模型部署

可以使用以下任一方法删除自定义模型的部署:

删除自定义模型

可以使用 Foundry 删除自定义模型。

注释

如果自定义模型具有现有部署,则无法删除它。 必须先 删除模型部署 ,然后才能删除自定义模型。

删除训练文件

可以选择性地在 Azure OpenAI 订阅中删除为训练上传的训练和验证文件,以及在训练期间生成的结果文件。 可以使用 Foundry 删除文件。

Microsoft Foundry 门户中有两种独特的微调体验:

重要

本文中标记了“(预览版)”的项目目前为公共预览版。 此预览版未提供服务级别协议,不建议将其用于生产工作负载。 某些功能可能不受支持或者受限。 有关详细信息,请参阅 Microsoft Azure 预览版补充使用条款

先决条件

支持的模型

若要检查哪些区域当前支持微调,请参阅 有关模型的文章

你也可以微调以前已微调的模型,格式为 base-model.ft-{jobid}

查看 Foundry 门户的工作流程

花点时间查看使用 Foundry 门户的优化流程:

  1. 准备训练和验证数据。
  2. 使用 Foundry 门户中 的“创建优化模型 ”对话框来训练自定义模型。
    1. 选择训练方法。
    2. 选择基础模型。
    3. 选择训练类型。
    4. 选择训练数据。
    5. (可选)选择验证数据。
    6. (可选)为微调作业配置任务参数。
    7. (可选)为生成的自定义模型启用自动部署。
    8. 查看你的选择并训练新的自定义模型。
  3. 检查自定义微调模型的状态。
  4. 部署供使用的自定义模型。
  5. 使用自定义模型。
  6. (可选)分析自定义模型的性能和拟合度。

准备训练和验证数据

你的训练和验证数据集包含希望模型执行方式的输入和输出示例。

使用的训练和验证数据 必须 格式化为 JSON 行(JSONL)文档。 它还必须采用聊天完成 API 使用的对话格式。

除 JSONL 格式外,训练和验证数据文件必须以 UTF-8 编码并包含字节顺序标记 (BOM)。 每个文件的大小必须小于 512 MB。

我们通常建议你使用在每一个训练示例中找到的最佳说明和提示。 此方法可帮助你获得最佳结果,尤其是在只有不到一百个示例的情况下。

示例文件格式

{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who discovered Antarctica?"}, {"role": "assistant", "content": "Some chaps named Fabian Gottlieb von Bellingshausen and Mikhail Lazarev, as if they don't teach that in every school!"}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What is the biggest ocean?"}, {"role": "assistant", "content": "The Pacific Ocean. It's not like it's a small pond or anything."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What is the largest planet?"}, {"role": "assistant", "content": "It's called Jupiter, you might have heard of it...or not."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who painted the Mona Lisa?"}, {"role": "assistant", "content": "Oh, some obscure artist named Leonardo da Vinci. Not that he is famous or anything."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the boiling point of water?"}, {"role": "assistant", "content": "Exciting fact of the day: it's 100 degrees Celsius. Life-changing, isn't it?"}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who wrote 'The Odyssey'?"}, {"role": "assistant", "content": "Oh, just some poet named Homer. Nothing special, really."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What is the largest mammal?"}, {"role": "assistant", "content": "Blue Whale. Quite a big fish isn't it? Oh wait, it's not a fish!"}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the highest mountain peak?"}, {"role": "assistant", "content": "Everest. Brace yourself, it's not a walk in the park."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who invented the telephone?"}, {"role": "assistant", "content": "A guy named Alexander Graham Bell. Bet you didn't guess that one!"}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What is the distance from Earth to the Sun?"}, {"role": "assistant", "content": "About 93 million miles. Just a quick drive, really."}]}

Azure OpenAI 的多轮聊天文件格式

还支持在 JSONL 训练文件的单个行中进行多轮对话。 若要跳过对特定助理消息的微调,请添加可选的 weight 键/值对。 目前, weight 可以设置为 01

{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the capital/major city 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}]}

使用视觉的聊天补全

{"messages": [{"role": "user", "content": [{"type": "text", "text": "What's in this image?"}, {"type": "image_url", "image_url": {"url": "https://raw.githubusercontent.com/MicrosoftDocs/azure-ai-docs/main/articles/ai-services/openai/media/how-to/generated-seattle.png"}}]}, {"role": "assistant", "content": "The image appears to be a watercolor painting of a city skyline, featuring tall buildings and a recognizable structure often associated with Seattle, like the Space Needle. The artwork uses soft colors and brushstrokes to create a somewhat abstract and artistic representation of the cityscape."}]}

数据集大小注意事项

训练示例越多越好。 如果没有至少 10 个训练示例,则微调作业不会继续,但这样一小部分不足以显著影响模型响应。 成功微调的最佳做法是提供数百个训练示例(如果不是数千个)。 建议从 50 个精心制作的示例开始。

通常,将数据集大小加倍会促使模型质量呈线性增长。 但请记住,低质量的示例可能会对性能产生负面影响。 如果在没有先筛选出最高质量示例的情况下使用大量内部数据训练模型,你的模型性能可能会低于预期。

创建微调的模型

Foundry 门户提供 “创建微调模型 ”对话框,以便可以在一个位置为 Azure 资源创建和训练微调模型。

  1. 转到 Foundry 门户 ,使用有权访问 Azure OpenAI 资源的凭据登录。 在登录工作流中,选择适当的目录、Azure 订阅和 Azure OpenAI 资源。

  2. 转到 “工具>微调”,然后选择 “微调模型”。

    显示用于在 Foundry 门户中创建自定义模型的选择的屏幕截图。

  3. 选择要微调的模型,然后选择“ 下一步”。

    Foundry 门户中模型选择的屏幕截图。

    此时会显示 “创建微调模型 ”对话框。

    用于创建微调模型的对话框的屏幕截图。

选择训练方法

第一步是确认模型选择和训练方法。 并非所有模型都支持所有训练方法。

选择模型时,还可以选择以前经过微调的模型,如 本文稍后所述。

选择训练类型

Foundry 提供三个培训层以满足客户需求。

标准训练层

标准层提供专用微调容量,性能和 SLA 可预测。 它非常适合需要有保证吞吐量的生产工作负荷。

全球标准培训等级

全球训练层以更实惠的全球产品定价扩大模型定制的覆盖范围。 它不提供 数据驻留。 如果需要数据驻留,请参阅所选模型的 可用区域列表

训练数据和生成的模型权重可能会复制到另一个 Azure 区域。

使用此层时,可以:

  • 从十多个 Azure OpenAI 区域中训练最新的 OpenAI 模型。
  • 受益于较低的每标记训练速率(与标准层相比)。

开发人员培训层

开发人员级别是一个具有成本效益的选择,它利用空闲容量来处理非紧急或探索性的工作负荷。 此层中的作业可能会被抢占并稍后恢复,因此非常适合实验和成本敏感型用例。

选择训练数据

下一步是选择现有的已准备训练数据,或者通过选择 “添加训练数据”来自定义模型时上传要使用的新准备训练数据。

训练数据 ”对话框显示任何现有的以前上传的数据集。 它还提供上传新训练数据的选项。

Foundry 门户训练数据窗格的屏幕截图

  • 如果训练数据已上传到服务,请选择“来自连接的 AI 资源的文件”。 然后从下拉列表中选择该文件。

  • 上传新的训练数据时可使用以下选项之一:

    • 选择“ 上传文件 ”以从本地文件上传训练数据。
    • 选择 Azure Blob 或其他共享 Web 位置 ,从 Azure Blob 存储或其他共享 Web 位置导入训练数据。

对于大型数据文件,建议从 Blob 存储导入。 通过多部分表单上传大型文件时,大型文件可能会变得不稳定,因为请求是原子的,无法重试或恢复。 有关 Blob 存储的详细信息,请参阅 什么是 Azure Blob 存储?

选择验证数据(可选)

如果有验证数据集,请选择 “添加训练数据”。 可以选择现有的已准备验证数据,也可以上传自定义模型时要使用的新准备验证数据。

验证数据 ”对话框显示任何现有的、以前上传的训练和验证数据集。 它还提供用于上传新验证数据的选项。

Foundry 门户中验证数据窗格的截屏。

  • 如果验证数据已上传到服务,请选择“选择数据集”。 然后从下拉列表中选择该文件。

  • 上传新的验证数据时可使用以下选项之一:

    • 选择 “本地文件 ”,从本地文件上传验证数据。
    • 选择 Azure Blob 或其他共享 Web 位置 ,从 Azure Blob 存储或其他共享 Web 位置导入验证数据。

对于大型数据文件,建议从 Blob 存储导入。 通过多部分表单上传大型文件时,大型文件可能会变得不稳定,因为请求是原子的,无法重试或恢复。

使模型可识别(可选)

建议包含一个 suffix 参数,以便更轻松地区分微调模型的迭代。 参数 suffix 采用最多 18 个字符的字符串,用于命名生成的微调模型。

配置训练参数(可选)

可以提供可选的种子并调节其他超参数。

种子控制作业的可重现性。 传入相同的种子和任务参数应产生相同的结果,但在极少数情况下可能会有所不同。 如果未指定种子,则会随机生成一个种子。

Foundry 门户中配置种子和超参数区域的截图。

以下超参数可通过 Foundry 门户进行调整:

Name 类型 DESCRIPTION
批大小 整数 要用于训练的批大小。 批大小表示用于训练单个前向和后向传递的训练示例的数量。 一般情况下,我们发现较大的批大小往往更适用于较大的数据集。

此属性的默认值和最大值特定于基础模型。 批大小越大意味着模型参数的更新频率越低,但方差越小。
学习速率乘数 Number 用于训练的学习率乘数。 微调学习率是用于预训练的原始学习率乘以此值。

较大的学习率通常在较大的批大小中表现更好。 建议试验 0.020.2 范围内的值,以查看能够产生最佳结果的值。 较小的学习率可以用于避免过度拟合。
训练周期数 整数 训练模型的时期数。 一个时期是指训练数据集的一个完整周期。

启用自动部署(可选)

为节省时间,可以选择为生成的模型启用自动部署。 如果训练成功完成,则会根据所选 部署类型部署模型。 部署名称基于为自定义模型生成的唯一名称以及你可能之前提供的可选后缀。

Foundry 门户中自动部署切换的截图。

注释

目前仅支持全球标准部署和开发者部署进行自动部署。 这两个选项都未提供 数据所在地。 有关详细信息,请参阅 有关部署类型的文档

查看所做的选择并训练模型

查看你的选择,然后选择 “提交 ”以开始训练新的微调模型。

检查自定义模型的状态

提交微调作业后,将显示一个页面,其中包含有关优化模型的详细信息。 可以在 Foundry 门户中的“ 微调 ”页上找到有关微调模型的状态和详细信息。

你的作业可能排在系统上的其他作业后面。 训练模型可能需要几分钟或几个小时,具体取决于模型和数据集大小。

生成检查点

每个训练时期完成后,将生成一个检查点。 检查点是模型的一种完全可运行版本,可以被部署并用作随后的微调作业的目标模型。

检查点尤其有用,因为它们可能提供过拟合前的快照。 微调作业完成后,可以使用三个最新版本的模型进行部署。 可以通过 REST API 在资源和订阅之间复制检查点。

暂停和恢复

可以在 Foundry 门户的两个微调视图中跟踪进度。 您的作业会经历与正常微调作业相同的状态(已排队正在运行已成功)。

您还可以在训练进行时查看结果文件,从而了解进度并检查训练是否按预期进行。

在训练期间,可以查看指标并根据需要暂停作业。 如果指标不聚合,或者认为模型没有以正确的速度学习,暂停可能会很有用。 暂停训练作业时,安全评估完成后会创建可部署的检查点。 此检查点可用于部署并进行推理,或者您可以恢复任务以将其完成。 暂停操作仅适用于经过至少一个步骤的训练且处于 “正在运行” 状态的任务。

正在运行作业的强化微调截图。

分析自定义模型

Azure OpenAI 会在完成每个微调作业后附加一个名为 results.csv 的结果文件。 可以使用该结果文件来分析自定义模型的训练和验证性能。 结果文件的文件 ID 在 Foundry 门户的“模型”窗格的“结果文件 ID”列中为每个自定义模型列出。 可以使用文件 ID 从 Foundry 门户的 “数据文件 ”窗格标识和下载结果文件。

结果文件是一个 CSV 文件,其中包含一个标头行,以及微调作业所执行的每个训练步骤对应的一行。 结果文件包含以下列:

列名称 DESCRIPTION
step 训练步骤数。 一个训练步骤代表针对一批训练数据前向和后向执行的一轮操作。
train_loss 训练批的损失。
train_mean_token_accuracy 模型在训练批次中正确预测的标记百分比。

例如,当批量大小设置为3,且数据中包含完成品[[1, 2], [0, 5], [4, 2]]时,如果模型预测为0.83,那么该值将被设置为[[1, 1], [0, 5], [4, 2]](6分之5)。
valid_loss 验证批的损失。
validation_mean_token_accuracy 验证批次中模型正确预测的令牌百分比。

例如,当批量大小设置为3,且数据中包含完成品[[1, 2], [0, 5], [4, 2]]时,如果模型预测为0.83,那么该值将被设置为[[1, 1], [0, 5], [4, 2]](6分之5)。
full_valid_loss 在每个纪元结束时计算的验证损失。 训练正常时,损失应减少。
full_valid_mean_token_accuracy 在每个纪元结束时计算的有效平均标记准确性。 训练正常时,标记准确性应增加。

还可以在 Foundry 门户中以图表的形式查看 results.csv 文件中的数据。 为已训练的模型选择链接时,将显示三个图表:丢失、平均令牌准确性和令牌准确性。 如果提供了验证数据,则这两个数据集都显示在同一绘图上。

随着时间的推移,损失会减少,而准确度提高。 如果你的训练数据和验证数据出现偏差,可能存在过拟合情况。 尝试使用更少的时期或较小的学习率乘数进行训练。

部署微调模型

如果对微调作业中的指标感到满意,或者只想继续推理,则必须部署模型。

如果您正在部署以进行进一步验证,可以考虑使用开发人员部署进行 测试

如果已准备好进行生产部署,或者需要特定的数据驻留需求,请遵循 部署指南

使用部署的微调模型

部署优化后的模型后,可以像使用任何其他已部署的模型一样使用它。 你可以在 Foundry 的游乐场中对新的部署进行实验。 还可以使用 REST API 从自己的应用程序调用微调模型。 你甚至可以开始在提示流中使用此新的微调模型来生成你的生成式 AI 应用程序。

注释

对于聊天模型,用于指导微调模型的系统消息(无论是已部署还是在游乐场中可测试)必须与训练时使用的系统消息相同。 如果使用其他系统消息,则模型可能无法按预期执行。

执行连续微调

创建经过微调的模型后,可能需要通过进一步微调以继续改进模型。 持续微调是选择已经微调的模型作为基础模型并在新的训练示例集上进一步对其进行微调的迭代过程。

若要对以前微调的模型执行微调,请使用“ 创建微调模型”中所述的相同过程。 但是,无需指定泛型基础模型的名称,而是指定已微调的模型。 自定义微调模型如下所示 gpt-4o-2024-08-06.ft-d93dda6110004b4da3472d96f4dd4777-ft

用于创建自定义模型的界面的屏幕截图,其中突出显示了微调的模型。

清理部署、自定义模型和训练文件

不再需要自定义模型时,可以删除部署和模型。 如有必要,还可以删除上传到服务的训练和验证文件。

删除模型部署

重要

部署自定义模型后,如果部署随时保持非活动状态超过 15 天,则会删除部署。 如果模型部署了 15 天以上,并且连续 15 天期间未进行聊天完成或响应 API 调用,则自定义模型的部署处于 非活动 状态。

删除非活动部署不会删除或影响基础自定义模型。 可以随时重新部署自定义模型。

Azure OpenAI 在 Microsoft Foundry 模型定价中的描述,每个部署的自定义(微调)模型都会产生每小时托管费用,无论是否对模型进行聊天完成或响应 API 调用。 若要详细了解如何使用 Azure OpenAI 规划和管理成本,请参阅 规划和管理 Azure OpenAI 的成本

可以在 Foundry 门户中的 “部署 ”窗格中删除自定义模型的部署。 选择要删除的部署,然后选择“ 删除”。

删除自定义模型

可以在 Foundry 门户中的“ 模型 ”窗格中删除自定义模型。 选择要从“ 自定义模型 ”选项卡中删除的自定义模型,然后选择“ 删除”。

注释

如果自定义模型具有现有部署,则无法删除它。 必须先 删除模型部署 ,然后才能删除自定义模型。

删除训练文件

可以选择在 Foundry 门户的 “管理>数据 + 索引 ”窗格中删除为训练上传的训练和验证文件,以及训练期间生成的结果文件。 选择要删除的文件,然后选择“ 删除”。

先决条件

支持的模型

若要检查哪些区域当前支持微调,请参阅 有关模型的文章

你也可以微调以前已微调的模型,格式为 base-model.ft-{jobid}

审阅 Python SDK 的工作流

花点时间审阅将 Python SDK 与 Azure OpenAI 配合使用的微调工作流:

  1. 准备训练和验证数据。
  2. 选择基础模型。
  3. 上传训练数据。
  4. 训练新的自定义模型。
  5. 检查自定义模型的状态。
  6. 部署供使用的自定义模型。
  7. 使用自定义模型。
  8. (可选)分析自定义模型的性能和拟合度。

准备训练和验证数据

你的训练和验证数据集包含希望模型执行方式的输入和输出示例。

使用的训练和验证数据 必须 格式化为 JSON 行(JSONL)文档。 它还必须采用聊天完成 API 使用的对话格式。

除 JSONL 格式外,训练和验证数据文件必须以 UTF-8 编码并包含字节顺序标记 (BOM)。 每个文件的大小必须小于 512 MB。

如果需要微调 gpt-4o-mini-2024-07-18的分步演练,请参阅 Azure OpenAI 微调教程

示例文件格式

{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who discovered Antarctica?"}, {"role": "assistant", "content": "Some chaps named Fabian Gottlieb von Bellingshausen and Mikhail Lazarev, as if they don't teach that in every school!"}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What is the biggest ocean?"}, {"role": "assistant", "content": "The Pacific Ocean. It's not like it's a small pond or anything."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What is the largest planet?"}, {"role": "assistant", "content": "It's called Jupiter, you might have heard of it...or not."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who painted the Mona Lisa?"}, {"role": "assistant", "content": "Oh, some obscure artist named Leonardo da Vinci. Not that he is famous or anything."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the boiling point of water?"}, {"role": "assistant", "content": "Exciting fact of the day: it's 100 degrees Celsius. Life-changing, isn't it?"}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who wrote 'The Odyssey'?"}, {"role": "assistant", "content": "Oh, just some poet named Homer. Nothing special, really."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What is the largest mammal?"}, {"role": "assistant", "content": "Blue Whale. Quite a big fish, isn't it? Oh wait, it's not a fish!"}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the highest mountain peak?"}, {"role": "assistant", "content": "Everest. Brace yourself, it's not a walk in the park."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who invented the telephone?"}, {"role": "assistant", "content": "A guy named Alexander Graham Bell. Bet you didn't guess that one!"}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What is the distance from Earth to the Sun?"}, {"role": "assistant", "content": "About 93 million miles. Just a quick drive, really."}]}

多轮聊天文件格式

还支持在 JSONL 训练文件的单个行中进行多轮对话。 若要跳过对特定助理消息的微调,请添加可选的 weight 键/值对。 目前, weight 可以设置为 01

{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the capital/major city 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}]}

使用视觉的聊天补全

{"messages": [{"role": "user", "content": [{"type": "text", "text": "What's in this image?"}, {"type": "image_url", "image_url": {"url": "https://raw.githubusercontent.com/MicrosoftDocs/azure-ai-docs/main/articles/ai-services/openai/media/how-to/generated-seattle.png"}}]}, {"role": "assistant", "content": "The image appears to be a watercolor painting of a city skyline, featuring tall buildings and a recognizable structure often associated with Seattle, like the Space Needle. The artwork uses soft colors and brushstrokes to create a somewhat abstract and artistic representation of the cityscape."}]}

创建训练和验证数据集

训练示例越多越好。 如果没有至少 10 个训练示例,则微调作业不会继续,但这样一小部分不足以显著影响模型响应。 成功微调的最佳做法是提供数百个训练示例(如果不是数千个)。

通常,将数据集大小加倍会促使模型质量呈线性增长。 但请记住,低质量的示例可能会对性能产生负面影响。 如果在没有先筛选出最高质量示例的情况下使用大量内部数据训练模型,你的模型性能可能会低于预期。

上传训练数据

下一步是选择现有的已准备训练数据,或在自定义模型时上传要使用的新准备训练数据。 准备好训练数据后,可将文件上传到服务。 可通过两种方式上传训练数据:

对于大型数据文件,建议从 Blob 存储导入。 通过多部分表单上传大型文件时,大型文件可能会变得不稳定,因为请求是原子的,无法重试或恢复。 有关 Blob 存储的详细信息,请参阅 什么是 Azure Blob 存储?

以下 Python 示例使用 Python SDK 上传本地训练和验证文件,并检索返回的文件 ID:

import os
from openai import OpenAI

# Load the OpenAI client
client = OpenAI(
  api_key = os.getenv("AZURE_OPENAI_API_KEY"),  
  base_url="https://YOUR-RESOURCE-NAME.openai.azure.com/openai/v1/"
)

# Upload the training and validation dataset files to Microsoft Foundry with the SDK.
training_file_name = 'training_set.jsonl'
validation_file_name = 'validation_set.jsonl'

training_response = client.files.create(file=open(training_file_name, "rb"), purpose="fine-tune")
validation_response = client.files.create(file=open(validation_file_name, "rb"), purpose="fine-tune")
training_file_id = training_response.id
validation_file_id = validation_response.id

print("Training file ID:", training_file_id)
print("Validation file ID:", validation_file_id)

创建自定义模型

上传训练和验证文件后,即可启动微调作业。

以下 Python 代码演示了如何使用 Python SDK 创建新的微调作业的示例:

response = client.fine_tuning.jobs.create(
    training_file=training_file_id,
    validation_file=validation_file_id,
    model="gpt-4.1-2025-04-14", # Enter the base model name.
    suffix="my-model", # Custom suffix for naming the resulting model. Note that in Microsoft Foundry, the model can't contain dot/period characters.
    seed=105, # Seed parameter controls reproducibility of the fine-tuning job. If you don't specify a seed, one is generated automatically.
    extra_body={ "trainingType": "GlobalStandard" } # Change this value to your preferred training type. Other options are `Standard` and `Developer`.
)

job_id = response.id

# You can use the job ID to monitor the status of the fine-tuning job.
# The fine-tuning job takes some time to start and finish.

print("Job ID:", response.id)
print(response.model_dump_json(indent=2))

注释

建议对训练类型使用全局标准层,因为它可以 节省成本 ,并使用全局容量来加快排队时间。 但是,它会在当前资源区域之外复制数据和权重。 如果需要 数据驻留 ,请使用支持标准层训练的 模型

还可以传递其他可选参数(如超参数)以更好地控制微调过程。 对于初始训练,我们建议使用不存在的自动默认值,而无需指定这些参数。

当前支持的用于监督微调的超参数包括:

Name 类型 DESCRIPTION
batch_size 整数 要用于训练的批大小。 批大小表示用于训练单个前向和后向传递的训练示例的数量。 一般情况下,我们发现较大的批大小往往更适用于较大的数据集。

此属性的默认值和最大值特定于基础模型。 批大小越大意味着模型参数的更新频率越低,但方差越小。
learning_rate_multiplier Number 用于训练的学习率乘数。 微调学习率是用于预训练的原始学习率乘以此值。

较大的学习率通常在较大的批大小中表现更好。 建议试验范围从 0.020.2 的值,以查看哪个能产生最佳结果。 较小的学习率可以用于避免过度拟合。
n_epochs 整数 训练模型的时期数。 一个时期是指训练数据集的一个完整周期。
seed 整数 控制作业可重复性的种子。 传入相同的种子和任务参数应产生相同的结果,但在极少数情况下可能会有所不同。 如果未指定种子,则会为你生成一个种子。

若要使用 OpenAI Python API 的 1.x 版本设置自定义超参数,请将其作为以下内容的一部分 method提供:

client.fine_tuning.jobs.create(
  training_file="file-abc123", 
  model="gpt-4.1-2025-04-14",
  suffix="my-model",
  seed=105,
  method={
    "type": "supervised", # In this case, the job is using supervised fine-tuning.
    "supervised": {
      "hyperparameters": {
        "n_epochs": 2
      }
    }
  },
  extra_body={ "trainingType": "GlobalStandard" }
)

若要了解其他自定义方法支持的超参数,请参阅 直接首选项优化指南强化微调指南

训练类型

根据用例和预算选择训练层:

  • 标准:训练发生在当前 Foundry 资源的区域中,并提供数据驻留的保证。 非常适合数据必须驻留在特定区域的工作负载。

  • 全球:通过使用超出当前区域的容量,提供比标准更实惠的定价。 数据和权重被复制到训练发生的区域。 非常适合数据驻留不是限制,并且需要更快队列时间的情况。

  • 开发人员(预览版):使用空闲容量进行培训,可节省大量成本。 没有延迟或 SLA 保证,因此此等级的作业可能会被自动抢占并稍后恢复。 数据驻留也没有保证。 非常适合实验和具有价格敏感性的工作负载。

import openai
from openai import AzureOpenAI

base_uri = "https://<ACCOUNT-NAME>.services.ai.azure.com"
api_key = "<API-KEY>"
api_version = "2025-04-01-preview"
client = AzureOpenAI(
azure_endpoint=base_uri,
api_key=api_key,
api_version=api_version
)
try:
    client.fine_tuning.jobs.create(
    model="gpt-4.1-mini",
    training_file="<FILE-ID>",
    extra_body={"trainingType": "developerTier"}
    )
except openai.APIConnectionError as e:
    print("The server could not be reached")
    print(e.__cause__) # An underlying exception, likely raised within httpx.
except openai.RateLimitError as e:
    print("A 429 status code was received; we should back off a bit.")
except openai.APIStatusError as e:
    print("Another non-200-range status code was received")
    print(e.status_code)
    print(e.response)
    print(e.body)

检查微调作业状态

response = client.fine_tuning.jobs.retrieve(job_id)

print("Job ID:", response.id)
print("Status:", response.status)
print(response.model_dump_json(indent=2))

列出微调事件

若要检查训练期间生成的单个微调事件,请运行以下命令。 运行命令之前,可能需要使用 pip install openai --upgrade以下命令将 OpenAI 客户端库升级到最新版本。

response = client.fine_tuning.jobs.list_events(fine_tuning_job_id=job_id, limit=10)
print(response.model_dump_json(indent=2))

列出检查点

每个训练时期的完成都会生成一个检查点。 检查点是模型的一种完全可运行版本,可以被部署并用作随后的微调作业的目标模型。 检查点尤其有用,因为它们可能提供过拟合前的快照。

微调作业完成后,可以使用三个最新版本的模型进行部署。 你的微调模型代表最终训练周期的模型。 前两个时期可用作检查点。

可以运行以下命令来检索与单个微调作业关联的检查点列表。 运行命令之前,可能需要使用 pip install openai --upgrade以下命令将 OpenAI 客户端库升级到最新版本。

response = client.fine_tuning.jobs.checkpoints.list(job_id)
print(response.model_dump_json(indent=2))

分析自定义模型

Azure OpenAI 会在完成每个微调作业后附加一个名为 results.csv 的结果文件。 可以使用该结果文件来分析自定义模型的训练和验证性能。 将为每个自定义模型列出结果文件的文件 ID。 可以使用 Python SDK 检索文件 ID 并下载结果文件进行分析。

以下 Python 示例检索附加到自定义模型的微调作业的第一个结果文件的文件 ID。 然后,它使用 Python SDK 将文件下载到当前工作目录进行分析。

# Retrieve the file ID of the first result file from the fine-tuning job
# for the customized model.
response = client.fine_tuning.jobs.retrieve(job_id)
if response.status == 'succeeded':
    result_file_id = response.result_files[0]

retrieve = client.files.retrieve(result_file_id)

# Download the result file.
print(f'Downloading result file: {result_file_id}')

with open(retrieve.filename, "wb") as file:
    result = client.files.content(result_file_id).read()
    file.write(result)

结果文件是一个 CSV 文件,其中包含一个标头行,以及微调作业所执行的每个训练步骤对应的一行。 结果文件包含以下列:

列名称 DESCRIPTION
step 训练步骤数。 一个训练步骤代表针对一批训练数据前向和后向执行的一轮操作。
train_loss 训练批的损失。
train_mean_token_accuracy 模型在训练批次中正确预测的标记百分比。

例如,当批量大小设置为3,且数据中包含完成品[[1, 2], [0, 5], [4, 2]]时,如果模型预测为0.83,那么该值将被设置为[[1, 1], [0, 5], [4, 2]](6分之5)。
valid_loss 验证批的损失。
validation_mean_token_accuracy 验证批次中模型正确预测的令牌百分比。

例如,当批量大小设置为3,且数据中包含完成品[[1, 2], [0, 5], [4, 2]]时,如果模型预测为0.83,那么该值将被设置为[[1, 1], [0, 5], [4, 2]](6分之5)。
full_valid_loss 在每个纪元结束时计算的验证损失。 训练正常时,损失应减少。
full_valid_mean_token_accuracy 在每个纪元结束时计算的有效平均标记准确性。 训练正常时,标记准确性应增加。

还可以在 Microsoft Foundry 门户中以图表形式查看 results.csv 文件中的数据。 为已训练的模型选择链接时,将显示三个图表:丢失、平均令牌准确性和令牌准确性。 如果提供了验证数据,则这两个数据集都显示在同一绘图上。

随着时间的推移,损失会减少,而准确度提高。 如果你的训练数据和验证数据出现偏差,可能存在过拟合情况。 尝试使用更少的时期或较小的学习率乘数进行训练。

部署微调模型

如果对微调作业中的指标感到满意,或者只想继续推理,则必须部署模型。

如果您正在部署以进行进一步验证,可以考虑使用开发人员部署进行 测试

与以前的 SDK 命令不同,必须使用控制平面 API 进行部署。 此任务需要单独的授权、不同的 API 路径和不同的 API 版本。

Variable 定义
token 授权令牌。 可通过多种方式生成授权令牌。 初始测试的最简单方法是从 Azure 门户打开 Azure Cloud Shell。 然后运行 az account get-access-token。 可以将此令牌用作 API 测试的临时授权令牌。 建议将此令牌存储在新的环境变量中。
subscription 关联的 Azure OpenAI 资源的订阅 ID。
resource_group Azure OpenAI 资源的资源组名称。
resource_name Azure OpenAI 资源名称。
model_deployment_name 新微调模型部署的自定义名称。 此名称在聊天完成调用的代码中被引用。
fine_tuned_model 你的微调模型。 请从上一步的微调作业结果中检索此值。 应类似于 gpt-4.1-2025-04-14.ft-b044a9d3cf9c4228b5d393567f693b83。 需要将该值添加到 deploy_data JSON。 或者,可以通过传递以格式 ftchkpt-e559c011ecc04fc68eaa339d8227d02d显示的检查点 ID 来部署检查点。
import json
import os
import requests

token= os.getenv("<TOKEN>") 
subscription = "<YOUR_SUBSCRIPTION_ID>"  
resource_group = "<YOUR_RESOURCE_GROUP_NAME>"
resource_name = "<YOUR_AZURE_OPENAI_RESOURCE_NAME>"
model_deployment_name ="gpt-41-ft" # Custom deployment name that you use to reference the model when making inference calls.

deploy_params = {'api-version': "2024-10-01"} # Control plane API version rather than the data plane API for this call 
deploy_headers = {'Authorization': 'Bearer {}'.format(token), 'Content-Type': 'application/json'}

deploy_data = {
    "sku": {"name": "standard", "capacity": 1}, 
    "properties": {
        "model": {
            "format": "OpenAI",
            "name": <"fine_tuned_model">, # Retrieve this value from the previous call; it looks like gpt-4.1-2025-04-14.ft-b044a9d3cf9c4228b5d393567f693b83
            "version": "1"
        }
    }
}
deploy_data = json.dumps(deploy_data)

request_url = f'https://management.azure.com/subscriptions/{subscription}/resourceGroups/{resource_group}/providers/Microsoft.CognitiveServices/accounts/{resource_name}/deployments/{model_deployment_name}'

print('Creating a new deployment...')

r = requests.put(request_url, params=deploy_params, headers=deploy_headers, data=deploy_data)

print(r)
print(r.reason)
print(r.json())

若要了解跨区域部署以及如何使用已部署的模型,请参阅 使用已部署的微调模型

如果已准备好进行生产部署,或者需要特定的数据驻留需求,请遵循 部署指南

执行连续微调

创建经过微调的模型后,可能需要通过进一步微调以继续改进模型。 持续微调是选择已经微调的模型作为基础模型并在新的训练示例集上进一步对其进行微调的迭代过程。 仅 OpenAI 模型支持连续微调。

若要对以前微调的模型执行微调,请使用“ 创建自定义模型”中所述的相同过程。 但不是指定通用基础模型的名称,而是指定微调模型的 ID。 经过微调的模型的 ID 如下所示 gpt-4.1-2025-04-14.ft-5fd1918ee65d4cd38a5dcf6835066ed7

response = client.fine_tuning.jobs.create(
    training_file=training_file_id,
    validation_file=validation_file_id,
    model="gpt-4.1-2025-04-14.ft-5fd1918ee65d4cd38a5dcf6835066ed7"
)
job_id = response.id

# You can use the job ID to monitor the status of the fine-tuning job.
# The fine-tuning job takes some time to start and finish.

print("Job ID:", response.id)
print("Status:", response.id)
print(response.model_dump_json(indent=2))

我们还建议包含 suffix 参数,以便更轻松地区分微调模型的迭代。 该 suffix 参数采用字符串,并设置为标识微调的模型。 使用 OpenAI Python API,可以将最多 18 个字符的字符串添加到微调模型的名称中。

如果不确定现有微调模型的 ID,可以在 Microsoft Foundry 的 “模型 ”页上找到此信息。 或者,可以使用 REST API 为 Azure OpenAI 资源生成 模型列表

清理部署、自定义模型和训练文件

不再需要自定义模型时,可以删除部署和模型。 如有必要,还可以删除上传到服务的训练和验证文件。

删除模型部署

重要

部署自定义模型后,如果部署随时保持非活动状态超过 15 天,则会删除部署。 如果模型部署了 15 天以上,并且连续 15 天期间未进行聊天完成或响应 API 调用,则自定义模型的部署处于 非活动 状态。

删除非活动部署不会删除或影响基础自定义模型。 可以随时重新部署自定义模型。

Azure OpenAI 在 Microsoft Foundry 模型定价中的描述,每个部署的自定义(微调)模型都会产生每小时托管费用,无论是否对模型进行聊天完成或响应 API 调用。 若要详细了解如何使用 Azure OpenAI 规划和管理成本,请参阅 规划和管理 Azure OpenAI 的成本

可以使用以下任一方法删除自定义模型的部署:

删除自定义模型

可以使用 Foundry 删除自定义模型。

注释

如果自定义模型具有现有部署,则无法删除它。 必须先 删除模型部署 ,然后才能删除自定义模型。

删除训练文件

可以选择性地在 Azure OpenAI 订阅中删除为训练上传的训练和验证文件,以及在训练期间生成的结果文件。 可使用以下方法删除训练、验证和结果文件:

以下 Python 示例使用 Python SDK 删除自定义模型的训练、验证和结果文件:

print('Checking for existing uploaded files.')
results = []

# Get the complete list of uploaded files in your subscription.
files = openai.File.list().data
print(f'Found {len(files)} total uploaded files in the subscription.')

# Enumerate all uploaded files. Extract the IDs for the
# files with file names that match your training dataset file and
# validation dataset file.
for item in files:
    if item["filename"] in [training_file_name, validation_file_name, result_file_name]:
        results.append(item["id"])
print(f'Found {len(results)} already uploaded files that match our files')

# Enumerate the file IDs for your files and delete each file.
print(f'Deleting already uploaded files.')
for id in results:
    openai.File.delete(sid = id)

先决条件

支持的模型

若要检查哪些区域当前支持微调,请参阅 有关模型的文章

你也可以微调以前已微调的模型,格式为 base-model.ft-{jobid}

审阅 REST API 的工作流

花点时间查看有关将 REST API 和 Python 与 Azure OpenAI 配合使用的微调工作流:

  1. 准备训练和验证数据。
  2. 选择基础模型。
  3. 上传训练数据。
  4. 训练新的自定义模型。
  5. 检查自定义模型的状态。
  6. 部署供使用的自定义模型。
  7. 使用自定义模型。
  8. (可选)分析自定义模型的性能和拟合度。

准备训练和验证数据

你的训练和验证数据集包含希望模型执行方式的输入和输出示例。

使用的训练和验证数据 必须 格式化为 JSON 行(JSONL)文档。 它还必须采用聊天完成 API 使用的对话格式。

除 JSONL 格式外,训练和验证数据文件必须以 UTF-8 编码并包含字节顺序标记 (BOM)。 每个文件的大小必须小于 512 MB。

如果需要微调 gpt-4o-mini-2024-07-18的分步演练,请参阅 Azure OpenAI 微调教程

示例文件格式

{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who discovered Antarctica?"}, {"role": "assistant", "content": "Some chaps named Fabian Gottlieb von Bellingshausen and Mikhail Lazarev, as if they don't teach that in every school!"}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What is the biggest ocean?"}, {"role": "assistant", "content": "The Pacific Ocean. It's not like it's a small pond or anything."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What is the largest planet?"}, {"role": "assistant", "content": "It's called Jupiter, you might have heard of it...or not."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who painted the Mona Lisa?"}, {"role": "assistant", "content": "Oh, some obscure artist named Leonardo da Vinci. Not that he is famous or anything."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the boiling point of water?"}, {"role": "assistant", "content": "Exciting fact of the day: it's 100 degrees Celsius. Life-changing, isn't it?"}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who wrote 'The Odyssey'?"}, {"role": "assistant", "content": "Oh, just some poet named Homer. Nothing special, really."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What is the largest mammal?"}, {"role": "assistant", "content": "Blue Whale. Quite a big fish isn't it? Oh wait, it's not a fish!"}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the highest mountain peak?"}, {"role": "assistant", "content": "Everest. Brace yourself, it's not a walk in the park."}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who invented the telephone?"}, {"role": "assistant", "content": "A guy named Alexander Graham Bell. Bet you didn't guess that one!"}]}
{"messages": [{"role": "system", "content": "Clippy is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What is the distance from Earth to the Sun?"}, {"role": "assistant", "content": "About 93 million miles. Just a quick drive, really."}]}

多轮聊天文件格式

还支持在 JSONL 训练文件的单个行中进行多轮对话。 若要跳过对特定助理消息的微调,请添加可选的 weight 键/值对。 目前, weight 可以设置为 01

{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the capital/major city 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}]}

使用视觉的聊天补全

{"messages": [{"role": "user", "content": [{"type": "text", "text": "What's in this image?"}, {"type": "image_url", "image_url": {"url": "https://raw.githubusercontent.com/MicrosoftDocs/azure-ai-docs/main/articles/ai-services/openai/media/how-to/generated-seattle.png"}}]}, {"role": "assistant", "content": "The image appears to be a watercolor painting of a city skyline, featuring tall buildings and a recognizable structure often associated with Seattle, like the Space Needle. The artwork uses soft colors and brushstrokes to create a somewhat abstract and artistic representation of the cityscape."}]}

创建训练和验证数据集

训练示例越多越好。 如果没有至少 10 个训练示例,则微调作业不会继续,但这样一小部分不足以显著影响模型响应。 成功微调的最佳做法是提供数百个训练示例(如果不是数千个)。

通常,将数据集大小加倍会促使模型质量呈线性增长。 但请记住,低质量的示例可能会对性能产生负面影响。 如果在没有先筛选出最高质量示例的情况下使用大量内部数据训练模型,你的模型性能可能会低于预期。

上传训练数据

下一步是选择现有的已准备训练数据,或在自定义模型时上传要使用的新准备训练数据。 准备好训练数据后,可将文件上传到服务。 可通过两种方式上传训练数据:

对于大型数据文件,建议从 Blob 存储导入。 通过多部分表单上传大型文件时,大型文件可能会变得不稳定,因为请求是原子的,无法重试或恢复。 有关 Blob 存储的详细信息,请参阅 什么是 Azure Blob 存储?

上传训练数据

curl -X POST $AZURE_OPENAI_ENDPOINT/openai/v1/files \
  -H "Content-Type: multipart/form-data" \
  -H "api-key: $AZURE_OPENAI_API_KEY" \
  -F "purpose=fine-tune" \
  -F "file=@C:\\fine-tuning\\training_set.jsonl;type=application/json"

上传验证数据

curl -X POST $AZURE_OPENAI_ENDPOINT/openai/v1/files \
  -H "Content-Type: multipart/form-data" \
  -H "api-key: $AZURE_OPENAI_API_KEY" \
  -F "purpose=fine-tune" \
  -F "file=@C:\\fine-tuning\\validation_set.jsonl;type=application/json"

创建自定义模型

上传训练和验证文件后,即可启动微调作业。 以下代码演示了如何使用 REST API 创建新的微调作业 的示例。

此示例包括传递种子参数。 种子控制作业的可重现性。 传入相同的种子和任务参数应产生相同的结果,但在极少数情况下可能会有所不同。 如果未指定种子,则会为你生成一个种子。

curl -X POST $AZURE_OPENAI_ENDPOINT/openai/v1/fine_tuning/jobs \
  -H "Content-Type: application/json" \
  -H "api-key: $AZURE_OPENAI_API_KEY" \
  -d '{
    "model": "gpt-4.1-2025-04-14",
    "training_file": "<TRAINING_FILE_ID>",
    "validation_file": "<VALIDATION_FILE_ID>",
    "seed": 105
}'

如果要微调支持 全局训练的模型,您可以通过使用 extra_body 命名参数并结合 api-version=2025-04-01-preview 来指定训练类型:

curl -X POST $AZURE_OPENAI_ENDPOINT/openai/fine_tuning/jobs?api-version=2025-04-01-preview \
  -H "Content-Type: application/json" \
  -H "api-key: $AZURE_OPENAI_API_KEY" \
  -d '{
    "model": "gpt-4.1-2025-04-14",
    "training_file": "<TRAINING_FILE_ID>",
    "validation_file": "<VALIDATION_FILE_ID>",
    "seed": 105,
    "trainingType": "globalstandard"
}'

还可以传递其他可选参数(例如超参数),以更好地控制微调过程。 对于初始训练,我们建议使用不存在的自动默认值,而无需指定这些参数。

当前支持的用于监督微调的超参数包括:

Name 类型 DESCRIPTION
batch_size 整数 要用于训练的批大小。 批大小表示用于训练单个前向和后向传递的训练示例的数量。 一般情况下,我们发现较大的批大小往往更适用于较大的数据集。

此属性的默认值和最大值特定于基础模型。 批大小越大意味着模型参数的更新频率越低,但方差越小。
learning_rate_multiplier Number 用于训练的学习率乘数。 微调学习率是用于预训练的原始学习率乘以此值。

较大的学习率通常在较大的批大小中表现更好。 建议试验范围从 0.020.2 的值,以查看哪个能产生最佳结果。 较小的学习率可以用于避免过度拟合。
n_epochs 整数 训练模型的时期数。 一个时期是指训练数据集的一个完整周期。
seed 整数 控制作业可重复性的种子。

若要了解其他自定义方法支持的超参数,请参阅 直接首选项优化指南强化微调指南

选择训练类型

根据用例和预算选择训练层:

  • 标准:训练发生在当前 Foundry 资源的区域中,并提供数据驻留的保证。 非常适合数据必须驻留在特定区域的工作负载。

  • 全球:通过使用超出当前区域的容量,提供比标准更实惠的定价。 数据和权重被复制到训练发生的区域。 非常适合数据驻留不是限制,并且需要更快队列时间的情况。

  • 开发人员(预览版):使用空闲容量进行培训,可节省大量成本。 没有延迟或 SLA 保证,因此此等级的作业可能会被自动抢占并稍后恢复。 也没有数据驻留保证。 非常适合实验和具有价格敏感性的工作负载。

curl -X POST "https://<ACCOUNT-NAME>.openai.azure.com/openai/fine_tuning/jobs?api-version=2025-04-01-preview" -H "Content-Type: application/json" -H "api-key: <API-KEY>" -d "{"model": "gpt-4.1", "training_file": "<FILE_ID>", "hyperparameters": {"prompt_loss_weight": 0.1}, "trainingType": "developerTier"}"

检查自定义模型的状态

启动微调作业后,可能需要一些时间才能完成。 你的作业可能排在系统上的其他作业后面。 训练模型可能需要几分钟或几个小时,具体取决于模型和数据集大小。

以下示例使用 REST API 检查微调作业的状态。 该示例使用上一示例返回的作业 ID 检索有关作业的信息。

curl -X GET $AZURE_OPENAI_ENDPOINT/openai/v1/fine_tuning/jobs/<YOUR-JOB-ID> \
  -H "api-key: $AZURE_OPENAI_API_KEY"

列出微调事件

若要检查训练期间生成的各个微调事件:

curl -X POST $AZURE_OPENAI_ENDPOINT/openai/v1/fine_tuning/jobs/{fine_tuning_job_id}/events \
  -H "Content-Type: application/json" \
  -H "api-key: $AZURE_OPENAI_API_KEY" 

列出检查点

每个训练时期的完成都会生成一个检查点。 检查点是模型的一种完全可运行版本,可以被部署并用作随后的微调作业的目标模型。 检查点尤其有用,因为它们可能提供过拟合前的快照。

微调作业完成后,可以使用三个最新版本的模型进行部署。 你的微调模型代表最终训练周期的模型。 前两个时期可用作检查点。

可以运行以下命令来检索与单个微调作业关联的检查点列表:

curl -X POST $AZURE_OPENAI_ENDPOINT/openai/v1/fine_tuning/jobs/{fine_tuning_job_id}/checkpoints \
  -H "Content-Type: application/json" \
  -H "api-key: $AZURE_OPENAI_API_KEY" 

暂停和恢复

在训练期间,可以查看日志和指标,并根据需要暂停作业。 如果指标不聚合,或者认为模型没有以正确的速度学习,暂停可能会很有用。

训练作业暂停并完成安全评估后,将创建可部署的检查点。 此检查点可用于部署并进行推理,或者您可以恢复任务以将其完成。

暂停操作仅适用于经过至少一个步骤的训练且处于 “正在运行” 状态的任务。

暂停

curl -X POST $AZURE_OPENAI_ENDPOINT/openai/v1/fine_tuning/jobs/{fine_tuning_job_id}/pause \
  -H "Content-Type: application/json" \
  -H "api-key: $AZURE_OPENAI_API_KEY" 

恢复

curl -X POST $AZURE_OPENAI_ENDPOINT/openai/v1/fine_tuning/jobs/{fine_tuning_job_id}/resume \
  -H "Content-Type: application/json" \
  -H "api-key: $AZURE_OPENAI_API_KEY" 

复制模型(预览版)

现在可以将微调后的检查点模型从一个区域复制到另一个区域,跨不同订阅,但需在同一租户内进行。 此过程使用专用 API 来帮助确保高效且安全的传输。 此功能目前仅适用于 API,而不能通过 Foundry 门户使用。

将模型从区域 A 复制到区域 B 后,可以不断微调区域 B 中的模型,并从此位置部署模型。

注释

删除源区域中的模型检查点不会导致在目标区域中删除模型。 若要在复制模型后删除这两个区域中的模型,必须在每个区域中单独部署模型。

先决条件

  • 目标资源或账户应至少存在一个微调作业。
  • 目标资源或帐户不应禁用公共网络访问(至少发送复制请求时)。
  • 如果启动副本的帐户具有访问目标帐户的足够权限,则只能复制到目标帐户。

配置权限

  1. 创建 用户分配的托管标识
  2. 为目标资源或账户上的用户分配的托管身份授予 Azure AI 用户角色。
  3. 将用户分配的托管标识分配给源资源帐户。

复制模型

curl --request POST \
  --url 'https://<aoai-resource>.openai.azure.com/openai/v1/fine_tuning/jobs/<ftjob>/checkpoints/<checkpoint-name>/copy' \
  --header 'Content-Type: application/json' \
  --header 'api-key: <api-key>' \
  --header 'aoai-copy-ft-checkpoints: preview' \
  --data '{
  "destinationResourceId": "<resourceId>",
  "region": "<region>"
}'

由于这是长时间运行的操作,因此通过提供所用调用中的 POST 源帐户检查点 ID 来检查经微调的模型副本的状态。

检查复制状态

curl --request GET \
  --url 'https://<aoai-resource>.openai.azure.com//openai/v1/fine_tuning/jobs/<ftjob>/checkpoints/<checkpoint-name>/copy' \
  --header 'Content-Type: application/json' \
  --header 'api-key: <api-key>' \
  --header 'aoai-copy-ft-checkpoints: preview' 

注释

从源帐户复制检查点时,目标帐户中会保留相同的检查点名称。 确保在目标账户中对微调、部署或其他操作使用完全相同的名称。 此检查点不会显示在 UI 或 list checkpoints API 中。

分析自定义模型

Azure OpenAI 会在完成每个微调作业后附加一个名为 results.csv 的结果文件。 可以使用该结果文件来分析自定义模型的训练和验证性能。 将为每个自定义模型列出结果文件的文件 ID。 可以使用 REST API 检索文件 ID 并下载结果文件进行分析。

以下 Python 示例使用 REST API 检索附加到自定义模型的微调作业的第一个结果文件的文件 ID。 然后,它将文件下载到工作目录进行分析。

curl -X GET "$AZURE_OPENAI_ENDPOINT/openai/v1/fine_tuning/jobs/<JOB_ID>" \
  -H "api-key: $AZURE_OPENAI_API_KEY")
curl -X GET "$AZURE_OPENAI_ENDPOINT/openai/v1/files/<RESULT_FILE_ID>/content" \
    -H "api-key: $AZURE_OPENAI_API_KEY" > <RESULT_FILENAME>

结果文件是一个 CSV 文件,其中包含一个标头行,以及微调作业所执行的每个训练步骤对应的一行。 结果文件包含以下列:

列名称 DESCRIPTION
step 训练步骤数。 一个训练步骤代表针对一批训练数据前向和后向执行的一轮操作。
train_loss 训练批的损失。
train_mean_token_accuracy 模型在训练批次中正确预测的标记百分比。

例如,当批量大小设置为3,且数据中包含完成品[[1, 2], [0, 5], [4, 2]]时,如果模型预测为0.83,那么该值将被设置为[[1, 1], [0, 5], [4, 2]](6分之5)。
valid_loss 验证批的损失。
validation_mean_token_accuracy 验证批次中模型正确预测的令牌百分比。

例如,当批量大小设置为3,且数据中包含完成品[[1, 2], [0, 5], [4, 2]]时,如果模型预测为0.83,那么该值将被设置为[[1, 1], [0, 5], [4, 2]](6分之5)。
full_valid_loss 在每个纪元结束时计算的验证损失。 训练正常时,损失应减少。
full_valid_mean_token_accuracy 在每个纪元结束时计算的有效平均标记准确性。 训练正常时,标记准确性应增加。

还可以在 Foundry 门户中以图表的形式查看 results.csv 文件中的数据。 为已训练的模型选择链接时,将显示三个图表:丢失、平均令牌准确性和令牌准确性。 如果提供了验证数据,则这两个数据集都显示在同一绘图上。

随着时间的推移,损失会减少,而准确度提高。 如果你的训练数据和验证数据出现偏差,可能存在过拟合情况。 尝试使用更少的时期或较小的学习率乘数进行训练。

部署微调模型

如果对微调作业中的指标感到满意,或者只想继续推理,则必须部署模型。

如果您正在部署以进行进一步验证,可以考虑使用开发人员部署进行 测试

如果已准备好进行生产部署,或者需要特定的数据驻留需求,请遵循 部署指南

Variable 定义
token 授权令牌。 可通过多种方式生成授权令牌。 初始测试的最简单方法是从 Azure 门户打开 Azure Cloud Shell。 然后运行 az account get-access-token。 可以将此令牌用作 API 测试的临时授权令牌。 建议将此令牌存储在新的环境变量中。
subscription 关联的 Azure OpenAI 资源的订阅 ID。
resource_group Azure OpenAI 资源的资源组名称。
resource_name Azure OpenAI 资源名称。
model_deployment_name 新微调模型部署的自定义名称。 此名称在聊天完成调用的代码中被引用。
fine_tuned_model 你的微调模型。 请从上一步的微调作业结果中检索此值。 应类似于 gpt-4.1-2025-04-14.ft-b044a9d3cf9c4228b5d393567f693b83。 需要将该值添加到 deploy_data JSON。 或者,可以通过传递以格式 ftchkpt-e559c011ecc04fc68eaa339d8227d02d显示的检查点 ID 来部署检查点。
curl -X POST "https://management.azure.com/subscriptions/<SUBSCRIPTION>/resourceGroups/<RESOURCE_GROUP>/providers/Microsoft.CognitiveServices/accounts/<RESOURCE_NAME>/deployments/<MODEL_DEPLOYMENT_NAME>?api-version=2024-10-21" \
  -H "Authorization: Bearer <TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
    "sku": {"name": "standard", "capacity": 1},
    "properties": {
        "model": {
            "format": "OpenAI",
            "name": "<FINE_TUNED_MODEL>",
            "version": "1"
        }
    }
}'

若要了解跨区域部署以及如何使用已部署的模型,请参阅 使用已部署的微调模型

执行连续微调

创建经过微调的模型后,可能需要通过进一步微调以继续改进模型。 持续微调是选择已经微调的模型作为基础模型并在新的训练示例集上进一步对其进行微调的迭代过程。 仅 OpenAI 模型支持连续微调。

若要对以前微调的模型执行微调,请使用“ 创建自定义模型”中所述的相同过程。 但不是指定通用基础模型的名称,而是指定微调模型的 ID。 经过微调的模型的 ID 如下所示 gpt-4.1-2025-04-14.ft-5fd1918ee65d4cd38a5dcf6835066ed7

curl -X POST $AZURE_OPENAI_ENDPOINT/openai/v1/fine_tuning/jobs \
  -H "Content-Type: application/json" \
  -H "api-key: $AZURE_OPENAI_API_KEY" \
  -d '{
    "model": "gpt-4.1-2025-04-14.ft-5fd1918ee65d4cd38a5dcf6835066ed7",
    "training_file": "<TRAINING_FILE_ID>",
    "validation_file": "<VALIDATION_FILE_ID>",
    "suffix": "<additional text used to help identify fine-tuned models>"
}'

我们还建议包含 suffix 参数,以便更轻松地区分微调模型的迭代。 该 suffix 参数采用字符串,并设置为标识微调的模型。 后缀最多可以包含 40 个字符(azAZ09-_),这些字符将被添加到您的微调模型的名称中。

如果不确定现有微调模型的 ID,可以在 Foundry 的 “模型 ”页上找到此信息。 或者,可以使用 REST API 为 Azure OpenAI 资源生成 模型列表

清理部署、自定义模型和训练文件

不再需要自定义模型时,可以删除部署和模型。 如有必要,还可以删除上传到服务的训练和验证文件。

删除模型部署

可以使用以下任一方法删除自定义模型的部署:

删除自定义模型

可以使用 Foundry 删除自定义模型。

注释

如果自定义模型具有现有部署,则无法删除它。 必须先 删除模型部署 ,然后才能删除自定义模型。

删除训练文件

可以选择性地在 Azure OpenAI 订阅中删除为训练上传的训练和验证文件,以及在训练期间生成的结果文件。 可以使用 Foundry 删除文件。