训练集和测试集分布不匹配的情况很多:
如果没有测试集,仅有训练集和验证集,那么这个时候验证集被有些人们称之为测试集,但其实这个“测试集”起到的是验证集的作用。所以叫做测试集是错误的。只有两个划分的时候,就只有训练集和验证集。
存在高偏差高方差的情况:
上述结论是在基础误差很小的情况下成立的。
在大数据和深度学习时代,不用过多关心如何平衡偏差和方差。这是大数据和深度学习带来的一个益处。
在网络比较规范的情况下,训练一个更大的网络的主要代价也只是计算时间(or算力)。其他负面影响很小。
逻辑回归:
J(w,b)=1m∑mi=1L(y^(i),y(i))+λ2m||w||22 J ( w , b ) = 1 m ∑ i = 1 m L ( y ^ ( i ) , y ( i ) ) + λ 2 m | | w | | 2 2
L2 L 2 正则化: λ2m||w||22 λ 2 m | | w | | 2 2 ,其中, ||w||22=∑nxj=1w2j=wTw | | w | | 2 2 = ∑ j = 1 n x w j 2 = w T w
L1 L 1 正则化: λ2m||w||1=λ2m∑nxj=1|wj| λ 2 m | | w | | 1 = λ 2 m ∑ j = 1 n x | w j | ; L1 L 1 正则化之后的 w w 是稀疏的。
神经网络:
J(w[1],b[1],w[2],b[2],...,w[L],b[L])=1m∑mi=1L(y^(i),y(i))+λ2m∑Ll=1||w[l]||2F J ( w [ 1 ] , b [ 1 ] , w [ 2 ] , b [ 2 ] , . . . , w [ L ] , b [ L ] ) = 1 m ∑ i = 1 m L ( y ^ ( i ) , y ( i ) ) + λ 2 m ∑ l = 1 L | | w [ l ] | | F 2
L2 L 2 正则化: λ2m∑Ll=1||w[l]||2F λ 2 m ∑ l = 1 L | | w [ l ] | | F 2 ,其中, ||w||2F=∑n[l]i=1∑n[l−1]j=1w2ij | | w | | F 2 = ∑ i = 1 n [ l ] ∑ j = 1 n [ l − 1 ] w i j 2
则:
dw[l]=∂J∂w[l]+λmw[l] d w [ l ] = ∂ J ∂ w [ l ] + λ m w [ l ]
那么:
w[l]=w[l]−αdw[l]=w[l]−α(∂J∂w[l]+λmw[l])=(1−αλm)w[l]−α∂J∂w[l] w [ l ] = w [ l ] − α d w [ l ] = w [ l ] − α ( ∂ J ∂ w [ l ] + λ m w [ l ] ) = ( 1 − α λ m ) w [ l ] − α ∂ J ∂ w [ l ]
即正则化与没有正则化相比,就是在 w[l] w [ l ] 更新的时候减去了一个 αλmw[l] α λ m w [ l ] ,也就是为原来 w[l] w [ l ] 的 1−αλm 1 − α λ m 倍。
如果将 λ λ 取得非常大,那么很多 w w 接近于0,也就是网络变得更加简单,这样会从高方差(过拟合)导致到高偏差(欠拟合)。
但是 λ λ 适中的时候,我们会减少很多隐藏单元的影响,神经网络变得更简单,不容易发生过拟合。但也不会简化到欠拟合的程度。
直观理解:
如果 w w 在一个很小的区间,那么最后的 z z 也很小,经过激活函数的时候一直在其线性部分,如果整个网络都是这样,那么实际上,这就是个线性分类器。非线性的部分很少。也就是说,如果 w w 的范围小,那么网络去拟合数据集的非线性决策边界的能力就弱,不容易发生过拟合。
dropout是一种正则化
方法。
能防止过拟合。
除非算法过拟合,不然不使用dropout。
dropout:以一定概率随机删除网络中的神经单元。让每次训练的网络都不同。防止过拟合的问题。
dropout有很多种。
inverted dropout (反向随机失活):
训练阶段:
以神经网络的第三层为例: l=3 l = 3
keep_prob = 0.8 # 保留80%的节点,删除20%的节点。
d3 = np.random.rand(a3.shape[0], a3.shape[1]) < keep_prob # d3,第三层的dropout矩阵,a3,第三层的输出。
a3 = np.mutiply(a3, b3) # a3 *= b3,点乘
a3 /= keep_prob # 保持a3的期望和与dropout之前相比,不发生变化
a3 /= keep_prob
这一步,保持了a3
的期望不变,所以和不除相比,在测试阶段变得更容易,因为平均值不会发生太大变化。
inverted dropout 最常用。
测试阶段:
测试阶段不使用dropout,所以在训练阶段除以keep_prob
的意义就在于此。即让训练阶段和测试阶段的激活函数的预期结果不要发生太大变化。
对下一层的神经单元来说,上一次神经单元就是这个神经单元的输入。
因为神经单元的输入随时有可能被删除,所以该神经单元不能依赖于某一个特定的单一特征,必须将权重在所有特征上分配,也就是传播权重。
dropout的效果就是:收缩权重的平方范数。即:压缩权重。正则化
,防止过拟合。
功能上类似L2正则化
,不同之处是应用的方式不同,dropout也会有相应变化。更适用于不同的输入范围。
keep_prob=1
,即没有dropout正则化;keep_prob=1
,即使使用,keep_prob
的值也接近1
;keep_prob
可以不同: keep_prob
可以设置的小一些;keep_prob
可以设置的大一些,甚至是1
;keep_prob
设置成不一样的,这样做的缺点是:为了使用交叉验证,必须寻找更多的超参数。keep_prob
值。dropout的缺点:
代价函数J
没有办法去明确定义。因此,我们失去了调试工具,没有办法绘制梯度下降迭代的J
的下降曲线。
- 解决办法:
先将keep_prob=1
,即关闭dropout,待模型的代价函数的曲线下降后,再打开dropout。
Normalizing inputs
训练集数据算出 μ μ 和 σ2 σ 2 ;
用 μ μ 和 σ2 σ 2 对整个数据集(训练集、验证集、测试集)进行归一化;
梯度消失和梯度爆炸在本质上是一种情况。
梯度消失经常出现在深层网络和采用了不合理的损失函数之时,如sigmoid;
梯度爆炸经常出现在深层网络和权重初始化值太大之时。
激活函数角度
sigmoid函数的导数最大不超过0.25,选择这样的激活函数很容易导致梯度消失;
tanh比sigmoid略佳,但导数仍然小于1;
解决办法:
权重初始化是对一开始的 w w 进行初始化的技巧,可以减缓梯度消失和梯度爆炸。属于加快训练速度的技巧之一。
思想是,神经元的输入越多,所有的随机化的 wi w i 乘以 xi x i 的之和就越大。为了不变大,将 w w 的方差减小。即 w w 的方差为 1/n 1 / n
权重初始化,即对随机生成的 w w 的方差进行初始化。
W_l=np.random.randn((l_n, L_n_1))*np.sqrt(1/n)
在实际操作过程中,针对不同的激活函数, w w 有不同的方差。
- relu:
2n[n−1] 2 n [ n − 1 ]
w[l]=np.random.randn(shape)∗np.sqrt(2n[n−1]) w [ l ] = n p . r a n d o m . r a n d n ( s h a p e ) ∗ n p . s q r t ( 2 n [ n − 1 ] )
- tanh:
1n[n−1] 1 n [ n − 1 ] 或者 2n[n−1]+ n[n] 2 n [ n − 1 ] + n [ n ]
w[l]=np.random.randn(shape)∗np.sqrt(1n[n−1]) w [ l ] = n p . r a n d o m . r a n d n ( s h a p e ) ∗ n p . s q r t ( 1 n [ n − 1 ] )
w[l]=np.random.randn(shape)∗np.sqrt(2n[n−1]+ n[n]) w [ l ] = n p . r a n d o m . r a n d n ( s h a p e ) ∗ n p . s q r t ( 2 n [ n − 1 ] + n [ n ] )
以上就是初始化权重矩阵 w w 的方差的默认值。
在这些默认的方差效果不理想的情况下,可以调整方差的分子(算是一个超参数)——方差参数。在神经网络的众多超参数中,调整该参数的优先级很低。
双边误差比单边误差精确度更高,梯度的数值逼近一般用双边误差。
gradient checking
grad check
用梯度检验检查一个神经网络反向传播的正确与否。
dΘ[i]approx=J(…,θi+ϵ,…)−J(…,θi−ϵ,…)2ϵ d Θ a p p r o x [ i ] = J ( … , θ i + ϵ , … ) − J ( … , θ i − ϵ , … ) 2 ϵ
||dΘapprox−dΘ||2||dΘapprox||2+||dΘ||2 | | d Θ a p p r o x − d Θ | | 2 | | d Θ a p p r o x | | 2 + | | d Θ | | 2
取 ϵ=10−7 ϵ = 10 − 7
如果结果约等于 10−7 10 − 7 ,那么认为梯度没有问题。
如果大于了,可能就有bug。
keep_prob = 1
,再进行梯度检验。优化算法帮助你快速训练模型。
数据集分成若干个小的子集,每个子集叫一个mini-batch。每次训练神经网络,只用一个mini-batch,可以加快网络的训练速度。
x(i) x ( i ) ,第 i i 个样本;
z[i] z [ i ] ,第 i i 层神经网络;
X{i}, X { i } , 第 i i 个mini-batch,每一个mini-batch都有很多个样本;
必然要引入for循环,为了训练完所有的mini-batch。
1 epoch
:遍历了一遍训练集。1 epoch
只有一次梯度下降。1 epoch
有5000次梯度下降(每个mini batch
有1000个数据,整个训练集有500 0000个数据)。与batch gradient descent相比,mini-batch gradient descent的学习曲线没有那么平滑,有很多噪声,但总体趋势应该也是不断降低向下。
mini-batch size=m
:batch gradient descent——批梯度下降 (X{1},Y{1})=(X,Y) ( X { 1 } , Y { 1 } ) = ( X , Y ) ,单次迭代耗时太长。mini-batch size=1
:stochastic gradient descent——随机梯度下降,每一个样本就是一个mini-batch。 (X{i},Y{i})=(x(i),y(i)) ( X { i } , Y { i } ) = ( x ( i ) , y ( i ) ) ,失去向量化带来的加速作用,效率低。1 << mini-batch size << m
,mini batch gradient descent——mini-batch 梯度下降,介于梯度下降和随机梯度下降之间。mini-batch size not too big, not too small
——>学习速率最快。 batch梯度下降:
随机梯度下降:
mini-batch 梯度下降:
接下来几节学习比梯度下降快的优化算法。
在学习这些算法前,必须学会指数加权平均(统计学叫指数加权移动平均)。
向量化 Vθ V θ 的计算,基本上只占一行代码。
Vθ=0 V θ = 0
repeat:{ r e p e a t : {
get next θt g e t n e x t θ t
Vθ=βVθ+(1−β)θt V θ = β V θ + ( 1 − β ) θ t
} }
优点:
如果没有偏差修正,曲线的最左侧很小,无法反应真实情况。
那么添加偏差修正会改善这种情况。
即: Vθ=βVθ+(1−β)θt1−βt V θ = β V θ + ( 1 − β ) θ t 1 − β t
分开写:
Vθ=0 V θ = 0
repeat:{ r e p e a t : {
get next θt g e t n e x t θ t
Vθ=βVθ+(1−β)θt V θ = β V θ + ( 1 − β ) θ t
Vθ=Vθ/(1−βt) V θ = V θ / ( 1 − β t )
} }
对结果除以 1−βt 1 − β t ,效果是能够消除一开始的偏差,而对后期没有影响。
大部分人不愿意使用偏差修正,而是熬过初始时期。
如果你关心初始时期的偏差, 偏差修正能够帮助你在模型训练的早期获得更好的估计。
紫色为没有偏差修正,绿色为偏差修正后。
训练速度比标准的梯度下降法要快。
标准梯度下降(包括batch梯度下降、mini batch梯度下降、随机梯度下降),下降过程中存在波动。导致:1,训练模型耗时;2,无法使用过大的学习率 α α 。为了避免摆动过大,需要使用较小的 α α 。
在纵轴上,希望学习的慢一点;在横轴上,希望学习快。
Vdw=0、Vdb=0 V d w = 0 、 V d b = 0
On iteration t: O n i t e r a t i o n t :
compute dw、db on current mini-batch compute dw、db on current mini-batch
Vdw=βVdw+(1−β)dw V d w = β V d w + ( 1 − β ) d w
Vdb=βVdb+(1−β)db V d b = β V d b + ( 1 − β ) d b
w=w−αVdw w = w − α V d w
b=b−αVdb b = b − α V d b
两个超参数:
一般不会添加偏差修正;
在竖直方向上,计算指数加权移动平均值,正负相抵,减少纵轴方向上的波动;
在水平方向上,所有的微分都是指向最小值方向的,所以指数加权移动平均值的影响不大;
所以,纵轴方向波动减小,横轴方向运动更快。
即,在抵达最小值的路上减少了摆动。
想象一个碗装的函数,开口朝上。一个点位于碗的上沿。momentum梯度下降就相当于给下降的小球一个加速度。因为 β β 比1小一些,类似于摩擦力,所以速度不会无限制的增大下去。
在 Vdw=βVdw+(1−β)dw V d w = β V d w + ( 1 − β ) d w 中, Vdw V d w 就是前一刻的速度, dw d w 就是加速度。小球具有的动量会越来越大。
与梯度下降每次迭代都是独立的不同,模型可以从momentum梯度下降中获得一个越来越大的动量。而这个动量是跟以前的若干次梯度下降有关系的。
图像来自深度学习优化函数详解(4)– momentum 动量法
momentum GD可以想象成小球从坡上往下滚。小球的动量越来越大,过最低点后仍然会往前冲,如果冲到了另一个下坡。,有可能到一个更低点(更好的局部极小值)。如果动量没那么大,会慢慢的慢下来,再次返回到第一个低点。
0
的情况(导致参数变动很大),一般在 w=w−αdwSdw√ w = w − α d w S d w 添加一个很小的数字 ϵ ϵ ( ϵ=10−8 ϵ = 10 − 8 ),防止这种情况的发生,即: 0.9
(一般情况下);0.999
(Adam算法作者推荐);以固定的学习率 α α 去学习,在mini batch过程中存在噪声,下降的过程如上图所示,不会精确的收敛到最优解,而是在附近大幅度地振荡。
如果学习率会衰减,在学习初期的时候, α α 比较大,学习的速率比较快,随着 α α 的减小,步伐也渐渐变慢变小。最后学习曲线在最小值附近的一小块区域内摆动。
使用学习率衰减的原因是:
学习初期可以承受较大的步伐。
到了收敛的阶段,小的学习率可以让步伐变得小一些。
1 epoch = 1 pass through data
,即遍历一遍数据集;
第一次遍历数据集,(将数据集分为若干mini batch),为epoch 1
;
第二次,为epoch 2
;
那么:
α0=0.2 α 0 = 0.2 | decay rate = 1 |
---|---|
epoch | α α |
1 | 0.1 |
2 | 0.067 |
3 | 0.05 |
4 | 0.04 |
。。。 | 。。。 |
学习速率衰减可以加快训练的速度;
但在一开始调整模型的超参数的时候,不考虑学习率衰减;
设置一个固定的学习速率,待尝试出一个比较好的模型后,可以用学习速率衰减加快训练。
我们提起局部最优,往往想到的是如下图所示:
但梯度为0的点(驻点)不一定是一个局部极小值点,也有可能是鞍点。
往往代价函数梯度为0的点,是鞍点。
尽管梯度为0,但是在一个方向上为极小值点,在另一个方向上为极大值点。
在碰到鞍点这种情况的时候,鞍点附近为平稳段;
在平稳段,由于梯度接近于0,所以学习的步伐很小;
如图,算法慢慢抵达平稳段的鞍点,然后慢慢走出平稳段,这需要花费很长时间。
在训练较大的神经网络时:
α α 最重要;
其次是黄色部分;
最后是紫色部分;
随机取值可以提高对超参数的搜索效率。
使用对数尺度。
在Python中的用法:
也就是,如果 α α 的范围在 10a 10 a 到 10b 10 b 之间,那么,r的范围为[a, b]。
在[a, b]的范围内对r进行随机均匀取值。
即, α α 取值在对数刻度上随机均匀取值;希望能在每十倍程里边探索的 α α 的值一样多。
1−β=10r 1 − β = 10 r
β=1−10r β = 1 − 10 r
即 β β 在0.9-0.99、0.99-0.999之间探索的值一样多。
随着算法的不断改进、数据的不断变化,运算硬件的升级等,每隔几个月至少一次去重新测试和评估超参数。
超参数调整的两种不同方式(取决于算力大小):
对于逻辑回归,归一化输入,可以加速训练 w、b w 、 b 。
X(i) 2 X ( i ) 2 即 X X 中的每一个元素的平方,即点积。
那么,对于深层网络,可不可以归一化每层网络的激活函数的输出值 a[l] a [ l ] ,来加速训练 w[l+1]、b[l+1] w [ l + 1 ] 、 b [ l + 1 ] ?
严格来说,我们归一化的是 z[l] z [ l ] ,而不是 a[l] a [ l ] 。
学术界对归一化 z[l] z [ l ] 还是 a[l] a [ l ] 有争论。
但此处,我们学习归一化 z[l] z [ l ] 。
batch norm就是将归一化过程从输入层推广到了隐藏层。使得隐藏层单元值的均值和方差标准化,或者取得想要的均值和方差。
Given some intermediate values in NN :z[l](1)、...、z[l](m) Given some intermediate values in NN : z [ l ] ( 1 ) 、 . . . 、 z [ l ] ( m )
μ=1m∑iz[l](i) μ = 1 m ∑ i z [ l ] ( i )
σ2=1m∑i(z[l](i)−μ)2 σ 2 = 1 m ∑ i ( z [ l ] ( i ) − μ ) 2
z[l](i)norm=z[l](1)−μσ2+ϵ√ z n o r m [ l ] ( i ) = z [ l ] ( 1 ) − μ σ 2 + ϵ
z˜[l](i)=γz[l](i)norm+β z ~ [ l ] ( i ) = γ z n o r m [ l ] ( i ) + β
usez˜[l](i) instend of z[l](i) use z ~ [ l ] ( i ) instend of z [ l ] ( i )
其中, γ、β γ 、 β 为模型的learnable parameters。
参数 γ、β γ 、 β 的意义在于,给出任意均值和方差的 z z 。
比如,如果隐藏层使用的是sigmoid激活函数,那么,我们需要的输入可能就不是均值为0,方差为1的输入数据。
在反向传播更新 β、γ β 、 γ 的时候,可以使用梯度下降,也可以使用其他优化算法。
在深度学习框架中,不用自己去实现BN。已经有了现成的框架可以实现。
比如在tensorflow中,使用:tf.nn.batch_normalization()
虽然不用实现细节,但是必须了解原理。
实践中,BN往往和训练集的mini-batch一起使用。
网络的参数为: w[l]、β[l]、γ[l] w [ l ] 、 β [ l ] 、 γ [ l ] 。
为什么没有 b[l] b [ l ] ?
因为BN的过程,先是把数据的均值转换成0。再利用训练出来的参数 β β 给数据新的均值。那么,原始数据的参数 b[l] b [ l ] 不管如何取值,都会在均值转换成0这一步消掉。也就是,有没有 b[l] b [ l ] ,都不会影响到最后的 Z~[i] Z ~ [ i ] 。
如果输入数据 X{t} X { t } (第t批数据)为(n,m)
,那么,
for t = 1 ...... num of mini_batches: for t = 1 ...... num of mini_batches :
compute forward prop on X{t}: compute forward prop on X { t } :
in each hidden layer, use BN to replace Z[l] with Z~[l]; in each hidden layer, use BN to replace Z [ l ] w i t h Z ~ [ l ] ;
use back prop to compute dw[l]、dβ[l]、dγ[l]; use back prop to compute d w [ l ] 、 d β [ l ] 、 d γ [ l ] ;
update parameters w[l]=w[l]−αdw[l]、β[l]=β[l]−αdβ[l]、γ[l]=γ[l]−αdγ[l]; update parameters w [ l ] = w [ l ] − α d w [ l ] 、 β [ l ] = β [ l ] − α d β [ l ] 、 γ [ l ] = γ [ l ] − α d γ [ l ] ;
感性的理解,貌似BN是将输入数据归一化这一技巧用到了所有的隐藏层,而输入数据归一化的好处就是能加速网络的训练,但是其实,BN之所以有效,还有更深层次的原因:
对这个逻辑回归模型
用一个数据集训练网络来找猫。训练集正例的猫都是黑色的。而真正的数据集的正例是各种颜色的猫。
即训练集和验证集(以及测试集)的数据分布不一样。
那么,在左边训练的很好的模型,不能期待它同样在右边也运行的很好。即使真的存在在左右两侧都运行的很好的一个函数。
但你不能期望自己有这么好的运气。
这种问题,就叫做covariate shift 。
上边这个概念其实是有些错误的,再加以延伸:
上图有一个深层的网络,如果我们单看中间的第三层,在该层之前的前一层的输出 a[2]1 a 1 [ 2 ] 、…、 a[2]4 a 4 [ 2 ] 作为它的输入。
那么,蓝色部分的参数 w[l] w [ l ] 、 b[l] b [ l ] 由于参数更新而发生了变化,在发生变化后的网络中输入数据,最后得到的新的 a[2]1 a 1 [ 2 ] 、…、 a[2]4 a 4 [ 2 ] 可能和参数更新前的分布不一致。
或者说,在参数 w[l] w [ l ] 、 b[l] b [ l ] 更新前后,算出来的 a[2]1 a 1 [ 2 ] 、…、 a[2]4 a 4 [ 2 ] 的分布可能不一致(方差不同,均值不同)。
不同分布的 a[2]1 a 1 [ 2 ] 、…、 a[2]4 a 4 [ 2 ] 在输入后半部分以后,必然引起不同的结果。
这就是covariate shift 问题。
每一次计算均值和方差都是在一个mini batch上进行,而不是整个数据集。这样计算出来的 z~[l] z ~ [ l ] 会有噪声。所以,会对每一个隐藏层的激活函数添加噪声进去。这迫使后层的单元不过分依赖任何一个隐藏单元。类似于dropout,这种由在mini batch上计算均值和误差的方式会加入噪声,从而达到轻微的正则化效果。
算是BN的一个副作用。有时候,会期望这种副作用,有时候又要避免。
这种轻微正则化会随着mini batch的size的增大而减小。比如,mini batch为128的数据集,就比为512的数据集的正则化作用明显。
在训练集上,BN一次只能处理一个mini batch的数据。在一个mini batch上计算均值和方差。
而验证集和测试集不会去分mini batch。这时候BN怎么work呢?
测试的时候,没有mini batch,而测试集数据又是一个一个喂给模型的,没有 μ μ 和 σ2 σ 2 ,这个时候, μ μ 和 σ2 σ 2 从哪里来?
容易想到的是,用整个训练集数据去计算一个 μ μ 和 σ2 σ 2 ;
但更好的办法是,使用训练集数据在mini batch过程中计算出来的 μ μ 和 σ2 σ 2 的移动加权平均值。
关键词:softmax层,softmax激活函数
从二分类到多分类,从logistic回归推广到softmax回归。
注意:
以上为给一个多分类的神经网络加入softmax层,让其输出变成概率值。
在没有加入隐藏层的情况下,有logistics回归以及其升级版的softmax回归。
学习吴恩达ufldl的softmax回归
softmax是相对于hardmax的一个说法;
对一个向量:
所谓hardmax:
即在对应原向量最大元素的位置上放置1
,其他位置为0
;
所谓softmax:
成了概率值,这四个元素之和为1;
最大概率值对应的就是原始向量的最大值;
相对于hard max,soft max所做的从向量 z z 到最终概率的映射更为温和;
softmax回归是将logistics回归从二分类问题推广到了多分类问题:
多个类别的分类问题;
也就是,要让损失函数 L(y^,y) L ( y ^ , y ) 最小,在上图中,就必须让正确的标签值 y2 y 2 所对应的预测概率 y^2 y ^ 2 尽可能的大。