目录
三、自动调整学习速率(Learning Rate)
1.loss无法再下降时,gradient真的很小吗?
2.特制化learning rate
Root Mean Square
RMSProp
Adam:RMSProp+Momentum
3.Learning Rate Scheduling
Learning Rate Decay
Warm Up
4.Optimization的完整版本
四、分类(Classification)
1.Classification as Regression?
Class as one-hot vector
Classification with softmax
2.Loss of Classification
Mean Square Error
Cross-entropy
五、批次标准化(Batch Normalization)简介
Changing Landscape
feature normalization
Considering Deep Learning
Batch Normalization
接上篇李宏毅《机器学习》| 神经网络训练不起来怎么办(上)。
在训练一个network时,我们往往会把它的loss记录下来,随着参数update的次数增加loss通常会减小,最后就卡住了。多数时候可能会认为是因为走到了critical point,gradient=0,无法更新参数。但当loss无法再下降时,gradient真的很小吗?
比如当训练终止时,loss几乎已经不动,但gradient却在反复振荡。可能是现在的gradient在error surface山谷的两个谷壁间反复振荡,这时loss不会再下降,但gradient却不是最小的(步幅太大,没法掉下去)。
如果gradient descend所有的参数都设了同样的learning rate,那么当步幅过大时,无法得到较小的loss;反之,无法逼近local minima。当遇到更复杂的error surface,training一个deep network时,gradient descend或许是唯一可以依赖的工具。
我们需要gradient descend更好的版本——learning rate,特制化每一个参数。
一个大的原则是:如果某一方向上gradient值很小,即较为平坦,则希望learning rate大一点;反之,如果某一方向上坡度很大,可以让learning rate大一点。
修改学习率的具体操作:
这也被用在adagrad中。坡度缓的时候,gradient较小,而σ是gradient的平方和取平均再开根号。所以若gradient小则算出的σ就小,learning rate就大(蓝色曲线)。反之,坡度陡峭时,gradient较大,σ就比较大,learning rate就较小(绿色曲线)。
但就算是同一参数,所需的learning rate也会随时间而改变,所以希望learning rate可以动态调整。
RMS Prop的方法是新增一个α,这是一个需要自己调整的hyper parameter 。
以第二步为例:若α趋于0,代表相较于之前算出的gradient较重要;反之,如果α趋于1 ,代表现在算出的不太重要,之前算出的gradient较重要。 α决定了在整个里面占多大的影响力,用RMSProp就可以动态调整σ这一项。
如当滚到下坡时(第三个点)gradient 变大,如用RMSProp使α设小一点,即让刚看到的gradient影响较大的话,就可以很快使σ值变大,也就可以很快让步伐变小(踩一个刹车,避免飞出去)。
目前最常用的optimization的策略是Adam:RMSProp + Momentum
例如,一开始的那个简单的error surface无法train起来,加上 Adaptive Learning Rate 以后:
如右下角所示,最开始的方法只能走到刚刚拐弯的地方,加上Adam后逐渐可以走到终点。因为左右方向上的gradient很小,所以左右方向的learning rate会自动变大,不断前进。至于为什么走到一个地方突然爆炸,是由于是将所有的gradient累计,初始的地方很大,后来纵轴方向上的gradient都很小,累计了很多这样很小的gradient,当累计到一定程度后,step就变得很大,暴走喷出去;随后走到了gradient较大的地方,σ又慢慢变大,于是参数update的距离慢慢变小(左右振荡力度变小),又回到中间峡谷,所以喷出去后有办法修正回来。
解决的暴走的方法:Learning Rate Scheduling,即令learning rate与时间有关,随着时间增加令η越来越小,因为越更新离终点越近。
在刚刚的例子中如果使用该方法,在将要暴走的时候由于时间限制learning rate会慢慢变小,知道走到终点。
learning rate要先变大后变小
那么为什么要用warm up呢?一个可能的解释是,在中σ是一个统计的结果,传达某一个方向到底有多陡峭或者平滑的信息,但这需要足够多的数据统计结果才会精准。一开始σ并不精准,所以最开始不要使learning rate距离初始值太远,令learning rate小一点,探索、搜集有关error surface的信息;等σ统计得较为精准后,再慢慢增大learning rate(具体可见RAdam)。
momentum有考虑gradient的方向,root mean square考虑gradient的大小,所以两者并不会抵消。
接下来探讨的方向是:路不好走,就直接将山炸平,即能否通过修改Neural Network使得error surface变得相对平整,相对便于train。
Regression就是输入一个向量,输出一个数值,我们希望输出的数值跟某个label(目标)越接近越好。其实可以把Classification当作Regression来看:输出仍然是scaler y,要让y跟正确答案的Class越接近越好,但y是一个数字,所以必须把Class也变成数字。假设Class1就是编号1...,那y跟Class的编号越接近越好。
我认为这个方法只适合定序数据,即数字可以表示个体在有序状态中所处的位置,比如此时的假设意味着Class1跟Class2比较像,跟Class3比较不像;但不适合定类数据,即数字仅用于区分类别,没有序次关系。
比较常见的做法是把Class用one-hot vector来表示,此时两两Class之间的距离都是一样的。如果目标是一个向量,如是有3个element的向量,那network输出的维度也要是3个数字。目前为止所讲的network都只output一个数值(因为过去做的都是regression的问题,所以只output一个数字),那怎么改到三个数值呢?就是把本来output一个数值的方法重复三次:
把乘上3个不同的weight加上bias,得到,再把乘上另外3个weight加上另外一个bias得到,再把再乘上另外一组Weight再加上另外一个bias得到,就可以产生3组数字。此时input一个feature的vector,就产生,和,希望,和离目标越接近越好。
做classification时,往往会把y再通过一个叫做激活函数(softmax)的function得到y',然后计算y'跟间的距离。为什么要加上softmax呢?(关于softmax函数可以参考之前的笔记:激活函数)
一个比较简单的解释是,这个one-hot vector里的值都是0,1,但y里面有任何值。既然目标只有0和1,就先把y给normalize到0到1间,这样才好跟label计算相似度。
上图是soft-max的block,输入会产生。先把所有的y取一个exponential,就算是负数,取exponential后也变成正的;然后再对它做normalize,除掉所有y的exponential值的和,然得到y'。具体做法:分别取exponential后把它全部加起来,得到一个summation,再把exp 除summation,exp 除掉summation,exp 除掉summation,就得到,且都介于0到1之间,的和是1。除此之外,softmax还有一个附带的效果:会让大的值跟小的值的差距更大。
如果是两个class会是怎么样?既可以直接套用softmax这个function,但更常用的是sigmoid(这两件事情是等价的)。
把x丢到network里产生y后,会通过softmax得到y',再计算y'跟间的距离,记作е。计算y'跟间的距离不只一种做法。可以是Mean Square Error:计算里每一个element的平方和,当作error,即计算两个向量间的距离。当minimize MSE时,让等于y'。
一个更常用的做法是cross-entropy:,当跟y'相等时,也可以minimize cross-entropy的值,此时MSE会是最小的,cross-entropy也会是最小的。
Minimize Cross-entropy其实就是maximize likelihood(极大似然),它们两个就是一模一样的东西,只是同一件事不同的讲法而已。cross-entropy更常用在分类里,在pytorch里,cross-entropy和softmax是被绑在一起的,是一个set,只要copy cross-entropy,里面就自动内建了softmax。
接下来从optimization的角度说明相较于MSE,Cross-entropy更常被用于分类。
现在做3个class的分类:Network先输出,在通过softmax后产生。假设正确答案就是[1 0 0],计算向量[1 0 0]跟间的距离,用е来表示(可以是MSE,也可以是Cross-entropy)。假设的变化分别是-10-10,-10-10,-1000。由于设得很小,所以经过softmax后就非常趋近于0,跟正确答案非常接近,且对我们的结果影响很少。总之设一个定值,只看跟有变化的时候,对e、对loss有什么样的影响。
如果e分别设定为MSE跟Cross-entropy,算出来的Error surface会有什么不一样呢?
上图分别在e是MSE跟Cross-entropy时,的变化对loss对error surface的影响(红色代表loss大,蓝色代表loss小)。 如果很大,很小,就代表会很接近1,会很接近0,所以不管是对MSE或是Cross-entropy,大小时loss都是小的。反之,如果很小,很大的话,会很接近0,会很接近1,此时loss会比较大。 所以这两个图都是左上角loss大,右下角loss小,我们希望最后在training的时候,参数可以走到右下角。
假设选择Cross-Entropy,左上角这个地方是有斜率的,所以有办法透过gradient一路往右下走。 如果选MSE的话就卡住了,MSE在loss很大的地方是非常平坦的,如果初始在这个地方,离目标非常远,且gradient又很小(趋近于0),就无法用gradient descent顺利走到右下角。 如果做classification选MSE,有非常大的可能性会train不起来,当然这是在没有好的optimizer的情况下;如果用Adam,这个地方gradient很小,那learning rate会自动调大,也许还有机会走到右下角,不过这会让training比较困难,training的起步比较慢。 所以就算是loss function的定义,都可能影响training是不是容易,可以通过修改loss function改变optimization的难度。
如果error surface很崎岖,它比较难train,batch normalization就是其中一个把山铲平的想法。不要小看optimization这个问题,有时error surface是confessed的(比如碗状)都不见得很好train。
假设两个参数对loss的斜率差别非常大,在方向上斜率变化很小,上变化很大,如果learning rate是固定的,可能很难得到好的结果,所以需要adaptive的learning rate ,较进阶的optimization的方法才能够得到好的结果。
可以从另一个方向想,直接把难做的error surface改掉。假设有一个非常简单的linear model没有activation function,输入是,对应的参数是,什么样的状况会产生上面这种比较不好train的error surface呢?
如果或有改变,y就有改变,e随着也有改变,进而loss也有改变。当input很小时,假设的值都很小,有变化的时候,它对y的影响也是小的,进而loss变化也是小的。
反之,当input很大时 ,假设的值都很大,有变化时,它对y的影响也是大的,进而loss变化也是大的。
当input的feature每一个dimension的值它的scale差距很大时,就可能产生像这样的error surface。
如果可以给不同的dimension同样的数值范围,那可能就可以制造比较好的error surface,让training变得比较容易一点。有很多不同方法可以做到,将其统称为feature normalization。其中一个方法是:
假设到是所有训练资料的feature vector,把同一个dimension不同笔资料中的数值取出来,计算某个dimension的mean,记作;第i个dimension的standard deviation记作。接下来就可以做标准化normalization得到新的数值,做完normalization的dimension的数值平均是0 ,variances是1。
当所有的dimension都做一样的normalization后,所有feature不同的dimension的数值都在0上下,那可能就会制造一个比较好的error surface。所以像这样的normalization往往对training有帮助, 可以在做gradient descent的时使得loss收敛更快。
当然deep learning可以做feature normalization,可能会把feature做normalization以后得到,把它丢到deep network里面去做接下来的计算。但进一步地,对来说,其实也是另外一种input,虽然已经做过normalization,但通过后没有做normalization。
如果不同dimension间的数值分布仍然有很大差异的话,要train第二层的参数会不会也有困难呢?所以也应该对a或z进行normalization(对来说a或z其实也是一种feature)。 那应该在activation function之前做normalization还是之后呢?
在实际操作上这两件事情其实差异不大,如果选sigmoid,比较推荐对z做feature normalization(因为sigmoid在0附近斜率比较大,所以如果对z做feature normalization,把所有的值都挪到0附近,算出来的gradient值会比较大)。
对z做feature normalization:把z想成是另一种feature,分别计算三个vector里每一个dimension的μ和σ,然后把z标准化。
当改变的时候μ和σ也会随着改变 ,右侧的值也会跟着改变,之前是独立分开处理的,但在做feature normalization后,这三个example变得彼此关联了,所以做feature normalization时要把这一整个process,即收集feature算出μ和σ这件事情当做network的一部分。
也就是说之前的network都只是吃一个input得到一个output,现在这个大的network是吃一堆 input,用这堆input在这个network里算出μ和σ然后接下来产生一堆output。
随之而来的问题是:训练资料里的data非常多,没有办法一次把上百万的数据丢到一个network里面。在实际操作中,不应该让这个network考虑整个training data里所有的example,只会考虑一个batch里的example。因为在实际操作中只对一个batch里的data做normalization,即batch normalization。注:Batch Normalization适用于batch size比较大的时候。
在做Batch Normalization时候,往往还会有下面的操作:
实操中,γ初始值是一个都是1的向量,β初始值是一个都是0的向量。network在一开始训练时,每个dimension的分布是较接近的,也许训练够长的一段时间,已经找到一个较好的error surface,走到一个好的地方后,再把γ和β慢慢加进去。
接下来是testing部分,有时又叫inference。Batch Normalization在testing中遇到一些问题:假设真的有系统上线,batch设64,一定要等64笔资料都进来才做一次运算吗?这显然是不行的,如果是线上服务,每笔资料进来都有做一次运算,不能等累积了一个batch的资料才开始做运算。那如果根本就没有一个batch,应该怎么算μ和σ?
实际上pytorch已经帮你处理好了。用训练时得到的和来代替。其中p是一个hyper parameter,通常设为0.1。
具体可参考论文:
其中黑色虚线代表没有做batch normalization的结果,红色的虚线代表用了batch normalization的结果,可以在比较短的时间内跑到比较好的结果。