cs231n_lecture_6_怎样训练神经网络-PART 1

之前我们学习了怎样用计算图表示一个函数;神经网络——score functionloss functionCNN——用convolutional layer表达空间结构,conv layeractivation maps来自不同filter的卷积;通过最优化的方法得到参数值;更新的时候我们用的方法是mini-batch SGD.其方法是我们先=随机得到一组weights,在训练集上随机采样得到一批数据,在computational graphforward prop计算loss,然后back prop计算梯度,更新我们的weights,直到我们的loss小于误差。


这节课我们将学习训练NN的一些细节。

包括哪些东西呢?

1.one time setup

**函数的选取;预处理;权重初始化;正则化;梯度检查

2.training dynamics

检查调整学习过程;参数更新;超参数的最优化

3.评估模型效果


Activation functions

常见的**函数:

cs231n_lecture_6_怎样训练神经网络-PART 1

这些函数是不是用哪个都可以呢?他们之间有什么区别呢?可不可以对这些函数进行修改呢?下面我们一一探讨。

首先我们看到近些年常用的**函数都是非线性的,这一点符合神经细胞输出复杂的特性。

sigmoid函数

1.sigmoid将所有输入x压缩到[0,1]之间,如果x正的比较大,输出为1x负的比较大,输出接近0;如果x0附近,输出类似于一个线性函数。

2.sigmoid曾经十分流行,你可以把它看成是一个有饱和的**率的神经元。

缺点:
1.容易kill gradient

比如,当x=-10时,梯度=0,反向传播时参数就没有更新,x=10时类似。只有当x0附近时,能得到一个合适的梯度。

2。输出不是以0为中心的

f(WiXi + b)

x都是正数或负数的时候,lossw的导数(DL/DF * DF/DW)就全为正或负,这样当你在更新W的时候,所有Wi都朝着同一个方向更新,要么都增加要么都减少。

这是一种非常低效的更新方式,下图中蓝色是最优的W的向量,要找到这个W,我们要经过很多迭代才能到达。

cs231n_lecture_6_怎样训练神经网络-PART 1

这也引出了一个问题——我们总是希望zero-mean data

3.exp()  计算上较复杂。


tanh(x)

输出范围是[-1,1],是zero-center了。但是仍然存在killgradient的问题。


ReLU ——Rectified Linear Unit,2012年首次被使用

这是我们在之前的CNN中使用的函数。

1.在+ region没有饱和的问题了

2.计算也快,max(0,x)

3.在实际中比sigmoid和tanh收敛更快,大概快6倍

4.输出更接近生物学上的神经元than sigmoid

缺点:
1.不是zero-center的

2.当x<0时,仍然会饱和,kill gradient

存在dead ReLU的情况:
 cs231n_lecture_6_怎样训练神经网络-PART 1

当你的learning rate很高的时候,一开始的时候ReLU还是OK的,但是由于你的更新步长很大,weights会跳的很高,back prop的数据流就被阻塞了。

在训练的时候,就会出现这种情况:一开始模型更新好好的,从某个点开始,开始变坏直至死掉。这时候你停下来测试一下你的神经网络,给一批输入数据,你会发现有大约10%-20% 的结点死掉了。

这是一个问题,但并没有完全阻碍ReLuctant训练网络。

什么时候导致dead ReLu
当输入数据使得weights下降的时候会出现。


为了避免dead,有人会给ReLU 初始化一个很小的正的biases,比如0.01.但是实际中往往是有时有用,有时无用,大多数人还是使用zerobiases


Leaky ReLU

Max(0.01x,x)

1.不会饱和

2.计算简单

3.收敛快than sigmoid/tanh

4.不会dead


参数形式max(ax,x)a不是固定的,而是当做一个需要更新的参数back prop into and learn


ELU——Exponential Linear Units

1.有着ReLU的所有优点

2.更接近zero mean

3.参数a使得其对噪声有一定的鲁棒性


1.相比leaky ReLu还是会有负数区域饱和的情况,当然了比ReLU要好一点

2.exp()计算消耗大


Maxout()

——max(W1.T*x+b1,W2.T*x+b2)

ReLUleaky ReLU的推广。

1.线性的

2.不会饱和

3.不会die


1.需要两倍的参数:W1W2


In practice,指导原则:
1.
使用ReLU,小心设置自己learning rates

2.尝试leaky ReLU/maxout/ELU

3.尝试tanh,但是不要抱太大期望

4.不要用sigmoid


Data preprocessing

cs231n_lecture_6_怎样训练神经网络-PART 1

在图像领域,我们通常会zero centering data,原因上面介绍过,防止当数据都是pos或者neg,更新低效,使得数据流能顺利完成back prop

但是不常标准化数据。在ML中,数据很分散,来自不同特征,不同尺度,但是在image中,pixel采样时已经是相对集中分布的了。

ML中,还有一些更复杂的处理:

cs231n_lecture_6_怎样训练神经网络-PART 1

通常我们也不会做pca和白化。

在训练的时候我们通常只进行数据中心化处理。

训练时减去mean值,测试时减去同样的mean值。


有两种减去mean值的方法:

CIFAR-10为例:
1.减去平均图像([32,32,3] 每个像素各自的均值,AlexNet

2.减去每个通道的均值([3,] 3个通道各自的均值,VGGNet


这里的中心化能不能解决sigmoid等不是zero-mean的问题?

不能。因为初始输入的zero-mean只能解决第一层的问题,后面各个层就不能保证了。**函数本身不是zero-mean的谁也救不了它。


Weights initialization

初始化为0,即W=0

A:所有的神经元将做同样的事情(反向传播时得到的梯度值一样,更新操作也一样)。而我们期望的是不同的神经元学习得到不同的事情。

 

初始化为small random numbers

对小型的网络OK,对深层的网络将会出现问题。

我们可以看一个例子:10层,每层有500个神经元,,使用tanhw随机初始化为很小的数

cs231n_lecture_6_怎样训练神经网络-PART 1

我们画出每次迭代层输出的均值和方差:

cs231n_lecture_6_怎样训练神经网络-PART 1

均值都在0附近,嗯,tanh0均值的,这是我们想要的;但是我们发现,标准差很快下降,最终变成了0,也就是每一层的输出结果(activations)几乎一样。

我们再画出最后一次activations的分布:

cs231n_lecture_6_怎样训练神经网络-PART 1

第一层还接近于高斯分布(是我们想要的,why?),后面层的activations迅速缩小,最后几乎都是0了(因为我们一次又一次乘以W,而W很小)。

当我们做back prop的时候会出现什么情况呢?

可以设想我们的x狠下,因为做过zero-mean,当我们求w的梯度时就是x,因为x太小了,所以更新时w几乎不变,依然很小。当下一次forward prop时,w.dot(x)变得更小,形成了一个恶性循环,最终变成了0。

所以训练前我们可以经常想一想:当梯度流返回流过时,在不用的输入下,我们的前向传播会出现什么情况。

那我们就会想到把W初始化大点,还是用tanh():

cs231n_lecture_6_怎样训练神经网络-PART 1

我们看一下均值,方差,以及activations的分布图:
cs231n_lecture_6_怎样训练神经网络-PART 1

神经元都饱和了,要么是1要么是-1!也就是说W太大了,W*X很大,梯度都变成0了,W也就不更新了。

那怎样才是一个好的初始化呢?

一种方法是Xavier initialization

cs231n_lecture_6_怎样训练神经网络-PART 1

cs231n_lecture_6_怎样训练神经网络-PART 1

这种方法基于一个假设——就是激励是线性的。也就是输入在tanh的线性区。

如果你用的是非线性的ReLU,它会杀掉一般的神经元,你就得不到一个正确的方差(有一半的神经元坏掉了,而你计算方差时算进去了)。activations的分布也会迅速崩塌(应该是相较于一些输入来说w太小了),很多peaks将变成0.

cs231n_lecture_6_怎样训练神经网络-PART 1

改进如下:

将输入除以2,因为有一半神经元坏掉了,所以输入也只记一半。

cs231n_lecture_6_怎样训练神经网络-PART 1

cs231n_lecture_6_怎样训练神经网络-PART 1

初始化时一件需要认真对待的事,它决定了你的网络是得到一个好结果还是直接死掉,这一块有专门的人研究。

Batch normalization

批规范化可以得到单位高斯输入。

步骤:

1.对于输入数据,计算每个维度的meanvar的经验值

2.规范化:

cs231n_lecture_6_怎样训练神经网络-PART 1

通常将BN插在Fully Connected 或者Convolutional layers之后。

cs231n_lecture_6_怎样训练神经网络-PART 1

问题是我们需要单位高斯分布的输入吗?

实际上不是太明确。单位高斯的使得输入在非线性**函数的线性区,这样可以防止饱和,但是没人证明饱和就一定是不好的,也许一点点饱和是有益的。

所以说,你想控制你的神经元的饱和程度,在规范化之后,再加一个scalingshift的操作——乘以一个数scaling factor.再加上一个数shifting factor.。如果你想或者有必要,你的网络可以学习gammabeta,他们通常为mini-batchvarmean,这样你可以还原原来的数据(通过映射关系),就像你没有使用过BN一样。这样你就可以控制tanh的饱和程度了。

BN还带来一个好处就是增加了learning rateinitialization的鲁棒性,现在你可以尝试更多的数据了,它们都会得到一个好的结果。所以加入BN的网络变得更加容易训练了。

你可以把BN理解成一种regularizationactivations是输入x的输出,也就是batch data 的输出,这些输入被它们的meanvar规范化了,就相当于被绑定在一起了,就不会像没BN前各自输出各自固定的值。这时候如果你的X有一些jitters,也被稀释掉了,类似一种正则化的效果。

 

我们为什么要还原数据,有一个还原的步骤?

因为我们想给输入数据一种灵活性。我们把数据规范成了unit guassian,但是unit guassian不一定就是最好的啊,所以,比如说tanh,你希望它有一点saturation,就需要进行一点调整,有时候我们希望保留一点原始的想法,但是也要进行一点scaled or shifted,这样学习得到的gammabeta就有用了,它使得模型/输入/结点更新具有了一定的flexibility

当我们让模型去学习这些参数gamma and beta的时候,他们跟原来的恒等映射并不一样,会有一点改变,你可以理解为这个改变对模型是一种优化,它既保留了batch normalization effect,有使得模型具有一定的灵活性。

高斯化会丢失原始数据的结构吗?

不会。BN只是shiftingscaling你的data,将他们规范到一个范围,并不会影响数据的结果。同样,其他预处理,不如zero-mean等也不会。 


另外,只在训练时求meanstd,测试时不求,使用训练时得来的经验值。

cs231n_lecture_6_怎样训练神经网络-PART 1

cs231n_lecture_6_怎样训练神经网络-PART 1

深度学习Batch Normalization为什么效果好? - 魏秀参的回答 - 知乎

https://www.zhihu.com/question/38102762/answer/85238569

BN到底是什么原理呢?说到底还是为了防止“梯度弥散”。关于梯度弥散,大家都知道一个简单的栗子:

。在BN中,是通过将activation规范为均值和方差一致的手段使得原本会减小的activationscale变大。可以说是一种更有效的local response normalization方法。

关于梯度弥散和梯度爆炸:https://www.cnblogs.com/yangmang/p/7477802.html

Babysitting the learning process

可视化、监视训练过程、调整参数

1.预处理数据

2.设计网络结构——layersNeurons?

3.检查loss是否合理

先不要加正则化,记下loss,然后加上正则化,loss应该增加。

cs231n_lecture_6_怎样训练神经网络-PART 1

4.训练时,先从小的数据集开始,关掉正则化项,使用简单的SGD,此时应当能得到一个非常好的效果,loss接近0,甚至是过拟合的。

先从小的reg开始,找到使得loss下降的learning rate

如果loss下降太慢,就是lr太小了。

这里以softmax()为例:

cs231n_lecture_6_怎样训练神经网络-PART 1

为什么loss几乎没变,但是精确度很快增加到20%呢?
因为此时的概率分布依然是分散的,但是当我们把这些概率朝正确的方向稍微移动一点时,也就是权重向正确的方向移动了一点,因为我们是取得分最大值,此时纠正了很多错误的分类,准确率有了很大的提升。

如果leaning rate太大,cost就会得到NaN值,loss跳出最优方向,一直增加了。

hyperparameter optimization

学习速率,迭代次数,层数,每层神经元的个数(网络结构),正则化等等。

1.cross-validation策略

第一步:迭代一个小的次数,大致分析下现在的params是否有效,怎么调整

第二步:多迭代几步,进一步探索

反复

Tip:如果cost>3倍最初cost,肯定有问题了。

先设定一个范围:

cs231n_lecture_6_怎样训练神经网络-PART 1

cs231n_lecture_6_怎样训练神经网络-PART 1

调整:

cs231n_lecture_6_怎样训练神经网络-PART 1

cs231n_lecture_6_怎样训练神经网络-PART 1

2.随机搜索vs网格搜索

cs231n_lecture_6_怎样训练神经网络-PART 1

通常来说,随机搜索更佳,不会错过good region

3.可视化损失曲线

cs231n_lecture_6_怎样训练神经网络-PART 1

cs231n_lecture_6_怎样训练神经网络-PART 1

4.可视化准确率

cs231n_lecture_6_怎样训练神经网络-PART 1

最终我们在CNN里采用的方法如下:
1.Activationfunctions:ReLU

2.data preprocessing:减去mean

3.weight initializationXavier init

4.batch normalization:要的

5.Babysitting the learning process:要的

6.hyperparameter optimization:要的