Ng深度学习笔记 超参数调试和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[104,100],最左边的数字是 1 0 − 4 10^{-4} 104,最右边是 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时,这样,你就可以更加有效的分布取样点,更有效率的探究可能的结果。

超参数调试的实践

如何搜索超参数?

  1. babysit一个模型,通常是有庞大的数据组,但没有许多计算资源或足够的CPU和GPU的前提下,可以逐渐改良,观察它的表现,耐心地调试学习率,但那通常是因为没有足够的计算能力,不能在同一时间试验大量模型时才采取的办法。

  2. 同时试验多种模型。设置了一些超参数,尽管让它自己运行,或者是一天甚至多天。

在这里插入图片描述

归一化网络的**函数

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[l1]+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[l1] 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循环)

  1. 在mini-batch X { t } X^{\{t \}} X{t}上应用正向prop,每个隐藏层都应用正向prop,用Batch归一化 z ~ [ l ] {\tilde{z}}^{[l]} z~[l]
  2. 反向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,这部分其实已经去掉了。
  3. 更新这些参数: 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]=5213 ,我们要做的就是用这个元素取幂方法来计算 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=e5e2e1e3 =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],)=m1i=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维矩阵。