微调 GPT-3.5:一个实用的 Python 示例 – 迷途通

微调 GPT-3.5:一个实用的 Python 示例

5月 1, 2023                      👁️ 18
微调 GPT-3.5:一个实用的 Python 示例

现在可以对 OpenAI 提供的关键模型之一进行微调。到目前为止,我们只能对性能低于 GPT-3.5 和 GPT-4 等的旧型号进行微调。现在可以在不耗尽预算的情况下最大限度地提高 OpenAI 模型的性能。

为什么要微调?

  1. 更好的响应
  2. 与少样本学习方法相比,使用更多示例进行训练(在提示中给出一些示例)
  3. 更短的提示 – 更低的成本和延迟

OpenAI 还列出了以下好处:改进的可操纵性、可靠的输出格式和自定义音调。

您可以在 GitHub 上找到本文中的所有代码:
https://github.com/horosin/open-finetuning
该代码是实验性的,仅供多次使用,不要指望它会被打磨。

请记住,对于 JSON 输出,最好使用函数调用功能。也就是说,本教程应该向您展示如何进行一般的微调。

示例用例:用于生成虚假身份的 JSON 输出格式

将大型语言模型用于 JSON 输出格式设置等任务通常会导致冗长且成本高昂的提示。让我们通过一个示例用例来探讨这一挑战。

我非常喜欢使用像 GPT-4 这样的大型语言模型 (LLM) 进行语言处理。许多人在这个用例中使用流行的库 Langchain(我写过它),而其他人则使用原生函数调用功能(我做了一个简短的演示)。这两者都使用额外的令牌,并且容易出错。

让我们看一个特定的例子。假设我们经常需要以结构化格式生成人们的身份,以为我们的演示数据库提供种子,在开发阶段填充仪表板等。让我们以典型的 Twitter/X 用户配置文件为例,并尝试生成其部分。

{
    "name": "John Doe",
    "handle": "jdoe",
    "age": 30,
    "hobbies": ["programming", "gaming", "reading"],
    "email": "john.doe@gmail.com",
    "bio": "Avid Python programmer and gamer",
    "location": "USA",
    "is_blue_badge": True,
    "joined": "2019-01-01",
    "gender": "male",
    "appearance": "white, brown hair, brown eyes, 6'0",
    "avatar_prompt": "A photorealistic image of a man, white, brown hair, brown eyes, against a blurred backdrop od a home scenery. Use a Hasselblad camera with a 85mm lens at F 1.2 aperture setting and soft sunlight falling on the subject to capture the subject’s creativity.",
    "banner_prompt": "High resolution photo of a desk with a laptop, a gamepad and a book. Canon DSLR."
}

实现这一点并取得高度成功的提示很长,尤其是使用 Langchain 模板,请看一下:

也就是说,输入需要 923 个令牌,输出需要 236 个令牌。使用 GPT-41 生成一千个将花费我们 85.4 美元。使用 GPT 3.5,我们可以以 1.85 美元的价格做到这一点。如果能够实现微调的承诺,并且我们通过更短的提示获得更接近 GPT-4 的性能,我们将节省大量资金。大多数用例需要更多数据。

我们可以尝试做的是通过微调到以下内容来减少提示:

作为响应,请在 JSON 字典中提供以下字段:姓名、句柄、年龄、爱好、电子邮件、简历、位置、is_blue_badge、加入、性别、外貌、avatar_prompt和banner_prompt。

生成随机 Twitter 个人资料的详细信息。

有了这个及时和微调的模型,我们将支付 4.388 美元。比 GPT-10 少 4 倍,但几乎是 GPT-3.3 的 5 倍。本教程中的微调成本约为 0.4 USD。

让我们看看这是如何实现的。我没有自动比较生成结果的质量的方法,但如果您知道任何研究,请在评论中告知大家。

可以在项目存储库中找到生成此提示的代码。

准备合成训练数据

通过运行 确保您拥有最新版本的 openai 包。pip install -U -r requirements.txt

您还需要在环境变量中包含 OpenAPI 密钥。.export OPENAI_API_KEY="XXXXX"

让我们使用 GPT-4 按照 OpenAI 的最低要求准备 50 个示例。这将花费我们大约 2.4 美元。我们正在利用 GPT-4 的强大功能来提供高质量的示例来训练我们的模型。

import openai
import json

prompt = "COMPLICATED LONG PROMPT"

SAMPLE_COUNT = 50

examples = []

for i in range(SAMPLE_COUNT):
    chat_completion = openai.ChatCompletion.create(
        model="gpt-4", messages=[{"role": "user", "content": prompt}]
    )
    print(chat_completion.choices[0].message.content)
    examples.append(json.loads(chat_completion.choices[0].message.content))

with open("training_examples.json", "w") as outfile:
    outfile.write(json.dumps(examples))

现在,有了 GPT-50 的 4 个强大示例,我们可以微调我们的 3.5 模型。

数据格式

OpenAI 建议使用系统消息作为输入数据。它使用系统提示作为传递一般指令的推荐方法。让我们构建模板消息。

{
    "messages": [
        {
            "role": "system",
            "content": "As a response, provide the following fields in a JSON dict: name, handle, age, hobbies, email, bio, location, is_blue_badge, joined, gender, appearance, avatar_prompt, and banner_prompt."
        },
        {
            "role": "user",
            "content": "Generate details of a random Twitter profile."
        },
        {
            "role": "assistant",
            "content": f"{profile_details}"
}

我们还需要准备一个文件,每个 JSON 对象都在一个新行中,并通过 OpenAI 提供的验证器运行它。

transform_data.py

import json

# Load the data from the json file
with open('training_examples.json', 'r') as f:
    profiles = json.load(f)

# Output file to save the formatted messages
with open('mydata.jsonl', 'w') as out_file:
    for profile in profiles:
        profile_details = json.dumps(profile)

        # Create the desired format
        formatted_message = {
            "messages": [
                {
                    "role": "system",
                    "content": "As a response, provide the following fields in a JSON dict: name, handle, age, hobbies, email, bio, location, is_blue_badge, joined, gender, appearance, avatar_prompt, and banner_prompt."
                },
                {
                    "role": "user",
                    "content": "Generate details of a random Twitter profile."
                },
                {
                    "role": "assistant",
                    "content": profile_details
                }
            ]
        }

        # Write the formatted message to the output file, each on a new line
        out_file.write(json.dumps(formatted_message) + "\n")

现在,让我们运行格式化脚本(在名为 .openai_formatting.py

python openai_formatting.py

您应该会收到以下消息。

0 examples may be over the 4096 token limit, they will be truncated during fine-tuning
Dataset has ~14194 tokens that will be charged for during training
By default, you'll train for 3 epochs on this dataset
By default, you'll be charged for ~42582 tokens
See pricing page to estimate total costs

在我们的例子中,微调将花费 0.34 美元。

微调模型

我已将所有必要的调用编译到一个文件中。该脚本将文件与我们的数据一起上传,等待它进行处理,然后开始微调过程。小心,运行它会产生成本!

finetune.py

import os
import openai
import time

openai.api_key = os.getenv("OPENAI_API_KEY")

file_upload = openai.File.create(file=open("mydata.jsonl", "rb"), purpose="fine-tune")
print("Uploaded file id", file_upload.id)

while True:
    print("Waiting for file to process...")
    file_handle = openai.File.retrieve(id=file_upload.id)
    if len(file_handle) and file_handle.status == "processed":
        print("File processed")
        break
    time.sleep(3)


job = openai.FineTuningJob.create(training_file=file_upload.id, model="gpt-3.5-turbo")

while True:
    print("Waiting for fine-tuning to complete...")
    job_handle = openai.FineTuningJob.retrieve(id=job.id)
    if job_handle.status == "succeeded":
        print("Fine-tuning complete")
        print("Fine-tuned model info", job_handle)
        print("Model id", job_handle.fine_tuned_model)
        break
    time.sleep(3)

通过键入 .python finetune.py

如果您不想等待,请停止脚本并等待收到来自 OpenAI 的电子邮件。

终端中的消息和电子邮件都将包含型号 ID!现在让我们来测试一下!

测试模型

让我们准备测试文件。将model_id替换为您的。

run_model.py

import os
import openai

openai.api_key = os.getenv("OPENAI_API_KEY")

model_id = "ft:gpt-3.5-turbo:my-org:custom_suffix:id"

completion = openai.ChatCompletion.create(
    model=model_id,
    messages=[
        {
            "role": "system",
            "content": "As a response, provide the following fields in a JSON dict: name, handle, age, hobbies, email, bio, location, is_blue_badge, joined, gender, appearance, avatar_prompt, and banner_prompt.",
        },
        {"role": "user", "content": "Generate details of a random Twitter profile."},
    ],
)

print(completion.choices[0].message)
python run_model.py

我们应该收到与此类似的输出!

{
    "name": "Daniela Kolarova",
    "handle": "PragueReveries",
    "age": 29,
    "hobbies": ["classical piano", "literature", "yoga"],
    "email": "daniela.kolarova@czmail.cz",
    "bio": "Finding harmony through keys, books, and breaths. Embracing Prague's spellbinding tales.",
    "location": "Prague, Czech Republic",
    "is_blue_badge": True,
    "joined": "2014-05-01",
    "gender": "female",
    "appearance": "Caucasian, long wavy auburn hair, green eyes, 5'6\"",
    "avatar_prompt": "Photorealistic image of a caucasian woman with green eyes, playing a grand piano. Use Olympus PEN-F with a 38mm lens.",
    "banner_prompt": "High-resolution depiction of Prague's rooftops, cozy libraries, and serene yoga studios. Samsung Galaxy S20 II.",
}

正如你所看到的,我们已经实现了我们的目标,即用更短的提示生成高质量的数据,以拟合复杂的指令。我们没有衡量质量,因此请确保在您的用例中,这有意义且具有成本效益。

结论

微调为从 OpenAI 的模型中获得更具体和一致的输出开辟了一条途径。正如 Twitter 配置文件生成示例所示,微调满足了通过简短提示实现特定输出的承诺。

虽然微调提供了精确度,但它需要精心制作的训练数据,以确保模型不只是记住示例。这个过程涉及时间和金钱方面的初始投资(幸运的是,我们可以使用更强大的模型生成微调数据)。此外,应不断评估产出的质量,以确保其符合规定的标准。

对于严重依赖 GPT-4 等 LLM 性能的企业或项目,微调是优化性能和成本的可行选择。

与任何技术一样,及时了解该领域的最佳实践和最新发展至关重要。OpenAI 继续发展其产品,采用灵活的方法可确保您可以利用这些模型的最佳功能来满足您的特定需求。

您可以在 GitHub 上找到本教程的代码:
https://github.com/horosin/open-finetuning

发表回复

您的电子邮箱地址不会被公开。