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

部署运行你感兴趣的模型镜像

原文:towardsdatascience.com/create-a-synthetic-dataset-using-llama-3-1-405b-for-instruction-fine-tuning-9afc22fb6eef?source=collection_archive---------2-----------------------#2024-08-07

使用庞大的 Llama 3.1 405B 和 Nvidia Nemotron 4 奖励模型来创建用于指令微调的合成数据集。

https://medium.com/@itshesamsheikh?source=post_page---byline--9afc22fb6eef--------------------------------https://towardsdatascience.com/?source=post_page---byline--9afc22fb6eef-------------------------------- Hesam Sheikh

·发布于 Towards Data Science ·9 分钟阅读·2024 年 8 月 7 日

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/d59b24212f7745714c66c7591192d4a8.png

由 AI 使用 Leonardo.AI 创建

数据是 AI 的核心,尽管它是宝贵的资产,但我们知道开发高质量数据集是多么具有挑战性和成本高昂。一个精心策划和过滤的数据集可以弥补模型复杂度的不足。对于大型语言模型来说也是如此,较小的模型通过利用良好的数据往往能优于更大的 LLM。

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

这将是快速、免费的,并且让你掌握更多的控制权。

我将保持这篇文章简洁且充满干货,因此请确保阅读到最后,并熟悉这一重要技能。

🦙 为什么选择 Llama 3.1

Meta 在发布最新一代 LLM 家族后,牢牢占据了市场的份额,Llama 3.1。这个新家族包括了升级版的 8B 和 70B 模型,具有更强的推理能力,并推出了庞大的 405B 模型。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/cbadf588e2561f45221657f93c764fa2.png

Llama 3.1 405 在成功接近最佳闭源模型的基准方面取得了显著成就。(图表由 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。

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/07a1f36079f8e08fdc8b2bb76c584e37.png

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

设置 API 密钥

我们将使用Nvidia NIM API来利用这些大型 LLM,而无需在本地运行它们。像 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 = """\
I want to create a synthetic dataset of natural language and Git commands. Based on this context, give me {n_subtopics} subtopics
to cover what needs to be covered when working with Git. 

The list must be without numbers, and without any description of the subtopics. The subtopics should be separated by a comma. There must be no other text than the list.
"""

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条指令时:即使是这样一个大型模型,也很少会返回正好等于你想要的数量。

最终,我为五个子主题得到了总共 335 条指令,这与 500 条有很大差距。虽然有方法可以确保这种情况不发生,但为了简化起见,我们就不再深入讨论了。

n_instructions = 100

INSTRUCTION_PROMPT_TEMPLATE = """\
The objective is to create a dataset of user instructions in natural language that should be returned by Git commands.
Given a topic in Git, generate {n_instructions} possible concise instructions that could be given to an AI assitant about that topic.
Write some of these instructions as if given by someone with limited knowledge of Git terminologies and knowledge, 
like a beginner programmer. Your response should be in a list format.

The topic is: {sub_topic}
The list must be without numbers. The questions/instructions should be separated by a newline character. There must be no other text than the list.
"""
subtopic_list = responses.choices[0].message.content.split(",")
def generate_instructions(client, sub_topic, n_instructions):
    print(f"Generating Instructions for {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)

下面是一些生成的指令示例:

'Make a branch that I can merge back into the main branch',
'I want to make a branch that is based on an older version of the code',
'Can you show me a log of all commits that have been made to the repository this year?',

响应生成

对于每一条提供的指令,我们还将要求给出响应。正如下面的代码片段所示,我特别要求我的响应是切题、有信息量且简洁的。到最后,我将得到一对指令响应的列表。

RESPONSE_PROMPT_TEMPLATE = """\
Given an question/instruction related to Git, generate a response that could be given. 
Keep the response on-topic, informative, concise.

The user prompt is: {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": "Can you make a branch for me and name it \"new-feature\"", 
"responses": "To create a new branch named \"new-feature\", you can use the following Git command:\n\n`git branch new-feature`\n\nThis will create a new branch with the specified name. If you want to switch to the new branch immediately, you can use:\n\n`git checkout -b new-feature`\n\nThis will create the branch and switch to it in one step."}

使用 Nemotron 4 筛选响应

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

https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/68716e2a3af1320dfe4da92f01e82d06.png

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 并提供一个令牌,具体步骤可参考登录页面提供的链接。

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")

恭喜 🏆!到目前为止,你已经能够使用 Llama 3.1 创建一个指令和回答的数据集,并且使用 Nemotron 4 对数据集进行优化并过滤掉不好的回答。最后,我们看到将数据集推送到 HuggingFace 是如此轻松。从一个主题创建合成数据集用于指令微调 也是本文的一个重要灵感来源,如果你喜欢这个主题,我建议你观看它。

这里还有代码仓库,你可以在其中找到我使用的完整代码。如果你查看了它,别忘了给仓库加星⭐。

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

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

让我们保持联系!

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

[## 每当 Hesam Sheikh 发布新文章时,您将收到电子邮件通知。

每当 Hesam Sheikh 发布新文章时,你将收到电子邮件通知。通过注册,如果你还没有 Medium 账户,你将创建一个账户……

medium.com](https://medium.com/@itshesamsheikh/subscribe?source=post_page-----9afc22fb6eef--------------------------------)

深入阅读

如果你已经阅读到这里,你可能会对以下文章感兴趣:

## 我们仍然不理解的机器学习

机器学习中的未知问题,研究人员一直在努力理解——从批量归一化到 SGD 隐藏的内容

towardsdatascience.com ## 实践中的协作 AI 代理全面指南

定义,并建立一个能够优化你简历和求职信的代理团队

towardsdatascience.com

您可能感兴趣的与本文相关的镜像

Llama Factory

Llama Factory

模型微调
LLama-Factory

LLaMA Factory 是一个简单易用且高效的大型语言模型(Large Language Model)训练与微调平台。通过 LLaMA Factory,可以在无需编写任何代码的前提下,在本地完成上百种预训练模型的微调

基于径向基函数神经网络RBFNN的自适应滑模控制学习(Matlab代码实现)内容概要:本文介绍了基于径向基函数神经网络(RBFNN)的自适应滑模控制方法,并提供了相应的Matlab代码实现。该方法结合了RBF神经网络的非线性逼近能力和滑模控制的强鲁棒性,用于解决复杂系统的控制问题,尤其适用于存在不确定性和外部干扰的动态系统。文中详细阐述了控制算法的设计思路、RBFNN的结构与权重更新机制、滑模面的构建以及自适应律的推导过程,并通过Matlab仿真验证了所提方法的有效性和稳定性。此外,文档还列举了大量相关的科研方向和技术应用,涵盖智能优化算法、机器学习、电力系统、路径规划等多个领域,展示了该技术的广泛应用前景。; 适合人群:具备一定自动控制理论基础和Matlab编程能力的研究生、科研人员及工程技术人员,特别是从事智能控制、非线性系统控制及相关领域的研究人员; 使用场景及目标:①学习和掌握RBF神经网络与滑模控制相结合的自适应控制策略设计方法;②应用于电机控制、机器人轨迹跟踪、电力电子系统等存在模型不确定性或外界扰动的实际控制系统中,提升控制精度与鲁棒性; 阅读建议:建议读者结合提供的Matlab代码进行仿真实践,深入理解算法实现细节,同时可参考文中提及的相关技术方向拓展研究思路,注重理论分析与仿真验证相结合。
先展示下效果 https://pan.quark.cn/s/a4b39357ea24 本项目是本人参加BAT等其他公司电话、现场面试之后总结出来的针对Java面试的知识点或真题,每个点或题目都是在面试中被问过的。 除开知识点,一定要准备好以下套路: 个人介绍,需要准备一个1分钟的介绍,包括学习经历、工作经历、项目经历、个人优势、一句话总结。 一定要自己背得滚瓜烂熟,张口就来 抽象概念,当面试官问你是如何理解多线程的时候,你要知道从定义、来源、实现、问题、优化、应用方面系统性地回答 项目强化,至少与知识点的比例是五五开,所以必须针对简历中的两个以上的项目,形成包括【架构和实现细节】,【正常流程和异常流程的处理】,【难点+坑+复盘优化】三位一体的组合拳 压力练习,面试的时候难免紧张,可能会严重影响发挥,通过平时多找机会参与交流分享,或找人做压力面试来改善 表达练习,表达能力非常影响在面试中的表现,能否简练地将答案告诉面试官,可以通过给自己讲解的方式刻意练习 重点针对,面试官会针对简历提问,所以请针对简历上写的所有技术点进行重点准备 Java基础 JVM原理 集合 多线程 IO 问题排查 Web框架、数据库 Spring MySQL Redis 通用基础 操作系统 网络通信协议 排序算法 常用设计模式 从URL到看到网页的过程 分布式 CAP理论 锁 事务 消息队列 协调器 ID生成方式 一致性hash 限流 微服务 微服务介绍 服务发现 API网关 服务容错保护 服务配置中心 算法 数组-快速排序-第k大个数 数组-对撞指针-最大蓄水 数组-滑动窗口-最小连续子数组 数组-归并排序-合并有序数组 数组-顺时针打印矩形 数组-24点游戏 链表-链表反转-链表相加 链表-...
### 对 LLaMA 3.1 模型进行微调 为了在 AutoDL 环境中对 LLaMA 3.1 模型进行微调,需遵循一系列特定的操作流程。这不仅涉及模型加载,还包括数据准备、训练参数设置以及实际的微调过程。 #### 加载预训练模型 首先,在 Python 脚本或 Jupyter Notebook 中导入必要的库并加载预训练的 LLaMA 3.1 模型: ```python import torch from transformers import AutoModelForCausalLM, AutoTokenizer tokenizer = AutoTokenizer.from_pretrained("/root/autodl-tmp/LLM-Research/Meta-Llama-3___1-8B-Instruct") model = AutoModelForCausalLM.from_pretrained( "/root/autodl-tmp/LLM-Research/Meta-Llama-3___1-8B-Instruct", device_map="auto", torch_dtype=torch.bfloat16 ) ``` 这段代码展示了如何通过指定路径来加载已有的 LLaMA 3.1 模型及其对应的分词器[^1]。 #### 准备用于微调数据集 对于微调而言,准备好适当格式化的数据至关重要。通常情况下,这些数据应该已经被转换成适合输入给定模型的形式。假设有一个 CSV 文件作为数据源,则可以利用 `pandas` 库读取该文件,并进一步处理为 PyTorch 数据集对象。 ```python import pandas as pd from datasets import Dataset df = pd.read_csv(&#39;path_to_your_data.csv&#39;) dataset = Dataset.from_pandas(df) def preprocess_function(examples): return tokenizer(examples[&#39;text&#39;], truncation=True, padding=&#39;max_length&#39;) tokenized_datasets = dataset.map(preprocess_function, batched=True) ``` 此部分说明了从原始文本数据到可用于训练的 token ID 的转换方法[^2]。 #### 设置优化器与学习率调度程序 选择合适的优化算法和调整策略有助于提高最终性能。这里采用 AdamW 作为默认推荐的选择之一,并配合线性衰减的学习率计划来进行更有效的梯度下降更新操作。 ```python optimizer = torch.optim.AdamW(model.parameters(), lr=5e-5) num_epochs = 3 total_steps = num_epochs * len(tokenized_datasets["train"]) scheduler = get_linear_schedule_with_warmup(optimizer, num_warmup_steps=0, num_training_steps=total_steps) ``` 上述片段解释了创建优化器实例的方式及初始化学习率调度机制的过程。 #### 开始微调过程 最后一步就是执行真正的微调工作。在此期间,会遍历整个训练集多次(即 epoch),每次迭代都会计算损失函数值并通过反向传播更新权重参数;与此同时,还需定期保存检查点以便后续恢复或评估目的。 ```python for epoch in range(num_epochs): for step, batch in enumerate(tokenized_datasets["train"]): outputs = model(**batch) loss = outputs.loss loss.backward() optimizer.step() scheduler.step() optimizer.zero_grad() if (step + 1) % 100 == 0: print(f"Epoch [{epoch+1}/{num_epochs}], Step [{step+1}], Loss: {loss.item():.4f}") # Save checkpoint after each epoch model.save_pretrained(f"./llama_finetuned_epoch_{epoch+1}") ``` 以上代码实现了完整的微调循环逻辑,包括前向传递、误差累积、参数修正等核心环节。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值