04 全连接神经网络(上)

设计一个分类器的各个步骤

同线性分类器设计一样,如下:
image.png

如何表示图像

直接利用原始像素作为特征,展开为列向量。
image.png

线性分类器

image.png
对于线性分类器,
《04 全连接神经网络(上)》 - 图4
其中,x代表输入图像,维度为d;f为分数向量,维度为类别个数c;W为权值矩阵,行数为类别数(每个类别都有一个权值向量),列数为特征维度;b为偏置向量,行数即为类别数,每个类别都有个偏置量。

全连接神经网络(多层感知器)

不同于线性分类器,不是给一个x,通过一次线性变换就输出结果,会级联多个变换来实现输入到输出的映射。
image.png
全连接神经网络的核心还是线性分类器,但是多了非线性操作。非线性操作是不可以去掉的,否则就不是全连接神经网络的,又变成了线性分类器。 :::info 后面会递推 :::

全连接神经网络的权值有启发

Q:线性分类器级联的构架,真实情况是如何工作,为什么会有效,如何直观理解。
image.png

两层全连接网络中,W1的行数人为指定,W2的行数就必须为类别数了。 max为逐元素的操作。

Q:指定W1的行数有何作用呢?
A:比如在原来学的马里面,数据集有两个方向的马头,马的模板要去记录马,平均一下因此模板里会有两个方向的马头;显然模板记录的马是不准确的马。如果模板数够多,比如W1行数为100,也就是有100个模板,那么可以用一个模板去记录正向的马,另一个模板记录朝另一个方向的马;只要模板够多,就有机会学到真正的马长什么样。这就是全连接神经网络第一层权值重要的地方。
Q:两层神经网络为何比线性分类器好
A:W2通常用来融合多个模板的比较结果然后给出结论。W2通常用来融合当前x在低层各个模板的响应结果。
image.png

全连接神经网络与线性不可分

  • 线性分类器解决的是线性可分问题。
    • 线性可分:至少存在一个线性分界面能把两类样本没有错误的分开。
  • 如果任务的样本是线性不可分的话,这时候就要求助于全连接神经网络这样的分类器。

image.pngimage.png

全连接神经网络绘制与命名

:::info 全连接神经网络其实是将线性分类器经过非线性操作后级联起来,想写几层全连接网络就级联几次线性分类器。 ::: image.png

图中W1中包含了b,为了简化才没有单独写出来。 隐层即模板的个数,输出层的个数是固定的,即类别数。

  • N层全连接神经网络:除输入层之外其他层的数量为N的网络。

image.png

激活函数

Q:为什么需要非线性操作?
A:去掉激活函数后,全连接神经网络将变成一个线性分类器。
image.png

常用的激活函数

image.png

激活函数会对前一层输出的向量中的每个维度分别进行处理。

网络结构设计

1、用不用隐层,用一个还是用几个隐层?(深度设计)
2、每隐层设置多少个神经元合适?(宽度设计)
没有统一的答案。

  • 结论:神经元个数越多,分界面就可以越复杂,在这个集合上的分类能力就越强。

image.png
image.png

全连接神经网络小结

image.png

Softmax与交叉熵(softmax让网络可以输出概率)

现在预测的时候,只能求出输出层最大的分数,比如f3,然后将其下标作为预测的类别,比如第3类。分数的取值范围为负无穷到正无穷。
而我们想知道做这个决定的正确的可能性,通过现在的输出达不到这个效果,因此引入下面的softmax操作。
softmax操作后,输出层就是一个概率分布。
image.png
image.png

交叉熵损失(计算输出和标准答案间的距离)

Q:如何度量现在的分类器输出和预测值之间的距离?
A:需要比较图中两个分布之间的距离,这就是交叉熵所作的。当两个分布越接近时,交叉熵的损失值就越小。
image.png

真实分布用one-hot向量表示的。 上述距离不能用多类支撑向量机损失来度量,因为它不考虑右侧,只考虑左侧比如车的答案和鸟的答案之间的关系,大过1没有。无法考虑两个概率分布之间的关系。

交叉熵

  • 熵:信息量的体现。当信息量大的时候,熵就大。比如巴西队和中国队足球比赛,中国队基本必输,这时候熵就小。
    • 比如[胜,负,平]的概率为[1,0,0],则熵算出来就为0,当每种情况出现的概率都为1/3即一样时,计算出来熵最大。
  • 交叉熵:是p和q两个分布之间的关系。x也是对每种可能性进行的求和。
  • 相对熵
    • 为什么叫散度(不相似性)不叫距离,距离满足可交换性,但散度不满足。

image.png
image.png

  • 真实的p通常就是one-hot向量即标准答案,[1,0,0],此时熵为0,则KL散度就等于交叉熵。所以就可以用交叉熵来度量两个分布之间的距离。

image.png

  • 真实分布为one-hot形式时,交叉熵损失简化为:

《04 全连接神经网络(上)》 - 图23

交叉熵损失 vs 多类支撑向量机损失

image.png
Q:相同分数下两种分类器的损失有什么区别?
A:交叉熵在下面第二种情况下并没有停止训练,因为不仅要求预测类别分数高,同时要求其他类别分数低。而多类支撑向量机损失只要比别人高1分就行了。
image.png

总结

1、softmax操作能让神经网络的输出从绝对的数值变成概率分布
2、交叉熵能度量输出的概率分布与真实的标签(一般为one-hot形式)之间的距离


优化算法

计算图:让计算机实现任意复杂函数的求导问题

  • 计算图上前向计算可以由输入计算出输出。
  • 反向计算可以得出输出相对于输入的梯度。可以算出各局部梯度,由链式法则,相乘即可得到梯度。
    • 计算图可以算出输出相对于图上所有单元的梯度(不仅是对输入的梯度)

image.png

计算图总结

image.png :::info 由于链式法则一路都在做乘法,会存在一些问题。如果局部梯度都比较小,那么每乘一次,数值就变小一次,如果操作叠加的越多,那么梯度信息传着传着很快就没了。这也叫梯度消失问题。 :::

计算图的颗粒度

我们可以将红框中的当成一个整体来看,直接用下面的公式计算这个框的输出和输入间的局部梯度,然后再乘上游梯度。这也就将原本四五次的操作一次完成。
因此计算图中有个颗粒度问题,计算图中的某个门,可以是个复杂的函数,也可以是简单的加减法;我们可以将一些已知的函数,如sigmoid,将其导数求出来,然后把它当作一个基元,这个函数的颗粒度较大,但是计算此函数时计算效率就变高了。

如果完全交给tensorflow,颗粒度较小,计算效率较低,因此有时候可以手写复杂函数的梯度

image.png

计算图中常见的门单元

image.png
拷贝门(一个神经元输出多个结果给多人用),一个数据拷贝成两份,回传时,两路的信息要累加起来。
max门,哪个输入大,梯度就回传给谁。

再谈激活函数

梯度消失

  • 梯度消失是神经网络训练中非常致命的一个问题,其本质是由于链式法则的乘法特性导致的。
    • 一旦梯度消失,前面神经网络的参数就改变不了了。
    • sigmoid函数大部分时候都是很小的梯度,接近0,最大的时候也才1/4,比如串10个,每次缩小1/4,几次以后梯度也消失了。因此现在sigmoid不再使用。
  • 梯度爆炸,也是由于链式法则的乘法特性导致的。

image.png
image.png

  • 作为输出层,比如希望输出为0到1之间。可能会用到sigmoid或tanh。但作为隐层不会使用,因为局部梯度特性不利于网络梯度的传递。

image.png

  • 而relu函数,计算更简单(不用算指数),局部特性也很好。
    • 但有些缺点,输入小于0时梯度为0。

image.png

  • Leaky ReLU,相对于relu来说更好,输入小于0时也有梯度。

    激活函数选择总结

    image.png

    梯度下降算法改进

    梯度下降算法存在的问题

  • 损失函数特性:一个方向上变化迅速而在另一个方向上变化地缓慢。

image.png

  • 仅增大步长并不能加快算法收敛速度。

    动量法

  • 目标:改进梯度下降算法存在地问题,即减少震荡,加速通往谷底。

  • 改进思想:利用累加历史梯度信息更新梯度。

image.png
Q:为什么有效?
A:累加过程中震荡方向相互抵消,平坦方向得到加强。

\mu为何不取1,v=v+g,这样的话即使梯度下降算法走到平坦区域,g=0了,然而累加值v不为0,仍然会一直走,梯度下降算法就停止不了;而\mu为0.9的话,v=0.9v,相当于加了个摩擦系数,算法慢慢会停下来。

image.png

  • 不光能让梯度下降速度加快,而且还能够让我们找到更好的局部最优点。

    自适应梯度法

  • 自适应梯度法通过减小震荡方向步长,增大平坦方向步长来减小震荡,加速通往谷底方向。

Q:如何区分震荡方向和平坦方向?
A:梯度幅度的平方较大的方向是震荡方向;幅度较小的方向是平坦方向。
写成代码的方式如下:
image.png :::info 其实是自适应的调节学习率 :::

缺陷是,累加时间过长时,r会是个很大的值,此时学习率即真实的步长就会很小,就失去了调节的意义了。 因此下面讲解一种改进方法。

RMSProp

image.png

  • 做法:每次的历史梯度加上一个衰减值。
  • 好处:
    • 《04 全连接神经网络(上)》 - 图40为0时,仅靠当前梯度,当前梯度很大,就把此方向速度降慢;当前梯度小,就把此方向速度增大。
    • 《04 全连接神经网络(上)》 - 图41为1时,就不考虑当前梯度了,因此不会取1.
    • 《04 全连接神经网络(上)》 - 图42一般设个0.999,非常接近1的值。如果梯度老是0,虽然《04 全连接神经网络(上)》 - 图43为0.999,但求出的r会被一直衰减。因为每次乘0.999,连乘下去会是很小的值了,就不会再去影响梯度了。
    • 增大《04 全连接神经网络(上)》 - 图44代表着考虑的历史值越多。保留的历史次数越多,《04 全连接神经网络(上)》 - 图45的值就要设置越大。打个比方,比如我要保留100次历史,《04 全连接神经网络(上)》 - 图46可能就设为0.99。 :::info 自适应梯度即不同方向迈不同的步长来实现的。 :::

      Adam

      既然上面两种都是来解决这个问题,为何不结合在一起呢?这就是Adam,同时使用动量和自适应的思想。
      image.png :::info 修正项仅在训练初期,冷启动时起作用,来防止初期优化得很慢。t为训练轮次,当训练轮次变多时,《04 全连接神经网络(上)》 - 图48越来越小,《04 全连接神经网络(上)》 - 图49就越来越接近1,修正项就不起作用了。 :::

      总结

      推荐使用:
      1、SGD+动量法
      2、或直接用Adam。
      但是SGD+动量法,调优的效果更好,手动调这两个东西的学习率会比Adam更好,但手动调到一个很优的值不太容易,这就是所谓的炼丹,炼丹很多时候就是在调这个东西。
      Adam在很多任务下很快就能弄好。
      很多时候我们使用Adam初始学习一下,学不动的时候用SGD+动量法手动调;也有时SGD+动量法先学一学,之后用Adam做后面的加速。

训练过程

权值初始化

训练的时候,总得给个权值来前向求解,然后才能反向计算梯度。即梯度下降时总要先给个起始点,起始点怎么给即权值初始化的问题。

  • 建议采用随机初始化,避免全零初始化。

    • 全零初始化时,网络中不同神经元的输出一样,返回来计算的梯度一样,更新值也一样。
    • 因此这些神经元学到的参数都一样,等价于一个神经元,这不是我们所希望的。

      随机权值初始化

      比如权值采样自《04 全连接神经网络(上)》 - 图50的高斯分布。至少每层计算出的结果不一样,传回来的梯度也不一样,更新的值也不一样了;至少保证更新不是相同的。
      然而只是更新不同并不一定能解决我们的问题,因为很多时候甚至都无法更新,如下:
      image.png
  • 如上图,采样自方差为0.1的高斯分布,输出值为0,则局部梯度也为0;后面的层,输出值为0,则输入的信息,根本就传不到输出。证明前向计算流都不畅通,反向梯度流也不可能畅通,网络无法被训练。

    • 因此随机初始化如果初始化太小,前向传递就会被衰减。

image.png

  • 那如果采样自方差为1的高斯分布呢?如上图。-1到1时tanh函数的梯度进入饱和区,梯度就传不回来,网络还是无法训练。
  • 结论:

    • 初始化时让权值不相等,并不能保证网络能够正常的被训练。
    • 有效的初始化方法:使网络中各层的激活值和局部梯度的方差在传播过程中尽量保持一致;以保持网络中正向和反向数据流动。

      Xavier初始化

  • 目标是希望输出的y和输入的z有相同的分布,这样迭代过程中信息会正常的流动,反向梯度流也会正常。

image.png

image.png
image.png

  • 如上图,每层输出值的分布不再是0附近,基本符合正态分布了,这样前向输出流就比较均匀,反向梯度也可以计算了。

    HE初始化

    对于ReLU激活函数来说,Xavier初始化方法仍然不好。
    image.png
    因此引入何凯明推出的方法。
    image.png

    权值初始化小结

  • 好的初始化方法可以防止前向传播过程中的信息消失,也可以解决反向传递过程中的梯度消失。 :::info 当激活函数选择双曲正切或sigmoid时,建议适用Xavier初始化;
    激活函数选择ReLU或leaky relu时,推荐使用He初始化方法 :::

    批归一化(Batch Normalization)

  • 批归一化考虑问题的角度和权值初始化不一样。

image.png

批归一化与梯度消失

  • 批归一化也称为BN操作,经常插入到全连接层后,非线性激活前。
  • 解决两个问题:
    • 正向传递时能保证每一层有数据往前传,不至于小到0。
    • 反向传递问题,让数据都在激活函数梯度最有效的范围。

image.png

批归一化实现算法

image.png

  • 批归一化算法除了归一化外,最后还加了一步平移缩放。

    算法中的输入即原来神经网络的输出,算法的输出即经过批归一化算法的输出。m是批量。 多了两个参数,《04 全连接神经网络(上)》 - 图61是希望数据映射到新方差上去,《04 全连接神经网络(上)》 - 图62是希望数据映射到新均值上去。这两个参数也是神经网络学习的,并非超参。 这样输出的y就对应到神经网络自己选择的均值和方差。

Q:训练的时候是有批量的,测试的时候均值和方差怎么设置(测试时只有一个样本)?
A:来自于训练中。累加训练时每个批次的均值和方差,最后进行平均,用平均后的结果作为预测时的均值和方差。 :::info 批归一化和权值初始化要解决的问题,都是让我的信息流正向传递通常,反向传递也顺畅,这样才能保证网络能得到正常的训练。 :::


过拟合与欠拟合

出现过拟合,得到的模型在训练集上的准确率很高,但在真实场景中识别率很低。
image.png :::info 之前学过,此部分没做笔记 :::

应对过拟合

image.png
image.png
image.png

随机失活的应用

image.png
上图可以看出,因为随机失活在测试阶段是不用的,所有神经元都会打开,就会导致训练阶段的输出和测试阶段的输出范围之间差着1/2倍。
因此要给测试阶段的输出乘上p后,两个阶段的输出范围才是一样的,神经网络才能正常工作。
image.png

mask矩阵U里的元素非0即1。 测试阶段时,如果后面不乘p,则H输出的值,与训练阶段的H值就不一样了;因此预测时乘以p才能保证与训练时的输出一样。

  • 真实应用中这样写起代码来不太方便,我们更希望随机失活作为一个层,希望这个层我加到H1后预测的时候不用再考虑它。
  • 因此在U1后面除掉p。这样在训练阶段的输出就和真实预测的输出一样了。
  • 这样就可以将U1当作一个层,即Dropout层。
    • 输入H1,输出是随机失活处理后的H1,这个层只有一个参数p。

image.png

模型正则与超参数调优

  • 超参数:
    • 网络结构:隐层神经单元个数,网络层数,非线性单元选择等。
    • 优化相关:学习率,dropout比率,正则化强度等。

      超参数优化方法

      image.png
      image.png

      超参数搜索策略

      先粗搜索找到一些比较好的点,然后在比较好的点附近精搜索。
      image.png

      超参数的标尺空间

      image.png
      从0-1之间随机采值,90%会落在0.1-1之间,这种采样其实不太有效。
      因此真实采样空间会在log空间里做,取了log之后,千分之一到百分之一,百分之一到十分之一等等之间是等间距的,在这个空间上采样时,学习率分布就比较均衡。
      image.png