6-超参数调试和Batch正则化

超参数调试和Batch正则化

调试处理

神经网络中有很多的超参数,那么如何系统性地组织超参数调试呢?

首先需要明确哪些超参数是更为重要的,一般来说,学习率α\alpha是最为重要的,其他的例如mini-batchepoch等。

在深度学习领域,推荐使用的超参数调试方法是:随机选择点。

因为对于要解决的问题而言,很难知道哪个超参数最重要,因此需要进行随机的测试,从而判断哪些参数对最终效果影响最大。

举一个极端的例子是:

存在两个超参数,一个是学习率α\alpha,一个是Adam算法中的ε\varepsilon,那么学习率显然很重要,而ε\varepsilon无关紧要。

如果学习率和ε\varepsilon各有五种取值,把所有的取值组合画成网格。

image-20220917151913810

就像这样,那么测试了25组取值后,会发现无论ε\varepsilon取何值,结果基本都是一样的,但进行实验的α\alpha只有五个。

另一个指导原则是:采用由粗糙到精细的策略,也就是先大致进行测试,然后在聚焦到取到最优结果的参数值周围,进行更密集的取值进行测试。

为超参数选择合适的范围

在选择超参数的合适范围时,随机取值可以提升搜索效果。

但是随机取值并不是在有效范围内的随机均匀取值。


假设要选择隐藏单元的数量,取值范围是[50, 100],那么可以从50开始取,51,52这样,一致取到100。

或者,如果选择神经网络的层数,取值范围是[2, 4],那么取2,3,4是合理的。


但是对于例如学习率α\alpha,或Momentum算法中的β\beta,这样取值并不适用。

例如对于学习率,取值范围可以是[0.0001, 1],那么随着数轴均匀取值,90%的数值都在[0.1, 1]的范围内,因此并不合理。

这种情况下,可以让学习率以指数的形式取值。

α=10r,r[4,0]\alpha = 10^{r},r \in [-4, 0],在Python中,可以使用r = -4 * np.random.rand()

更为常见的情况是,某个超参数在10a10^a10b10^b之间取值,那么可以在区间[a,b]之间随机取值,然后令超参数等于10r10^r


另外一种情况是,例如给β\beta取值,如果取值范围是[0.9, 0.999]。那么就可以利用上面的方法,将其转换成β=110r\beta = 1- 10^r

这样,r的取值方式还是和上面的一样。

归一化网络的激活函数

在逻辑回归中,归一化输入特征可以加快学习过程,计算平均值和方差,从训练集中减去平均值,然后使用方法归一化整个数据集。

把代价函数的等高线图,从扁长的图像变成更圆的图像,从而利于算法优化。

那么对于更深的神经网络呢,不仅有输入特征值x,而且对于每一层来说都有输入a[l]a^{[l]}

那么可以将每一层的输入都进行归一化,从而更有效地训练参数w,bw,b

这就是Batch归一化

那么应该归一化a[l]a^{[l]}还是z[l]z{[l]},这有一些争论,但是在实践中,经常做的是对z[l]z^{[l]}进行归一化。

假设针对神经网络的某一层,有一些隐藏单元值,从z(1)z^{(1)}z(m)z^{(m)}(这里省略了层数l,实际应该为z[l](1)z^{[l] (1)})。

那么归一化的过程为:

μ=1mi=1mz(i)σ2=1mi=1m(z(i)μ)2znorm(i)=z(i)μσ2+ε\mu = \frac{1}{m}\sum_{i = 1}^{m}z^{(i)} \\ \sigma^{2} = \frac{1}{m}\sum_{i=1}^{m} {(z^{(i)} - \mu) }^2 \\ z^{(i)}_{norm} = \frac{z^{(i)} - \mu}{\sqrt{ {\sigma}^2 + \varepsilon} }

(ε\varepsilon是为了稳定数值,不会出现除以0的情况)

其中znorm(i)z^{(i)}_{norm}就是归一化后的值。

现在已经将z值归一化,平均值为0,方差为1。


但是有时候并不想让隐藏单元的平均值为0,方差为1。

也许有不同的分布会更有意义。

因此可以变成:

z~(i)=γznorm(i)+β\tilde{z}^{(i)} = \gamma z^{(i)}_{norm} + \beta

其中γ,β\boldsymbol{\gamma,\beta}都是要学习的参数,也就是使用梯度下降或其他优化算法时,和权重一样需要更新。

(这里的β\beta和Momentum算法中的超参数没有关系)

这两个参数的作用是:可以随意设置z~(i)\tilde{z}^{(i)}的平均值和方差。

事实上,如果γ=σ2+ε,β=μ\gamma = \sqrt{\sigma^2 + \varepsilon}, \beta = \mu,那么实际上z~(i)=z(i)\tilde{z}^{(i)} = z^{(i)}

即,参数β\beta控制平均值,γ\gamma控制方差。

将Batch Norm 拟合进神经网络

image-20220917165441650

将Batch归一化拟合到神经网络中。

如上图所示。

在将z输入激活函数,转换成a之前,先讲z归一化,然后使用归一化后的z~[i]\tilde{z}^{[i]}输入到激活函数,得到a[1]a^{[1]}

每一层的每一个神经元都有不同的参数γ,β\gamma,\beta


需要注意的是:

计算z的方法是z[l]=w[l]a[l1]+b[l]z^{[l]} = w^{[l]}a^{[l-1]} + b^{[l]},但是Batch归一化中,z[l]z^{[l]}会求平均值,然后再减去这个平均值,因此对于常数bb来说,无论值是多少,都会被均值减去所抵消,不影响归一化后的znorm[l]z^{[l]}_{norm},因此可以去掉b[l]b^{[l]}这个参数,由β[l]\beta^{[l]}代替控制。


梯度下降的反向传播中,参数γ,β\gamma,\beta要和权重一同进行更新。

即计算dw[l],db[l]dw^{[l]},db^{[l]}(其实b已经去掉了,不需要计算dbdb),dβ[l],dγ[l]d\beta^{[l]},d\gamma^{[l]}

然后更新参数:

w[l]=w[l]αdw[l]β[l]=β[l]αdβ[l]γ[l]=γ[l]αdγ[l]w^{[l]} = w^{[l]} - \alpha dw^{[l]} \\ \beta^{[l]} = \beta^{[l]} - \alpha d\beta^{[l]} \\ \gamma^{[l]} = \gamma^{[l]} - \alpha d\gamma^{[l]} \\

如果使用其他优化算法,例如Momentum,RMSprop等,同样把参数γ,β\gamma,\beta一起更新。

维度说明

加入了Batch归一化后,确认一下各变量的维度。

以神经网络的第l层为例,该层神经元个数为n[l]n^{[l]},前一层神经元个数为n[l1]n^{[l-1]},样本个数为m。

那么各变量维度为:

  • a[l1]:(n[l1],m)\boldsymbol{a^{[l-1]}:(n^{[l-1]}, m)}

  • w[l]:(n[l],n[n1])\boldsymbol{w^{[l]}:(n^{[l]}, n^{[n-1]})}

  • z[l],znorm[l]:(n[l],m)\boldsymbol{z^{[l]},z^{[l]}_{norm}:(n^{[l]}, m)}

  • γ[l]:(n[l],1)\boldsymbol{\gamma^{[l]}:(n^{[l] }, 1)}γznorm[l]\boldsymbol{\gamma z^{[l]}_{norm} }中的乘法是对应矩阵位置相乘,不是矩阵乘法,利用Python的广播机制先将γ[l]\boldsymbol{\gamma^{[l]}}的维度转换成(n[l],n[l])(n^{[l]},n^{[l]})

  • β[l]:(n[l],1)\boldsymbol{\beta^{[l]}:(n^{[l] }, 1)}:与γ\boldsymbol{\gamma}类似,先广播,再相加

Batch Norm为什么奏效

没听太懂。

简单来说,Batch归一化减弱了前层参数的作用和后层参数的作用之间的联系,这使得网络每层都可以自己学习,稍微独立于其它层,这有助于加速整个网络的学习。

Batch归一化有轻微的正则化效果。

因为Batch归一化是在每个mini-batch上进行的,而不是在整个数据集上,因此mini-batch均值和方差和整个数据集的均值和方差有差距,也就是均值和方差有一些小的噪声。

所以这个dropout类似,dropout也是给每个隐藏层增加了噪音,有一定会的概率乘以0。

因此使得后层的神经元不过分依赖任何一个隐藏神经元。

如果想要得到强大的正则化效果,可以将Batch归一化和dropout一起使用。

Softmax回归

在之前讲过的分类例子中只使用了二分类,即只有两种可能的类别。

如果有多个不同的类别,那么有一种逻辑回归的一般形式,称为Softmax回归。

例如,将输入的图片分为四类:0-其他,1-猫,2-狗,3-鸡。

使用大写的C来表示类别总个数,此时C=4。

在这个例子中,建立一个神经网络,输出层神经元有C个,也就是四个。

image-20220918095416854

那么四个神经元应该计算出某一样本被分类到四个类别的概率,即对于样本输入X,计算概率P(otherX),P(catX),P(dogX),P(chickenX)P(other|X),P(cat|X),P(dog|X),P(chicken|X)

并且这四个概率值和为1。

要做到这一点就需要Softmax激活函数,输出层称为Softmax输出层。


对于输出层来说,输出向量为z[l]z^{[l]},维度为(4,1)

得到z[l]z^{[l]}后,应用Softmax激活函数:

t=ez[l]a[l]=ez[l]j=14ti\boldsymbol{ t = e^{z^{[l]} } } \\ \boldsymbol{ a^{[l]} = \frac{e^{z^{[l]} } } {\sum_{j=1}^{4} t_i} } \\

其中,tt也是一个维度为(4,1)的向量,对z[l]z^{[l]}取指数,相当于对向量z[l]z^{[l]}的每一个元素取指数;

然后将向量tt的元素求总和,ez[l]\boldsymbol{e^{z^{ [l] } } }除以这个总和,得到a[l]\boldsymbol{a^{[l]} }

相当于对z[l]z^{[l]}进行了归一化。


一个例子。

z[l]=[5213]t=ez[l]=[e5e2e1e3][148.47.40.420.1]sum=j=14ti=148.4+7.4+0.4+20.1=176.3a[l]=ez[l]j=14ti=ez[l]sum=[148.4176.37.4176.30.4176.320.1176.3][0.8420.0420.0020.114]z^{[l]} = \begin{bmatrix} 5 \\ 2 \\ -1 \\ 3 \\ \end{bmatrix} \\ t = e^{z^{[l]} } = \begin{bmatrix} e^5 \\ e^2 \\ e^{-1} \\ e^3 \\ \end{bmatrix} \approx \begin{bmatrix} 148.4 \\ 7.4 \\ 0.4 \\ 20.1 \\ \end{bmatrix} \\ sum = \sum_{j=1}^{4}t_i = 148.4 + 7.4 + 0.4 + 20.1 = 176.3 \\ a^{[l]} = \frac{e^{z^{[l]} } } {\sum_{j=1}^{4} t_i} =\frac{e^{z^{[l]} } } {sum} = \begin{bmatrix} \frac{148.4}{176.3} \\ \frac{7.4}{176.3} \\ \frac{0.4}{176.3} \\ \frac{20.1}{176.3} \\ \end{bmatrix} \approx \begin{bmatrix} 0.842 \\ 0.042 \\ 0.002 \\ 0.114 \\ \end{bmatrix}

可以得到,类0的概率为84.2%,类1的概率为4.2%,以此类推。


Softmax激活函数的特殊之处在于:

之前的激活函数例如Sigmoid和Relu都是接受单个数值输入,输入一个实数,输出一个实数。

而Softmax激活函数因为要将所有的可能归一化,所以需要输入一个向量,输出一个向量。


Softmax和Hardmax对应,Hardmax同样接受一个输入向量,然后将元素最大值设为1,其余所有值设为0。


当C=2时,Softmax其实变回了逻辑回归,因为C=2时,Softmax输出两个概率值,和为1,所以其实是冗余的,只需要输出一个值即可,所以其实就是逻辑回归。

训练一个Softmax分类器

以上面的给图片分类为例,C=4。

首先定义单个样本的损失函数。

可以假设一个例子:

某个样本的真实标签是:[0,1,0,0]T{[0,1,0,0]}^T,而神经网络的输出是[0.3,0.2,0.1,0.4][0.3, 0.2, 0.1, 0.4],所以对这个样本,神经网络表现不佳,实际上是一只猫,但预测为猫的概率是20%。

因此可以给出,单个样本的损失函数:

L(y^,y)=j=1Cyjlogy^jL(\widehat{y}, y) = - \sum_{j=1}^{C}y_j \log{\widehat{y}_j }

以上面给出的例子为例,在这个样本中,y1=y3=y4=0y_1 = y_3 = y_4 = 0,因此损失函数变成L(y^,y)=y2logy^2L(\widehat{y}, y) = - y_2 \log{\widehat{y}_2 },而y2=1y_2= 1所以,L(y^,y)=logy^2L(\widehat{y}, y) = - \log{\widehat{y}_2 }

这意味着,如果想要减小损失函数值,就要增大y^2\widehat{y}_2的值。

概括来讲,损失函数就是找到训练集中的真实类别,然后使该类别所对应的概率值尽可能的高,这样损失函数值就会减小。


整个训练样本的损失JJ定义为:

J(w[l],b[l],)=1mi=1mL(y^(i),y(i))J(w^{[l]},b^{[l]},\cdots) = \frac{1}{m}\sum_{i=1}^mL(\widehat{y}^{(i)}, y^{ (i) } )


那么如何实现梯度下降法,最主要的是得到dz[l]dz^{[l]}的表达式,有这个值,就可以连续计算前面所有层的梯度下降。

dz[l]=y^ydz^{[l]} = \widehat{y} - y

有了这个表达式,就可以进行反向传播。


6-超参数调试和Batch正则化
https://zhaoquaner.github.io/2022/09/19/DeepLearning/CourseNote/6-超参数调试和Batch正则化/
更新于
2022年9月19日
许可协议