1.训练集、开发集、测试集
图1 神经网络开发流程
在进行神经网络项目时,其过程不是一次写好代码就能成功的,而是要经过想法(Idea)->代码(Code)->实验(Experiment)的循环,当实验时发现效果不佳,再进行调整超参数经过多次迭代后才能做出最优的模型。
图2 训练集、开发集、测试集
其中训练集是用来训练模型的,而开发集是用来测试训练模型并用测试结果来调整模型的超参数来迭代优化模型的,而测试集是最终用来评判模型的效果的。如果没有开发集,其比例为7:3,存在开发集其比例通常为6:2:2。但是在数据样本比较多的时候,只需要保证开发集和测试集样本数量足够就行,不必按照比例来,比如有100万个样本,开发集和测试集可能分别只占到1万个就足够了。
当有些只有测试集而没有开发集的数据源时,测试集还兼顾开发集的任务——进行交叉验证,来确定样本的偏差和方差是否合理。
2.偏差和方差
图3 高偏差和高方差和刚刚好的预测
1.当预测存在高偏差时,有多个点会被误判。
2.当预测存在高方差时,预判的线会非常曲折以迎合每个训练样本,但是这样会使得未通过训练的测试集预测的准确率较低。
3.当刚刚好时,预测的结果应该会舍弃哪些偏差值比较大的点,预测线比较平滑且能囊括大多数正确的点。
图4高方差和高偏差的辨别方法
如果训练集的预测误差很小但是开发集的预测偏差较大,那么这个模型是高方差的。
如果训练集和开发集的预测误差都比较大但是两者相差较小,那么这个模型是高偏差的。
如果训练集的误差大而开发集的预测误差更大,那么这个模型是即高偏差又高方差的。
如果训练集的误差很小,开发集的误差也很小,那么这个模型是一个不错的模型。
如果训练集本身就很模糊,连人类都可能很难分清,假设人识别的误差为15%(这个叫做贝叶斯误差),即使预测结果稍微高于15%那么也可以认为该模型是低偏差的。
3.调试机器学习的基本准则
1.高偏差解决办法
尝试使用更大的网络,增加梯度下降算法迭代次数,或者更换其他种类网络。
2.高方差解决办法
尝试更多的数据,尝试正则化,更换更适合的网络种类。
经过反复地调优,将方差和偏差降到最小,便可以得到最优的模型。
在机器学习早期,我们只能对低方差和低偏差进行取舍。但是在目前的大数据和深度学习下,现在有更多的方法将只减少方差或者只减少偏差而另一个不会因此改变而增大。(这些方法在之后的教学中有所讲解)
4.正则化
图5 L2范数正则化
如图所示在计算损失函数J(w,b)额外加上一个lambda/2m乘以w的2范数项便是L2正则化,这里w的二范数是w乘以w转置。为什么这里只加w的二范数不加上b的二范数,因为w代表的维度更高,通常高方差的模型,往往是因为w参数维度过高引起的。
L1正则化则是令L2正则化中的w二范数变为一范数便是L1正则化。
这里的lambda也是我们需要调优的一个超参数,其决定了我们需要正则化的网络层的正则化权重。
图6 L2范数正则化在神经网络中起到的作用
在经过作者的计算在第L层正则化后的网络中,dw[L]比没有正则化的dw[L]新增了一项lambda/m乘以w[L]而这一项往往是正的。所以在计算新的w[L]时要多减去一个α*lambda/m*dw[L]项,也就是说这样w[L]始终要比没有正则化的网络要小那么一点点。所以L2正则化又称为权重衰减。
5.为什么正则化能够防止过拟合
图7 为什么正则化会防止过拟合
在上图中,可以直观看到,当把lambda设置得比较大时,最后计算出的w值会很小,这样经过正则化层的w对模型的影响会很小就相当于减少了网络层数,这样就能自动起到减少网络大小来防止过拟合现象。所以只要设置合适的lambda便可以使得模型预测结果从high variance变为just right图所示的状态。
图8 带有tanh激活的层使用正则化
如图所示,当激活函数为tanh时,正则化会使得w很小,那么它的输出值应该也会很小,所以输出会在tanh的线性区,这样就可以减少模型会模拟非线性的比较复杂的函数的情况。
6.随机失活正则化(Dropout regularization)
图9 随机失活正则化原理
随机失活就是每次梯度迭代计算的时候模型会自动按设定的概率随机将指定层的神经单元的激活值A[L]置0.
具体方法是生成一个与L层输出A[L]一样的随机矩阵,这个矩阵只有1和0,0和1出现的概率是设定的概率值keep-prob大小而定的。让A[L]按位乘以这个新矩阵便得到随机失活后的L层输出A[L]'。另外生成的A[L]还需要除以keep-prob以保持输出的激活值整体期望值不变,以保证在测试模型的时候,因为不能使用Dropout来进行预测(如果测试的时候使用Droupout会导致预测结果不稳定),导致测试结果期望值会比训练的时候不一样,这样预测的结果就不准确了。
6.理解随机失活方法
假设一次迭代过程中有个4个单元中有两个单元的输出被随机失活了,而下次迭代中另外两个单元的输出被舍弃了。那么神经网络会学习到,不能把所有权重都放在某一个单元上(否则那个权重过高的单元失活损失函数会很大),而是把权重均分到4个单元中,通过分散权重将会达到类似于L2正则化效果。实际上随机失活方法的强度与L2正则化差不多,事实上相当于一种自适应的L2正则化,对防止过拟合都是有效的。
图10 随机失活正则化的网络
如图所示的网络,将输入的keep-prob保持为1,而第1层和第二层的网络比较大,可以将keep-prob值设置的稍微小一点,防止过拟合,而后续的3,2,1层都比较小,可以将keep-prob设置得大点或者置1。
7.其他的正则化方法
图11 数据增强
1.数据增强
将原始数据裁剪、旋转,稍微扭曲,增加样本数量的方法来减少过拟合。
图12 提前停止梯度下降算法
2.提前停止梯度下降算法
自动检测开发集误差和训练集误差,当两者之差lambda变大,大到一定值时就停止学习。他的缺点是不能保证即能使损失J小又防止过拟合,最后得出损失J可能会比较大也许会出现高偏差现象。(正交化法则是保证J值小再防止过拟合,或者保证不过拟合来使得J更小,但是提前停止梯度下降算法没有做到正交化法则)
解决这一缺点可以尝试不同的lambda,进行多次训练,尝试最合适的lambda使得最后模型刚刚好。前提是投入更多计算机资源和时间成本。
8.规范化输入
图13 规范化输入数据
如图所示,第一步将输入减去一个所有样本平均值,第二步将所有输入值除以样本均方的平方根,这个会使得扁平的数据变为一个接近为原型的数据。这便是规范化输入。
规范化输入可以使得梯度学习起来更快。其原理如下图所示:
如果样本没有做规范化,损失函数J会相应得更扁,那么当学习速率比较小时,需要更多的步骤找到J的最小值,如果样本做了规范化,损失函数会变成圆形,这样不论从哪个点开始梯度下降,都能最快达到梯度最低点。
需要注意的是,训练时我们对训练样本输入进行规范化,在测试时我们同样也需要将测试样本输入进行规范化。
9.梯度爆炸和梯度消失
在一个很深层的网络中,每一层的w如果比1稍大,那么输出的激活函数将是输入的指数倍,越到后面层,dw会变得越来越大,最后会大到爆炸,后面层梯度每次迭代会变得非常大,从而不能保证能下降到最低值。同样如果每一层的w如果比1稍小,输出也是输入的指数级小,越到后面层dw会越来越小,会造成梯度消失情况,后面层学习效率变得很低。
10.深度神经网络权重初始化
如果是ReLu激活层则用下式激活:
其中shape是w[L]的形状。而n[L-1]是上一层的节点数。用这个方法会使得Z值在初始化时始终保持w[L]矩阵始终保平均值为0而方差保持为1,这样会使得z项也呈现相同的分布特征,这种方法使得w不会比1大很多也不会比1小很多(A[L-1]乘以w[L]后基本不会变化很大),会有效降低梯度消失和梯度爆炸的出现。
而在tanh激活函数会使用1/n[L-1]而不是2/n[L-1]。(作者在这里没有讲清楚原因,只好暂且这么记着)
11.近似计算梯度
利用导数定义:
这样计算的梯度便是近似计算的梯度,这个方法将会在梯度检验中用到。
12. 梯度校验
如图令θ[i]=W[L]*A[L-1]+b[L]将损失函数写成J(θ[1],θ[2],....θ[i],....)按照11节的方式,形式求θ[i]的梯度dθ(approx),如果这样求得的dθ(approx)与实际的dθ求欧几里得距离,这个距离在10的-7次方以下说明模型梯度算法没有问题。如果在10的-3次方以上说明模型梯度算法有很大问题。
12.梯度检验需要注意的点
1.需要注意的是梯度检验只有在调试的时候打开,在训练的时候需要关闭,因为它会浪费计算机资源。
2.在L2范数正则化的时候梯度检验不要忘了加上被加上的正则化项加入到检验公式中。
3.在开启了随机失活的网络中,梯度检验会无法计算,因此,需要先关闭随机失活进行梯度检验后再开启随机失活。
13.编程作业
13.1.权重初始化
He初始化,用于ReLu激活函数的层:
parameters['W' + str(l)] = np.random.randn(layers_dims[l],layers_dims[l1])*np.sqrt(2./layers_dims[l-1])
Xavier初始化:
parameters['W' + str(l)] = np.random.randn(layers_dims[l],layers_dims[l1])*np.sqrt(1./layers_dims[l-1])
0初始化,梯度消失的结果,梯度下降几乎停止:
超大值初始化,梯度爆炸,损失函数损失值不能达到最小值,预测准确率低:
He初始化效果,损失下降平滑且能达到很小的值:
13. 2.正则化
无正则化效果:
出现过拟合
13.2.1.L2正则化
L2正则化损失函数补偿量计算:
L2_regularization_cost = 1./2.*lambd/m(np.sum(np.square(W1))+np.sum(np.square(W2))+np.sum(np.square(W3)))
L2正则化反向传播dw计算:
dW3 = 1./m * np.dot(dZ3, A2.T) +lambd/m*W3
效果:
13.2.2.Dropout正则化
正向传播Dropout计算A:
D1=np.random.rand(A1.shape[0],A1.shape[1])
D1=(D1 < keep_prob).astype(int)
A1=np.multiply(D1,A1)
A1=A1/keep_prob
反向传播计算dA
dA1=np.multiply(dA1,D1)
dA1=dA1/keep_prob
效果:
13.3梯度校验
计算J+:
theta_plus=np.copy(parameters_values)
theta_plus[i]=theta_plus[i]+epsilon
J_plus[i], _ =forward_propagation_n(X, Y, vector_to_dictionary(theta_plus))
计算J-:
theta_minus=np.copy(parameters_values)
theta_minus[i]=theta_minus[i]-epsilon
J_minus[i], _ =forward_propagation_n(X, Y, vector_to_dictionary(theta_minus))
计算grad(approx):
gradapprox[i] =(J_plus[i]-J_minus[i])/2/epsilon
计算grad与grad(approx)欧几里得距离
numerator= np.linalg.norm(gradapprox)+np.linalg.norm(grad)
denominator=np.linalg.norm(gradapprox-grad)
difference=denominator/numerator