Ng深度学习笔记 超参数调试和Batch正则化
超参数调试与batch正则化
调试处理(Tuning process)
训练深度最难的事情之一是参数的数量。
结果证实一些超参数比其它的更为重要,我认为,最为广泛的学习应用是 a a a,学习速率是需要调试的最重要的超参数。
除了 a a a,还有一些参数需要调试,例如Momentum参数 β \beta β,0.9就是个很好的默认值,还有mini-batch的大小,以确保最优算法运行有效。
超参数有重要性区别。
a
a
a无疑是最重要的,接下来是用橙色圈住的那些,然后是用紫色圈住的那些,但这不是严格且快速的标准。
选择调试值: 在早一代的机器学习算法中,有两个超参数时常在网格中取样点,然后系统的研究这些数值。如5×5的网格,实践证明,网格可以是5×5,也可多可少,但对于这个例子,你可以尝试这所有的25个点,然后选择哪个参数效果最好。当参数的数量相对较少时,这个方法很实用。
在深度学习领域,常常随机选择点来调整。
给超参数取值时,另一个惯例是采用从粗到细的搜索:比如在二维的那个例子中,发现效果最好的某个点,接下来要做的是放大这块小区域(小蓝色方框内),然后在其中更密集得取值或随机取值,在这个蓝色的方格中搜索。
为超参数选择合适的范围(Using an appropriate scale to pick hyperparameters)
看看这个例子,假设你在搜索超参数 a a a(学习速率),假设你怀疑其值最小是0.0001或最大是1。如果你画一条从0.0001到1的数轴,沿其随机均匀取值,那90%的数值将会落在0.1到1之间,结果就是,在0.1到1之间,应用了90%的资源,而在0.0001到0.1之间,只有10%的搜索资源。
反而,用对数标尺搜索超参数的方式会更合理,因此这里不使用线性轴,分别依次取0.0001,0.001,0.01,0.1,1,在对数轴上均匀随机取点,这样,在0.0001到0.001之间,就会有更多的搜索资源可用。
所以在Python中,使r=-4*np.random.rand()
,然后
a
a
a随机取值,
a
=
1
0
r
a =10^{r}
a=10r,所以,
r
∈
[
4
,
0
]
r \in [ 4,0]
r∈[4,0],
a
∈
[
1
0
−
4
,
1
0
0
]
a \in[10^{-4},10^{0}]
a∈[10−4,100],最左边的数字是
1
0
−
4
10^{-4}
10−4,最右边是
1
0
0
10^{0}
100。
即,在对数坐标下取值, a a a为最小值的对数, b b b为最大值的对数,在 a a a, b b b间随意均匀的选取 r r r值,将超参数设置为 1 0 r 10^{r} 10r。
另一个棘手的例子是给 β \beta β 取值,用于计算指数的加权平均值。假设 β \beta β是0.9到0.999之间的某个值,也许这就是你想搜索的范围。
如果在0.9到0.999区间搜索,那就不能用线性轴取值。考虑这个问题最好的方法就是探究 1 − β 1-\beta 1−β,此值在0.1到0.001区间内。
β \beta β值如果在0.999到0.9995之间,这会对算法产生巨大影响,对吧?在这两种情况下,是根据大概10个值取平均。但这里,它是指数的加权平均值,基于1000个值,现在是2000个值,因为这个公式 1 1 − β \frac{1}{1- \beta} 1−β1,当 β \beta β接近1时, β \beta β就会对细微的变化变得很敏感。所以整个取值过程中,需要更加密集地取值,在 β \beta β 接近1的区间内,或者说,当 1 − β 1-\beta 1−β 接近于0时,这样,你就可以更加有效的分布取样点,更有效率的探究可能的结果。
超参数调试的实践
如何搜索超参数?
-
babysit一个模型,通常是有庞大的数据组,但没有许多计算资源或足够的CPU和GPU的前提下,可以逐渐改良,观察它的表现,耐心地调试学习率,但那通常是因为没有足够的计算能力,不能在同一时间试验大量模型时才采取的办法。
-
同时试验多种模型。设置了一些超参数,尽管让它自己运行,或者是一天甚至多天。
归一化网络的**函数
Batch归一化:
归一化输入特征可以加快学习过程。
一般归一化
z
(
i
)
z^{(i)}
z(i)。减去均值再除以标准偏差,为了使数值稳定,通常将
ε
\varepsilon
ε作为分母,以防
σ
=
0
σ=0
σ=0的情况。
所以现在 z z z的每一个分量都含有平均值0和方差1,但也许隐藏单元有了不同的分布会有意义,所以 z ~ ( i ) = γ z norm ( i ) + β {\tilde{z}}^{(i)}= \gamma z_{\text{norm}}^{(i)} +\beta z~(i)=γznorm(i)+β这里 γ \gamma γ和 β \beta β是学习参数,作用是设置 z ~ ( i ) {\tilde{z}}^{(i)} z~(i)的平均值。
如果 γ = σ 2 + ε \gamma= \sqrt{\sigma^{2} +\varepsilon} γ=σ2+ε ,如果 γ \gamma γ等于这个分母项( z norm ( i ) = z ( i ) − μ σ 2 + ε z_{\text{norm}}^{(i)} = \frac{z^{(i)} -\mu}{\sqrt{\sigma^{2} +\varepsilon}} znorm(i)=σ2+ε z(i)−μ中的分母), β \beta β等于 μ \mu μ,这里的这个值是 z norm ( i ) = z ( i ) − μ σ 2 + ε z_{\text{norm}}^{(i)}= \frac{z^{(i)} - \mu}{\sqrt{\sigma^{2} + \varepsilon}} znorm(i)=σ2+ε z(i)−μ中的 μ \mu μ,那么 γ z norm ( i ) + β \gamma z_{\text{norm}}^{(i)} +\beta γznorm(i)+β的作用在于,它会精确转化这个方程,如果这些成立( γ = σ 2 + ε , β = μ \gamma =\sqrt{\sigma^{2} + \varepsilon},\beta =\mu γ=σ2+ε ,β=μ),那么 z ~ ( i ) = z ( i ) {\tilde{z}}^{(i)} = z^{(i)} z~(i)=z(i)。
通过对 γ \gamma γ和 β \beta β合理设定,规范化过程,即这四个等式,从根本来说,只是计算恒等函数,通过赋予 γ \gamma γ和 β \beta β其它值,可以构造含其它平均值和方差的隐藏单元值。
将 Batch Norm 拟合进神经网络(Fitting Batch Norm into a neural network)
神经网络中,每个单元负责计算计算z,然后应用其到**函数中再计算a,每个圆圈代表着两步的计算过程。
如果你没有应用Batch归一化,你会把输入
X
X
X拟合到第一隐藏层,然后首先计算
z
[
1
]
z^{[1]}
z[1],这是由
w
[
1
]
w^{[1]}
w[1]和
b
[
1
]
b^{[1]}
b[1]两个参数控制的。接着,通常而言,你会把
z
[
1
]
z^{[1]}
z[1]拟合到**函数以计算
a
[
1
]
a^{[1]}
a[1]。但Batch归一化的做法是将
z
[
1
]
z^{[1]}
z[1]值进行Batch归一化,简称BN,此过程将由
β
[
1
]
{\beta}^{[1]}
β[1]和
γ
[
1
]
\gamma^{[1]}
γ[1]两参数控制,这一操作会给你一个新的规范化的
z
[
1
]
z^{[1]}
z[1]值(
z
~
[
1
]
{\tilde{z}}^{[1]}
z~[1]),然后将其输入**函数中得到
a
[
1
]
a^{[1]}
a[1],即
a
[
1
]
=
g
[
1
]
(
z
~
[
l
]
)
a^{[1]} = g^{[1]}({\tilde{z}}^{[ l]})
a[1]=g[1](z~[l])。
Batch归一化是发生在计算 z z z和 a a a之间的。直觉就是,与其应用没有归一化的 z z z值,不如用归一过的 z ~ \tilde{z} z~,这是第一层( z ~ [ 1 ] {\tilde{z}}^{[1]} z~[1])。所以网络的参数就会是 w [ 1 ] w^{[1]} w[1], b [ 1 ] b^{[1]} b[1], w [ 2 ] w^{[2]} w[2]和 b [ 2 ] b^{[2]} b[2]等等,我们将要去掉这些参数。但现在,想象参数 w [ 1 ] w^{[1]} w[1], b [ 1 ] b^{[1]} b[1]到 w [ l ] w^{[l]} w[l], b [ l ] b^{[l]} b[l],我们将另一些参数加入到此新网络中 β [ 1 ] {\beta}^{[1]} β[1], β [ 2 ] {\beta}^{[2]} β[2], γ [ 1 ] \gamma^{[1]} γ[1], γ [ 2 ] \gamma^{[2]} γ[2]等等。对于应用Batch归一化的每一层而言。
接下来可以使用优化算法。
实践中,Batch归一化通常和训练集的mini-batch一起使用。
一个细节: z [ l ] = w [ l ] a [ l − 1 ] + b [ l ] z^{[l]} =w^{[l]}a^{\left\lbrack l - 1 \right\rbrack} +b^{[l]} z[l]=w[l]a[l−1]+b[l],将 z [ l ] z^{[l]} z[l]归一化,结果为均值0和标准方差,再由 β \beta β和 γ \gamma γ重缩放。但这意味着,无论 b [ l ] b^{[l]} b[l]的值是多少,都是要被减去的。所以,在使用Batch归一化时,其实你可以消除这个参数( b [ l ] b^{[l]} b[l]),或暂时把它设置为0。
那么,参数变成 z [ l ] = w [ l ] a [ l − 1 ] z^{[l]} = w^{[l]}a^{\left\lbrack l - 1 \right\rbrack} z[l]=w[l]a[l−1], z ~ [ l ] = γ [ l ] z [ l ] + β [ l ] {\tilde{z}}^{[l]} = \gamma^{[l]}z^{[l]} + {\beta}^{[l]} z~[l]=γ[l]z[l]+β[l]。
最后,请记住 z [ l ] z^{[l]} z[l]的维数,因为在这个例子中,维数会是 ( n [ l ] , 1 ) (n^{[l]},1) (n[l],1), b [ l ] b^{[l]} b[l]的尺寸为 ( n [ l ] , 1 ) (n^{[l]},1) (n[l],1),如果是l层隐藏单元的数量,那 β [ l ] {\beta}^{[l]} β[l]和 γ [ l ] \gamma^{[l]} γ[l]的维度也是 ( n [ l ] , 1 ) (n^{[l]},1) (n[l],1)。
关于如何用Batch归一化来应用梯度下降法:(假设使用mini-batch梯度下降法,运行 t = 1 t=1 t=1到batch数量的for循环)
- 在mini-batch X { t } X^{\{t \}} X{t}上应用正向prop,每个隐藏层都应用正向prop,用Batch归一化 z ~ [ l ] {\tilde{z}}^{[l]} z~[l]。
- 反向prop计算 d w [ l ] dw^{[l]} dw[l]和 d b [ l ] db^{[l]} db[l],及所有l层所有的参数, d β [ l ] d{\beta}^{[l]} dβ[l]和 d γ [ l ] d\gamma^{[l]} dγ[l]。尽管严格来说,因为你要去掉 b b b,这部分其实已经去掉了。
- 更新这些参数: w [ l ] = w [ l ] − αd w [ l ] w^{[l]} = w^{[l]} -\text{αd}w^{[l]} w[l]=w[l]−αdw[l], β [ l ] = β [ l ] − α d β [ l ] {\beta}^{[l]} = {\beta}^{[l]} - {αd}{\beta}^{[l]} β[l]=β[l]−αdβ[l], γ [ l ] = γ [ l ] − α d γ [ l ] \gamma^{[l]} = \gamma^{[l]} -{αd}\gamma^{[l]} γ[l]=γ[l]−αdγ[l]。
Batch Norm 为什么奏效?
- 归一化输入特征值加速学习。Batch归一化不仅仅作用于这里的输入值,还有隐藏单元的值。
- 使权重比网络更滞后或更深层。
-
*covariate shift: 已经学习了 x x x到 y y y 的映射,则 x x x 的分布改变了后可能需要重新训练你的学习算法。
-
Batch归一化做的,是它减少了这些隐藏值分布变化的数量。Batch归一化可以确保无论其怎样变化 z 1 [ 2 ] z_{1}^{[2]} z1[2], z 2 [ 2 ] z_{2}^{[2]} z2[2]的均值和方差保持不变,所以即使 z 1 [ 2 ] z_{1}^{[2]} z1[2], z 2 [ 2 ] z_{2}^{[2]} z2[2]的值改变,至少他们的均值和方差是由 β [ 2 ] {\beta}^{[2]} β[2]和 γ [ 2 ] \gamma^{[2]} γ[2]决定的值。它限制了在前层的参数更新,会影响数值分布的程度,第三层看到的这种情况,因此得到学习。它减弱了前层参数的作用与后层参数的作用之间的联系,它使得网络每层都可以自己学习,稍稍独立于其它层,这有助于加速整个网络的学习。
-
- Batch归一化有轻微的正则化效果。
测试时的 Batch Norm(Batch Norm at test time)
在测试时可能需要对每个样本逐一处理。
在训练时,这些就是用来执行Batch归一化的等式。用于调节计算的
μ
\mu
μ和
σ
2
\sigma^{2}
σ2是在整个mini-batch上进行计算,但是在测试时,需要用其它方式来得到
μ
\mu
μ和
σ
2
\sigma^{2}
σ2。一个样本的均值和方差没有意义。
那么就需要单独估算 μ \mu μ和 σ 2 \sigma^{2} σ2,在典型的Batch归一化运用中,你需要用一个指数加权平均来估算,这个平均数涵盖了所有mini-batch。
选择 l l l层,假设我们有mini-batch, X [ 1 ] X^{[1]} X[1], X [ 2 ] X^{[2]} X[2], X [ 3 ] X^{[3]} X[3]……以及对应的 y y y值等等,那么在为 l l l层训练 X 1 X^{{ 1}} X1时,你就得到了 μ [ l ] \mu^{[l]} μ[l]( μ [ l ] → μ { 1 } [ l ] \mu^{[l]} \rightarrow \mu^{\{1 \}[l]} μ[l]→μ{1}[l])。当你训练第二个mini-batch,在这一层和这个mini-batch中,你就会得到第二个 μ \mu μ( μ 2 [ l ] \mu^{{2}[l]} μ2[l])值。然后在这一隐藏层的第三个mini-batch,你得到了第三个 μ \mu μ( μ { 3 } [ l ] \mu^{\{3 \}[l]} μ{3}[l])值。正如我们之前用的指数加权平均来计算 θ 1 \theta_{1} θ1, θ 2 \theta_{2} θ2, θ 3 \theta_{3} θ3的均值,当时是试着计算当前气温的指数加权平均,你会这样来追踪你看到的这个均值向量的最新平均值,于是这个指数加权平均就成了对这一隐藏层的 z z z均值的估值。同样的,你可以用指数加权平均来追踪你在这一层的第一个mini-batch中所见的 σ 2 \sigma^{2} σ2的值,以及第二个mini-batch中所见的 σ 2 \sigma^{2} σ2的值等等。
因此在用不同的mini-batch训练神经网络时,能够得到所查看的每一层的 μ \mu μ和 σ 2 \sigma^{2} σ2的平均数的实时数值。
最后在测试时,对应这个等式( z norm ( i ) = z ( i ) − μ σ 2 + ε z_{\text{norm}}^{(i)} = \frac{z^{(i)} -\mu}{\sqrt{\sigma^{2} +\varepsilon}} znorm(i)=σ2+ε z(i)−μ),你只需要用你的 z z z值来计算 z norm ( i ) z_{\text{norm}}^{(i)} znorm(i),用 μ \mu μ和 σ 2 \sigma^{2} σ2的指数加权平均,用你手头的最新数值来做调整,然后你可以用左边我们刚算出来的 z norm z_{\text{norm}} znorm和你在神经网络训练过程中得到的 β \beta β和 γ \gamma γ参数来计算你那个测试样本的 z ~ \tilde{z} z~值。
总结一下就是,在训练时, μ \mu μ和 σ 2 \sigma^{2} σ2是在整个mini-batch上计算出来,但在测试时需要逐一处理样本,方法是根据训练集估算 μ \mu μ和 σ 2 \sigma^{2} σ2,理论上你可以在最终的网络中运行整个训练集来得到 μ \mu μ和 σ 2 \sigma^{2} σ2,但在实际操作中,通常运用指数加权平均来追踪在训练过程中你看到的 μ \mu μ和 σ 2 \sigma^{2} σ2的值。
Softmax 回归(Softmax regression)
假设你算出了 z [ l ] z^{[l]} z[l], z [ l ] z^{[l]} z[l]是一个四维向量,假设为 z [ l ] = [ 5 2 − 1 3 ] z^{[l]} = \begin{bmatrix} 5 \\ 2 \\ - 1 \\ 3 \ \end{bmatrix} z[l]=⎣⎢⎢⎡52−13 ⎦⎥⎥⎤,我们要做的就是用这个元素取幂方法来计算 t t t,所以 t = [ e 5 e 2 e − 1 e 3 ] = [ 148.4 7.4 0.4 20.1 ] t =\begin{bmatrix} e^{5} \\ e^{2} \\ e^{- 1} \\ e^{3} \ \end{bmatrix} = \begin{bmatrix} 148.4 \\ 7.4 \\ 0.4 \\ 20.1 \\ \end{bmatrix} t=⎣⎢⎢⎡e5e2e−1e3 ⎦⎥⎥⎤=⎣⎢⎢⎡148.47.40.420.1⎦⎥⎥⎤,我们从向量 t t t得到向量 a [ l ] a^{[l]} a[l]就只需要将这些项目归一化,使总和为1。如果你把 t t t的元素都加起来,把这四个数字加起来,得到176.3,最终 a [ l ] = t 176.3 a^{[l]} = \frac{t} {176.3} a[l]=176.3t, 输出 a [ l ] a^{[l]} a[l],也就是 y ^ \hat y y^,是一个4×1维向量,这个4×1向量的元素就是我们算出来的这四个数字( [ 0.842 0.042 0.002 0.114 ] \begin{bmatrix} 0.842 \\ 0.042 \\ 0.002 \\ 0.114 \\ \end{bmatrix} ⎣⎢⎢⎡0.8420.0420.0020.114⎦⎥⎥⎤),所以这种算法通过向量 z [ l ] z^{[l]} z[l]计算出总和为1的四个概率。
之前**函数都是接受单行数值输入, Softmax**函数的特殊之处在于,因为需要将所有可能的输出归一化,就需要输入一个向量,最后输出一个向量。
那么Softmax分类器还可以代表其它的什么东西么?
这个例子中(左边图),原始输入只有
x
1
x_{1}
x1和
x
2
x_{2}
x2,一个
C
=
3
C=3
C=3个输出分类的Softmax层能够代表这种类型的决策边界,请注意这是几条线性决策边界,但这使得它能够将数据分到3个类别中,在这张图表中,我们所做的是选择这张图中显示的训练集,用数据的3种输出标签来训练Softmax分类器,图中的颜色显示了Softmax分类器的输出的阈值,输入的着色是基于三种输出中概率最高的那种。因此我们可以看到这是logistic回归的一般形式,有类似线性的决策边界,但有超过两个分类,分类不只有0和1,而是可以是0,1或2。
Softmax回归或Softmax**函数将logistic**函数推广到
C
C
C类,而不仅仅是两类,如果
C
=
2
C=2
C=2,那么
C
=
2
C=2
C=2的Softmax实际上变回了logistic回归。
训练一个 Softmax 分类器
先定义训练神经网络使会用到的损失函数。举个例子某个样本目标输出真实标签是 [ 0 1 0 0 ] \begin{bmatrix} 0 \\ 1 \\ 0 \\ 0 \\ \end{bmatrix} ⎣⎢⎢⎡0100⎦⎥⎥⎤,这表示这是一张猫的图片,因为它属于类1(我把猫加做类1,狗为类2,小鸡是类3),假设神经网络输出的是 y ^ \hat y y^, y ^ \hat y y^是一个包括总和为1的概率的向量, y = [ 0.3 0.2 0.1 0.4 ] y = \begin{bmatrix} 0.3 \\ 0.2 \\ 0.1 \\ 0.4 \\ \end{bmatrix} y=⎣⎢⎢⎡0.30.20.10.4⎦⎥⎥⎤,对于这个样本神经网络的表现不佳,这实际上是一只猫,但却只分配到20%是猫的概率。
来看上面的单个样本来更好地理解整个过程。在Softmax分类中,我们一般用到的损失函数是 L ( y ^ , y ) = − ∑ j = 1 4 y j l o g y ^ j L(\hat y,y ) = - \sum_{j = 1}^{4}{y_{j}log\hat y_{j}} L(y^,y)=−∑j=14yjlogy^j。在这个样本中 y 1 = y 3 = y 4 = 0 y_{1} =y_{3} = y_{4} = 0 y1=y3=y4=0,只有 y 2 = 1 y_{2} =1 y2=1,如果你看这个求和,所有含有值为0的 y j y_{j} yj的项都等于0,最后 L ( y ^ , y ) = − ∑ j = 1 4 y j log y ^ j = − y 2 l o g y ^ 2 = − l o g y ^ 2 L\left( \hat y,y \right) = - \sum_{j = 1}^{4}{y_{j}\log \hat y_{j}} = - y_{2}{\ log} \hat y_{2} = - {\ log} \hat y_{2} L(y^,y)=−∑j=14yjlogy^j=−y2 logy^2=− logy^2
因为梯度下降法是用来减少训练集的损失的,所以就需要使 y ^ 2 \hat y_{2} y^2尽可能大,但不可能比1大。
整个训练集的损失
J
J
J:
J
(
w
[
1
]
,
b
[
1
]
,
…
…
)
=
1
m
∑
i
=
1
m
L
(
y
^
(
i
)
,
y
(
i
)
)
J( w^{[1]},b^{[1]},\ldots\ldots) = \frac{1}{m}\sum_{i = 1}^{m}{L( \hat y^{(i)},y^{(i)})}
J(w[1],b[1],……)=m1∑i=1mL(y^(i),y(i))用梯度下降法,使这里的损失最小化。
最后还有一个实现细节,注意因为 C = 4 C=4 C=4, y y y是一个4×1向量, y y y也是一个4×1向量,如果你实现向量化,矩阵大写 Y Y Y就是 [ y ( 1 ) y ( 2 ) … … y ( m ) ] \lbrack y^{(1)}\text{}y^{(2)}\ldots\ldots\ y^{\left( m \right)}\rbrack [y(1)y(2)…… y(m)],例如如果上面这个样本是你的第一个训练样本,那么矩阵 Y = [ 0 0 1 … 1 0 0 … 0 1 0 … 0 0 0 … ] Y =\begin{bmatrix} 0 & 0 & 1 & \ldots \\ 1 & 0 & 0 & \ldots \\ 0 & 1 & 0 & \ldots \\ 0 & 0 & 0 & \ldots \ \end{bmatrix} Y=⎣⎢⎢⎡010000101000………… ⎦⎥⎥⎤,那么这个矩阵 Y Y Y最终就是一个 4 × m 4×m 4×m维矩阵。类似的, Y ^ = [ y ^ ( 1 ) y ^ ( 2 ) … … y ^ ( m ) ] \hat{Y} = \lbrack{\hat{y}}^{(1)}{\hat{y}}^{(2)} \ldots \ldots\ {\hat{y}}^{(m)}\rbrack Y^=[y^(1)y^(2)…… y^(m)],这个其实就是 y ^ ( 1 ) {\hat{y}}^{(1)} y^(1)( a l = y ( 1 ) = [ 0.3 0.2 0.1 0.4 ] a^{l} = y^{(1)} = \begin{bmatrix} 0.3 \\ 0.2 \\ 0.1 \\ 0.4 \\ \end{bmatrix} al=y(1)=⎣⎢⎢⎡0.30.20.10.4⎦⎥⎥⎤),或是第一个训练样本的输出,那么 Y ^ = [ 0.3 … 0.2 … 0.1 … 0.4 … ] \hat{Y} = \begin{bmatrix} 0.3 & \ldots \\ 0.2 & \ldots \\ 0.1 & \ldots \\ 0.4 & \ldots \\ \end{bmatrix} Y^=⎣⎢⎢⎡0.30.20.10.4…………⎦⎥⎥⎤, Y ^ \hat{Y} Y^本身也是一个 4 × m 4×m 4×m维矩阵。