这一章是关于进步LLMs在特定场景中可靠性和功能的技能和最佳实践,比方杂乱的推理和问题处理使命。调整模型以习惯特定使命或保证模型输出契合预期的进程被称为条件化。在本章中,咱们将评论微谐和提示作为条件化办法。

微调触及对预练习的基础模型进行在与所需运用相关的特定使命或数据集上的练习。这一进程使得模型能够习惯,变得愈加精确而且在预期用例中具有上下文相关性。

另一方面,在揣度时经过供给额定的输入或上下文,LLMs能够生成契合特定使命或风格的文本。提示工程在开释LLM推理才能方面十分重要,提示技能构成了研讨人员和从业者在与LLMs一起作业时的名贵东西包。咱们将评论并施行高档提示工程战略,如少样本学习、思想树和自共同性。

在整个章节中,咱们将运用微谐和提示来处理LLMs。你能够在本书的GitHub存储库中找到相应的代码,网址为github.com/benman1/gen…

本章的首要部分包含:

  1. LLMs的条件化
  2. 微调
  3. 提示工程

让咱们从评论条件化开端,探讨其重要性以及怎么完结它。

条件化LLMs

在多样化的数据上对LLM进行预练习,以学习言语模式,得到一个具有广泛了解各种主题的基础模型。虽然像GPT-4这样的基础模型能够在各种主题上生成令人形象深化的文本,但经过对其进行条件化,能够提升其在使命相关性、特定性和连贯性方面的才能,并引导模型的行为与道德和适当性的考虑保持共同。在本章中,咱们将专心于微谐和提示技能这两种条件化办法。

条件化指的是一系列用于引导模型生成输出的办法。这不只包含提示的制造,还包含更体系性的技能,比方在特定数据集上进行微调,以使模型的呼应继续习惯特定的主题或风格。

条件化技能使LLMs能够了解并履行杂乱的指令,供给与咱们希望亲近匹配的内容。这涵盖了从即兴互动到体系练习的各种情境,这些练习能够引导模型的行为以在专业范畴(如法律咨询或技能文档)中完结可靠的功能。此外,条件化的一部分包含施行防范措施,以防止生成歹意或有害内容,例如引入过滤器或练习模型防止发生某些类型的问题输出,然后更好地使其契合希望的道德规范。

对齐(Alignment)指的是练习和修改LLMs的进程和方针,以使它们的一般行为、决议计划进程和输出契合更广泛的人类价值观、道德准则和安全考虑。

这两个术语并不是近义词;虽然条件化能够包含微调,侧重于经过不同层次互动的各种技能影响模型,但对齐重视的是将模型的行为底子和全面地校准到人类道德和安全规范。

条件化能够在模型生命周期的不同阶段运用。一种战略触及在代表预期用例的数据上对模型进行微调,以协助模型专心于该范畴。这种办法取决于这些数据的可用性以及将其整合到练习进程中的才能。另一种办法触及在揣度时动态地对模型进行条件化,其间输入提示经过附加上下文进行定制,以塑造希望的输出。这种办法供给了灵活性,但在实时环境中或许增加模型操作的杂乱性。

在接下来的部分,我将总结关于条件化的要害办法,如微谐和提示工程,评论其根本原理,并审视它们的相对优缺点。

条件化的办法

跟着像GPT-3这样的大型预练习言语模型的出现,人们对调整这些模型以习惯下流使命的技能体现出越来越稠密的兴趣。跟着LLMs的不断开展,它们将在更广泛的运用范畴中变得愈加有用和有用,咱们能够期待在微谐和提示技能方面的未来开展,以更深化地参加触及推理和东西运用的杂乱使命。

现已提出了几种用于条件化的办法。以下是对不同技能进行总结的表格:

运用LangChain的生成式AI——自界说LLMs及其输出

将这些技能结合起来使开发人员能够更好地操控生成式人工智能体系的行为和输出。终究方针是保证在从练习到布置的一切阶段都融入人类价值观,以创立负责任且与希望成果共同的人工智能体系。

在本章中,咱们着重微谐和提示,由于它们以其在LLMs条件化中的有用性和普及性而锋芒毕露。微调触及经过在专门使命上进行额定练习来调整预练习模型的一切参数。这种办法旨在增强模型在特定方针上的功能,而且已知能够发生稳健的成果。但是,微调或许会消耗许多资源,存在功能与核算效率之间的权衡。为了处理这些局限性,咱们探讨了诸如适配器和低秩习惯(LoRA)之类的战略,引入了稀疏性的元素或施行参数的部分冻住以减轻负担。

另一方面,根据提示的技能供给了一种在揣度时动态调整LLMs的办法。经过精心规划输入提示以及随后的优化和评价,这些办法能够引导LLMs的行为朝着希望的方向开展,而无需进行深重的从头练习。提示能够经过精心规划,以引发特定行为或概括特定常识范畴,为模型条件化供给了一种文武双全且资源智能的办法。

此外,咱们深化探讨了在微调进程中强化学习与人类反应(RLHF)的革新性作用,其间人类反应充任模型学习轨道的要害攻略。RLHF已展现出在改善GPT-3等言语模型的才能方面具有潜力,使微调成为更具影响力的技能。经过整合RLHF,咱们利用人类评价者对模型行为的奇妙了解,进一步完善模型输出,保证其不只相关而精确,而且与用户意图和希望共同。

一切这些不同的条件化技能有助于开发既高功能又契合各种运用希望的LLMs。让咱们首要评论一下InstructGPT为何具有如此革新性影响,而该模型是经过RLHF进行练习的。

强化学习与人类反应

在2022年3月的论文中,来自OpenAI的欧阳等人展现了运用RLHF(强化学习与人类反应)结合近端战略优化(PPO)来使LLMs(例如GPT-3)与人类偏好共同。

RLHF是一种在线办法,运用人类偏好对LM进行微调。它包含三个首要进程:

  1. 监督预练习:首要经过规范的监督学习在人类演示上对LM进行练习。
  2. 奖赏模型练习:经过对LM输出的人类评分进行奖赏模型练习,以估计奖赏。
  3. 强化学习微调:经过强化学习对LM进行微调,以最大化来自奖赏模型的预期奖赏,运用像PPO这样的算法。

首要改变RLHF答应将奇妙的人类判别归入言语模型的练习中,经过学得的奖赏模型。因而,人类反应能够引导和进步言语模型的才能,逾越规范的监督微调。这个新模型能够用于依照自然言语给出的指令,并以比GPT-3更精确和相关的办法回答问题。虽然参数数量少了100倍,InstructGPT在用户偏好、真实性和削减伤害方面均优于GPT-3。

从2022年3月开端,OpenAI开端发布GPT-3.5系列模型,这是GPT-3的晋级版本,其间包含运用RLHF进行微调。

InstructGPT经过引入强化学习与人类反应办法打破了传统微调办法的边界,为改善言语模型打开了新的途径。虽然RL练习或许不稳定且核算成本昂扬,但其成功激发了进一步研讨,以改善RLHF技能,削减对齐的数据需求,并为各种运用开发更强壮和可拜访的模型。

低秩习惯

跟着LLMs变得越来越巨大,用一般顾客硬件对它们进行练习变得困难,而且为每个特定使命布置它们会变得贵重。有一些办法能够下降核算、内存和存储成本,一起在低数据和超范畴场景中进步功能。

参数高效微调(PEFT)办法使每个使命能够运用小的查看点,然后使模型更具可移植性。这一小组经过练习的权重能够增加到LLM的顶部,答应同一模型用于多个使命而无需替换整个模型。

低秩习惯(LoRA)是PEFT的一种类型,其间预练习模型的权重被冻住。它在Transformer架构的每一层引入可练习的秩分化矩阵,以削减可练习参数的数量。与微调比较,LoRA在拥有更少可练习参数和更高练习吞吐量的情况下完结了适当的模型质量。

QLORA办法是LoRA的一种扩展,经过将梯度反向传播到冻住的4位量化模型中,使大型模型能够进行高效微调,然后构成可学习的低秩适配器。这使得你能够在单个GPU上对一个65B参数的模型进行微调。QLORA模型在Vicuna上完结了ChatGPT功能的99%,利用了新的数据类型和优化器等立异。QLORA将微调65B参数模型的内存要求从超过780 GB下降到小于48 GB,而不影响运转时或猜想功能。

量化是指削减神经网络(如LLMs)中权重和激活的数值精度的技能。量化的首要意图是减小大型模型的内存占用和核算需求。 关于LLMs的量化的一些要害点包含:

  • 它触及运用比规范的单精度浮点数(FP32)更少的比特来表示权重和激活。例如,权重能够量化为8位整数。
  • 这使得您能够将模型巨细缩小最多4倍,并进步在专用硬件上的吞吐量。
  • 量化一般对模型的精确性影响较小,特别是在从头练习时。
  • 常见的量化办法包含标量、向量和乘积量化,它们能够单独或分组地对权重进行量化。
  • 经过估计激活的散布并适当地进行分箱,还能够对激活进行量化。
  • 量化感知练习在练习进程中调整权重,以最小化量化丢失。
  • 像BERT和GPT-3这样的LLMs现已被证明经过微调能够很好地适用于4-8位的量化。

鄙人一部分中,咱们将评论在推理时对LLMs进行条件化的办法,其间包含提示工程。

推理时条件化

一个常用的办法是在推理时进行条件化(输出生成阶段),在这个阶段,特定的输入或条件会动态地被供给,以引导输出生成进程。在某些情境下,LLM的微调或许并不总是可行或有利:

  1. 有限的微调服务:当模型只能经过缺少或具有受限微调才能的API拜访时。
  2. 数据不足:在某些情况下,或许缺少用于微调的数据,无论是用于特定下流使命仍是相关运用范畴。
  3. 动态数据:在运用中存在经常改变的数据,例如与新闻相关的渠道,经常进行微调变得具有挑战性,或许导致潜在的缺点。
  4. 上下文灵敏运用:关于动态和特定上下文的运用,例如个性化聊天机器人,无法根据个体用户数据进行微调。

关于推理时的条件化,一般咱们在文本生成进程的开端供给一个文本提示或指示。这个提示能够是几句话,乃至是一个单词,充任所需输出的清晰指示。

一些推理时条件化的常见技能包含:

  • 提示调整:为预期行为供给自然言语辅导。对提示规划灵敏。
  • 前缀调整:在LLM层之前增加可练习的向量。
  • 约束符号:强制包含/排除某些词汇。
  • 元数据:供给高档信息,如门户、方针受众等。

提示能够协助生成契合特定主题、风格乃至模仿特定作者写作风格的文本。这些技能在推理时供给上下文信息,例如用于上下文学习或检索增强。

提示调整的一个比如是前缀调整,其间相似“编写一个关于…的适合儿童的故事”的指示被增加到提示之前。例如,在聊天机器人运用中,经过运用用户音讯对模型进行条件化,有助于生成个性化和与当时对话相关的呼应。

其他比如包含在提示之前增加相关文档以协助LLM完结写作使命(例如新闻报道、维基百科页面和公司文件),或在提示LLM之前检索并增加用户特定数据(财政记载、健康数据和电子邮件),以保证生成个性化答案。经过在运转时在LLM输出上施加上下文信息,这些办法能够引导模型,而无需依靠传统的微调进程。

一般,演示是推理使命指令的一部分,其间供给了少数示例来引导希望的行为。强壮的LLM,如GPT-3,能够经过提示技能处理使命,而无需进一步的练习。在这种办法中,要处理的问题被呈现给模型作为文本提示,其间包含相似问题及其处理方案的一些文本示例。模型有必要经过推理供给提示的完结。零提示触及没有已处理的示例,而少数提示包含一小部分相似(问题和处理方案)对的示例。

现已证明,经过提示能够轻松操控像GPT-4这样的大型冻住模型,而且能够在不进行许多微调的情况下引导模型行为。

经过提示能够在低开销的情况下将模型条件化为新常识,但需求仔细规划提示以获得最佳成果。这是咱们将在本章的一部分中评论的内容。在前缀调整中,会在推理时练习并供给连续的使命特定向量供模型运用。相似的想法现已被提出用于适配器办法,例如参数高效迁移学习(PELT)或阶梯侧调整(LST)。

在推理时进行条件化还能够在采样进程中发生,例如根据语法的采样,其间输出能够遭到某些清晰界说的模式的约束,例如编程言语语法。

鄙人一节中,咱们将运用PEFT和量化对一个小型开源LLM(OpenLLaMa)进行微调,用于问答(QA),然后将其布置到Hugging Face。

微调

正如本章第一节评论的那样,对LLMs进行模型微调的方针是优化模型,使其生成比原始基础模型更与使命和上下文相关的输出。 进行微调的原因在于预练习的LMs被规划用于建模通用言语常识,而非特定的下流使命。它们的才能只有在习惯运用程序时才会显现出来。微调答应更新预练习权重以习惯方针数据集和方针。这使得能够从通用模型中转移常识,一起为专门的使命进行定制。 总体而言,微调有三个对这些模型的用户立即明显的优势:

  1. 可操控性:模型遵循指示的才能(指示微调)。
  2. 可靠的输出格局:这关于API调用/函数调用十分重要。
  3. 定制的语气:这使得能够根据使命和受众适当地调整输出风格。
  4. 共同性:模型的输出应与中心价值观相符,例如关于安全性、安全性和隐私考虑的价值观。

对预练习神经网络进行微调的思想起源于2010年代初的核算机视觉研讨。Howard和Ruder(2018)展现了鄙人流使命上微调像ELMo和ULMFit这样的模型的有用性。开创性的BERT模型(Devlin等人,2019)确立了对预练习transformers进行微调作为NLP中的现实规范办法。

在本节中,咱们将微调一个用于问答的模型。这个进程并不特定于LangChain,但咱们将指出一些定制,其间LangChain或许适用。您能够在书籍的GitHub存储库的notebooks目录中找到代码。

作为第一步,咱们将运用库和环境变量设置微调。

微调设置

微调在各种使命上始终能够取得强壮的成果,但需求许多的核算资源。因而,在一个能够拜访强壮的GPU和内存资源的环境中进行微调是个好主意。咱们将在Google Colab上运转此操作,而不是在本地环境中进行,这样咱们能够免费运转LLMs的微调(仅有一些约束)。

Google Colab是一个核算环境,供给不同的办法来加快核算使命,如张量处理单元(TPUs)和图形处理单元(GPUs)。这些都在免费和专业版中都可用。关于本节的使命,免费版现已满足了。您能够在以下网址登录Colab环境:colab.research.google.com/

请保证您将Google Colab机器设置在顶部菜单中为TPU或GPU,以保证您有满足的资源来运转以下代码,而且练习时刻不会太长。咱们将在Google Colab环境中装置一切所需的库 – 我正在增加这些库的版本,以使咱们的微调可重复:

  • peft: PEFT(版本0.5.0)
  • trl: Proximal Policy Optimization(0.6.0)
  • bitsandbytes: k位优化器和矩阵乘法例程,用于量化(0.41.1)
  • accelerate: 运用多GPU、TPU和混合精度练习和运用PyTorch模型的库(0.22.0)
  • transformers: Hugging Face transformers库,支持JAX、PyTorch和TensorFlow后端(4.32.0)
  • datasets: 社区驱动的开源数据集库(2.14.4)
  • sentencepiece: 用于快速分词的Python包装器(0.1.99)
  • wandb: 用于在Weights和Biases上监视练习进展的库(0.15.8)
  • langchain: 用于在练习后将模型加载回LangChain LLM的库(0.0.273)

咱们能够在Colab笔记本中运用以下命令装置这些库:

!pip install -U accelerate bitsandbytes datasets transformers peft trl sentencepiece wandb langchain huggingface_hub

要从Hugging Face下载并练习模型,咱们需求在渠道上进行身份验证。请留意,假如您以后想将模型推送到Hugging Face,您需求生成一个具有在Hugging Face上写入权限的新API令牌:huggingface.co/settings/to…

运用LangChain的生成式AI——自界说LLMs及其输出

咱们能够在笔记本中经过以下办法进行身份验证:

from huggingface_hub import notebook_login
notebook_login()

在提示时,张贴您的Hugging Face拜访令牌。

在开端履行代码之前,需求留意一点:在履行代码时,您需求登录不同的服务,因而在运转笔记本时请保证留意!

Weights and Biases(W&B)是一个MLOps渠道,能够协助开发者监视和记载端到端的ML练习作业流程。如前所述,咱们将运用W&B来了解练习的作用怎么以及模型是否跟着时刻的推移而改善。关于W&B,咱们需求为项目命名;或许,咱们能够运用wandb的init()办法:

import os
os.environ["WANDB_PROJECT"] = "finetuning"

要运用W&B进行身份验证,您需求在www.wandb.ai创立一个免费账户。您能够在授权页面wandb.ai/authorize找到API密钥。再次着重,咱们需求张贴咱们的API令牌。

假如之前的练习依然活泼 – 这或许是由于笔记本的先前履行导致的,假如您第二次运转它 – 让咱们保证发动一个新的练习!这将保证咱们获得新的陈述和W&B上的仪表板:

import wandb
if wandb.run is not None:
    wandb.finish()

接下来,咱们需求挑选一个数据集,用于对模型进行优化。咱们能够在此处运用许多不同的数据集,适用于编码、叙述、东西运用、SQL生成、小学数学问题(GSM8k)或许多其他使命。Hugging Face供给了丰厚的数据集,能够在此URL查看:huggingface.co/datasets。这些数据集涵盖了许多不同乃至是最专业的使命。

咱们也能够定制自己的数据集。例如,咱们能够运用LangChain设置练习数据。有许多可用于过滤的办法,能够协助削减数据会集的冗余。虽然在本章中展现数据收集作为一个有用的进程会很有吸引力,但由于其杂乱性,这超出了本书的范围。

从Web数据中过滤质量或许愈加困难,但有许多或许性。关于代码模型,咱们能够运用代码验证技能来将片段评分作为质量过滤器。假如代码来自GitHub,咱们能够按存储库一切者的星号或按星号进行过滤。

关于自然言语中的文本,质量过滤并不是一个简略的问题。搜索引擎排名能够作为一个受欢迎程度的过滤器,由于它一般根据用户与内容的互动。此外,常识蒸馏技能能够经过现实密度和精确性进行调整,作为过滤器。

在这个示例中,咱们将微调用于问答功能的Squad V2数据集。您能够在Hugging Face上查看有关数据集的具体描绘:huggingface.co/spaces/eval…

from datasets import load_dataset
dataset_name = "squad_v2"
dataset = load_dataset(dataset_name, split="train")
eval_dataset = load_dataset(dataset_name, split="validation")

咱们正在运用练习和验证的两个拆分。Squad V2数据集有一个部分用于练习,另一个用于验证,如load_dataset(dataset_name)的输出所示:

DatasetDict({
    train: Dataset({
        features: ['id', 'title', 'context', 'question', 'answers'],
        num_rows: 130319
    })
    validation: Dataset({
        features: ['id', 'title', 'context', 'question', 'answers'],
        num_rows: 11873
    })
})

咱们将运用验证拆分进行早停。早停将答应咱们在验证过错开端下降时中止练习。

Squad V2数据集由各种特征组成,咱们能够在这儿看到:

{'id': Value(dtype='string', id=None),
 'title': Value(dtype='string', id=None),
 'context': Value(dtype='string', id=None),
 'question': Value(dtype='string', id=None),
 'answers': Sequence(feature={'text': Value(dtype='string', id=None),
 'answer_start': Value(dtype='int32', id=None)}, length=-1, id=None)}

在练习中的根本思想是用一个问题提示模型,并将答案与数据集进行比较。鄙人一节中,咱们将运用这个设置微调一个开源的LLM。

开源模型

咱们希望运用一个在本地能够以不错的符号速率运转的小型模型。LLaMa-2模型需求经过您的电子邮件地址签署许可协议并得到承认(公平地说,这或许十分快),由于它带有商业用途的约束。OpenLLaMa等衍生品体现适当不错,能够在HF排行榜上看到:huggingface.co/spaces/Hugg… OpenLLaMa版本1不能用于编码使命,由于其分词器的原因。因而,让咱们运用v2!咱们将运用一个3B参数模型,即便在旧硬件上也能够运用:

model_id = "openlm-research/open_llama_3b_v2"
new_model_name = f"openllama-3b-peft-{dataset_name}"

咱们也能够运用更小的模型,如EleutherAI/gpt-neo-125m,这也能够在资源运用和功能之间取得特别好的折衷。

让咱们加载模型:

import torch
from transformers import AutoModelForCausalLM, BitsAndBytesConfig
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.float16,
)
device_map="auto"
base_model = AutoModelForCausalLM.from_pretrained(
    model_id,
    quantization_config=bnb_config,
    device_map="auto",
    trust_remote_code=True,
)
base_model.config.use_cache = False

Bits and Bytes配置使咱们能够将模型量化为8、4、3乃至2位,具有更快的推理速度和更低的内存占用,而功能丢失不大。

咱们将在Google Drive上存储模型查看点;您需求承认登录到您的Google账户:

from google.colab import drive
drive.mount('/content/gdrive')

咱们需求经过Google进行身份验证,以使其作业。

咱们能够将模型查看点和日志的输出目录设置为咱们的Google Drive:

output_dir = "/content/gdrive/My Drive/results"

假如您不想运用Google Drive,只需将其设置为核算机上的一个目录。

关于练习,咱们需求设置一个分词器:

from transformers import AutoTokenizer
tokenizer = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token
tokenizer.padding_side = "right"

现在,咱们将界说咱们的练习配置。咱们将设置LORA和其他练习参数:

from transformers import TrainingArguments, EarlyStoppingCallback
from peft import LoraConfig
# More info: https://github.com/huggingface/transformers/pull/24906
base_model.config.pretraining_tp = 1
peft_config = LoraConfig(
    lora_alpha=16,
    lora_dropout=0.1,
    r=64,
    bias="none",
    task_type="CAUSAL_LM",
)
training_args = TrainingArguments(
    output_dir=output_dir, 
    per_device_train_batch_size=4,
    gradient_accumulation_steps=4,
    learning_rate=2e-4,
    logging_steps=10,
    max_steps=2000,
    num_train_epochs=100,
    evaluation_strategy="steps",
    eval_steps=5,
    save_total_limit=5,
    push_to_hub=False,
    load_best_model_at_end=True,
    report_to="wandb"
)

这儿需求解说一下一些参数。push_to_hub参数意味着咱们能够在练习进程中定时将模型查看点推送到HuggingSpace Hub。为使其作业,您需求设置HuggingSpace身份验证(如前所述,需求写权限)。假如挑选这个选项,作为output_dir,咱们能够运用new_model_name。这将是模型在Hugging Face上可用的存储库称号:huggingface.co/models。 或许,正如我在这儿所做的,您能够将模型保存在本地或云端,例如在Google Drive的一个目录中。我将max_steps和num_train_epochs设置得很高,由于我留意到练习能够在许多进程后依然改善。前期中止和较高数量的最大练习进程应该有助于使模型供给更高的功能。关于前期中止,咱们需求将evaluation_strategy设置为”steps”,并将load_best_model_at_end设置为True。 eval_steps是两个评价之间的更新步数。save_total_limit=5表示只保存终究五个模型。终究,report_to=”wandb”表示咱们将发送练习计算信息、一些模型元数据和硬件信息到W&B,咱们能够在那里查看每个运转的图形和仪表板。

然后,练习能够运用咱们的配置:

from trl import SFTTrainer
trainer = SFTTrainer(
    model=base_model,
    train_dataset=dataset,
    eval_dataset=eval_dataset,
    peft_config=peft_config,
    dataset_text_field="question",  # this depends on the dataset!
    max_seq_length=512,
    tokenizer=tokenizer,
    args=training_args,
    callbacks=[EarlyStoppingCallback(early_stopping_patience=200)]
)
trainer.train()

练习或许需求适当长的时刻,即便在TPU设备上运转。频繁的评价会大大减慢练习速度。假如禁用前期中止,能够加快速度。

在练习进行时,咱们应该看到一些计算数据,但展现功能图表会更好,就像咱们在W&B上看到的那样。

运用LangChain的生成式AI——自界说LLMs及其输出

练习完结后,咱们能够将终究查看点保存在磁盘上以便从头加载:

trainer.model.save_pretrained(
    os.path.join(output_dir, "final_checkpoint"),
)

现在,咱们能够经过手动推送到Hugging Face,与朋友共享咱们所取得的功能。咱们能够运用咱们的Hugging Face用户名和存储库称号(新模型称号)的组合来加载模型。让咱们快速展现怎么在LangChain中运用此模型。一般,peft模型存储为适配器,而不是完好的模型;因而,加载办法有点不同:

from peft import PeftModel, PeftConfig
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline
from langchain.llms import HuggingFacePipeline
model_id = 'openlm-research/open_llama_3b_v2'
config = PeftConfig.from_pretrained("benji1a/openllama-3b-peft-squad_v2")
model = AutoModelForCausalLM.from_pretrained(model_id)
model = PeftModel.from_pretrained(model, "benji1a/openllama-3b-peft-squad_v2")
tokenizer = AutoTokenizer.from_pretrained(model_id, trust_remote_code=True)
tokenizer.pad_token = tokenizer.eos_token
pipe = pipeline(
    "text-generation",
    model=model,
    tokenizer=tokenizer,
    max_length=256
)
llm = HuggingFacePipeline(pipeline=pipe)

到目前为止,咱们在Google Colab上完结了一切操作,但咱们同样能够在本地履行;只需留意您需求装置Hugging Face peft库!

商业模型

到目前为止,咱们现已展现了怎么对开源LLM进行微谐和布置。一些商业模型也能够在自界说数据上进行微调。例如,OpenAI的GPT-3.5和Google的PaLM模型都供给了这种才能。这现已与一些Python库集成了起来。

运用Scikit-LLM库,这只需求几行代码。在本节中,咱们不会具体介绍整个进程,但请查看Scikit-LLM库或不同云LLM供给商的文档,以获取一切细节。Scikit-LLM库不是咱们在第3章“LangChain入门”中评论的设置的一部分,因而您需求手动装置它。我还没有包含练习数据X_train。您需求自己预备练习数据集。

关于文本分类,能够这样微调PaLM模型:

from skllm.models.palm import PaLMClassifier
clf = PaLMClassifier(n_update_steps=100)
clf.fit(X_train, y_train)  # y_train是标签的列表
labels = clf.predict(X_test)

同样,您能够这样微调GPT-3.5模型进行文本分类:

from skllm.models.gpt import GPTClassifier
clf = GPTClassifier(
        base_model = "gpt-3.5-turbo-0613",
        n_epochs = None, # int或None。当为None时,将由OpenAI主动确认
        default_label = "Random", # 可选
)
clf.fit(X_train, y_train)  # y_train是标签的列表
labels = clf.predict(X_test)

有趣的是,在OpenAI供给的微调中,一切输入都会经过一个审查体系,以保证输入契合安全规范。

这就结束了微调。LLM能够在没有任何使命特定调整的情况下进行布置和查询。经过提示,咱们能够完结少样本学习,乃至是零样本学习,正如咱们将鄙人一节中评论的那样。

提示工程

提示是咱们向言语模型供给的指令和示例,用于引导其行为。它们关于引导LLM的行为至关重要,由于它们答应您在不进行贵重的从头练习的情况下将模型输出与人类意图对齐。精心规划的提示能够使LLM适用于原始练习之外的各种使命。提示充任指示,向LLM演示所需的输入-输出映射是什么。

提示由三个首要组件组成:

  1. 描绘使命要求、方针和输入/输出格局的阐明。它们清楚地向模型解说使命。
  2. 展现所需输入-输出对的示例。它们供给不同演示,阐明不同输入应该怎么映射到输出。
  3. 模型有必要对其进行操作以生成输出的输入。

以下图示显现了提示不同言语模型的一些示例(来源:Pre-train, Prompt, and Predict – A Systematic Survey of Prompting Methods in Natural Language Processing by Liu and colleagues, 2021):

运用LangChain的生成式AI——自界说LLMs及其输出

提示工程,也被称为上下文学习,是指经过精心规划的提示技能来引导LLM行为,而无需更改模型权重。其方针是使模型输出与给定使命的人类意图共同。另一方面,提示调整供给了对模型行为的直观操控,但对提示的切当遣词和规划灵敏,因而需求精心拟定的准则以完结希望的成果。那么,好的提示是什么样的呢?

最重要的第一步是从简略开端,并进行迭代。从简明扼要、开门见山的阐明开端,根据需求逐渐增加杂乱性。将杂乱的使命分化为更简略的子使命。这样能够防止一开端就使模型不堪重负。尽或许具体、描绘具体关于切当使命和希望的输出格局。供给相关示例在演示所需的推理链或输出款式方面十分有用。

关于杂乱的推理使命,引导模型解说其逐渐考虑进程会进步精确性。像“链式思想提示”这样的技能引导模型进行清晰推理。供给少数示例进一步演示所需的推理格局。将杂乱问题分化为较小、更易管理的子使命的问题分化提示还经过启用更有结构的推理进程来进步可靠性。对多个候选呼应进行采样并挑选最共同的呼应有助于削减与依靠单一模型输出比较的过错和不共同性。

与其重视不要做什么,不如清楚指定希望的操作和成果。直接、清晰的指令作用最佳。防止运用不清晰或含糊的提示。从简略开端,具体阐明,供给示例,要求解说,分化问题,以及采样多个呼应 – 这些都是运用精心规划的提示工程有用引导LLM的一些最佳实践。经过迭代和实验,能够优化提示以进步可靠性,即便关于杂乱使命,也能够到达一般可与微调相媲美的功能。

在了解了最佳实践之后,让咱们看一些提示技能,从简略到越来越高档的!

提示技能

根本的提示办法包含零射击提示,仅运用输入文本,以及少射击提示,其间包含几个演示示例,显现所需的输入-输出对。研讨人员现已确认了像大多数标签成见和最近成见这样的成见,这些成见导致了少射击功能的变异性。经过示例挑选、排序和格局设置的谨慎提示规划能够协助缓解这些问题。

更高档的提示技能包含指令提示,其间清晰描绘使命要求,而不只仅是演示。自共同性采样生成多个输出并挑选与示例最契合的输出。思想链(CoT)提示生成清晰的推理进程,导致终究的输出。这关于杂乱的推理使命尤其有利。CoT提示能够手动编写,也能够经过增强-修剪-挑选等办法主动生成。

一些提示技能结合了外部信息检索,以在生成输出之前向LLM供给缺失的上下文。关于敞开域问答,能够经过搜索引擎检索相关阶段并合并到提示中。关于封闭式问答,具有证据-问题-答案格局的少数示例比QA格局更有用。

在接下来的几个末节中,咱们将介绍前面提到的一些技能。LangChain供给了东西,能够启用高档提示工程战略,如零射击提示、少射击学习、思想链、自共同性和思想树。这儿描绘的一切这些技能经过供给更清晰的阐明、运用有针对性的数据进行微调、采用问题分化战略、结合多样的采样办法、整合验证机制以及采用概率建模框架,增强了LLM在杂乱使命上的推理才能的精确性、共同性和可靠性。

您能够在本书的GitHub存储库中的提示目录中找到本节中的一切示例。让咱们从最简略的战略开端:咱们只是要求一个处理方案。

Zero-shot prompting

零射击提示与少射击提示相反,是直接向LLM供给使命阐明而不供给任何演示或示例。此提示测试了预练习模型了解和遵循阐明的才能:

from langchain import PromptTemplate
from langchain.chat_models import ChatOpenAI
model = ChatOpenAI()
prompt = PromptTemplate(input_variables=["text"], template="Classify the sentiment of this text: {text}")
chain = prompt | model
print(chain.invoke({"text": "I hated that movie, it was terrible!"}))

这输出了带有输入文本的情感分类提示,没有任何示例:

content='The sentiment of this text is negative.' additional_kwargs={} example=False

Few-shot learning

Few-shot learning向LLM展现与使命相关的少数输入-输出示例,而不供给清晰的阐明。这使得模型能够仅经过演示来揣度意图和方针。精心挑选、排序和格局化的示例能够改善模型的推理才能。但是,少射击学习或许简略遭到成见和实验间的变异性影响。增加清晰的阐明能够使模型更透明地了解意图,并进步鲁棒性。总体而言,提示结合了阐明和示例的优势,以最大程度地引导LLM履行手头的使命。

FewShotPromptTemplate答应您向模型展现使命的少数演示示例,而无需清晰的阐明。

让咱们扩展前面关于情感分类的示例,运用少射击提示。在此示例中,咱们希望LLM将客户反应分类为积极、消极或中性。咱们为其供给了一些示例:

examples = [{
    "input": "I absolutely love the new update! Everything works seamlessly.",
    "output": "Positive",
    },{
    "input": "It's okay, but I think it could use more features.",
    "output": "Neutral",
    }, {
    "input": "I'm disappointed with the service, I expected much better performance.",
    "output": "Negative"
}]

咱们能够运用这些示例创立以下提示:

from langchain.prompts import FewShotPromptTemplate, PromptTemplate
from langchain.chat_models import ChatOpenAI
example_prompt = PromptTemplate(
    template="{input} -> {output}",
    input_variables=["input", "output"],
)
prompt = FewShotPromptTemplate(
    examples=examples,
    example_prompt=example_prompt,
    suffix="Question: {input}",
    input_variables=["input"]
)
print((prompt | ChatOpenAI()).invoke({"input": " This is an excellent book with high quality explanations."}))

咱们应该得到以下输出:

content='Positive' additional_kwargs={} example=False

您能够希望LLM运用这些示例来辅导其对新句子的分类。少射击办法在不进行许多练习的情况下引导模型,而是依靠于其预练习常识和示例供给的上下文。

为了针对每个输入挑选定制的示例,FewShotPromptTemplate能够接受SemanticSimilarityExampleSelector,该挑选器根据嵌入而不是硬编码的示例。SemanticSimilarityExampleSelector会主动找到每个输入的最相关示例。

关于许多使命,规范的少射击提示作用很好,但在处理更杂乱的推理使命时,还有许多其他技能和扩展。

Chain-of-thought prompting

CoT提示旨在经过让模型供给中心进程来鼓舞推理,然后导致终究答案。这是经过在提示前加入指示来展现其考虑进程来完结的。

CoT有两个变体,即零射击和少射击。在零射击CoT中,咱们只需将指令“让咱们逐渐考虑!”增加到提示中。

当要求LLM经过一个问题进行推理时,一般更有用的做法是在陈述终究答案之前要求其解说其推理进程。这鼓舞LLM首要经过逻辑考虑问题,而不是只是猜想答案然后企图在之后证明。要求LLM解说其考虑进程与其中心才能很好地协调。 例如:

from langchain.chat_models import ChatOpenAI
from langchain.prompts import PromptTemplate
reasoning_prompt = "{question}nLet's think step by step!"
prompt = PromptTemplate(
  template=reasoning_prompt,
  input_variables=["question"]
)
model = ChatOpenAI()
chain = prompt | model
print(chain.invoke({
   "question": "There were 5 apples originally. I ate 2 apples. My friend gave me 3 apples. How many apples do I have now?",
}))

运转此示例后,咱们将得到推理进程以及成果:

content='Step 1: Originally, there were 5 apples.nStep 2: I ate 2 apples.nStep 3: So, I had 5 - 2 = 3 apples left.nStep 4: My friend gave me 3 apples.nStep 5: Adding the apples my friend gave me, I now have 3 + 3 = 6 apples.' additional_kwargs={} example=False

前述办法也被称为零射击链式考虑。 少射击链式考虑提示是一种少射击提示,其间推理被解说为示例处理方案的一部分,其意图是鼓舞LLM在做出决议计划之前解说其推理进程。 假如咱们回到之前的少射击示例,能够将它们扩展如下:

examples = [{
    "input": "I absolutely love the new update! Everything works seamlessly.",
    "output": "Love and absolute works seamlessly are examples of positive sentiment. Therefore, the sentiment is positive",
    },{
    "input": "It's okay, but I think it could use more features.",
    "output": "It's okay is not an endorsement. The customer further thinks it should be extended. Therefore, the sentiment is neutral",
    }, {
    "input": "I'm disappointed with the service, I expected much better performance.",
    "output": "The customer is disappointed and expected more. This is negative"
}]

在这些示例中,解说了做出决议计划的原因。这鼓舞LLM以解说其推理的办法给出相似的成果。

现已证明,CoT提示能够导致更精确的成果;但是,发现这种功能提升与模型规划成正比,而且在较小的模型中改善微乎其微,乃至是负面的。

Self-consistency

运用自共同性提示,模型会对一个问题生成多个候选答案。然后,这些答案彼此比较,挑选最共同或最频繁的答案作为终究输出。自共同性提示在现实验证或信息归纳的布景下特别有用,由于精确性至关重要。

在第一步中,咱们将为一个问题或问题创立多个处理方案:

from langchain import PromptTemplate, LLMChain
from langchain.chat_models import ChatOpenAI
solutions_template = """
Generate {num_solutions} distinct answers to this question:
{question}
Solutions:
"""
solutions_prompt = PromptTemplate(
   template=solutions_template,
   input_variables=["question", "num_solutions"]
)
solutions_chain = LLMChain(
   llm=ChatOpenAI(),
   prompt=solutions_prompt,
   output_key="solutions"
)

在第二步中,咱们想要计算不同的答案。咱们能够再次运用一个LLM:

consistency_template = """
For each answer in {solutions}, count the number of times it occurs. Finally, choose the answer that occurs most.
Most frequent solution: 
"""
consistency_prompt = PromptTemplate(
   template=consistency_template,
   input_variables=["solutions"]
)
consistency_chain = LLMChain(
   llm=ChatOpenAI(),
   prompt=consistency_prompt,
   output_key="best_solution"
)

让咱们用SequentialChain将这两个链条结合在一起:

from langchain.chains import SequentialChain
answer_chain = SequentialChain(
   chains=[solutions_chain, consistency_chain],
   input_variables=["question", "num_solutions"],
   output_variables=["best_solution"]
)

让咱们提一个简略的问题并查看答案:

print(answer_chain.run(
   question="Which year was the Declaration of Independence of the United States signed?",
   num_solutions="5"
))

咱们应该得到相似这样的呼应:

1776 is the year in which the Declaration of Independence of the United States was signed. It occurs twice in the given answers (3 and 4).

咱们应该根据投票得到正确的呼应;但是,咱们生成的五个答案中有三个是过错的。 这种办法利用了模型推理和利用内部常识的才能,一起经过重视最常见的答案来下降异常值或过错信息的危险,然后进步了LLM给出的呼应的整体可靠性。

Tree-of-thought

在Tree-of-Thought(ToT)提示中,咱们生成给定提示的多个处理问题进程或办法,然后运用AI模型对其进行评论。评论将根据模型对处理方案适用于问题的判别。

实际上,现在在LangChain的实验性软件包中有ToT的完结;但是,让咱们经过运用LangChain逐渐示例来具体阐明怎么施行ToT。

首要,咱们将运用PromptTemplates界说四个链组件。咱们需求一个处理方案模板、一个评价模板、一个推理模板和一个排名模板。

首要,让咱们生成处理方案:

solutions_template = """
Generate {num_solutions} distinct solutions for {problem}. Consider factors like {factors}.
Solutions:
"""
solutions_prompt = PromptTemplate(
   template=solutions_template,
   input_variables=["problem", "factors", "num_solutions"]
)

然后,让咱们要求LLM评价这些处理方案:

evaluation_template = """
Evaluate each solution in {solutions} by analyzing pros, cons, feasibility, and probability of success.
Evaluations:
"""
evaluation_prompt = PromptTemplate(
  template=evaluation_template,
  input_variables=["solutions"] 
)

在这一步之后,咱们想要对它们进行更深化的考虑:

reasoning_template = """
For the most promising solutions in {evaluations}, explain scenarios, implementation strategies, partnerships needed, and handling potential obstacles.
Enhanced Reasoning:
"""
reasoning_prompt = PromptTemplate(
  template=reasoning_template,
  input_variables=["evaluations"]
)

终究,根据咱们迄今为止的推理,咱们能够对这些处理方案进行排名:

ranking_template = """
Based on the evaluations and reasoning, rank the solutions in {enhanced_reasoning} from most to least promising.
Ranked Solutions:
"""
ranking_prompt = PromptTemplate(
  template=ranking_template,
  input_variables=["enhanced_reasoning"]
)

接下来,咱们从这些模板创立链,然后将一切链衔接在一起:

from langchain.chains.llm import LLMChain
from langchain.chat_models import ChatOpenAI
solutions_chain = LLMChain(
   llm=ChatOpenAI(),
   prompt=solutions_prompt,
   output_key="solutions"
)
evalutation_chain = LLMChain(
   llm=ChatOpenAI(),
   prompt=evaluation_prompt,
   output_key="evaluations"
)
reasoning_chain = LLMChain(
   llm=ChatOpenAI(),
   prompt=reasoning_prompt,
   output_key="enhanced_reasoning"
)
ranking_chain = LLMChain(
   llm=ChatOpenAI(),
   prompt=ranking_prompt,
   output_key="ranked_solutions"
)

请留意,每个output_key对应于以下链的prompt中的input_key。终究,咱们将这些链衔接成一个SequentialChain:

from langchain.chains import SequentialChain
tot_chain = SequentialChain(
   chains=[solutions_chain, evalutation_chain, reasoning_chain, ranking_chain],
   input_variables=["problem", "factors", "num_solutions"],
   output_variables=["ranked_solutions"]
)

让咱们运转tot_chain并查看打印输出:

1. Train or fine-tune language models using datasets that are relevant to the reasoning task at hand.
2. Develop or adapt reasoning algorithms and techniques to improve the performance of language models in specific reasoning tasks.
3. Evaluate existing language models and identify their strengths and weaknesses in reasoning.
4. Implement evaluation metrics to measure the reasoning performance of the language models.
5. Iteratively refine and optimize the reasoning capabilities of the language models based on evaluation results.
It is important to note that the ranking of solutions may vary depending on the specific context and requirements of each scenario.

我完全同意这些建议。它们展现了ToT的优势。这其间许多主题都是本章的一部分,而一些将在第9章《生成式AI在生产中》中评论,届时咱们将探讨评价LLMs及其功能。

这使咱们能够在推理进程的每个阶段利用LLM。ToT办法经过促进探索来防止了走入死胡同。假如您想看到更多示例,在LangChain Cookbook中,您能够找到一个用于玩数独的ToT。

关于开释LLM推理才能而言,提示规划十分重要,而且它为模型和提示技能的未来开展供给了潜在的或许性。这些准则和技能为与LLMs一起作业的研讨人员和实践者供给了名贵的东西包。

总结

调理答应引导生成式AI以进步功能、安全性和质量。在本章中,焦点是经过微谐和提示来进行调理。在微调中,言语模型经过练习许多以自然言语指令构建的使命示例以及适当的呼应来进行练习。一般经过强化学习与人类反应进行此操作;但是,现已开发了其他技能,据证明其在资源占用较低的情况下发生具有竞争力的成果。在本章的第一个示例中,咱们施行了一个用于问答的小型开源模型的微调。

有许多提示技能能够进步LLMs在杂乱推理使命中的可靠性,包含逐渐提示、替代挑选、推理提示、问题分化、采样多个呼应以及运用独立的验证模型。这些办法已被证明能够增强推理使命中的精确性和共同性。正如咱们在示例中所展现的,LangChain供给了解锁高档提示战略的构建块,如few-shot学习、CoT、ToT等。

在第9章《生成式AI在生产中》,咱们将评论生成式AI的生产化以及与之相关的要害问题,例如评价LLM运用程序、将它们布置到服务器并对其进行监控。