一文读懂 LLM 如何进行微调?

news2024/11/15 13:53:16

​你知道吗,咱们用那些已经训练好的大型语言模型,其实有好多不同的玩法。最常见的有三种:一种是用模型提取的特征来训练新的小模型;另一种是直接给模型看新任务的例子,让它学着怎么回答,这招叫做提示;最后一种就是调整模型里面的一些参数,可能是全部,或者就那么几个,来让它更好地完成任务,这就涉及到微调了。

先说说第一种,就是拿现成的模型当工具用,不用改它,就用它提取的那些信息来训练我们的新模型,比如线性分类器。第二种呢,就是我们给模型出个示范,让它看看我们想要的答案是什么样的,这样它就能学着模仿了。最后一种情况,如果我们想要更精确地控制模型,那就得动动它的参数了。

咱们接下来再细聊聊这些方法。

使用转换器(Transformers)进行分类任务

先聊聊怎么用那些已经训练好的转换器吧。咱们有几种老派的方法,比如在模型提取的特征上再训练一个新模型,或者调整模型的输出层,甚至是把整个模型的层都调整一遍。

基于特征的方法

先说说这个用特征的方法。就是咱们把已经训练好的模型拿出来,但是让它保持原样,不改它的任何设置。我们就用它来提取新数据的特征,然后拿这些特征去训练另一个模型。这个新模型啥样的都行,比如随机森林或者XGBoost,但通常简单的线性分类器效果最好。为啥呢?因为像BERT、GPT这些已经训练好的模型,它们提取的特征质量特别高,信息量也大。这些特征能捕捉到数据里的复杂关系和模式,让线性分类器能更容易地把数据分到不同的类别里。

而且,线性分类器这种东西,比如逻辑回归或者支持向量机,它们还有很好的防止过拟合的特性。这点在用高维特征空间的时候特别有用。因为咱们不需要更新原来的转换器模型,所以这个方法特别高效。还有,因为这些特征提取出来就不变了,所以咱们可以在训练开始之前就一次性算好,用在好几个训练周期里。

图1就给我们展示了一下,怎么用微调的方法让这些大型语言模型去做一些具体的任务,比如把德语翻译成英语。咱们就是拿一个在很多文本上训练好的模型,然后稍微调整一下,让它能做这种语言翻译的活儿。

图1:大型语言模型的通用微调工作流程

微调

微调呢,基本上就是让模型更好地适应咱们手头的任务。这事儿咱们一般有两种做法:一种是微调I,就是只动模型的输出层;另一种是微调II,得动模型的所有层。

微调I这招,其实跟上头说的用特征的方法有点像。就是咱们在模型上加几层输出层,但是模型的主体部分咱们还是保持原样,不动它。这样的好处是,不用把整个网络都重新训练一遍,所以相对来说,对计算资源的要求没那么高。

然后是微调II,这个就复杂点了。咱们还是得加输出层,但是这次,我们得让整个模型都参与到训练中来,包括那些之前保持不变的层。这就意味着,咱们得从头到尾都进行反向传播,这事儿可就费劲儿了,计算成本也高。不过,要是咱们手头的数据特别专业,或者模型需要更精细的调整,这种方法往往能带来更好的效果。

简单来说,微调I适合快速上手,资源消耗少;微调II呢,就是精雕细琢,虽然费时费力,但效果可能更棒。咱们得根据实际情况来选。

图2:利用预训练LLMs的三种传统方法。

咱们再看图2,这里总结了咱们刚聊完的那三种微调方法,还教了咱们一些怎么判断训练效率的小技巧。简单来说,微调II因为要动的层和参数比微调I多,所以它在反向传播的时候,需要的计算量和资源自然就更多,成本也就上去了。同样的道理,跟那个只需要动动输出层的微调I,或者是更简单、直接用模型提取特征的方法比起来,微调II的开销肯定是要大的。

上下文学习、索引和提示调整

再来说说上下文学习这个概念,这可是GPT-2和GPT-3这些大型语言模型(LLMs)带火的。上下文学习,有时候也叫零样本学习或者少样本学习,意思是咱们不需要给模型喂一大堆数据,它也能学会新任务。

图3:为上下文学习提示LLM

那上下文学习有什么技巧呢?就像图3里画的那样。这个技巧的核心就是给模型提供一些上下文信息或者例子,让它能够自己琢磨出来应该怎么完成任务。这就好比咱们给学生一些例题,他们看了之后就能理解怎么解题了。

比如说,咱们想用GPT-3这样的大型预训练语言模型来做德语到英语的翻译,而且是只用很少的样本。那就给模型几个德语句子和它们的英语翻译,让模型看看。比如:

  • 德语说“Ich liebe Pfannkuchen”,英语就是“I love pancakes。”

  • 德语说“Das Wetter ist heute schön”,英语就是“The weather is nice today。”

然后,就可以让模型试着翻译新的句子,比如“Wo ist die nächste Bushaltestelle?”

不过,说实话,上下文学习在某些情况下可能没有直接微调模型效果好,因为它主要是靠模型自己从训练数据里学的东西来解决问题,而不是专门针对这个任务去调整参数。

但是,上下文学习也有它的好处。比如,咱们手头没有足够的标记数据来做微调,或者不能直接改模型,只能通过界面或者API来用模型的时候,上下文学习就特别有用了。

还有一个跟上下文学习很像的概念,叫做硬提示调整。硬提示调整就是咱们不改模型里面的参数,而是改咱们给模型的提示,让它能更好地完成任务。比如,可以换几种方式来提示模型做翻译:

  • “将德语句子'{german_sentence}'翻译成英语:{english_translation}”

  • “德语:'german_sentence}'英语:{english_translation”

  • “从德语到英语:'{german_sentence}' -> {english_translation}”

硬提示调整不需要改模型的参数,所以相对来说资源消耗小,但是效果可能没有全面微调模型那么好,因为它不能让模型针对特定任务去做深入的调整。而且,找一个好的提示可能得花不少力气,有时候还得人工来比较不同的提示哪个更好。当然,也有人提出用另一个语言模型来自动生成和评估提示,这就是另一种玩法了。

另一种利用纯粹的上下文学习基础方法是LLM索引,如图4所示。

图4:LLM索引从外部文档检索信息。

在大型语言模型(LLMs)的世界里,索引就像是咱们给模型的一个小技巧,让它们能够变身成信息检索的小能手,去网上或者其他地方找信息。就像图4里展示的,索引模块会把文档或者网页拆成小块小块的。然后,这些小块会被转换成向量,就像给它们贴上标签一样,存到一个向量数据库里。

等到有人来问问题的时候,索引模块就忙起来了。它会算算用户的问题变成向量后,跟数据库里存的那些向量哪个最相似。最后,它会找出最匹配的前几个向量,用这些信息来合成答案。

这么说吧,如果咱们把信息比作图书馆里的书,索引模块就像是图书馔的目录,帮助读者快速找到他们想要的那本书。在这个情况下,读者的问题就像是图书馔的搜索词,索引模块会根据这个搜索词,找出最相关的几本书,也就是最接近的向量,然后给出答案。

参数高效微调

近年来,开发了许多方法,以更高效地适应新的预训练转换器的目标任务。这些方法通常被称为参数高效微调,写作时最受欢迎的方法总结在图5中。

图5:参数高效微调技术的主要类别,以及流行的示例

软提示调整

软提示调整,就是咱们在输入的文本变成向量之前,先加一个可以训练的参数组,咱们就叫它“软提示”。这个软提示是活的,可以根据需要调整,不像硬提示那样死板。咱们用梯度下降这种数学方法来慢慢调整这个软提示,让模型在处理特定数据集的时候表现得更好。在代码里,这个软提示就像是给输入的向量前面加了个扩展包,让模型能从更长的句子里理解更多信息。

在类似Python的伪代码中,软提示调整可以描述为

x = EmbeddingLayer(input_ids)
x = concatenate([soft_prompt_tensor, x],
                 dim=seq_len)
output = model(x)

其中soft_prompt_tensor与嵌入层产生的嵌入输入具有相同的特征维度。因此,修改后的输入矩阵具有额外的行(就好像它通过额外的令牌扩展了原始输入序列,使其更长)。

前缀调整

前缀调整这个方法跟软提示调整挺像的,区别在于咱们不是只在输入前加东西,而是在模型的每个处理单元前都加个软提示。这样做的好处是,可以让整个模型在训练的时候更稳定,就像给船加了锚,不容易翻。前缀调整的时候,咱们还是用类似的方法,只是在模型的不同部分加这个软提示,让模型在处理信息的时候更灵活。

简单来说,软提示和前缀调整都是为了让模型更好地适应咱们的问题,只是它们加提示的地方和方式不太一样。软提示调整更注重在输入阶段,而前缀调整则是在模型的每个处理单元前都做点小动作,让模型整体表现更上一层楼。

与前面讨论的硬提示方法不同,软提示策略优化嵌入版本的提示。虽然在硬提示调整中我们修改离散输入令牌,在软提示调整中我们使用可训练的参数张量。

软提示调整

软提示调整的理念是在嵌入查询令牌之前添加一个可训练的参数张量(“软提示”)。然后使用梯度下降调整附加张量,以提高在目标数据集上的建模性能。在类似Python的伪代码中,软提示调整可以描述为

x = EmbeddingLayer(input_ids)
x = concatenate([soft_prompt_tensor, x],
                 dim=seq_len)
output = model(x)

其中soft_prompt_tensor与嵌入层产生的嵌入输入具有相同的特征维度。因此,修改后的输入矩阵具有额外的行(就好像它通过额外的令牌扩展了原始输入序列,使其更长)。

前缀调整

前缀调整类似于软提示调整,只是在前缀调整中,我们在每个转换器块之前添加可训练的张量(软提示),而不仅仅是嵌入输入,这可以使训练更稳定。前缀调整的实现如图6所示。

图6:普通转换器块与前缀调整转换器块的比较

两个软提示调整和前缀调整都被认为是参数高效的,因为它们只需要训练添加的参数张量,而不需要LLM参数本身。

适配器方法

咱们来聊聊适配器方法,这可是跟前缀调整有亲戚关系的技巧。适配器方法也是在转换器层里加东西,不过它加的是额外的全连接层,这就像是在模型的每个处理单元后面又加了个小助手。

在原始的适配器方法里,咱们在每个转换器块的多头自注意力和已有的全连接层之后,再加上一些新的全连接层。只有这些新加的适配器层在训练的时候会更新,其他的层就保持原样,不用动。因为这些适配器层一般个头不大,第一个全连接层把输入压扁到一个更低的维度,第二个全连接层再把它拉回到原来的维度。这样一来,适配器方法就挺省事儿的,不需要动用太多的参数。

如图7所示。

图7:普通转换器块(左)和带有适配器层的转换器块的比较。

就好比咱们在足球队里加了几个新教练,只训练这几个新教练,其他的球员还是按老规矩来。这样既能带来一些新战术,又不用大动干戈,挺经济实惠的。

在伪代码中,原始适配器方法可以编写如下:

def transformer_block_with_adapter(x):
    residual = x
    x = SelfAttention(x)
    x = FullyConnectedLayers(x)  # Adapter
    x = LayerNorm(x + residual)
    residual = x
    x = FullyConnectedLayers(x)
    x = FullyConnectedLayers(x)  # Adapter
    x = LayerNorm(x + residual)
    return x

低秩适应

再来聊聊一个挺火的微调方法,叫做低秩适应,简称LoRA。这个方法就是用一种特殊的数学技巧来重新配置那些已经训练好的大型语言模型(LLMs)的权重。低秩变换这玩意儿,就是用小的维度来近似表示大的矩阵,就像是用几块积木来搭一个大致的形状。

咱们这么想,如果有一个特别大的权重矩阵,尺寸是( A \times B ),LoRA方法就是把这个大矩阵分解成两个小矩阵的乘积,也就是( W_A )和( W_B )。这样,咱们就不用动原来的大矩阵,只训练这两个小矩阵就行。

为啥说它参数效率高呢?因为这两个新矩阵可以小得多。比如说,如果原来的矩阵是25乘以50,那参数就有1250个。但如果咱们用LoRA方法,只训练( W_A )和( W_B ),假设它们各自都只跟5个维度有关,那( W_A )就有125个参数,( W_B )有250个参数,加起来才375个参数,省了不少呢。

这就像是咱们要搬家,本来得搬一大堆东西,但用LoRA这个方法,就像是只挑了几样最重要的东西搬,既省力又省心。这样,模型在学新任务的时候,就不需要记住那么多旧的东西,能更专注地学习新知识。

咱们学完怎么更新权重矩阵之后,下一步就是写代码来实现全连接层的矩阵乘法。就像这段伪代码一样:

def lora_forward_matmul(x):
    h = x . W  # 这是常规的矩阵乘法
    h += x . (W_A . W_B) * scalar  # 这是加上我们的低秩适应部分
    return h  # 返回结果

这里的scalar就像是一个旋钮,用来调节最终结果的大小。它的作用是平衡模型原来学到的知识跟新任务需要的调整。

按照最早提出LoRA方法的那篇论文里说的,用LoRA调整过的模型在一些针对特定任务的测试里,表现得比用适配器方法的模型要好一点。而且,LoRA通常还能比咱们之前聊的那种全面微调的模型(微调II)表现得更棒。

简单来说,LoRA这个方法就像是给模型一个小小的助推器,让它在新任务上表现得更上一层楼,同时还保留了它之前学到的所有知识。

通过人类反馈的强化学习

咱们聊聊怎么让大型语言模型(LLMs)更懂人心,这就是通过人类反馈来做强化学习,简称RLHF。

通常,咱们让模型适应新任务,就是用有标签的数据来告诉它怎么干。比如,用一堆标了积极、中立、消极的情感标签的句子来训练模型,让它学会情感分类。

但这还不够,咱们想让模型更贴近人类的想法,这时候就得用到RLHF了。RLHF就是让模型在人类的指导下,通过奖励和惩罚来学习。比如,ChatGPT和InstructGPT就是这么训练出来的。

在RLHF里,咱们先是用监督学习让模型有个基础,然后再用强化学习让模型更上一层楼。这就像是先教会孩子基本的对错,然后通过奖励好行为、纠正不好的行为来让他们学得更好。

那怎么收集人类反馈呢?就是让真人来看模型的回答,然后打分、排名,这些评价就成了奖励信号。然后,咱们用这些信号来训练一个奖励模型,这个模型学会了人类的喜好之后,就能用来指导LLMs的训练。

为啥要这么麻烦用奖励模型呢?因为咱们不能实时地让真人来反馈,那样太慢了,得用模型来模拟这个过程。

这个近端策略优化,就是一种强化学习方法,它能让模型在训练的时候更加精准地适应人类的喜好。这样一来,咱们的模型不仅能回答问题,还能更懂人心,给出更贴近人类思维的答案。

总结

虽然把预训练的大型语言模型(LLMs)的所有层都微调一遍,是让它们适应新任务的最好办法,但咱们本文中列举的这些方法,像基于特征的方法、上下文学习,或者用那些参数少、效率高的微调技术,这样既能达到目的,又能省不少计算资源。

本文中提及了三种常用的方法:一个是用模型提取的特征来训练新模型;一个是只微调模型的输出层;还有一个是把模型所有层都微调一遍。这三种方法各有利弊,计算效率高的,可能效果就一般;效果好的,计算成本可能就高。

另外,还有像软提示调整、前缀调整和适配器方法这样的技术,它们都能让模型在训练的时候更省事儿,不用动那么多参数。还有RLHF,也就是通过人类反馈来做强化学习,这种方法能给监督微调提供一个替代方案,有时候能让模型表现得更好。

总的来说,预训练的LLMs越来越厉害,给咱们提供了各种新机会和新策略,让它们能更好地适应各种不同的任务和领域。随着这个领域的研究越来越深入,咱们可以期待将来会有更多改进和创新出现。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2075299.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深度探究|软件主宰世界,我们究竟错过了什么?

这乃是知乎 COO 张宁于近期针对国内过往十年创投环境展开的深度思索。 张宁觉得,在过去的十年当中,美国硅谷专注于 SaaS 领域,凭借软件的标准化来提升企业的效率与经济性,同时倡导开放性与多样性。 中国在过去的十年里&#xff…

Java之线程篇二

目录 Thread的常见构造方法 Thread的常见属性 代码示例1 代码示例2 示例代码3 代码示例4 代码示例5 小结 线程中断 代码示例1 代码示例2 代码示例3 代码示例4 小结 线程等待 获取当前线程的引用 Thread的常见构造方法 举例 Thread t1 new Thread(); Thread t2…

YOLOv8改进 | 融合改进 | C2f融合Faster模块提升检测速度【完整代码 + 主要代码解析】

秋招面试专栏推荐 :深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡 专栏目录 :《YOLOv8改进有效…

conda环境安装与删除

安装 1.cmd安装 conda create -n xxxxx(名字) python3.8 进入虚拟环境 activate xxxxx(名字) 查看虚拟环境的库 pip list 退出虚拟环境 deactivate 2.pycharm直接创建 对一个项目右下角: 可以使用现有环境,也可以创建新环境 删除 在cmd中输入&…

大模型在安全领域的十大应用场景及实现路径

作为网络安全及AI的双重爱好者,笔者也一直在关注大模型在安全领域的相关应用,从目前市面上看到的产品来说,相关的结合还在一个较为早期的阶段,很多产品能力也是为了大模型而大模型,并未真正发挥其价值。 在去年上一篇相…

lvgl 滚轮roller 选项循环设置

lvgl 中可以通过设置滚轮的属性使所有选项循环出现,对于时间、日期之类的组件非常实用。 lv_roller_set_options(lv_obj_t * obj, const char * options, lv_roller_mode_t mode); 这个函数的最后一个参数有两个值: LV_ROLLER_MODE_NORMAL…

大模型面经——Langchain总结

本篇介绍Langchain相关面试题。 本次将会分为上下两个部分,本篇章将会介绍前三个问题,下一次在将后三个问题补充完毕。 以下是一个快捷目录: 什么是 LangChain? LangChain 包含哪些部分? LangChain 中 Chat Message History …

49、Python之模块和包:模块导入对命名空间的影响

引言 前面文章中,关于Python解释器在模块导入行为背后所执行的操作,已经做了深入的介绍。本文打算在此基础上,结合实际代码案例,进行进一步的补充说明。同时,比较看似只是微小的导入方式的改变,可能会导致…

「ComfyUI」生图修图神器,自定义调节颜色光暗,更生动更强对比度生图技巧分享!

前言 ‍‍‍‍‍前 言 今天再给小伙伴们分享一个简单又实用生图神器插件,可以调整整个图像的光暗变化以及颜色变化。 原理的话,我们也简单来说下,我们在使用 VAE 将图像编码为潜在噪声时,VAE 解码的值通常在一定范围内&#xf…

在Mac上打开UE4Editor

编译MacEditor 使用如下命令在Mac机器上编译Mac的UE4Editor: ${EnginePath}/Engine/Build/BatchFiles/Mac/Build.sh ${ProjectName}Editor Mac Development ${ProjectPath} -buildubt -buildscw -waitmutex -log${ClientPath}/Saved/Logs/${ProjectName}Editor.log…

SpringBoot集成kafka-自定义拦截器(可以在拦截器中做记录日志、安全检查等操作)

TOC 1、kafka配置类 kafka配置类添加Configuration注解,springboot启动后会自动读取该配置类;由于在application.yml文件中我们找不到kafak拦截器相关的配置项,因此需要自定义拦截器;消费者相关配置方法中添加自定义拦截器配置&a…

FORTIFY: FD_ISSET: file descriptor 1024 >= FD_SETSIZE 128 记录

问题 在开发过程中,遇到一个问题,即使用FD_ISSET时,当文件描述符数量超过1023,导致netd进程出现crash。通过代码和log分析,发现这是由于内核限制导致的数组越界问题。 总结:FD_ISSET(sock, &read_fds)…

【日记】这个月花了好多钱(1317 字)

正文 这几天都好热。热到人不想动,只想睡觉。 今天写文章发现自己有个很显著的特点,就是在有个框架之后,具体细节完全没有预设。我只能像马尔可夫链一样,形成一个比较窄的窗口,接着这个窗口里的情节往下写,…

.NET Razor类库 - 生成NuGet包

上一篇讲了Razor类库组件化:https://blog.csdn.net/CsethCRM/article/details/141558974 本篇说一下Razor类库生成NuGet包 1.右键Razor类库项目 - 属性 2. 输入Nuget 包信息 点击 左侧菜单 包 在生成操作期间 创建包文件 打勾 版本号 我们输入 2023.1.0 作者 Xxx…

外卖霸王餐项目是什么?怎么搭建属于自己的外卖霸王餐小程序 ?

前言: 外卖霸王餐项目是一种结合了优惠促销与推广合作的商业模式,主要针对外卖行业。这个项目的核心是通过提供低于市场价的外卖餐品(通常是半价或者更大折扣)来吸引新用户尝试,并通过用户的口碑传播来增加餐厅的知名…

降本高达30%,磁集成是电源企业的福音吗?

导语 为什么说磁集成将会是大功率电源产品趋势?因为终端价格战越来越激烈,只有磁集成才能同时解决电源企业的三大核心竞争需求。 终端持续“卷”价格 储能价格正式步入0.5元时代。从价格战的角度来看,储能领域自2023年起就已经进入“0.5元/Wh时代”&…

集群 NAT(地址转换)、TUN(IP隧道)、DR(直接路由)

一、企业群集应用概述 1、群集的含义 ①、Cluster、集群、群集 ②、由多台主机构成,但对外只表现为一个整体,只提供一个访问入口(域名与IP地址),相当于一台大型计算机。 2、问题 ①、互联网应用中,随着站…

composer常用命令列表和实践使用、服务器lnmp环境自动化部署脚本及netstat命令常用选项笔记-及state各值的意义

一、composer常用命令列表和实践使用 1. composer常用的命令列表如下: #. composer install 命令(composer.lock与composer.json) 如果当前目录下存在composer.lock文件,则从此文件读取依赖版本,否则就读取compose…

计算机毕业设计选题推荐-社区康养管理系统-Java/Python项目实战

✨作者主页:IT研究室✨ 个人简介:曾从事计算机专业培训教学,擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

SQL注入漏洞WAF绕过

目录 如何检测和防范SQL注入攻击中的编码伪装? 检测SQL注入攻击中的编码伪装 防范SQL注入攻击中的编码伪装 WAF在处理SQL注入时为什么有时会对大小写不敏感? SQL注入中的联合查询注入有哪些常见的攻击方式? 在绕过Web应用防火墙&#xf…