本文主要参考红色石头Will大佬的完结篇 | 吴恩达deeplearning.ai专项课程精炼笔记全部汇总、何宽大大的【目录】【中文】【deplearning.ai】【吴恩达课后作业目录】,诸多语句和代码摘取其中原句。两位前辈将吴恩达的学习视频和课后编程作业解读得通俗透彻,适合如我这样的初学者,吹爆!
该笔记是吴恩达深度学习课程中Course 2 改善深层神经网络 的全部内容小结,综合了课后编程的部分代码实现和个人思绪归类。
文章目录
实用层面
Train/Dev/Test sets
数据集分类
- 训练集Training sets用来训练你的算法模型
- 验证集Dev sets用来验证不同算法的表现情况,从中选择最好的算法模型
- 测试集Test sets用来测试最好算法的实际表现,作为该算法的无偏估计。
数据集比例
- 样本数量不大
- Train : Test = 7 : 3
- Train : Dev : Test = 3 : 1 : 1
- 样本数量大
- Train : Test = 99 : 1
- Train : Dev : Test = 98 : 1 : 1
根据实际样本数量考虑,样本数据量越大,对应的Dev/Test sets比例可以相较Train设置得越低。
数据集注意
- 尽量保证Dev sets和Test sets来自于同一分布
- 对Train sets做如翻转、随机噪声等处理,扩大训练样本数量。
- 不进行无偏估计也可以,即没有Test sets也没有问题。
Bias/Variance
解决高偏差和高方差的方法不同,分别通过训练集和验证集判断是否出现高偏差或高方差,再分别针对性解决。
偏差
偏差过高,即欠拟合。
减少偏差的方法:
- 增加神经网络的隐藏层个数、神经元个数
- 延长训练时间
- 选择其他的神经网络模型
方差
方差过高,即过拟合
减少方差的方法:
- 增加训练样本数据
- 进行正则化
- 选择其他的神经网络模型
Regularization
L2正则化
- L1正则化
- L2正则化
L1正则得到的w更加稀疏,能节约存储空间,但微分求导方面更复杂,所以一般用L2正则。
使用L2正则后,梯度下降算法中:
故L2正则也被称作权重衰减,w在迭代中相较于没有正则项的w不断减小。
Dropout正则化
在深度学习网络的训练过程中,对于每层的神经元,按照一定的概率将其暂时从网络中丢弃。
dl = np.random.rand(al.shape[0], al.shape[1]) < keep_prob # 生成dropout vector
al = np.multiply(al,dl) # 对l层进行dropout处理,随机删减神经元
al /= keep_prob # 对l层进行scale up处理,保持期望值不变
在用dropout训练结束后,在测试和实际应用中不需要进行dropout正则化。
其他正则化方法
- 数据扩张(data augmentation),对已有图片进行翻转、缩放或扩大、扭曲、增加噪音等等。
- 提前停止法(early stopping),在避免欠拟合后及时停止训练避免过拟合,但会影响损失函数的减小,不常用。
Normalizing inputs
标准化输入即对训练数据集进行归一化操作,将原始数据减去其均值后,再除以其方差,以此提高训练速度。
让所有输入归一化同样的尺度上,避免其中某些与其他输出差异大的输出发生振荡,方便进行梯度下降算法时能够更快更准确地找到全局最优解。
Vanishing and Exploding gradients
梯度消失和梯度爆炸,是指当训练一个层数非常多的神经网络时,计算得到的梯度可能非常小或非常大,甚至是指数级别的减小或增大,从而让训练过程变得非常困难。
本质原因是权重W随着层数的增加,出现指数型增大或减小,从而影响预测输出。
解决方法即初始化权重W,使得W与n有关,且n越大,W应该越小。
w[l] = np.random.randn(n[l], n[l-1]) * np.sqrt(1 / n[l - 1]) # 激活函数是tanh常用
w[l] = np.random.randn(n[l], n[l-1]) * np.sqrt(2 / n[l - 1]) # 激活函数是ReLU常用
Gradient checking
一维线性
根据求导的定义计算每个 θ \theta θ的近似梯度,利用欧式距离与反向传播得到的 θ \theta θ比较,检查是否一致。
def gradient_check(x,theta,epsilon=1e-7):
"""
实现图中的反向传播。
参数:
x - 一个实值输入
theta - 参数,也是一个实数
epsilon - 计算输入的微小偏移以计算近似梯度
返回:
近似梯度和后向传播梯度之间的差异
"""
#使用公式(3)的左侧计算gradapprox。
thetaplus = theta + epsilon # Step 1
thetaminus = theta - epsilon # Step 2
J_plus = forward_propagation(x, thetaplus) # Step 3
J_minus = forward_propagation(x, thetaminus) # Step 4
gradapprox = (J_plus - J_minus) / (2 * epsilon) # Step 5
#检查gradapprox是否足够接近backward_propagation()的输出
grad = backward_propagation(x, theta)
numerator = np.linalg.norm(grad - gradapprox) # Step 1'
denominator = np.linalg.norm(grad) + np.linalg.norm(gradapprox) # Step 2'
difference = numerator / denominator # Step 3'
if difference < 1e-7:
print("梯度检查:梯度正常!")
else:
print("梯度检查:梯度超出阈值!")
return difference
高维
For i in num_parameters
:
-
计算
J_plus[i]
:- 把 θ + \theta^{+} θ+ 设置为
np.copy(parameters_values)
- 把 θ + \theta^{+} θ+ 设置为 θ + + ε \theta^{+}+\varepsilon θ++ε
- 使用
forward_propagation_n(x, y, vector_to_dictionary(
θ+))
来计算 J i + J_{i}^{+} Ji+
- 把 θ + \theta^{+} θ+ 设置为
-
计算
J_minus[i]
: 使用相同的方法计算 θ − \theta^{-} θ− -
计算 g r a d a p p r o x [ i ] = J i + − J i − 2 ε gradapprox[i]=\frac{J_{i}^{+}-J_{i}^{-}}{2\varepsilon} gradapprox[i]=2εJi+−Ji−
-
计算梯度
-
计算误差:
d i f f e r e n c e = ∥ g r a d − g r a d a p p r o x ∥ 2 ∥ g r a d ∥ 2 + ∥ g r a d a p p r o x ∥ 2 difference = \frac{\|grad-gradapprox\|_{2}}{\|grad\|_{2}+\|gradapprox\|_{2}} difference=∥grad∥2+∥gradapprox∥2∥grad−gradapprox∥2
def gradient_check_n(parameters,gradients,X,Y,epsilon=1e-7):
"""
检查backward_propagation_n是否正确计算forward_propagation_n输出的成本梯度
参数:
parameters - 包含参数“W1”,“b1”,“W2