人工智能学习

使用 Llama 3.1 创建合成数据集以微调您的LLM

本文主要是介绍使用 Llama 3.1 创建合成数据集以微调您的LLM,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
使用巨大的Llama 3.1 405B和Nvidia Nemotron 4奖励模型来创建一个合成数据集用于指令微调。

由 AI 使用 Leonardo.AI 创建

数据是人工智能的核心,虽然数据是一项宝贵的资产,但我们知道开发高质量的数据集是多么具有挑战性和耗费成本。一个精心整理和过滤过的数据集可以弥补模型复杂度的不足。这种情况也适用于大型语言模型,较小规模的模型通过利用优质数据已经显示出比更大规模的LLM更好的表现。

在本文中,我们将探讨如何使用 Llama 3.1 405B 创建一个包含 git 命令的自然语言 的合成数据集。我将展示如何在不并行运行数十个 GPU 的情况下使用这个 405B 的模型。在有了初始的指令和响应数据集之后,我们将使用 Nvidia 的 Nemotron 4 作为奖励模型来过滤掉任何不良的提示/响应对。最后,我们将把该数据集推送到 HuggingFace,以便后续对我们的大语言模型进行微调。

这将会很快,免费,并且会给你很大的控制权。

我会保持这篇帖子简洁且内容充实,所以请务必读到最后,熟悉这项必备技能。

🦙 为什么选择 Llama 3.1

Meta 最新发布的 LLMs 系列Llama 3.1已经获得了稳固的地位。该系列包括了之前 8B 和 70B 模型的升级版本,增强了推理能力,并新增了一个巨大的 405B 模型。

Llama 3.1 405B 已经成功接近了最佳闭源模型的基准。(图表由 Maxime Labonne 提供,经许可)

Llama 3.1 405B 不仅仅在规模上令人印象深刻,还通过缩小闭源模型和开源模型之间的差距,在这方面做得比以往任何时候都好(上图)。

这种405B模型的能力使其非常适合一些最重要和最复杂的流程,例如检索增强生成(RAG)、监督微调(SFT),尤其是合成数据生成

为什么使用合成数据?

合成数据是通过人工模型创建的,该模型复制了现实世界数据的特性和特征。在某些时候,当你需要的数据比你拥有的更多时,你将需要使用它。

我们的自然语言形式的git命令数据集示例可以完美地展示这一点。如果我们想要创建一个应用程序,该应用程序可以接受用户需要的内容作为输入,然后为其推荐正确的git命令,那么在这个应用程序的核心,我们需要一个专家级的大语言模型(LLM)。我们可以使用GPT-4o或Claude,并且很可能会得到很好的结果。但是存在成本问题。因此,另一种选择是微调一个小型语言模型(SML),例如Llama 3.1 8B或Gemma 2 2B(我将在后续的帖子中介绍)。

而且猜猜我们需要什么来进行微调……数据!

由于我没有找到适合这个任务的合适数据集,我们只剩下一种解决方案:使用 Llama 3.1 405B 合成 创建我们的数据集。

🛠️构建数据集

为了使用AI构建合成数据集,我们将使用以下大纲。您可以从我选择的模型中选择任何其他LLM。

我们创建合成数据集的提纲。(由作者提供)

设置API密钥

我们将使用 Nvidia NIM API 来利用这些大型语言模型,而无需在本地运行它们的麻烦。运行像 Llama 3.1 405B 这样的模型通常需要多个 H100 GPU,除非你在一个拥有这些资源的组织工作,否则你需要使用外部 API。

为了访问你的免费Nvidia信用,前往Llama 3.1 on Nvidia NIM,并点击获取API密钥。这是我们将在代码或.env文件中使用的。一旦我们有了API,就可以设置与Nvidia服务器的连接,以远程使用模型。

    client = OpenAI(  
        base_url="https://integrate.api.nvidia.com/v1",  
        api_key=os.environ["NVIDIA_API_KEY"]  
    )  
    MODEL = "meta/llama-3.1-405b-instruct"
生成子主题

理想情况下,我们希望数据集能够涵盖尽可能多的不同场景和情况。一种确保这一点的方法是定义 子主题,并要求Llama 3.1为每个子主题提供指令/响应对。我们可以自己选择这些子主题,或者让大语言模型(LLM)来决定。我在以下代码片段中选择了第二种方法。

    n_subtopics = 5  

    TOPIC_GENERATION_PROMPT_TEMPLATE = """\  
    我想创建一个自然语言和Git命令的合成数据集。基于这个背景,给我 {n_subtopics} 个子主题,涵盖在使用Git时需要覆盖的内容。  

    列表中不能有数字,也不能有任何子主题的描述。子主题之间需要用逗号分隔。除了列表之外,不能有任何其他文本。  
    """  

    def generate_subtopics(client, n_subtopics):  
        prompt = TOPIC_GENERATION_PROMPT_TEMPLATE.format(n_subtopics=n_subtopics)  
        response = client.chat.completions.create(  
            model=MODEL,  
            messages=[  
                {"role": "user",  
                 "content": prompt}  
            ],  
            temperature=0.2,  
            top_p=0.7,  
        )  
        return response  

    responses = generate_subtopics(client, n_subtopics=n_subtopics)  
    print(responses.choices[0].message.content)

LLM 建议了五个主题:分支、合并、提交、远程仓库和解决冲突。看来这些主题的选取相当全面。

生成指令

拥有五个与Git操作相关的子主题,我们需要Llama 3.1生成每个子主题的一套指令(或提示)。我要求每个主题生成一百条指令,因此理想情况下,我应该得到500个提示。

需要注意的是,当你要求生成 N 个指令时:模型通常不会恰好返回你想要的数量,即使是像这样的大型模型也是如此。

最终,我得到了5个子主题总共335条指令,这与500条有很大的不同。有一些方法可以确保这种情况不会发生,但为了简单起见,我们不会深入讨论这个问题。

    n_instructions = 100  

    INSTRUCTION_PROMPT_TEMPLATE = """\  
    目标是创建一个由Git命令返回的用户指令的数据集。  
    给定一个Git主题,生成{n_instructions}条可能的简洁指令,这些指令可以由AI助手针对该主题给出。  
    其中一些指令应由一个对Git术语和知识了解有限的人编写,例如初学者程序员。你的回答应该以列表格式呈现。  

    主题是:{sub_topic}  
    列表中不应包含数字。问题/指令之间应由换行符分隔,列表中不应包含其他文本。  
    """  
    subtopic_list = responses.choices[0].message.content.split(",")  
    def generate_instructions(client, sub_topic, n_instructions):  
        print(f"正在生成 {sub_topic} 的指令。")  
        prompt = INSTRUCTION_PROMPT_TEMPLATE.format(sub_topic=sub_topic, n_instructions=n_instructions)  
        response = client.chat.completions.create(  
            model=MODEL,  
            messages=[  
                {"role": "user",  
                 "content": prompt}  
            ],  
            temperature=0.2,  
            top_p=0.7,  
        )  
        return response.choices[0].message.content  

    def instructions_generator(client, subtopic_list, n_instructions):  
        instruction_list = [generate_instructions(client, subtopic, n_instructions) for subtopic in subtopic_list]  
        return instruction_list  

    instruction_list = instructions_generator(client, subtopic_list, n_instructions)  

    instruction_list_formatted = []  
    for instruction_set in instruction_list:  
        instruction_list_formatted.extend([instruction.strip() for instruction in instruction_set.split("\n") if instruction])  
    print(instruction_list_formatted)

这里有一些生成的指令示例:

    '创建一个我可以合并回主分支的分支',  
    '我想基于旧版本的代码创建一个分支',  
    '你能给我展示一下今年对仓库所做的所有提交的日志吗?',
响应生成

对于每个提供的指令,我们还将要求一个响应。如以下代码片段所示,我特别要求我的响应要 紧扣主题、信息丰富且简洁。最终,我将拥有一系列 instructionresponse 对。

    RESPONSE_PROMPT_TEMPLATE = """\  
    根据与Git相关的问题/指令,生成可能的回答。  
    保持回答与主题相关、信息丰富、简洁。  

    用户提示是:{instruction}  
    """  
    def generate_responses(client, instruction):  
        prompt = RESPONSE_PROMPT_TEMPLATE.format(instruction=instruction)  
        response = client.chat.completions.create(  
            model=MODEL,  
            messages=[  
                {"role": "user",  
                 "content": prompt}  
            ],  
            temperature=0.2,  
            top_p=0.7,  
            max_tokens=1024,  
        )  
        return response.choices[0].message.content  

    def response_generator(client, instruction_list):  
        response_list = [generate_responses(client, instruction) for instruction in instruction_list]  
        return response_list  

    instruction_response_list = response_generator(client, instruction_list_formatted)  
    instruction_response_pair_list = []  
    for instruction, response in zip(instruction_list_formatted, instruction_response_list):  
        instruction_response_pair_list.append(  
            {  
                "instruction": instruction,  
                "responses": response,  
            }  
        )
    {"instruction": "你能为我创建一个名为\"new-feature\"的分支吗?",   
    "responses": "要创建一个名为\"new-feature\"的新分支,你可以使用以下 Git 命令:\n\n`git branch new-feature`\n\n这将创建一个具有指定名称的新分支。如果你想立即切换到新分支,你可以使用:\n\n`git checkout -b new-feature`\n\n这将创建分支并一步切换到该分支。"}
使用Nemotron 4过滤响应

即使我们有了指令/响应对,但并非所有的响应都是高质量的。它们可能冗长、复杂或不准确。这时,Nvidia 的 Nemotron 4 340B Reward 模型就派上了用场。它正是为我们的用例设计的,根据 Nvidia 的说法,它 “可以作为合成数据生成管道的一部分,用于创建帮助研究人员和开发人员构建自己的大语言模型(LLMs)的训练数据。”

Nemotron 4 的示例用法。(由作者提供)

我们将每个指令/响应对提供给Nemotron 4,并收到五个评分,范围从0到4。这五个评分分别是有用性、正确性、连贯性、复杂性和冗长性。为了使用该模型,我将首先定义一个简单的函数,将指令和响应输入模型,并以字典的形式接收这五个评分。

    def get_scores_from_response(score_response_template):  
        logprobs = score_response_template.choices[0].logprobs.content  
        score_dict = {}  
        for score in logprobs:  
            score_dict[score.token] = score.logprob  
        return score_dict  

    def get_response_and_scores(client, model, question, response_content):  
        messages = [  
            {  
                "role": "user",  
                "content": question  
            },  
            {  
                "role": "assistant",  
                "content": response_content  
            }  
        ]  
        response = client.chat.completions.create(  
            model=model,  
            messages=messages,  
        )  
        scores = get_scores_from_response(response)  
        return scores

在我们为数据集中的每一行都打分之后,我们可以根据提供的五个标准来过滤数据集。我将根据 有用性冗长度 过滤掉不好的回复,因为我希望我的回复简明且具有信息量。

    helpfulness_THRESHOLD = 3  
    verbosity_THRESHOLD = 2.5  
    synthetic_data = [data for i, data in enumerate(synthetic_data)  
                      if not (score_list[i]["helpfulness"] < helpfulness_THRESHOLD or  
                              score_list[i]["verbosity"] > verbosity_THRESHOLD)]
将数据集推送到HuggingFace

最后,在你完成了数据集之后,将它推送到HuggingFace以供以后使用或与其它开发者共享是一个好习惯。为此,首先登录HuggingFace并提供一个 token ,按照登录页面提供的链接进行操作。

    from huggingface_hub import login  
    login()

然后你可以加载保存的数据集,并将其上传到你的 HuggingFace 页面。

    with open(f'synthetic_data_filtered.jsonl', 'r') as f:  
        data = [json.loads(line) for line in f]  
    dataset = Dataset.from_list(data)  
    dataset_dict = DatasetDict({"train": dataset})  
    dataset_dict.push_to_hub("hesamsheikh/git-prompt")

恭喜&#127942;!到目前为止,你已经能够使用Llama 3.1创建指令和响应的数据集,并使用Nemotron 4来优化数据集并过滤掉不良响应。最后,我们看到了将数据集推送到HuggingFace是多么简单。如果你喜欢这个主题,我建议你观看从一个主题创建合成数据集以进行指令微调,这也是本文的一个很好的灵感来源。

这里也有我使用的完整代码的仓库。如果你查看了代码,别忘了给仓库点赞 ⭐。

使用Llama 3.1 405B和Nemotron 4创建合成数据集

感谢 阅读本文!如果您认为有任何需要修改的地方,请分享您的意见和建议。

让我们连接起来!

订阅免费通知新文章!你也可以在我的 LinkedIn Twitter 上找到我。

每当 Hesam Sheikh 发布文章时都收到一封邮件。通过注册,如果你还没有 Medium 账户,将会创建一个。获取更多内容,请访问 medium.com
进一步阅读

如果你已经阅读到这里,你可能会发现这些文章也很有趣:

我们仍然不了解的机器学习机器学习中的未知领域 — 从批量归一化到随机梯度下降隐藏的内容towardsdatascience.com
全面指南:协作AI代理在实践中的应用——定义及构建一个团队来完善你的简历和求职信towardsdatascience.com
这篇关于使用 Llama 3.1 创建合成数据集以微调您的LLM的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!