构建LLM应用:大语言模型LLM(第六部分)

点击上方“AI公园”,关注公众号,选择加“星标“或“置顶”


作者:Vipra Singh

编译:ronghuaiyang

导读

接下来,我们将转向RAG应用的生成部分。在文本生成方面,我们将运用大型语言模型。

到此为止,我们已经了解到原始数据是如何被转化并存入向量数据库的,随后再依据用户的提示从数据库中检索出相关的数据片段。这标志着应用程序检索部分的工作已经完成。

接下来,我们将转向RAG应用的生成部分。在文本生成方面,我们将运用大型语言模型。

8687490ce950f6cfee0cdc3040662c40.png

1. 什么是大语言模型?

大型语言模型(LLM)是基于海量数据预训练的大型深度学习模型。其底层架构Transformer,是由包含编码器和解码器的神经网络集合组成,这些组件具备自注意机制。编码器与解码器从文本序列中抽取意义,并理解文本内单词及短语之间的关联性。

8e964a2112471469ad3b87899b1ac5f0.png

大语言模型家族

cf3396a6c55d565d7c132a7675b80b7e.png

以下是一些最具代表性的大型语言模型(LLM)框架的时间线(截至目前)

Transformer神经网络架构使得使用参数量极高的大型模型成为可能,这些模型的参数数量往往达到数百亿。如此大规模的模型可以处理海量数据,数据来源通常包括互联网,以及像“Common Crawl”这样的资源,该资源包含了超过500亿个网页,还有Wikipedia,其页面总数大约为5700万。

自然语言处理(NLP)应用中的关键工具之一就是语言建模

a4f06db401effb2bc775072bb2a21795.png

这张图展示了大型语言模型(LLMs)的不同组成部分。

2. 语言建模 (LM)

语言和沟通的过程能否被简化为计算?

语言模型通过从一个或多个文本语料库中学习来生成概率。文本语料库是一种语言资源,由大量的、结构化的、一种或多种语言的文本集合构成。文本语料库可以包含一种或多种语言的文本,并且通常会进行标注。

d2199807db4a129fd95312b535fb58b1.png

一个语言模型可以根据在训练过程中学到的统计模式,预测最有可能跟随某个短语出现的词(或词组)。在图中,语言模型可能会估计出有91%的概率,词blue会跟在序列The color of the sky is之后。

构建语言模型的最早方法之一是基于n-gram。n-gram是从给定文本样本中提取的连续的n个项的序列。在此模型中,假设序列中下一个词的概率仅仅依赖于固定大小的前几个词的窗口。

80b2b0f78031a12d555bb1033fd94b11.jpeg

然而,n-gram语言模型已经被神经网络语言模型取代。神经网络语言模型基于神经网络,这是一种受生物神经网络启发的计算系统。这些模型利用词的连续表示或嵌入来做出预测:

f0a94765379f453caa129fd21ce26bf8.jpeg

神经网络将词以权重的非线性组合分布形式表示。因此,它可以避免在语言建模中的维度灾难问题。对于语言建模,已经提出了几种神经网络架构。

3. 基础模型和大语言模型

这与早期的自然语言处理应用中的方法大相径庭,在早期应用中,专门的语言模型被训练来执行特定任务。相反,研究者们在大型语言模型(LLMs)中观察到了许多涌现的能力,即模型未曾被专门训练过的能力。

例如,大型语言模型已被证明能够执行多步算术运算,解开单词字母的混乱顺序,以及识别口语中的冒犯性内容。最近,基于OpenAI的GPT系列大型语言模型构建的热门聊天机器人ChatGPT,已经通过了诸如美国医学执照考试(USMLE)等专业考试!

基础模型通常指的是在广泛数据上训练,能够适应大量下游任务的模型。这些模型通常采用深度神经网络创建,并使用自监督学习在大量无标签数据上进行训练。

cffad250937e6fd4de19d0e79f2ebb35.png

在训练过程中,从语料库中提取文本序列并进行截断。语言模型计算后续缺失单词的概率,然后通过基于梯度下降的优化机制对这些概率进行微调,并反馈给模型以匹配真实值。这一过程在整个文本语料库上反复进行。

然而,大型语言模型(LLMs)通常是在如文本等语言相关数据上进行训练的。但基础模型通常是基于多模态数据训练的,这种数据包含了文本、图像、音频等多种类型。更重要的是,基础模型旨在作为更具体任务的基础或基石:

6430168e5852c680d617f0b5775f2b03.jpeg

基础模型通常通过进一步的训练针对各种下游认知任务进行微调。微调是指采用一个预训练的语言模型,并使用特定数据对其进行不同但相关任务的再训练过程。这一过程也被称为迁移学习。

4. 大语言模型的结构

大多数早期的大型语言模型(LLMs)都是使用带有LSTMs和GRUs的循环神经网络(RNN)模型创建的。然而,它们在进行大规模自然语言处理任务时遇到了挑战。但正是在这种大规模任务上,人们期望大型语言模型能够表现出色。这促使了变换器(Transformers)的诞生!

早期的LLM架构

起初,大型语言模型主要是使用自监督学习算法创建的。自监督学习指的是处理无标签数据以获得有助于下游学习任务的有用表示

自监督学习算法经常使用基于人工神经网络(ANN)的模型。我们可以用多种架构来创建人工神经网络,但在大型语言模型中最广泛使用的架构是循环神经网络(RNN)。

ee541ecb987b1bd3afa27f3dd57e80af.jpeg

现在,循环神经网络(RNNs)能够利用其内部状态来处理可变长度的输入序列。RNN既具有长期记忆也具有短期记忆。RNN的一些变体包括长短时记忆(LSTM)和门控循环单元(GRU)。

LSTM与GRU的问题

使用LSTM单元的RNN训练速度非常慢。此外,对于这类架构,我们需要按顺序或串行地输入数据。这不允许我们并行化处理,也无法充分利用可用的处理器核心。

另一方面,带有GRU的RNN模型虽然训练速度较快,但在较大数据集上的表现却较差。不过,很长一段时间里,LSTMs和GRUs仍然是构建复杂自然语言处理系统的首选。然而,这些模型同样遭受梯度消失问题的困扰:

921154819160061d05185b32110582ba.jpeg

注意力机制

通过在RNN的架构中加入注意力机制,部分解决了RNN存在的问题。在像LSTM这样的循环架构中,信息传播的量是有限的,且保留的信息窗口较短。

然而,有了注意力机制,这个信息窗口可以显著增加。注意力是一种增强输入数据某些部分同时削弱其他部分的技术。其背后的动机是网络应该更多地关注数据的重要部分:

618b736102d30ddc029d9e7632db1fc1.jpeg

注意力和自注意力之间存在微妙的区别,但它们的动机是相同的。注意力机制指的是关注另一个序列的不同部分的能力,而自注意力指的是关注当前序列不同部分的能力。

自注意力允许模型从任意输入序列元素中获取信息。在自然语言处理应用中,这提供了关于远距离词汇的相关信息。因此,模型可以在不需要固定或滑动窗口的情况下捕捉整个序列的依赖关系。

Transformer的出现

带有注意力机制的循环模型在其性能上看到了显著的提升。然而,循环模型本质上难以扩展。但是,自注意力机制很快证明了它的强大,以至于它甚至不需要循环的顺序处理。

2017年Google Brain团队引入的Transformer也许是大型语言模型历史上最重要的转折点之一。变换器是一种采用自注意力机制的深度学习模型,能够一次性处理整个输入:

b82745c5a2dabecd26a0a634f78c9374.jpeg

与早期基于RNN的模型相比,Transformer没有循环结构。只要有足够的训练数据,Transformer架构中的注意力机制单独就能匹敌带注意力的RNN模型的性能。

使用Transformer模型的另一个重要优势在于,它们更加并行化,需要的训练时间显著减少。这正是我们利用现有资源在大量基于文本的数据上构建大型语言模型所需要的优点。

编码器-解码器架构

许多基于人工神经网络的自然语言处理模型都是使用编码器-解码器架构构建的。例如,seq2seq是一系列最初由Google开发的算法家族。它通过使用带有LSTM或GRU的RNN,将一个序列转换成另一个序列。

最初的Transformer模型也采用了编码器-解码器架构。编码器由一系列的编码层组成,它们逐层迭代处理输入。解码器则由解码层组成,对编码器的输出做同样的事情:

8a851d0bfb6b408b1a86f0be3902f1a7.png

每个编码层的作用是生成编码,这些编码包含了输入各部分之间相关性的信息。然后,这些输出编码被传递给下一个编码层作为其输入。每个编码器都包含一个自注意力机制和一个前馈神经网络。

此外,每个解码层接收所有的编码,并利用其所包含的上下文信息来生成输出序列。与编码器类似,每个解码器也包含一个自注意力机制、一个对编码的注意力机制,以及一个前馈神经网络。

83bd8613fbad9b2c0984f73a0b05f9a9.png

5. 预训练

在这个阶段,模型以自监督的方式在大量非结构化文本数据集上进行预训练。预训练的主要挑战是计算成本。

所需GPU内存以存储10亿参数模型:

=> 1参数 -> 4字节(32位浮点数)

=> 10亿参数 -> 4 * 10^9 字节 = 4GB

10亿参数模型所需的GPU内存 = 4GB @ 32位全精度

让我们来计算训练10亿参数模型所需的内存:

Model Parameter --> 4 bytes per parameter  
Gradients --> 4 bytes per parameter  
ADAM Optimizer (2 states) --> 8 bytes per parameter  
Activations and temp memory (variable size) --> 8 bytes per parameter (high-end estimate)  
==> 4 bytes parameter + 20 extra bytes per paramter

因此,训练所需的内存大约是存储模型所需内存的20倍。

存储10亿参数模型所需的内存 = 4GB @ 32位全精度

训练10亿参数模型所需的内存 = 80GB @ 32位全精度

6. 数据并行训练技术

6.1. 分布式数据并行(DDP)

分布式数据并行(DDP)要求模型权重以及训练所需的所有其他附加参数、梯度和优化器状态必须能够装入单个GPU中。如果模型过大,应改用模型分片技术。

54ad2f7fdded7f89e408e0260fd71d4f.png

6.2. 完全分片数据并行(FSDP)

完全分片数据并行(FSDP)通过在GPU之间分配(分片)模型参数、梯度和优化器状态来减少内存需求。

e27a002dd5eb5fb2c88a6a07391db467.png

7. 微调

微调帮助我们从预训练的大型语言模型(LLMs)中获得更多的效益,通过调整模型权重使其更贴合特定的任务或领域。这意味着你可以以更低的成本和延迟,获得比单纯的提示工程更高质量的结果。

d5cde1463d90ba4f234b0bb4e65b5732.png

近年来微调方法的演变发展。同一分支上的模型具有一些共同的特点。模型的垂直位置显示了它们发布时间的时间线。请注意,由于当前环境的限制,我无法提供实际的视觉图表或图像,但这段描述意在解释一个展示微调技术随时间演进的图表。

为何要对LLM进行微调?

相比于提示工程,微调通常在引导大型语言模型(LLM)的行为方面更为有效和高效。通过对模型进行一系列示例训练,你能缩短精心设计的提示,节省宝贵的输入tokens,同时不牺牲质量。此外,你还可以经常使用更小的模型。这反过来意味着降低延迟和推理成本。

例如,与现成的GPT-3.5模型相比,微调过的Llama 7B模型在每token基础上的成本效益更高(大约50倍),并且性能相当。

微调是如何工作的?

正如之前提到的,微调是将一个已训练好的模型调整用于其他任务。其工作原理是通过取原始模型的权重,并根据新任务进行调整。

模型在训练过程中学会执行某些特定任务,例如,GPT-3在一个庞大的数据集上进行了训练,结果它学会了生成故事、诗歌、歌曲、信件以及很多其他内容。人们可以利用GPT-3的这种能力,并将其微调到一个特定任务上,比如以特定方式生成对客户查询的答案。

有不同的方法和技术来微调模型,其中最流行的是迁移学习。迁移学习起源于计算机视觉领域,它是冻结网络初始层的权重,只更新后层权重的过程。这是因为较低层,即靠近输入的层,负责学习训练数据集的一般特征。而较高层,靠近输出的层,学习更具体的信息,这些信息直接与生成正确输出相关联。

下面是微调工作原理的快速可视化示意:请注意,由于当前环境限制,我无法提供实际的视觉图表或图像,但这段描述旨在解释微调如何改变模型的权重以适应新任务。在微调过程中,模型的顶层权重被更新以适应新的输出需求,而底层的通用特征识别能力保持不变。

b8bac5af656c3eec2d6d80f76318a952.gif

7.1. 参数高效微调(PEFT)

PEFT,即参数高效微调,是一系列技术和方法的集合,旨在以最高效的方式对大型模型进行微调,同时不会损失全量微调可能带来的任何性能。这是因为随着模型规模不断增大,如BLOOM拥有惊人的1760亿参数,如果不花费数万美元,几乎不可能对其进行微调。但有时为了获得更好的性能,使用这样大的模型几乎是必要的。这时,PEFT就发挥作用了。它帮助解决在处理超大规模模型时所面临的问题。

这里列举一些PEFT技术:

f4a332e9eec513f24722df1eb579d7ce.png

7.2. 迁移学习

迁移学习是指我们将模型的一部分已学习参数应用于其他任务。这听起来与微调相似,但实际上有所不同。在微调中,我们重新调整模型的所有参数,或者冻结一部分权重,然后调整其余参数。而在迁移学习中,我们从一个模型中使用其部分已学习的参数,并将它们应用于其他网络中。这为我们提供了更多的灵活性,尤其是在我们能做的事情上。例如,在微调时,我们不能改变模型的架构,这在很多方面限制了我们。但使用迁移学习时,我们只使用训练模型的一部分,然后可以将其连接到任何其他具有任意架构的模型上。

迁移学习常出现在自然语言处理(NLP)任务中,特别是在大型语言模型(LLMs)中,人们会使用预训练模型(如T5)的变换器网络的编码器部分,并训练后续的层。这种方法允许利用预训练模型的强大特征提取能力,同时结合新任务的具体需求进行定制化训练,从而在保持高效和灵活性的同时提高性能。

7.3. 适配器

适配器是最早发布的参数高效微调技术之一。研究者表明可以在现有的Transformer架构中添加更多的层,并且只对这些新增的层进行微调,而不是对整个模型进行微调。他们证明了这种方法在与完全微调相比时,能够产生相似的性能。这种方法的核心在于插入的适配器层可以学习到任务特定的转换,而无需修改原有模型的大部分参数,从而实现了高效的微调过程。

00c8e16a94e4475dac87b4ed5b26b686.png

在左边,展示的是加入了适配器层的修改后的Transformer架构。可以看到,适配器层被添加在注意力层和前馈层之后。而在右边,我们可以看到适配器层本身的架构。适配器层采用bottolneck架构,它接收输入并将之缩减到一个较小维度的表示,然后通过非线性激活函数,再将其扩展回输入的维度。这样确保了Transformer堆栈中的下一层能够接收到来自适配器层产生的输出。

作者表明这种微调方法与完全微调相比性能相当,但消耗的计算资源和训练时间要少得多。他们能够在GLUE基准测试上只比完全微调性能的差0.4%,而仅增加了3.6%的参数。这种方法不仅极大地降低了计算成本,还保持了模型的高性能,展现了参数高效微调技术的有效性和潜力。

bde7b7ff2c5efadd60266cc5299053f6.png

7.4. ‍LoRA — 低秩适配器(Low-Rank Adaptation)

LoRA是一种类似于适配器层的策略,但其目标是进一步减少可训练参数的数量。它采取了一种更为严谨的数学方法。LoRA的工作原理是改变了神经网络中可更新参数的训练和更新方式。

从数学角度来解释。我们知道,预训练神经网络的权重矩阵是满秩的,意味着每个权重都是独特的,不能通过组合其他权重得到。但在这篇论文中,作者指出当预训练的语言模型调整到新任务时,权重具有较低的“内在维度”。也就是说,权重可以用一个更小的矩阵来表示,或者说是具有较低的秩。这意味着在反向传播过程中,权重更新矩阵具有较低的秩,因为预训练过程已经捕获了大部分必要信息,而在微调期间仅需进行任务特定的调整。

一个更简单的解释是,在微调过程中,只有非常少的权重会被大量更新,因为大部分的学习发生在神经网络的预训练阶段。LoRA利用这一信息来减少可训练参数的数量。

LoRA通过分解原有的权重矩阵为两个低秩矩阵的乘积,其中一个矩阵代表任务无关的特性,另一个矩阵则捕捉任务相关的调整。这样,LoRA仅需要训练这两个低秩矩阵,从而大大减少了参数的数量,同时保持了模型在新任务上的性能。这种方法在保证模型效果的同时,显著降低了计算成本和训练时间。

e8045d4680673c76566aec85ddbe201b.png

以GPT-3 175B为例,LoRA研究团队证明了即使完整矩阵的秩(即d)高达12,288,一个非常低的秩(即图1中的r可以是一或二)也足以满足需求,这使得LoRA在存储和计算上都非常高效。

上图展示了矩阵A[d X r]和B[r X k]的乘积将是[d X k],而我们可以变化r的值。一个非常小的r会导致更少的参数需要调整。虽然这会缩短训练时间,但也可能导致信息丢失,随着r变得更小,模型性能可能会下降。然而,即使在低秩阶下,LoRA的表现也与完全训练的模型一样好,甚至更好。

使用HuggingFace进行LoRA微调

要使用HuggingFace实施LoRA微调,你需要使用PEFT库将LoRA适配器注入模型中,并将它们用作更新矩阵。这允许你以参数高效的方式微调模型,只需调整LoRA适配器中的参数,而不是整个模型。HuggingFace的PEFT库简化了LoRA微调的过程,使得即使是大型预训练模型也能以较少的计算资源和时间成本进行高效微调。

from transformers import AutoModelForCausalLM
from peft import get_peft_config, get_peft_model, LoraConfig, TaskType

model = AutoModelForCausalLM.from_pretrained(model_name_or_path, device_map="auto", trust_remote_code=True) # load the model
peft_config = LoraConfig(
    task_type=TaskType.CAUSAL_LM, inference_mode=False, r=32, lora_alpha=16, lora_dropout=0.1,
    target_modules=['query_key_value'] # optional, you can target specific layers using this
) # create LoRA config for the finetuning

model = get_peft_model(model, peft_config) # create a model ready for LoRA finetuning
model.print_trainable_parameters() 
# trainable params: 9,437,184 || all params: 6,931,162,432 || trainable%: 0.13615586263611604‍

完成以上步骤后,你可以像平常一样训练模型。但这一次,由于只需要调整LoRA适配器中的参数,所以会大大减少时间和计算资源的消耗。

LoRA的高效性

论文中的作者表明,LoRA仅使用总可训练参数的2%就能超越完全微调的效果。

f90fa7afa402e85870c1f9572184d542.png

至于训练的参数数量,我们可以通过秩r参数来很大程度上控制它。例如,假设权重更新矩阵有100,000个参数,A是200,B是500。权重更新矩阵可以分解为维度更低的小矩阵,A200 x 3B3 x 500。这给我们带来了200 x 3 + 3 x 500 = 2100个可训练参数,这只是总参数数量的2.1%。我们还可以进一步减少参数数量,因为我们可以选择只对特定层应用LoRA。

由于训练和应用的参数数量远远小于实际模型,文件可以小至8MB。这使得加载、应用和迁移所学模型变得更加容易和快速。

如果你想了解更多并深入探讨这个主题,可以阅读LoRA论文。

LoRA在稳定扩散(Stable Diffusion)中的应用

LoRA最有趣的用例之一可以在图像生成应用中体现。图像固有的一种风格是可以直观看到的。现在,用户不再需要训练庞大的模型来从模型中获取特定风格的图像,而是可以直接训练LoRA权重,并使用像Dreambooth这样的技术来实现高质量图像,同时还具有很大的定制性。

LoRA权重也可以与其他LoRA权重结合,并以加权组合的方式使用,生成携带多种风格的图像。你可以在网上找到大量的LoRA适配器,并在CivitAI上将它们加载到你的模型中。

在图像生成领域,LoRA的应用不仅简化了模型训练流程,还极大地增强了用户的创造性和个性化能力。通过微调LoRA权重,用户可以根据自己的需求和偏好生成独特风格的图像,这在艺术创作、设计和娱乐行业有着广阔的应用前景。

bd2d1495dea6739dd8fe3dee55f37873.png

7.5. QLoRA

01fd93702bb6370223d287179e252b71.png

它与LoRA有何不同

  • 它是一个4位的Transformer。

  • QLoRA是一种微调技术,它结合了高精度计算技术和低精度存储方法。这有助于保持模型尺寸小巧,同时确保模型仍具有高性能和准确性。

  • QLoRA使用LoRA作为一种辅助手段,用于修正量化过程中引入的误差。

QLoRA的工作原理

  • QLoRA通过引入三个新概念来帮助在保持相同质量性能的同时减少内存占用。这些概念是4位标准浮点数双重量化分页优化器

4位标准浮点数(NF4)

  • 4位标准浮点数是一种新的数据类型,是维持16位性能水平的关键成分。其主要特性如下:数据类型中的任何位组合,例如0011或0101,都会从输入张量中分配相同数量的元素。

  • 4位量化权重和PEFT,以32位精度训练注入的适配器权重(LoRA)。

  • QLoRA有一个存储数据类型(NF4)和一个计算数据类型(16位BrainFloat)。

  • 我们将存储数据类型反量化为计算数据类型,以执行前向和后向传播,但我们仅计算使用16位BrainFloat的LoRA参数的权重梯度。

1. 标准化:首先将模型的权重标准化,使其具有零均值和单位方差。这确保了权重围绕零分布,并处于一定范围内。

2. 量化:然后将标准化的权重量化为4位。这涉及到将原始高精度权重映射到一组较小的低精度值。在NF4的情况下,量化级别在标准化权重的范围内均匀间隔。

3. 反量化:在前向传播和反向传播期间,将量化后的权重反量化回全精度。这是通过将4位量化值映回其原始范围完成的。反量化的权重用于计算中,但在内存中是以4位量化形式存储的。

通过以上步骤,QLoRA能够在保持模型性能的同时显著减少内存占用和计算资源需求,特别适合于处理大尺寸模型和有限计算资源的情况。

609daa98ce42e1fc49c83f37dfbdc231.png

在量化过程中,数据被分为“桶”或“箱”,其中的数据被量化。例如,数字2和3都落入了相同的量化区间,也就是2。这一量化过程通过“四舍五入”到最近的量化区间,允许你使用更少的数值来表示数据。

反量化

  • 双重量化是指在4位NF量化过程中对所使用的量化常数进行量化的独特实践。虽然乍看之下可能不起眼,但根据相关研究论文的亮点,这种方法有可能为每个参数平均节省0.5位。这种优化在QLoRA的背景下尤其有益,该技术使用Block-wise k-bit Quantization。与集体量化所有权重不同,这种方法涉及将权重分割成不同的块或片段,这些块或片段独立地进行量化。

通过双重量化,QLoRA进一步压缩了模型的存储需求,同时保持了模型的预测精度。这是因为,通过量化量化常数,QLoRA有效地减少了用于表示权重的比特数,而不会显著影响模型的性能。这种方法尤其适用于处理大型模型,因为它允许在有限的计算资源下运行更复杂的模型,同时保持较高的预测能力。

6940bec10a116f37a408e4a655349065.png

  • 块量化方法导致生成多个量化常数。有趣的是,这些常数可以进行第二轮量化,为额外的空间节省提供了机会。由于量化常数的数量有限,这种策略依然有效,缓解了与该过程相关的计算和存储需求。

分页优化器

  • 正如前面所示,分位数量化涉及创建桶或箱来覆盖广泛的数值。这一过程导致多个不同的数字被映射到同一个桶中,例如,在量化过程中,2和3都被转化为3。因此,权重的反量化会引入1的误差。

  • 在神经网络更广泛的权重分布中可视化这些误差揭示了分位数量化固有的挑战。这种差异强调了为什么QLoRA更像是一种微调机制而非独立的量化策略,尽管它适用于4位推理。在使用QLoRA进行微调时,LoRA调优机制开始发挥作用,涉及创建两个较小的权重更新矩阵。这些以较高精度格式(如brain float 16或float 16)维护的矩阵随后被用来更新神经网络的权重。

通过这种机制,QLoRA能够在保持模型性能的同时,显著降低模型大小和计算成本,特别是在微调大型预训练模型时。分页优化器和双重量化等技术确保了在低精度表示下,模型仍能保持良好的泛化能力和预测准确性。

d315f0db25591498db24966df7211779.png

  • 值得注意的是,在整个反向传播和前向传播过程中,网络的权重会进行反量化,确保实际训练是在更高精度的格式中进行的。虽然存储仍然是低精度的,但这种刻意的选择引入了量化误差。然而,模型训练过程本身展现出能够适应和缓解量化过程中固有不精确性问题的能力。实质上,高精度的LoRA训练方法帮助模型学习并主动减少量化误差。

使用HuggingFace进行QLoRA微调

要使用HuggingFace进行QLoRA微调,你需要安装BitsandBytes库和PEFT库。BitsandBytes库负责4位量化以及整个低精度存储和高精度计算的部分。PEFT库将用于LoRA微调部分。

通过结合使用这两个库,你可以在HuggingFace的环境中轻松地应用QLoRA技术,对大型预训练模型进行微调。BitsandBytes库处理量化和计算精度的问题,而PEFT库专注于LoRA的微调,两者的结合确保了在降低模型存储需求的同时,能够保持甚至提升模型的性能。这种方式特别适合于那些需要处理大量数据和复杂模型,但受限于计算资源和存储空间的应用场景。

import torch
from peft import prepare_model_for_kbit_training, LoraConfig, get_peft_model
from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig

model_id = "EleutherAI/gpt-neox-20b"
bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_use_double_quant=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.bfloat16
) 

# setup bits and bytes config
model = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=bnb_config, device_map={"":0})

model.gradient_checkpointing_enable()

model = prepare_model_for_kbit_training(model) # prepares the whole model for kbit training
config = LoraConfig(
    r=8, 
    lora_alpha=32, 
    target_modules=["query_key_value"], 
    lora_dropout=0.05, 
    bias="none", 
    task_type="CAUSAL_LM"
)
model = get_peft_model(model, config) # Now you get a model ready for QLoRA training

然后,你可以再次切换到使用HF Trainer的常规训练流程。

7.6. IA3

IA3(通过抑制和放大内部激活进行融合的适配器)是一种基于适配器的技术,它在某种程度上类似于LoRA。作者的目标是复制ICL(即境学习或Few-Shot提示)的优点,同时避免伴随而来的问题。ICL在成本和推理方面可能会变得复杂,因为它需要通过示例提示模型。较长的提示需要更多的时间和计算来处理。但ICL可能是开始使用模型的最简单方式。

IA3通过引入重缩放向量来针对模型的激活。总共引入了3个向量,lv, ik 和 lff。这些向量分别针对注意力层中的value,key以及密集层中的非线性层。这些向量与模型中的默认值逐元素相乘。一旦注入,这些参数就会在训练过程中被学习,而模型的其余部分保持冻结。这些学习到的向量本质上是对目标预训练模型权重进行重新缩放或优化,以适应手头的任务。

通过这种方式,IA3能够在保持模型大部分固定的同时,通过调整关键组件的激活,有效地对模型进行微调。这种方法不仅减少了计算成本,还提高了模型在特定任务上的性能,尤其是对于那些希望利用预训练模型强大能力但又受限于计算资源的场景来说。IA3提供了一个灵活且高效的解决方案,使模型能够快速适应新任务,而无需从头开始训练。

03ce0793d0ef1c733fc96cbc3a513e42.png

迄今为止,这看起来像是基本的适配器类型的PEFT方法。但这并非全部。作者还使用了三种损失项来增强学习过程。这三种损失分别是LLM, LUL,LLNLLM是标准的交叉熵损失,它增加了生成正确响应的可能性。然后是LUL,即Unlikelihood Loss。这个损失项通过等级分类减少了错误输出的概率。最后,我们有LLN,这是一种长度归一化损失,它将长度归一化的所有输出选择的log概率的softmax交叉熵损失应用到模型上。在这里使用多种损失是为了确保模型更快、更好地学习。因为我们试图使用少量示例进行学习,这些损失项是必要的。

现在,让我们讨论IA3中两个非常重要的概念:等级分类和长度归一化。

在等级分类中,模型被要求通过其正确性对一组响应进行排名。这是通过计算潜在响应的概率得分来完成的。然后使用LUL来减少错误响应的概率,从而增加正确响应的概率。但是,使用等级分类,我们会遇到一个关键问题,那就是响应的标记越少,排名越高,这是由概率的运作方式决定的。较少的生成标记确保了更高的概率,因为每个生成标记的概率都<1。为了解决这个问题,作者建议将响应的得分除以响应中的标记数。这样做将对得分进行归一化。这里需要注意的一个非常重要的事情是,归一化是在对数概率上进行的,而不是原始概率。对数概率是介于0到1之间的负数,。

示例使用

对于序列分类任务,可以按照以下方式初始化Llama模型的IA3配置:

peft_config = IA3Config(
    task_type=TaskType.SEQ_CLS, target_modules=["k_proj", "v_proj", "down_proj"], feedforward_modules=["down_proj"]
)

7.7. P-Tuning

P-tuning方法旨在优化传递给模型的提示的表示。在P-Tuning论文中,作者强调了在处理大型语言模型时,提示工程是一项非常强大的技术。P-tuning方法在此基础上构建,试图进一步提高优质提示的有效性。

P-tuning通过为你的提示创建一个小的编码网络来工作,该网络为你的传递提示创建一个软提示。要使用P-tuning调整你的LLM,你应该创建一个提示模板来表示你的提示。以及一个上下文x,它在模板中用于获取标签y。这是论文中提到的方法。用于提示模板的tokens是可训练和可学习的参数,这些被称为 pseudo tokens。我们还添加了一个提示编码器,它帮助我们将pseudo tokens更新到手头的具体任务。提示编码器通常是一个双向LSTM网络,它学习模型的提示最优表示,然后将表示传递给模型。LSTM网络附加到原始模型上。这里只训练编码网络和pseudo tokens,原始网络的权重不受影响。一旦训练完成,LSTM头部就被丢弃,因为我们已经有了可以直接使用的hi

简而言之,提示编码器仅改变传递提示的嵌入,以更好地表示任务,其他一切保持不变。通过这种方式,P-tuning能够在不改变模型结构的情况下,优化模型对特定任务的理解和处理能力,从而提高模型的性能和适应性。

ae907924dd6252e568f19391fc5dd444.png

7.8. ‍Prefix Tuning

Prefix tuning可以被认为是P-tuning的升级版。P-tuning的作者们发表了一篇关于P-Tuning V-2的论文,旨在解决P-tuning存在的问题。在这篇论文中,他们实现了在这篇论文中引入的Prefix tuning。虽然Prefix tuning和P-tuning之间没有太大的区别,但它们仍然可能导致不同的结果。让我们深入了解一下。

6b67af3fb73312bf36702ecb8a54f5b4.png

在P-Tuning中,我们仅在输入嵌入中添加了可学习参数,但在前缀调优中,我们将它们添加到了网络的所有层。这确保了模型本身对其正在微调的任务有更深入的了解。我们在提示和Transformer层的每一层激活中附加可学习参数。与P-Tuning的不同之处在于,我们不是完全修改提示嵌入,而是在每一层提示的开始处仅添加非常少的可学习参数。

下面是一个视觉上的解释:

cc13b151d590c39e9bb23406328c066f.png

在Transformer的每一层中,我们将带有可学习参数的软提示与输入拼接在一起。这些可学习参数是通过一个非常小的多层感知器(MLP),只有2个全连接层来进行调整的。这样做的原因是,作者在论文中指出,直接更新这些提示token对学习率和初始化非常敏感。软提示虽然增加了可训练参数的数量,但也实质上提升了模型的学习能力。在后期,我们可以舍弃MLP或全连接层,因为我们只关心软提示,这些将在推理时附加到输入序列上,以引导模型的行为。

8959963e05bbce3fb4ab5ed9576d3412.png

‍7.9. Prompt Tuning (不是提示工程)

Prompt tuning是最早基于仅使用软提示进行微调的概念建立的论文之一。Prompt tuning是一个非常简单且易于实现的想法。它涉及在输入前添加一个特定的提示,并使用虚拟tokens或针对该特定提示的新可训练tokens。这些新的虚拟tokens可以在过程中进行微调,以学习提示的更好表示。这意味着模型被调整以更好地理解提示。以下是来自论文的prompt tuning与完全微调的比较:

0d77033906a26dcee88e5b9ae67473b1.png

在这里,你可以看到,如果我们想让模型用于多个任务,完全模型微调需要存在模型的多个副本。但使用Prompt Tuning,你只需要存储学习到的提示token的虚拟token。所以,例如,如果你使用一个像“Classify this tweet: {tweet}”这样的提示,目标将是学习提示的新、更好的嵌入。而在推理过程中,只有这些新嵌入会被用来生成输出。这使得模型能够调整提示,帮助自己在推理时生成更好的输出。

Prompt Tuning的效率

使用Prompt Tuning的最大优势是学习参数的小尺寸。文件可以是KB级别的。由于我们可以确定新token的维度大小和要使用的参数数量,我们可以很好地控制我们将要学习的参数数量。在论文中,作者展示了即使使用非常少的可训练token,该方法的表现也非常好。并且随着使用更大模型,性能只会提升。

1dba7b003255ace4828b52abce318f33.png

另一个巨大优势是我们可以无需任何改动就使用同一模型处理多个任务,因为唯一被更新的是提示令牌的嵌入。这意味着,只要模型足够大且足够复杂以执行这些任务,你就可以使用同一模型进行推文分类任务和语言生成任务,而无需对模型本身进行任何更改。但一个重大限制是模型本身并没有学到任何新东西。这是一个纯粹的提示优化任务。这意味着如果模型从未在情感分类数据集上进行过训练,那么提示调优可能不会带来任何帮助。非常重要的一点是,这种方法优化的是提示,而不是模型。因此,如果你无法手工制作一个能相对较好地完成任务的硬提示,尝试使用提示优化技术来优化软提示就没有意义了。

硬提示与软提示

硬提示可以被视为定义明确、静态的提示,或者最多是一个模板。生成式AI应用也可以拥有多个可用的提示模板。

硬提示是手动精心制作的文字提示,具有离散的输入token。~ HuggingFace

提示模板允许提示被存储重复使用共享编程。生成式提示可以被整合进程序中,用于编程、存储和重复使用。

软提示是在提示调优的过程中创建的。

与硬提示不同,软提示不能以文本形式查看和编辑。提示由嵌入组成,即一系列数字,这些数字从更大的模型中获取知识。

因此,一个缺点是软提示缺乏可解释性。AI发现了与特定任务相关的提示,但无法解释为何选择了那些嵌入。就像深度学习模型本身一样,软提示是不透明的。

软提示充当了额外训练数据的替代品。在训练数据有限或收集成本高昂的情况下,软提示可以提供一种有效的方法来增强模型的性能,通过优化模型对现有数据的理解和利用。软提示的使用,尤其是与提示调优技术结合时,可以显著改善模型在特定任务上的表现,而无需大量额外的标注数据。

ff50b66559d81af0477997e170c4829b.png

7.10. LoRA vs Prompt Tuning

现在我们已经探讨了各种PEFT技术。接下来的问题是应该使用像Adapter和LoRA这样的加性技术,还是使用基于提示的技术,如P-Tuning和前缀调优。

在比较LoRA与P-Tuning和前缀调优时,可以说在充分利用模型潜力方面,LoRA无疑是最佳策略。但是否最高效则取决于你的具体需求。如果你想在与模型原本训练任务截然不同的任务上训练模型,毫无疑问,LoRA是最有效的模型调优策略。但如果你的任务在很大程度上已经被模型理解,而挑战在于如何正确地提示模型,那么你应该使用基于提示的调优技术。基于提示的调优技术不会在模型中修改太多参数,而是主要集中在传递给模型的提示上。

值得注意的一点是,LoRA将权重更新矩阵分解为更小的秩矩阵,并使用它们来更新模型的权重。尽管可训练参数较少,但LoRA会更新神经网络目标部分的所有参数。而在基于提示的调优技术中,会在模型中添加一些可训练参数,这通常有助于模型调整和更好地理解任务,但并不利于模型学习新属性。

选择哪种技术取决于你的目标和约束条件。LoRA适合于需要模型在新任务上做出较大调整的情况,而基于提示的技术更适合于模型已经具备基本能力,只需通过优化提示来提升性能的场景。每种技术都有其适用范围和优势,正确选择将对模型性能产生显著影响。

7.11. LoRA和PEFT与完全微调的对比

PEFT(Parameter-Efficient Fine-Tuning)作为一种替代完全微调的方案,已经在多项任务中展示出与完全微调相当甚至更好的效果。然而,当你要使模型适应的任务与模型预训练时接触的任务完全不同,PEFT可能就显得力不从心了。在这种情况下,有限的可训练参数可能会导致显著的问题。

例如,如果我们试图使用基于文本的模型,如LLaMA或Alpaca,来构建一个代码生成模型,我们可能应该考虑对整个模型进行微调,而不是仅仅使用LoRA来调整模型。这是因为任务与模型已有知识和训练背景相差甚远。另一个类似的例子是训练一个仅理解英语的模型来生成尼泊尔语文本。这类任务要求模型学习全新的语言结构和语法,这远远超出了PEFT技术通过少量参数调整所能达到的效果。

8. LLM推理

在使用大型语言模型(LLM)进行推理时,我们经常可以通过配置不同的参数来精细调整其输出和性能。以下是一些关键参数的详细说明:

1. Top-k 采样:

  • 每一步只采样可能性最高的前k个词汇,促进多样性并防止重复。更高的k值会导致更多样化的输出,但可能连贯性稍差。

2. 温度:

  • 影响下一个可能词汇的概率分布,控制随机性和“创造性”。

  • 较低的温度生成更可能但可能重复的文本,而较高的温度鼓励多样性和不可预测的输出。

3. Top-P(核)采样:

  • Top-P 或核采样将词汇选择限制在累积概率质量达到阈值值的词汇子集中。它有助于控制生成输出的多样性。

4. 最大长度:

  • 设置LLM生成的词汇最大数量,防止输出过长。

5. 上下文提示:

  • 通过提供特定的上下文提示或输入,你可以引导模型生成与该上下文一致的文本。这有助于确保生成的输出在给定的上下文中是相关和连贯的。

6. 重复惩罚:

  • 对含有重复n-gram的序列进行惩罚,鼓励多样性和原创性。

7. 采样:

  • 在确定性(贪婪)和基于随机采样的生成之间进行选择。贪婪模式在每一步选择最可能的词汇,而随机采样引入随机性。

  • 贪婪模式优先考虑准确性,而随机采样鼓励多样性和创造性。

  • 束搜索: 维持多个潜在序列,每一步扩展最有前景的序列,与top-k采样相比,旨在获得更连贯和更准确的输出。

通过调整这些参数,用户可以根据具体需求定制模型的输出,无论是追求高度准确的文本生成,还是寻求更具创造性和多样性的结果。这些参数的灵活运用是大型语言模型能够适应广泛应用的关键所在。

53bd6159f9c36c1df44793b21fbc1dfd.png

11c6572e3382c617d70151cffe0169c6.png

9. 提示工程

Prompt Engineering,也被称作In-Context Prompting,指的是在不更新模型权重的情况下,通过特定方法与大型语言模型(LLM)交流,以引导其行为达到期望结果的技巧。这是一门经验科学,不同的模型对提示工程方法的反应可能大相径庭,因此需要大量的实验和直觉判断。

什么是提示?

我们与大型语言模型交互时使用的自然语言指令被称为提示。构建这些提示的过程就是提示工程

提示可以被视为一种桥梁,它连接了人类的意图和模型的理解。一个好的提示能够清晰地传达任务的细节和上下文,帮助模型生成符合期望的响应。提示工程不仅涉及到如何构造一个有效的指令,还包括如何组织和呈现信息,以便模型能够更好地理解和处理。

提示工程的关键在于理解和利用模型的工作原理。例如,通过在提示中包含类似任务的例子,可以激活模型的类比思维,使其更准确地完成任务。此外,通过调整提示的结构、语气和具体词汇,可以影响模型生成的输出类型和风格。

在实践中,提示工程往往需要经过多次迭代和测试,以找到最适合特定模型和任务的提示形式。这包括试验不同的指令框架、调整词汇选择,以及探索如何通过上下文信息来引导模型的响应。通过不断优化提示,可以显著提高模型的性能和响应质量,使其更贴合用户的需求和期望。

9f4b8c926c6a63797f9e5b96d7578f6c.png

大型语言模型(LLM)根据提示中给出的指令进行推理并完成任务的过程被称为In-Context Learning(在情境中学习)。

少量样本提示

大型语言模型(LLM)在没有任何示例的情况下,能够根据提示中的指令作出响应的能力被称为Zero-Shot Learning(零样本学习)。

当提供了一个示例时,这种情况被称为One-Shot Learning(一样本学习)。

如果提供了多个示例,则称为Few-Shot Learning(少量样本学习)。

Context Window,即大型语言模型能够提供和推理的最大令牌数量,在Zero/One/Few Shot Learning中起着关键作用。这个窗口大小决定了模型能够处理的上下文信息的范围,直接影响了模型在不同学习模式下的表现。

dac7d35189f7575f3ff4dd0c57bcdeb7.png

9.1. 思维链提示(Chain-of-Thought (CoT) Prompting)

130b1f46d88538c3269624f5cd075046.png

思维链(Chain-of-Thought,CoT)提示(Wei et al. 2022) 是一种生成一系列短句的方法,这些短句逐步描述推理逻辑,形成所谓的“推理链”或“理由”,最终导向最终答案。CoT提示的主要优势在于,当使用大型模型(例如,参数量超过500亿)处理复杂推理任务时更为明显。对于简单任务,CoT提示的益处则相对较小。

9.2. 程序辅助语言模型

Gao et al., (2022) 提出了一种方法,利用大型语言模型(LLM)阅读自然语言问题,并生成程序作为中间推理步骤。这种方法被称为程序辅助语言模型(Program-Aided Language Models,PAL),它与思维链(Chain-of-Thought,CoT)提示的区别在于,PAL不是使用自由格式的文本来获得解决方案,而是将解决方案的步骤搬到了程序运行时环境,如Python解释器。

a7599c19886f1bdfb07a99c949dfc17c.png

9.3. ReAct Prompting

ReAct 灵感来源于“行动”与“推理”之间的协同作用,这种作用使得人类能够学习新任务并做出决策或推理。

CoT(Chain of Thought)无法访问外部世界或无法更新其知识,这可能导致幻觉和错误传播等问题。

ReAct 是一种结合了推理和行动的通用范式,与大型语言模型(LLMs)相结合。ReAct 激励 LLMs 为任务生成言语推理轨迹和行动。这使得系统能够进行动态推理,以创建、维持和调整行动计划,同时还能与外部环境(例如,维基百科)进行互动,将额外信息融入推理过程。下图展示了一个 ReAct 的示例,以及涉及的不同步骤,用于执行问题回答。

b19332ec576e57351b51f8b2691fb657.png

10. 模型优化技术

a046c36fbfb5945989b5995bcdfca135.png

b13ac9504e4514a524e8a86d00544ac9.png

10.1. 量化

模型量化是一种技术,用于通过修改大型神经网络(包括大型语言模型(LLMs))的权重精度来减小其规模。大型语言模型的量化得以实现,这得益于实证结果表明,虽然神经网络训练和推理的一些操作必须利用高精度,但在某些情况下,可以使用显著较低的精度(例如 float16),从而减少模型的整体大小,使其能够在功能较弱的硬件上运行,同时能力与准确性可接受地下降

4bd65592318f38a16446605aeca4a12d.png

70b9188b4db49685b9f43b62a5c64fdd.png

通常来说,在神经网络中使用高精度与更高的准确性和更稳定的训练相关。使用高精度也意味着更高的计算成本,因为它需要更多的硬件更昂贵的硬件。谷歌和英伟达进行的研究主要关注在某些神经网络操作中使用较低精度的可能性,结果显示,较低精度可以用于一些训练和推理操作。

除了研究之外,这两家公司还开发了硬件和框架来支持较低精度的操作。例如,NVIDIA 的 T4 加速器是具有 Tensor Cores 技术的低精度 GPU,其效率远高于 K80。谷歌的 TPU 引入了 bfloat16 的概念,这是一种针对神经网络优化的特殊原始数据类型。较低精度的基本理念是神经网络并不总是需要使用 64 位浮点数的全部范围,以允许它们表现良好。

1cb387c27937970474db9c8d1b665dee.png

随着神经网络日益庞大,利用较低精度的重要性对使用这些网络的能力产生了重大影响。对于大型语言模型(LLMs),这一点变得更加关键。

作为参考,英伟达的A100 GPU在其最先进版本中拥有80GB的内存。从下表我们可以看到,LLama2-70B模型大约需要138GB的内存,这意味着要承载它,我们需要多块A100 GPU。将模型分布在多块GPU上意味着不仅要支付更多的GPU费用,还要承担额外的基础设施开销。相反,量化的版本大约只需要40GB的内存,因此它可以轻松装入一块A100中,显著降低了推理的成本。这个例子还没有提及,在单一A100内,使用量化模型会导致大部分单独计算操作的执行速度更快。

de5a91846bd9bf7d0e392b238285bad7.png

量化如何缩小模型体积?

量化通过减少表示每个模型权重所需的比特数来大幅减小模型的大小。一个典型场景是从FP16(16位浮点数)减少到INT4(4位整数)。这使得模型能够在更便宜的硬件上运行,或者以更高的速度运行。通过降低权重的精度,大型语言模型(LLM)的整体质量也可能受到一定影响

研究表明,这种影响因所使用的技术而异,并且较大的模型受精度变化的影响较小。对于更大的模型(超过约700亿参数),即使转换为4位,它们也能保持其性能,有些技术如NF4表明对它们的性能没有影响。因此,对于这些大模型而言,4位似乎是在性能与大小/速度之间最好的折衷方案,而对于较小的模型,6位或8位可能更为合适。

大型语言模型量化类型

可以将获得量化模型的技术分为两类:

  1. 后训练量化(PTQ):将已经训练好的模型的权重转换为更低的精度,无需重新训练。尽管PTQ实施简单,但由于权重值精度的损失,可能会轻微降低模型的性能。

  2. 量化感知训练(QAT):与PTQ不同,QAT在训练阶段就整合了权重转换的过程。这通常能带来更好的模型性能,但计算需求更高。一个广泛使用的QAT技术是QLoRA。

2e8752ae88a0e5875cb2bad3b838426d.jpeg

本篇帖子将专注于后训练量化(PTQ)策略及其之间的核心区别。

大量化模型与小非量化模型对比

认识到降低精度会减少模型的准确性,你是应该选择一个较小的全精度模型,还是一个具有相当推理成本的较大量化模型?尽管理想的选择可能因多种因素而异,Meta近期的研究提供了一些深刻的指导原则。

我们原本预期降低精度会导致准确性下降,但Meta的研究人员证明,在某些情况下,量化模型不仅展现出更优的性能,还允许减少延迟并提高吞吐量。同样的趋势在比较8位130亿参数模型与16位70亿参数模型时也能观察到。实质上,当比较具有相似推理成本的模型时,较大的量化模型可以胜过它们较小的、非量化版本。这一优势在更大规模的网络中更为明显,因为它们在量化时表现出的质量损失更小。

在哪里能找到已量化的模型?

幸运的是,可以在Hugging Face Hub找到许多使用GPTQ(部分兼容ExLLama)、NF4GGML已经量化的模型版本。快速浏览一下就会发现,这些模型中的很大一部分是由TheBloke量化的,他是LLM社区中一个有影响力且受尊敬的人物。该用户发布了多种量化方法的模型,因此人们可以根据每个特定用例选择最适合的模型。

为了轻松地试验这些模型,打开Google Colab,并确保你的运行环境设置为GPU(有一个免费的GPU可供使用)。首先安装由Hugging Face维护的transformers库和所有必要的库。因为我们将会使用使用Auto-GPTQ量化的模型,相应的库也将被需要:

!pip install transformers
!pip install accelerate

# Due to using GPTQ
!pip install optimum
!pip install auto-gptq

你可能需要重启运行环境,以便让安装的库生效。然后,只需加载已经量化的模型。在这个例子中,我们将加载一个之前使用Auto-GPTQ量化的Llama-2 7B Chat模型,如下所示:

from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

model_id = "TheBloke/Llama-2-7b-Chat-GPTQ"
tokenizer = AutoTokenizer.from_pretrained(model_id, torch_dtype=torch.float16, device_map="auto")
model = AutoModelForCausalLM.from_pretrained(model_id, torch_dtype=torch.float16, device_map="auto")

量化大型语言模型

正如前面提到的,Hugging Face Hub上已经存在大量的量化模型,这在很多情况下消除了个人手动压缩模型的需求。然而,在某些情况下,你可能想要使用尚未量化的模型,或者你可能想要自己压缩模型。这可以通过使用针对你特定领域定制的数据集来实现。

为了演示如何轻松地使用AutoGPTQ和Transformers库来量化模型,我们采用了一种Optimum中简化的AutoGPTQ接口——Optimum是Hugging Face针对训练和推理优化的解决方案:

from transformers import AutoModelForCausalLM, AutoTokenizer, GPTQConfig

model_id = "facebook/opt-125m"

tokenizer = AutoTokenizer.from_pretrained(model_id)

quantization_config = GPTQConfig(bits=4, dataset = "c4", tokenizer=tokenizer)

model = AutoModelForCausalLM.from_pretrained(model_id, device_map="auto", quantization_config=quantization_config)

模型压缩可能耗时较长。例如,一个1750亿参数的模型至少需要4小时的GPU时间,特别是在使用像“c4”这样庞大的数据集时。值得注意的是,量化过程中的比特数或数据集可以通过GPTQConfig的参数轻易调整。改变数据集会影响量化的方式,因此如果可能的话,使用与推理中见到的数据类似的数据集,以最大化性能。

量化技术

6fbd620ae229b988289717df28f78333.png

在模型量化领域,出现了几种前沿的方法。让我们深入了解一下其中一些显著的技术:

  1. GPTQ: 包括AutoGPTQ、ExLlama和GPTQ-for-LLaMa等实现选项,这种方法主要侧重于GPU执行。

  2. NF4: 它在bitsandbytes库中实现,与Hugging Face的transformers库紧密合作。它主要被QLoRA方法使用,以4位精度加载模型进行微调。

  3. GGML: 这个C库与llama.cpp库紧密配合。它为LLMs设计了一种独特的二进制格式,允许快速加载和易于读取。值得注意的是,它最近转向GGUF格式,确保了未来的可扩展性和兼容性。

许多量化库支持多种不同的量化策略(例如4位、5位和8位量化),每种策略在效率和性能之间提供了不同的权衡。

10.2. 蒸馏

3bbff72e12b6fd59ae7ad7bb83271c5b.png

知识蒸馏KD;Hinton等人,2015,Gou等人,2020)是一种简单有效的方法,通过将预训练的昂贵模型(“教师模型”)的技能转移到更小、更经济的模型(“学生模型”)上来加速推理。除了要求学生模型与教师模型有匹配的输出空间以构建适当的训练目标外,对学生架构的构建并没有太多限制。

18cb0ac4f354f2f99cbe23a7c8049410.png

教师模型已经在训练数据上进行了微调。因此,概率分布很可能与真实数据非常接近,且在tokens上的变化不会太多。

所以,当温度 > 1时,概率分布变得更宽泛。T > 1 => 教师模型的输出 -> 软标签,学生模型的输出 -> 软预测 T = 1 => 教师模型的输出 -> 硬标签,学生模型的输出 -> 硬预测

蒸馏对于生成解码模型并不是特别有效。它更适合于只有编码器的模型,比如BERT,这类模型具有大量的表示冗余。

10.3. 剪枝

网络剪枝是通过修剪模型中不重要的权重或连接来减小模型大小,同时保持模型的容量。剪枝可能需要重新训练,也可能不需要。剪枝可以是无结构的有结构的

  • 无结构剪枝允许删除任何权重或连接,因此不会保留原始网络架构。无结构剪枝通常与现代硬件不太兼容,也不会导致实际的推理加速。

  • 有结构剪枝旨在保持密集矩阵乘法的形式,其中某些元素为零。它们可能需要遵循一定的模式限制,以适应硬件内核支持的特性。在这里,我们专注于有结构剪枝,以在Transformer模型中实现高稀疏度

构建剪枝网络的一般工作流程包含三个步骤:

  1. 训练一个稠密网络直到收敛;

  2. 剪枝网络以移除不必要的结构;

  3. 可选地,重新训练网络以使用新的权重恢复性能。

通过网络剪枝在稠密模型中发现稀疏结构的想法,同时稀疏网络仍能保持相似性能,源于彩票假设LTH):随机初始化的、稠密的、前馈网络包含了一组子网络,其中只有一部分(稀疏网络)是“中奖票”,当孤立训练时,可以达到最优性能。

在我们的下一篇博客中,我们将继续讨论大型语言模型(LLM)的评估。

结论

在这篇博文中,我们探讨了检索增强生成(RAG)应用中的文本生成部分,重点在于大型语言模型(LLM)的使用。它涵盖了语言建模、预训练挑战、量化技术、分布式训练方法以及LLM的微调。讨论了Parameter Efficient Fine-Tuning(PEFT)技术,包括Adapters、LoRA和QLoRA。介绍了提示策略、模型压缩方法如剪枝和量化,以及各种量化技术(GPTQ、NF4、GGML)。博文以对模型尺寸缩减的蒸馏和剪枝的见解结束。

2c0138b265d2bca7cf4b90842d830c3d.png

—END—

英文原文:https://medium.com/@vipra_singh/building-llm-applications-large-language-models-part-6-ea8bd982bdee

b65de539f83e5b3b4a9f8df39394a297.jpeg

请长按或扫描二维码关注本公众号

喜欢的话,请给我个在看吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值