反向传播

详见https://blog.csdn.net/Dynomite/article/details/80848748
底层实现原理:https://blog.csdn.net/lr87v5/article/details/80002374

分类网络终点使用的softmax函数非常神奇,其求导以后:
image.png
image.png
首先算输出层梯度(输出层往往没有激活函数act),而后层与层之间通过以下公式传播梯度:
image.png

池化层怎么求导?平均池化的梯度,所有节点的梯度都为grad / f;最大池化的梯度,激活节点的梯度为grad,其余为0。因此最大池化还需要记录被激活的节点以便反向传播。

Mini-Batch下的反传

  1. ![QQ截图20200510151231.png](https://cdn.nlark.com/yuque/0/2020/png/1333618/1589094760681-c2be8138-df4a-4917-8b33-52a9a856d00c.png#align=left&display=inline&height=171&margin=%5Bobject%20Object%5D&name=QQ%E6%88%AA%E5%9B%BE20200510151231.png&originHeight=244&originWidth=684&size=17409&status=done&style=none&width=478)<br />在写框架的时候踩了坑,每个batch的输出层梯度算出来取平均后直接反传,**这时候一直在用batch中最后一个****sample****的****x**,导致训练失败!<br />实际上Mini-Batch**需要存储所有的FeatureMap**,因此bs大的时候显存开销会变大,反传的时候按照上示公式逐sample计算参数的梯度。另外虽然pytorch计算的loss默认降维并取平均,但是这一过程也会被作为一个层求导,**实际反传的时候每个sample对应的loss都会被保留**。

梯度弥散与梯度爆炸

梯度饱和:由于激活函数在某区域内梯度趋向于0导致反向传播训练受阻(如Sigmoid)
梯度弥散:深层参数的训练远远快于浅层参数,导致深层早已收敛而浅层几乎完全随机
梯度爆炸:参数过大引起反向传播时梯度过大引起梯度爆炸

CNN的层与基本部件

卷积层

作用于局部图像区域获得图像的局部信息,不同的卷积核用于提取图像中不同的信息特征。多通道层中的卷积,如10通道->20通道,该层包含20个10HW的卷积核(每个输入通道中H*W的卷积核参数均不相同),10个输入通道中的元素与每一个卷积核作用后求和,得到输出元素。

池化层

包括平均值池化、最大值池化、随机池化等。池化操作实际上就是一种降采样和抽象,起到特征降维和防止过拟合的作用。

激活函数

又称非线性映射,激活函数的引入是为了增加整个网络的表达能力(非线性)。简单的例子:拟合xor函数。激活函数模拟了生物神经元的特性(兴奋/抑制)

全连接层

通常用于CNN末尾起到分类器的作用,或者将输入映射到特定维度的特征向量,将学到的特征表示映射到样本的标记空间。卷积层可以看做是稀疏连接的全连接层。

激活函数

Sigmoid

首个被广泛接受的激活函数。
深度学习笔记 - 图4
Sigmoid函数将输出值域压缩到[0,1]之间,其中0对应了生物神经元的“抑制状态”,1对应“兴奋状态”。但对于Sigmoid函数,输入|x|>5时易出现梯度饱和现象,可能导致梯度无法有效回传,进而影响这个网络的训练。另外,Sigmoid函数的值域均值并非为0,这样的结果并不符合我们对神经网络内数值的期望应为0的设想。

tanh

在Sigmoid函数的基础上解决了激活函数输出均值不为0的问题。
深度学习笔记 - 图5

修正线性单元ReLU

为了避免梯度饱和现象,Nair与Hinton在2010年将ReLU引入神经网络。ReLU是目前深度卷积神经网络中最为常用的激活函数之一。

ReLU函数在x**0时完全消除了Sigmoid函数的梯度饱和效应,计算也更为简单。另外,实验表明ReLU函数能帮助SGD的收敛速度提高6**倍左右。不过ReLU也有自身的缺陷,即在x<0**时梯度死亡**。

Leaky ReLU

为了缓解“死区”现象,研究者将**ReLU函数中x<0****部分调整为**![](https://cdn.nlark.com/yuque/__latex/d38138d655b44f7560b26504c31bdb11.svg#card=math&code=y%3Dax&height=14&width=49),其中![](https://cdn.nlark.com/yuque/__latex/0cc175b9c0f1b6a831c399e269772661.svg#card=math&code=a&height=12&width=8)为0.01或0.001数量级的较小正数。由于超参数a较难设定且较为敏感,Leaky ReLU在实际使用中的性能并不十分稳定。
深度学习笔记 - 图6

参数化ReLU(PReLU)

深度学习笔记 - 图7直接作为一个网络中可学习的变量融入模型的整体训练。实验表明,网络浅层学得的深度学习笔记 - 图8较大(0.6)而深层学得的深度学习笔记 - 图9较小(0.05)。

ReLU6

在Mobile v1里使用了ReLU6,使得在float16低精度运算的时候也能有很好的数值分辨率。如果对ReLU的激活范围不加限制,激活值可能分布在很大的范围内,float16无法很好地精确描述如此大范围的数值,带来精度损失。另外激活值过大也可能影响模型的稳定性。
深度学习笔记 - 图10

网络的训练技巧

局部响应规范化LRN

对局部神经元的活动创建竞争机制,使得其中响应比较大的值变得更大,并抑制其它反馈较小的神经元,增强了模型的泛化能力。(现已被BN完全取代)
假设深度学习笔记 - 图11为第d 个通道的卷积核在深度学习笔记 - 图12位置处的输出结果(即响应),随后经过激活函数作用。其局部响应规范化的结果深度学习笔记 - 图13可表示为:


深度学习笔记 - 图14
其中n指定了作用于LRN的相邻深度卷积核数目,N为该层所有卷积核数目。

随机失活dropout

缓解了神经元之间复杂的协同适应,降低了神经元间依赖,避免了网络过拟合。
训练阶段以概率深度学习笔记 - 图15随机将神经元置0,测试阶段所有神经元均呈激活态。但其权重初始化时需将入度乘深度学习笔记 - 图16以保证训练和测试阶段各自权重拥有相同的期望。

正则化

L2正则化(岭回归):权重衰减
L1正则化:不仅能约束参数量级,还能使参数更稀疏(便于量化与稀疏编码)
最大范数约束:深度学习笔记 - 图17

BN层

  1. ![image.png](https://cdn.nlark.com/yuque/0/2020/png/1333618/1589113507512-d6061f8d-36f3-4cc9-b790-ab7de39628a2.png#align=left&display=inline&height=242&margin=%5Bobject%20Object%5D&name=image.png&originHeight=226&originWidth=519&size=78387&status=done&style=none&width=555)<br />(式中**m=bs * H * W**)<br />BN是**逐通道**进行的<br />BN中γ与β等同网络权重w,**所有****Batch****共享****γ****与****β**;但**不同****Batch****的均值****与方差****是独立的。**<br />去除归一化直接取y=γx+β?不可取,需要给定初始分布才能学习(γ、β只用于微调)

BN层的梯度推导

根据此前对于梯度传递的讨论,参数w的大小会对梯度的传递有所影响。w过小会引起梯度弥散而w多大会引起梯度爆炸。
1.png
带BN层的梯度反传过程:
深度学习笔记 - 图19
2.png
当某一层的权重深度学习笔记 - 图21扩大了深度学习笔记 - 图22倍变为深度学习笔记 - 图23时,卷积层的输出深度学习笔记 - 图24变为深度学习笔记 - 图25倍、深度学习笔记 - 图26变为深度学习笔记 - 图27倍、深度学习笔记 - 图28变为深度学习笔记 - 图29倍:
image.png
可见,当某一层的权重大小变为深度学习笔记 - 图31倍时,传回上一层的梯度依然没有发生变化
以下是错误的理解
深度学习笔记 - 图32
以下是正确的理解
深度学习笔记 - 图33

使用BN层的好处

  1. 前面推导了,缓解梯度消失和梯度爆炸
  2. 防止过拟合

BN是针对一整个batch进行的(batch size=1时就没有正则化了)。使用BN后可以不用或少用Drop out与正则化。
垃圾阿里的面试问了bs=1的时候BN是怎么样的,答案应该就是直接当前sample每个通道做归一化。

  1. 缓解内部协变量偏移

深度学习中各层的输出分布均不同且每层的更新都会影响整个网络,浅层网络的调整会影响深层,可能导致深层参数落入激活函数饱和区。这将导致每一层网络都需要持续适应上一层输出数据分布的变化。因此采用BN后训练速度大幅提升且最终准确度也有所提高。

  1. 使得网络不再极度依赖初始化权重

BN的引入使得神经网络不再极度依赖初始化权重,另外即使使用较大的学习率进行训练也不会出现参数发散的现象(因为之前推出来的深度学习笔记 - 图34
当输入样本X服从高斯分布且输入元素之间相互独立时,BN可以使层参数的Jacobian拥有接近于1的单值,能够完整保留梯度的值在反向传播时不衰减。(什么意思)

带BN的CNN的完整训练过程

测试过程中running_mean与running_var取所有Batch的无偏估计
3.png

网络参数初始化

  1. 全零初始化(NG!)

参数全零会导致输出全零梯度全零,网络将无法学习并且原地boom boom shakalaka!

  1. 随机初始化

    1. ![](https://cdn.nlark.com/yuque/__latex/d699309806bdc9b8c64c51a0a8fef798.svg#card=math&code=w%3Drand%280%2C1%29&height=20&width=107)<br />其中![](https://cdn.nlark.com/yuque/__latex/e3b1333ed9c54d3dce3e25c8db6c4a36.svg#card=math&code=rand%28%29&height=20&width=48)函数用于生成符合标准正态分布的随机数<br />这么做会使得网络的**输出数据的方差**会随着输入神经元个数的不同而不同。<br /> ![](https://cdn.nlark.com/yuque/__latex/f9aba666ef06f81a984b4a5c4c4f7b3b.svg#card=math&code=%0A%5Cbegin%7Baligned%7D%0AVar%28y%29%26%3DVar%28%5Csum%5Climits_i%5ENx_iw_i%29%5C%5C%20%26%3D%5Csum%5Climits_i%5EN%5BVar%28x%29Var%28w%29%2BVar%28x%29E%28w%29%5E2%2BVar%28w%29E%28x%29%5E2%5D%5C%5C%0A%26%3DN%28Var%28x%29%2BE%28x%29%5E2%29%0A%5Cend%7Baligned%7D%0A&height=131&width=456)

因此实际往往会将初始值归一化(其中gain考虑了非线性激活函数的方差):
深度学习笔记 - 图36

  1. 均匀初始化

    1. ![](https://cdn.nlark.com/yuque/__latex/5beb8da7bb52d2c96ce43f8857893f0f.svg#card=math&code=w%3Duniform%28-%5Csqrt%7B%5Cdfrac%7B3%7D%7BN%7D%7D%2C%5Csqrt%7B%5Cdfrac%7B3%7D%7BN%7D%7D%29&height=45&width=209)

优化器

SGD

经典方法,最常见,收敛效果较稳定,不过收敛速度慢
深度学习笔记 - 图37

基于动量的SGD

用于改善SGD更新时可能产生的震荡现象,一般深度学习笔记 - 图38取0.9。也可以使用动态设定动量参数,譬如初始化为深度学习笔记 - 图39,随着训练的进行逐渐增长为0.9或0.99。
深度学习笔记 - 图40

Nesterov型动量SGD

Nesterov型动量会首先复制一份当前参数的副本,基于动量对副本进行更新,对更新后的参数计算梯度,最终完成当前step的参数更新。
深度学习笔记 - 图41
1.png
这个pytorch代码很精髓!p中一直存放的是深度学习笔记 - 图43,因此使用nesterov时需要把下一迭代中的深度学习笔记 - 图44也加上。

Adagrad

用于动态调整学习率,实现学习率自适应。
深度学习笔记 - 图45

RMSProp

对Adagrad的改进,防止网络训练到一定程度时分母累积过大导致学习率趋向于0而过早结束训练。
深度学习笔记 - 图46
常取超参数深度学习笔记 - 图47

Adam

将动量与RMSProp结合起来。
深度学习笔记 - 图48
常取超参数深度学习笔记 - 图49

网络压缩

低秩近似

全连接层中使用SVD;
卷积层中参数W为mnk(k为输入通道数),也可采用类似的方法进行分解:
深度学习笔记 - 图50
为了减小重构误差,可以进行多次迭代,根据深度学习笔记 - 图51推导下一次迭代,最终权重张量W被表示为深度学习笔记 - 图52

剪枝与稀疏约束

剪枝策略认为,如果某个连接的权重值过低,则意味着该连接并不重要,因而可以移除。L1与L2正则化也会促进网络的权值趋向于0。
剪枝的一般步骤:1.衡量神经元重要程度;2.移除不重要的神经元;3.微调
该方法的不足在于,剪枝后网络是非结构化的,这种随机稀疏的结构导致了缓存命中率降低,制约了实际加速效果。另一方面由于网络结构的改变使得剪枝后的网络模型极端依赖专门的运行库,严重制约了通用性。

参数量化

模型量化

知识蒸馏

网络的微调(fine-tune)

  1. 设置较小的学习率。
  2. 浅层学习率小深层学习率大(浅层是繁华特征深层是高层语义)。
  3. 微调层数:
    1. 目标数据少、与原始数据非常相似时,可仅微调网络靠近目标函数的后几层;
    2. 目标数据充足且相似时,可微调更多网络层,也可全部微调;
    3. 目标数据充足但、与原始数据差异较大,此时须多调节一些网络层,直至微调全部;
    4. 当目标数据极少、与原始数据差异较大时较麻烦,仍可先微调后几层再微调整个模型;