5.正则化
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 *
%matplotlib inline
plt.rcParams['figure.figsize'] = (7.0, 4.0)
plt.rcParams['image.interpolation'] = 'nearest'
plt.rcParams['image.cmap'] = 'gray'
##############################################
这段代码看起来是一个Python脚本的开头,它导入了一些必要的库和模块,以及一些自定义的工具函数和测试用例。
-
import numpy as np
: 导入NumPy库,并将其重命名为np
,以便在代码中使用更短的别名来引用NumPy函数。 -
import matplotlib.pyplot as plt
: 导入Matplotlib库的pyplot
模块,并将其重命名为plt
,以便在代码中使用更短的别名来创建和操作图形。 -
from reg_utils import ...
: 这一行导入了自定义的一些函数和工具类,它们似乎与正则化(regularization)有关,包括sigmoid函数、relu函数、绘制决策边界的函数、初始化模型参数的函数、加载数据集的函数、进行预测的函数、计算损失的函数、前向传播和反向传播的函数以及更新模型参数的函数。这些函数很可能在后续的代码中使用。 -
import sklearn
和import sklearn.datasets
: 导入scikit-learn库以及其datasets模块,这些库和模块通常用于机器学习任务,可能会在后续的代码中使用。 -
import scipy.io
: 导入SciPy库,SciPy通常用于科学计算和数据分析,它也可能会在后续的代码中使用。 -
from testCases import *
: 这一行导入了一个名为testCases
的模块中的所有内容。这通常用于测试代码的正确性,测试用例包含在testCases
模块中。 -
%matplotlib inline
: 这是一个Jupyter Notebook魔术命令,用于在Jupyter Notebook中显示Matplotlib图形。如果您不是在Jupyter Notebook中运行代码,可以忽略这一行。 -
plt.rcParams['figure.figsize'] = (7.0, 4.0)
: 设置Matplotlib图形的默认大小为7.0 x 4.0英寸。 -
plt.rcParams['image.interpolation'] = 'nearest'
: 设置Matplotlib图像的插值方式为最近邻插值,以确保图像在显示时不会模糊。 -
plt.rcParams['image.cmap'] = 'gray'
: 设置Matplotlib图像的默认颜色映射为灰度,通常用于显示灰度图像。
这段代码的主要作用是导入必要的库、模块和函数,为后续的代码准备环境。
##############################################
train_X, train_Y, test_X, test_Y = load_2D_dataset()
##############################################
这行代码调用了名为load_2D_dataset()
的函数,并将其返回的值分配给四个变量:train_X
、train_Y
、test_X
和test_Y
。这些变量是用于训练和测试模型的数据集。
具体来说,这个函数可能的作用是加载一个二维数据集,将其分为训练集和测试集,并返回四个数组,每个数组包含以下内容:
-
train_X
: 训练集的输入特征,通常是一个包含多个训练样本的矩阵,其中每行代表一个样本,每列代表一个特征。 -
train_Y
: 训练集的标签或输出,与train_X
中的样本一一对应,通常是一个包含标签值的向量或矩阵。 -
test_X
: 测试集的输入特征,与train_X
的结构相同,但包含不同的测试样本。 -
test_Y
: 测试集的标签或输出,与test_X
中的样本一一对应,通常是一个包含标签值的向量或矩阵。
这种数据集的加载通常用于机器学习任务,其中你需要将模型训练在训练集上,然后在测试集上评估模型的性能。
##############################################
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)
# 防止同时使用L2正则化和dropout。
# 其实是可以同时使用它们的,但是为了教学目的,突出重点,所以单次只允许用其中一个。
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))
if print_cost and i % 1000 == 0:
costs.append(cost)
plt.plot(costs)
plt.ylabel('cost')
plt.xlabel('iterations (x1,000)')
plt.title("Learning rate =" + str(learning_rate))
plt.show()
return parameters
##############################################
这段代码定义了一个用于构建深度神经网络模型的函数,函数名为 model
。
-
def model(X, Y, learning_rate=0.3, num_iterations=30000, print_cost=True, lambd=0, keep_prob=1):
: 这是一个函数定义,它接受以下参数:X
: 输入特征数据Y
: 输出标签数据learning_rate
: 学习率,用于控制参数更新的步长,默认值为0.3num_iterations
: 迭代次数,指定训练迭代的次数,默认为30000次print_cost
: 是否打印成本(损失)信息,默认为Truelambd
: 正则化超参数,默认为0(没有正则化)keep_prob
: dropout的概率,默认为1(没有dropout)
-
grads = {}
: 初始化一个空字典,用于存储梯度信息。 -
costs = []
: 初始化一个空列表,用于存储损失函数的值,以便后续可视化损失。 -
m = X.shape[1]
: 获取训练样本的数量,即X
的第二维的大小。 -
layers_dims = [X.shape[0], 20, 3, 1]
: 定义神经网络的层次结构,包括输入层、隐藏层1(20个神经元)、隐藏层2(3个神经元)和输出层(1个神经元)的维度。 -
parameters = initialize_parameters(layers_dims)
: 使用initialize_parameters
函数初始化神经网络的参数。 -
for i in range(0, num_iterations):
: 开始迭代训练模型,迭代次数由num_iterations
决定。 -
根据
keep_prob
和lambd
的值,选择相应的前向传播和计算损失的方式。如果keep_prob
等于1并且lambd
等于0,则使用普通的前向传播和损失计算方式,否则根据条件选择使用正则化或dropout。 -
根据
lambd
的值,选择相应的反向传播方式,同样根据条件选择使用正则化或dropout。 -
使用梯度下降法更新参数,更新方式由
update_parameters
函数实现。 -
如果
print_cost
为True,并且当前迭代次数是10000的倍数,打印当前损失值。 -
如果
print_cost
为True,并且当前迭代次数是1000的倍数,将当前损失值添加到costs
列表中,以便后续可视化。 -
最后,通过Matplotlib绘制损失函数随迭代次数变化的图形,以观察模型的训练过程。
-
返回训练好的参数。
这个函数的主要作用是训练深度神经网络模型,并支持正则化和dropout技术,以提高模型的泛化能力。
##############################################
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)
##############################################
这段代码用于训练神经网络模型并进行预测。
-
parameters = model(train_X, train_Y)
: 调用之前定义的model
函数来训练神经网络模型。train_X
是训练集的输入特征,train_Y
是训练集的标签。模型训练完成后,返回的parameters
包含了训练好的神经网络参数。 -
print("On the training set:")
: 打印以下信息,表示接下来要在训练集上进行预测。 -
predictions_train = predict(train_X, train_Y, parameters)
: 调用predict
函数来对训练集进行预测。train_X
是训练集的输入特征,train_Y
是训练集的真实标签,parameters
是之前训练得到的模型参数。函数返回的predictions_train
是模型对训练集的预测结果。 -
print("On the test set:")
: 打印以下信息,表示接下来要在测试集上进行预测。 -
predictions_test = predict(test_X, test_Y, parameters)
: 调用predict
函数来对测试集进行预测。test_X
是测试集的输入特征,test_Y
是测试集的真实标签,parameters
是之前训练得到的模型参数。函数返回的predictions_test
是模型对测试集的预测结果。
##############################################
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.ravel())
##############################################
这段代码用于绘制决策边界图,以可视化模型在训练数据上的表现。
-
plt.title("Model without regularization")
: 设置图的标题为 "Model without regularization",表示这是没有正则化的模型。 -
axes = plt.gca()
: 获取当前图的坐标轴。 -
axes.set_xlim([-0.75, 0.40])
: 设置x轴的坐标范围,限制在-0.75到0.40之间。 -
axes.set_ylim([-0.75, 0.65])
: 设置y轴的坐标范围,限制在-0.75到0.65之间。 -
plot_decision_boundary(lambda x: predict_dec(parameters, x.T), train_X, train_Y.ravel())
: 调用plot_decision_boundary
函数来绘制决策边界。这个函数接受三个参数:- 第一个参数是一个lambda函数,它使用训练好的模型参数
parameters
来对输入数据x.T
(转置后的训练数据)进行预测,从而得到决策边界。 - 第二个参数是训练集的输入特征
train_X
。 - 第三个参数是训练集的真实标签
train_Y
,使用ravel()
函数将其转换为一维数组。
- 第一个参数是一个lambda函数,它使用训练好的模型参数
这段代码的目的是在图上绘制模型的决策边界,以帮助可视化模型如何对训练数据进行分类。通过调整坐标轴范围和查看决策边界,您可以更好地了解模型的性能。
##############################################
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尾巴
L2_regularization_cost = lambd * (np.sum(np.square(W1)) + np.sum(np.square(W2)) + np.sum(np.square(W3))) / (2 * m)
cost = cross_entropy_cost + L2_regularization_cost
return cost
##############################################
这段代码定义了一个函数 compute_cost_with_regularization
,用于计算带有L2正则化的损失函数。
-
A3
: 是模型的输出,即最后一层的激活值,它代表模型对每个样本的预测概率。 -
Y
: 是训练集的真实标签。 -
parameters
: 是模型的参数,包括权重矩阵和偏置向量。 -
lambd
: 是L2正则化的超参数,控制正则化的强度。 -
m = Y.shape[1]
: 获取训练样本的数量,即Y
的第二维大小。 -
W1
,W2
, 和W3
:分别是神经网络的权重矩阵,这些权重矩阵包括了不同层次的权重参数。 -
cross_entropy_cost
: 调用compute_cost
函数计算交叉熵损失,这是常规的损失计算,衡量了模型的预测和真实标签之间的差异。 -
L2_regularization_cost
: 计算L2正则化的损失,这个损失是通过对所有权重矩阵的平方和进行缩放来计算的,它惩罚了权重的大小。 -
cost = cross_entropy_cost + L2_regularization_cost
: 将交叉熵损失和L2正则化损失相加,得到最终的损失值。 -
返回
cost
,即带有L2正则化的总损失。
这个函数的作用是计算带有L2正则化的损失,正则化有助于减少模型的过拟合问题,使模型更具泛化能力。
##############################################
# 单元测试
A3, Y_assess, parameters = compute_cost_with_regularization_test_case()
print("cost = " + str(compute_cost_with_regularization(A3, Y_assess, parameters, lambd = 0.1)))
##############################################
这段代码看起来是用于进行单元测试的代码,测试 compute_cost_with_regularization
函数的实现是否正确。
-
A3, Y_assess, parameters = compute_cost_with_regularization_test_case()
: 这一行调用了一个名为compute_cost_with_regularization_test_case
的测试用例函数,并将返回的值分配给三个变量:A3
: 模型的输出。Y_assess
: 真实标签。parameters
: 模型的参数。
-
compute_cost_with_regularization(A3, Y_assess, parameters, lambd = 0.1)
: 调用compute_cost_with_regularization
函数,传入上述获得的模型输出A3
、真实标签Y_assess
、模型参数parameters
和正则化超参数lambd
(这里设置为0.1)。函数将计算带有L2正则化的损失,并返回损失值。 -
print("cost = " + str(compute_cost_with_regularization(A3, Y_assess, parameters, lambd = 0.1)))
: 打印计算得到的带有L2正则化的损失值。
这段代码的主要目的是测试 compute_cost_with_regularization
函数是否正确地计算了带有L2正则化的损失。如果打印的损失值与预期结果一致,那么函数的实现是正确的。这是一种常见的测试方式,用于确保代码的准确性。
##############################################
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. / m * np.dot(dZ3, A2.T) + (lambd * W3) / m
db3 = 1. / m * np.sum(dZ3, axis=1, keepdims=True)
dA2 = np.dot(W3.T, dZ3)
dZ2 = np.multiply(dA2, np.int64(A2 > 0))
dW2 = 1. / m * np.dot(dZ2, A1.T) + (lambd * W2) / m
db2 = 1. / m * np.sum(dZ2, axis=1, keepdims=True)
dA1 = np.dot(W2.T, dZ2)
dZ1 = np.multiply(dA1, np.int64(A1 > 0))
dW1 = 1. / m * np.dot(dZ1, X.T) + (lambd * W1) / m
db1 = 1. / 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
##############################################
这段代码定义了一个名为 backward_propagation_with_regularization
的函数,用于计算带有L2正则化的梯度。
-
X, Y, cache, lambd
: 这个函数接受四个参数,分别是输入特征X
、真实标签Y
、缓存cache
(包含了前向传播过程中的一些中间值),以及正则化超参数lambd
,它控制正则化的强度。 -
m = X.shape[1]
: 获取训练样本的数量,即X
的第二维大小。 -
从缓存
cache
中获取前向传播过程中的中间值,包括:Z1
,A1
,W1
,b1
:第一个隐藏层的线性变换、激活值、权重和偏置。Z2
,A2
,W2
,b2
:第二个隐藏层的线性变换、激活值、权重和偏置。Z3
,A3
,W3
,b3
:输出层的线性变换、激活值、权重和偏置。
-
计算输出层的梯度
dZ3
,这是预测值A3
与真实标签Y
之间的差异。 -
计算权重矩阵
W3
的梯度dW3
,考虑了L2正则化的影响,通过添加(lambd * W3) / m
来惩罚权重的大小。 -
计算偏置
b3
的梯度db3
。 -
计算第二个隐藏层的梯度
dA2
,用于反向传播到第二个隐藏层。 -
计算第二个隐藏层的线性变换的梯度
dZ2
,同时通过乘以np.int64(A2 > 0)
来考虑ReLU激活函数的导数。 -
计算权重矩阵
W2
的梯度dW2
,同样考虑了L2正则化的影响。 -
计算偏置
b2
的梯度db2
。 -
计算第一个隐藏层的梯度
dA1
,用于反向传播到第一个隐藏层。 -
计算第一个隐藏层的线性变换的梯度
dZ1
,同时通过乘以np.int64(A1 > 0)
来考虑ReLU激活函数的导数。 -
计算权重矩阵
W1
的梯度dW1
,同样考虑了L2正则化的影响。 -
计算偏置
b1
的梯度db1
。 -
将所有梯度存储在字典
gradients
中,以便后续的参数更新。 -
返回包含所有梯度的
gradients
字典。
这个函数的作用是计算带有L2正则化的梯度,正则化有助于减少模型的过拟合问题,使模型更具泛化能力。
##############################################
这段代码用于进行单元测试,测试 backward_propagation_with_regularization
函数的实现是否正确。
-
X_assess, Y_assess, cache = backward_propagation_with_regularization_test_case()
: 这一行调用了一个名为backward_propagation_with_regularization_test_case
的测试用例函数,并将返回的值分配给三个变量:X_assess
: 用于测试的输入特征。Y_assess
: 用于测试的真实标签。cache
: 包含了前向传播过程中的中间值,用于后续的反向传播。
-
grads = backward_propagation_with_regularization(X_assess, Y_assess, cache, lambd=0.7)
: 调用backward_propagation_with_regularization
函数,传入测试用的输入特征X_assess
、真实标签Y_assess
、缓存cache
和正则化超参数lambd
(这里设置为0.7)。函数将计算带有L2正则化的梯度,并返回梯度信息。 -
print ("dW1 = " + str(grads["dW1"]))
: 打印第一层权重矩阵W1
的梯度信息。 -
print ("dW2 = " + str(grads["dW2"]))
: 打印第二层权重矩阵W2
的梯度信息。 -
print ("dW3 = " + str(grads["dW3"]))
: 打印输出层权重矩阵W3
的梯度信息。
这段代码的目的是测试 backward_propagation_with_regularization
函数是否正确地计算了带有L2正则化的梯度。如果打印的梯度信息与预期结果一致,那么函数的实现是正确的。这是一种常见的测试方式,用于确保代码的准确性。
##############################################
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)
##############################################
这段代码使用带有L2正则化的模型进行训练和预测。
-
parameters = model(train_X, train_Y, lambd=0.7)
: 调用model
函数,传入训练集的输入特征train_X
和标签train_Y
,以及正则化超参数lambd
(这里设置为0.7)。函数将训练带有L2正则化的神经网络模型,并返回训练好的参数parameters
。 -
print("On the train set:")
: 打印以下信息,表示接下来要在训练集上进行预测。 -
predictions_train = predict(train_X, train_Y, parameters)
: 调用predict
函数来对训练集进行预测。train_X
是训练集的输入特征,train_Y
是训练集的真实标签,parameters
是之前训练得到的模型参数。函数返回的predictions_train
是模型对训练集的预测结果。 -
print("On the test set:")
: 打印以下信息,表示接下来要在测试集上进行预测。 -
predictions_test = predict(test_X, test_Y, parameters)
: 调用predict
函数来对测试集进行预测。test_X
是测试集的输入特征,test_Y
是测试集的真实标签,parameters
是之前训练得到的模型参数。函数返回的predictions_test
是模型对测试集的预测结果。
通过这些步骤,您使用带有L2正则化的模型对训练集和测试集进行了预测。您可以进一步分析预测结果以评估模型的性能和泛化能力。
##############################################
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.ravel())
##############################################
这段代码用于绘制带有L2正则化的模型的决策边界图,以可视化模型在训练数据上的表现。
-
plt.title("Model with L2-regularization")
: 设置图的标题为 "Model with L2-regularization",表示这是带有L2正则化的模型。 -
axes = plt.gca()
: 获取当前图的坐标轴。 -
axes.set_xlim([-0.75, 0.40])
: 设置x轴的坐标范围,限制在-0.75到0.40之间。 -
axes.set_ylim([-0.75, 0.65])
: 设置y轴的坐标范围,限制在-0.75到0.65之间。 -
plot_decision_boundary(lambda x: predict_dec(parameters, x.T), train_X, train_Y.ravel())
: 调用plot_decision_boundary
函数来绘制带有L2正则化的模型的决策边界。这个函数接受三个参数:- 第一个参数是一个lambda函数,它使用训练好的模型参数
parameters
来对输入数据x.T
(转置后的训练数据)进行预测,从而得到决策边界。 - 第二个参数是训练集的输入特征
train_X
。 - 第三个参数是训练集的真实标签
train_Y
,使用ravel()
函数将其转换为一维数组。
- 第一个参数是一个lambda函数,它使用训练好的模型参数
这段代码的目的是在图上绘制带有L2正则化的模型的决策边界,以帮助可视化模型如何对训练数据进行分类。通过调整坐标轴范围和查看决策边界,您可以更好地了解带有L2正则化的模型的性能。
##############################################
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
##############################################
这段代码定义了一个名为 forward_propagation_with_dropout
的函数,用于实现带有Dropout的前向传播过程。
-
X, parameters, keep_prob=0.5
: 这个函数接受三个参数,分别是输入特征X
、模型参数parameters
,以及keep_prob
,它是Dropout的概率(默认为0.5,即保留50%的神经元)。 -
np.random.seed(1)
: 设置随机种子,以确保每次运行时生成的随机数相同,以便复现结果。 -
从模型参数
parameters
中获取各层的权重矩阵W
和偏置向量b
。 -
计算第一层的线性变换
Z1
和激活值A1
(使用ReLU激活函数)。 -
Dropout的实现包括四个步骤:
- 第一步:生成一个与
A1
维度相同的随机矩阵D1
,其中的元素是从均匀分布[0, 1)中随机抽取的值。 - 第二步:将
D1
中的元素与keep_prob
比较,生成一个与A1
维度相同的布尔矩阵D1
,其中元素值为True
的比例约为keep_prob
。 - 第三步:将
A1
与D1
相乘,将一部分神经元的输出设置为0,实现了Dropout。 - 第四步:为了保持激活值的期望不变,对
A1
进行缩放,将除以keep_prob
。
- 第一步:生成一个与
-
计算第二层的线性变换
Z2
和激活值A2
,同样应用了Dropout。 -
计算第三层(输出层)的线性变换
Z3
和激活值A3
,这一层使用了Sigmoid激活函数。 -
将计算过程中的中间值存储在
cache
变量中,以便后续的反向传播过程使用。 -
返回输出值
A3
和cache
。
这个函数的主要作用是在前向传播过程中实现Dropout,以减少神经网络的过拟合问题,提高模型的泛化能力。
##############################################
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))
##############################################
这段代码用于对带有Dropout的前向传播过程进行单元测试,测试 forward_propagation_with_dropout
函数的实现是否正确。
-
X_assess, parameters = forward_propagation_with_dropout_test_case()
: 这一行调用了一个名为forward_propagation_with_dropout_test_case
的测试用例函数,并将返回的值分配给两个变量:X_assess
: 用于测试的输入特征。parameters
: 模型的参数。
-
A3, cache = forward_propagation_with_dropout(X_assess, parameters, keep_prob=0.7)
: 调用forward_propagation_with_dropout
函数,传入测试用的输入特征X_assess
、模型参数parameters
,以及Dropout概率keep_prob
(这里设置为0.7)。函数将执行带有Dropout的前向传播过程,计算输出值A3
和缓存cache
。 -
print ("A3 = " + str(A3))
: 打印输出值A3
,即带有Dropout的前向传播的结果。
这段代码的目的是测试 forward_propagation_with_dropout
函数是否正确地实现了Dropout操作,并生成了带有Dropout的前向传播结果。如果打印的输出值与预期结果一致,那么函数的实现是正确的。这是一种常见的测试方式,用于确保代码的准确性。
##############################################
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. / m * np.dot(dZ3, A2.T)
db3 = 1. / 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. / m * np.dot(dZ2, A1.T)
db2 = 1. / 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. / m * np.dot(dZ1, X.T)
db1 = 1. / 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
##############################################
这段代码定义了一个名为 backward_propagation_with_dropout
的函数,用于计算带有Dropout的反向传播梯度。
-
X, Y, cache, keep_prob
: 这个函数接受四个参数,分别是输入特征X
、真实标签Y
、缓存cache
(包含了前向传播过程中的一些中间值),以及Dropout的概率keep_prob
。 -
m = X.shape[1]
: 获取训练样本的数量,即X
的第二维大小。 -
从缓存
cache
中获取前向传播过程中的中间值,包括:Z1
,D1
,A1
,W1
,b1
:第一个隐藏层的线性变换、Dropout掩码、激活值、权重和偏置。Z2
,D2
,A2
,W2
,b2
:第二个隐藏层的线性变换、Dropout掩码、激活值、权重和偏置。Z3
,A3
,W3
,b3
:输出层的线性变换、激活值、权重和偏置。
-
计算输出层的梯度
dZ3
,这是预测值A3
与真实标签Y
之间的差异。 -
计算权重矩阵
W3
的梯度dW3
。 -
计算偏置
b3
的梯度db3
。 -
计算第二层的梯度
dA2
,用于反向传播到第二个隐藏层。 -
Dropout的反向传播包括两个步骤:
- 第一步:将
dA2
与D2
相乘,通过Dropout掩码将一部分神经元的梯度置为0。 - 第二步:为了保持梯度的期望不变,对
dA2
进行缩放,将其除以keep_prob
。
- 第一步:将
-
计算第二层的线性变换的梯度
dZ2
,同时通过乘以np.int64(A2 > 0)
来考虑ReLU激活函数的导数。 -
计算权重矩阵
W2
的梯度dW2
。 -
计算偏置
b2
的梯度db2
。 -
计算第一个隐藏层的梯度
dA1
,用于反向传播到第一个隐藏层。 -
Dropout的反向传播包括两个步骤,类似于第二层:
- 第一步:将
dA1
与D1
相乘,通过Dropout掩码将一部分神经元的梯度置为0。 - 第二步:为了保持梯度的期望不变,对
dA1
进行缩放,将其除以keep_prob
。
- 第一步:将
-
计算第一个隐藏层的线性变换的梯度
dZ1
,同时通过乘以np.int64(A1 > 0)
来考虑ReLU激活函数的导数。 -
计算权重矩阵
W1
的梯度dW1
。 -
计算偏置
b1
的梯度db1
。 -
将所有梯度存储在字典
gradients
中,以便后续的参数更新。 -
返回包含所有梯度的
gradients
字典。
这个函数的主要作用是计算带有Dropout的反向传播梯度,Dropout有助于减少模型的过拟合问题,提高模型的泛化能力。
##############################################
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的反向传播过程进行单元测试,测试 backward_propagation_with_dropout
函数的实现是否正确。
-
X_assess, Y_assess, cache = backward_propagation_with_dropout_test_case()
: 这一行调用了一个名为backward_propagation_with_dropout_test_case
的测试用例函数,并将返回的值分配给三个变量:X_assess
: 用于测试的输入特征。Y_assess
: 用于测试的真实标签。cache
: 包含了前向传播过程中的中间值,用于后续的反向传播。
-
gradients = backward_propagation_with_dropout(X_assess, Y_assess, cache, keep_prob=0.8)
: 调用backward_propagation_with_dropout
函数,传入测试用的输入特征X_assess
、真实标签Y_assess
、缓存cache
,以及Dropout的概率keep_prob
(这里设置为0.8)。函数将计算带有Dropout的反向传播梯度,并将梯度信息存储在gradients
字典中。 -
print ("dA1 = " + str(gradients["dA1"]))
: 打印第一个隐藏层的梯度dA1
。 -
print ("dA2 = " + str(gradients["dA2"]))
: 打印第二个隐藏层的梯度dA2
。
这段代码的目的是测试 backward_propagation_with_dropout
函数是否正确地计算了带有Dropout的反向传播梯度。如果打印的梯度信息与预期结果一致,那么函数的实现是正确的。这是一种常见的测试方式,用于确保代码的准确性。
##############################################
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的模型进行训练和预测
-
parameters = model(train_X, train_Y, keep_prob=0.86, learning_rate=0.3)
: 调用model
函数,传入训练集的输入特征train_X
和标签train_Y
,并指定了两个超参数:keep_prob=0.86
:这是Dropout的保留概率,表示在训练中保留每个神经元的概率为0.86。learning_rate=0.3
:学习率,用于控制参数更新的步长。这里设置为0.3。
函数将训练带有Dropout的神经网络模型,并返回训练好的参数
parameters
。 -
print("On the train set:")
: 打印以下信息,表示接下来要在训练集上进行预测。 -
predictions_train = predict(train_X, train_Y, parameters)
: 调用predict
函数来对训练集进行预测。train_X
是训练集的输入特征,train_Y
是训练集的真实标签,parameters
是之前训练得到的模型参数。函数返回的predictions_train
是模型对训练集的预测结果。 -
print("On the test set:")
: 打印以下信息,表示接下来要在测试集上进行预测。 -
predictions_test = predict(test_X, test_Y, parameters)
: 调用predict
函数来对测试集进行预测。test_X
是测试集的输入特征,test_Y
是测试集的真实标签,parameters
是之前训练得到的模型参数。函数返回的predictions_test
是模型对测试集的预测结果。
通过这些步骤,您使用带有Dropout的模型对训练集和测试集进行了预测。Dropout有助于减少过拟合问题,提高模型的泛化能力,尤其在训练数据较少时具有重要作用。您可以进一步分析预测结果以评估模型的性能和泛化能力。
##############################################
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.ravel())
##############################################
这段代码用于绘制带有Dropout的模型的决策边界图,以可视化模型在训练数据上的表现。
-
plt.title("Model with dropout")
: 设置图的标题为 "Model with dropout",表示这是带有Dropout的模型。 -
axes = plt.gca()
: 获取当前图的坐标轴。 -
axes.set_xlim([-0.75, 0.40])
: 设置x轴的坐标范围,限制在-0.75到0.40之间。 -
axes.set_ylim([-0.75, 0.65])
: 设置y轴的坐标范围,限制在-0.75到0.65之间。 -
plot_decision_boundary(lambda x: predict_dec(parameters, x.T), train_X, train_Y.ravel())
: 调用plot_decision_boundary
函数来绘制带有Dropout的模型的决策边界。这个函数接受三个参数:- 第一个参数是一个lambda函数,它使用训练好的模型参数
parameters
来对输入数据x.T
(转置后的训练数据)进行预测,从而得到决策边界。 - 第二个参数是训练集的输入特征
train_X
。 - 第三个参数是训练集的真实标签
train_Y
,使用ravel()
函数将其转换为一维数组。
- 第一个参数是一个lambda函数,它使用训练好的模型参数
这段代码的目的是在图上绘制带有Dropout的模型的决策边界,以帮助可视化模型如何对训练数据进行分类。通过调整坐标轴范围和查看决策边界,您可以更好地了解带有Dropout的模型的性能和泛化能力。
##############################################