为什么transformer抓取序列信息更RNN更好?目前认为归纳偏置,所以抓取能力更弱,需要更大的模型。
1.单隐藏层的多层感知机
2.现代卷积神经网络
AlexNet
X = torch.randn(1, 1, 224, 224)
Conv2d output shape: torch.Size([1, 96, 54, 54])
ReLU output shape: torch.Size([1, 96, 54, 54])
MaxPool2d output shape: torch.Size([1, 96, 26, 26])
Conv2d output shape: torch.Size([1, 256, 26, 26])
ReLU output shape: torch.Size([1, 256, 26, 26])
MaxPool2d output shape: torch.Size([1, 256, 12, 12])
Conv2d output shape: torch.Size([1, 384, 12, 12])
ReLU output shape: torch.Size([1, 384, 12, 12])
Conv2d output shape: torch.Size([1, 384, 12, 12])
ReLU output shape: torch.Size([1, 384, 12, 12])
Conv2d output shape: torch.Size([1, 256, 12, 12])
ReLU output shape: torch.Size([1, 256, 12, 12])
MaxPool2d output shape: torch.Size([1, 256, 5, 5])
Flatten output shape: torch.Size([1, 6400])
Linear output shape: torch.Size([1, 4096])
ReLU output shape: torch.Size([1, 4096])
Dropout output shape: torch.Size([1, 4096])
Linear output shape: torch.Size([1, 4096])
ReLU output shape: torch.Size([1, 4096])
Dropout output shape: torch.Size([1, 4096])
Linear output shape: torch.Size([1, 10])
使用块的网络 VGG网络
X = torch.randn(size=(1, 1, 224, 224))
Sequential output shape: torch.Size([1, 64, 112, 112])
Sequential output shape: torch.Size([1, 128, 56, 56])
Sequential output shape: torch.Size([1, 256, 28, 28])
Sequential output shape: torch.Size([1, 512, 14, 14])
Sequential output shape: torch.Size([1, 512, 7, 7])
Flatten output shape: torch.Size([1, 25088])
Linear output shape: torch.Size([1, 4096])
ReLU output shape: torch.Size([1, 4096])
Dropout output shape: torch.Size([1, 4096])
Linear output shape: torch.Size([1, 4096])
ReLU output shape: torch.Size([1, 4096])
Dropout output shape: torch.Size([1, 4096])
Linear output shape: torch.Size([1, 10])
LeNet、AlexNet和VGG都有一个共同的设计模式:通过一系列的卷积层与汇聚层来提取空间结构特征;然后通过全连接层对特征的表征进行处理。AlexNet和VGG对LeNet的改进主要在于如何扩大和加深这两个模块。
网络中的网络(NiN)
如果使用了全连接层,可能会完全放弃表征的空间结构。网络中的网络(NiN)提供了一个非常简单的解决方案:在每个像素的通道上分别使用多层感知机。
NiN和AlexNet之间的一个显著区别是NiN完全取消了全连接层。相反,NiN使用一个NiN块,其输出通道数等于标签类别的数量。最后放一个全局平均汇聚层(global average pooling layer),生成一个对数几率(logits)。NiN设计的一个优点是,它显著减少了模型所需参数的数量。然而,在实践中,这种设计有时会增加训练模型的时间。
X = torch.rand(size=(1, 1, 224, 224))
Sequential output shape: torch.Size([1, 96, 54, 54])
MaxPool2d output shape: torch.Size([1, 96, 26, 26])
Sequential output shape: torch.Size([1, 256, 26, 26])
MaxPool2d output shape: torch.Size([1, 256, 12, 12])
Sequential output shape: torch.Size([1, 384, 12, 12])
MaxPool2d output shape: torch.Size([1, 384, 5, 5])
Dropout output shape: torch.Size([1, 384, 5, 5])
Sequential output shape: torch.Size([1, 10, 5, 5])
AdaptiveAvgPool2d output shape: torch.Size([1, 10, 1, 1])
Flatten output shape: torch.Size([1, 10])
含并行连结的网络(GoogLeNet)
Inception块相当于一个有4条路径的子网络。它通过不同窗口形状的卷积层和最大汇聚层来并行抽取信息,并使用1×1卷积层减少每像素级别上的通道维数从而降低模型复杂度。 GoogLeNet将多个设计精细的Inception块与其他层(卷积层、全连接层)串联起来。其中Inception块的通道数分配之比是在ImageNet数据集上通过大量的实验得来的。
相当于多个大小不同的卷积块获得的信息合并
X = torch.rand(size=(1, 1, 96, 96))
Sequential output shape: torch.Size([1, 64, 24, 24])
Sequential output shape: torch.Size([1, 192, 12, 12])
Sequential output shape: torch.Size([1, 480, 6, 6])
Sequential output shape: torch.Size([1, 832, 3, 3])
Sequential output shape: torch.Size([1, 1024])
Linear output shape: torch.Size([1, 10])
残差除了直接把x送过去外,还可能把x1乘1卷积块处理后送过去。
X = torch.rand(size=(1, 1, 224, 224))
Sequential output shape: torch.Size([1, 64, 56, 56])
Sequential output shape: torch.Size([1, 64, 56, 56])
Sequential output shape: torch.Size([1, 128, 28, 28])
Sequential output shape: torch.Size([1, 256, 14, 14])
Sequential output shape: torch.Size([1, 512, 7, 7])
AdaptiveAvgPool2d output shape: torch.Size([1, 512, 1, 1])
Flatten output shape: torch.Size([1, 512])
Linear output shape: torch.Size([1, 10])
残差映射可以更容易地学习同一函数,例如将权重层中的参数近似为零。
利用残差块(residual blocks)可以训练出一个有效的深层神经网络:输入可以通过层间的残余连接更快地向前传播。
稠密连接网络(DenseNet)
ResNet和DenseNet的关键区别在于,DenseNet输出是连接(用图中的[,]表示)而不是如ResNet的简单相加。
3. 循环神经网络(考虑了时间因素)
4.现代循环神经网络
GRU 门控循环单元
LSTM 长短期记忆网络
候选记忆元: ˜C t ∈ R (n×h)
记忆元:输入门I t 控制采用多少来自 ˜ C t 的新数据,而遗忘门F t 控制保留多少过去的记忆元C 的内容。
如果遗忘门始终为1且输入门始终为0,则过去的记忆元C t−1 将随时间被保存并传递到当前时间步。
解决了长期信息保存和短期输入缺失的问题。
输入门x候选记忆元和遗忘门x前一个记忆元。进行加和操作得到记忆元,进行输出门操作,得到h。
深度循环神经网络
当前时间段的前一个阶段隐藏层和前一个时间段的当前隐藏层。
我们可以将多层循环神经网络堆叠在一起,通过对几个简单层的组合,产生了一个灵活的机制。特
别是,数据可能与不同层的堆叠有关。例如,我们可能希望保持有关金融市场状况(熊市或牛市)的宏观数据可用,而微观数据只记录较短期的时间动态。l越小越短期,网络越深历史影响越大。
输出层的计算仅基于第l个隐藏层最终的隐状态 。
双向循环神经网络
可以根据后文来补充前文
代价:在训练期间,我们能够利用过去和未来的数据来估计现在空缺的词;而在测试期间,我们只有过去的数据,因此精度将会很差。
另一个严重问题是,双向循环神经网络的计算速度非常慢。其主要原因是网络的前向传播需要在双向层中进行前向和后向递归,并且网络的反向传播还依赖于前向传播的结果。因此,梯度求解将有一个非常长的链。
编码器-解码器架构
键决定权重,权重+值决定结果。
上下文变量在所有的时间步与解码器的输入进行拼接(concatenate)。为了预测输出词元
的概率分布,在循环神经网络解码器的最后一层使用全连接层来变换隐状态。并且softmax。
从技术上讲,编码器可以将长度可变的输入序列转换成形状固定的上下文变量c
嵌入层(embedding layer)来获得输入序列中每个词元的特征向量。 也就是使每一个词变成唯一的特征向量。词汇表中的索引转换为嵌入向量。
解码器的隐状态之后,我们可以使用输出层和softmax操作,得到最终概率:
实现解码器时,我们直接使用编码器最后一个时间步的隐状态来初始化解码器的隐状态
目标就是前一个时间步的y和隐藏状态s,通过全连接层,得到当前时间步的s和y。
束约束
上面得到的结果是贪心搜索,结果不一定是最优的。采用穷尽太耗资源。于是采用束搜索。贪心搜索可以看作一种束宽为1的特殊类型的束搜索。通过灵活地选择束宽,束搜索可以在正确率和计算代价之间进行权衡。
得到六个候选输出序列:(1)A;(2)
C;(3)A,B;(4)C,E;(5)A,B,D;(6)C,E,D。
其中L是最终候选序列的长度,α通常设置为0.75。分母中的L α 用于惩罚长序列。
注意力机制
每个值都与一个键(key)配对,可以通过设计注意力汇聚的方式,便于给定的查询(自主性提示)与键(非自主性提示)进行匹配,这将引导得出最匹配的值(感官输入)。
注意力权重就是查询。
Nadaraya-Watson核回归(非参数模型)
一个键x i 越是接近给定的查询x,那么分配给这个键对应值y i 的注意力权重就会越大,也
就“获得了更多的注意力”。
将查询x和键x i 之间的关系建模为 注意力权重(attention weight)α(x,x i ),这个权重将被分配给每一个对应值y i 。
对于任何查询,模型在所有键值对注意力权重都是一个有效的概率分布:它们是非负的,并且总和为1。
带参数注意力汇聚
带参数的模型加入可学习的参数后,曲线在注意力权重较大的区域变得更不平滑 。x坐标相当于key,y坐标相当于query。
注意力评分函数,前文的K(x)
加性注意力评分函数 查询和键是不同长度时使用
缩放点积注意力评分函数
计算效率更高,但是点积操作要求查询和键具有相同的长度d
Bahdanau 注意力的循环神经网络编码器‐解码器模型
ht就是st‘ 这里凑合看吧。目标就是前一个时间步的y和s
把 编码解码器模型中的上下文变量从不随预测时间步的变化改为随时间变化。更符合人类认知会随着更多的信息而改变。根据前一个预测的隐状态来对每一个输入词元打分,重新衡量上文中每一个词元的重要性。
s是解码器的隐状态,h是某个词元的隐状态,具有时间信息。
多头注意力
对于h个注意力汇聚输出,每一个注意力汇聚都被称作一个头(head)。
最后输出的这个张量h包含了经过一层编码器处理后序列中每个位置的新的表示向量。而且同时存在了多个向量。
多头注意力的输出需要经过另一个线性转换,它对应着h个头连结后的结果
hpv就是h个头,pv是每个value的权重,最后得到长度为po的一个注意力权重向量。一般:
p q = p k = p v = p o /h。从而方便计算。
全连接层把不同长度的key,value,query投射到同一个长度。然后一起放入注意力中学习。
自注意力和位置编码
自注意力和前面的点积注意力是一个性质
每个查询都会关注所有的键-值对并生成一个注意力输出。由于查询、键和值来自同一组输入,因此被称为 自注意力(self‐attention)
给定一个由词元组成的输入序列x 1 ,...,x n ,其中任意x i ∈ R d (1 ≤ i ≤ n)。该序列的自注意力输出为一个长度相同的序列 y 1 ,...,y n ,其中:
xi作为key,其余的作为key和value。用点积注意力评分函数。
MultiHeadAttention(
(attention): DotProductAttention(
(dropout): Dropout(p=0.5, inplace=False)
)
(W_q): Linear(in_features=100, out_features=100, bias=False)
(W_k): Linear(in_features=100, out_features=100, bias=False)
(W_v): Linear(in_features=100, out_features=100, bias=False)
(W_o): Linear(in_features=100, out_features=100, bias=False)
)
顺序操作会妨碍并行计算,而任意的序列位置组合之间的路径越短,则能更轻松地学习序列中的远距离依赖关系。也就是x1和x5路径越短,越容易学习二者之间的关系。
考虑一个卷积核大小为k的卷积层,由于序列长度是n,输入和输出的通道数量都是d,所以卷积层的计算复杂度为O(knd^ 2 ) 卷积神经网络是分层的,因此为有O(1)个顺序操作,最大路径长度为O(n/k)。例如,x 1 和x 5 处于卷积核大小为3的双层卷积神经网络的感受野内。
当更新循环神经网络的隐状态时,d×d权重矩阵和d维隐状态的乘法计算复杂度为O(d 2 )。由于序列长度为n,因此循环神经网络层的计算复杂度为O(nd 2 )。根据 图10.6.1,有O(n)个顺序操作无法并行化,最大路径长度也是O(n)。
在自注意力中,查询、键和值都是n × d矩阵。考虑到缩放的”点-积“注意力,其中n × d矩阵乘以d×n矩阵。之后输出的n×n矩阵乘以n×d矩阵。因此,自注意力具有O(n 2 d)计算复杂性。(n^2个矩阵元素,每个元素需要经过d次运算)
每个词元都通过自注意力直接连接到任何其他词元。因此,有O(1)个顺序操作可以并行计算,最大路径长度也是O(1)。
总而言之,卷积神经网络和自注意力都拥有并行计算的优势,而且自注意力的最大路径长度最短。而且解决长序列依赖问题(即x相互信息的传递)但是因为其计算复杂度是关于序列长度的二次方,所以在很长的序列中计算会非常慢。但是忽视了位置信息。
位置编码
绝对位置信息:位置编码通过使用三角函数在编码维度上降低频率。直接反映在i的大小。
相对位置信息:上述的位置编码还允许模型学习得到输入序列中相对位置信息。这是因为对于
任何确定的位置偏移δ,位置i + δ处的位置编码可以线性投影位置i处的位置编码来表示。
PE就是p函数,包含位置信息。
一个东西,只不过下面的矩阵更官方,看起来更厉害。(相对位置的旋转矩阵,妙!!!有一种螺旋上升的感觉)
Transformer
Transformer模型中,三个embedding层(编码器输入embedding层、解码器输入embedding层和输出softmax之前的embedding层)可以共享参数
-
编码器的输入是输入序列的词嵌入(word embedding)表示,这个embedding层位于编码器的开头,用于将输入词汇序列中的每个词转换成密集的词嵌入向量表示,以供后续的处理。
- 在解码器端,与编码器输入embedding层类似,解码器的输入也需要经过一个embedding层,将目标语言中的词嵌入转换成密集向量表示,以便解码器能够处理和生成目标语言的序列。
- 在解码器的输出端,在计算最终的softmax概率分布之前,通常会存在一个embedding层,作用是将解码器的隐藏表示映射到词汇表的维度,以便通过softmax计算输出序列中下一个词的概率分布。
编码器,解码器的embedding把源语言转换为中间态特征。
用编码器中间态特征经过注意力机制的隐状态作为key,value。
用解码器中间态特征经过掩蔽注意力机制的隐状态作为query获得其中高度相关部分,形成过渡语言特征。最后对过渡语言再次转换为中间态特征,并进行softmax获得目标语言的概率。
源就是问题(中文),目标就是要生成的回答。(英文)
解码器这里输入是output,是因为解码器是自回归模型,之前时刻的输出是当前时刻的输入
所以要掩蔽未预测的目标结果。因为结果是一个一个蹦出来的。
对序列中的所有位置的特征向量进行变换时使用的是同一个多层感知机(MLP),这就是称前馈网络是基于位置的(positionwise)的原因。(不同时间步使用同一个MLP)
一维卷积就是在直线上的卷积核。卷积是批次x通道xdimension。(如alexnet一样,最后把通道和特征融合了一起送进全连接层)但是对于语言模型而言,n也就是通道会随着输入发生改变。我们用每一个词去预测结果。
在下面的实现中,输入X的形状(批量大小,时间步数或序列长度,隐单元数或特征维度)将被一个两层的感知机转换成形状为(批量大小,时间步数,ffn_num_outputs)的输出张量。
加法和规范化(add&norm)组件。这是由残差连接和紧随其后的层规范化组成的。两者都是构建有效的深度架构的关键。
batchnorm
是对一个batch里不同图片的同一个特征进行norm,而layernorm是对一个batch的一个句子的所有词元向量进行归一化。
编码器
第一个子层是多头自注意力(multi‐head self‐attention)汇聚;第二个子层是基于位置的前馈网络(positionwise feed‐forward network)。
先实现编码器中的一个层:
X = torch.ones((2, 100, 24))
valid_lens = torch.tensor([3, 2])
encoder_blk = EncoderBlock(24, 24, 24, 24, [100, 24], 24, 48, 8, 0.5)
encoder_blk.eval()
encoder_blk(X, valid_lens).shape
torch.Size([2, 100, 24])
Transformer编码器中的任何层都不会改变其输入的形状。
目前的理解:编码器出来的是key自身的各种关系。也就是hi(每个词元的隐状态)。用最后一个时间步词元的隐状态初始化解码器的隐状态。
解码器
除了编码器中描述的两个子层之外,解码器还在这两个子层之间插入了第三个子层,称为编码器-解码器注意力(encoder‐decoder attention)层。在编码器-解码器注意力中,查询来自前一个解码器层的输出,而键和值来自整个编码器的输出。在解码器自注意力中,查询、键和值都来自上一个解码器层的输出。
解码器中的每个位置只能考虑该位置之前的所有位置。这种掩蔽(masked)注意力保留了自回归(auto‐regressive)属性,确保预测仅依赖于已生成的输出词元。和后面无关。
valid_lens = torch.tensor([3, 2])
有一个查询张量为Q,键张量为K,值张量为V,都是形状为 (2, 4, 100) 的张量。
这里的2代表batch_size,4是num_queries,100是num_hiddens。
那么第一个批次(下标为0),有效长度为3,这意味着只有前三个query是有效的
第二个批次前两个有效
预测
一个句子的第一个词是bos,根据这个词作为query开始从编码器的key-value中获得第一个词,之后自回归直到eos