版权为吴恩达老师所有,参考Koala_Tree的博客,部分根据自己实践添加
使用google翻译,部分手工翻译
你可能需要的参考资料https://pan.baidu.com/s/1FYIAD_x1YT1evWM5X0ODjA
第2部分:正规化
我们首先导入您要使用的包。
import numpy as np
import matplotlib.pyplot as plt
from reg_utils import sigmoid,relu,plot_decision_boundary,initialize_parameters,load_2D_dataset,predict_dec
from reg_utils import compute_cost,predict,forward_propagation,backward_propagation,update_parameters
import sklearn
import sklearn.datasets
import scipy.io
from testCases import *
plt.rcParams['figure.figsize'] = (7.0, 4.0) # set default size of plots
plt.rcParams['image.interpolation'] = 'nearest'
plt.rcParams['image.cmap'] = 'gray'
问题陈述:您刚刚被法国足球公司聘为AI专家。他们希望你推荐法国队的守门员应该踢球的位置,以便法国队的球员可以用他们的头来击球。
图1 :足球场
守门员将球踢到空中,每支球队的球员都在用头撞击球
他们为您提供了法国过去10场比赛的以下2D数据集。
每个点对应于足球场上的位置,在法国守门员从足球场的左侧射球之后,足球运动员用他/她的头击球。
- 如果点是蓝色,则意味着法国球员设法用他/她的头部击球
- 如果点是红色,则意味着其他球队的球员用他们的头击球
你的目标:使用深度学习模型找到守门员应该踢球的场地位置。
数据集的分析:这个数据集有点乱,但它看起来像是左上半部分(蓝色)和右下半部分(红色)分开的对角线,效果很好。
您将首先尝试非正规化模型。然后你将学习如何规范它并决定你将选择哪种模式来解决法国足球公司的问题。
1 - 非正则化模型
您将使用以下神经网络(已在下面为您实现)。可以使用此模型:
- 在正则化模式下 - 通过将lambd
输入设置为非零值。我们使用“ lambd
”而不是“ lambda
”因为“ lambda
”是Python中的保留关键字。
- 在退出模式下 - 通过将keep_prob
值设置为小于1
您将首先尝试没有任何正规化的模型。然后,您将实现:
- L2正则化 - 函数:“ compute_cost_with_regularization()
”和“ backward_propagation_with_regularization()
”
- Dropout - 函数:“ forward_propagation_with_dropout()
”和“ backward_propagation_with_dropout()
”
在每个部分中,您将使用正确的输入运行此模型,以便它调用您已实现的功能。请查看下面的代码以熟悉模型。
def model(X,Y,learning_rate=0.3,num_iterations=30000,print_cost=True,lambd=0,keep_prob=1):
grads={}
costs=[]
m=X.shape[1]
layers_dims=[X.shape[0],20,3,1]
parameters=initialize_parameters(layers_dims)
for i in range(0,num_iterations):
if keep_prob==1:
a3,cache=forward_propagation(X,parameters)
elif keep_prob<1:
a3,cache=forward_propagation_with_dropout(X,parameters,keep_prob)
if lambd==0:
cost=compute_cost(a3,Y)
else:
cost=compute_cost_with_regularization(a3,Y,parameters,lambd)
assert(lambd==0 or keep_prob==1)
if lambd==0 and keep_prob == 1:
grads=backward_propagation(X,Y,cache)
elif lambd!=0:
grads=backward_propagation_with_regularization(X,Y,cache,lambd)
elif keep_prob<1:
grads=backward_propagation_with_dropout(X,Y,cache,keep_prob)
parameters=update_parameters(parameters,grads,learning_rate)
if print_cost and i%10000 == 0:
print("Cost after iteration {}: {}" .format(i,cost))
costs.append(cost)
plt.close()
plt.plot(costs)
plt.ylabel("cost")
plt.xlabel("iterations (x1000)")
plt.title("learning rate = "+str(learning_rate))
plt.show()
return parameters
让我们在没有任何正则化的情况下训练模型,并观察训练/测试集的准确性。
parameters = model(train_X, train_Y)
print ("On the training set:")
predictions_train = predict(train_X, train_Y, parameters)
print ("On the test set:")
predictions_test = predict(test_X, test_Y, parameters)
训练精度为94.8%,测试精度为91.5%。这是基线模型(您将观察正则化对此模型的影响)。运行以下代码以绘制模型的决策边界。
plt.title("Model without regularization")
axes = plt.gca()
axes.set_xlim([-0.75,0.40])
axes.set_ylim([-0.75,0.65])
plot_decision_boundary(lambda x: predict_dec(parameters, x.T), train_X, train_Y)
非正则化模型显然过度拟合了训练集。拟合了嘈杂的点!现在让我们看看两种减少过度拟合的技术。
2 - L2正则化
避免过度拟合的标准方法称为L2正则化。它包括适当修改您的成本函数,来自:
至:
让我们修改您的成本并观察后果。
练习:实现compute_cost_with_regularization()
计算公式(2)给出的成本。计算
np.sum(np.square(Wl))
请注意,您必须为,,执行此操作,然后将这三个项相加并乘以
def compute_cost_with_regularization(A3,Y,parameters,lambd):
m=Y.shape[1]
W1=parameters["W1"]
W2=parameters["W2"]
W3=parameters["W3"]
cross_entropy_cost=compute_cost(A3,Y)
L2_regularization_cost=(1.0/m*lambd/2)*(np.sum(np.square(W1))+np.sum(np.square(W2))+np.sum(np.square(W3)))
cost=cross_entropy_cost+L2_regularization_cost
return cost
A3, Y_assess, parameters = compute_cost_with_regularization_test_case()
print("cost = " + str(compute_cost_with_regularization(A3, Y_assess, parameters, lambd = 0.1)))
当然,因为你改变了成本,你也必须改变向后传播!必须根据这个新成本计算所有梯度。
练习:实现向后传播所需的更改以考虑正则化。这些变化仅涉及dW1,dW2和dW3。对于每个,您必须添加正则化项的梯度
.
def backward_propagation_with_regularization(X,Y,cache,lambd):
m=X.shape[1]
(Z1,A1,W1,b1,Z2,A2,W2,b2,Z3,A3,W3,b3)=cache
dZ3=A3-Y
dW3=1.0/m*np.dot(dZ3,A2.T)+lambd/m*W3
db3=1.0/m*np.sum(dZ3,axis=1,keepdims=True)
dA2=np.dot(W3.T,dZ3)
dZ2=np.multiply(dA2,np.int64(A2>0))
dW2=1.0/m*np.dot(dZ2,A1.T)+lambd/m*W2
db2=1.0/m*np.sum(dZ2,axis=1,keepdims=True)
dA1=np.dot(W2.T,dZ2)
dZ1=np.multiply(dA1,np.int64(A1>0))
dW1=1.0/m*np.dot(dZ1,X.T)+lambd/m*W1
db1=1.0/m*np.sum(dZ1,axis=1,keepdims=True)
gradients = {"dZ3": dZ3, "dW3": dW3, "db3": db3,"dA2": dA2,
"dZ2": dZ2, "dW2": dW2, "db2": db2, "dA1": dA1,
"dZ1": dZ1, "dW1": dW1, "db1": db1}
return gradients
X_assess, Y_assess, cache = backward_propagation_with_regularization_test_case()
grads = backward_propagation_with_regularization(X_assess, Y_assess, cache, lambd = 0.7)
print ("dW1 = "+ str(grads["dW1"]))
print ("dW2 = "+ str(grads["dW2"]))
print ("dW3 = "+ str(grads["dW3"]))
现在让我们运行L2正则化模型(λ=0.7)。该model()
函数将调用:
- compute_cost_with_regularization
而不是compute_cost
- backward_propagation_with_regularization
而不是backward_propagation
parameters = model(train_X, train_Y, lambd = 0.7)
print ("On the train set:")
predictions_train = predict(train_X, train_Y, parameters)
print ("On the test set:")
predictions_test = predict(test_X, test_Y, parameters)
恭喜,测试集的准确率提高到93%。你救了法国足球队!
你不再过度拟合训练数据了。让我们绘制决策边界。
plt.title("Model with L2-regularization")
axes = plt.gca()
axes.set_xlim([-0.75,0.40])
axes.set_ylim([-0.75,0.65])
plot_decision_boundary(lambda x: predict_dec(parameters, x.T), train_X, train_Y)
观察:
- λ的值升是一个超参数,您可以使用开发集进行调整。
- L2正则化使您的决策边界更加平滑。如果λ升 太大,也可能“过度平滑”,导致模型具有高偏差。
什么是L2正规化实际上在做什么?:
L2正则化依赖于这样的假设:具有小权重的模型比具有大权重的模型更简单。因此,通过惩罚成本函数中权重的平方值,可以将所有权重变为更小的值。拥有大权值的成本太昂贵了!这导致更平滑的模型,其中输出随输入变化而变化更慢。
您应该记住的内容--L2正则化对以下因素的影响:
- 成本计算:
- 将正则化项添加到成本中
- 反向传播函数:
- 在权重矩阵的梯度中有额外的项
- 权重最终变小(“权值衰减”):
- 权值被推到较小的值。
3 - Dropout
最后,dropout是一种广泛使用的正规化技术,专门用于深度学习。
它在每次迭代中随机关闭一些神经元。
当你关闭一些神经元时,你实际上修改了你的模型。dropout背后的想法是,在每次迭代中,您训练一个仅使用神经元子集的不同模型。随着dropout,您的神经元因此对另一个特定神经元的激活变得不那么敏感,因为其他神经元可能随时关闭。
3.1 - 带有dropout的前向传播
练习:使用dropout实现前向传播。您正在使用3层神经网络,并将dropout添加到第一个和第二个隐藏层。我们不会将dropout应用于输入层或输出层。
说明:
您想关闭第一层和第二层中的一些神经元。为此,您将执行4个步骤:
1.在课程中,我们讨论了用np.random.rand()(
获得0和1之间的随机数字)
创建和形状相同的变量,在这里,你会实现向量化,创建一个与形状相同的随机矩阵。
2.合理地设置每项中为0的概率(1-keep_prob
)或为1的概率(keep_prob)
。提示:将矩阵X的所有项设置为0(如果小于0.5)或1(如果大于0.5),您将执行以下操作:X = (X < 0.5)
。注意,0和1分别等于False和True。
3.将变为(你正在关闭一些神经元)。你可以想到D.[1]d[1]作为一个掩码,当它与另一个矩阵相乘时,它会关闭一些值。
4.除以keep_prob
。通过这样做,您可以确保成本的结果仍然具有与没有dropout相同的预期值。(这种技术也称为反向丢失。)
def forward_propagation_with_dropout(X,parameters,keep_prob=0.5):
np.random.seed(1)
W1=parameters["W1"]
b1 = parameters["b1"]
W2 = parameters["W2"]
b2 = parameters["b2"]
W3 = parameters["W3"]
b3 = parameters["b3"]
Z1=np.dot(W1,X)+b1
A1=relu(Z1)
D1=np.random.rand(A1.shape[0],A1.shape[1])
D1=D1<keep_prob
A1=A1*D1
A1=A1/keep_prob
Z2=np.dot(W2,A1)+b2
A2=relu(Z2)
D2=np.random.rand(A2.shape[0],A2.shape[1])
D2=D2<keep_prob
A2=A2*D2
A2=A2/keep_prob
Z3=np.dot(W3,A2)+b3
A3=sigmoid(Z3)
cache=(Z1,D1,A1,W1,b1,Z2,D2,A2,W2,b2,Z3,A3,W3,b3)
return A3,cache
X_assess, parameters = forward_propagation_with_dropout_test_case()
A3, cache = forward_propagation_with_dropout(X_assess, parameters, keep_prob = 0.7)
print ("A3 = " + str(A3))
3.2 - 带有dropout的向后传播
练习:使用dropout实现向后传播。和以前一样,您正在训练3层网络。将dropout添加到第一个和第二个隐藏层使用存储在cache中的。
说明:
带dropout的反向传播实际上非常简单。你将执行两个步骤:
1。你曾经通过应用到上在前向传播期间关闭了一些神经元。在反向传播中,您必须通过重新应用相同的来关闭相同的神经元dA1
。
2.在正向传播,你已经将A1除以
keep_prob
。在反向传播,你需要再将dA1除以
keep_prob
(微积分解释是,如果一个按比例缩放keep_prob
,它的导数也要按比例缩放keep_prob
)。
def backward_propagation_with_dropout(X,Y,cache,keep_prob):
m=X.shape[1]
(Z1,D1,A1,W1,b1,Z2,D2,A2,W2,b2,Z3,A3,W3,b3)=cache
dZ3=A3-Y
dW3=1.0/m*np.dot(dZ3,A2.T)
db3=1.0/m*np.sum(dZ3,axis=1,keepdims=True)
dA2=np.dot(W3.T,dZ3)
dA2=dA2*D2
dA2=dA2/keep_prob
dZ2=np.multiply(dA2,np.int64(A2>0))
dW2=1.0/m*np.dot(dZ2,A1.T)
db2=1.0/m*np.sum(dZ2,axis=1,keepdims=True)
dA1=np.dot(W2.T,dZ2)
dA1=dA1*D1
dA1=dA1/keep_prob
dZ1=np.multiply(dA1,np.int64(A1>0))
dW1=1.0/m*np.dot(dZ1,X.T)
db1=1.0/m*np.sum(dZ1,axis=1,keepdims=True)
gradients = {"dZ3": dZ3, "dW3": dW3, "db3": db3,"dA2": dA2,
"dZ2": dZ2, "dW2": dW2, "db2": db2, "dA1": dA1,
"dZ1": dZ1, "dW1": dW1, "db1": db1}
return gradients
X_assess, Y_assess, cache = backward_propagation_with_dropout_test_case()
gradients = backward_propagation_with_dropout(X_assess, Y_assess, cache, keep_prob = 0.8)
print ("dA1 = " + str(gradients["dA1"]))
print ("dA2 = " + str(gradients["dA2"]))
现在让我们使用dropout(keep_prob = 0.86
)运行模型。这意味着在每次迭代中,您以24%的概率关闭第1层和第2层的每个神经元。该功能model()
现在将调用:
- forward_propagation_with_dropout
而不是forward_propagation
。
- backward_propagation_with_dropout
而不是backward_propagation
。
parameters = model(train_X, train_Y, keep_prob = 0.86, learning_rate = 0.3)
print ("On the train set:")
predictions_train = predict(train_X, train_Y, parameters)
print ("On the test set:")
predictions_test = predict(test_X, test_Y, parameters)
dropout效果很好!测试精度再次提高(达到95%)!您的模型不会过度拟合训练集,并且在测试集上做得很好。法国足球队将永远感激你!
运行下面的代码绘制决策边界。
plt.title("Model with dropout")
axes = plt.gca()
axes.set_xlim([-0.75,0.40])
axes.set_ylim([-0.75,0.65])
plot_decision_boundary(lambda x: predict_dec(parameters, x.T), train_X, train_Y)
注意:
- 使用dropout时常见的错误是在训练和测试中使用它。您应该仅在训练中使用dropout(随机消除节点)。
- 像tensorflow,PaddlePaddle,keras或caffe这样的深度学习框架带有一个dropout层实现。
不要紧张 - 你很快就会学到一些这样的框架。
关于dropout你应该记住什么:
- dropout是一种正规化技术。
- 您只在训练期间使用dropout。在测试期间不要使用dropout(随机消除节点)。
- 在向前和向后传播期间应用dropout。
- 在训练期间,通过keep_prob划分每个dropout层,以保持激活的预期值相同。例如,如果keep_prob为0.5,那么我们将平均关闭一半节点,因此输出将缩放0.5,因为只有剩下的一半对解决方案有贡献。除以0.5相当于乘以2.因此,输出现在具有相同的期望值。即使keep_prob的值不是0.5,您也可以检查这是否有效。
4。结论
以下是我们三种模型的结果:
**模型** | **训练准确度** | **测试准确度** |
没有正则化的3层NN | 95% | 91.5% |
具有L2正则化的3层NN | 94% | 93% |
具有dropout的3层NN | 93% | 95% |
请注意,正规化会损害训练集的性能!这是因为它限制了网络过度拟合训练集的能力。但由于它最终会提供更好的测试精度,因此它可以帮助您的系统。
恭喜你完成这项任务!而且还为法国足球的革命。(祝贺法国队获得2018年世界杯冠军) :-)
我们希望您从中记住:
- 正规化将帮助您减少过度拟合。
- 正规化将使您的权重降低到更低的值。
- L2正则化和dropout是两种非常有效的正则化技术。