cs31n_lesson6_7

1.生物学解释

神经网络中的神经元(neurons):从输入(如图像)得到的一个输出最小单元称之为一个神经元。具体一点说,对于一个双层网络(1输入、1中间层、1输出),如果输入为一个样本,则隐藏层的维数H+最终输出维度数C,就是神经元的个数。一个神经元包括所需要的所有参数;包括一组wij(i=0,,D) ,b,以及激活函数这几个参数。比如XNXDWDXC 中,wii=0,,,D)

树突:x0
轴突:w0x1
The idea is that the synaptic strengths (the weights ww) are learnable and control the strength of influence (and its direction: excitory (positive weight) or inhibitory (negative weight)) of one neuron on another.当累加到一定程度后,输出激活(由激活函数控制),将输出传到下一个神经元的突触(wnext

由于算出结果只是一个标量,所以一个神经元的输出可以处理成概率(如softmax等),可以进行对一幅图进行二分类。
SVM可以看做是单层神经网络(没有中间层,只有输入输出层,由于不必考虑输入,所以是单层)。

2.图像数据预处理

零中心值化的作用:
由于对W求导数是xi ,如果恒为正或恒为负,则梯度下降的方向是同一个方向,最终可能无法朝着优化的方向前进。

如图,我们需要不同方向的x(红色),来使得最终的下降方向接近最优方向(蓝色)图:
这里写图片描述

具体做法是(灰度图)减去所有值的平均值,或(彩色图)RGB等channel分别减去各自channel的平均值。也可以从train数据中选一批图像来做训练。

PCA and Whitenning
如图,对于输入图像xi和xj,他们的协方差矩阵为:
所以PCA预处理过程为

# Assume input data matrix X of size [N x D]
X -= np.mean(X, axis = 0) # zero-center the data (important)
cov = np.dot(X.T, X) / X.shape[0] # get the data covariance matrix

由于cov是半正定的,对其进行svd分解,可以得到特征向量U,U各个维度相互正交。然后可以对数据进行去耦合,所谓去耦合,直观上是将数据进行一定旋转,具体方法是将各个数据维度投影到/乘上新的座标轴U(得到结果如中间的图,x轴与y轴整体上已经没有相关性):

U,S,V = np.linalg.svd(cov)
Xrot = np.dot(X, U) # decorrelate the data

同时由于U已经按照对应特征值的权重进行了排序,因此我们可以选择前n个权重较大的轴/维度,舍弃剩下部分,以达到降维目的。

Xrot_reduced = np.dot(X, U[:,:100]) # Xrot_reduced becomes [N x 100]

将这些数据归一化(除以各自座标轴的权重),同时为了避免权重为0,可以加上一个白噪声处理。【在降低维度阶段就消除这些为0或过小的维度?】

Xwhite = Xrot / np.sqrt(S + 1e-5)

整个过程相当于消除了低频信号(图像中梯度比较小的部分),增强高频信号(特征点、线)。

Batch Normalization
如果在每一层输入的时候,先加个预处理操作,比如网络第三层输入数据X3(X3表示网络第三层的输入数据)把它归一化至:均值0、方差为1,然后再输入第三层计算,这样我们就可以解决前面所提到的“Internal Covariate Shift”的问题了。一般讲BN放在全连接层和非线性函数之间
如图:
这里写图片描述
如果认为每个输入都需要在相同的scale区间(比如[-1,1]),如不同图片的光照条件差别很大,则可以对图像进行normalization.
normalization的好处:
提高梯度平滑度;
减少强相关;
可以使用更高的学习率;

再说两句

一般预处理是只对train数据进行零均值化,得到的均值用来处理validation和test数据。

3.初始化

由于反向传播时对x的梯度就是w,所以w需要进行一些初始化,一般认为w应该整体上以0对称分布,同时不能太大,也不能太小。如果认为输入和结果都满足标准高斯分布的话,那么w的方差即是1/n,则标准差/平均值为1/sqrt(n)
所以对于类似tanh的激活函数,一般初始化成:

W=np.random.randn(fanin,fanout)/np.sqrt(fanin/2)

fanin,fanout 分别是该层输入和输出的个数。
而对于Relu函数,由于分布不同,一般初始化为:
w = np.random.randn(n) * sqrt(2.0/n)

此外还有随机游走、数据关联等方法来初始化。
而对b来说,一般初始化为0.

4.正则化

正则化的λ ,意味着每次更新都要减去λW
L1和L2正则化的使用区别
L1会导致一个比较稀疏的结果,也就是最终的w使得该系统更青睐于那些更重要高的输入;相比之下L2更容易导致一个比较均匀的w。如果无法明确知道输入有明显的feature特性,就用L2吧。
Max norm constraints
即对w元素的最大值进行上界限制。
Dropout
在训练时用一个概率p来丢弃某些参数,比如
H1*(np.random.rand(*H1.SHAPE)

5.调参

对于一个给定的模型框架,需要调试的参数包括:最初的学习率,学习率下降框架,正则项权重,droput项参数;对于一个给定的工作,需要的调参还包括初始值,训练次数,神经网络总层数包括每层的神经元个数
在设计程序时,需要设计一个worker部分来不断地尝试不同参数并记录并输出最终结果(时间、精确度等)到文件,同时一些worker在validation上验证最终结果;并同时设计一个master来开启或杀掉集群中的这些workers.
先不加正则项来测试loss和grad;单独调正则项确定它的权重,
确定grad没问题时,现在一个小集合上训练:
loss not going down:
- learning rate too low
loss exploding:
- learning rate too high
同时,需要调:
不同的初始化
coarse to fine:先挑一小部分数据跑,再在所有数据上跑;如故loss>3*original_cost
Prefer random search to grid search

梯度检查:

对2层网络来说:
relative error > 1e-2 usually means the gradient is probably wrong
but usually means the gradient is probably wrong
relative error < 1e-4 OK
but if ther are activation function, then relative error <1e-7 may be ok.
对多层网络来说:
深度越深,可容纳的误差越大,比如10层网络,1e-2可能就差不多了。

调学习率

x += -learning_rate * dx;#一般情况

Momentum update(动量下降):

直观上我们能感受到整个下降过程的斜率变化越来越小,所以可以近似看做是一个减速运动模型

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

mu即是动量momentum,是一个待调试的hyperparameter(常常在0.9左右,所以常常在交叉验证时设置为[0.5,0,9,0.95,0.99])
动量下降可以极大加快下降速度

Nesterov Momentum

x_ahead = x + mu * v
# evaluate dx_ahead     (the gradient at x_ahead instead of at x)
v = mu * v - learning_rate * dx_ahead
x += v

mu越大,表示越相信之前的迭代速度,也就是惯性越大

x_ahead = x + mu * v
dx = ....#calculate the gradient based ahead x.
v_prev = v # back this up
v = mu * v - learning_rate * dx # velocity update stays the same
x += mv*(v- v_prev) + v # position update changes form

AdaGrad (不常用)

相当于对之前的”速度”,也就是梯度,求平均值,那么随着梯度降低,最后的梯度也会越来越小没速度也越来越小。假如有很多局部最优解呢,AdaGrad随着时间,速度快速下降的特性会局限在局部最优解中。下面是对它的改进

RMSProp

将上一次梯度下降速度融入到当前速度中,这样会减缓速度的下降。

Adam(最常用)

相当于对(某个变量)下降速度和下降梯度平方之间进行一个权衡,使得变量迭代得更加平滑。此处的first_moment相当于下降速度,第二个相当于下降速度的速度。初值设置时需要注意:不能将moment2的初值设为0,而要设一个很小的正数。
否则第一次迭代后分母过大会导致x的步长太大
此外还有变种:Adamax,Nadam
还有一种全的方法
Adam比较常用

annealing/decay the learning rate(降低学习率)

有单步降低:a_{i+1} = a_0 - t * decay_a#t 是迭代次数  
指数降低:
a = a_0* e^{-kt}1/t a = a_0/(1+kt)$
常用的是单步降低,先跑一遍,得到一个比较合适的a,再降低decay_a来进一步得到合适的a。

可以先不用学习率的decay,看看下降情况,再使用上述各种decay方法。

L-BFGS(目前比较popular的limited memory的拟牛顿方法)

在相比小数据集,它在大数据集上表现比较好,也就是需要在很大的batch上甚至全局上进行计更新算;在非凸问题上表现不佳

根据结果继续调参

过拟合

如果train精度与test精度的gap过大,则可能存在过拟合:
更深层的网络容易出现过拟合现象,数据稀少也会造成过拟合。
- 使用浅层的网络
- 增加训练数据吗,或者增加训练/测试数据的比值
- 增加正则项权重
- 更多的dropout来阻止过拟合
- batch normalization
- data augmentation(即生成更多样性的数据,比如一个猫的镜像、平移、旋转等等)
- max pooling
- 残差网络
一般先使用batch normalization,如果还不足够,则加上其他功能。

如果模板比较模糊,可能是

最后模型集成(model ensembles)

模型集成有助于利用不同的参数
可以通过不同的方式训练形成10个不同的model,然后将这些model加起来取平均值得到的效果可能好于一个model.
不同的模板的方法有
- 单一模型但不同的初始化;
- 通过交叉验证在不同数据集上生成的模型;
- 每个模型之后设置不同的checkponits

transfer trainning

如果数据量很小,可以先看做类似目标(如分类)的已经训练好的模型在数据也很相似的很大的数据上的参数。由于自己处理的任务可能只是它的任务的子集(比如它分成1000类,我只分成10类)以及自己数据量也比较小,自己可以只调这个模型的部分层的参数(如头几层):图:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章