CS231n学习笔记(中)

Posted by Kriz on 2017-05-01

睡醒了继续肝

神经网络训练细节

这一部分蜜汁长总有种不好的预感

复习:Mini-batch SGD

采用小批随机梯度下降算法对神经网络进行训练。

训练神经网络的过程:

  1. Sample 在数据集中抽样出一小批数据
  2. Forward 将数据运入神经网络中来计算损失值
  3. Backprop 通过反向传播来确定梯度
  4. Update 通过梯度值来微调权值的数值

优化过程:权值会慢慢汇聚在低损失值的权值区域,这说明我们对训练集进行了正确的分类。

……等等我怎么不记得之前讲了随机梯度下降

嘛算了这不重要

比较激活函数

先重新考虑下激活函数。还是用这个图吧:

pic11

sigmoid函数
  1. 饱和的神经元会导致在反向传播算法中出现梯度趋0的问题。这就是梯度弥散(梯度消失)。
  2. sigmoid函数的输出不中心对称,这可能会影响收敛(?)。
  3. exp计算的代价较高。
tanh函数
  1. 将数据集中在-1到1之间
  2. 虽然关于中心店对称,但仍然可能造成梯度饱和(梯度饱和就无法在网络中传播)

优于sigmoid,毕竟少一个毛病

ReLU(Rectified Linear Unit)
  1. 输入为正时不会饱和,计算效率高(只需要进行比较,所以效率很高),收敛无敌快(sigmoid/tanh的6倍)
  2. 不关于原点对称,小于0时梯度会消散。这代表:非激活的输入值无法进行反向传播,权值也不会更新,什么都不会做。其实就是正值直接传递梯度,负值杀掉梯度,0的时候……无定义……迷幻。

出现dead ReLU的情况可能有:

  1. 初始化的时候权重被设置为不能使神经元激活的数值,这种情况下神经元是不会训练的。
  2. 训练过程中学习率太高,可能会发生数据多样性丢失(?)。

一般初始化ReLU都会把偏置值设定成非常小的正数(如0.01),而不是0。

Leaky ReLU

Leaky ReLU:f(x)=max(0.1x, x)

PReLU:f(x)=max(αx, x)

具有ReLU的一切优点,同时不会有神经元失活问题。

ELU
  1. 具有全部ReLU的优点,不会失活,容易得到0均值的输出(?)
  2. 然而需要用到exp。
Maxout
  1. 并不只是改变了激活函数,它改变了计算的变量和计算方式
  2. 各种优点(分段线性,高效率,不失活,不饱和etc)
  3. 然而每一个神经元有两组权重。介意的话就不要拍了

综上所述,目前最流行的还是ReLU,可以试试Leaky ReLU、ELU和Maxout;Tanh可以试但不要抱什么期望,至于sigmoid就算了吧。

我之前还一直觉得sigmoid特别高大上???而且有气势???

数据预处理

预处理:假设有一个二维原始数据团,以(2,0)为中心。我们要让每一个特征值减去均值,生成零中心化数据再进行归一化。

归一化在图像处理中并不常用,因为图像中所有特征都是像素,而且在0-255之间。零中心化在机器学习中应用很多,比如用PCA算法把协方差矩阵变成对角矩阵(如萍听了想射击.jpg),对数据进行白化处理等。

图像处理中常见的是均值中心化处理及其变种。

考虑数据为32*32*3的CIFAR-10图像。每张图像减去均值图像以进行中心化处理能够获得更好的训练效果。

另一个更加方便的中心化形式是减去单通道均值

权重初始化

初始化权重是非常重要又非常容易被忽视的一个前戏部分。

如果不进行初始化的话(比如全0),所有的神经元都会进行相同的计算,会造成非常迷幻的效果。

对于层数较少的网络,随机取高斯分布权值乘0.01是个办法,但层数增多之后就会存在问题。不乘0.01的话就全饱和了,什么都得不到。

Xavier初始化是个很不错的办法:随机取高斯分布,再除以对每个神经元的输入开根号的值。

1
W = np.random.randn(fan_in, fan_out) / np.sqrt(fan_in)

然而这个办法并不适用于ReLU,因为ReLU会杀死一半的输入(置0)。因此,要考虑这种情况:

1
W = np.random.randn(fan_in, fan_out) / np.sqrt(fan_in / 2)

讲道理的话何种初始化方式是数据驱动的……啊调参炼狱看来是逃不出去了【

批数据的规范化(BN,batch normalization)是最近才出现的玄学。主旨是:“You want unit gaussian activations? Just make them so.”就非常抖S。想令神经网络的每一部分都有粗略的单位高斯激活(unit gaussian activation),就直接应用这个函数:

pic1

接下来把执行BN的层插入到神经网络,这些层接收输入x。所以不管x是什么,BN保证这里每一列的每一个单位都是unit gaussian,所以下一步的激活也就没什么问题了。

BN层一般放在Fully Connected Layer和Nonlinearity Layer之间。(其实BN就是刻意防止梯度弥散)

但是目前这个约束太刻意了,tanh是否真的需要这么规范的输入呢?

因此BN还有另一个部分,在取到unit gaussian之后还可以对x进行变换:

pic2

Babysitting the Learning Process

这个部分的标题真的不会翻译……简直太形象了【

  1. 预处理
  2. 选择结构:使用有50个隐藏神经元的两层神经网络
  3. 检查损失:先检查损失函数输出,再加入正则化看是否上升
  4. 完整性检查:尝试对于某个小部分数据过拟合
  5. 进行训练。导致训练出问题的原因千千万,慢慢找就好。eg:损失爆炸就降低学习速率吧。

超参数优化

为了给网络找到最好的超参数。

首先只需要有个大概的参数空间,然后对这个学习速率的区间做一个粗略的研究,在原有的区间内选出表现比较好的一个小区间。

然后重复这个步骤,最后选出一个表现最好的参数。

pic3

参数更新

动量(momentum)更新

SGD直接校正W:

1
x += - learning_rate * dx

而momentum不是根据得到的梯度直接更新,而是增加变量v(速度)。mu是介于0-1之间的超参数(一般取0.5或0.9)。

1
2
v = mu * v - learning_rate * dx
x += v

那么梯度就可以提供下降的动力……好像有点像重力势能的感觉?那mu就可以理解成摩擦系数来放缓v?【妈妈神经网络真可怕

Nesterov动量更新

和普通动量更新的区别在于

pic4

AdaGrad

有一个放缩梯度的附加变量:

1
2
cache += dx**2
x += - learning_rate * dx / (np.sqrt(cache) + 1e-7)

相当于针对不同梯度方向进行补偿。

RMSProp
1
2
cache += decay_rate * cache + (1 - decay_rate) * dx**2
x += - learning_rate * dx / (np.sqrt(cache) + 1e-7)

decay_rate通常为0.99。

Adam

RMSProp+momentum

1
2
3
4
m = beta1 * m + (1 - beta1) * dx
v = beta2 * v + (1 - beta2) * (dx**2)
# some correct bias
x += - learning_rate * m / (np.sqrt(v) + 1e-7)

用前几个梯度的衰减和来代替梯度,从而稳定梯度方向。

目前效果最好的是Adam。

BFGS/L-BFGS

二阶方法,没怎么搞懂,略。只适用于小批量训练。

随机失活(Dropout)

前向传播的时候,随机地把一些神经元置零;反向传播的时候也要单独使用。

之前用了BN的话,可以不加或少加Dropout。

卷积神经网络详解

CNN的工作流程:

  1. 得到一些数据,作为网络的输入

  2. 使用滤波器和输入图像做卷积运算(深度要保持和图像一致),得到的结果称为激活图(activation map)

  3. 换一个与上一步独立的滤波器重复2过程。重复这一步,直到所有的滤波器都生成了各自的激活图。即我们使用了一个新的图组重构了输入图像。

    pic5

  4. 将这个图组作为输入,对于下一层,继续之前的全部步骤。

    pic6

(感性理解CNN:不断构建特征层级。)

一般的CNN由四个部分构成:

  1. CONV:卷积层
  2. ReLU:激活层
  3. POOL:池化层
  4. FC:全连接层(放在最后)

有时为了保持相邻两个卷积层尺寸一致,会进行0的填补(pad)。

为了计算方便,滤波器数目总是选择2的指数

奇数尺寸的滤波器更常见(一般最小为3)。但1*1的卷积核也是有意义的(因为大多数情况下输入不是二维)。

一般卷积层会保持尺寸(?),减小尺寸的过程由下采样完成(深度不变)。最常见的下采样方式:最大池化

pic7

平均值池化也挺常见的。

全连接层用来计算分类得分。

LeNet-5

pic8

AlexNet和ZFNet也差别不大,就略过了。

VGGNet

全部维持的设定:3*3卷积核,2步长;2*2池化滤波器,2步长。

重点是操作重复了多少层

有很好和很统一的结构,易于理解。

pic9

GoogLeNet

最关键的创新点:引入了inception模块。

增加计算量,减少参数。

pic10

ResNet

152层,不要妄想当轮子了少年。

残差网络里,每一层的输出值要加上输入的残差。

pic12

总结

pic13

CNN可视化和深入理解

一个很不错的深度卷积神经网络可视化工具:deepvis。(可以实时可视化调试)

啊好困后面的待续【