2.浅层神经网络

发布时间 2023-08-31 16:16:24作者: 王哲MGG_AI

import numpy as np
import matplotlib.pyplot as plt
import sklearn 
import sklearn.datasets
import sklearn.linear_model

from planar_utils import plot_decision_boundary, sigmoid, load_planar_dataset, load_extra_datasets
from testCases import *

%matplotlib inline

np.random.seed(1) 

#################################################

  1. import numpy as np: 导入NumPy库,用于处理和执行数值计算。通常,它被重命名为np,以减少代码中的重复输入。

  2. import matplotlib.pyplot as plt: 导入Matplotlib库,用于绘制图表和可视化数据。通常,它被重命名为plt,以减少代码中的重复输入。

  3. import sklearn: 导入Scikit-Learn库,这是一个用于机器学习和数据分析的强大工具。

  4. import sklearn.datasets: 导入Scikit-Learn的datasets模块,用于加载一些内置的数据集。

  5. import sklearn.linear_model: 导入Scikit-Learn的linear_model模块,该模块包含线性模型的实现。

  6. from planar_utils import plot_decision_boundary, sigmoid, load_planar_dataset, load_extra_datasets: 从自定义模块planar_utils中导入一些函数和工具,包括绘制决策边界的函数、S型激活函数、加载平面数据集的函数以及加载额外数据集的函数。

  7. from testCases import *: 从testCases模块导入所有内容。这通常用于加载测试用例,以确保代码的正确性。

  8. %matplotlib inline: 这是一个Jupyter Notebook的魔法命令,它告诉Jupyter在notebook中直接显示Matplotlib图形,而不是将它们保存到文件中。

  9. np.random.seed(1): 设置NumPy的随机种子为1。这将确保在代码中使用随机数生成器时,得到的随机数是可重现的,即多次运行代码时生成的随机数相同

#################################################

X, Y = load_planar_dataset()

plt.scatter(X[0, :], X[1, :],c=Y.ravel(), s=40, cmap=plt.cm.Spectral)

#################################################

这部分代码执行了以下操作:

  1. X, Y = load_planar_dataset(): 这行代码调用了之前从planar_utils模块导入的load_planar_dataset函数,用于加载一个平面数据集。数据集被加载到两个变量中,XYX包含了数据点的特征,Y包含了每个数据点的标签(0或1)。

  2. plt.scatter(X[0, :], X[1, :], c=Y.ravel(), s=40, cmap=plt.cm.Spectral): 这行代码使用Matplotlib库绘制散点图,将数据集的数据点可视化出来。具体来说:

    • X[0, :]X[1, :] 表示数据集中所有数据点的 x 和 y 坐标。
    • c=Y.ravel() 指定了每个数据点的颜色,Y.ravel()Y 的二维数组转换为一维数组,以便与散点的颜色对应。在这个数据集中,Y 的值是0或1,通常用颜色来表示不同的类别。
    • s=40 指定了散点的大小为40。
    • cmap=plt.cm.Spectral 指定了使用"Spectral"颜色地图来着色散点,这是一种在可视化中常用的颜色映射。

这段代码的结果是绘制了一个散点图,其中的数据点以不同的颜色表示,每种颜色对应一个类别(0或1),并且数据点的位置由 X[0, :]X[1, :] 定义。

#################################################

shape_X = X.shape 
shape_Y = Y.shape 
m = Y.shape[1]

print ('X的维度是: ' + str(shape_X))
print ('Y的维度: ' + str(shape_Y))
print ('训练样本的个数是:' + str(m))

#################################################

这部分代码执行了以下操作:

  1. shape_X = X.shape: 这行代码计算了数组 X 的形状(维度)。X 包含了数据点的特征,通常是一个二维数组,其中每一列代表一个特征,每一行代表一个数据点。shape_X 将包含一个元组,其中第一个元素是行数,第二个元素是列数,这将提供有关数据集维度的信息。

  2. shape_Y = Y.shape: 同样,这行代码计算了数组 Y 的形状。Y 包含了数据点的标签,通常是一个一维数组,其中每个元素是一个标签。shape_Y 也将包含一个元组,其中第一个元素是行数,第二个元素是列数。在这种情况下,由于 Y 是一个行向量,它的形状将是 (1, 数据点个数)。

  3. m = Y.shape[1]: 这行代码计算了数据集中的样本数。由于 Y 是一个包含标签的数组,Y.shape[1] 返回的是 Y 的第二维的大小,即数据点的个数。

  4. 最后,print 语句用于打印出数据集 XY 的维度以及数据点的个数。

#################################################

clf = sklearn.linear_model.LogisticRegressionCV();

clf.fit(X.T, Y.T.ravel());

#################################################

这部分代码使用了Scikit-Learn库中的LogisticRegressionCV模型来训练一个逻辑回归模型。

  1. clf = sklearn.linear_model.LogisticRegressionCV(): 这行代码创建了一个名为clf的逻辑回归分类器对象。LogisticRegressionCV是Scikit-Learn中的一个类,它实现了逻辑回归模型,并且具有交叉验证功能,可以自动选择正则化参数。这可以帮助提高模型的性能。

  2. clf.fit(X.T, Y.T.ravel()): 这行代码使用训练数据来训练逻辑回归模型。具体来说:

    • X.TY.T分别表示输入特征矩阵X和标签向量Y的转置。逻辑回归模型通常期望特征矩阵的每一列表示一个特征,而每个样本位于行中,因此这里进行了转置。
    • .ravel()函数用于将Y的二维数组转换为一维数组,以确保输入的标签数据的形状与逻辑回归模型的期望形状相匹配。
    • clf.fit(...)用于将模型拟合到训练数据上,学习模型的参数,以使其能够进行二分类任务(在这种情况下,0或1)的预测。

一旦模型被训练,clf对象就包含了已经学习到的逻辑回归模型的参数。您可以使用这个模型来进行预测,评估模型的性能,或者用于其他任务。

#################################################

LR_predictions = clf.predict(X.T)

print ('预测准确度是: %d ' % float((np.dot(Y, LR_predictions) + np.dot(1 - Y,1 - LR_predictions)) / float(Y.size) * 100) + '% ')

plot_decision_boundary(lambda x: clf.predict(x), X, Y.ravel())

#################################################

这部分代码执行了以下操作:

  1. LR_predictions = clf.predict(X.T): 这行代码使用已经训练好的逻辑回归模型 clf 对训练数据 X.T 进行预测,并将预测结果存储在 LR_predictions 变量中。这将包含每个数据点的二元分类预测结果(0或1)。

  2. print ('预测准确度是: %d ' % float((np.dot(Y, LR_predictions) + np.dot(1 - Y,1 - LR_predictions)) / float(Y.size) * 100) + '% '): 这行代码计算和打印出了逻辑回归模型的预测准确度。具体来说:

    • np.dot(Y, LR_predictions) 计算了正确分类的数据点的数量。Y 是实际标签,LR_predictions 是模型的预测结果。
    • np.dot(1 - Y, 1 - LR_predictions) 计算了错误分类的数据点的数量。
    • Y.size 计算了总的数据点数量。
    • 这些数量被用于计算准确度,并将结果以百分比的形式打印出来。
  3. plot_decision_boundary(lambda x: clf.predict(x), X, Y.ravel()): 这行代码调用了之前从 planar_utils 模块导入的 plot_decision_boundary 函数,用于绘制决策边界。这个函数接受一个用于进行预测的函数作为参数(在这里是 clf.predict(x)),然后绘制决策边界,将数据点分成不同的类别,并显示它们的分布。

这段代码的结果是打印出模型的预测准确度,并绘制出决策边界,以可视化地表示模型对数据的分类能力。

#################################################

def initialize_parameters(n_x, n_h, n_y):

np.random.seed(2)

W1 = np.random.randn(n_h, n_x) * 0.01

b1 = np.zeros(shape=(n_h, 1))

W2 = np.random.randn(n_y, n_h) * 0.01
b2 = np.zeros(shape=(n_y, 1))

parameters = {"W1": W1,
"b1": b1,
"W2": W2,
"b2": b2}
return parameters

#################################################

这段代码定义了一个函数 initialize_parameters,用于初始化神经网络的参数。

  1. def initialize_parameters(n_x, n_h, n_y):: 这是函数的定义行,它接受三个参数 n_xn_hn_y,它们分别代表输入层的大小、隐藏层的大小和输出层的大小。

  2. np.random.seed(2): 这行代码设置了随机种子,以确保每次运行程序时生成的随机数是一致的。这有助于使结果可重现。

  3. W1 = np.random.randn(n_h, n_x) * 0.01: 这行代码初始化了第一层的权重矩阵 W1。使用 np.random.randn 函数生成一个均值为0、标准差为1的随机数组成的矩阵,然后乘以0.01以缩小权重的范围。这是一种常见的权重初始化方法,有助于确保权重初始值不会太大,避免梯度爆炸的问题。

  4. b1 = np.zeros(shape=(n_h, 1)): 这行代码初始化了第一层的偏差(偏置)矩阵 b1,它是一个大小为 (n_h, 1) 的全零列向量。

  5. W2 = np.random.randn(n_y, n_h) * 0.01: 这行代码初始化了第二层(输出层)的权重矩阵 W2,使用了与初始化 W1 相同的方法。

  6. b2 = np.zeros(shape=(n_y, 1)): 这行代码初始化了第二层的偏差(偏置)矩阵 b2,它是一个大小为 (n_y, 1) 的全零列向量。

  7. 最后,这个函数将初始化的参数以字典的形式存储在 parameters 变量中,并返回 parameters

这个函数的作用是为神经网络的每一层(输入层、隐藏层和输出层)初始化权重和偏差,以便开始训练神经网络。这些初始化参数是神经网络训练的起点。

#################################################

n_x, n_h, n_y = initialize_parameters_test_case()

parameters = initialize_parameters(n_x, n_h, n_y)
print("W1 = " + str(parameters["W1"]))
print("b1 = " + str(parameters["b1"]))
print("W2 = " + str(parameters["W2"]))
print("b2 = " + str(parameters["b2"]))

print("--------------------------------------------")

print("nn dim(" + str(n_x) + "," + str(n_h) + "," + str(n_y) + ")");
print("W1 dim:" + str(parameters["W1"].shape))
print("b1 dim:" + str(parameters["b1"].shape))
print("W2 dim:" + str(parameters["W2"].shape))
print("b2 dim:" + str(parameters["b2"].shape))

#################################################

这部分代码执行了以下操作:

  1. n_x, n_h, n_y = initialize_parameters_test_case(): 这行代码从测试用例中获取了三个值 n_xn_hn_y,它们分别代表输入层的大小、隐藏层的大小和输出层的大小。这些值是用于初始化神经网络参数的。

  2. parameters = initialize_parameters(n_x, n_h, n_y): 这行代码调用了之前定义的 initialize_parameters 函数,使用 n_xn_hn_y 来初始化神经网络的参数,并将初始化后的参数存储在 parameters 字典中。

  3. print("W1 = " + str(parameters["W1"])): 这一系列的 print 语句用于打印出初始化后的参数值,包括权重矩阵 W1、偏差 b1、权重矩阵 W2 和偏差 b2

  4. print("--------------------------------------------"): 这行代码用于在输出中添加一个分隔线,以便更清晰地区分不同的输出部分。

  5. print("nn dim(" + str(n_x) + "," + str(n_h) + "," + str(n_y) + ")");: 这行代码打印出神经网络的维度信息,即输入层、隐藏层和输出层的大小。

  6. 最后,这一系列 print 语句分别打印出每个参数的维度信息,以确保它们与期望的维度相匹配。

这段代码的主要目的是验证参数初始化函数是否按预期工作,并确保参数的维度正确。

#################################################

def forward_propagation(X, parameters):

m = X.shape[1] 
print("样本数:" + str(m))

W1 = parameters['W1']
b1 = parameters['b1']
W2 = parameters['W2']
b2 = parameters['b2']

Z1 = np.dot(W1, X) + b1
A1 = np.tanh(Z1) 
Z2 = np.dot(W2, A1) + b2
A2 = sigmoid(Z2) 

cache = {"Z1": Z1,
"A1": A1,
"Z2": Z2,
"A2": A2}

return A2, cache

#################################################

这段代码定义了前向传播(Forward Propagation)函数 forward_propagation,用于计算神经网络的前向传播过程。

  1. def forward_propagation(X, parameters):: 这是函数的定义行,它接受输入数据 X 和神经网络的参数 parameters 作为输入。

  2. m = X.shape[1]: 这行代码计算了样本的数量,存储在变量 m 中。X.shape[1] 返回 X 矩阵的第二维度的大小,即样本数量。

  3. print("样本数:" + str(m)): 这行代码用于打印出样本的数量,以便在执行时查看。

  4. 接下来的代码块获取了神经网络的参数,包括权重矩阵 W1、偏差 b1、权重矩阵 W2 和偏差 b2,这些参数是从输入的 parameters 字典中获取的。

  5. Z1 = np.dot(W1, X) + b1: 这行代码计算了第一层的线性组合,即加权和,其中 np.dot(W1, X) 表示权重矩阵 W1 与输入数据 X 的点积,然后加上偏差 b1

  6. A1 = np.tanh(Z1): 这行代码对第一层的线性组合应用了双曲正切激活函数 tanh,得到激活值 A1

  7. Z2 = np.dot(W2, A1) + b2: 这行代码计算了第二层的线性组合,其中 np.dot(W2, A1) 表示权重矩阵 W2 与第一层的激活值 A1 的点积,然后加上偏差 b2

  8. A2 = sigmoid(Z2): 这行代码对第二层的线性组合应用了 S 型激活函数 sigmoid,得到输出层的激活值 A2,它表示神经网络的最终预测。

  9. 最后,函数返回输出层的激活值 A2 和一个包含中间计算结果的缓存字典 cache,这个缓存将在后续的反向传播中使用。

这个函数执行了一次完整的前向传播,从输入数据开始,通过网络的各个层,最终得到神经网络的预测输出。

#################################################

def compute_cost(A2, Y, parameters):

m = Y.shape[1]

logprobs = np.multiply(np.log(A2), Y) + np.multiply((1 - Y), np.log(1 - A2))
cost = - np.sum(logprobs) / m

return cost

#################################################

这段代码定义了计算神经网络成本函数(cost function)的函数 compute_cost,它用于计算神经网络的成本。

  1. def compute_cost(A2, Y, parameters):: 这是函数的定义行,它接受三个参数:A2 表示神经网络的输出(预测),Y 表示实际标签,以及神经网络的参数 parameters

  2. m = Y.shape[1]: 这行代码计算了样本的数量,存储在变量 m 中。Y.shape[1] 返回 Y 矩阵的第二维度的大小,即样本数量。

  3. logprobs = np.multiply(np.log(A2), Y) + np.multiply((1 - Y), np.log(1 - A2)): 这行代码计算了成本函数的一部分,即交叉熵损失(cross-entropy loss)。具体来说:

    • np.log(A2) 计算了神经网络输出 A2 中每个样本的对数概率。
    • np.log(1 - A2) 计算了神经网络输出的补集的对数概率。
    • np.multiply(..., ...) 执行逐元素的乘法,将对数概率与实际标签 Y 相乘,并将对数概率的补集与 (1 - Y) 相乘。
  4. cost = - np.sum(logprobs) / m: 这行代码计算了最终的成本。它将逐元素乘法的结果求和,然后取负数,最后除以样本数量 m,以计算平均成本。这是典型的二分类问题的成本函数,用于衡量预测值 A2 与实际标签 Y 之间的差异。

  5. 最后,函数返回计算得到的成本值 cost

这个函数的目的是为了评估神经网络的性能,通过计算预测值与实际标签之间的差异来衡量模型的准确性。

#################################################

A2, Y_assess, parameters = compute_cost_test_case()

print("cost = " + str(compute_cost(A2, Y_assess, parameters)))

#################################################

这段代码执行了以下操作:

  1. A2, Y_assess, parameters = compute_cost_test_case(): 这行代码从测试用例中获取了三个值,分别是神经网络的预测值 A2、实际标签 Y_assess,以及神经网络的参数 parameters。这些值将用于测试计算成本的函数 compute_cost

  2. compute_cost(A2, Y_assess, parameters): 这行代码调用了 compute_cost 函数,将预测值 A2、实际标签 Y_assess 和神经网络参数 parameters 作为输入,计算神经网络的成本。

  3. print("cost = " + str(compute_cost(A2, Y_assess, parameters))): 这行代码将计算得到的成本值打印出来,以评估神经网络的性能。成本值衡量了神经网络的预测与实际标签之间的差异,成本越低表示预测越准确。

这段代码的目的是验证 compute_cost 函数是否按预期工作,以及在给定一组测试数据后计算出的成本是否合理

#################################################

def backward_propagation(parameters, cache, X, Y):
m = X.shape[1] 

W1 = parameters['W1']
W2 = parameters['W2']

A1 = cache['A1']
A2 = cache['A2']

dZ2= A2 - Y
dW2 = (1 / m) * np.dot(dZ2, A1.T)
db2 = (1 / m) * np.sum(dZ2, axis=1, keepdims=True)
dZ1 = np.multiply(np.dot(W2.T, dZ2), 1 - np.power(A1, 2))
dW1 = (1 / m) * np.dot(dZ1, X.T)
db1 = (1 / m) * np.sum(dZ1, axis=1, keepdims=True)

print("W1 dim:" + str(W1.shape))
print("W2 dim:" + str(W2.shape))
print("------------------------------")

print("dZ2 dim:" + str(dZ2.shape))
print("dZ1 dim:" + str(dZ1.shape))
print("------------------------------")

grads = {"dW1": dW1,
"db1": db1,
"dW2": dW2,
"db2": db2}

return grads 

#################################################

这段代码定义了反向传播(Backward Propagation)函数 backward_propagation,用于计算神经网络的梯度。

  1. def backward_propagation(parameters, cache, X, Y):: 这是函数的定义行,它接受四个参数:parameters 包含了神经网络的参数,cache 包含了前向传播过程中的中间计算结果,X 是输入数据,Y 是实际标签。

  2. m = X.shape[1]: 这行代码计算了样本的数量,存储在变量 m 中。X.shape[1] 返回 X 矩阵的第二维度的大小,即样本数量。

  3. 接下来的代码块获取了神经网络的参数,包括权重矩阵 W1W2,以及前向传播过程中计算得到的激活值 A1A2

  4. dZ2= A2 - Y: 这行代码计算了输出层的激活值 A2 与实际标签 Y 之间的差异,存储在 dZ2 中。

  5. dW2 = (1 / m) * np.dot(dZ2, A1.T): 这行代码计算了输出层权重矩阵 W2 的梯度,用于更新参数。dW2 是通过将 dZ2A1 的转置相乘,然后除以样本数量得到的。

  6. db2 = (1 / m) * np.sum(dZ2, axis=1, keepdims=True): 这行代码计算了输出层偏差 b2 的梯度,也用于参数更新。它是将 dZ2 按列求和,并除以样本数量得到的。

  7. dZ1 = np.multiply(np.dot(W2.T, dZ2), 1 - np.power(A1, 2)): 这行代码计算了隐藏层的激活值 A1 的梯度 dZ1。它使用了链式法则,通过将输出层的梯度 dZ2 与权重矩阵 W2 相乘,然后乘以 (1 - np.power(A1, 2)),其中 (1 - np.power(A1, 2)) 是双曲正切激活函数的导数。

  8. dW1 = (1 / m) * np.dot(dZ1, X.T): 这行代码计算了隐藏层权重矩阵 W1 的梯度,用于参数更新。dW1 是通过将 dZ1 与输入数据 X 的转置相乘,然后除以样本数量得到的。

  9. db1 = (1 / m) * np.sum(dZ1, axis=1, keepdims=True): 这行代码计算了隐藏层偏差 b1 的梯度,也用于参数更新。它是将 dZ1 按列求和,并除以样本数量得到的。

  10. grads = {"dW1": dW1, "db1": db1, "dW2": dW2, "db2": db2}: 这行代码将计算得到的梯度存储在一个字典 grads 中,以便后续的参数更新步骤使用。

  11. 最后,函数返回梯度字典 grads,这些梯度将用于更新神经网络的参数。

这个函数的作用是计算神经网络中各个参数的梯度,以便在训练过程中使用梯度下降或其他优化算法来更新参数,从而不断优化神经网络的性能。

#################################################

parameters, cache, X_assess, Y_assess = backward_propagation_test_case()

grads = backward_propagation(parameters, cache, X_assess, Y_assess)

print("dW1 dim:" + str(grads["dW1"].shape))
print("db1 dim:" + str(grads["db1"].shape))
print("dW2 dim:" + str(grads["dW2"].shape))
print("db2 dim:" + str(grads["db2"].shape))
print("------------------------------")

print ("dW1 = "+ str(grads["dW1"]))
print ("db1 = "+ str(grads["db1"]))
print ("dW2 = "+ str(grads["dW2"]))
print ("db2 = "+ str(grads["db2"]))

#################################################

def update_parameters(parameters, grads, learning_rate=1.2):

W1 = parameters['W1']
b1 = parameters['b1']
W2 = parameters['W2']
b2 = parameters['b2']

dW1 = grads['dW1']
db1 = grads['db1']
dW2 = grads['dW2']
db2 = grads['db2']

W1 = W1 - learning_rate * dW1
b1 = b1 - learning_rate * db1
W2 = W2 - learning_rate * dW2
b2 = b2 - learning_rate * db2

parameters = {"W1": W1,
"b1": b1,
"W2": W2,
"b2": b2}

return parameters

#################################################

这段代码定义了更新神经网络参数的函数 update_parameters,它使用梯度下降算法来更新神经网络的参数。

  1. def update_parameters(parameters, grads, learning_rate=1.2):: 这是函数的定义行,它接受三个参数:parameters 包含了神经网络的参数,grads 包含了参数的梯度,learning_rate 是学习率,它控制了参数更新的步长,默认值为1.2。

  2. 接下来的代码块获取了神经网络的参数,包括权重矩阵 W1W2,以及偏差 b1b2,同时也获取了参数的梯度,包括 dW1db1dW2db2

  3. W1 = W1 - learning_rate * dW1: 这行代码使用梯度下降算法来更新权重矩阵 W1。新的 W1 值等于旧的 W1 减去学习率乘以 dW1,这将使权重朝着减小成本的方向更新。

  4. b1 = b1 - learning_rate * db1: 同样,这行代码使用梯度下降来更新偏差 b1

  5. W2 = W2 - learning_rate * dW2: 这行代码使用梯度下降来更新权重矩阵 W2

  6. b2 = b2 - learning_rate * db2: 同样,这行代码使用梯度下降来更新偏差 b2

  7. 最后,函数将更新后的参数以字典的形式存储在 parameters 变量中,并返回 parameters

这个函数的作用是在训练过程中根据梯度信息更新神经网络的参数,以不断减小成本并提高模型性能。学习率 learning_rate 决定了每一次参数更新的步长,它是一个重要的超参数,需要进行调整以获得最佳的训练效果。

#################################################

# 单元测试
parameters, grads = update_parameters_test_case()
parameters = update_parameters(parameters, grads)

print("W1 = " + str(parameters["W1"]))
print("b1 = " + str(parameters["b1"]))
print("W2 = " + str(parameters["W2"]))
print("b2 = " + str(parameters["b2"]))

#################################################

这段代码执行了以下操作:

  1. parameters, grads = update_parameters_test_case(): 这行代码从测试用例中获取了两个值,分别是神经网络的参数 parameters 和参数的梯度 grads。这些值将用于测试参数更新函数 update_parameters

  2. parameters = update_parameters(parameters, grads): 这行代码调用了 update_parameters 函数,传入参数和梯度,执行参数的更新操作。新的参数存储在 parameters 变量中。

  3. 接下来的一系列 print 语句用于打印更新后的参数 parameters,包括权重矩阵 W1、偏差 b1、权重矩阵 W2 和偏差 b2 的值。

这段代码的目的是验证 update_parameters 函数是否按预期工作,以及参数是否正确更新。参数更新是深度学习训练过程中的关键步骤,它通过梯度下降来不断调整参数,以使成本函数最小化。

#################################################

def nn_model(X, Y, n_h, num_iterations=10000, print_cost=False):

np.random.seed(3)
n_x = X.shape[0] 
n_y = Y.shape[0] 

parameters = initialize_parameters(n_x, n_h, n_y)
W1 = parameters['W1']
b1 = parameters['b1']
W2 = parameters['W2']
b2 = parameters['b2']

for i in range(0, num_iterations):

A2, cache = forward_propagation(X, parameters)

cost = compute_cost(A2, Y, parameters)

grads = backward_propagation(parameters, cache, X, Y)

parameters = update_parameters(parameters, grads)

if print_cost and i % 1000 == 0:
print ("在训练%i次后,成本是: %f" % (i, cost))

return parameters

#################################################

这段代码定义了一个神经网络模型的训练函数 nn_model,用于训练一个两层的神经网络。让我逐行解释这个函数的功能:

  1. def nn_model(X, Y, n_h, num_iterations=10000, print_cost=False):: 这是函数的定义行,它接受输入数据 X、实际标签 Y、隐藏层的大小 n_h、迭代次数 num_iterations 和是否打印成本的标志 print_cost 作为参数。

  2. np.random.seed(3): 这行代码设置了随机种子,以确保每次运行程序时生成的随机数是一致的。这有助于使结果可重现。

  3. n_x = X.shape[0]n_y = Y.shape[0]:这两行代码分别获取输入特征的维度 n_x 和输出标签的维度 n_y

  4. parameters = initialize_parameters(n_x, n_h, n_y): 这行代码调用了之前定义的 initialize_parameters 函数,初始化神经网络的参数,并将参数存储在 parameters 字典中。

  5. 这个函数包含一个循环,迭代次数为 num_iterations,在每次迭代中执行以下步骤:

    • A2, cache = forward_propagation(X, parameters): 调用前向传播函数 forward_propagation,计算神经网络的预测值 A2 和缓存结果,缓存结果将在后续的反向传播中使用。
    • cost = compute_cost(A2, Y, parameters): 调用成本计算函数 compute_cost,计算当前预测值 A2 与实际标签 Y 之间的成本。
    • grads = backward_propagation(parameters, cache, X, Y): 调用反向传播函数 backward_propagation,计算参数的梯度。
    • parameters = update_parameters(parameters, grads): 调用参数更新函数 update_parameters,使用梯度下降来更新参数。
  6. 如果 print_costTrue 且迭代次数可以被1000整除,那么会打印出当前迭代次数和成本。

  7. 最后,函数返回训练完成后的参数 parameters

这个函数的作用是构建、训练和优化一个两层的神经网络模型。它包括前向传播、成本计算、反向传播和参数更新等步骤,通过多次迭代来不断调整参数,以最小化成本函数。

#################################################

# 单元测试
X_assess, Y_assess = nn_model_test_case()

parameters = nn_model(X_assess, Y_assess, 4, num_iterations=10000, print_cost=False)
print("W1 = " + str(parameters["W1"]))
print("b1 = " + str(parameters["b1"]))
print("W2 = " + str(parameters["W2"]))
print("b2 = " + str(parameters["b2"]))

#################################################

这段代码执行了以下操作:

  1. X_assess, Y_assess = nn_model_test_case(): 这行代码从测试用例中获取了输入数据 X_assess 和实际标签 Y_assess,这些数据将用于测试神经网络模型。

  2. parameters = nn_model(X_assess, Y_assess, 4, num_iterations=10000, print_cost=False): 这行代码调用了 nn_model 函数,传入输入数据 X_assess、实际标签 Y_assess,指定了隐藏层大小为4,迭代次数为10000,且不打印成本。该函数会训练一个神经网络模型,并返回训练后的参数 parameters

  3. 接下来的一系列 print 语句用于打印训练后的参数 parameters,包括权重矩阵 W1、偏差 b1、权重矩阵 W2 和偏差 b2 的值。

这段代码的目的是测试神经网络模型的训练过程,以及查看训练后的参数值。在这个测试中,您使用了测试用例的数据来训练模型。

#################################################

def predict(parameters, X):

A2, cache = forward_propagation(X, parameters)
predictions = np.round(A2)

return predictions

#################################################

这段代码定义了一个用于进行预测的函数 predict,它使用训练好的神经网络参数来进行预测。让我逐行解释这个函数的功能:

  1. def predict(parameters, X):: 这是函数的定义行,它接受两个参数:parameters 包含了训练好的神经网络参数,X 是待预测的输入数据。

  2. A2, cache = forward_propagation(X, parameters): 这行代码调用了前向传播函数 forward_propagation,使用输入数据 X 和训练好的参数 parameters 来计算神经网络的预测值 A2cache 变量包含了前向传播过程中的中间计算结果,但在这里没有使用。

  3. predictions = np.round(A2): 这行代码将预测值 A2 中的每个元素四舍五入到最接近的整数,得到二分类的预测结果。通常,如果 A2 大于等于0.5,预测结果会被四舍五入为1,否则会被四舍五入为0。

  4. 最后,函数返回包含预测结果的数组 predictions

这个函数的作用是使用训练好的神经网络来对输入数据进行预测,返回二分类的预测结果。这对于评估模型在新数据上的性能非常有用。

#################################################

parameters, X_assess = predict_test_case()

predictions = predict(parameters, X_assess)
print("predictions mean = " + str(np.mean(predictions)))

#################################################

这段代码执行了以下操作:

  1. parameters, X_assess = predict_test_case(): 这行代码从测试用例中获取了两个值,分别是训练好的神经网络参数 parameters 和用于测试的输入数据 X_assess

  2. predictions = predict(parameters, X_assess): 这行代码调用了 predict 函数,传入参数 parameters 和输入数据 X_assess,进行预测操作。函数返回的 predictions 是包含了预测结果的数组。

  3. print("predictions mean = " + str(np.mean(predictions))): 这行代码计算了预测结果 predictions 的平均值,以评估预测的准确性。如果模型的预测准确,那么平均值应该接近期望的标签分布(例如,如果有70%的正样本和30%的负样本,那么平均值应该接近0.7)。

这段代码的目的是测试 predict 函数,看看模型在测试数据上的平均预测值是否合理。

#################################################

 

parameters = nn_model(X, Y, n_h = 4, num_iterations=10000, print_cost=True)

predictions = predict(parameters, X)
print ('预测准确率是: %d' % float((np.dot(Y, predictions.T) + np.dot(1 - Y, 1 - predictions.T)) / float(Y.size) * 100) + '%')

plot_decision_boundary(lambda x: predict(parameters, x.T), X, Y.ravel())

#################################################

这段代码执行了以下操作:

  1. parameters = nn_model(X, Y, n_h=4, num_iterations=10000, print_cost=True): 这行代码调用了 nn_model 函数来训练一个神经网络模型。它传入输入数据 X、实际标签 Y,指定隐藏层大小为4,迭代次数为10000,并设置 print_cost=True 来打印训练过程中的成本。

  2. predictions = predict(parameters, X): 这行代码使用训练好的模型参数 parameters 对输入数据 X 进行预测,得到预测结果 predictions

  3. print ('预测准确率是: %d' % float((np.dot(Y, predictions.T) + np.dot(1 - Y, 1 - predictions.T)) / float(Y.size) * 100) + '%'): 这行代码计算并打印了模型的预测准确率。它将预测结果 predictions 与实际标签 Y 进行比较,计算准确率并打印出来。

  4. plot_decision_boundary(lambda x: predict(parameters, x.T), X, Y.ravel()): 这行代码用于绘制决策边界。它通过调用 plot_decision_boundary 函数,传入一个函数 lambda x: predict(parameters, x.T),这个函数用于根据输入 x 预测分类结果,并将结果与输入数据 X 和实际标签 Y 一起传递给 plot_decision_boundary 函数以绘制决策边界。

这段代码的目的是训练一个神经网络模型,评估其在训练数据上的预测准确率,并可视化决策边界,以便观察模型的分类效果。

#################################################

plt.figure(figsize=(16, 32))
hidden_layer_sizes = [1, 2, 3, 4, 5, 20, 50] 
for i, n_h in enumerate(hidden_layer_sizes):
plt.subplot(5, 2, i + 1)
plt.title('Hidden Layer of size %d' % n_h)
parameters = nn_model(X, Y, n_h, num_iterations=5000)
plot_decision_boundary(lambda x: predict(parameters, x.T), X, Y.ravel())
predictions = predict(parameters, X)
accuracy = float((np.dot(Y, predictions.T) + np.dot(1 - Y, 1 - predictions.T)) / float(Y.size) * 100)
print ("{}个隐藏层神经元时的准确度是: {} %".format(n_h, accuracy))

#################################################