跳到正文
北京时间
原文
LangChain:Blog·· 2023-08-23精选AI 评分60

LangChain 实战教程:用 LangSmith 微调并评测 LLaMA2-7b-chat 与 gpt-3.5-turbo

Using LangSmith to Support Fine-tuning

AI 导读

LangChain 发布微调与评测指南,用 LangSmith 做数据集管理和评测,在 CoLab 上以 qLoRA 微调 LLaMA2-7b-chat,并用 50 条样本微调 OpenAI 的 gpt-3.5-turbo,测试任务是知识图谱三元组抽取。

推荐理由

原文给出了从数据集管理到评测的完整微调流程和实测分数,读者可以据此判断小模型微调与 GPT-4 few-shot 的取舍。

正文 · AI 翻译

摘要

我们创建了一份指南,用于使用 LangSmith 进行数据集管理和评估来微调和评估 LLM。我们既在 CoLab 和 HuggingFace 上使用开源 LLM 进行模型训练,也使用了 OpenAI 新的微调服务。作为测试案例,我们使用从 LangSmith 导出的训练数据,为一项抽取任务(知识图谱三元组抽取)微调了 LLaMA2-7b-chat 和 gpt-3.5-turbo,并使用 LangSmith 评估了结果。CoLab 指南在这里。

背景

过去几周,人们对微调的兴趣迅速增长。这很大程度上可归因于两个原因。

首先,开源 LLM 生态发展显著,从远远落后于最先进水平(SOTA)的开源 LLM,发展到约 1 年内就能在消费级笔记本电脑上运行的接近 SOTA 的 LLM(例如 Llama-2)!这一进步的驱动因素包括越来越大的训练语料库(下图 x 轴)以及针对指令遵循和更好对齐人类响应的微调(y 轴)。性能出色的开源基础模型带来了诸多好处,例如节省成本(例如对于token 密集型任务)、隐私,以及——通过微调——有机会用小得多的开源模型在高度特定的任务上超越 SOTA LLM。

其次,领先的 LLM 提供商 OpenAI 已发布对 gpt-3.5-turbo(以及其他模型)的微调支持。此前,微调仅适用于较旧的模型。这些模型的能力远不及较新的模型,这意味着即使经过微调,它们通常也无法与 GPT-3.5 和少样本示例相竞争。既然较新的模型现在可以微调,许多人预计这种情况将会改变。

一些人已经认为,组织可能会选择许多源自开源基础模型的专家型微调 LLM,而不是单个庞大的通用模型。考虑到这一点以及像 HuggingFace 这样支持微调的库,你可能想知道何时以及如何微调。本指南提供了概述,并展示了 LangSmith 如何支持这一过程。

何时微调

LLM 至少可以通过两种方式学习新知识:权重更新(例如预训练或微调)或提示(例如检索增强生成,RAG)。模型权重就像长期记忆,而提示就像短期记忆。这份 OpenAI cookbook 有一个有用的类比:当你微调模型时,就像为一周后的考试复习。当你把知识插入提示中(例如通过检索)时,就像带着开卷笔记参加考试。

考虑到这一点,不 建议使用微调来教 LLM 新知识或事实回忆;OpenAI 的 John Schulman 的演讲指出,微调可能会增加幻觉。微调更适合教授专门任务,但应该考虑相对于提示或 RAG。如此处所述,对于有充足示例的明确定义的任务和/或缺乏少样本提示的上下文学习能力的 LLM,微调可能会有所帮助。这篇 Anyscale 博客很好地总结了这些观点:微调是为了形式,而不是事实。

如何微调

已经发布了许多有用的 LLaMA 微调方案,用于诸如在 HuggingFace 中使用 OpenAssistant 语料库的子集进行聊天等任务。值得注意的是,这些方案可以在单个 CoLab GPU 上运行,使得工作流程易于上手。然而,微调中剩余的两个最大痛点是数据集收集/清洗和评估。下面我们展示如何使用 LangSmith 来帮助解决这两个问题(见下方绿色部分)。

任务

像分类/打标签或抽取这样的任务非常适合微调;Anyscale 报告称,通过在抽取、text-to-SQL 和 QA 上微调 LLaMA 7B 和 13B 大语言模型,取得了有前景的结果(超过 GPT4)。作为测试用例,我们选择从文本中抽取形式为(主体,关系,客体)的知识三元组:主体和客体是实体,关系是它们之间的属性或连接。三元组随后可用于构建知识图谱,即存储实体及其关系信息的数据库。我们构建了一个公开的 Streamlit 应用,用于从用户输入文本中抽取三元组,以探索大语言模型(GPT3.5 或 4)通过函数调用抽取三元组的能力。同时,我们使用公开数据集为这一任务微调了 LLaMA2-7b-chat 和 GPT-3.5。

数据集

数据集收集和清洗在训练大语言模型时往往是一项具有挑战性的任务。当在 LangSmith 中建立项目时,生成内容会自动记录,从而易于获取大量数据。LangSmith 提供了可查询接口,因此你可以使用用户反馈过滤器、标签和其他指标来筛选低质量案例,在应用中修正输出,并保存到数据集中,用于改进模型的结果(见下文)。

例如,我们根据公开的 BenchIE 和 CarbIE 数据集中的知识图谱三元组创建了 LangSmith 训练和测试数据集;我们将它们转换为统一的 JSON 格式,每个三元组表示为 {s: subject, object: object, relation: relationship},并将合并后的数据随机划分为约 1500 条带标签句子的训练集和 100 条句子的测试集。CoLab 展示了如何轻松加载 LangSmith 数据集。加载后,我们使用下面的系统提示和 LLaMA 指令 token(如此处所做)创建用于微调的指令:

"you are a model tasked with extracting knowledge graph triples from given text. "
"The triples consist of:\n"
"- \"s\": the subject, which is the main entity the statement is about.\n"
"- \"object\": the object, which is the entity or concept that the subject is related to.\n"
"- \"relation\": the relationship between the subject and the object. "
"Given an input sentence, output the triples that represent the knowledge contained in the sentence."

量化

如此处的优秀指南所示,我们微调一个 7B 参数的 LLaMA 聊天模型。我们希望在单个 GPU 上完成这一操作(HuggingFace 指南见此处),这带来一个挑战:如果每个参数是 32 位,一个 7B 参数的 LLaMA2 模型将占用 28GB,超过 T4(16GB)的显存。为解决这一问题,我们对模型参数进行量化,这意味着将值分箱(例如,在 4 位量化的情况下分为 16 个值),从而减少存储模型所需的内存(7B * 4 位/参数 = 3.5GB),约8倍。

LoRA 和 qLoRA

模型加载到内存后,我们仍需要在剩余 GPU 资源的约束下找到微调的方法。为此,参数高效微调(PEFT)是一种常见做法:LoRA 冻结预训练模型权重,并在模型架构的每一层注入可训练的秩分解矩阵(参见此处),从而减少微调时需要训练的参数数量(例如,约占模型总量的 1%)。qLoRA 在此基础上进一步冻结量化权重。微调期间,冻结的权重在前向和反向传播时会被反量化,但只有(少量)LoRA 适配器会保存在内存中,从而减小微调后模型的占用。

训练

我们从预训练的 LLaMA-7b 聊天模型 llama-2-7b-chat-hf 开始,在 A100 上基于 CoLab 中的约 1500 条指令进行微调。训练配置方面,我们使用了此处的 LLaMA 微调参数:BitsAndBytes 以 4 位精度加载基础模型,但前向和反向传播使用 fp16。我们使用监督微调(SFT)在我们的指令上进行微调,对于这么小的数据量,在 A100 上速度相当快(< 15 分钟)。

OpenAI 微调

为了微调 OpenAI 的 GPT-3.5-turbo 聊天模型,我们从训练数据集中选取了 50 个示例,并将它们转换为符合预期格式的聊天消息列表:

{
   "messages": [
       {
           "role": "user",
           "content": "Extract triplets from the following sentence:\n\n{sentence}"},
       {
           "role": "assistant",
           "content": "{triples}"
       },
       ...
   ]
}

由于基础模型能力非常广泛,我们不需要太多数据就能实现期望的行为。训练数据旨在引导模型始终生成正确的格式和风格,而不是教给它大量信息。 正如我们将在下面的评估部分看到的那样,50 个训练示例足以让模型每次都按正确格式预测三元组。

我们通过 openai SDK 上传了微调数据,并直接在 LangChain 的 ChatOpenAI 类中使用生成的模型。微调后的模型可以直接使用:

from langchain.chat_models import ChatOpenAI

llm = ChatOpenAI(model="ft:gpt-3.5-turbo-0613:{openaiOrg}::{modelId}")

整个过程只花了几分钟,除了不再需要在提示模板中添加少样本示例外,我们的链无需任何代码更改。随后我们将该模型与其他模型进行基准测试,以量化其性能。你可以在我们的 CoLab notebook 中看到整个过程的示例。

评估

我们使用 LangSmith 评估每个模型,应用 LLM(GPT-4)评估器对每个预测进行评分,该评估器被指示识别标签与预测三元组之间的事实差异。当模型预测出标签中不存在的三元组,或预测未能包含某个三元组时,结果会被扣分;但如果对象或关系的具体措辞以无意义的方式不同,则会从宽处理。评估器按 0-100 的等级对结果评分。我们在 CoLab 中运行评估,以便轻松配置自定义评估器和要测试的链。

下表显示了 llama 基础聊天模型和微调变体的评估结果。作为对比,我们还对使用 OpenAI 聊天模型的 3 条链进行了基准测试:使用少样本提示的 gpt-3.5-turbo、在 50 个训练数据点上微调的 gpt-3.5-turbo 模型,以及少样本 gpt-4 链:

  • GPT-4 的少样本提示表现最佳
  • 微调后的 GPT-3.5 位居第二
  • 微调后的 LLaMA-7b-chat 超过了 GPT-3.5 的性能
  • 并且微调后的 LLaMA-7b-chat 比基线 LLaMA-7b-chat 好约 29%

微调后的 llama-2

基础 llama-2 聊天模型

few-shot gpt-3.5-turbo

finetuned gpt-3.5-turbo

few-shot gpt-4

Score

49%

38%

40%

56%

59%

Analysis

我们使用 LangSmith 来刻画常见的失败模式,并更好地理解微调模型在哪些方面比基础模型表现更好。通过筛选低分预测,我们可以看到基线 LLaMA-7b-chat 滑稽地产生幻觉的案例:在下面的案例中,LLM 认为主体是 Homer Simpson,并随意地给出超出所需格式范围的回答(此处)。微调后的 LLaMA-7b-chat(此处)则更接近参考(真实标注)。

基础模型因从其预训练知识中推断过多信息而产生幻觉的示例。

即使提供了 few-shot 示例,基线 LLaMA-7b-chat 仍倾向于以非正式的闲聊风格回答(此处)。

基础 llama 模型常常在未被要求时也加入叙述。

相比之下,微调后的模型倾向于生成(此处)符合所需答案格式的文本,并避免添加不需要的对话。

微调后的模型仍有未能生成所需内容的情况。在下面的示例(链接)中,模型重复了指令,而不是生成提取结果。这可以通过多种方法修复,例如不同的解码参数(或使用 logit 偏置)、更多指令、更大的基础模型(例如 13b),或改进指令(提示工程)。

微调后的模型偶尔会变得重复。

我们可以对比下面(链接)上述 few-shot 提示的 GPT-4,它能够在未在训练数据集上微调的情况下提取出合理的三元组。

结论

我们可以提炼出几个核心经验:

  • LangSmith 可以帮助解决微调工作流程中的痛点,例如数据收集、评估和结果检查。我们展示了 LangSmith 如何轻松收集和加载数据集,以及运行评估和检查特定生成结果。
  • 在转向更具挑战性和成本更高的微调之前,应仔细 考虑 RAG 或 few-shot 提示。Few-shot 提示的 GPT-4 实际上比我们所有微调变体表现更好。
  • 在定义明确的任务上微调小型开源模型可以胜过更大的通用模型。正如 Anyscale 和其他机构此前所报告的,我们看到微调后的 LLaMA2-chat-7B 模型超过了更大的通用 LLM(GPT-3.5-turbo)的性能。
  • 有许多杠杆可以提升微调性能,其中最值得注意的是仔细的任务定义和数据集整理。一些工作,例如 LIMA,报告了通过在仅 1000 条为高质量而精选的指令上微调 LLaMA 而取得令人印象深刻的表现。进一步的数据收集/清洗、使用更大的基础模型(例如 LLaMA 13B),以及通过 GPU 服务扩展微调(Lambda Labs、Modal、Vast.ai、Mosaic、Anyscale 等)都是可预见能改善这些结果的方法。

总体而言,这些结果(以及链接的 CoLab)提供了一个使用 LangSmith 这一有助于完整工作流程的工具来微调开源 LLM 的快速配方。

来源:LangChain:Blog · langchain.com