乐趣区

关于人工智能:落地领域大模型应知必会-1-主要微调方法总览

编者按:随着大规模预训练模型的倒退和利用,大模型微调技术曾经在很多畛域都有了突破性的停顿,并推动了人工智能技术的倒退与利用。

本文会简要介绍上下文学习(in-context learning)的含意,并介绍对 LLMs 进行微调的各种可行形式。还可能帮忙咱们理解如何抉择大语言模型的微调办法。

快快浏览此文,开启一趟大模型微调学习之旅吧!

以下是译文,Enjoy!

本文经原作者受权,由 Baihai IDP 编译。如需转载译文,请分割获取受权。

原文链接:https://magazine.sebastianraschka.com/p/finetuning-large-lang…

作者 | SEBASTIAN RASCHKA, PHD

编译 | 岳扬

在现在高速倒退的人工智能畛域,高效地利用大语言模型(LLMs)曾经变得越来越重要。然而,利用大语言模型的形式太多了,如果你才刚刚开始接触它,可能会感到手足无措。

本质上,咱们能够通过两种次要形式将预训练大语言模型用于新工作:上下文学习(in-context learning)以及微调(finetuning)

本文咱们将简要介绍上下文学习(in-context learning)的含意,并介绍对 LLMs 进行微调的各种可行形式。

01 In-Context Learning 和 Indexing

自从 GPT-2(Radford 等人 [1])和 GPT-3(Brown 等人[2])问世以来,咱们发现,在通用文本语料库上进行预训练的生成式大语言模型(LLMs)能够进行上下文学习。这意味着, 如果咱们想要执行新的特定工作,咱们无需对预训练的 LLM 进行进一步的训练或微调,能够通过输出 Prompt 间接提供一些指标工作的示例,如上面的例子所示。

上下文学习的例子

如果咱们 不能间接拜访模型(例如如果咱们通过 API 应用模型),那么上下文学习就用途十分大。

与上下文学习相干的是 hard prompt tuning,即试图 通过批改输出改善输入,如下图所示。

An illustration of (hard) prompt tuning 顺便说一下,咱们称这种办法为 hard prompt tuning,因为在这种办法中,咱们 间接批改了输出的单词或 tokens。稍后咱们将探讨另外一种版本的办法,称为soft prompt tuning(或通常称为 prompt tuning)。

刚刚提到的 prompt tuning 办法为参数微调(parameter finetuning)提供了一种代替计划(且这种计划更 节俭资源 )。然而,它的 性能通常不迭微调 (finetuning),因为这种办法 不会针对特定工作更新模型的参数 ,这可能会 限度它对不同特定工作间细微差别的适应能力 。此外,prompt tuning 可能须要进行大量工作, 消耗大量人力财力,因为这种办法须要人工参加比拟不同 prompt 的品质。

在咱们更进一步地探讨微调之前,先来理解另一种利用纯正的上下文学习的办法——indexing。在大语言模型畛域中,indexing 能够被视为一种上下文学习的变通方法,其使得 LLMs 可能转变为信息检索零碎(information retrieval systems),从内部资源和网站中提取数据。在这个过程中,indexing 模块将文档或网站分解成较小的片段,并将它们转换为能够存储在向量数据库中的向量(vectors)。而后,当用户提交查问(query)时,indexing 模块计算嵌入查问(embedded query)与数据库中每个向量之间的向量类似度(vector similarity)。最终,indexing 模块检索出与查问最类似的前 k 个嵌入(embeddings),生成响应。

An illustration of indexing.

02 惯例的基于特色的办法和微调办法

如果咱们无奈间接拜访大型语言模型(LLM),例如通过 API 或应用用户界面与 LLM 进行交互,那么上下文学习是一种有价值且用户敌对的办法。

然而,如果咱们能够间接接触到 LLM,应用指标畛域的数据对其进行调整(adapting)和微调(finetuning)通常会取得更好的后果。那么,如何使一个模型适应指标工作呢?下图概述了三种常见的办法:

3 种惯例的基于特色的办法和微调的办法

下文中,咱们将以对编码器类型(encoder-style)的大型语言模型(例如 BERT)微调为例,解析具体的微调形式原理和示例代码。下述示例微调工作为分类器工作,在这个工作中,咱们试图预测电影评论是侧面情感还是负面情感。须要留神的是,除了对编码器类型(encoder-style)的 LLM 进行微调外,同样的办法也实用于相似 GPT 的解码器类型(decoder-style)的 LLM。在后续的文章中,我将会举例说明这一点。

此外,咱们还能够对解码器类型(decoder-style)的 LLM 进行微调,以生成对特定指令的多句子答复(multiple-sentence answers),而不仅仅是进行文本分类。对于这个问题,我会在将来的文章中提供实战案例,敬请期待。

2.1 基于特色的办法

在基于特色的办法(feature-based approach)中,咱们须要加载一个预训练 LLM,并将其利用于指标数据集。在这种办法中,我对生成训练集的输入嵌入(output embeddings)特地感兴趣,这些嵌入能够作为输出特色(input features)用于训练分类模型(classification model)。尽管这种办法在像 BERT 这样以嵌入为重点的模型中十分常见,但咱们也能够从生成式的 GPT-style 模型中提取嵌入。

接下来,咱们能够应用逻辑回归模型(logistic regression model)、随机森林(random forest)或 XGBoost 等任何咱们想要应用的模型作为分类模型。(然而,依据我的教训,在这种状况下,像逻辑回归(logistic regression)这样的线性分类器(linear classifiers)体现最佳

实践上,咱们能够用上面这段代码来解释基于特色的办法:

model = AutoModel.from_pretrained("distilbert-base-uncased")

# ...
# tokenize dataset
# ...

# generate embeddings
@torch.inference_mode()
def get_output_embeddings(batch):
output = model(batch["input_ids"],
attention_mask=batch["attention_mask"]
).last_hidden_state[:, 0]
return {"features": output}

dataset_features = dataset_tokenized.map(get_output_embeddings, batched=True, batch_size=10)

X_train = np.array(imdb_features["train"]["features"])
y_train = np.array(imdb_features["train"]["label"])

X_val = np.array(imdb_features["validation"]["features"])
y_val = np.array(imdb_features["validation"]["label"])

X_test = np.array(imdb_features["test"]["features"])
y_test = np.array(imdb_features["test"]["label"])

# train classifier
from sklearn.linear_model import LogisticRegression

clf = LogisticRegression()
clf.fit(X_train, y_train)

print("Training accuracy", clf.score(X_train, y_train))
print("Validation accuracy", clf.score(X_val, y_val))
print("test accuracy", clf.score(X_test, y_test))

(对此感兴趣的读者能够在此处 [4] 找到残缺的代码)

2.2 微调办法 I —— 更新输入层(Output Layers)

有一种办法与上述基于特色的办法比拟相干,叫做微调输入层(本文称之为微调办法 I)。与基于特色的办法相似,这种办法不扭转预训练 LLM 的参数,只会训练新减少的输入层,相似于在嵌入特色(embedded features)上训练逻辑回归分类器(logistic regression classifier)或小型多层感知器(small multilayer perceptron)。

相干代码如下:

model = AutoModelForSequenceClassification.from_pretrained(
    "distilbert-base-uncased",
     num_labels=2
) 

# freeze all layers
for param in model.parameters():
    param.requires_grad = False
    
# then unfreeze the two last layers (output layers)
for param in model.pre_classifier.parameters():
    param.requires_grad = True

for param in model.classifier.parameters():
    param.requires_grad = True
    
# finetune model
lightning_model = CustomLightningModule(model)

trainer = L.Trainer(
    max_epochs=3,
    ...
)

trainer.fit(
  model=lightning_model,
  train_dataloaders=train_loader,
  val_dataloaders=val_loader)

# evaluate model
trainer.test(lightning_model, dataloaders=test_loader)

(对此感兴趣的读者能够在此处 [4] 找到残缺的代码)

从实践上讲,这种办法的建模性能和速度(modeling performance and speed)应该与基于特色的办法差不多,因为都会去解冻骨干模型(frozen backbone model)(译者注:通过解冻骨干模型,咱们能够放弃其模型权重不变,仅对工作模块进行训练。这样能够缩小须要更新的参数数量,进步训练效率,并在肯定水平上保留原始骨干模型的特征提取能力)。然而,因为基于特色的办法使得预计算(pre-compute)和存储训练数据集的嵌入特色(embedded features)略微更容易一些,所以 在具体场景中,基于特色的办法可能更加不便

2.3 微调办法 II – 更新所有层(All Layers)

尽管 BERT 那篇论文(Devlin 等人)说过,仅微调输入层(output layer)能够实现与微调所有层相当的模型性能,但因为后者波及的参数更多,所以老本要高得多。 例如,BERT 根底模型约有 1.1 亿个参数。然而,用于二元分类的 BERT 根底模型最初一层仅蕴含 1500 个参数。此外,BERT 根底模型的最初两层共有 6 万个参数,这仅占总模型大小的 0.6% 左右。

咱们抉择走哪条门路会依据指标工作和指标畛域与模型预训练的数据集的类似水平而有所不同。然而在具体实际中,微调所有层简直总是能取得更优的模型性能。

因而,在优化模型性能时,应用预训练 LLM 的黄金规范(the gold standard)是更新所有层(本文称之为微调办法 II)。从实践上讲,微调办法 II 与微调办法 I 十分类似。惟一的区别是办法 II 不会解冻预训练 LLM 的参数,而是对其进行微调

model = AutoModelForSequenceClassification.from_pretrained(
    "distilbert-base-uncased",
     num_labels=2
) 

# freeze layers (which we don't do here)
# for param in model.parameters():
#    param.requires_grad = False
    

# finetune model
lightning_model = LightningModel(model)

trainer = L.Trainer(
    max_epochs=3,
    ...
)

trainer.fit(
  model=lightning_model,
  train_dataloaders=train_loader,
  val_dataloaders=val_loader)

# evaluate model
trainer.test(lightning_model, dataloaders=test_loader)

(对此感兴趣的读者能够在此处 [4] 找到残缺的代码)

下面的这段代码被用来训练一个基于 DistilBERT 根底模型的电影评论分类器(你能够去 the code notebooks 看一看[4])

1)基于特色的办法与逻辑回归:83% 的测试准确率(accuracy);

2)微调办法 I,更新最初两层:87% 准确率(accuracy);

3)微调办法 II,更新所有层:92% 准确率(accuracy)。

这些准确率后果合乎预期,即微调更多层通常会取得更好的性能,但也须要破费更高的老本。

本文 3 种办法的训练效率和模型性能衡量经验之谈

上述场景强调了微调的三种最不同或最极其的状况:即仅训练最初一层(或几层)与训练所有层。当然,具体成果可能会因模型和数据集而异,但在摸索两者之间的各种状况也是值得的。 例如,有时候咱们只需训练一半的模型,就能取得与训练实现的模型雷同的性能(更多对于轻量化微调(parameter-efficient finetuning)的内容将在下一节介绍)。如果你是一个好奇宝宝,下图形容了在 IMDB 电影评论数据集(IMDB movie review dataset)的 2 万个训练实例上进行微调的 DistilBERT 模型的预测性能(predictive performances)和训练工夫。

在 IMDB 电影评论数据集上微调的预训练 DistilBERT 模型的性能。相干代码能够在 GitHub 上找到[5]

正如咱们能够看到的,仅训练最初一层是最疾速的,但模型性能也最差。 合乎预期的是,训练更多层会进步模型性能,但也会减少计算成本。 有一件事件十分乏味,能够看到当训练两个全连贯的输入层(fully connected output layers)和最初两个 transformer blocks(从右边数起的第三个 block)时,预测性能(predictive performance)就曾经趋于饱和。因而,在这种特定状况下(即对于这个特定的模型和数据集组合),训练超过这些层(layers)仿佛是一种计算资源的节约。

03 轻量化微调(Parameter-Efficient Fine-Tuning)

轻量化微调让咱们可能重复使用预训练的模型,同时最大限度地缩小算力和资源的占用。总体来说,轻量化微调具备以下五个长处:

1. 可能升高计算成本(须要更少的 GPU 和 GPU 运行工夫);

2. 领有更快的训练工夫(更快地实现训练);

3. 具备更低的硬件要求(实用于较小显存的 GPU 和较小的内存);

4. 具备更好的模型性能(升高过拟合);

5. 须要更少的存储空间(大部分 weights 能够在不同工作(tasks)之间共享)。

在之前的章节中,咱们理解到微调更多的层通常会带来更好的后果。下面的试验是基于一个绝对较小的 DistilBERT 模型。然而,如果咱们想微调那些简直无奈包容在 GPU 显存中的较大模型(例如最新的生成式 LLM 模型),咱们该怎么办呢?当然,咱们能够应用上述基于特色的办法或者微调办法 I。但假如咱们想要取得与微调办法 II 相似的模型品质呢?

这些年来,钻研人员们开发了几种技术(Lialin 等人[6])来微调 LLM,使其只须要训练大量的参数,也能具备较高的模型性能。这些办法通常被称为参数高效微调技术(parameter-efficient finetuning techniques,PEFT,本文亦译作轻量化微调)。

一些目前最受欢迎的 PEFT 技术在下图中可见。

最受欢迎的轻量化微调(PEFT)技术可选择项

那么,这些技术是如何工作的呢?简略来说,都波及到引入大量额定的参数进行微调(而不是像咱们在下面的微调办法 II 中那样对所有层进行微调)。从某种意义上说,微调办法 I(只微调最初一层)也能够被认为是一种轻量化微调(PEFT)技术。然而,像前缀微调(prefix tuning)、adapters 和 Low-Rank Adaptation (LoRA, 低秩自适应))等技术,它们都“批改”了多个层(layers),以极低的老本实现了更好的预测性能(predictive performance)。

因为本文的篇幅目前曾经很长了,而且这些都是超级乏味的技术,我将在将来独自介绍这些技术。

04 基于人类反馈的强化学习(Reinforcement Learning with Human Feedback)

在基于人类反馈的强化学习(Reinforcement Learning with Human Feedback,RLHF)中,应用一种联合了监督学习(supervised learning)和强化学习(reinforcement learning)的办法对预训练模型进行微调——这一办法被 ChatGPT 应用而失去大力推广,而 ChatGPT 又是基于 InstructGPT(Ouyang 等人[7])的。

在 RLHF 中,通过让人类对不同的模型输入进行排序或评分来收集人类反馈,从而提供 处分信号(reward signal)。收集到的 处分标签(reward labels) 能够用来训练 处分模型(reward model),进而反过来领导 LLM(Language Model)适应人类的爱好。

处分模型自身是通过监督学习(supervised learning)来学习的(通常应用预训练的 LLM 作为根底模型)。接下来,应用处分模型来更新预训练的 LLM,使其适应人类偏好——训练过程应用一种被称为 近端策略优化(proximal policy optimization,Schulman 等人[8])的强化学习办法。

InstructGPT 相干论文的截图,概述了 RLHF 的过程

为什么要应用处分模型而不是间接在人类反馈的根底上训练预训练模型?这是因为让人类参加模型的学习过程会产生瓶颈(bottleneck),因为咱们无奈实时获取反馈。

这篇文章的篇幅曾经很长了,所以我把更具体的解释推延到当前的文章中,敬请期待!

05 总结

对预训练 LLM 的 所有层 (layers)进行微调依然是适应新指标工作(new target tasks)的 黄金规范 (the gold standard),然而对于预训练的 Transformer 模型,有几种无效的代替办法。诸如基于特色的办法、上下文学习和轻量化微调等这些办法可能无效地 将 LLM 利用于新的工作 ,同时还能最大限度地 缩小计算成本和计算资源

此外,基于人类反馈的强化学习(RLHF)作为监督微调(supervised finetuning,SFT)的一种代替办法,能够晋升模型性能。

END

参考资料

1.https://d4mucfpksywv.cloudfront.net/better-language-models/la…

2.https://arxiv.org/abs/2005.14165

3.https://arxiv.org/abs/1810.04805

4.https://github.com/rasbt/LLM-finetuning-scripts/tree/main/conventional/distilbert-movie-review

5.https://github.com/rasbt/LLM-finetuning-scripts/tree/main/conventional/distilbert-movie-review/layerwise-experiment

6.https://arxiv.org/abs/2303.15647

7.https://arxiv.org/abs/2203.02155

8.https://arxiv.org/abs/1707.06347

本文经原作者受权,由 Baihai IDP 编译。如需转载译文,请分割获取受权。

原文链接

https://magazine.sebastianraschka.com/p/finetuning-large-lang…

退出移动版