零、如何读论文
读三遍:
1. 第一遍
读完标题和摘要后,直接跳到结论,这几个部分读完就大概知道文章在讲什么东西了,之后还可以看一下正文中的图表,判断一下这篇文章是否适合自己,是否要继续读;
2. 第二遍
按顺序通读一遍全文,了解文章中的图表、方法都在干什么,有什么特点,这期间遇到不懂的细节可以先做标记,之后如果要精读再去研究引用的相关论文。读完之后根据需要选择是否需要精读;
3. 第三遍
精读,读的时候思考如果是我来做我会怎么做,想象自己来实现整篇文章。
一、AlexNet
AlexNet 是深度学习的奠基之作,其精髓在于它首次成功证明了深度卷积神经网络(CNN)在大规模图像识别任务上的卓越性能,并引入或有效推广了几项关键技术和设计理念。
1. 深度网络的可行性
AlexNet 拥有 8 层学习层(5 个卷积层 + 3 个全连接层),这在当时是“非常深”的网络。它在ImageNet上的成功证明了深度网络的可行性;它的架构展示了深度学习的过程就是一个知识的压缩过程,将原始信息的尺寸(size)逐渐压缩,但信息密度(channel)逐渐增大,将人类能看懂的一个个像素压缩成机器能看懂的向量。
AlexNet整体架构
2. ReLu的应用
激活函数使用ReLu而不是当时常用的tanh和sigmoid,发现训练速度要更快。虽然当时认为ReLu更快的原因现在看来都不是很对,但现在仍然流行ReLu,因为它更简单。
3. 多GPU训练
受限于当时 GPU 显存,模型被拆分成两部分,分别在两块 NVIDIA GTX 580 GPU 上并行训练,并在特定层进行通信。这启发了后续更大模型的分布式训练策略。
4. 重叠池化
使用步长 (stride=2) 小于池化窗口大小 (size=3) 的池化操作。相比于传统的非重叠池化 (stride=size),重叠池化能略微提升精度,并有助于减轻过拟合(通过引入轻微的空间平移不变性扰动)。它代表了池化操作的一种优化选择。
5. Dropout的应用
Dropout就是在训练期间,以一定概率(前两个全连接层设为 0.5)随机将神经元的输出置零。在当时人们会采用模型融合(结合多个模型的预测结果)来避免过拟合,但是对于本身就需要数天来训练的深度网络来说成本太昂贵了,所以作者使用了Dropout,认为其效果相当于每次输入就得到一个新模型,等价于模型融合。不过后来的研究发现Dropout更多等价于一个L2正则项。
6. 数据增强
采用图像平移和水平翻转(生成位置和镜像变化)、改变 RGB 通道强度(使用 PCA 对 RGB 像素值进行扰动,模拟光照和颜色变化)等技术来扩充训练数据,利用有限的数据生成更多的训练样本,提高模型的泛化能力,是缓解过拟合的关键且成本低廉的方法。
二、ResNet
ResNet的精髓在于使用了Residual Connection(残差连接)来更好地训练很深的网络,避免了退化问题和梯度消失问题。所谓退化问题指网络较浅时效果好,加深后反而不好,这不合常理,因为如果更深的层次没用,将其设为恒等映射也不至于效果更差。
1. Residual Connection
残差连接就是将浅层的输出跳跃到深层的输出处将两者相加,使网络学习残差映射(F(x) = H(x) - x)而不是目标映射 (H(x))。若最优映射接近恒等变换(H(x) = x),则学习残差 F(x) → 0 比学习完整映射更易优化。
另外残差连接还解决了梯度消失的问题,使得训练更快。梯度消失是指由于反向传播中使用了求梯度的链式法则,如果梯度都是小于1的,连乘之后会接近0导致梯度消失。而残差连接的输出是F(x) + x,其梯度由于加法的存在不会变为0,避免了梯度消失问题。
梯度公式
2. Bottleneck Block
当层数比较深时输入输出的通道数会比较大,这时如果直接计算的话复杂度会比较高,ResNet采用了Bottleneck Block的设计,先使用1*1的卷积对输入进行降维,计算以后再用1*1的卷积对输出进行升维还原回原来的维度,这样可以将复杂度降低到与降维之后的通道数差不多。
Building Block (左) Bottleneck Block (右)
三、Transformer
《Attention Is All You Need》是近年来机器学习领域最重要的文章之一,提出了Transformer架构。在这篇文章之前,seq2seq模型基本都是使用基于复杂的RNN或CNN的encoder-decoder架构,再在encoder和decoder之间使用attention机制,而RNN不能并行训练,CNN一次只能看到一个小窗口(卷积核)内的信息,需要经过多层卷积才能融合两个隔得远的信息,而这篇文章提出的Transformer架构只使用attention机制,没有前面二者的缺点,在效果和性能上都比之前的模型要好。
1. Model Architecture
Transformer的总体架构如下图,是encoder-decoder结构:
左边的encoder将token序列经过embedding和positional encoding后,得到长为n的向量序列,这些序列经过N个encoder block的处理,输出长为n的融合了序列信息的向量序列,然后接到decoder每个块的cross attention的输入;
右边的decoder将token序列经过embedding和positional encoding后,使向量序列经过N个decoder block的处理,得到输出向量序列,再将这些向量经过Linear层和Softmax层,得到一个分布,从这个分布中argmax或采样得到输出token,然后将这个token加入到输入token序列的末尾,继续重复前面的过程。
Transformer架构图
1)Encoder Block
每个Encoder Block由两个子层组成,第一层是Multi-Head Attention,第二层是Feed Forward,每个子层后面都有残差连接 (Add) 和Layer Norm. 这里选择Layer Norm而不是Batch Norm是为了使模型在训练 (批量) 和推理 (单个样本) 时行为一致。
2)Decoder Block
每个Decoder Block由三个子层组成,第一层是Masked Multi-Head Attention,第二层是将Encoder的输出以及上个子层的输出作为输入,进行Multi-Head Cross Attention,第三层是Feed Forward,每个子层后面都有残差连接 (Add) 和Layer Norm. 由于推理过程中输出向量是一个一个出来的,每个输出向量只能看到之前的向量,而训练时self attention可以看到完整的序列,为了使模型在训练和推理时行为一致,第一层使用Masked来保证每个向量看不到后面的向量。
2. Scaled Dot-Product Attention
Attention机制就是将输入向量变换为3个向量,分别是query, key和value,然后根据query和key算出相似度α,并经过softmax得到权重,最后计算value的weight sum得到输出。而注意力的计算通常有两种方法,一种是加法注意力机制,通常用于处理query和key不等长的情况;另一种是点乘注意力机制,需要query和key等长。虽然二者理论复杂度一样,但点乘可以更好地利用并行性,实际计算更快。Transformer使用的是后者,不同的是它还除了一个根号dk,因为在dk比较大时(Transformer中是512)α之间会相差得比较大,经过softmax之后就会更向两端 (0和1) 靠拢,这样的话算梯度时会发现梯度比较小,因为softmax向两端靠拢时表示收敛得差不多了,所以需要通过除以一个根号dk来减少差距。
另外对于mask机制,是通过在softmax之前将想要掩盖的数全部换成很大的负数,从而在经过softmax之后变为0实现的(如果在softmax之后直接置零会导致和不为1)。
Scaled Dot-Product Attention示意图和公式
3. Multi-Head Attention
为了像CNN一样有多个输出通道来抓取多个特征,Transformer采用了Multi-Head Attention机制,将Q, K, V线性投影到h个低纬度,然后经过h次Scaled Dot-Product Attention得到h个低维输出向量,最后将这h个向量拼接在一起再通过线性层进行一次投影得到最终的输出。
Multi-Head Attention示意图和公式
4. Cross Attention
Decoder Block中的第二个子层负责将Encoder的输出信息融合进来,因此这一层attention的key和value来自于Encoder的输出,而query来自上一子层,通过Cross Attention获得Encoder输出与Decoder Block上一子层输出的相关性并将Encoder输出的加权信息融合进来。
5. Position-wise Feed-Forward NetWorks
为了加深每个position的信息表示能力,Encoder Block和Decoder Block最后都有一层FFN (Feed-Forward Network),对每个position作用相同的FFN进行非线性映射,提取更复杂的局部特征。Transformer的FFN就是MLP,由两个全连接网络组成,中间有一个ReLu激活函数,并且其中W1为512*2048的矩阵,用于将输入维度扩大4倍到2048,最后W2再投影回512.
在RNN中也是使用MLP做语义转换的,只不过它在MLP做完语义转换后直接将其输出传到下一次的输入,而Transformer是先提取位置间信息再单独对每个位置进行语义转换。
FFN公式
Transformer与RNN中MLP的对比
6. Position Encoding
由于Attention不像RNN和CNN一样自带位置信息,所以需要在Embedding之后与位置编码向量相加来加入位置信息。Transformer使用的是正弦位置编码,公式如下,其中pos表示token在序列中的位置,i表示编码向量中的第几对维度对 (从0到255,因为一对 sin 和 cos 占据两个维度:第 2i 维和第 2i+1 维),d表示编码的总维度 (512, 和Embedding向量维度相同).
正弦位置编码公式
四、GNN
GNN是用于解决图结构数据的预测问题的,本质是一种对图的所有属性(顶点,边,全局信息)的可优化变换,这种变换是具有排列不变性的,也就是图的顶点顺序不会影响结果。
1. 图在神经网络中的表示
顶点和边的属性用一个集合表示,其值可以是标量也可以是向量。对于图的连接性的表示使用邻接列表法,也就是稀疏矩阵表示法,节省空间。
图的表示
2. 简易版GNN
对所有顶点使用同一个MLP进行更新,对所有边使用同一个MLP进行更新,对所有全局信息使用同一个MLP进行更新,就得到了一个输出图,这样的操作符合GNN的定义(排列不变性的可优化变换),这就是一个简易版的GNN.
简单的GNN示意图
3. 预测和池化
GNN输出一个图后就可以对这个图进行预测了,以最简单的顶点二分类为例,就是对每个顶点应用分类器,得到结果即可。
分类预测
但是有时候我们可能只有边的信息而没有顶点的信息,预测顶点分类依然需要顶点信息,这时可以使用池化技术,以求和池化为例,将顶点所连的边的向量求和作为顶点的向量。同理了对边进行预测时也可以将边所连的顶点向量求和作为边的向量。
顶点求和池化
当整个图都只有边的信息时可以对所有顶点都通过池化来进行顶点预测。
只有边的图进行顶点预测
4. 消息传递
前面的简易版GNN是对每个顶点每条边单独进行更新的,这没有考虑到图的连接上下文。这一问题可以通过消息传递来解决:对每个顶点将它与它相连的所有顶点或边的信息聚合起来,用聚合后的信息作为MLP变化层输入。这样就可以充分利用到图的连接上下文了。
消息传递
如果图只有顶点或只有边,可以先池化再进行消息传递。
池化+消息传递
如果图非常大,两个离得很远的顶点信息要传递过去需要经过很多步,可以通过设置一个连接所有顶点和边的虚拟顶点来解决,这个虚拟顶点抽象出来的信息就是前面的全局信息U.
全局信息U的消息传递
五、GAN
GAN有两个模型,模型G (Generator) 负责拟合训练数据的分布 (也就是拟合概率密度),模型D (Discriminator) 负责评估一个样本是来自训练数据还是来自G的概率,在训练过程中G要尽可能骗过D,而D要尽可能分辨出G生成的样本。两个模型都是MLP,在对抗的过程中得到训练,最终的理想情况是G生成的分布完全拟合训练数据的分布,并且D无法分辨二者 (输出永远是1/2).
1. 对抗模型
设G的分布为pg (p代表概率密度),其随机变量为x,定义一个服从分布pz (一般为高斯分布) 的噪音变量z,G(z)的作用是将z映射到x. (以800万像素的游戏图片生成为例,假设z是100维的向量,代表游戏中人物地点等变量,x为800万维的向量,代表800万像素点,G就负责将z映射到x)。而D的输出是一个标量,D(x)表示x是来自训练数据的概率。我们的目标是训练D以最大化给来自训练数据的样本 (x ~ pdata) 和G生成的样本 (G(z) ~ pg) 打上正确标签的概率,在公式中表示就是最大化logD(x)的期望和log(1 - D(G(z)))的期望;同时训练G以最小化log(1 - D(G(Z))),在公式中表示就是最小化log(1 - D(G(z)))的期望。不过在训练的早期G还很弱,D(G(z))趋于0,log(1 - D(G(z)))的梯度会非常小,不利于训练,如果改为最大化logD(G(z))就会好很多。
GAN的价值函数
GAN的算法伪代码
下图是GAN的训练过程,黑点是训练数据,绿色实线是G生成的分布,由z映射而来,蓝色虚线是D的输出。(a) 是最初的状态,pg与pdata相差较大,D的输出正确率低;(b) 是D经过训练后能很好地分辨pg和pdata;(c) 是G经过训练后为了骗过D使pg更加拟合pdata;(d) 是最终的状态,pg完全拟合pdata,D的输出始终是1/2.
GAN的训练过程
2. 理论结果
1)最优的D
在给定G的情况下,最优的D为,其中p(x)表示某个x在该分布中的概率密度。证明如下:要使V这个积分最大,就是使a*log(y) + b*log(1-y)取最大值,当且仅当y = a/(a+b)时满足,也就是D(x) = pdata(x) / (pdata(x) + pg(x)).
可以发现当pdata与pg完全拟合时D*输出恒为1/2.
2)最优的G
将最优的D代入到价值函数中,会得到如下式子:
对两个log进行如下变形
可以发现这就是pdata和(1/2)*pdata+pg这两个分布的KL散度,写成如下形式,由于KL散度大于等于0,当且仅当pdata = pg时取0,故pdata = pg时C(G)最小,也就是G最优。
补充知识:KL散度,描述两个分布的相似程度的量,定义如下,表示p和q两个分布的KL散度。
3)对抗收敛
在对抗过程中如果每次D和G都能到最优,则最终pg会收敛于pdata. 证明略。
六、BERT
BERT是一种基于Transformer架构的预训练模型,使用微调来适应下游任务。其最主要的特点是双向性,相比于GPT这类decoder only的单向模型 (只能从左往右读),encoder only的BERT可以更好地理解上下文。不过虽然说是encoder only,如果将最后的全连接层看作decoder的话BERT也是一个带掩码的encoder-decoder架构,这对后面MAE的理解有帮助。
BERT预训练-微调示意图
1. Model Architecture
BERT的架构基于Transformer的Encoder,超参数设置如下:BERTBASE (L=12, H=768, A=12, Total Parameters=110M) and BERTLARGE (L=24, H=1024, A=16, Total Parameters=340M). 其中L是Transformer blocks的块数,H是embedding的维度,A是注意力头的个数。根据这些超参数和Transformer Encoder的架构可以算出总的可学习参数量:
由超参数计算可学习参数
2. Input Representation
BERT的Embedding使用WordPiece进行切词,共有30k个token。BERT的输入可以是一个句子也可以是一对句子 (如<Question, Answer>),不管是哪种都将其整体视为一个序列。输入序列总是以一个特殊的classification token开头 ( [CLS] ),其最终输出代表了整个序列的信息。为了区分输入的两个句子,BERT会在两个句子之间添加一个特殊的separate token( [SEP] ),此外还会学习出一个segment embedding来表示该token是属于句子A还是句子B。对于一个token来说,它的input representation是对应的token,segment embedding和position embedding的和。
BERT的input representation
3. Pre-training
BERT使用无监督学习进行预训练,主要有两个任务。
1)Masked LM
BERT通过掩码预测来训练模型对上下文的理解能力。具体的做法是,在Wordpiece生成一个token时,有15%的概率将其随机替换成一个“掩码”([CLS]和[SEP]不会被替换),这个“掩码”有80%几率是 [MASK] 这个特殊token,有10%几率是一个随机的token,还有10%几率不变。然后该token对应的最终输出会被用于预测原始token,使用cross entropy损失函数。
“掩码”示例
2)Next Sentence Prediction
BERT通过下个句子预测来训练模型对两个句子之间关系的理解能力。具体的做法是,在训练资料中有50%句子A的后面接的是正确的句子B,标为 (IsNext),还有50%句子A的后面接的是无关的句子B,标为 (NotNext),然后根据 [CLS] 的最终输出判断是否是正确的句子。这样可以显著提升模型的Q&A能力和自然语言推理能力。
NSP示例
4. Fine-tuning
BERT的微调很简单,直接使用相应的输入输出训练即可,并且BERT可以更好地处理句子对,不需要像传统的方法那样分别编码两个句子再做cross attention,只需要把两个句子拼在一起就行了。对于输入,如果是句子对的任务则句子A和句子B都要放入输入,如果是只有一个句子的任务则句子B为空。
各类任务微调方式
七、ViT
ViT的主要思想就是将图像分为一堆16*16的patch,然后拉平把这些patch丢进Transformer的Encoder来做CV任务。这不仅对CV领域有重大意义,还对多模态领域有重大意义,因为他统一了NLP和CV的网络架构。
1. Model Architecture
ViT的模型架构和BERT基本相似,除了Layer Norm的位置提前到了每个Sub-Layer之前 (即Pre-Norm,这样有利于训练稳定性和深层网络收敛,现代Transformer大多采用Pre-Norm),以及针对图像输入进行了特殊的预处理。
ViT模型架构
预处理的具体做法是:以224*224的图像为例,将其分割为16*16的patch,总共196个patch,每个patch拉平为长16*16*3 = 768 (3是RGB) 的向量,则是一个196*768的矩阵,将这个矩阵放入线性投影层,即乘以一个768*D (D是Transformer的向量维度) 的投影矩阵,得到最终的输入patch. 预处理完毕后拼接上 [CLS] token再加上位置编码就得到Transformer Encoder的输入了。
ViT算法表示
2. Position Encoding
ViT的位置编码采用的是1D位置编码,即没有考虑图像的平面性,作者试过2D位置编码,即从X轴和Y轴分别编码,每个编码长为D/2,之后再拼接起来,但效果和1D编码差不多,推测是由于图像分割为patch后空间分辨率比较小,1D编码就足够学到位置信息的表达了。
1D和2D编码示意图
3. 和CNN对比
ViT和CNN的主要区别就是ViT的有更少的图片特有的归纳偏置。在CNN中局部性、平移等变性和2D结构特性贯穿整个模型,而ViT中只有MLP中用到了局部性和平移等变性,以及分割patch时用了2D结构性。这就使得CNN学习更快,在小数据集上效果更好,但模型受限,而ViT学习慢,在大数据集上效果更好,可以拟合更复杂的模型。
作者也尝试过把两者混合了一下,即在图像预处理中直接使用CNN将其变为14*14 = 196的特征图,然后做Embedding并放入Transformer. 混合架构的效果在小数据集上比原始ViT好,但大数据集上还是不如原始ViT.
分割patch (上) 与使用CNN (下)
4. Self Supervision
在NLP领域Transformer能火起来除了他的效果好以外还有一个很重要的原因,就是大规模的自监督训练, 那么在CV领域这也是一个重要的研究方向,这样才能让NLP和CV做到真正的大一统。作者使用了Masked Patch Prediction,即将某些patch抹掉,再让模型将patch重建出来,这样虽然比有监督学习的效果还是差了4个百分点,但后续使用对比学习这种最好的自监督学习方式的模型 (MoCo v3,DINO)做得很不错。
八、MAE
如果说ViT是CV版的Transformer,那么MAE是CV版的BERT,他使得自监督训练在ViT上的应用更加普及. MAE的主要思想是将图像分割为patch后随机掩盖大部分patch (如75%),用剩余的patch去训练一个encoder,然后将encoder的输出和被掩盖的patch去训练一个decoder还原成原图像。这样做有两个好处:一是只对剩余patch做encoding可以节省开销;二是掩盖大部分patch可以让decoder学到更多东西,因为像素的信息密度小,掩盖太少的话decoder只能学到一些简单插值。
MAE Model Architecture
1. CV和NLP中掩码自编码的差异
掩码自编码 (Masked Encoding) 的思想在CV和NLP领域都有应用,但在CV领域的应用始终不如NLP领域,作者认为有如下原因:
(i) CV在以前一直是CNN架构为主流,在CNN中不好使用masked,因为卷积核扫过图片时不好区分那一部分是否masked. 这一点现在由于ViT的提出已经解决了;
(ii) 图像和语言的信息密度不同,语言中一个词就代表一定意义,而图像中每个像素是比较冗余的,某一部分去掉了可以直接通过对相邻像素进行插值还原出来。这一点可以通过大量掩码解决。
(iii) 在NLP中decoder是预测具有丰富语义的单词,一个MLP就够了,而在CV中decoder需要重构像素,这是低语义层次的表示,难度更大,因此需要更复杂的decoder.
2. Model Architecture
和其他autoencoder模型一样,MAE也是使用一个encoder将观察到的信号映射到一个潜表示,然后再通过decoder用这个潜表示去重构出原始的信号。不一样的是MAE是非对称的encoder-decoder,因为他的encoder只能看到未被masked的patch,这样可以节省开销。
1)Masking
为了让模型学到更多东西,masking ratio要足够高,并且为了更均匀的masking,我们使用随机采样来选择要mask的patch,避免center bias,其中被mask的patch直接移除,而不是使用mask token.
2)Encoder
MAE encoder和ViT的一样,要将patch先经过线性投影再加上位置编码变为token,只不过他的Transformer blocks的输入只有unmasked tokens,这样可以大幅降低计算成本,并且实验结果显示效果比使用mask token要更好。
3)Decoder
MAE decoder的输入是encoder的输出以及mask tokens,其中所有的mask tokens都是一个共享的学习出来的vector,表示了需要被预测的patch,另外这些token还要重新加上一次位置编码,也就是encoder输入加了一次位置编码,这里decoder输入又要加一次,因为encoder的抽象输出不会直接传递位置编码给decoder,decoder需要自己重新构建位置编码。
MAE decoder是一个轻量级的ViT,计算成本很低,并且只用于预训练,不用于推理,只有encoder被用来产生图片表示以供下游任务使用。
4)Reconstruction target
Decoder的每个输出都是一个向量,对应了一个patch中每个像素的值,最后会被reshape成图像的形状。损失函数使用的是MSE,并且只在masked patch上面计算。另外还可以对每个patch中的像素进行归一化,获得更稳定的数值。
5)Simple Implementation
一种简单的实现方法如下:首先对每个patch进行线性投影再加上位置编码变为token,然后进行randomly shuffle,根据masking ratio将后面的token直接移除,在encoding之后,在输出token序列后面添加上mask token变为原来的长度,然后进行unshuffle (就是前面shuffle的逆操作),再加上一次位置编码,最后丢给decoder进行重构。