在开始之前,有几点建议给到刚入门的小白:
1️⃣想要弄清楚整个训练,推理过程,就要关注输入的数据流经模型的形状变化,最好自己去推一遍。
2️⃣现在的大模型科研的现状是,代码能力强的人科研一般不会差,不要忽视代码能力。其实入大模型坑之后很少会写代码,但是如果想要真正做出一些有意思的东西,最好还是提升一下自己的coding水平。刷算法题其实是一个不错的路径。
3️⃣正则表达式很重要,可以练起来了。
4️⃣希望读者能花时间将文章中推荐的资料都细细品味下来。
为了照顾新手小白,本系列不写成综述,以及尽量少出现数学公式。
入门论文10篇
⑴A Survey of Large Language Models
http://arxiv.org/abs/2303.18223
⑵Training language models to follow instructions with human feedback (instrcutGPT), OpenAI , https://arxiv.org/pdf/2203.02155.pdf
⑶Finetuned Language Models Are Zero-shot Learners (FLAN), Google Research, https://arxiv.org/pdf/2109.01652v2.pdf
⑷Language Models are Few-Shot Learners (GPT-3) OpenAI.
https://arxiv.org/pdf/2005.14165.pdf
⑸Constitutional AI: Harmlessness from AI Feedback, Anthropic,
https://arxiv.org/pdf/2212.08073.pdf
⑹Knowledge-Augmented Language Model Prompting for Zero-Shot Knowledge Graph Question Answering http://arxiv.org/abs/2306.04136
⑺WebGPT: Browser-assisted question-answering with human feedback (WebGPT), OpenAI, https://arxiv.org/pdf/2112.09332.pdf
⑻Automatic Chain Of Thought Prompting In Large Language Models
https://arxiv.org/pdf/2210.03493.pdf
⑼Orca: Progressive Learning from Complex Explanation Traces of GPT-4
http://arxiv.org/abs/2306.02707
⑽LORA: LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS
http://arxiv.org/abs/2106.09685
Introduction
古希腊哲学中有个罗格斯(logos)学派,罗格斯有“语言,话语”的含义,他们认为语言是人与人交流的媒介,人类的智慧就蕴含在语言之中。人类对如何让机器学会人类的语言这个艰巨的任务展开了数十年的研究,取得了丰硕的成果。对语言模型的研究大体可以分为四个阶段:
●Statistical language models (SLM):最简单的例子,使用最近的上文来预测the next word。假设S是句子,[w1, w2, …, wn]是句子里的词语,那么整条句子出现的概率可以表示为:
但是我们的窗口一般就选为3,也就是说使用前三个词语来预测后一个词语,因为随着估计阶数的增加(上下文扩大),时间和空间复杂度都随即呈指数级增长。他的思想其实和现在的自回归生成模型有点类似。
●Neural language models (NLM):代表作为RNN。
●Pre-trained language models (PLM):代表作为BERT,GPT2
●Large language models (LLM):大模型的定义多种多样,现在比较普遍的定义是百亿参数以上+具有涌现能力的模型叫做大模型。
大模型资源
目前常见的中文大模型有baichuan,ziya,glm,glm2。其中ziya是由英文大模型LLaMA经过词表扩充以及重新在中文语料进行预训练得到。
Baichuan:百川大模型-汇聚世界知识 创作妙笔生花-百川智能 (baichuan-ai.com)
Ziya:IDEA-CCNL/Ziya-LLaMA-13B-v1 · Hugging Face
Glm-6b:https://huggingface.co/THUDM/chatglm-6b
Glm2-6b:https://huggingface.co/THUDM/chatglm2-6b
GPT3.5 以及 GPT4接口
其他常见的实验对比用途的大模型有:LLaMA,LLaMA2,Vicuna,Chinese-Alpaca-13B,Chinese-LLaMA-13B,falcon。
大模型组成架构
Transformer分成左边红色框框里的encoder编码器和右边绿色框框的decoder解码器。
如果有对transformer完全不了解的读者,这里给出李宏毅老师的讲解课程(优先)以及李沐老师的论文带读供大家学习。
强烈推荐!台大李宏毅自注意力机制和Transformer详解!_哔哩哔哩_bilibili
Transformer论文逐段精读【论文精读】_哔哩哔哩_bilibili
Architecture
目前的模型架构大多是decoder-only,也就是丢弃transformer左边的encoder部分以及交叉注意力(上面的transformer图示中,蓝色框框框住的部分),只保留带掩码的注意力机制的decoder部分。
至于decoder-only为什么有效,我认为苏剑林这篇博客从矩阵的秩的角度来分析比较合理。为什么现在的LLM都是Decoder-only的架构?- 科学空间|Scientific Spaces
下面总结一下市面上的模型架构,大概可以分为三种:
Encoder-decoder架构,以T5,BART模型为代表。
Causal Decoder架构,以GPT系列为代表。
Prefix Decoder架构,修改了mask机制,使得在前缀tokens上有双向注意力,在生成的tokens上只有单向注意力。典型例子就是GLM-130B,强烈建议大家阅读论文原文。
GLM论文原文:http://arxiv.org/abs/2103.10360
拓展阅读(三种架构的比较):
https://blog.csdn.net/qq_35812205/article/details/130734021
Tokenizer
Hugging face提供的简易教程
https://huggingface.co/learn/nlp-course/chapter6/1
分词是整个pipeline中非常重要的一步。它将一条句子拆成一个个的tokens(token可能是一个word,也可能是某个word的前后缀或者中间的一部分,也叫做subword)以便将tokens放入词表(词表是一张包含了数千甚至数万个tokens的表,如果从句子中拆出来的token在词表里有记录,那么就可以找到对应的embedding向量,如果没有记录,则以’<unk>’符号代替)中查询,进行embedding。
如果有不知道embedding是什么的读者,可以了解一下embedding的经典方法word2vec。这里推荐Xin Rong博士(博士已经因为意外离开了我们,祝愿他在天堂幸福快乐)的论文:《word2vec Parameter Learning Explained》https://arxiv.org/pdf/1411.2738.pdf
目前最常见的体系是subword tokenizers。可以使用英语中的词根词缀来初步类比理解。将一个单词拆成一些小的部分,称为subword,这样可以有效防止词表不够大的困境。典型的方法包括Byte-Pair Encoding(BPE) tokenization,WordPiece tokenization,Unigram tokenization。
BPE
下面介绍BPE的步骤:
使用BPE的代表模型有:GPT2,BART,LLaMA。BPE有一个很大的缺点,那就是对于同一个单词,它可能会有好几种不同的表示方法。之后要介绍的unigram tokenization会有解决方法。
WordPiece
WordPiece和BPE非常像,稍微有一点点区别。为了合并,首先需要训练一个语言模型,使用它给所有的可能的pair打分。
思想就是introduction部分提到的统计语言模型。人们假设每个词语都有自己的上下文语境,那么我们就可以利用这一点来计算一条句子出现的概率有多大,例如给定前两个词的条件下第三个词出现的概率,再计算前三个词为条件时,第四个词出现的概率,如此算下去,最后将结果相乘,得分越高,就认为它就越像一条正常的,符合人类语言习惯的句子。
WordPiece每次合并选取的是使得整体分数更高的pair(合并之后重新给所有的pair进行打分)。使用WordPiece最典型的模型就是BERT。
Unigram tokenization
Unigram tokenization的宗旨是选择最可能的切分方法去解决BPE的问题。它开始于一大堆任何可能的子词和子字符串,然后逐步地从里面去除,直到词表大小达到要求。
Unigram 论文地址:
https://arxiv.org/abs/1804.10959
sentencepiece
上面提到的分词法,都是将输入句子以空格拆分,但是并不是所有的语言都是以空格分割的,而且根据空格拆分之后,也会因为信息损失而无法逆还原成原句子。
一个最简单的例子,例如[hello world.],hello和world之间有空格,world和符号。之间却没有空格。又比如英文的单词之间有空格,而中文,日语之间的词汇又没有空格。如果以人工编写的规则来实现,这些规则的编写和维护开销很高。
Sentencepiece做了如下两点优化:
l 将空格编码为’_’ (U+2581),保留在文本中。因为空格被保留,所以不会有什么歧义
l 将所有的输入都转化为unicode字符
缺点是为了优化多语言问题,有些特殊字符需要删掉,就变成了<unk>,如果想加上就使用tokenizer.add_tokens([’{’, ‘}’])
BPE、WordPiece和SentencePiece - 简书 (jianshu.com)
位置编码
由于self-attention是并行的,不像RNN串行那样天然地含有位置信息。而位置信息是非常重要的,因为一句话的词语稍微调换一下位置,就可能表达完全不一样的意思。所以我们需要手动加入位置信息。
位置信息又分为绝对位置信息和相对位置信息。
像bert那样,给512个位置每个位置训练出一个位置向量,就是绝对位置信息。它指明了谁是第一个token,谁是第二个token。这种添加位置信息的方法非常快速,但是十分不好拓展上下文长度。原因很显然,我的位置向量只有512个,再多就不能捕捉到位置信息了。
相对位置信息则代表让模型知道,token 1与token2相差多少个位置,比较灵活。
推荐一些学习位置编码的博客
Transformer位置编码:
https://kazemnejad.com/blog/transformer_architecture_positional_encoding/
让研究人员绞尽脑汁的Transformer位置编码 - 科学空间|Scientific Spaces
旋转位置编码:
旋转位置编码写于苏神的Transformer升级之路系列,推荐重点阅读,我们后面也会写一些文章对难点进行解析:
Transformer升级之路:1、Sinusoidal位置编码追根溯源 - 科学空间|Scientific Spaces
Transformer升级之路:2、博采众长的旋转式位置编码 - 科学空间|Scientific Spaces
上下文扩展
由于self-attention的复杂度是O(n^2),模型在训练时都会规定一个最大输入长度,这就是模型的上下文长度。如果碰到一些长文本领域(例如大模型检索领域,会检索出很多很长的文档,拼接在prompt里)很多模型的上下文长度就明显不够了,需要进行扩展,不然模型的能力会在上下文窗口之外降成弱智。
目前的研究来看,模型对内缩的接受程度比外扩更高,田渊栋团队提出了位置插值(PI),经过少于1000步的微调可以达到扩充模型上下文窗口的目的。所需操作非常简单,原来位置编码中的tokens所在的位置m是用整数表示的
但是经过研究,m用小数表示也是可以的,想要扩充几倍,就除几倍。举个简单的例子,如果一个模型的上下文长度是4,位置序列为0,1,2,3。扩展两倍后变成了0, 0.5, 1, 1.5, 2, 2.5, 3, 3,5, 4。也就是原来的上下文窗口位置数值边界不变,还是0-4,通过内插而不是外扩成0~7来扩大上下文窗口。
论文地址:http://arxiv.org/abs/2306.15595
其余解决方案有:ALIBI,NTK-RoPE(不用经过微调!),Sandwich等等。Baichuan 2-13B模型中就使用到了ALIBI。
ALIBI论文:《Train short, test long: Attention with linear biases enables input length extrapolation》
这里同样放上一些学习资料。
Transformer升级之路:7、长度外推性与局部注意力 - 科学空间|Scientific Spaces
Transformer升级之路:8、长度外推性与位置鲁棒性 - 科学空间|Scientific Spaces
Transformer升级之路:9、一种全局长度外推的新思路 - 科学空间|Scientific Spaces
Transformer升级之路:10、RoPE是一种β进制编码 - 科学空间|Scientific Spaces(提出了NTK-RoPE)
Transformer升级之路:11、将β进制位置进行到底 - 科学空间|Scientific Spaces
Transformer升级之路:12、无限外推的ReRoPE?- 科学空间|Scientific Spaces
Attention
Full attention
Attention非常好理解,下面这篇博客从数据库查询(key是作家的名字,value是作家写的书)的角度来解释自注意力机制。我认为对初学者理解self-attention非常有帮助
https://new.qq.com/rain/a/20230620A0207500
总体来说就是要计算每个位置对每个位置的注意力分数,得到一张sequence*sequence的注意力分数表(这就是为什么它的复杂度是O(n^2)),然后再乘上对应的value。
如何判断注意力分数的大小呢?通过k(key向量)和q(查询向量)的点乘大小来决定。通俗理解,在数学里,两个向量的点乘越大,代表它们两个向量的夹角越小,夹角越小就越相关,那么这个key向量代表的value向量对于最后的结果贡献更大,占比更重。
稀疏attention & 线性attention
在full-attention中,计算的复杂度是O(n^2),空间复杂度也是O(n^2),优化的道路大致分为两条,稀疏化和线性化。
https://spaces.ac.cn/archives/6853
线性Attention的探索:Attention必须有个Softmax吗?- 科学空间|Scientific Spaces
https://spaces.ac.cn/archives/7921
线性self-attention的漫漫探索路(1)---稀疏Attention - 知乎 (zhihu.com)
Multi-query attention
首先科普一下什么是多头注意力机制。原本的K、Q、V矩阵的形状都是sequence*embedding,其中sequence是句子的长度,embedding是向量长度。通俗理解多头注意力就是顺着embedding方向将矩阵劈开,现在每一个头都是sequence * embedding // head_num的大小。操作完成之后进行concat,然后再乘上一个投影矩阵整合收集每个子空间的信息。
(代码可以在cs224n的作业5,有一个mini-gpt的项目找到)
然后就可以看下面这篇博客,理解一下什么是Multi-query attention
https://zhuanlan.zhihu.com/p/634236135
通俗来说就是,只有Q矩阵还是sequence * embedding大小,即保留了所有的头,其余的K、V都只有sequence * embedding//head_num大小了,即只有一个公共头了。这样的话牺牲了一点点性能,但是非常节省缓存,提高解码速度。
Group Query Attention
GQA是对multi-head attention和multi-query attention的折中,并不是所有的query共享一对K、V,而是提出组这个概率,例如一组算两个的话,那就是两个query共享一对K、V。
具体可以看博客:
https://zhuanlan.zhihu.com/p/647130255
各种norm
batch Norm
主要是对不同样本的同一特征进行归一化。但是NLP领域中,一个batch中的句子通常是不等长的。所以NLP一般情况下不使用batch Norm。但是理解batch Norm对其他norm的理解会有帮助。
Batch Normalization原理与实战 - 知乎 (zhihu.com)
LayerNorm
LayNorm舍弃了batch的概念,但是操作依然是将Internal Covariate Shift纠正成标准正态分布,然后加上可学习的参数。也就是说,之前数据的分布肯定是有自己的形状,可能长得乱七八糟的,很大可能不是正态分布。
我们强行将它标准正态,那么我们加上了可学习的参数,为了让被纠正的分布去模仿原先分布的形状从而不会丢失太多信息。
RMSNorm:RMSNorm发现LayNorm分子的减去均值操作没用,于是将公式改成了下面这样:
分母的方差被替换成了RMS,这也是RMSNorm的由来。注意,因为并没有减去均值,所以也没有必要重新学习偏移(偏移信息并没有丢失),所以偏移B也被去掉。
RMSNorm的速度相较LayNorm提高了40%左右。
Pre-LN & Post-LN & DeepNorm
论文名称:
《On Layer Normalization in the Transformer Architecture》
《DeepNet: Scaling Transformers to 1,000 Layers》
Transformer初期提出的LayNorm位置并不合适,会导致模型参数量增大到一定程度时,出现难以收敛,性能严重下降的问题。将两个LayNorm分别换到attention之前以及FFN之前,就能有效解决训练稳定性问题。但是pre-LN的效果不如post-LN。
为什么Pre-LN效果不如Post-LN:
https://spaces.ac.cn/archives/9009
DeepNorm是微软提出的用来结合Post-LN的性能以及Pre-LN的稳定性的方法。被GLM-130B采用。
拓展博客:
【DL&NLP】再谈Layer-Norm:Pre-LN、Post-LN、DeepNorm - 知乎 (zhihu.com)
各种激活函数
激活函数总结(一):ReLU及其变体_relu的变体_sjx_alo的博客-CSDN博客
激活函数总结(八):基于Gate mechanism机制的激活函数补充(GLU、SwiGLU、GTU、Bilinear、ReGLU、GEGLU)_sjx_alo的博客-CSDN博客
下期预告
①GLM,LLaMA详细分析
②Deepspeed参数选取讲解
③各种微调方法与训练经验分享
④大模型推理加速框架
⑤笔者收集的大量开源数据集分享
⑥上下文学习
⑦CoT
⑧大模型评估
⑨大模型使用工具(langchain,IR检索系统,toolbench)