[DL/论文阅读](卷积神经网络)


CNN组件

CNN架构

为什么使用CNN?
在这里插入图片描述
在这里插入图片描述
如果只是简单的用全连接层做模型的话,那么它的参数会巨大
在这里插入图片描述
随着参数的增加,我们可以增加他的弹性/能力,但也增加了过拟合的风险

但实际上,做图像识别是不需要这么多参数的,所以从两个方面考虑简化:

(1)Receptive field

如同人类识别鸟是通过鸟的特征,而不是整张图片一样,一个neuron也并不需要观察整个图片,而只用观察到鸟的pattern。patten在的地方,就是receptive filed。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
把这一块333的receptive field,变成一个27维列向量,传入Neural
在这里插入图片描述

当然,不同的Neural可以守卫任意receptive field。receptive field也可以只包含一个channel,但是CNN一般不这样搞。当然receptive field也不一定非要正方形

Receptive field存在的意义是抓pattern,所以,对于不同的目标,可以自己设计receptive field 的size,3×3,5×5都可以。size的形状也可以自己设定。
虽然receptive field size可以设置的比较小,但是它能学习到比较大的pattern
在这里插入图片描述
我们是希望两个receptive field是有重叠的,如果pattern正好出现在两个感受野交界上面。
如果stride后超过边界了怎么办?做padding,也就是补零

(2) Weight Sharing
在这里插入图片描述

特征不会说固定出现在一个地方,比如鸟嘴不会总在左上方出现,而是有可能出现在图片的中央、右上方等,但位置的改变没有改变本质,鸟嘴还是鸟嘴。如何利用这个特性简化模型呢?

在这里插入图片描述
在这里插入图片描述
不同的neuron计算时共享相同的参数,但是由于input不同,所以output也会不同。负责同一个receptive field 的neuron不会共享参数。

在这里插入图片描述
假设一共有64组不同的参数,(实际上,一个filter就是其中的一组参数),对于同一个 receptive field,64个filter都会参与计算。而到了下一个receptive field, 还是这64组参数作为w ,与作为x 的input计算产生output。
这时,一个CNN初步成型了。

padding填白

参考
在这里插入图片描述
从上面我们可以知道,原图像在经过filter卷积之后,变小了,从(8,8)变成了(6,6)。假设我们再卷一次,那大小就变成了(4,4)了。

这样有啥问题呢?
主要有两个问题:

  1. 每次卷积,图像都缩小,这样卷不了几次就没了;

  2. 相比于图片中间的点,图片边缘的点在卷积中被计算的次数很少。这样的话,边缘的信息就易于丢失。

为了解决这个问题,我们可以采用padding的方法。我们每次卷积前,先给图片周围都补一圈空白,让卷积之后图片跟原来一样大,同时,原来的边缘也被计算了更多次。通过填充的方法,当卷积核扫描输入数据时,它能延伸到边缘以外的伪像素,从而使输出和输入size相同。
在这里插入图片描述
比如,我们把(8,8)的图片给补成(10,10),那么经过(3,3)的filter之后,就是(8,8),没有变。

我们把上面这种“让卷积之后的大小不变”的padding方式,称为 “Same” 方式,(进行填充,允许卷积核超出原始图像边界,并使得卷积后结果的大小与原来的一致)
把不经过任何填白的,称为 “Valid”方式。这个是我们在使用一些框架的时候,需要设置的超参数。(不进行任何处理,只使用原始图像,不允许卷积核超出原始图像边界)

pooling池化

比如max pooling, 不会学习任何参数,只是减少计算量的手段
在这里插入图片描述
在这里插入图片描述
pooling的主要作用就是减少运算量

这个pooling,是为了提取一定区域的主要特征,并减少参数数量,防止模型过拟合。
比如下面的MaxPooling,采用了一个2×2的窗口,并取stride=2:
在这里插入图片描述
除了MaxPooling,还有AveragePooling,顾名思义就是取那个区域的平均值。

QA1:pooling层的作用:

池化层的一般作用是对特征图进行下采样,它本身没有参数权重,计算也简单,但它可达到降维特征(将低层次组合为高层次的特征)、突显特征、减少参数量、减少计算量、增加非线性、防止过拟合及提升模型泛化能力等作用

QA2:pooling层的反向传播:

池化层的前向传播我们都比较好理解,但是其是如何参与反向传播的呢?

池化层在反向传播时,它是不可导的,因为它是对特征图进行下采样会导致特征图变小,比如一个2x2的池化,在L+1层输出的特征图是16个神经元,那么对应L层就会有64个神经元,两层之间经过池化操作后,特征图尺寸改变,无法一一对应,这使得梯度无法按位传播。那么如何解决池化层不可导但却要参与反向传播呢?

在反向传播时,梯度是按位传播的,那么,一个解决方法,就是如何构造按位的问题,但一定要遵守传播梯度总和保持不变的原则

对于平均池化,其前向传播是取某特征区域的平均值进行输出,这个区域的每一个神经元都是有参与前向传播了的,因此,在反向传播时,框架需要将梯度平均分配给每一个神经元再进行反向传播,相关的操作示意如下图所示。
在这里插入图片描述
对于最大池化,其前向传播是取某特征区域的最大值进行输出,这个区域仅有最大值神经元参与了前向传播,因此,在反向传播时,框架仅需要将该区域的梯度直接分配到最大值神经元即可,其他神经元的梯度被分配为0且是被舍弃不参与反向传播的,但如何确认最大值神经元,这个还得框架在进行前向传播时记录下最大值神经元的Max ID位置,这是最大池化与平均池化差异的地方,相关的操作示意如下图所示。
在这里插入图片描述
其中,上述表格中,前向传播时,每个单元格表示特征图神经元值,而在反向传播时,每个单元格表示的是分配给对应神经元的梯度值。
在这里插入图片描述

计算卷积输出大小、参数量和计算量

在这里插入图片描述

参数量

  1. 计算量对应我们之前的时间复杂度参数量对应于我们之前的空间复杂度,这么说就很明显了。也就是计算量要看网络执行时间的长短,参数量要看占用显存的量
  2. 计算量,参数量对于硬件的要求是不同的。计算量的要求是在于芯片的floaps(指的是gpu的运算能力)。参数量取决于显存大小。

针对于卷积层:
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

针对于全连接层:

参数个数: FC前层 × FC后层
计算量/乘法计算次数/times : FC前层 × FC后层
在这里插入图片描述在这里插入图片描述

感受野( R e c e p t i v e Receptive Receptive F i e l d Field Field

感受野( R e c e p t i v e Receptive Receptive F i e l d Field Field)的定义是卷积神经网络每一层输出的特征图( f e a t u r e feature feature m a p map map)上的像素点在原始输入图片上映射的区域大小。再通俗点的解释是,特征图上的一个点对应原始输入图片上的区域,如下图所示。
在这里插入图片描述
感受野的作用
(1)一般 t a s k task task 要求感受野越大越好,如图像分类中最后卷积层的感受野要大于输入图像,网络深度越深感受野越大性能越好;

(2)密集预测 t a s k task task要求输出像素的感受野足够的大,确保做出决策时没有忽略重要信息,一般也是越深越好;

(3)目标检测 t a s k task task中设置 a n c h o r anchor anchor要严格对应感受野, a n c h o r anchor anchor太大或偏离感受野都会严重影响检测性能。

感受野计算:

在计算感受野时有下面几点需要说明:

(1)第一层卷积层的输出特征图像素的感受野的大小等于卷积核的大小。

(2)深层卷积层的感受野大小和它之前所有层的滤波器大小步长有关系。

(3)计算感受野大小时,忽略了图像边缘的影响,即不考虑padding的大小。

下面给出计算感受野大小的计算公式:

R F l + 1 = ( R F l − 1 ) ∗ s t r i d e + k e r n e l RF_{l+1} = (RF_{l}-1)*stride + kernel RFl+1=(RFl1)stride+kernel

其中 R F l + 1 RF_{l+1} RFl+1为当前特征图对应的感受野的大小,也就是要计算的目标感受野, R F l RF_{l} RFl为上一层特征图对应的感受野大小, f l + 1 f_{l+1} fl+1为当前卷积层卷积核的大小,累乘项 s t r i d e s strides strides表示当前卷积层之前所有卷积层的步长乘积。

举一个例子,7 * 7的输入图经过三层卷积核为3 * 3的卷积操作后得到 O u t 3 Out3 Out3的感受野为7 * 7,也就是 O u t 3 Out3 Out3中的值是由 I n p u t Input Input所有区域的值经过卷积计算得到,其中卷积核( f i l t e r filter filter)的步长( s t r i d e stride stride)为1、 p a d d i n g padding padding为0,,如下图所示:
在这里插入图片描述
以上面举的 s a m p l e sample sample为例:

O u t 1 Out1 Out1层由于是第一层卷积输出,即其感受野等于其卷积核的大小,即第一层卷积层输出的特征图的感受野为3, R F 1 RF1 RF1=3;

O u t 2 Out2 Out2层的感受野 R F 2 RF2 RF2 = 3 + (3 - 1) * 1 = 5,即第二层卷积层输出的特征图的感受野为5;

O u t 3 Out3 Out3层的感受野 R F 3 RF3 RF3 = 3 + (5 - 1) * 1 = 7,即第三层卷积层输出的特征图的感受野为7;

常见网络的感受野如下:
在这里插入图片描述

CNN 与 MLP

记得之前说过,CNN限制了模型的弹性,具体如下,越内部就越限制弹性

  1. FC是自己决定是看全局还是局部范围(将一些weight设置为0),而加了感受野的概念之后就只能看一个小范围,所以model弹性变小

  2. 参数共享之后,某些神经元(卷积核)的参数都是一模一样的,没得选,这更加增加了对神经元的限制
    在这里插入图片描述

所以,CNN的model bias比较大。但对CV任务不是问题

Filter:

另一种理解CNN的方式是直接从filter的角度看
在这里插入图片描述
那么我们先给 定不同的Filter,每一个filter都会抓图片里面的pattern(33channel)

以黑白图片为例子
在这里插入图片描述
filter看到image里面出现什么东西的时候他的值最大(这里出现对角线1的时候最大)

在这里插入图片描述
如果说我们设置64个filter,那就会得到一个channel为64的 Image,每一个矩阵就是相应的feature map

在这里插入图片描述
我们再根据Image-1进行Convolution,构造3364的filter

那么33是否太小而无法看到更大范围的pattern呢??其实根本不会,在第二层33我们看见的其实在原图是5*5,根据网络的不断叠加,我们会越看越大。

其实现在回过头来看,CNN跟我们之前学习的神经网络,也没有很大的差别。传统的神经网络,其实就是多个FC层叠加起来。
CNN,无非就是把FC改成了CONV和POOL,就是把传统的由一个个神经元组成的layer,变成了由filters组成的layer。

那么,为什么要这样变?有什么好处?
具体说来有两点:

  1. 参数共享机制

我们对比一下传统神经网络的层和由filters构成的CONV层:
假设我们的图像是8×8大小,也就是64个像素,假设我们用一个有9个单元的全连接层:
在这里插入图片描述
那这一层我们需要多少个参数呢?需要 64×9 = 576个参数(先不考虑偏置项b)。因为每一个链接都需要一个权重w。

那我们看看 同样有9个单元的filter是怎么样的:
在这里插入图片描述
其实不用看就知道,有几个单元就几个参数,所以总共就9个参数!

(1)因为,对于不同的区域,我们都共享同一个filter,因此就共享这同一组参数。这也是有道理的,通过前面的讲解我们知道,filter是用来检测特征的,那一个特征一般情况下很可能在不止一个地方出现,比如“竖直边界”,就可能在一幅图中多出出现,那么 我们共享同一个filter不仅是合理的,而且是应该这么做的。

(2)由此可见,参数共享机制,让我们的网络的参数数量大大地减少。这样,我们可以用较少的参数,训练出更加好的模型,典型的事半功倍,而且可以有效地 避免过拟合
(3)同样,由于filter的参数共享,即使图片进行了一定的平移操作,我们照样可以识别出特征,这叫做 “平移不变性”。因此,模型就更加稳健了。

补充:
1. 在欧几里得几何中,平移是一种几何变换,表示把一幅图像或一个空间中的每一个点在相同方向移动相同距离。比如对图像分类任务来说,图像中的目标不管被移动到图片的哪个位置,得到的结果(标签)应该是相同的,这就是卷积神经网络中的平移不变性。
2. 池化:比如最大池化,它返回感受野中的最大值,如果最大值被移动了,但是仍然在这个感受野中,那么池化层也仍然会输出相同的最大值。这就有点平移不变的意思了。
所以这两种操作共同提供了一些平移不变性,即使图像被平移,卷积保证仍然能检测到它的特征,池化则尽可能地保持一致的表达。

  1. 局部连接

由卷积的操作可知,输出图像中的任何一个单元,只跟输入图像的一部分有关系:
在这里插入图片描述
而传统神经网络中,由于都是全连接,所以输出的任何一个单元,都要受输入的所有的单元的影响。这样无形中会对图像的识别效果大打折扣。比较,每一个区域都有自己的专属特征,我们不希望它受到其他区域的影响。

在这里插入图片描述

在这里插入图片描述

CNN 与 Transformer

Self-attention

以下内容部分参考李宏毅笔记

为什么要引入Self-attention

基于RNN(LSTM)的序列模型来说,计算每个cell的输出无法进行并行化。而且单向的RNN无法很好的利用全局的信息。其中下面中的a和b均为向量。

在这里插入图片描述
CNN是可以平行化的,不需要第一个filter计算完毕才计算第二个filter,可以同时计算所有的filter。但是一个缺点是要叠许多层才可以看到长期的信息,如果第一个filter就需要长时间的信息那么是做不到的,所以有了自注意力。
在这里插入图片描述
self-attention取代RNN:
在这里插入图片描述
自注意力模型输入:
如下图所示,左侧的变长的输入序列即是自注意力模型的输入数据,注意这个向量序列的长度不是固定的。
在这里插入图片描述

self-attention的基本原理

在这里插入图片描述

因为要建立输入向量序列的长依赖关系,所以模型要考虑整个向量序列的信息。如下图所示,Self-Attention的输出序列长度是和输入序列的长度一样的对应的输出向量考虑了整个输入序列的信息。然后将输出向量输入到Fully-Connected网络中,做后续处理。
在这里插入图片描述
当然Self-Attention可以和Fully-Connected交替使用多次以提高网络的性能,如下图所示。
在这里插入图片描述
上边我们提到,Self-Attention可以使用多次,那么输入可能是整个网络的输入,也可能是前一个隐藏层的输出,这里我们使用[a1,a2,a3,a4]来表示输入,使用b1表示输出为例。
在这里插入图片描述
在这里插入图片描述
首先Self-Attention会计算a1分别与[a1,a2,a3,a4]的相关性[α1,1,α1,2,α1,3,α1,4]。相关性表示了输入[a1,a2,a3,a4]对a1是哪一个label的影响大小。而相关性α的计算方式共有Dot-product和Additive两种。

Dot-product:
在这里插入图片描述
在Dot-product中,输入的两个向量,左边的向量乘上矩阵Wq得到矩阵q,右边的向量乘上矩阵Wk得到矩阵k,然后将矩阵q和矩阵k对应元素相乘并求和得到相关性α。

Additive:
在这里插入图片描述
在Additive中同样也是先将两个输入向量与矩阵Wq和矩阵Wk相乘得到矩阵q和k。然后将矩阵q和k串起来输入到一个激活函数(tanh)中,在经过Transform得到相关性α。

self-attention的计算过程

为了提高模型能力,自注意力模型经常采用查询-键-值(Query-Key-Value,QKV)模型,其计算过程如下所示:
在这里插入图片描述


在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Self-Attention计算矩阵

由上边计算过程可知,每个输入a都会产生q、k和v三个矩阵。这里还是以[a1,a2,a3,a4]为输入为例:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

Multi-head self-attention

Self-Attention有一个使用非常广泛的的进阶版Multi-head Self-Attention,具体使用多少个head,是一个需要我们自己调节的超参数(hyper parameter)。

在这里插入图片描述
(可能相关性有不同的定义)
在这里插入图片描述

在后续的计算中,我们只将属于相同相关性的矩阵进行运算,如下图所示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Positional Encoding

通过前边的了解,可以发现对于每一个input是出现在sequence的最前面,还是最后面这样的位置信息,Self-Attention是无法获取到的。这样子可能会出现一些问题,比如在做词性标记(POS tagging)的时候,像动词一般不会出现在句首的位置这样的位置信息还是非常重要的。

我们可以使用positional encoding的技术,将位置信息加入到Self-Attention中。

在这里插入图片描述
如上图所示,我们可以为每个位置设定一个专属的positional vector,用ei表示,上标i代表位置。我们先将ei和ai相加,然后再进行后续的计算就可以了。ei向量既可以人工设置,也可以通过某些function或model来生成,具体可以查阅相关论文。
在这里插入图片描述

self-attention vs CNN

在这里插入图片描述
在这里插入图片描述
self-attention比较flexible,比较flexible的model比较需要更多的data,如果data不够就有可能过拟合。而小的model,比较有限制的model适合在data少的时候,不容易过拟合
在这里插入图片描述
self-attention的弹性比较大,所以需要更多的训练资料,训练资料少的时候就会overfitting。而CNN的弹性比较小,训练资料比较少的时候效果比较好,但是训练资料多的时候无法从更大量的训练资料得到好处

Transformer

Transformer是一个sequence to sequence(seq2seq)的模型,输入一个序列,输出一个序列。这两个序列的长度、关系是由模型自己确定的。相关场景包括:语音识别(一段语音转换成的文字的长度是由模型决定的)、机器翻译(翻译后的语句的长度是由机器决定的)、语音翻译(直接对语音进行翻译)、聊天机器人(输入是语句、输出也是语句)。还有很多看起来和seq2seq完全没关系的问题也可以用seq2seq硬做。

Seq2seq模型包括一个encoder和decoder

encoder和decoder

Encoder:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
layer norm不考虑batch信息

Decoder:

在这里插入图片描述
Decoder的很常见的一种是autoregressive(AT)。以语音识别为例来介绍AT。Decoder的输入是encoder的输出向量(但不完全是,看了后面就会知道原因)。Decoder的输入中会有一个标记开始的token。在中文语音识别的模型中,Decoder的输出就是一个个的汉字。那么,每个输出位可能的输出是所有汉字(不是真正意义上的所有汉字,而是训练中的用到的汉字)。对于每个输出位,可以做一个softmax,来决定这个输出位到底输出什么汉字
在这里插入图片描述
有趣的部分是,当decoder决定在第一个字的位置输出“机”后,这个“机”会被当成decoder的输入,然后decoder输出“器”;同样地,“器”也被当成decoder的输入。这样进行下去,逐渐输出“机器学习”四个字。也就是说,这种decoder(具体来说,AT)的输入是它在上一个时间点的输出。那么如果decoder的上一个输出是错的该怎么办呢?即便decoder努力输出正确的结果,但也可能会造成连环错误:从一个字错了之后,后面的结果接连出错。我们暂时不考虑这个问题。
在这里插入图片描述
在这里插入图片描述

(下面一排token都是onehot编码)

Encoder和decoder的构成对比:
在这里插入图片描述
如果把灰色的部分遮起来,其实decoder和encoder的构成没有太大差别。细小的差别在于,decoder中的multi-head attention前面加了一个“masked”。这一部分涉及到self attention的知识,这里只是简单提一下。

对于self attention,输出向量的每一位和输入向量的每一位是有关系的。即b1与a1~a4都有关系。
在这里插入图片描述
而masked self attention中,b1只与a1有关系,b2只与a1a2有关系,b3只与a1a3有关系…
在这里插入图片描述
具体来说:原有的:
在这里插入图片描述
masked:
在这里插入图片描述

那么为什么在decoder里面要用这种masked的形式呢?其实这和decoder的特征很符合。在decoder中,每一位的输出会被当成输入用来产生下一个输出,也就是说,decoder的输入是随着输出的过程一个一个产生的,而不是一下子就有一个完整的输入送给decoder。所以,比如,计算b2的时候,此时还没有b3和b4,所以当然只能根据a1~a2来计算b2。

这里还有一个问题没有提及,就是:到底模型要产生多长的输出?当模型产生“习”之后,就应该停止了,但模型如果不知道该停了,也许会继续把“习”当成输入继续产生输出。
在这里插入图片描述

怎么办?我们可以在每一位的输出列表中加一个stop token。每一位的输出列表是汉字列表,因此要在汉字组成的列表中加一个表示结束的stop token:
在这里插入图片描述
在这里插入图片描述

与AT相对的是NAT(non-autoregressive)。NAT的结果一般比AT差。
在这里插入图片描述

NAT的好处是平行化,因为AT的decoder是逐个产生的输出,如果你句子长度为100,就要做100次decoder。所以在速度上,NAT更快

en-decoder之间的资讯传递cross-attention

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
各式各样的cross-attention
在这里插入图片描述

Training

这一部分从decoder的训练开始。训练的过程如下:
在这里插入图片描述
训练的时候,对于输出的每一个字,我们都给它一个独热向量,希望它输出的各汉字的分布和独热向量越接近越好。其实,对于输出的每一位,相当于在做分类问题。如果汉字列表中有4000个汉字,那么每一个汉字的输出过程就都是一个4000类的分类问题 。这里“机器学习”四个字相当于是做了4个4000类的分类问题。

虽然decoder的输入是随着输出的产生而逐渐产生的,但在训练的时候我们会直接一次性告诉decoder正确答案

在这里插入图片描述
我们希望机器可以在有begin的情况下输出“机”,在有“begin”和“机”的情况下输出“器”……在有“begin机器学习”的情况下输出“end”。这个叫做teacher foring:把ground truth(真实值)作为输入。

Tips

接下来讲一些关于训练transformer(或者不一定是transformer,也可以是其他的seq2seq模型)的小技巧。

Copy Mechanism:

在聊天机器人中,可以采用copy mechanism:
在这里插入图片描述
在第一段对话中,模型应该回答“库洛洛你好”,但是库洛洛对模型来说是很奇怪的词汇,也许训练数据中根本没有出现过这个词。这是,模型其实没有必要真的去生成“库洛洛”,而是可以学会在见到“我是…”这样的句式时,原封不动地输出“我是”后面的内容。这是一种从输入内容进行copy的方式。另一种情况是,模型遇到了一些不懂的内容。“不能使用念能力”是模型没有见过的内容,那么这时机器可以直接把这部分语句复制过来直接输出,而不是试图去产生这个语句。

另一种情况是做摘要的时候:

在这里插入图片描述
在这里插入图片描述
摘要本身不需要产生新的词汇,而是直接从文章里选词汇就可以。当然,真实生活中,我们可能会用到一些原文中没有的词来更好的概括内容,但这是很高级的能力,在这里我们不涉及。

Guided Attention:

模型可能会犯一些低级错误。以TTS(语音合成,text to speech)为例,如果让模型重复念一个词很多次,它的读音可能会不一样。比如,让某个模型念“发财”4遍,模型念的这4遍“发财”是有区别的;只念一遍“发财”时,甚至不能完整念出“发财”二字。苹果的Siri、papago翻译都有这样的问题。这样的例子不多,但确实是存在的。

要求机器做attention的时候是有固定方式的。与此问题相关的训练技巧是强迫模型的输出的顺序和输入的顺序之间是保持单调的。比如,在语音识别,语音合成的过程中,模型必须从单调地左向右处理输入(关键词:monotonic attention, location-aware attention):
在这里插入图片描述
beam search(集束搜索):
在这里插入图片描述

假设世界上只有两种token:A和B。模型每次生成A或B的抉择过程可以用一棵树来表示。每次输出时,模型都用一个分数来决定到底输出什么。图中的红色路径是贪心的结果,其实绿色路径是最好的选择。如果在刚开始选择了输出A,结果可能会错过更好的结果。一种简单但幼稚不可行的方案是暴力搜索这棵树来发现最好的路径,因为计算量大到无法想象:以中文语音识别为例,如果汉字列表中有4000个字,那么树的每个节点的分叉就有4000个,这是不可能进行暴力搜索的。所以要用到beam search的方法。这个方法具体是怎么进行的,这里不提及。这个方法有时候有用,有时候没用(至少两种情况都有不少大佬的论文来证明)。对于那些有确定唯一答案的任务,比如语音识别,集束搜索很有用;而对于需要发挥一些创造力的任务,比如,根据上文续写下文,集束搜索的表现不好。

这里提到一个很神奇的现象。在进行语音合成的测试时,需要加入一些随机的噪声。这是很违反常理的,我们往往在训练的时候使用噪声来让模型可以接触到更多的可能性,让模型更强健。但在语音合成的技术中,在测试的时候也要加入一些噪声,这样反而合成的语音质量更好。

Optimizing Evaluation Metric:

有一种评估标准叫blue score:把模型产生的句子和真实的句子进行比较。但是问题在于,我们训练的时候并不是这样做的。对于识别“机器学习”这四个字的语音识别任务来说,训练的过程实际上是做了4个4000类(4000是假设的汉字总数量)的分类问题,对于每个字的产生,我们用了交叉熵。但是在评估的时候,我们用的是blue score。交叉熵和blue score之间并没有什么直接的联系。那么我们可不可以在训练的时候就用blue score进行优化呢?不行,因为对两个句子之间计算的blue score是不可微分的。那么怎么办呢?一个方法是。遇到用optimization无法解决的问题时,采用强化学习硬训练一次就行了。即便有人成功过,这依然是一个很难的方法。
在这里插入图片描述
schedule sampling:

训练的过程中,decoder可以看到正确答案,但在测试的时候,decoder只能看到自己的输出,因此会出现一步错步步错的情况,这种情况被称为exposure bias。解决办法是训练的过程中,在给decoder展示的ground truth中故意加入一些错误,decoder反而会学得更好。
在这里插入图片描述
但是这一招会伤害到transformer平行化的能力

[2016] (CVPR)Deep Residual Learning for Image Recognition

abstract

  1. 提出问题:深的神经网络非常难以训练
  2. 干了什么:做了一个使用残差学习的框架来使得训练非常深的网络更加容易
    提出的方法:把层作为一个残差学习函数相对于层输入的一个方法,而不是说跟之前一样的学习unreferenced functions
    提供了非常多的证据证明这些残差网络容易训练、能够得到很好的精度,特别是在把层增加了之后,在ImageNet数据集上使用了152层的深度,但是有了更低的复杂度

论文第一张图

在这里插入图片描述

  1. 一般会在第一页放上一个比较好看的图
  2. 左图是训练误差,右图是在CIFAR-10上的测试误差
  3. x轴是轮数
  4. y轴是错误率
  5. 从图中可以看到,更深(更大的)网络误差率反而更高:训练误差更高,测试误差也更高

introduction

深度神经网络好在可以加很多层把网络变得特别深,然后不同程度的层会得到不同等级的feature,比如低级的视觉特征或者是高级的语义特征

提出问题:随着网络越来越深,梯度就会出现爆炸或者消失

  1. 解决他的办法就是:1、在初始化的时候要做好一点,就是权重在随机初始化的时候,权重不要特别大也不要特别小。 2、在中间加入一些normalization,包括BN(batch normalization)可以使得校验每个层之间的那些输出和他的梯度的均值和方差,相对来说比较深的网络是可以训练的,避免有一些层特别大,有一些层特别小。使用了这些技术之后是能够训练(能够收敛),虽然现在能够收敛了,但是当网络变深的时候,性能其实是变差的(精度会变差)
  2. 文章提出出现精度变差的问题不是因为层数变多了,模型变复杂了导致的过拟合,而是因为训练误差也变高了(overfitting是说训练误差变得很低,但是测试误差变得很高)训练误差和测试误差都变高了,所以他不是overfitting。虽然网络是收敛的,但是好像没有训练出一个好的结果

深入讲述了深度增加了之后精度也会变差

  1. 考虑一个比较浅一点的网络和他对应的比较深的版本(在浅的网络中再多加一些层进去),如果浅的网络效果还不错的话,深的网络是不应该变差的:深的网络新加的那些层,总是可以把这些层学习的变成一个identity mapping(恒等映射)(输入是x,输出也是x,等价于可以把一些权重学成比如说简单的n分之一,是的输入和输出是一一对应的),但是实际情况是,虽然理论上权重是可以学习成这样,但是实际上做不到:假设让SGD去优化,深层学到一个跟那些浅层网络精度比较好的一样的结果,上面的层变成identity(相对于浅层神经网络,深层神经网络中多加的那些层全部变成identity),这样的话精度不应该会变差,应该是跟浅层神经网络是一样的,但是实际上SGD找不到这种最优解

  2. 这篇文章提出显式地构造出一个identity mapping使得深层的神经网络不会变的比相对较浅的神经网络更差,它将其称为deep residual learning framework

  3. 要学的东西叫做H(x),假设现在已经有了一个浅的神经网络,他的输出是x,然后要在这个浅的神经网络上面再新加一些层,让它变得更深。新加的那些层不要直接去学H(x),而是应该去学H(x)-xx是原始的浅层神经网络已经学到的一些东西,新加的层不要重新去学习,而是去学习学到的东西和真实的东西之间的残差,最后整个神经网络的输出等价于浅层神经网络的输出x和新加的神经网络学习残差的输出之和将优化目标从H(x)转变成为了H(x)-x
    在这里插入图片描述

  4. 上图中最下面的红色方框表示所要学习的H(x)

  5. 蓝色方框表示原始的浅层神经网络

  6. 红色阴影方框表示新加的层

  7. o表示最终整个神经网络的输出

  8. 这样的好处是:只是加了一个东西进来,没有任何可以学的参数,不会增加任何的模型复杂度,也不会使计算变得更加复杂,而且这个网络跟之前一样,也是可以训练的,没有任何改变

非常深的residual nets非常容易优化,但是如果不添加残差连接的话,效果就会很差。越深的网络,精度就越高

introduction是摘要的扩充版本,也是对整个工作比较完整的描述

related work

一篇文章要成为经典,不见得一定要提出原创性的东西,很可能就是把之前的一些东西很巧妙的放在一起,能解决一个现在大家比较关心难的问题

残差连接如何处理输入和输出的形状是不同的情况:

  1. 第一个方案是在输入和输出上分别添加一些额外的0,使得这两个形状能够对应起来然后可以相加
  2. 第二个方案是之前提到过的全连接怎么做投影做到卷积上,是通过一个叫做1*1的卷积层,这个卷积层的特点是在空间维度上不做任何东西,主要是在通道维度上做改变。所以只要选取一个1*1的卷积使得输出通道是输入通道的两倍,这样就能将残差连接的输入和输出进行对比了。在ResNet中,如果把输出通道数翻了两倍,那么输入的高和宽通常都会被减半,所以在做1*1的卷积的时候,同样也会使步幅为2,这样的话使得高宽和通道上都能够匹配上

implementation中讲了实验的一些细节

  1. 把短边随机的采样到256和480(AlexNet是直接将短边变成256,而这里是随机的)。随机放的比较大的好处是做随机切割,切割成224*224的时候,随机性会更多一点
  2. 将每一个pixel的均值都减掉了
  3. 使用了颜色的增强(AlexNet上用的是PCA,现在我们所使用的是比较简单的RGB上面的,调节各个地方的亮度、饱和度等
  4. 使用了BN(batch normalization)
  5. 所有的权重全部是跟另外一个paper中的一样(作者自己的另外一篇文章)。注意写论文的时候,尽量能够让别人不要去查找别的文献就能够知道你所做的事情
  6. 批量大小是56,学习率是0.1,然后每一次当错误率比较平的时候除以10
  7. 模型训练了60*10^4个批量。建议最好不要写这种iteration,因为他跟批量大小是相关的,如果变了一个批量大小,他就会发生改变,所以现在一般会说迭代了多少遍数据,相对来说稳定一点
  8. 这里没有使用dropout,因为没有全连接层,所以dropout没有太大作用
  9. 在测试的时候使用了标准的10个crop testing(给定一张测试图片,会在里面随机的或者是按照一定规则的去采样10个图片出来,然后再每个子图上面做预测,最后将结果做平均)。这样的好处是因为训练的时候每次是随机把图片拿出来,测试的时候也大概进行模拟这个过程,另外做10次预测能够降低方差
  10. 采样的时候是在不同的分辨率上去做采样,这样在测试的时候做的工作量比较多,但是在实际过程中使用比较少

实验

  1. 如何评估ImagNet以
  2. 各个不同版本的ResNet是如何设计的

首先阐述了ImageNet

描述了plain networks

没有带残差的时候,使用了一个18层和34层
在这里插入图片描述

  1. 上表是整个ResNet不同架构之间的构成信息(5个版本)
  2. 第一个7*7的卷积是一样的
  3. 接下来的pooling层也是一样的
  4. 最后的全连接层也是一样的(最后是一个全局的pooling然后再加一个1000的全连接层做输出)
  5. 不同的架构之间,主要是中间部分不一样,也就是那些复制的卷积层是不同的
  6. conv2.x:x表示里面有很多不同的层(块)
  7. 【3*3,64】:46是通道数
  8. 模型的结构为什么取成表中的结构,论文中并没有细讲,这些超参数是作者自己调出来的,实际上这些参数可以通过一些网络架构的自动选取
  9. flops:整个网络要计算多少个浮点数运算。卷积层的浮点运算等价于输入的高乘以宽乘以通道数乘以输出通道数再乘以核的窗口的高和宽

在这里插入图片描述

  1. 上图中比较了18层和34层在有残差连接和没有残差连接的结果
  2. 左图中,红色曲线表示34的验证精度(或者说是测试精度)
  3. 左图中,粉色曲线表示的是34的训练精度
  4. 一开始训练精度是要比测试精度高的,因为在一开始的时候使用了大量的数据增强,使得寻来你误差相对来说是比较大的,而在测试的时候没有做数据增强,噪音比较低,所以一开始的测试误差是比较低的
  5. 图中曲线的数值部分是由于学习率的下降,每一次乘以0.1,对整个曲线来说下降就比较明显。为什么现在不使用乘0.1这种方法:在什么时候乘时机不好掌控,如果乘的太早,会后期收敛无力,晚一点乘的话,一开始找的方向更准一点,对后期来说是比较好的
  6. 上图主要是想说明在有残差连接的时候,34比28要好;另外对于34来说,有残差连接会好很多;其次,有了残差连接以后,收敛速度会快很多,核心思想是说,在所有的超参数都一定的情况下,有残差的连接收敛会快,而且后期会好

输入输出形状不一样的时候怎样做残差连接

  1. 填零
  2. 投影
  3. 所有的连接都做投影:就算输入输出的形状是一样的,一样可以在连接的时候做个1*1的卷积,但是输入和输出通道数是一样的,做一次投影

对比以上三种方案

在这里插入图片描述

  1. A表示填0
  2. B表示在不同的时候做投影
  3. C表示全部做投影
  4. B和C的表现差不多,但是还是要比A好一点
  5. B和C虽然差不多,但是计算复杂度更高,B对计算量的增加比较少,作者采用了B

怎样构建更深的ResNet

如果要做50或者50层以上的,会引入bottleneck design
在这里插入图片描述

  1. 左图是之前的设计,当通道数是64位的时候,通道数不会发生改变
  2. 如果要做到比较深的话,可以学到更多的模式,可以把通道数变得更大,右图从64变到了256
  3. 当通道数变得更大的时候,计算复杂度成平方关系增加,这里通过1个1*1的卷积,将256维投影回到64维,然后再做通道数不变的卷积,然后再投影回256(将输入和输出的通道数进行匹配,便于进行对比)。等价于先对特征维度降一次维,在降一次维的上面再做一个空间上的东西,然后再投影回去
  4. 虽然通道数是之前的4倍,但是在这种设计之下,二者的算法复杂度是差不多的

ImageNet标号的错误率本来挺高的,估计有1%

CIFAR-10是一个很小的数据集,跑起来相对来说比较容易,32*32,五万个样本,10类的数据集

在整个残差连接,如果后面新加上的层不能让模型变得更好的时候,因为有残差连接的存在,新加的那些层应该是不会学到任何东西,应该都是靠近0的,这样就等价于就算是训练了1000层的ResNet,但是可能就前100层有用,后面的900层基本上因为没有什么东西可以学的,基本上就不会动了

这篇文章没有结论

mAP:目标检测上最常见的一个精度,锚框的平均精度,越高越好

为什么ResNet训练起来比较快?

  1. 一方面是因为梯度上保持的比较好,新加一些层的话,加的层越多,梯度的乘法就越多,因为梯度比较小,一般是在0附近的高斯分布,所以就会导致在很深的时候就会比较小(梯度消失)。虽然batch normalization或者其他东西能够对这种状况进行改善,但是实际上相对来说还是比较小,但是如果加了一个ResNet的话,它的好处就是在原有的基础上加上了浅层网络的梯度,深层的网络梯度很小没有关系,浅层网络可以进行训练,变成了加法,一个小的数加上一个大的数,相对来说梯度还是会比较大的。也就是说,不管后面新加的层数有多少,前面浅层网络的梯度始终是有用的,这就是从误差反向传播的角度来解释为什么训练的比较快
    在这里插入图片描述

  2. 在CIFAR上面加到了1000层以上,没有做任何特别的regularization,然后效果很好,overfitting有一点点但是不大。SGD收敛是没有意义的,SGD的收敛就是训练不动了,收敛是最好收敛在比较好的地方。做深的时候,用简单的机器训练根本就跑不动,根本就不会得到比较好的结果,所以只看收敛的话意义不大,但是在加了残差连接的情况下,因为梯度比较大,所以就没那么容易收敛,所以导致一直能够往前SGD的精髓就是能够一直能跑的动,如果哪一天跑不动了,梯度没了就完了,就会卡在一个地方出不去了,所以它的精髓就在于需要梯度够大,要一直能够跑,因为有噪音的存在,所以慢慢的他总是会收敛的,所以只要保证梯度一直够大,其实到最后的结果就会比较好

在这里插入图片描述

为什么ResNet在CIFAR-10那么小的数据集上他的过拟合不那么明显?

open question

虽然模型很深,参数很多,但是因为模型是这么构造的,所以使得他内在的模型复杂度其实不是很高,也就是说,很有可能加了残差链接之后,使得模型的复杂度降低了,一旦模型的复杂度降低了,其实过拟合就没那么严重了

  1. 所谓的模型复杂度降低了不是说不能够表示别的东西了,而是能够找到一个不那么复杂的模型去拟合数据,就如作者所说,不加残差连接的时候,理论上也能够学出一个有一个identity的东西(不要后面的东西),但是实际上做不到,因为没有引导整个网络这么走的话,其实理论上的结果它根本过不去,所以一定是得手动的把这个结果加进去,使得它更容易训练出一个简单的模型来拟合数据的情况下,等价于把模型的复杂度降低了

这篇文章的residual和gradient boosting是不一样的

1. gradient boosting是在标号上做residual
2. 这篇文章是在feature维度上

李沐精讲

随着我们设计越来越深的网络,深刻理解“新添加的层如何提升神经网络的性能”变得至关重要。更重要的是设计网络的能力,在ResNet这种网络中,添加层会使网络更具表现力

函数类

在这里插入图片描述
虽然模型更大,但是可能学偏了,所谓的模型偏差。如果更大的模型里面包含小模型,我学到的模型就会严格的比前面更大,所以至少不会变差
在这里插入图片描述在这里插入图片描述在这里插入图片描述

  1. 矩阵乘法变加法,抑制梯度消失//利用残差块(residual blocks)可以训练出一个有效的深层神经网络:输入可以通过层间的残余连接更快地向前传播。
  2. 模型虽然变大,但是模型偏差也变大了,过拟合了噪声,而跳连接使得新加入的块学习目标是f(x)与前一层模型输出x的残差,就是带有明确的目的去学,缺什么学什么。

残差块

  1. 神经网络中的具体实现:假设我们的原始输入为x,而希望学出的理想映射为f(x),左图虚线框中的部分需要直接拟合出该映射f(x),而右图虚线框中的部分则需要拟合出残差映射f(x)−x。而右图正是ResNet的基础架构–残差块(residual block)
    在这里插入图片描述在这里插入图片描述
    残差块的代码实现:
import torch
from torch import nn
from torch.nn import functional as F
from d2l import torch as d2l


class Residual(nn.Module):
    def __init__(self, input_channels, num_channels,
                 use_1x1conv=False, strides=1):
        super().__init__()
        # 第一个卷积层
        self.conv1 = nn.Conv2d(input_channels, num_channels,
                               kernel_size=3, padding=1, stride=strides)
        # 第二个卷积层
        self.conv2 = nn.Conv2d(num_channels, num_channels,
                               kernel_size=3, padding=1)
        # 如果使用1 x 1卷积以使得输入变换成需要的形状
        if use_1x1conv:
            self.conv3 = nn.Conv2d(input_channels, num_channels,
                                   kernel_size=1, stride=strides)
        else:
            self.conv3 = None
        # 对应第一个卷积层的批量规范化层
        self.bn1 = nn.BatchNorm2d(num_channels)
        # 对应第二个卷积层的批量规范化层
        self.bn2 = nn.BatchNorm2d(num_channels)

    def forward(self, X):
        # 第一层:卷积 -> 规范化 -> relu激活
        Y = F.relu(self.bn1(self.conv1(X)))
        # 第二层:卷积 -> 规范化
        Y = self.bn2(self.conv2(Y))
        # 如果要让输入变换成需要的形状
        if self.conv3:
            # 对X使用1 x 1卷积,以使输出成为需要的形状
            X = self.conv3(X)
        # 嵌套模型的实现,即对上一次训练后的模型进行嵌套
        Y += X
        # relu激活并输出
        return F.relu(Y)

在这里插入图片描述在这里插入图片描述

resnet模型

  1. ResNet的前两层跟之前介绍的GoogLeNet中的一样: 在输出通道数为64、步幅为2的7×7卷积层后,接步幅为2的3×3的最大汇聚层。 不同之处在于ResNet每个卷积层后增加了批量规范化层。
b1 = nn.Sequential(nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3),
                   nn.BatchNorm2d(64), nn.ReLU(),
                   nn.MaxPool2d(kernel_size=3, stride=2, padding=1))
  1. GoogLeNet在后面接了4个由Inception块组成的模块。 ResNet则使用4个由残差块组成的模块,每个模块使用若干个同样输出通道数的残差块。 第一个模块的通道数同输入通道数一致。 由于之前已经使用了步幅为2的最大汇聚层,所以无须减小高和宽。 之后的每个模块在第一个残差块里将上一个模块的通道数翻倍,并将高和宽减半。
def resnet_block(input_channels, num_channels, num_residuals,
                 first_block=False):
    blk = []
    for i in range(num_residuals):
        if i == 0 and not first_block:
            blk.append(Residual(input_channels, num_channels,
                                use_1x1conv=True, strides=2))
        else:
            blk.append(Residual(num_channels, num_channels))
    return blk
  1. 接着在ResNet加入所有残差块,这里每个模块使用2个残差块。
b2 = nn.Sequential(*resnet_block(64, 64, 2, first_block=True))
b3 = nn.Sequential(*resnet_block(64, 128, 2))
b4 = nn.Sequential(*resnet_block(128, 256, 2))
b5 = nn.Sequential(*resnet_block(256, 512, 2))
  1. 最后,与GoogLeNet一样,在ResNet中加入全局平均汇聚层,以及全连接层输出。
net = nn.Sequential(b1, b2, b3, b4, b5,
                    nn.AdaptiveAvgPool2d((1,1)),
                    nn.Flatten(), nn.Linear(512, 10))
  1. 每个模块有4个卷积层不包括恒等映射的1×1卷积层)。 加上第一个7×7卷积层和最后一个全连接层,共有18层。 因此,这种模型通常被称为ResNet-18。 通过配置不同的通道数和模块里的残差块数可以得到不同的ResNet模型,例如更深的含152层的ResNet-152。 虽然ResNet的主体架构跟GoogLeNet类似,但ResNet架构更简单,修改也更方便。这些因素都导致了ResNet迅速被广泛使用。
    在这里插入图片描述
    在这里插入图片描述在这里插入图片描述
    左conv-block 右 identity-block。右图可以看到,通过stride=2实现了图像下采样,并扩充了通道数。

在这里插入图片描述
进一步,在下图可以多个模板中同时存在conv-block 和 identity-block两种模式。本质区别就是有没有下采样downsample和通道转换
在这里插入图片描述

总结

在这里插入图片描述
在这里插入图片描述
如果g(x)很难训练或者训练没有什么好处的话他就会在梯度反传拿不到梯度,所以他的权重就不会被更新了

在这里插入图片描述
在这里插入图片描述

从梯度的角度: 梯度连乘变加法最下面的层(靠近数据层)也能拿到更大的梯度,不管网络多深,我都能拿到比较大的梯度做高效的更新

1.恒等映射 2. 梯度消失,梯度连乘变加法3.梯度相关性

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

姬霓钛美

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值