Press "Enter" to skip to content

LangChain 101 第2部分c. 使用PEFT、LORA和RL进行微调LLM

为了更好地理解本文,请参阅前面的部分,其中我讨论了大型语言模型:

LangChain 101:第2ab部分。关于(大型语言)模型,你需要知道的一切

pub.towardsai.net

如果你对langchain和大型语言模型感兴趣,请考虑访问系列文章的第1部分:

LangChain 101:第1部分。构建简单的问答应用程序

在本文中,我将向你介绍LangChain的基础知识,这是一个用于构建大型应用程序的框架…

pub.towardsai.net

关注作者以不错过下一部分的内容 🙂

在机器学习和数据科学中,常常将进行预测的黑盒子称为模型。有不同的模型,其中之一就是语言模型。语言模型已经存在了一段时间,但在ChatGPT出现之前并不像现在这样流行。其中一个原因是GPT-1模型是在少量数据上训练的。随着GPT后面的数字增加,数据量也增加,这导致出现了大型语言模型,或者更常被称为LLM。

模型微调

模型微调,也称为迁移学习,是一种用于在特定任务上进一步训练预先存在的模型以提高性能的机器学习技术。微调通常用于预先训练的模型在一般领域(在我们的例子中是自然语言)中学到有价值的表示,并针对更狭窄、更具体的任务进行适应,表现出色。

https://github.com/IvanReznikov/DataVerse/tree/main/Courses/LangChain/Lecture2.%20Models

我听到了很多问题:微调大型语言模型是否值得?为什么不使用提示 – 它们似乎还不错。我可以使用矢量存储代替吗?以及有关该主题的其他问题…

想象以下情况:你要去看牙医。你更愿意选择哪个:

  • 一个扮演牙医的人(提示:“想象你是一名牙医…”)
  • 一个阅读了所有关于口腔护理的文献的人(使用矢量存储)
  • 一个经过培训能够进行牙科手术的医生(微调模型)

我所演讲的观众,明确选择了最后一种选择(PyData和数据科学聚会)

PEFT – 参数高效微调

PEFT,即参数高效微调(Parameter-Efficient Fine-tuning),是一种在不微调所有模型参数的情况下提高预训练语言模型性能的方法。这使得对于具有数千亿或数万亿参数的大型模型来说,微调LLM变得更加高效和具有成本效益。

PEFT通过冻结预训练模型的一些层,并仅微调与下游任务相关的最后几层来实现。这基于这样一个观察结果,即LLM的较低层往往更加通用,不太专注于具体任务,而较高层则更加专门用于LLM训练的任务。经典的迁移学习。

这是一个使用PEFT对LLM进行微调的文本分类任务的示例:

  1. 冻结预训练LLM的前几层。
  2. 在标记文本的较小数据集上微调LLM的未冻结层。
  3. 对模型进行微调,并可以在未知数据上进行测试。

LoRa – 低秩适应,每个人都在谈论

LoRa,或称为低秩适应,是一种微调技术,可以将大型语言模型(LLM)适应于特定的任务或领域,而无需训练模型的所有参数。 LoRa不会根本改变当前的Transformer架构。 LoRa冻结预训练模型权重,并将可训练的秩分解矩阵注入到Transformer架构的每个层中

LORA通过将原始预训练权重与期望的微调权重之间的差异分解为两个较小的低秩矩阵来适应先前训练的变压器模型的权重到特定任务或领域。然后,这两个矩阵被微调,而不是完整的模型参数集。这可以将可训练参数的数量减少10000倍,仍然达到与全参数微调相当的性能。在微调过程中,LORA如同数据科学的通常做法一样,更新低秩嵌入和投影层的权重,最小化损失函数。

现在,PEFT和LoRa之间有什么区别?PEFT是一种高效微调大型语言模型的方法,包括LoRa在内的各种技术。

https://github.com/IvanReznikov/DataVerse/tree/main/Courses/LangChain/Lecture2.%20Models

这种方法具有以下几个优点:

  1. 相对于全参数微调,它更加节省时间,特别是针对大型变压器模型。
  2. 它更加节省内存,使得在内存有限的设备上进行模型微调成为可能。
  3. 它是更可控的微调,因为低秩矩阵编码了特定的知识或约束。

强化学习

强化学习(RL)是另一种微调模型的方法。它需要两个原始模型的副本。一个副本是活动模型,用于执行所需的任务。另一个副本是参考模型,用于生成约束活动模型训练的逻辑回归(模型的非标准化输出)。

LLM如何生成文本?

本文不讨论变压器或大型语言模型的训练方法。我们将专注于使用…

pub.towardsai.net

对模型进行两个副本的要求可能是一个挑战,特别是对于大型模型而言在GPU方面。然而,这个限制是必要的,以防止活动模型与其原始行为相差过大,因为RL算法可能导致生成意外或有害输出的模型。

https://github.com/IvanReznikov/DataVerse/tree/main/Courses/LangChain/Lecture2.%20Models

让我们来通过微调过程:

  1. 参考模型使用预训练语言模型的参数进行初始化。
  2. 主动模型开始使用强化学习进行训练。
  3. 在每一次优化步骤中,计算主动模型和参考模型的逻辑回归(对数概率)。
  4. 然后使用主动模型和参考模型的逻辑回归(KL指标)计算损失函数。
  5. 使用损失函数的梯度或近端策略优化更新主动模型的参数。

是时候编码了!

完整代码可以在GitHub上找到。

我们将开始导入peft并为微调做好准备。

from peft import prepare_model_for_kbit_trainingpretrained_model.gradient_checkpointing_enable()model = prepare_model_for_kbit_training(pretrained_model)

我们将设置 LoraConfig 参数,并使用 get_peft_model 方法创建一个 PeftModel

  • r:低秩矩阵的秩表示原始预训练权重和期望微调权重之间的差异。较高的 r 值可以让 LORA 学习更复杂的参数关系,但这也会增加计算开销。
  • lora_alpha:一个超参数,用于控制下游任务的损失函数和保留原始预训练权重的损失函数之间的权衡。较高的 lora_alpha 值将更多地权重给保护初始预训练权重的损失函数。
  • target_modules:应使用 LORA 进行微调的模型中的模块名称列表。
  • lora_dropout:训练期间对低秩矩阵应用的 dropout 率。
  • bias:在低秩矩阵中使用的偏置类型。有效选项为“none”、“shared”和“individual”。
  • task_type:进行微调的模型的任务类型。有效选项为“CAUSAL_LM”和“CLASSIFICATION”。
from peft import LoraConfig, get_peft_modelconfig = LoraConfig(    r=16,    lora_alpha=32,    target_modules=["query_key_value"],    lora_dropout=0.05,    bias="none",    task_type="CAUSAL_LM",)model = get_peft_model(model, config)

现在是时候设置 Trainer 类了:

  • data_collator:用于将训练数据合并成批次的函数。
  • per_device_train_batch_size:每个 GPU 的批处理大小。
  • gradient_accumulation_steps:在更新模型参数之前累积梯度的步骤数。这可以用于减少内存使用和提高训练速度。
  • warmup_ratio:线性学习率预热所占训练步骤的比例。
  • fp16:是否使用16位浮点(FP16)精度训练。这可以提高训练速度并减少内存使用。
  • logging_steps:训练日志更新之间的训练步骤数。
  • output_dir:训练后模型和其他训练产物保存的目录。
  • optim:用于训练模型的优化器。有效选项为“adamw”、“sgd”和“paged_adamw_8bit”。
  • lr_scheduler_type:要使用的学习率调度程序。有效选项为“cosine”、“linear”和“constant”。
trainer = transformers.Trainer(    model=model,    train_dataset=train_dataset,    # eval_dataset=val_dataset,    args=transformers.TrainingArguments(        num_train_epochs=10,        per_device_train_batch_size=8,        gradient_accumulation_steps=4,        warmup_ratio=0.05,        max_steps=40,        learning_rate=2.5e-4,        fp16=True,        logging_steps=1,        output_dir="outputs",        optim="paged_adamw_8bit",        lr_scheduler_type="cosine",    ),    data_collator=transformers.DataCollatorForLanguageModeling(tokenizer, mlm=False),)

我们现在只剩下开始训练了:

trainer.train()

我们现在可以立即使用带有tokenized input_ids的模型,或者保存它以备将来使用:

trained_model = (    trainer.model.module if hasattr(trainer.model, "module") else trainer.model)  # 处理分布式/并行训练trained_model.generate(input_ids)# 保存模型trained_model.save_pretrained("outputs")

提醒:完整的代码可以在GitHub上找到。

这就是Part 2c的结尾。下一部分(de)将专门讲解如何使用人类反馈来优化模型。

LangChain 101:Part 1. 构建简单的问答应用程序

在本文中,我将介绍您了解LangChain的基础知识,LangChain是一个用于构建具有大型语言模型的应用程序的框架…

pub.towardsai.net

LangChain 101:Part 2ab. 关于(大型语言)模型的一切

pub.towardsai.net

LangChain 101 第2部分c. 使用PEFT、LORA和RL进行微调LLM 四海 第4张

给我点赞并关注我,这会激励我写更多文章,并让你知道下一部分发布的时间。

Leave a Reply

Your email address will not be published. Required fields are marked *