大模型训练代价很高,国盛证券出过一个报告《ChatGPT需要多少算力》,指出GPT3(175B)训练一次成本约140万刀,大概是1千万人民币。GPT3已经是2020年的历史了,现在的训练成本可能更高。高昂的训练成本小公司难以撑住,可能未来的格局将会是几家头部大公司开源或者卖预训练好的基座模型,小公司基于自己的业务场景微调这些模型以定制自己的模型。当然,也有可能硬件发展地足够快,颠覆性的技术出现,训练成本被打到极低,从而人人都可以从0开始预训练自己的大模型,这种情况至少暂时1-2年里难以实现。
现在对于小公司、部分不想躬身踩坑的大公司而言,用别人的预训练模型微调出一个自己的模型仍然是最快速、最低成本的方法。本文我们分享一些大模型微调中常用的方法。
微调主要有两类,一类是全参数微调。这跟预训练差不太多,直接更新整个模型参数,只不过是训练数据可能会比较少,调整的范围也不会有预训练那么大,训少量的epoch就行了。但因为要更新整个模型,需要的计算资源还是很多。另一类叫参数高效微调(Parameter Efficient Fine-Tuning,PEFT)方法。顾名思义就是设计一些高效的方式来微调模型,包括“P”tuning系列方法(Prompt tuning、p-tuning、prefix tuning、p-tuning v2)以及Adapter tuning和LoRA。
prompt tuning
介绍prompt前需要先介绍一下什么是prompt。GPT3中的说法 prompt tuning中的prompt是指为微调模型而添加的少量的可训练参数。而在给大模型提问的时候会加上的prompt是指给大模型的一个指令或者模板,让大模型生成的期望的回答。比如直接喂给大模型“什么是量化?”那它可能会回答一些金融领域量化交易相关的内容,而如果喂“你是一个大模型算法研究人员,请介绍什么是量化。”那它的就会很确定地介绍大模型量化,这里“你是一个大模型算法研究人员,请介绍什么是” 就是prompt。
这两个prompt是否可以理解为同一个,个人感觉是可以的,prompt可以理解为用prompt(给输入加prompt)来微调大模型,只是这与GPT3中的说法略有差异,我感觉本质上是一样的。
prompt tuning是怎么做的呢?主要有两步,首先给输入加入一个prompt。以基于情感分类任务做prompt tuning 为例,原始输入可能是“今天看了我很喜欢的电影。”,给其加入一个prompt“今天看了一个我很喜欢的电影。这是一个很[Mask]的电影”。然后把加入了prompt的丢给模型,让模型预测[Mask]。模型给了这个mask后我们再加一个映射模块(Label Word Verbalizer),把预测输出映射到最终分类上,比如“好”映射到“积极”,这样大模型就胜任一个情感分类任务了。
对于指定任务而言,添加的prompt基本是一致的,所以输入的处理上可以有些技巧。一个seq输入后进入Embedding层是做一个矩阵乘,词表一般都比较大,矩阵shape很大。可以prompt部分使用缓存,后续使用就不用矩阵乘直接concat(跟KV cache原理一样)。甚至第一次矩阵乘都不需要做,prompt的token是确定的,可以直接从词表拿到Embedding结果。
prompt tuning中prompt非常关键,可以由人工设计也可以训一个小模型来生成。最后的映射模块也需要训练。这种微调方式简单直接,不会更改原始模型,只是用prompt的方式专门使用模型某方面的能力。
p-tuning
prompt tuning中设计恰当的prompt比较难,p-tuning对prompt tuning进行了改进。训练一个单独的结构来确定prompt,以及prompt中token放在原始序列中的位置,以及哪些位置mask。这个单独的结构是一个新的Embedding层,由MLP+LSTM+Embedding 或者 MLP+Embedding构成。
训练的时候,只训练prompt中的虚拟token,别的token的参数冻住。
prefix tuning
prefix tuning给输入seq添加一个虚拟前缀,论文里设置的默认是10个token,可以理解为10个向量,维度和Embedding dim相同,相当于是一个序列经过了一次Embedding。论文里,虚拟前缀并不是直接过原始模型的Embedding,而是Embedding+MLP,相当于新设计了一个模块,用于训练得到最优的虚拟前缀。然后所有的transformer模块都加了一个额外的处理单元,单独处理这个前缀,相当于每层都有参数来调这个前缀,参数量更多。这个额外的模块代码实现里放到了past_key_values里面,和KVcache逻辑类似,通过这个逻辑注入transformer而不改动原来的结构。
不同的模型前缀加入位置不同,decoder-only的直接加在序列前[prefix , x, y],每个decoder都会加入这个前缀计算。encoder-decoder模型,encoder和decoder加不同的前缀 [prefix1 , x , prefix2 , y]。
推理的时候直接把训练好的前缀与序列一起喂给模型。
p-tuning v2
跟prefix tuning基本相同,只是把Embedding层加入的重参数化编码器(prefix tuning的MLP,p-tuning的MLP+LSTM)取消。然后针对任务设计不同的虚拟前缀长度,每一层和prefix一样都有一个单独的处理单元处理虚拟前缀。另外,最后的输出映射上,p-tuning v2取消了前面这些tuning方法中的映射模块(Label Word Verbalizer),改为用原来的分类方法,用一个分类头(Classification Head)应用于tokens之上得到最后的输出。
主流的“P”tuning方法大概说完了。最开始的prompt tuning方法很简单,也不用修改原始参数,但是它很依赖于人工写prompt。p-tuning提出自动生成prompt的方法,但只是更改输入Embedding,对模型预测的影响还是很小。实验证明prompt tuning 和 p-tuning对较大模型(>10B)时效果与全量微调接近,但小模型效果就远不及全量微调了。prefix tuning在前两者的基础上进一步增加了微调可训练的参数,效果有一定提升。但前缀长度还需要手动调整,比较适合文本分类、情感分析类的任务,复杂一些的任务难以胜任。p-tuning v2又对prefix tuning进行改进。这些个“P”tuning方法本质上还是通过prompt指令去激活大模型某方面的能力。而如果大模型本身在这方面基础的能力就差,再怎么改进算法效果也做不起来。
Adapter tuning
这个方法跟前面就大不相同了,在transformer里面添加一个Adapter结构,每个adapter里面主要是两个线性层(图里的OOO部分是指Adapter的输入输出与中间结果),先降维再升维,那么两个线性层的权重矩阵就是(d,m) (m,d)的,由于m<<d,所以整体参数量非常少,训练时冻住原始参数,只训练Adapter的参数就行。这种方法对改变了原始模型结构,显然推理成本急剧增加,多了很多矩阵乘,落地来讲这种方式是没法接受的。
LoRA(Low-Rank Adaptation)
LoRA对Adapter tuning进行了改进,可以说是带来了一种新的微调范式,论文一出也是很轰动。思想很简单,给每一个参数加一个低秩的AB矩阵,只微调AB。微调一个模型,要做什么?修改模型参数。QKV怎么来的,Wq\*X,Wk\*X,Wv\*X。MLP层本质就是做矩阵乘X\*W。微调就是要调这些权重(当然,全参数微调可能Layernorm、softmax的参数都调,LoRA不包含这个)。
微调权重,假设调整后权重为△W,LoRA的思路就是用两个低秩矩阵AB来近似目标△W,即Y=X*(W+△W)=X*(W+AB)。因为AB的秩比较小,所以整体参数量还是非常少,原始的参数冻住,直接训练AB即可。AB一个初始化为0,一个高斯初始化。这里有个问题,为什么这样初始化。如果都初始化为0,那么微调的时候一开始就有梯度消失的问题。如果都用高斯初始化,那么一开始AB的乘积△W就很大,偏移太大可能导致难以收敛。
到这大概可以了解到LoRA以一种轻量的方式做到全参数微调的效果,但他相比Adapter tuning最大的改进是不会改变原始模型结构,不会带来推理时延,这是对Adapter tuning颠覆性的改变。这怎么做到的呢,AB乘积是与原始权重一样shape的矩阵,微调结束后可以将AB融入原始的权重,即保存W=W+AB为新的权重,推理的时候直接加载新的权重即可,模型没有任何改变。
LoRA可以实现接近全参数微调的效果,需要的微调资源很少,175B的模型8张A800就能调,不带来任何推理时延。而且这不是像“P”tuning那样激活模型的能力,而是真正调整模型的能力。这意味着,如果模型预训练时对于某个领域知识了解比较少,我们可以用领域数据+LoRA将模型效果调得比较理想。
我的论文里用了LoRA来微调量化误差,128条1024个token的训练数据,7B的LLaMA2训练5-10个epoch就够了,而且用一张A800训一次不到半个小时。当然,量化给权重带来的扰动本来就不是很大,所以微调量化误差会比领域微调快很多。
当然,LoRA毕竟改变了原始模型,换一个领域就要重新微调一个新模型这也是它的问题。
总结
本文介绍了大模型微调的一些高效方法,国内大部分公司都是走的微调的路子。预训练难度也很大,这两年应届生有预训练经验的人凤毛棱角。但微调门槛低很多,单张卡就能微调13B的模型。有微调的经验面试应该还是比较加分的,甚至可以自己尝试微调一个LLaMA2 7B。如果简历里项目经历不够,这都可以包装成一份项目经历了。Anyway,希望读完本文各位对大模型微调方法有所了解。
宠粉福利:为了帮助大家更好的学习网络安全,我给大家准备了一份网络安全入门/进阶学习资料,里面的内容都是适合零基础小白的笔记和资料,不懂编程也能听懂、看懂这些资料!
获取方式:戳我领取