赞
踩
GPT系列的这些模型基于自监督学习,利用大规模文本学习一个语言模型。在此基础上,针对每一个NLP 任务,用有限的标注数据进行微调。这种迁移学习技术推动了 NLP 发展,各项任务都上了一个大台阶。更为重要的是,产生的“预训练+微调”技术,可用一套技术解决不同语言和不同的 NLP 任务,有效地提升了开发效率。这标志着 NLP 进入到工业化实施阶段。 GPT系列的衍生使得生成类任务面临的难题,因此本文按照如下时间线,主要针对GPT系列的文章进行深入讲解。主要对Transformer、GPT1-GPT3、Instruct-GPT(ChatGPT技术细节)进行介绍。
Transformer未提出前,文本模型常使用的RNN、LSTM模型等时序模型处理NLP任务,但是这类递归模型对句子的处理有严格的先后关系,而且计算量也常常过大,注意力机制的提出能够有效解决这类问题,不依赖于过去的隐藏状态来捕获对先前单词的依赖性,而是整体上处理一个句子。允许并行计算(减少训练时间),并减少由于长期依赖性而导致的性能下降。具体对比分析可以参考:为什么transformer比RNN和LSTM更好?
网上的参考:https://blog.csdn.net/weixin_44750512/article/details/124250497
class MultiHeadSelfAttention(nn.Module): dim_in: int # input dimension dim_k: int # key and query dimension dim_v: int # value dimension num_heads: int # number of heads, for each head, dim_* = dim_* // num_heads def __init__(self, dim_in, dim_k, dim_v, num_heads=8): super(MultiHeadSelfAttention, self).__init__() # 维度必须能被num_head 整除 assert dim_k % num_heads == 0 and dim_v % num_heads == 0, "dim_k and dim_v must be multiple of num_heads" self.dim_in = dim_in self.dim_k = dim_k self.dim_v = dim_v self.num_heads = num_heads # 定义线性变换矩阵 self.linear_q = nn.Linear(dim_in, dim_k, bias=False) self.linear_k = nn.Linear(dim_in, dim_k, bias=False) self.linear_v = nn.Linear(dim_in, dim_v, bias=False) self._norm_fact = 1 / sqrt(dim_k // num_heads) def forward(self, x): # x: tensor of shape (batch, n, dim_in) batch, n, dim_in = x.shape assert dim_in == self.dim_in nh = self.num_heads dk = self.dim_k // nh # dim_k of each head dv = self.dim_v // nh # dim_v of each head q = self.linear_q(x).reshape(batch, n, nh, dk).transpose(1, 2) # (batch, nh, n, dk) k = self.linear_k(x).reshape(batch, n, nh, dk).transpose(1, 2) # (batch, nh, n, dk) v = self.linear_v(x).reshape(batch, n, nh, dv).transpose(1, 2) # (batch, nh, n, dv) dist = torch.matmul(q, k.transpose(2, 3)) * self._norm_fact # batch, nh, n, n dist = torch.softmax(dist, dim=-1) # batch, nh, n, n att = torch.matmul(dist, v) # batch, nh, n, dv att = att.transpose(1, 2).reshape(batch, n, self.dim_v) # batch, n, dim_v return att
如果需要使用mask矩阵作为padding的设置
if mask is not None:
scores = scores.masked_fill(mask == 0, float('-inf'))
在Transformer中的句子的处理不同于RNN这类有严格时序关系的输入,直接并行化的特点会使它的时序关系丢失。因此在Transformer模型中,位置编码是为了将序列中的每个位置赋予一个特定的编码,以便在注意力机制中捕捉序列中的位置信息。位置编码在Transformer的编码器和解码器中都起着重要的作用。
Transformer模型中使用的位置编码方式是正弦余弦编码(Sine-Cosine Encoding),具体来说,位置编码矩阵的每个元素根据位置和维度计算公式为:
P
E
(
p
o
s
,
2
i
)
=
s
i
n
(
p
o
s
/
1000
0
(
2
i
/
d
m
o
d
e
l
)
)
PE(pos, 2i) = sin(pos / 10000^(2i/d_{model}))
PE(pos,2i)=sin(pos/10000(2i/dmodel))
P E ( p o s , 2 i + 1 ) = c o s ( p o s / 1000 0 ( 2 i / d m o d e l ) ) PE(pos, 2i+1) = cos(pos / 10000^(2i/d_{model})) PE(pos,2i+1)=cos(pos/10000(2i/dmodel))
其中,PE表示位置编码矩阵,pos是位置索引,i是维度索引,
d
m
o
d
e
l
d_{model}
dmodel是模型的维度。
d
m
o
d
e
l
d_{model}
dmodel代表了Transformer模型中输入和输出向量的维度,通常是一个超参数。
这种正弦余弦编码的方式允许位置编码矩阵在一个固定的范围内变化,并且能够捕捉到序列中不同位置之间的相对距离和位置关系。通过在位置编码中使用正弦和余弦函数,能够在不同的维度上产生不同频率的周期性变化。
位置编码矩阵的形状通常是 (max_len, d_model),其中 max_len 是输入序列的最大长度。位置编码矩阵在Transformer的输入中与词向量进行按元素相加,从而将位置信息与语义信息结合起来。
使用正弦余弦编码的位置编码方式是Transformer模型中常用且有效的方法,它能够帮助模型更好地理解序列中的位置信息,从而提升序列建模和相关任务的性能。
Transformer的结构分为encoder和decoder两部分。标准的 Transformer 模型主要由两个模块构成:
Encoder(左边):负责理解输入文本,为每个输入构造对应的语义表示(语义特征);
Decoder(右边):负责生成输出,使用 Encoder 输出的语义表示结合其他输入来生成目标序列。
Encoder和Decoder的区别在于它们的输入和输出以及它们的功能。Encoder的输入是输入序列,输出是每个位置的隐藏向量表示;Decoder的输入是Encoder的输出和前面生成的部分输出序列,输出是生成的下一个位置的词。Encoder用于编码输入信息,Decoder用于生成输出信息。
这两个模块可以根据任务的需求而单独使用:
纯 Encoder 模型:适用于只需要理解输入语义的任务,例如句子分类、命名实体识别;
纯 Decoder 模型:适用于生成式任务,例如文本生成;
Encoder-Decoder 模型或 Seq2Seq 模型:适用于需要基于输入的生成式任务,例如翻译、摘要。Transformer 模型不同分支的代表模型
以encoder部分训练为代表的是BERT,以decoder部分训练为代表的就是后面的GPT系列。
BERT:双向预训练语言模型+fine-tuning(微调)
BERT的预训练采用了两个训练任务,Masked LM任务用来捕捉单词级的特征,Next Sentence Prediction任务用来捕捉句子级的特征
NLP中有很多下游任务都涉及到句子之间的关系,对于这类任务只使用语言模型来预训练不能获取到足够的信息,因此BERT将预测下一句话作为了第二个预训练任务。做任务的训练语料是两句话,预测第二句话是否是第一句话的下一句话。
BERT主要用于自然语言理解,具体应用如下:
问答系统:BERT可以在问答系统中用来理解问题并生成答案。
句子相似度比较:BERT可以用来比较两个句子之间的相似程度。
文本分类:BERT可以用来对文本进行分类。
情感分析:BERT可以用来对文本进行情感分析。
命名实体识别:BERT可以用来识别文本中的命名实体。
GPT:自回归 预训练语言模型+Prompting(指示/提示)。GPT的预训练任务只有一个:Predict Next Token。具体来说任务是预测接下来会出现的token是什么。
举例来说,假设训练资料里面,有一个句子是台湾大学,那GPT拿到这一笔训练资料的时候,选取BOS这个Token所对应的输出,作为Embedding的结果,用这个embedding去预测下一个应该出现的token是什么。
那在这个句子里面,根据这笔训练资料,下一个应该出现的token是"台",要训练模型,根据第一个token,根据BOS给的embedding,那它要输出"台"这个token。
这个部分,有一个embedding,这边用h来表示,然后通过一个Linear Transform,再通过一个softmax,得到一个概率分布,我们希望这个输出的概率分布,跟正确答案的交叉熵越小越好。
接下来要做的事情,就是以此类推了,输入BOS跟"台",它产生embedding,接下来它会预测,下一个出现的token是什么,以此类推来训练模型。
GPT和BERT在使用场景上有明显的不同:
GPT能够完成各种自然语言处理任务,在文本生成方面表现尤为优秀,可以生成各种类型的文本,如文章、诗歌、对话等。其主要具体应用如下:
文本生成:GPT可以用来生成文本。
文本自动完成:GPT可以用来自动完成用户输入的文本。
语言翻译:GPT可以用来生成翻译后的文本。
对话生成: GPT可以用来生成对话
摘要生成: GPT可以用来生成文章摘要
BERT:fine-tuning(微调)。微调是指模型要做某个专业领域任务时,需要收集相关的专业领域数据,做模型的小幅调整,更新相关参数。
GPT:Prompting。prompt是指当模型要做某个专业领域的任务时,我提供给他一些示例、或者引导。但不用更新模型参数,AI只是看看。
BERT、ELMo、GPT模型,GPT的具体细节在下面的section进行介绍。
GPT1到GPT3的发展主要体现在模型参数量以及训练数据的增加。以及为了尽量兼容到多个下游任务,所以对下游任务的统一优化形式进行构建,以及提出了使用few-shot和zero-shot的方法,避免对模型进行大量调优的策略。
在没有标号的数据上进行预训练,然后在有标号的子任务上训练一个分辨的微调模型(预训练+微调)。在微调的时候只要构造任务相关的输入形式,不改变模型。模型架构-transformer(12层)。训练数据集:BooksCorpus数据集,有7000篇没被发表的书
这种模型面临的难点在于如何实现达到通用性:损失函数到底哪些比较好(目标函数与子任务的相关度),怎么把学到的表示有效的传到下游的nlp子任务中。因此下面我们主要对其的训练方式和子任务构建方法进行详细介绍。
核心结构:中间部分主要由12个Transformer Decoder的block堆叠而成
以classification为例,text前面放一个初始词元Start,后面放一个抽取词元Extract,拼接成序列后经过gpt的transformer解码器,然后接一个线性层(新的)投影到预测区间。Delim是分隔符。
GPT2主要对下游任务的统一化形式进行构建,重点在于提高模型泛化性。
在推理模式上,虽然GPT1的预训练加微调的范式仅需要少量的微调即可,但能不能有一种模型完全不需要对下游任务进行适配就可以表现优异?GPT2便是在往这个方向努力:不微调但给模型一定的参考样例以帮助模型推断如何根据任务输入生成相应的任务输出
最终,针对小样本/零样本的N-shot Learning应运而生,分为如下三种
还是回到few-shot领域。效果上能生成一些新闻的文章。
还是使用了common crawl进行爬取,把所有爬取的样本作为负例(因为大部分是低质量的),然后利用gpt2的数据做正类,做一个二分类任务,正类是gpt2的数据集。接下来做预测,将common crawl的数据输入分类器,如果分类器预测出是正类的话就保留下来,否则过滤掉。然后用lsh算法对相似文章进行去重。(集合相似度)。然后把bert、gpt、gpt2的所有数据集都加进来。
GPT3在进行 few-shot learning、one-shot learning、zero-shot learning时不对GPT模型的参数做任何的更新,而是使用in-context learning。
Instruct GPT
大的语言模型会生成有问题的输出,因为模型训练用的目标函数不那么对。
从从零实现ChatGPT——RLHF技术笔记中可以了解到,对强化学习的粗糙理解RL。过程就是,让智能体在一个状态S下选择动作A,然后获得收益R,然后我们希望优化选择动作的策略,使得总体收益的期望最大。因为搜索空间很大,我们利用模型的预测结果决策,同时为了不让模型陷入局部最优而按蒙特卡洛方式一定比例随机游走,在这个过程中得到每个state-action对应的reward作为新的训练样本,即所谓的探索和利用(Exploration and Exploitation)过程。
近端策略优化PPO(Proximal Policy Optimization)是一种强化学习算法,它通过引入奖励信号来调整模型的行为,使模型生成的内容更符合人类的偏好。具体来说,PPO通过最大化预期奖励来调整模型的策略,使模型在选择行为时更倾向于选择可以得到更高奖励的行为。在这个阶段中,我们首先使用在第一阶段训练的有监督微调模型和第二阶段训练的奖励模型来生成一个初始的策略。然后,我们使用**PPO算法来调整这个策略,**使模型在生成内容时更考虑人类的偏好。通过这个阶段的训练,模型不仅可以理解人类的语言,还可以理解人类的偏好,并生成更符合人类偏好的内容。同时限制新策略和旧策略之间的相对差异,以确保策略更新是有限的。这是通过一个代表策略更新大小的裁剪函数来实现的。具体细节可以查看强化学习极简入门:通俗理解MDP、DP MC TC和Q学习、策略梯度、PPO
PPO 是一种用于训练强化学习模型的算法。它可以用于调整语言模型,使得模型生成的结果更符合人类的偏好。具体来说,过程可以分为三个阶段:
Kullback-Leibler (KL) 散度,也叫做KL散度或相对熵,是用于度量两个概率分布之间的差异的一种方法。在数学上,它表示一个分布相对于另一个分布的信息丢失。
在实际使用中,为了避免计算数值问题,可以添加一些平滑处理,如加上一个小的常数,以防止分母或分子为零。
KL散度是非对称的,即KL(P || Q) 不等于 KL(Q || P)。
KL(P || Q) 表示将近似分布 Q 逼近真实分布 P 时的 KL 散度,用于衡量 Q 相对于 P 的差异。
KL(Q || P) 表示将近似分布 P 逼近真实分布 Q 时的 KL 散度,用于衡量 P 相对于 Q 的差异。
代码实现: kl = np.sum(p * np.log(p / q))
如果 KL 散度等于零,表示两个分布完全相同;如果 KL 散度大于零,表示两个分布之间存在差异,且差异越大,KL 散度越大。
班里男生人数占40%,女生占60%,则班里随机抽取一个人的性别的概率分布是Q = [0.4, 0.6]。作为真实事件的概率分布。
小明猜测班里男生占30%,女生占70%,则小明拟合的概率分布P1 = [0.3, 0.7]。
小红猜测班里男生占20%,女生占80%,则小红拟合的概率分布P2 = [0.2, 0.8].
那么现在,小明和小红谁预测的概率分布离真实分布比较近?这时候就可以用KL散度来衡量P1与Q的相似性、P2与Q的相似性,然后对比可得谁更相似。
KL1 = KL(P|Q) = KL([0.4, 0.6] | [0.3, 0.7]) = (0.4log0.4 - 0.4log0.3) + (0.6log0.6 - 0.6log0.7) = 0.0226;KL2 同理可得 0.1046
H
(
y
,
p
)
=
−
[
y
×
l
o
g
(
p
)
+
(
1
−
y
)
×
l
o
g
(
1
−
p
)
]
H(y,p)=-[y \times log(p) + (1-y) \times log(1-p)]
H(y,p)=−[y×log(p)+(1−y)×log(1−p)]
交叉熵用来求目标与预测值之间的差距,数据分布不一定是概率分布。
一共用到三个模型,三个模型分别对应不同的数据集。SFT数据集是人工标注的数据,RM数据集是根据SFT模型对问题生成结果后人工排序,RF数据集使用RM模型打分。
RLHF
如上图所示,RLHF方法一共分为三步:
第一步:SFT。人工构建数据集并微调模型。花钱招人给问题(prompt)写回答(demonstration)形成第一个标注数据集,然后finetune一个GPT3(SFT)。这又被称为行为克隆(Behavioral Cloning,简称BC),即直接使用专家的行为数据(例如,专家在特定情况下采取的动作)来训练模型。在行为克隆中,模型的目标是尽可能地复制专家的行为,而不是尝试优化某种奖励函数,所以它可能无法处理那些专家数据中没有覆盖到的情况,因为它完全依赖于专家的行为数据。
第二步:RM。对第一步生成的模型提问并获得多个答案,人工对答案进行排序,并且训练出一个奖励模型打分。让模型(多个模型(可以是初始模型、finetune模型和人工等等)给出问题的多个回答)生成多个答案,然后人工给这些问答对按一些标准(可读性、无害、正确性)进行排序(只负责排序不打分),训练一个奖励模型/偏好模型来打分(reward model)(是用Elo得到一个完整排序后,经过归一化得到了奖励分数)。现在我们有一个RM给每个输入的问答对打分,这样就得到了强化学习中的reward。这个RM用什么模型?只要用Elo系统打分后归一化,然后直接上个LM做回归就行,可以从零训练也可以用老LM做finetune。这里有个有趣的事情在于,做问答和做评分都需要输入所有的文本,实际上两个模型的容量(或者说理解能力)应该是差不多的,而现有的RLHF模型都使用了两个不同大小的模型。
第三步:强化学习训练上面那个finetune后的GPT3模型。用强化学习做LM训练的一种思路是用Policy Gradient做,这一块OpenAI用的是他们在17年提出的PPO算法,即Proximal Policy Optimization。
首先定义强化学习的场景:
![image-20230526201040959](https://img-blog.csdnimg.cn/img_convert/f6f0a6ec82a25d498136a9e9368a67a9.png
需要对其中的强化学习概念进行了解的,可以参考强化学习入门
RL模型具体实现
基于GPT3.5的发展路线:增强代码/推理能力且更懂人类终于迭代出ChatGPT,ChatGPT初版与InstructGPT的差别:基于GPT3还是GPT3.5微调。能多轮对话,chatgpt会自己编造答案。不是在网络上搜寻的答案,是没有联网的,是2021年前的训练数据。具体可以参考ChatGPT技术原理解析:从RL之PPO算法、RLHF到GPT4、instructGPT
。
采样加上文字接龙。
基于GPT4的ChatGPT改进版:新增多模态技术能力。输入可以是图像和文本,输出是文本。
对抗性测试、训练稳定性的问题:大模型上训练成本太高了(一两个月)。
问题:大模型的涌现能力以及在小模型上有效的数据无法用到大模型上
GPT4:能够利用他们自己的内部代码库在GPT4 代码刚开始运行时就能准确预测得到GPT4最终训练完成的loss。这个loss时在另外的loss外推出去,比GPT4loss小一万倍的计算资源。
GPT-4 确实在很大程度上改变了 AI 研究的范式。以前的研究方法主要集中在为特定任务设计特定的网络结构,而现在的研究更多地关注探索大型语言模型的潜在能力,以及如何通过组织语言来驱动这些模型完成各种任务。
下一步:轻量化,安全性
其他新文章新方法:Toolformer, ChatGpt plugin,LLaMa,Visual ChatGpt,GigaGAN,AIpace,GPT-4,PALM,Claude,Copilot
模型能够理解图像和音频这件事,事实上早就用人把CLIP和GPT绑到一起,实现了ChatGPT理解图片(输入图片先用CLIP转成文字,然后拿去和ChatGPT聊)。这种做法语言模型本质上还是在做一个文本类的任务。他仍然局限在自己的文字世界里。无法将语言模型的强大能力覆盖到多模态领域,他就像一个盲人,大象是摸出来的(CLIP)而非真正看见。
ToolFormer解决的问题点:LLM能够理解图像+音频两种内容了,所以才叫多模态大语言模型。
不止放文本数据进行,还把交错的文本、数据(例如网页,图文穿插),图像-图像注释数据(是的就是Diffusion用的那个)一起放进去做预训练(预训练是什么以前讲过)。
#### 大概逻辑
语言模型的本身能力,还是靠文本数据的学习得来的,包括对话中的上下文理解,各类NLP任务,支持Prompt等。然后交错的文本、图像数据、图像-图像注释数据,用来实现文本-图像这两个模态之间的对齐打通(我的理解是把CLIP这种跨模态通道的事情在大语言模型预训练中完成了
#### CoT思维链
Cot思维链,他们会把问题拆成小问题,再让模型回答,例如下图:先让他描述图片,然后再把图片描述作为Prompt一起加入对图片的问题中。
abstract:基于 subword 进行分词:它可以较好的平衡词表大小与语义表达能力;常见的子词算法有Byte-Pair Encoding (BPE) / Byte-level BPE(BBPE)、Unigram LM、WordPiece、SentencePiece等。当前主流的一些开源大模型有很多基于 BBPE 算法使用 SentencePiece 实现分词器
当前在预训练模型领域较为关注的研究重点包括:如何训练超大规模参数的模型、对已有模型架构的创新性研究、更加有效的训练方法和训练加速的方法。还有简化微调的步骤,比如像 GPT-3 那样用一套提示机制来统一所有下游任务的微调,推动零样本学习和小样本学习。除此之外,多模态预训练模型和推理加速方法也是目前的研究焦点。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。