深度学习-改善训练结果
数据集划分
通常将数据集划分为:训练集(traing set)、验证集(validation set)(或开发集(development set))、测试集(test set)
在小数据时代,通常7:3划分或6:2:2划分
在大数据时代,则98%:1%:1%,
偏差(Bias)和方差(Variance)
当训练集错误率小(如1%),验证集错误率大(如11%)时,则通常方差较高
当训练集和验证集错误率均较大(如15%和16%)时,则通常偏差较高
当训练集错误率较大(如15%),验证集错误率更大(如30%)时,则通常偏差和方差都较高,属于欠拟合
当训练集错误率和验证集错误率都较小时(如0.5%和1%),则通常偏差和方差都较低
一些训练技巧
- 如果训练结果偏差高甚至无法拟合训练集,则需要选择一个新网络(规模更大、更深、训练时间更长、更适合的神经网络框架等)
- 如果训练结果方差偏高,则需要查看验证集效果,则可以使用更多的数据或通过正则化来解决过拟合或选择更适合的神经网络框架
- 直到最终偏差、方差都较小
L2正则化
以Logistic Regression为例:
\(J(w,b) = \frac{1}{m}\sum_{i=1}^mL(\hat y^{(i)},y^{(i)})+\frac{\lambda}{2m}||w||_2^2 \\ L2正则化:||w||_2^2 = \sum_{j=1}^{n_x}w_j^2=w^Tw \\ L1正则化:\frac{\lambda}{2m}\sum_{j=1}^{n_x}|w_j| = \frac{\lambda}{2m}||w||_1\)
\(\lambda\):正则化参数
注:由于lambda是python中的保留字,所以通常我们在编码中使用lambd来代替
在神经网络中:
\(J(w^{[1]},b^{[1]},\cdots,w^{[l]},b^{[l]})=\frac{1}{m}\sum_{i=1}^mL(\hat y^{(i)},y^{(i)}) + \frac{lambda}{2m}\sum_{l=1}^{L}||W^{[l]}||^2 \\ ||W^{[l]}||^2 = \sum_i^{n^{[l-1]}}\sum_j^{n^{[l]}}(W^{[l]}_{ij})^2 \ (Frobenius \ norm) \\ dw^{[l]} = (反向传播结果) + \frac{\lambda}{m}W^{[l]} \\ \Rightarrow W^{[l]} := W^{[l]}-\alpha dW^{[l]} = W^{[l]} - \frac{\alpha \lambda}{m}W^{[l]}-\alpha (反向传播结果)\)
为什么正则化有利于预防过拟合?
如果正则化\(\lambda\)设置得足够大,则权重矩阵被设置为接近于0的值,直观理解就是把多个隐藏单元的权重设为0,进而消除了这些单元,从而形成一个简化的小网络,从而接近逻辑回归,导致方差降低,解决过拟合问题。
如果正则化参数足够大,权重矩阵足够小,则\(z^{[l]}=w^{[l]}a^{[l-1]}+b^[[l]]\)也会相对变小,在z变小且取值范围较小的情况下,以tanh激活函数为例,则此时激活函数会相对呈线性关系,从而导致整个网络会计算类似线性函数的值,向欠拟合靠近,在这个靠近的过程中,有一个恰好适合的值,可以正好解决过拟合问题,
随机失活(Dropout) 正则化
最基本原理:将所有单元设置50%概率删除,以该概率删除部分单元,然后训练,进而减少网络复杂程度
实现方法:Inverted dropout
1 | # layer l=3,keep_prob=0.8(保留80%单元) |
其它正则化方法
- 数据扩增;通过增加训练的数据,改善训练结果,但有时我们无法获得更多的训练数据,这里可以对数据进行变换(如图片进行水平水平翻转、随意剪裁等得到新的图片)
- Early stopping;可以提前停止迭代,在训练集和验证集Loss均适度时停止,
归一化
零均值化(subtrat out or zero out the mean)
\(\mu = \frac{1}{m}\sum_{i=1}^mx^{(i)} \\ x:=x-\mu\)
归一化方差(normalize the variances)
\(\sigma^2 = \frac{1}{m}\sum_{i=1}^mx^{(i)}**2 \\ x /= \sigma^2\)
为什么要归一化?
image-20201220173527012 当正则化后,函数是一个更圆的球形轮廓,则无论从哪个位置开始,梯度下降都会更快的找到最小值
梯度消失与梯度爆炸(Vanishing/exploding gradients)
当训练深度网络时,导数或坡度有时会变得非常大或非常小甚至以指数方式变小
假设\(b^{[l]}=0,g(z)=z\)则\(\hat y=W^{[l]}W^{[l-1]}\cdots W^{[2]}W^{[1]}x\)
如果W中的值比1略大如\(W^{[l]} = \begin{bmatrix}1.5 \ 0 \\ 0 \ 1.5 \end{bmatrix}\),则最终结果\(1.5^{[l-1]}x\)指数增大,类似的,如果W中的值比1略小如\(W^{[l]} = \begin{bmatrix}0.5 \ 0 \\ 0 \ 0.5 \end{bmatrix}\),则最终结果\(0.5^{[l-1]}x\)指数减小,从而导致梯度下降算法将花费很长时间来学习
权重初始化
单个神经元
\(z=w_1x_1+w_2x_2+\cdots+w_nx_n (忽略b,暂时设为0) \\ 则n越大,w_i越小 \\ Var(w_i) = \frac{1}{n} (Var:Variance)\\ w^{[l]} = np.random.randn(shape)*np.sqrt(\frac{1}{n^{[l-1]}}) \\ 如果使用的是ReLU激活函数,则Var(w_i)设为\frac{2}{n}更好,同样的\\ w^{[l]} = np.random.randn(shape)*np.sqrt(\frac{2}{n^{[l-1]}}) \\\)
如果使用tanh激活函数,则可以使用\(\sqrt{\frac{1}{n^{[l-1]}}}\)或Xavier初始化(\(\frac{2}{n^{[n-1]}+n^{[l]}}\))
梯度的数值逼近
双边误差公式的结果更准确:
双边误差\(\displaystyle f'(\theta) = \lim_{\epsilon \rightarrow 0}\frac{f(\theta+\epsilon)-f(\theta+\epsilon)}{2\epsilon}(O(\epsilon^2))\)
单边误差\(\displaystyle f'(\theta) =\lim_{\epsilon \rightarrow 0} \frac{f(\theta+\epsilon)-f(\theta)}{\epsilon}\)
梯度检验
- 将\(W^{[1]},b^{[1]},\cdots,W^{[L]},b^{[L]}\)转换成一个向量\(\theta\),从而\(J(W^{[1]},b^{[1],\cdots,W^{[L]},b^{[L]}}=J(\theta))\)
- 将\(dW^{[1]},db^{[1]},\cdots,dW^{[L]},db^{[L]}\)转换成向量\(d\theta\),
\(J(\theta) = J(\theta_1,\theta_2,\cdots) \\ 对每个i,d\theta_{approx[i]}(d\theta的逼近值) = \frac{J(\theta_1,\theta_2,\cdots,\theta_i+\epsilon,\cdots) - J(\theta_1,\theta_2,\cdots,\theta_i-\epsilon,\cdots)}{2\epsilon} \approx d\theta[i] = \frac{\partial J}{\partial \theta_i}\)
检验: \[ \frac{||d\theta_{approx}-d\theta||_2}{||d\theta_{approx}||_2+||d\theta||_2}<(\epsilon=10^{-7}) \]
注:
- 不要在训练中使用梯度检验,它只用于调试
- 如果算法的梯度检验失败,需要检查每一项,并试着找出bug
- 注意正则化
- 梯度检验不能与dropout同时使用
- 在随机初始化下运行;可能经过一些训练后再次运行
Mini-batch梯度下降法
确定角标
\(x^{(i)}:第i个训练样本 \\ z^{[l]}:表示神经网络第l层的z值 \\ X^{\{t\}}:表示第t个Mini-batch\)
之前的向量化可以高效的计算m个训练样本
\(X = [x^{(1)} \ x^{(2)} \ \cdots \ x^{(m)}] \\ Y = [y^{(1)} \ y^{(2)} \ \cdots \ y^{(m)}] \\\)
如果m很大,处理速度还是会很慢,这样一来就可以有一种新的方式:
假设m=5,000,000,可以把训练集分割为小一点的子训练集,将这些子集称为Mini-batch,假设每个子集有1000个样本,则
\(X^{\{1\}} = [x^{(1)} \ x^{(2)} \ \cdots \ x^{(1000)}] \\ X^{\{2\}} = [x^{(1001)} \ \cdots \ x^{(2000)}] \\ \cdots \\ X^{\{5000\}} = [\cdots \ x^{(m)}] \\ Y^{\{1\}} = [y^{(1)} \ y^{(2)} \ \cdots \ y^{(1000)}] \\ Y^{\{2\}} = [y^{(1001)} \ \cdots \ y^{(2000)}] \\ \cdots \\ Y^{\{5000\}} = [\cdots \ y^{(m)}]\)
Mini-batch梯度下降法:
\(for \ t=1,\cdots,5000 \\ \ \ 在X^{\{t\}}上前向传播 \\ \ \ Z^{[1]} = W^{[l]}X^{\{t\}}+b^{[l]} \\ \ \ A^{[1]} = g^{[1]}(Z^{[1]}) \\ \ \ \cdots \\ \ \ A^{[l]} = g^{[l]}(Z^{[l]}) \\ \ \ 计算Cost \ J = \frac{1}{1000} \sum_{i=1}^lL(\hat y^{(i)},y^{(i)})+\frac{\lambda}{2*1000}\sum_l||W^{[l]}||_F^2 \\ \ \ 反向传播\\ \ \ W^{[l]} := W^{[l]}-\alpha dW^{[l]},b^{[l]} := b^{[l]}-\alpha db^{[l]} \\\)

选择每个mini-batch的大小
如果mini-batch size=m,则转为batch gradient descent,\((X^{\{1\}},Y^{\{1\}}) = (X,Y)\)
如果mini-batch size=1,则称为stochastic gradient descent(随机梯度下降法),每个样本都是独立的mini-batch,\((X^{\{1\}},Y^{\{1\}}) = (x^{(1)},y^{(1)})\),并且无法使用向量化加速

因此,在实际使用中时,通常对size的选择不能太大也不能太小,需要适中
指数加权平均(Exponentially weighted averages)
例:每日温度绘制出的散点图如下
image-20201221112802102
数据杂乱,如果要计算趋势,则计算局部平均值(或移动平均值)
\(V_0 = 0 \\ V_1 = 0.9V_0 + 0.1\theta_1(\theta_t为当日温度)\\ V_2 = 0.9V_1 + 0.1\theta_2 \\ \cdots \\ V_t = 0.9V_{t-1} + 0.1\theta_t\)
计算结果,绘制出图上红色的线
\(V_t = \beta V_{t-1} + (1-\beta)\theta_t(V_t可视为约\frac{1}{1-\beta}天的温度的平均)\\ 当\beta = 0.9,则是十天的平均值 \\ 当\beta = 0.98,则是50天的平均值 \\ 当\beta = 0.5,则是2天的平均值\)

指数加权平均的偏差修正,来使平均数运算更加准确
由于上述初始化\(V_0=0\),所以当第1天温度较低时,计算出来\(V_1\)也会较小,同理\(V_2,V_3\)等也会较小
为了解决这个问题,通过\(\frac{V_t}{1-\beta^t}\)进行修正,如在第2天,则\(V_2 = \frac{原本计算的V_2}{1-\beta^2}\)
动量梯度下降法(Gradient descent with momentum)
传统的梯度下降法中,计算以上下波动的方式向目标点靠近,如图

如果使用较大的学习率,则结果又可能会偏离函数的范围
在纵轴上,希望学习慢一点避免波动过大,而在横轴上,又希望加快学习,快速从左向右移
使用动量梯度下降法来解决这一点:
\(在第t次迭代中: \\ 使用现有的mini-batch计算dW,db \\ V_{dW} = \beta V_{dW} + (1-\beta)dW(和指数加权平均中的公式一样,计算出dw的移动平均数)\\ V_{db} = \beta V_{db} + (1-\beta)db \\ W := W - \alpha V_{dW},b:=b-\alpha V_{db}\)
最终结果类似如图红色线部分

约束:适用于碗状函数,因为如\(V_{db} = \beta V_{db}+(1-\beta)db\)中,\(db\)相当于加速度,\(V_{db}\)相当于速度,而\(\beta\)相当于摩擦力,所以,不同于梯度下降法的每一步都是独立的,动量梯度下降相当于小球从碗上向下滚,球可以获得动量
加速梯度下降(RMSprop)
同上述动量梯度下降类似
\(在第t次迭代时:\\ 通过现有mini-batch计算dW,db \\ S_{dW} = \beta_2 S_{dW} + (1-\beta_2)dW^2 \\ S_{db} = \beta_2 S_{db} + (1-\beta_2)db^2 \\ W := W - \alpha \frac{dW}{\sqrt{S_{dW}}} \ b:=b-\alpha\frac{db}{\sqrt{S_{db}}} \\为了保证分母不为0,通常会在分母上添加一个非常小的数\epsilon \\ W := W - \alpha \frac{dW}{\sqrt{S_{dW}}+\epsilon} \ b:=b-\alpha\frac{db}{\sqrt{S_{db}}+\epsilon} (如\epsilon = 10^{-8})\)
原理是通过这样计算,可以使用更大的学习率,而不会超出函数范围,进而加速梯度下降
Adam优化算法
Adam优化算法是将Momentum和RMSprop结合起来的优化算法
Adam:Adaptive Moment Estimation
具体: \[ V_{dW}=0,S_{dW}=0,V_{db}=0,S_{db}=0 \\ 在第t次迭代 \\ 通过现有mini-batch计算dW,db \\ V_{dW} = \beta_1 V_{dW}+(1-\beta_1)dW \\ V_{db} = \beta_1 V_{db}+(1-\beta_1)db \\ S_{dW} = \beta_2 S_{dW}+(1-\beta_2)dW^2 \\ S_{db} = \beta_2 S_{db}+(1-\beta_2)db^2 \\ V^{corrected}_{dW} = \frac{V_{dW}}{1-\beta_1^t},V^{corrected}_db = \frac{V_{db}}{1-\beta_1^t}(偏差修正) \\ S^{corrected}_{dW} = \frac{V_{dW}}{1-\beta_2^t},S^{corrected}_db = \frac{S_{db}}{1-\beta_2^t}(偏差修正) \\ W := W-\alpha \frac{V^{corrected}_{dW}}{\sqrt{S_{dW}^{corrected}}+\epsilon},b:=b-\alpha\frac{V_{db}^{corrected}}{\sqrt{S^{corrected}_{db}}+\epsilon} \]
超参数选择:
\(\alpha\):需要多次尝试调整
\(\beta_1\):默认值一般用0.9
\(\beta_2\):默认值一般用0.999
\(\epsilon\):建议用\(10^{-8}\)
学习率衰减(Learning rate decay)
本质在于在训练学习初期,可以快速向收敛点靠拢,当开始收敛时,小的学习率可以让步伐小一些,保证在收敛点小范围内波动
\[ \alpha = \frac{1}{1+decay \ rate(衰减率) * epoch\ num(迭代次数}\alpha_0 \\ decay \ rate是一个超参数 \]
eg:\(\alpha\)=0.2,decay rate=1,则
Epoch \(\alpha\) 1 0.1 2 0.067 3 0.05 4 0.04 ... ...
其它的学习率衰减方法:
\(\alpha = 0.95^{epoch\ num}\alpha_0\)学习率呈指数下降
\(\alpha = \frac{k}{\sqrt{epoch\ num}}\alpha_0\),k为常数
离散下降
手动衰减
局部最优问题
实际上,由于深度学习大多数在高维空间,所以遇到局部最优的可能并不大,更可能遇到的是鞍点
新的问题是平稳段会减缓学习(因此Momentum、RMSprop可以加速学习)