在第一门课中已经学习了如何建立一个神经网络,或者浅层的,或者深度的。而这第二门课,我们将着重讨论和研究如何优化神经网络模型,例如调整超参数,提高算法运行速度等等。
在构建一个神经网络的时候,我们需要设置许多参数,而且很对是超参数,例如:神经网络的层数、每个隐藏层包含的神经元个数、学习因子(学习速率)、激活函数的选择等等。很难在第一次设置的时候就选择到这些最佳的参数,而是需要通过不断地迭代更新来获得。
循环迭代的过程是这样的:
根据验证结果,我们对参数进行适当的调整优化,再进行下一次的Idea->Code->Experiment循环。通过很多次的循环,不断调整参数,选定最佳的参数值,从而让神经网络性能最优化。
最适合某个领域的深度学习网络往往不能直接应用在其它领域上。
假设你开发一个手机app,可以让用户上传图片,然后app识别出猫的图片。在app识别算法中,你的训练样本可能来自网络下载,而你的验证和测试样本可能来自不同用户的上传。
从网络下载的图片一般像素较高而且比较正规,而用户上传的图片往往像素不稳定,且图片质量不一。因此,训练样本和验证/测试样本可能来自不同的分布。解决这一问题的比较科学的办法是尽量保证Dev sets和Test sets来自于同一分布。
以猫识别为例子,输入是一幅图像,其特征维度很大。这种情况下,我们可以通过两个数值训练集误差(Train set error)和验证集误差(Dev set error)来理解bias和variance。
算法并没有在训练集中得到很好训练,如果训练数据的拟合度不高,就是 数 据 欠 拟 合 \color{red}数据欠拟合 数据欠拟合,就可以说这种算法 偏 差 ( b i a s ) 比 较 高 \color{red}偏差(bias)比较高 偏差(bias)比较高。
相反,它对于验证集产生的结果却是合理的,验证集中的错误率只比训练集的多了 1%,所以这种算法偏差高,因为它甚至不能拟合训练集。
以上分析的假设条件:
这些分析都是基于假设预测的,假设人眼辨别的错误率接近 0%,一般来说,最优误差也被称为 贝 叶 斯 误 差 \color{red}贝叶斯误差 贝叶斯误差,所以,最优误差接近 0%。如果最优误差或贝叶斯误差非常高,比如 15%。我们再看看这个分类器(训练误差 15%,验证误差 16%), 15%的错误率对训练集来说也是非常合理的,偏差不高,方差也非常低。
high bias and high variance的模型:
模型既存在high bias也存在high variance,可以理解成某段区域是欠拟合的,某段区域是过拟合的。
机器学习和深度学习的目标就是: 避 免 出 现 h i g h b i a s 和 h i g h v a r i a n c e \color{red}避免出现high\;bias和high\;variance 避免出现highbias和highvariance。
深度学习可能存在过拟合问题——高方差,有两个解决方法:一个是正则化;另一个是准备更多的数据(这是非常可靠的方法,但你可能无法时时刻刻准备足够多的训练数据或者获取更多数据的成本很高)。
为什么只对w进行正则化而不对b进行正则化呢?
其实也可以对b进行正则化。但是一般w的维度很大,而b只是一个常数。相比较来说,参数的变化程度上基本由w决定,改变b值对整体模型参数的变化影响较小。所以,一般为了简便,就忽略对b的正则化了。
实际上 L 1 L_1 L1 regularization在解决high variance方面比 L 2 L_2 L2 regularization并不更具优势。而且, L 1 L_1 L1的在微分求导方面比较复杂( L 1 L_1 L1范式有的时候会改用 L 21 L_{21} L21范式)。所以,一般 L 2 L_2 L2 regularization更加常用。
在python中,由于lambda是保留字,所以为了避免冲突,我们使用lambd来表示 λ \lambda λ。
L 2 L_2 L2 regularization:
表达式为:
J ( w [ 1 ] , b [ 1 ] , ⋯ , w [ L ] , b [ L ] ) = 1 m ∑ i = 1 m L ( y ^ ( i ) , y ( i ) ) + λ 2 m ∑ l = 1 L ∣ ∣ w [ l ] ∣ ∣ 2 其中 ∣ ∣ w [ l ] ∣ ∣ 2 = ∑ i = 1 n [ l ] ∑ j = 1 n [ l − 1 ] ( w i j [ l ] ) 2 \begin{array}{l}J(w^{[1]},b^{[1]},\cdots,w^{[L]},b^{[L]})=\frac1m\sum_{i=1}^mL(\hat y^{(i)},y^{(i)})+\frac{\lambda}{2m}\sum_{l=1}^L||w^{[l]}||^2\\ \text{其中}||w^{[l]}||^2=\sum_{i=1}^{n^{[l]}}\sum_{j=1}^{n^{[l-1]}}(w_{ij}^{[l]})^2\end{array} J(w[1],b[1],⋯,w[L],b[L])=m1∑i=1mL(y^(i),y(i))+2mλ∑l=1L∣∣w[l]∣∣2其中∣∣w[l]∣∣2=∑i=1n[l]∑j=1n[l−1](wij[l])2
通常,我们把 ∣ ∣ w [ l ] ∣ ∣ 2 ||w^{[l]}||^2 ∣∣w[l]∣∣2称为Frobenius范数,记为 ∣ ∣ w [ l ] ∣ ∣ F 2 ||w^{[l]}||_F^2 ∣∣w[l]∣∣F2。一个矩阵的Frobenius范数就是计算所有元素平方和再开方,如下所示:
∣ ∣ A ∣ ∣ F = ∑ i = 1 m ∑ j = 1 n ∣ a i j ∣ 2 ||A||_F=\sqrt {\sum_{i=1}^m\sum_{j=1}^n|a_{ij}|^2} ∣∣A∣∣F=i=1∑mj=1∑n∣aij∣2
梯度下降算法中的 d w [ l ] dw^{[l]} dw[l]计算表达式需要做如下修改:
d w [ l ] = d w b e f o r e [ l ] + λ m w [ l ] w [ l ] : = w [ l ] − α ⋅ d w [ l ] \begin{array}{l}dw^{[l]}=dw^{[l]}_{before}+\frac{\lambda}{m}w^{[l]}\\ w^{[l]}:=w^{[l]}-\alpha\cdot dw^{[l]}\end{array} dw[l]=dwbefore[l]+mλw[l]w[l]:=w[l]−α⋅dw[l]
L 2 L_2 L2 regularization也被称做 w e i g h t d e c a y weight\; decay weightdecay(权重衰减)
如下公式,由于加上了正则项, d w [ l ] dw^{[l]} dw[l]有个增量,在更新 w [ l ] w^{[l]} w[l]的时候,会多减去这个增量,使得 w [ l ] w^{[l]} w[l]比没有正则项的值要小一些。不断迭代更新,不断地减小:
w [ l ] : = w [ l ] − α ⋅ d w [ l ] = w ∣ l ∣ − α ⋅ ( d w b e f o r e [ l ] + λ m w [ l ] ) = ( 1 − α λ m ) w [ l ] − α ⋅ d w b e f o r e [ l ] \begin{aligned} w^{[l]} &:=w^{[l]}-\alpha \cdot d w^{[l]} \\ &=w^{|l|}-\alpha \cdot\left(d w_{b e f o r e}^{[l]}+\frac{\lambda}{m} w^{[l]}\right) \\ &=\left(1-\alpha \frac{\lambda}{m}\right) w^{[l]}-\alpha \cdot d w_{b e f o r e}^{[l]} \end{aligned} w[l]:=w[l]−α⋅dw[l]=w∣l∣−α⋅(dwbefore[l]+mλw[l])=(1−αmλ)w[l]−α⋅dwbefore[l]
其中, ( 1 − α λ m ) < 1 (1-\alpha\frac{\lambda}{m})<1 (1−αmλ)<1。
可以从三个方面来理解:为什么正则化有利于预防过拟合:
从上一讲最后一小节的公式进行理解:
w [ l ] : = w [ l ] − α ⋅ d w [ l ] = w ∣ l ∣ − α ⋅ ( d w b e f o r e [ l ] + λ m w [ l ] ) = ( 1 − α λ m ) w [ l ] − α ⋅ d w b e f o r e [ l ] \begin{aligned} w^{[l]} &:=w^{[l]}-\alpha \cdot d w^{[l]} \\ &=w^{|l|}-\alpha \cdot\left(d w_{b e f o r e}^{[l]}+\frac{\lambda}{m} w^{[l]}\right) \\ &=\left(1-\alpha \frac{\lambda}{m}\right) w^{[l]}-\alpha \cdot d w_{b e f o r e}^{[l]} \end{aligned} w[l]:=w[l]−α⋅dw[l]=w∣l∣−α⋅(dwbefore[l]+mλw[l])=(1−αmλ)w[l]−α⋅dwbefore[l]
从如下例子进行理解,如下图:
上图从左到右,分别表示:欠拟合,恰好拟合,过拟合三种情况。
从激活函数的角度来看:
假设激活函数是 t a n h tanh tanh函数。 t a n h tanh tanh函数的特点是在 z z z接近零的区域,函数近似是线性的。
当 ∣ z ∣ |z| ∣z∣很大的时候,函数非线性且变化缓慢。当使用正则化:
除了上面章节说的,利用正则化进行预防过拟合外,还有另外一种防止过拟合的有效方法:Dropout。
dl = np.random.rand(al.shape[0],al.shape[1])
al = np.multiply(al,dl)
al /= keep_prob
以上就是Inverted dropout的方法。之所以要对 a l al al进行scale up是为了保证在经过dropout后, a l al al作为下一层神经元的输入值尽量保持不变。假设第 l l l层有50个神经元,经过dropout后,有10个神经元停止工作,这样只有40神经元有作用。那么得到的 a l a_l al只相当于原来的80%。scale up后,能够尽可能保持 a l a_l al的期望值相比之前没有大的变化。
除了L2 regularization和dropout regularization之外,还有其它减少过拟合的方法。
Early stopping的做法通过减少得带训练次数来防止过拟合,这样J就不会足够小。也就是说,early stopping将上述两个目标融合在一起,同时优化,但可能没有“分而治之”( 正 交 化 ( o r t h o g o n a l i z a t i o n ) \color{red}正交化(orthogonalization) 正交化(orthogonalization))的效果好。
在训练神经网络时,标准化输入可以提高训练的速度。
在深度神经网络中可能存在这样一个问题:梯度消失和梯度爆炸。意思是:当训练一个 层数非常多的神经网络时,计算得到的梯度随着层数的增加,近似成指数级别的减小或增大。
改善梯度消失/梯度爆炸(Vanishing and Exploding gradients)这类问题:
w[l] = np.random.randn(n[l],n[l-1])*np.sqrt(1/n[l-1])
其中 n [ l − 1 ] n^{[l - 1]} n[l−1]是第 l − 1 l-1 l−1层神经元数量。w[l] = np.random.randn(n[l],n[l-1])*np.sqrt(1/n[l-1])
w[l] = np.random.randn(n[l],n[l-1])*np.sqrt(2/n[l-1])
w[l] = np.random.randn(n[l],n[l-1])*np.sqrt(2/n[l-1]*n[l])
至于选择哪种初始化方法因人而异,可以根据不同的激活函数选择不同方法。Back Propagation神经网络有一项重要的测试是梯度检查(gradient checking),是检查验证反向传播过程中梯度下降算法是否正确。
梯度检验的核心:
∂ J ∂ θ = lim ε → 0 J ( θ + ε ) − J ( θ − ε ) 2 ε \frac{\partial J}{\partial \theta}=\lim _{\varepsilon \rightarrow 0} \frac{J(\theta+\varepsilon)-J(\theta-\varepsilon)}{2 \varepsilon} ∂θ∂J=ε→0lim2εJ(θ+ε)−J(θ−ε)
对于1层神经网络的梯度检验
将 W [ 1 ] , b [ 1 ] , ⋯ , W [ L ] , b [ L ] W^{[1]},b^{[1]},\cdots,W^{[L]},b^{[L]} W[1],b[1],⋯,W[L],b[L]中矩阵/向量先"拉长"构造成一维向量,然后和同层的向量构成一个更大的向量。然后将这些一维向量组合起来构成一个更大的一维向量 θ = [ θ 1 , . . . θ L ] \color{red}\mathbb\theta = [\theta_1, ...\theta_L] θ=[θ1,...θL]。则cost function可以写成:
J ( W [ 1 ] , b [ 1 ] , ⋯ , W [ L ] , b [ L ] ) = J ( θ 1 , . . . θ L ) J(W^{[1]},b^{[1]},\cdots,W^{[L]},b^{[L]})=J(\theta_1, ...\theta_L) J(W[1],b[1],⋯,W[L],b[L])=J(θ1,...θL)
将Back Propagation通过梯度下降算法得到的 d W [ 1 ] , d b [ 1 ] , ⋯ , d W [ L ] , d b [ L ] dW^{[1]},db^{[1]},\cdots,dW^{[L]},db^{[L]} dW[1],db[1],⋯,dW[L],db[L]按照第一步的顺序构造成一个一维向量 d θ = [ d θ 1 , . . . d θ L ] \color{red}d\mathbb\theta = [d\theta_1, ...d\theta_L] dθ=[dθ1,...dθL]。 d θ d\theta dθ的维度与 θ \theta θ一致。
利用 J ( θ ) \color{red}J(\theta) J(θ)对每个 θ i \theta_i θi计算近似梯度,其值与反向传播算法得到的 d θ i \color{red}d\theta_i dθi相比较,检查是否一致。对于第 i i i个元素,近似梯度为:
d θ a p p r o x [ i ] ≈ J ( θ 1 , θ 2 , ⋯ , θ i + ε , ⋯ ) − J ( θ 1 , θ 2 , ⋯ , θ i − ε , ⋯ ) 2 ε d\theta_{approx}[i]\approx \frac{J(\theta_1,\theta_2,\cdots,\theta_i+\varepsilon,\cdots)-J(\theta_1,\theta_2,\cdots,\theta_i-\varepsilon,\cdots)}{2\varepsilon} dθapprox[i]≈2εJ(θ1,θ2,⋯,θi+ε,⋯)−J(θ1,θ2,⋯,θi−ε,⋯)
参数 θ \theta θ不再是一个标量,而是一个字典。我们需要实现一个字典转向量和向量转字典的函数,以用于梯度检验算法中。
计算:
∣ ∣ d θ a p p r o x − d θ ∣ ∣ 2 ∣ ∣ d θ a p p r o x ∣ ∣ 2 + ∣ ∣ d θ ∣ ∣ 2 \frac{||d\theta_{approx}-d\theta||_2}{||d\theta_{approx}||_2+||d\theta||_2} ∣∣dθapprox∣∣2+∣∣dθ∣∣2∣∣dθapprox−dθ∣∣2
在进行梯度检查的过程中有几点需要注意的地方:
上图左边,经典机器学习和深度学习模型所需要的样本数有非常大的差别,深度学习的样本数是经典 ML 的成千上万倍。因 此训练集、开发集和测试集的分配也有很大的区别,当然我们假设这些不同的数据集都服从同分布。
上图右边,偏差与方差问题同样是机器学习模型中常见的挑战,上图依次展示了由高偏差带来的欠拟合和由高方差带来的过拟合。一般而言,解决高偏差的问题是选择更复杂的网络或不同的神经网络架构,而解决高方差的问题可以添加正则化、减少模型冗余或使用更多的数据进行训练。
当然,机器学习模型需要注意的问题远不止这些,但在配置我们的 ML 应用中,它们是最基础和最重要的部分。其它如数据预处理、数据归一化、超参数的选择等都在后面的信息图中有所体现。
正则化
正则化是解决高方差或模型过拟合的主要手段,过去数年,研究者提出和开发了多种适合机器学习算法的正则化方法,如数据增强、L2 正则化(权重衰减)、L1 正则化、Dropout、Drop Connect、随机池化和提前终止等。
上图左列, L 1 L_1 L1和 L 2 L_2 L2 正则化也是是机器学习中使用最广泛的正则化方法。 L 1 L_1 L1正则化向目标函数添加正则化项,以减少参数的绝对值总和;而 L 2 L_2 L2 正则化中,添加正则化项的目的在于减少参数平方的总和。根据之前的研究, L 1 L_1 L1 正则化中的很多参数向量是稀疏向量,因为很多模型导致参数趋近于 0,因此它常用于特征选择设置中。此外,参数范数惩罚 L 2 L_2 L2 正则化能让深度学习算法「感知」到具有较高方差的输入 x x x,因此与输出目标的协方差较小(相对增加方差)的特征权重将会收缩。
中间列,上图展示了 Dropout 技术,即暂时丢弃一部分神经元及其连接的方法。随机丢弃神经元可以防止过拟合,同时指数级、高效地连接不同网络架构。一般使用了 Dropout 技术的神经网络会设定一个保留率 p,然后每一个神经元在一个批量的训练中以概率 1-p 随机选择是否去掉。在最后进行推断时所有神经元都需要保留,因而有更高的准确度。
Bagging 是通过结合多个模型降低泛化误差的技术,主要的做法是分别训练几个不同的模型,然后让所有模型表决测试样例的输出。而 Dropout 可以被认为是集成了大量深层神经网络的 Bagging 方法,因此它提供了一种廉价的 Bagging 集成近似方法,能够训练和评估值数据数量的神经网络。
右边列,上图还描述了数据增强与提前终止等正则化方法。数据增强通过向训练数据添加转换或扰动来人工增加训练数据集。数据增强技术如水平或垂直翻转图像、裁剪、色彩变换、扩展和旋转通常应用在视觉表象和图像分类中。而提前终止通常用于防止训练中过度表达的模型泛化性能差。如果迭代次数太少,算法容易欠拟合(方差较小,偏差较大),而迭代次数太多,算法容易过拟合(方差较大,偏差较小)。因此,提前终止通过确定迭代次数解决这个问题。
最优化-1
最优化是机器学习模型中非常非常重要的模块,它不仅主导了整个训练过程,同时还决定了最后模型性能的好坏和收敛需要的时长。以下展示了最优化方法需要关注的知识点,包括最优化的预备和具体的最优化方法,以下是第一部分。
最左边,归一化输入数据,而且开发集与测试集归一化的常数(均值与方差)与训练集是相同的。上图也展示了归一化的原因,因为如果特征之间的量级相差太大,那么损失函数的表面就是一张狭长的椭圆形,而梯度下降或最速下降法会因为「锯齿」现象而很难收敛,因此归一化为圆形有助于减少下降方向的震荡。
中间列,梯度消失与梯度爆炸问题也是十分常见的现象。「梯度消失」指的是随着网络深度增加,参数的梯度范数指数式减小的现象。梯度很小,意味着参数的变化很缓慢,从而使得学习过程停滞。梯度爆炸指神经网络训练过程中大的误差梯度不断累积,导致模型权重出现很大的更新,在极端情况下,权重的值变得非常大以至于出现 NaN 值。
右边列,梯度检验现在可能用的比较少,因为我们在 TensorFlow 或其它框架上执行最优化算法只需要调用优化器就行。梯度检验一般是使用数值的方法计算近似的导数并传播,因此它能检验我们基于解析式算出来的梯度是否正确。