本系列文章是吴恩达深度学习攻城狮系列课程的笔记,分为五部分。
这一章讲了关于优化神经网络的一系列trick,注重实践,否则会忘掉。
我的笔记不同于一般的笔记,我的笔记更加凝练,除了结论以及公式,更多的是对知识的理解,结合课程可以加速理解,省去很多时间,但是请注意,笔记不能替代课程,应该结合使用。
结构化机器学习项目,我建议放在最后看。
首先学这一节对你后面的学习没有影响,我就是跳过去学的。而且他更多的讲的是策略,尤其是举了很多后面的例子,你听了不仅不太好懂,而且没啥意思,所以我建议放在最后看。
神经网络与深度学习(Neural Networks and Deep Learning)
改善深层神经网络:超参数调整,正则化,最优化(Hyperparameter Tuning)
卷积神经网络(Convolutional Neural Networks)
序列模型与循环神经网络(Sequence Models)
结构化机器学习项目(Structuring Machine Learning Projects)
用来训练算法
调整参数,选择特征,以及对学习算法做出其他决定
从开发集中选出最优的几个模型在测试集上进行评估
以前数据量小的时候,是622分,但是当数据量变大,dev set和test set的增长没有那么快,所以后面这两个的比例会缩小,比如98 1 1的比例
一般小样本会习惯于7的训练3的测试,但是实际上严格来说,开发和测试是不可以混为一谈的,其两者的目的不一样
目前的理解也仅限于此,至于dev和test的区别,网上的总结千篇一律,都是抄吴恩达的讲义,我还需要后面进一步在实践中感悟。
欠拟合就是没把大头当回事,过拟合就是将偶然太当真。欠拟合准确率不够,过拟合不具有普遍适应性。
字面意思
模型对测试集的准确率高,则偏差低
模型在测试集和开发集上的差距小,则方差低。为什么叫方差呢?因为同一个模型,两个集上差距不大,说明两个集本身的差距就不大,均匀分布,就是方差小。还可以体现出模型是否过拟合,过拟合会加大方差。
一般来说,默认0,这是假设人工识别准确率极高。如果这个是15%,那么在训练集上16%的错误率就是很完美的拟合。毕竟,机器的效果是要和人对比的,人不行,机器也没必要做到极致。
解决高偏差
解决高方差
最终得到一个双低模型。一般来说,采用更多数据和更大网络可以更好的实现trade-off,
说白了,正则化就是减弱联系,制造干扰,来提高抗干扰行。
这里要用到范数,所以可以参考这篇文章
正则化是对J(cost function)下手的,进而影响到反向传播中的参数调整过程。
对Logistic Regression,我们可以采用L2和L1
J
(
w
,
b
)
=
1
m
∑
i
=
1
m
L
(
y
(
i
)
^
,
y
(
i
)
)
+
λ
2
m
∣
∣
w
∣
∣
2
+
λ
2
m
b
2
J(w,b)=\dfrac{1}{m}\sum_{\mathclap{i=1}}^{m}L(\hat{y^{(i)}},y^{(i)})+\dfrac{\lambda}{2m}||w||_2+\dfrac{\lambda}{2m}b^2
J(w,b)=m1i=1∑mL(y(i)^,y(i))+2mλ∣∣w∣∣2+2mλb2
理论上,b那一项不用写,因为和高维度的w比,b那一项没什么影响。
J
(
w
,
b
)
=
原有项
+
λ
2
m
∣
∣
w
∣
∣
1
J(w,b)=原有项+\dfrac{\lambda}{2m}||w||_1
J(w,b)=原有项+2mλ∣∣w∣∣1
L1的特点是,最后生成的w中0会多一些,有人说可以压缩模型体积,但是实际上体积没什么明显变化,所以目前主流还是采用L2
在深层神经网络中,就直接用L2了,但是需要注意的是,L2并不是用2范数,而是用Frobenius范数,就一种arcane的玄学原因导致明明是2范数的特征却使用Frobenius范数的名称
J
=
原有项
+
λ
2
m
∑
i
=
1
L
∣
∣
W
[
i
]
∣
∣
F
J=原有项+\dfrac{\lambda}{2m}\sum_{\mathclap{i=1}}^{L}||W^{[i]}||_F
J=原有项+2mλi=1∑L∣∣W[i]∣∣F
可以理解为加上所有元素的平方和根号
d
W
[
i
]
=
原有项
+
λ
m
W
[
i
]
dW^{[i]}=原有项+\dfrac{\lambda}{m}W^{[i]}
dW[i]=原有项+mλW[i]
形式上,F范数里是有平方项的,所以求个导把2分母消掉就好说。
仍然是用原有的公式,但是因为dW变化,所以W更新公式可以重写:
W [ i ] = W [ i ] − α [ 原有项 + λ m W [ i ] ] W^{[i]}=W^{[i]}-\alpha [原有项+\dfrac{\lambda}{m}W^{[i]}] W[i]=W[i]−α[原有项+mλW[i]]
W
[
i
]
=
(
1
−
λ
m
)
W
[
i
]
−
α
原有项
W^{[i]}=(1-\dfrac{\lambda}{m})W^{[i]}-\alpha 原有项
W[i]=(1−mλ)W[i]−α原有项
从这个角度理解,相当于W在更新之前先进行了缩放,常被称作weight decay。不过吴恩达不喜欢这么叫,或许这么理解没什么用。
从效果上来说,L2正则化的效果是将W的权值缩小。正则化参数 λ \lambda λ 越大,W的权值下降的更快,而且越小。
而且,即使是新增了一项,从效果上来说,新的J函数依然凸的,依然随着迭代次数的增加而monotonically减少。
反过来说,如果你使用正则化计算方法但是画图的时候还是用的旧的cost function,那你的函数图可能就不是单调的了。
当W的权值减少,那么部分神经元的效果就会打折扣,效果上相当于收缩了神经网络的规模。随着收缩,逐渐从过拟合转移到欠拟合高偏差状态,最后就变成了Logistic Regression。
当W权值减小,那么Z的值也会小,那么无论是ReLU还是sigmoid或者tanh函数,0附近的是g函数近似于线性的,前面也说过,如果一个神经网络都是线性的,那么就会被简化,所以这种理解方式其实也是从简化神经网络的角度理解的。
思想:随机让一部分神经元失效,生成一个简化的子神经网络。
常用方法:反向随机失活(inverted dropout)
步骤:
理解:
将数据进行轻微改变,比如翻转之类的,制造类似的数据,可以实现类似于正则化的效果,减弱过拟合。
将J函数和dev error画在一个图上,然后在要发生过拟合的附近终止训练即可。
优点:简单快速。
缺点:无法发挥出其他工具的力量,试图使用一个方法同时降低bias和variance,难以取得极致的效果。
μ
n
×
1
=
1
m
∑
i
=
1
m
X
(
i
)
\mu_{n\times 1} = \dfrac{1}{m}\sum_{\mathclap{i=1}}^mX^{(i)}
μn×1=m1i=1∑mX(i)
X
−
=
μ
X-=\mu
X−=μ
σ
n
×
1
2
=
1
m
∑
i
=
1
m
X
(
i
)
∗
∗
2
\sigma^2_{n\times 1}=\dfrac{1}{m}\sum_{\mathclap{i=1}}^mX^{(i)}**2
σn×12=m1i=1∑mX(i)∗∗2
X
/
=
σ
2
X/=\sqrt{\sigma^2}
X/=σ2
理解:
经过实验可以观察出:归一化后,即使是相差比较悬殊的维度,最后的范围也会相近,最多只是几倍的差距。如果不归一化,正常情况的cost function是一个狭长的(elongated)碗,对于狭窄维,需要定很小的步长来保证尽量收敛。
如果归一化,就可以选择尽量大的步长,学习率。
之前说过最后的结果是类似于W矩阵的累乘,那么在深度学习中很明显会产生一种指数效应,W的整体权小于1就会产生梯度消失,大于1会产生梯度爆炸,拖慢训练速度。所以我们要让W的初值权重大约为1附近
引理:如果输入特征 A [ i − 1 ] A^{[i-1]} A[i−1]就是大约标准化的,经过权重为1的W矩阵处理, Z [ i ] Z^{[i]} Z[i]仍然保持近似标准化的。
常用方法是进一步特殊地初始化W矩阵,不仅要更趋近于0,而且要自适应样本数量。
首先,假设 v a r ( W ) = 1 n var(W)=\dfrac{1}{n} var(W)=n1
然后:
W
[
i
]
=
n
p
.
r
a
n
d
o
m
.
r
a
n
d
n
(
W
[
i
]
.
s
h
a
p
e
)
∗
n
p
.
s
q
r
t
(
1
n
i
−
1
)
W^{[i]}=np.random.randn(W^{[i]}.shape)*np.sqrt(\dfrac{1}{n^{{i-1}}})
W[i]=np.random.randn(W[i].shape)∗np.sqrt(ni−11)
方差选择
偏导的近似求法:
应该使用双边误差, f ′ ( θ ) = f ( θ + ϵ ) − f ( θ − ϵ ) 2 ϵ f^\prime(\theta)=\dfrac{f(\theta+\epsilon)-f(\theta-\epsilon)}{2\epsilon} f′(θ)=2ϵf(θ+ϵ)−f(θ−ϵ)
其误差为 O ( ϵ 2 ) O(\epsilon^2) O(ϵ2)比单边误差的 O ( ϵ ) O(\epsilon) O(ϵ)要小很多
求解过程(Grad Check):
注意:
方法:
理解:
说白了,指数加权平均就是牺牲一点精准度来快速计算平均值。
在趋势预测中,我们要得出拟合线,拟合线的计算公式为:
v
t
=
β
v
t
−
1
+
(
1
−
β
)
θ
t
v_t=\beta v_{t-1}+(1-\beta)\theta_t
vt=βvt−1+(1−β)θt
其中,v代表拟合值,
θ
\theta
θ代表样本值
具体执行就是对v不断更新覆盖,如果想记录可以用一个列表来记录。这样求平均比直接求效率高很多,是一种替代方法。
我们可以这样理解:
偏差修正:
在初期求平均时,因为前面没有积累,会造成结果远低于真实值的偏差,这个时候就可以使用 v t = v t 1 − β t v_t=\dfrac{v_t}{1-\beta^t} vt=1−βtvt来修正,天数越少,放大效应越明显。
最终,原来的线会收敛到修正线上。
实际上,无论是batch还是mini-batch,梯度下降的方向并不总是最好的方向,存在着非最优方向的波动,这限制了我们对学习率的加大。反过来说,如果能保持接近正确的方向,就意味着我们可以加大学习率。
具体执行:
理解公式:
这同样是用来稳定方向的。
对每一次更新:
理解:
偏差修正:
综合Momentum和RMSProp,以及两种方法的修正,一种广泛适用且有效的优化算法Adam诞生了。
对t次mini-batch:
可调节超参数:
为了最后的收敛(converge),在最后阶段学习率不能太大。但是并不意味着在初始阶段学习率就不能大。理论上,刚开始大后面小是最佳选择。
使得初期快速向最低点迈进,后期快速收敛。
随epoch减少的各种实现方法:
α
=
1
1
+
D
e
c
a
y
−
r
a
t
e
×
E
p
o
c
h
−
n
u
m
×
α
0
\alpha=\dfrac{1}{1+Decay-rate\times Epoch-num}\times \alpha_0
α=1+Decay−rate×Epoch−num1×α0
此方法需要调节的超参数为
α
0
,
D
e
c
a
y
−
r
a
t
e
\alpha_0,Decay-rate
α0,Decay−rate
指数衰减(exponentially decay)
α
=
b
a
s
e
e
p
o
c
h
−
n
u
m
×
α
0
\alpha=base^{epoch-num}\times \alpha_0
α=baseepoch−num×α0
此方法需要调节的超参数为
b
a
s
e
,
α
0
base,\alpha_0
base,α0
还有其他各种方法,总之就是一个随着epoch-num增加而递减的系数。
α
=
k
e
p
o
c
h
−
n
u
m
×
α
0
\alpha=\dfrac{k}{\sqrt{epoch-num}}\times \alpha_0
α=epoch−num
k×α0
α
=
k
t
×
α
0
\alpha=\dfrac{k}{\sqrt{t}}\times \alpha_0
α=t
k×α0
α
=
d
i
s
c
r
e
t
e
−
s
t
a
i
r
c
a
s
e
\alpha=discrete-staircase
α=discrete−staircase,使用一个离散的分段函数来搞定。
还有手动调节方法:
就是你盯着你的模型,如果发现慢了,就自己调一下,有很多人在这么干,但是如果同时训练太多模型,这种方式就不实用了。
曾经人们担心出现大量的局部最优点,因为在二维空间上很容易产生。
但是实际上二维空间的直觉并不总是适应高维空间,比如20000维的空间,要让所有维度都是凸函数,可能性为 2 − 20000 ≈ 0 2^{-20000}\approx 0 2−20000≈0,也就是说,非全局最优点以外,导数为0的点,在高位空间大多是鞍点(saddle point)。
虽然不会造成局部最优问题,但是鞍点的平稳段(plateaus)仍然会造成学习缓慢的问题,所以优化算法就是用来加速来解决学习缓慢的问题的。
一般来说,超参数虽然多,但是也有个主次,以下是顺序
第一梯队:
第二梯队:
第三梯队:
首先就是有一个参数空间,维数和超参数数量相同。
有以下惯例(common practice):
其他技巧——非均匀选点:
一般来说,均匀选点是可以应付的。
但有时候,靠近0的要取得密集一点,也就是灵敏性会发生变化。这种时候就应该先进行线性变换,然后取对数,再均匀随机取点,最后用指数变回去,实现非均匀化,从一端到另一端逐渐稀疏。
比如:
α
[
0.0001
,
1
]
\alpha [0.0001,1]
α[0.0001,1],我们用
[
l
g
1
0
−
4
,
l
g
1
]
[lg10^{-4},lg1]
[lg10−4,lg1] 的区间
代码实现就是
r
=
−
4
∗
n
p
.
r
a
n
d
o
m
.
r
a
n
d
(
)
r=-4*np.random.rand()
r=−4∗np.random.rand()
α
=
1
0
r
\alpha=10^r
α=10r
又比如:
β [ 0.9 , 0.999 ] \beta [0.9,0.999] β[0.9,0.999],然后对我们来说, 1 1 − β \dfrac{1}{1-\beta} 1−β1才是重要的。取不取倒数对于均匀分布不影响,所以我们这里直接用 1 − β 1-\beta 1−β,即 r ∈ [ − 3 , − 1 ] , 1 − β = 1 0 r r \in [-3,-1],1-\beta=10^r r∈[−3,−1],1−β=10r 。从这个案例可以看出,用1做个减法就可以实现密集端的互换。
最后,再加几条技巧:
这是logistic regression归一化的深层版本batch-normalization可以让参数优化变得更加容易,神经网络更鲁棒。
通常和mini-batch一起使用,对iteration t:
结果不止两种,这种判断叫soft-max regression。
实际上,softmax是logistic彻头彻尾的推广。激活函数的算法都是sigmoid的推广。(具体细节在最后)
类比logistic regression,我们把输出层的sigmoid单节点层换成soft-max层,神经元个数由1变为C,激活函数使用其他的。
fp:
只需要推广最后一层的激活函数即可, g [ L ] 如下 g^{[L]}如下 g[L]如下:
bp:
令C=2,然后用一个样本实验。之所以用 z 2 = 0 z_2=0 z2=0是因为sigmoid的单样本实际上只接收一个特征。
输入:
[
z
1
z
2
=
0
]
\begin{bmatrix} z_1 \\ z_2=0 \\ \end{bmatrix}
[z1z2=0]
输出:
[
e
z
1
e
z
1
+
e
z
2
e
z
2
e
z
1
+
e
z
2
]
\begin{bmatrix} \dfrac{e^{z_1}}{e^{z_1}+e^{z_2}} \\ \\ \dfrac{e^{z_2}}{e^{z_1}+e^{z_2}}\\ \end{bmatrix}
⎣
⎡ez1+ez2ez1ez1+ez2ez2⎦
⎤
化简得:
[
1
1
+
e
−
z
1
1
−
1
1
+
e
−
z
1
]
=
[
s
i
g
m
o
i
d
(
z
1
)
1
−
s
i
g
m
o
i
d
(
z
1
)
]
\begin{bmatrix} \dfrac{1}{1+e^{-z_1}} \\ \\ 1-\dfrac{1}{1+e^{-z_1}} \\ \end{bmatrix} = \begin{bmatrix} sigmoid(z_1) \\ 1-sigmoid(z_1) \\ \end{bmatrix}
⎣
⎡1+e−z111−1+e−z11⎦
⎤=[sigmoid(z1)1−sigmoid(z1)]
是不是一下就明了了。
之前我们都是白手起家(from scratch)的,现在为了提高效率,我们要使用框架了。
框架的核心在于使用计算图实现链式法则的自动求导,解放双手,让数据科学家能够专注于fp,而bp这种机械的工作交给机器。
存在即合理,现在大量的框架都在高速发展,所以吴恩达没有强烈推荐(endorse)某一个框架,只是给出了评选标准(criteria):
如果非要提出几个,其实无非就是两个,tensorflow和pytorch,一个工业,一个学术。具体用法也不必举出,涉及的东西比较多,需要独立搜索。