3.深度神经网络识别猫
import numpy as np
import h5py
import matplotlib.pyplot as plt
from testCases import *
from dnn_utils import *
%matplotlib inline
plt.rcParams['figure.figsize'] = (5.0, 4.0)
plt.rcParams['image.interpolation'] = 'nearest'
plt.rcParams['image.cmap'] = 'gray'
np.random.seed(1)
##############################################
这段代码看起来是一个Python脚本,用于初始化一些库和设置绘图参数。
-
import numpy as np: 这里导入了NumPy库,并将其别名为np,以便在后续代码中使用更短的名称来引用NumPy函数和类。 -
import h5py: 这是导入HDF5文件处理库,通常用于读取和写入大型数据集。 -
import matplotlib.pyplot as plt: 这里导入了Matplotlib库,并将其别名为plt,以便在后续代码中使用更短的名称来创建和操作绘图。 -
from testCases import *: 这是从一个名为testCases的模块中导入了所有内容(使用星号*)。这可能是测试用例的一部分,用于测试某些函数或代码的正确性。 -
from dnn_utils import *: 类似地,这里从名为dnn_utils的模块中导入了所有内容。这可能包含与深度神经网络相关的实用函数。 -
%matplotlib inline: 这是一个Jupyter Notebook魔法命令,用于在Notebook中内联显示绘图。 -
plt.rcParams['figure.figsize'] = (5.0, 4.0): 这行代码设置Matplotlib的默认图形大小为宽度5.0和高度4.0。 -
plt.rcParams['image.interpolation'] = 'nearest': 这行代码设置Matplotlib图像的插值方式为“nearest”,这意味着在绘制图像时,使用最近邻插值以获得像素之间的连续性。 -
plt.rcParams['image.cmap'] = 'gray': 这行代码设置Matplotlib绘制图像时的颜色映射(colormap)为灰度,这意味着图像将以灰度色彩显示。 -
np.random.seed(1): 这里设置了随机数生成器的种子值为1,以确保在随机数生成过程中得到可重复的结果。这对于调试和验证模型的行为非常有用。
这段代码的主要目的是准备环境,导入所需的库和设置绘图参数,以便后续的深度学习代码可以正常运行。
##############################################
def initialize_parameters_deep(layer_dims):
np.random.seed(1)
parameters = {}
L = len(layer_dims)
for l in range(1, L):
parameters['W' + str(l)] = np.random.randn(layer_dims[l], layer_dims[l - 1]) / np.sqrt(layer_dims[l-1])
parameters['b' + str(l)] = np.zeros((layer_dims[l], 1))
assert(parameters['W' + str(l)].shape == (layer_dims[l], layer_dims[l - 1]))
assert(parameters['b' + str(l)].shape == (layer_dims[l], 1))
return parameters
##############################################
这段代码定义了一个函数 initialize_parameters_deep(layer_dims),用于初始化深度神经网络的参数。让我为您逐行解释这个函数的工作原理:
-
np.random.seed(1): 这行代码设置了随机数生成器的种子值为1,以确保在随机数生成过程中得到可重复的结果。 -
parameters = {}: 这里创建了一个空字典parameters,它将用于存储神经网络的权重矩阵和偏置向量。 -
L = len(layer_dims): 这里计算了神经网络的层数,layer_dims是一个包含每一层神经元数量的列表,它的长度就是网络的层数。 -
for l in range(1, L):: 这是一个循环,从第2层(索引1,因为Python中索引从0开始)开始遍历到最后一层。 -
parameters['W' + str(l)]: 在字典parameters中创建一个键,用于存储当前层的权重矩阵。'W' + str(l)创建了一个唯一的键,例如,'W1' 表示第一层的权重。 -
np.random.randn(layer_dims[l], layer_dims[l - 1]) / np.sqrt(layer_dims[l-1]): 这行代码使用均值为0、标准差为1的正态分布随机初始化权重矩阵,并通过np.sqrt(layer_dims[l-1])进行缩放以控制权重的范围。这是一种常用的权重初始化方法,有助于训练过程更稳定。 -
parameters['b' + str(l)]: 在字典parameters中创建一个键,用于存储当前层的偏置向量。'b' + str(l)创建了一个唯一的键,例如,'b1' 表示第一层的偏置。 -
np.zeros((layer_dims[l], 1)): 这行代码创建一个全零的偏置向量,其形状为(layer_dims[l], 1),这个形状与当前层的神经元数量匹配。 -
assert(parameters['W' + str(l)].shape == (layer_dims[l], layer_dims[l - 1]))和assert(parameters['b' + str(l)].shape == (layer_dims[l], 1)): 这两行代码是断言语句,用于检查初始化的权重矩阵和偏置向量的形状是否与预期的形状相匹配。如果不匹配,将引发错误。 -
最后,
return parameters: 函数返回初始化后的参数字典parameters,其中包含了神经网络的权重矩阵和偏置向量。
总之,这个函数的目的是初始化深度神经网络的参数,以便它们可以用于训练过程。
##############################################
parameters = initialize_parameters_deep([5,4,3])
print("W1 = " + str(parameters["W1"]))
print("b1 = " + str(parameters["b1"]))
print("W2 = " + str(parameters["W2"]))
print("b2 = " + str(parameters["b2"]))
##############################################
这段代码调用了之前定义的 initialize_parameters_deep 函数来初始化深度神经网络的参数,并打印了部分初始化后的参数值。
-
parameters = initialize_parameters_deep([5,4,3]): 这行代码调用了initialize_parameters_deep函数,传入一个包含[5, 4, 3]的列表作为参数。这个列表表示神经网络的结构,包含了3层,分别有5个输入神经元、4个隐藏层神经元和3个输出神经元。initialize_parameters_deep函数将返回一个包含初始化后的参数的字典,并将其赋值给变量parameters。 -
print("W1 = " + str(parameters["W1"])): 这行代码打印了第一层的权重矩阵W1的值。 -
print("b1 = " + str(parameters["b1"])): 这行代码打印了第一层的偏置向量b1的值。 -
print("W2 = " + str(parameters["W2"])): 这行代码打印了第二层的权重矩阵W2的值。 -
print("b2 = " + str(parameters["b2"])): 这行代码打印了第二层的偏置向量b2的值。
总之,这段代码的作用是初始化一个3层神经网络的参数,并打印出第一层和第二层的权重矩阵和偏置向量的值。
##############################################
def linear_forward(A, W, b):
Z = np.dot(W, A) + b
assert(Z.shape == (W.shape[0], A.shape[1]))
cache = (A, W, b)
return Z, cache
##############################################
这段代码定义了一个函数 linear_forward(A, W, b),用于执行神经网络的线性前向传播步骤。
-
Z = np.dot(W, A) + b: 这行代码计算线性变换的输出,其中A是输入矩阵,W是权重矩阵,b是偏置向量。这个计算通过矩阵乘法np.dot(W, A)来实现,然后加上偏置向量b。结果存储在变量Z中,表示当前层的线性输出。 -
assert(Z.shape == (W.shape[0], A.shape[1])): 这是一个断言语句,用于检查计算得到的Z的形状是否与预期的形状相匹配。具体来说,它检查Z的行数是否等于W的行数,以及Z的列数是否等于A的列数。这是为了确保矩阵维度匹配,以使后续计算能够正确进行。 -
cache = (A, W, b): 这行代码创建了一个元组cache,其中包含了输入矩阵A、权重矩阵W和偏置向量b。这个元组将用于后续的反向传播步骤,以保存这些值供后续使用。 -
return Z, cache: 函数返回线性变换的结果Z和存储在cache中的输入和参数信息。这些值将传递给后续的激活函数以完成神经网络的前向传播。
总之,这个函数的作用是计算神经网络中的线性前向传播步骤,将输入矩阵 A 通过权重矩阵 W 和偏置向量 b 进行线性变换,并返回结果 Z 和缓存信息 cache 以供后续使用。
##############################################
A, W, b = linear_forward_test_case()
Z, linear_cache = linear_forward(A, W, b)
print("Z = " + str(Z))
##############################################
这段代码执行了线性前向传播的测试。
-
A, W, b = linear_forward_test_case(): 这行代码调用了一个名为linear_forward_test_case()的测试用例函数,用于生成测试所需的输入矩阵A、权重矩阵W和偏置向量b。这些值将用于测试线性前向传播函数linear_forward。 -
Z, linear_cache = linear_forward(A, W, b): 这行代码调用了之前定义的linear_forward函数,传入输入矩阵A、权重矩阵W和偏置向量b,并执行线性前向传播。函数返回线性变换的结果Z和缓存信息linear_cache。 -
print("Z = " + str(Z)): 这行代码打印了线性变换的结果Z,以显示线性前向传播的输出。
总之,这段代码的目的是测试 linear_forward 函数,确保它能够正确计算线性变换的输出。
##############################################
def linear_activation_forward(A_prev, W, b, activation):
Z, linear_cache = linear_forward(A_prev, W, b)
if activation == "sigmoid":
A = sigmoid(Z)
elif activation == "relu":
A = relu(Z)
assert (A.shape == (W.shape[0], A_prev.shape[1]))
cache = (linear_cache, Z)
return A, cache
##############################################
这段代码定义了一个函数 linear_activation_forward(A_prev, W, b, activation),用于执行带有激活函数的前向传播步骤。
-
Z, linear_cache = linear_forward(A_prev, W, b): 这行代码调用了之前定义的linear_forward函数,传入输入矩阵A_prev、权重矩阵W和偏置向量b,执行线性前向传播。函数返回线性变换的结果Z和缓存信息linear_cache。 -
if activation == "sigmoid":: 这是一个条件语句,检查激活函数的类型。如果activation的值是"sigmoid",则执行以下代码块:A = sigmoid(Z): 这里调用了sigmoid函数,对线性变换的结果Z进行了 sigmoid 激活,得到激活后的输出A。
-
elif activation == "relu":: 如果激活函数的类型是"relu",则执行以下代码块:A = relu(Z): 这里调用了relu函数,对线性变换的结果Z进行了 ReLU 激活,得到激活后的输出A。
-
assert (A.shape == (W.shape[0], A_prev.shape[1])): 这是一个断言语句,用于检查激活后的输出A的形状是否与预期的形状相匹配。具体来说,它检查A的行数是否等于W的行数,以及列数是否等于A_prev的列数。这是为了确保矩阵维度匹配,以使后续计算能够正确进行。 -
cache = (linear_cache, Z): 最后,函数将缓存信息linear_cache和线性变换的结果Z存储在一个元组cache中,以供后续的反向传播步骤使用。 -
return A, cache: 函数返回激活后的输出A和缓存信息cache,这些值将传递给后续的层级以完成神经网络的前向传播。
总之,这个函数的作用是执行带有激活函数的前向传播步骤,根据指定的激活函数类型(sigmoid 或 relu)对线性变换的结果进行激活,并返回激活后的输出和缓存信息。
##############################################
A_prev, W, b = linear_activation_forward_test_case()
A, linear_activation_cache = linear_activation_forward(A_prev, W, b, activation = "sigmoid")
print("With sigmoid: A = " + str(A))
A, linear_activation_cache = linear_activation_forward(A_prev, W, b, activation = "relu")
print("With ReLU: A = " + str(A))
##############################################
这段代码执行了带有激活函数的前向传播的测试,一次使用 sigmoid 激活函数,一次使用 ReLU 激活函数。
-
A_prev, W, b = linear_activation_forward_test_case(): 这行代码调用了一个名为linear_activation_forward_test_case()的测试用例函数,用于生成测试所需的输入矩阵A_prev、权重矩阵W和偏置向量b。这些值将用于测试带有激活函数的前向传播函数linear_activation_forward。 -
A, linear_activation_cache = linear_activation_forward(A_prev, W, b, activation = "sigmoid"): 这行代码调用了linear_activation_forward函数,传入输入矩阵A_prev、权重矩阵W、偏置向量b以及激活函数的类型"sigmoid"。函数执行了线性前向传播,然后应用了 sigmoid 激活函数。它返回激活后的输出A和缓存信息linear_activation_cache。 -
print("With sigmoid: A = " + str(A)): 这行代码打印了使用 sigmoid 激活函数后的输出A。 -
A, linear_activation_cache = linear_activation_forward(A_prev, W, b, activation = "relu"): 这行代码再次调用linear_activation_forward函数,但这次传入了激活函数的类型"relu"。函数执行线性前向传播,然后应用 ReLU 激活函数。它返回激活后的输出A和缓存信息linear_activation_cache。 -
print("With ReLU: A = " + str(A)): 这行代码打印了使用 ReLU 激活函数后的输出A。
总之,这段代码的目的是测试 linear_activation_forward 函数,分别使用 sigmoid 和 ReLU 激活函数执行前向传播,并打印输出结果。这有助于确保该函数正确执行激活函数的操作。
##############################################
def L_model_forward(X, parameters):
caches = []
A = X
L = len(parameters) // 2
for l in range(1, L):
A_prev = A
A, cache = linear_activation_forward(A_prev,
parameters['W' + str(l)],
parameters['b' + str(l)],
activation='relu')
caches.append(cache)
AL, cache = linear_activation_forward(A,
parameters['W' + str(L)],
parameters['b' + str(L)],
activation='sigmoid')
caches.append(cache)
assert(AL.shape == (1, X.shape[1]))
return AL, caches
##############################################
这段代码定义了一个函数 L_model_forward(X, parameters),用于执行深度神经网络的前向传播。
-
caches = []: 这里创建一个空列表caches,用于存储每一层的缓存信息,缓存将在反向传播中使用。 -
A = X: 初始化输入数据A为X,其中X是神经网络的输入数据。 -
L = len(parameters) // 2: 计算神经网络的总层数L。parameters是一个字典,包含了神经网络的权重矩阵和偏置向量,通过计算字典长度的一半,可以得到神经网络的总层数。 -
for l in range(1, L):: 这是一个循环,从第1层遍历到倒数第二层(因为最后一层是 sigmoid 激活函数)。 -
A_prev = A: 将当前层的激活值A存储为上一层的激活值A_prev。 -
A, cache = linear_activation_forward(A_prev, parameters['W' + str(l)], parameters['b' + str(l)], activation='relu'): 这行代码调用了linear_activation_forward函数,执行当前层的线性前向传播并应用 ReLU 激活函数。A存储了当前层的激活值,而cache存储了当前层的缓存信息。然后,将该缓存信息cache添加到caches列表中。 -
AL, cache = linear_activation_forward(A, parameters['W' + str(L)], parameters['b' + str(L)], activation='sigmoid'): 这行代码执行神经网络的最后一层线性前向传播,并应用 sigmoid 激活函数。AL存储了神经网络的输出,而cache存储了最后一层的缓存信息,并将其添加到caches列表中。 -
assert(AL.shape == (1, X.shape[1])): 这是一个断言语句,用于检查神经网络的输出AL的形状是否与输入数据X的形状相匹配。具体来说,它检查输出的行数是否为1,列数是否与输入数据的列数相同。这是为了确保输出的形状正确。 -
return AL, caches: 函数返回神经网络的输出AL和存储了每一层缓存信息的列表caches。这些值将在反向传播中使用。
总之,这个函数的作用是执行深度神经网络的前向传播,遍历每一层,执行线性前向传播和激活函数,并将缓存信息存储在 caches 中。
##############################################
X, parameters = L_model_forward_test_case()
AL, caches = L_model_forward(X, parameters)
print("AL = " + str(AL))
print("Length of caches list = " + str(len(caches)))
##############################################
这段代码执行了深度神经网络的前向传播测试,并打印了神经网络的输出 AL 以及缓存列表 caches 的长度。
-
X, parameters = L_model_forward_test_case(): 这行代码调用了一个名为L_model_forward_test_case()的测试用例函数,用于生成测试所需的输入数据X和参数parameters。X是神经网络的输入数据,parameters包含了神经网络的权重矩阵和偏置向量。 -
AL, caches = L_model_forward(X, parameters): 这行代码调用了L_model_forward函数,传入输入数据X和参数parameters,执行深度神经网络的前向传播。函数返回神经网络的输出AL和存储了每一层缓存信息的列表caches。 -
print("AL = " + str(AL)): 这行代码打印了神经网络的输出AL,它是网络的最终输出。 -
print("Length of caches list = " + str(len(caches))): 这行代码打印了缓存列表caches的长度,即神经网络中层数的两倍。因为每一层都有一个缓存,而深度神经网络有 L 层,所以缓存列表的长度应为 2L。
总之,这段代码的目的是测试 L_model_forward 函数,执行深度神经网络的前向传播,计算网络的输出 AL,并检查缓存列表 caches 的长度。这有助于确保前向传播的正确性。
##############################################
def compute_cost(AL, Y):
m = Y.shape[1]
cost = (-1 / m) * np.sum(np.multiply(Y, np.log(AL)) + np.multiply(1 - Y, np.log(1 - AL)))
cost = np.squeeze(cost)
assert(cost.shape == ())
return cost
##############################################
这段代码定义了一个函数 compute_cost(AL, Y),用于计算神经网络的成本(损失)函数。
-
m = Y.shape[1]: 这行代码获取目标值Y的列数,其中m表示样本的数量。 -
cost = (-1 / m) * np.sum(np.multiply(Y, np.log(AL)) + np.multiply(1 - Y, np.log(1 - AL))): 这是成本函数的计算。它使用交叉熵损失函数来计算神经网络的成本。具体来说,它执行以下操作:np.multiply(Y, np.log(AL)):计算实际目标值Y与预测值AL的对数相乘。np.multiply(1 - Y, np.log(1 - AL)):计算实际目标值Y的补集与预测值AL的补集的对数相乘。np.sum(...):对上述两项进行求和。(-1 / m) * ...:将上述求和结果除以样本数量m,并取负值。
-
cost = np.squeeze(cost): 这行代码用于移除成本值cost的不必要的维度,以确保成本值是标量(一个单独的数值)。 -
assert(cost.shape == ()): 这是一个断言语句,用于检查成本值cost的形状是否为一个标量。如果形状不是标量,将引发错误。 -
return cost: 函数返回计算得到的成本值cost。
总之,这个函数的作用是计算神经网络的成本,使用交叉熵损失函数来衡量实际目标值 Y 与预测值 AL 之间的差异。
##############################################
Y, AL = compute_cost_test_case()
print("cost = " + str(compute_cost(AL, Y)))
##############################################
这段代码执行了成本函数的测试,并打印了计算得到的成本值 cost。
-
Y, AL = compute_cost_test_case(): 这行代码调用了一个名为compute_cost_test_case()的测试用例函数,用于生成测试所需的目标值Y和预测值AL。Y是实际目标值,AL是神经网络的预测值。 -
print("cost = " + str(compute_cost(AL, Y))): 这行代码调用了compute_cost函数,传入预测值AL和目标值Y,计算成本函数的值,并将其打印出来。
总之,这段代码的目的是测试 compute_cost 函数,计算神经网络的成本,并将成本值打印出来。
##############################################
def linear_backward(dZ, cache):
A_prev, W, b = cache
m = A_prev.shape[1]
dW = np.dot(dZ, cache[0].T) / m
db = np.sum(dZ, axis=1, keepdims=True) / m
dA_prev = np.dot(cache[1].T, dZ)
assert (dA_prev.shape == A_prev.shape)
assert (dW.shape == W.shape)
assert (db.shape == b.shape)
return dA_prev, dW, db
##############################################
这段代码定义了一个函数 linear_backward(dZ, cache),用于计算神经网络中某一层的反向传播梯度。
-
A_prev, W, b = cache: 这行代码从缓存cache中提取出上一层的激活值A_prev、权重矩阵W和偏置向量b,这些值是前向传播时存储的。 -
m = A_prev.shape[1]: 这行代码获取样本数量m,其中A_prev的列数表示样本数量。 -
dW = np.dot(dZ, cache[0].T) / m: 这行代码计算权重矩阵的梯度dW。具体来说,它执行以下操作:dZ是当前层的梯度。cache[0]是上一层的激活值A_prev,通过转置得到A_prev.T。np.dot(dZ, cache[0].T)执行矩阵乘法,计算了dW。- 最后,将结果除以样本数量
m,以求得平均梯度。
-
db = np.sum(dZ, axis=1, keepdims=True) / m: 这行代码计算偏置向量的梯度db。具体来说,它执行以下操作:dZ是当前层的梯度。np.sum(dZ, axis=1, keepdims=True)对dZ沿着列的方向进行求和,得到每个神经元的梯度总和。- 最后,将结果除以样本数量
m,以求得平均梯度,并使用keepdims=True保持结果的维度与b相同。
-
dA_prev = np.dot(cache[1].T, dZ): 这行代码计算上一层的激活值的梯度dA_prev。具体来说,它执行以下操作:cache[1]是当前层的权重矩阵W,通过转置得到W.T。np.dot(cache[1].T, dZ)执行矩阵乘法,计算了dA_prev。
-
assert (dA_prev.shape == A_prev.shape),assert (dW.shape == W.shape),assert (db.shape == b.shape): 这些是断言语句,用于检查计算得到的梯度的形状是否与相应的参数的形状相匹配。如果不匹配,将引发错误。 -
return dA_prev, dW, db: 函数返回上一层的激活值的梯度dA_prev、权重矩阵的梯度dW和偏置向量的梯度db,这些梯度将用于反向传播过程。
总之,这个函数的作用是根据当前层的梯度 dZ 和缓存信息 cache,计算上一层的梯度 dA_prev、权重矩阵的梯度 dW 和偏置向量的梯度 db,以进行反向传播。
##############################################
dZ, linear_cache = linear_backward_test_case()
dA_prev, dW, db = linear_backward(dZ, linear_cache)
print ("dA_prev = "+ str(dA_prev))
print ("dW = " + str(dW))
print ("db = " + str(db))
##############################################
这段代码执行了线性层的反向传播的测试,并打印了计算得到的梯度值 dA_prev、dW 和 db。
-
dZ, linear_cache = linear_backward_test_case(): 这行代码调用了一个名为linear_backward_test_case()的测试用例函数,用于生成测试所需的梯度dZ和缓存linear_cache。dZ是当前层的梯度,linear_cache包含了反向传播所需的信息,包括上一层的激活值A_prev、权重矩阵W和偏置向量b。 -
dA_prev, dW, db = linear_backward(dZ, linear_cache): 这行代码调用了linear_backward函数,传入梯度dZ和缓存信息linear_cache,执行线性层的反向传播。函数返回上一层的梯度dA_prev、权重矩阵的梯度dW和偏置向量的梯度db。 -
print ("dA_prev = "+ str(dA_prev)): 这行代码打印了上一层的梯度dA_prev,这是反向传播的输出,表示传递给前一层的梯度。 -
print ("dW = " + str(dW)): 这行代码打印了权重矩阵的梯度dW,表示该层权重的梯度。 -
print ("db = " + str(db)): 这行代码打印了偏置向量的梯度db,表示该层偏置的梯度。
总之,这段代码的目的是测试 linear_backward 函数,计算线性层的反向传播梯度,并打印梯度值。这有助于确保反向传播的计算是正确的。
##############################################
def linear_activation_backward(dA, cache, activation):
linear_cache, activation_cache = cache
if activation == "relu":
dZ = relu_backward(dA, activation_cache)
elif activation == "sigmoid":
dZ = sigmoid_backward(dA, activation_cache)
dA_prev, dW, db = linear_backward(dZ, linear_cache)
return dA_prev, dW, db
##############################################
这段代码定义了一个函数 linear_activation_backward(dA, cache, activation),用于计算带有激活函数的层级的反向传播梯度。
-
linear_cache, activation_cache = cache: 这行代码从传入的缓存cache中分离出线性层的缓存信息linear_cache和激活函数的缓存信息activation_cache。 -
if activation == "relu":: 这是一个条件语句,检查激活函数的类型。如果激活函数的类型是"relu",则执行以下代码块:dZ = relu_backward(dA, activation_cache): 这行代码调用了relu_backward函数,传入上一层的梯度dA和激活函数的缓存信息activation_cache,以计算当前层的梯度dZ。
-
elif activation == "sigmoid":: 如果激活函数的类型是"sigmoid",则执行以下代码块:dZ = sigmoid_backward(dA, activation_cache): 这行代码调用了sigmoid_backward函数,传入上一层的梯度dA和激活函数的缓存信息activation_cache,以计算当前层的梯度dZ。
-
dA_prev, dW, db = linear_backward(dZ, linear_cache): 这行代码调用了linear_backward函数,传入当前层的梯度dZ和线性层的缓存信息linear_cache,以计算上一层的激活值的梯度dA_prev、权重矩阵的梯度dW和偏置向量的梯度db。 -
return dA_prev, dW, db: 函数返回上一层的激活值的梯度dA_prev、权重矩阵的梯度dW和偏置向量的梯度db,这些梯度将用于继续进行反向传播。
总之,这个函数的作用是计算带有激活函数的层级的反向传播梯度,根据激活函数的类型选择不同的反向传播函数(如 relu 或 sigmoid),然后计算梯度。
##############################################
dAL, linear_activation_cache = linear_activation_backward_test_case()
dA_prev, dW, db = linear_activation_backward(dAL, linear_activation_cache, activation = "sigmoid")
print ("sigmoid:")
print ("dA_prev = "+ str(dA_prev))
print ("dW = " + str(dW))
print ("db = " + str(db) + "\n")
dA_prev, dW, db = linear_activation_backward(dAL, linear_activation_cache, activation = "relu")
print ("relu:")
print ("dA_prev = "+ str(dA_prev))
print ("dW = " + str(dW))
print ("db = " + str(db))
##############################################
这段代码执行了带有激活函数的层级的反向传播的测试,并打印了计算得到的梯度值 dA_prev、dW 和 db,分别使用了 sigmoid 和 relu 激活函数。
-
dAL, linear_activation_cache = linear_activation_backward_test_case(): 这行代码调用了一个名为linear_activation_backward_test_case()的测试用例函数,用于生成测试所需的上一层梯度dAL和缓存linear_activation_cache。dAL是当前层的梯度,linear_activation_cache包含了反向传播所需的信息,包括线性层和激活函数的缓存信息。 -
dA_prev, dW, db = linear_activation_backward(dAL, linear_activation_cache, activation = "sigmoid"): 这行代码调用了linear_activation_backward函数,传入当前层的梯度dAL、缓存信息linear_activation_cache和激活函数的类型"sigmoid"。函数计算了使用 sigmoid 激活函数时的上一层的激活值的梯度dA_prev、权重矩阵的梯度dW和偏置向量的梯度db。 -
print ("sigmoid:"): 这行代码打印了使用 sigmoid 激活函数时的输出标签,表示下面打印的是 sigmoid 激活函数的梯度值。 -
print ("dA_prev = "+ str(dA_prev)): 这行代码打印了上一层的激活值的梯度dA_prev,表示传递给前一层的梯度。 -
print ("dW = " + str(dW)): 这行代码打印了权重矩阵的梯度dW,表示该层权重的梯度。 -
print ("db = " + str(db) + "\n"): 这行代码打印了偏置向量的梯度db,表示该层偏置的梯度。\n用于在输出中添加一个空行。 -
同样的过程重复一次,但这次使用了 relu 激活函数。
总之,这段代码的目的是测试 linear_activation_backward 函数,分别使用 sigmoid 和 relu 激活函数计算带有激活函数的层级的反向传播梯度,并打印梯度值。
##############################################
def L_model_backward(AL, Y, caches):
grads = {}
L = len(caches)
Y = Y.reshape(AL.shape)
dAL = - (np.divide(Y, AL) - np.divide(1 - Y, 1 - AL))
current_cache = caches[-1]
grads["dA" + str(L-1)], grads["dW" + str(L)], grads["db" + str(L)] = linear_activation_backward(
dAL,
current_cache,
activation = "sigmoid")
for c in reversed(range(1,L)):
grads["dA" + str(c-1)], grads["dW" + str(c)], grads["db" + str(c)] = linear_activation_backward(
grads["dA" + str(c)],
caches[c-1],
activation = "relu")
return grads
##############################################
这段代码定义了一个函数 L_model_backward(AL, Y, caches),用于计算整个深度神经网络的反向传播梯度。
-
grads = {}: 这里创建一个空字典grads,用于存储每一层的梯度。 -
L = len(caches): 这行代码获取神经网络的总层数L,通过缓存列表caches的长度来确定。 -
Y = Y.reshape(AL.shape): 这行代码将目标值Y重塑为与预测值AL具有相同形状,以确保它们的维度匹配。 -
dAL = - (np.divide(Y, AL) - np.divide(1 - Y, 1 - AL)): 这行代码计算输出层的梯度dAL,使用交叉熵损失函数的导数计算方法。 -
current_cache = caches[-1]: 这行代码获取最后一层的缓存信息current_cache,以便后续计算输出层的梯度。 -
grads["dA" + str(L-1)], grads["dW" + str(L)], grads["db" + str(L)] = linear_activation_backward(dAL, current_cache, activation = "sigmoid"): 这行代码调用linear_activation_backward函数,计算输出层的梯度,并将结果存储在grads字典中。具体来说:grads["dA" + str(L-1)]存储上一层的激活值的梯度。grads["dW" + str(L)]存储输出层权重矩阵的梯度。grads["db" + str(L)]存储输出层偏置向量的梯度。
-
for c in reversed(range(1,L)):: 这是一个循环,从倒数第二层(第L-1层)向第1层(第1层是输入层,不必计算梯度)遍历每一层。 -
grads["dA" + str(c-1)], grads["dW" + str(c)], grads["db" + str(c)] = linear_activation_backward(grads["dA" + str(c)], caches[c-1], activation = "relu"): 这行代码调用linear_activation_backward函数,计算第c层的梯度,并将结果存储在grads字典中。具体来说:grads["dA" + str(c-1)]存储上一层的激活值的梯度。grads["dW" + str(c)]存储第c层的权重矩阵的梯度。grads["db" + str(c)]存储第c层的偏置向量的梯度。
-
最后,函数返回包含每一层梯度的
grads字典。
总之,这个函数的作用是计算整个深度神经网络的反向传播梯度,遍历每一层,依次计算梯度。
##############################################
AL, Y_assess, caches = L_model_backward_test_case()
grads = L_model_backward(AL, Y_assess, caches)
print ("dW1 = "+ str(grads["dW1"]))
print ("db1 = "+ str(grads["db1"]))
print ("dA1 = "+ str(grads["dA1"]))
##############################################
这段代码执行了深度神经网络的反向传播测试,并打印了第一层的权重梯度 dW1、偏置梯度 db1 和激活值梯度 dA1。
-
AL, Y_assess, caches = L_model_backward_test_case(): 这行代码调用了一个名为L_model_backward_test_case()的测试用例函数,用于生成测试所需的神经网络输出AL、目标值Y_assess和缓存列表caches。AL是神经网络的输出,Y_assess是实际目标值,caches包含了每一层的缓存信息。 -
grads = L_model_backward(AL, Y_assess, caches): 这行代码调用了L_model_backward函数,传入神经网络的输出AL、实际目标值Y_assess和缓存列表caches,执行整个深度神经网络的反向传播,计算梯度。结果存储在grads字典中。 -
print ("dW1 = "+ str(grads["dW1"])): 这行代码打印了第一层的权重矩阵的梯度dW1。 -
print ("db1 = "+ str(grads["db1"])): 这行代码打印了第一层的偏置向量的梯度db1。 -
print ("dA1 = "+ str(grads["dA1"])): 这行代码打印了第一层的激活值的梯度dA1。
总之,这段代码的目的是测试 L_model_backward 函数,执行深度神经网络的反向传播,计算每一层的梯度,并打印第一层的权重梯度 dW1、偏置梯度 db1 和激活值梯度 dA1。这有助于确保反向传播的计算是正确的。
##############################################
def update_parameters(parameters, grads, learning_rate):
L = len(parameters) // 2
for l in range(1,L+1):
parameters["W" + str(l)] = parameters["W" + str(l)] - learning_rate * grads["dW" + str(l)]
parameters["b" + str(l)] = parameters["b" + str(l)] - learning_rate * grads["db" + str(l)]
return parameters
##############################################
这段代码定义了一个函数 update_parameters(parameters, grads, learning_rate),用于更新神经网络的参数(权重和偏置)以进行梯度下降。
-
L = len(parameters) // 2: 这行代码计算神经网络的层数L,通过参数字典parameters中键的数量除以2。这是因为在parameters字典中,权重和偏置都以"W"和"b"为键,并且每一层都有一个"W"和一个"b"。 -
for l in range(1, L+1):: 这是一个循环,从第一层到最后一层遍历神经网络的所有层。 -
parameters["W" + str(l)] = parameters["W" + str(l)] - learning_rate * grads["dW" + str(l)]: 这行代码更新第l层的权重矩阵W,使用梯度下降的规则。具体来说,它从原始权重矩阵中减去学习率learning_rate乘以相应的权重梯度grads["dW" + str(l)]。 -
parameters["b" + str(l)] = parameters["b" + str(l)] - learning_rate * grads["db" + str(l)]: 这行代码更新第l层的偏置向量b,使用梯度下降的规则。它从原始偏置向量中减去学习率learning_rate乘以相应的偏置梯度grads["db" + str(l)]。 -
最后,函数返回更新后的参数字典
parameters,其中包含了更新后的权重和偏置。
总之,这个函数的作用是使用梯度下降算法来更新神经网络的参数,以便降低成本函数的值。
##############################################
parameters, grads = update_parameters_test_case()
parameters = update_parameters(parameters, grads, 0.1)
print ("W1 = " + str(parameters["W1"]))
print ("b1 = " + str(parameters["b1"]))
print ("W2 = " + str(parameters["W2"]))
print ("b2 = " + str(parameters["b2"]))
##############################################
这段代码执行了参数更新的测试,并打印了更新后的参数值。
-
parameters, grads = update_parameters_test_case(): 这行代码调用了一个名为update_parameters_test_case()的测试用例函数,用于生成测试所需的初始参数parameters和梯度grads。parameters包含了权重和偏置,grads包含了相应的梯度。 -
parameters = update_parameters(parameters, grads, 0.1): 这行代码调用了update_parameters函数,传入初始参数parameters、梯度grads,以及学习率0.1,执行参数的更新。函数返回更新后的参数parameters。 -
print ("W1 = " + str(parameters["W1"])): 这行代码打印了第一层的权重矩阵W1的更新后的值。 -
print ("b1 = " + str(parameters["b1"])): 这行代码打印了第一层的偏置向量b1的更新后的值。 -
print ("W2 = " + str(parameters["W2"])): 这行代码打印了第二层的权重矩阵W2的更新后的值。 -
print ("b2 = " + str(parameters["b2"])): 这行代码打印了第二层的偏置向量b2的更新后的值。
总之,这段代码的目的是测试 update_parameters 函数,执行参数更新,并打印更新后的参数值。这有助于确保参数更新的计算是正确的。
##############################################
train_x_orig, train_y, test_x_orig, test_y, classes = load_data()
m_train = train_x_orig.shape[0]
m_test = test_x_orig.shape[0]
num_px = test_x_orig.shape[1]
train_x_flatten = train_x_orig.reshape(train_x_orig.shape[0], -1).T
test_x_flatten = test_x_orig.reshape(test_x_orig.shape[0], -1).T
train_x = train_x_flatten/255.
test_x = test_x_flatten/255.
##############################################
这段代码执行了一些数据预处理操作,准备了训练集和测试集,以便用于深度神经网络的训练和测试。
-
train_x_orig, train_y, test_x_orig, test_y, classes = load_data(): 这行代码调用了一个名为load_data()的函数,从数据集中加载训练集和测试集,以及相关的类别信息。通常,train_x_orig和test_x_orig包含了原始图像数据,train_y和test_y包含了相应的标签,classes包含了类别名称。 -
m_train = train_x_orig.shape[0]和m_test = test_x_orig.shape[0]: 这两行代码分别计算了训练集和测试集的样本数量。train_x_orig.shape[0]给出了训练集的样本数,而test_x_orig.shape[0]给出了测试集的样本数。 -
num_px = test_x_orig.shape[1]: 这行代码计算了图像的像素尺寸。test_x_orig.shape[1]给出了测试集中每个图像的像素宽度(假设图像是正方形的)。 -
train_x_flatten = train_x_orig.reshape(train_x_orig.shape[0], -1).T和test_x_flatten = test_x_orig.reshape(test_x_orig.shape[0], -1).T: 这两行代码将训练集和测试集的图像数据从二维数组形式(图像索引,像素索引)转换为一维数组形式(像素索引,图像索引)。这个操作通常被称为“展平”操作,将每个图像的像素值排列成一列。 -
train_x = train_x_flatten/255.和test_x = test_x_flatten/255.: 这两行代码将图像的像素值归一化,将像素值除以 255。这将像素值缩放到范围 [0, 1] 之间,以便在神经网络中进行更好的训练。
总之,这段代码的目的是加载数据集,获取样本数量和图像尺寸,将图像数据展平,并对像素值进行归一化,以便用于训练深度神经网络。
##############################################
def dnn_model(X, Y, layers_dims, learning_rate=0.0075, num_iterations=3000, print_cost=False):
np.random.seed(1)
costs = []
parameters = initialize_parameters_deep(layers_dims)
for i in range(0, num_iterations):
AL, caches = L_model_forward(X, parameters)
cost = compute_cost(AL, Y)
grads = L_model_backward(AL, Y, caches)
parameters = update_parameters(parameters, grads, learning_rate)
if i % 100 == 0:
if print_cost and i > 0:
print ("训练%i次后成本是: %f" % (i, cost))
costs.append(cost)
plt.plot(np.squeeze(costs))
plt.ylabel('cost')
plt.xlabel('iterations (per tens)')
plt.title("Learning rate =" + str(learning_rate))
plt.show()
return parameters
##############################################
这段代码定义了一个深度神经网络的训练模型 dnn_model,它使用多个隐藏层进行前向传播、反向传播和参数更新,以便在训练数据上训练模型。
-
np.random.seed(1): 这行代码设置了随机数种子,以确保在每次运行模型时都生成相同的随机数,以便结果的可复现性。 -
costs = []: 这里创建一个空列表costs,用于存储每次迭代的成本值,以便后续绘制成本曲线。 -
parameters = initialize_parameters_deep(layers_dims): 这行代码调用了initialize_parameters_deep函数,根据神经网络的层数和每层的单元数量来初始化模型的参数(权重和偏置)。 -
进入迭代循环 (
for i in range(0, num_iterations):),在每次迭代中执行以下操作:a.
AL, caches = L_model_forward(X, parameters): 这行代码执行前向传播,计算模型的输出AL和缓存列表caches,其中AL是模型的预测输出,caches包含了每一层的缓存信息。b.
cost = compute_cost(AL, Y): 这行代码计算成本函数的值,将模型的预测输出AL与实际目标值Y进行比较。c.
grads = L_model_backward(AL, Y, caches): 这行代码执行反向传播,计算每一层的梯度。d.
parameters = update_parameters(parameters, grads, learning_rate): 这行代码使用梯度下降更新模型的参数。e. 如果迭代次数是100的倍数且
print_cost为真,则打印当前迭代次数和成本值。f. 将成本值
cost添加到costs列表中,以便后续绘制成本曲线。 -
最后,代码绘制了成本曲线,显示模型的学习进度。然后返回训练后的参数
parameters。
总之,这个函数的作用是训练深度神经网络模型,包括前向传播、反向传播和参数更新。
##############################################
layers_dims = [12288, 20, 7, 5, 1]
parameters = dnn_model(train_x, train_y, layers_dims, num_iterations=2000, print_cost=True)
##############################################
您正在使用定义的 dnn_model 函数来训练一个具有多个隐藏层的深度神经网络。
-
layers_dims = [12288, 20, 7, 5, 1]: 这是神经网络的架构,表示每个隐藏层的神经元数量。在这个架构中,输入层有12288个神经元,第一个隐藏层有20个,第二个隐藏层有7个,第三个隐藏层有5个,最后输出层有1个。这定义了神经网络的深度和宽度。 -
parameters = dnn_model(train_x, train_y, layers_dims, num_iterations=2000, print_cost=True): 这行代码调用了dnn_model函数,传入以下参数:train_x: 训练集的特征数据。train_y: 训练集的目标标签。layers_dims: 神经网络的架构。num_iterations=2000: 迭代次数,指定模型将在训练集上进行多少次迭代。print_cost=True: 控制是否在每100次迭代后打印成本值。
-
parameters: 这个变量将包含经过训练后的模型参数,包括权重和偏置。
总之,您正在使用指定的神经网络架构 layers_dims 对训练集进行深度神经网络的训练。训练会持续2000次迭代,同时会打印成本值以监测模型的训练进度。最终,parameters 变量将包含训练后的模型参数。如果您想了解训练的进度或其他细节,请查看成本曲线和训练日志。
##############################################
def predict(X,parameters):
m = X.shape[1]
n = len(parameters) // 2 # number of layers in the neural network
p = np.zeros((1,m))
probas, caches = L_model_forward(X, parameters)
for i in range(0, probas.shape[1]):
if probas[0,i] > 0.5:
p[0,i] = 1
else:
p[0,i] = 0
return p
##############################################
这段代码定义了一个用于进行预测的函数 predict(X, parameters)。它使用训练好的深度神经网络参数 parameters 来进行二分类预测。
-
m = X.shape[1]: 这行代码获取输入数据X中的样本数量m,即待预测的数据点个数。 -
n = len(parameters) // 2: 这行代码计算神经网络的层数n,通过参数字典parameters中键的数量除以2。这是因为在parameters字典中,权重和偏置都以"W"和"b"为键,并且每一层都有一个"W"和一个"b"。 -
p = np.zeros((1,m)): 这里创建一个全零数组p,用于存储预测结果,初始时将所有预测值设置为0。 -
probas, caches = L_model_forward(X, parameters): 这行代码执行前向传播,计算模型在输入数据X上的预测概率probas和缓存列表caches,其中probas包含每个样本的预测概率。 -
进入循环 (
for i in range(0, probas.shape[1]):),遍历每个样本的预测概率。 -
如果某个样本的预测概率
probas[0,i]大于0.5,则将p[0,i]设置为1,表示正类;否则,将p[0,i]设置为0,表示负类。这实现了二分类预测。 -
最后,函数返回包含预测结果的数组
p。
总之,这个函数的作用是使用训练好的深度神经网络参数来对输入数据进行二分类预测,并返回预测结果。
##############################################
pred_train = predict(train_x,parameters)
print("预测准确率是: " + str(np.sum((pred_train == train_y) / train_x.shape[1])))
##############################################
这段代码使用训练好的模型 parameters 对训练集 train_x 进行预测,并计算了预测的准确率。
-
pred_train = predict(train_x, parameters): 这行代码调用了之前定义的predict函数,传入训练集train_x和训练好的模型参数parameters,用于对训练集进行预测。pred_train是包含了每个样本的预测标签的数组。 -
np.sum((pred_train == train_y) / train_x.shape[1]): 这行代码计算了预测的准确率。具体做法是先比较预测值pred_train与真实标签train_y是否相等,得到一个布尔值数组,然后将True作为1、False作为0进行求和。最后,除以训练集样本数量train_x.shape[1]来计算准确率。 -
print("预测准确率是: " + str(...)): 这行代码将计算出的准确率以字符串的形式打印出来。
这段代码的目的是评估模型在训练集上的性能,以预测准确率的形式进行展示。
##############################################
pred_test = predict(test_x,parameters)
print("预测准确率是: " + str(np.sum((pred_test == test_y) / test_x.shape[1])))
##############################################
这段代码使用训练好的模型 parameters 对测试集 test_x 进行预测,并计算了测试的准确率。
-
pred_test = predict(test_x, parameters): 这行代码调用了之前定义的predict函数,传入测试集test_x和训练好的模型参数parameters,用于对测试集进行预测。pred_test是包含了每个样本的预测标签的数组。 -
np.sum((pred_test == test_y) / test_x.shape[1]): 这行代码计算了预测的准确率。具体做法是先比较预测值pred_test与真实标签test_y是否相等,得到一个布尔值数组,然后将True作为1、False作为0进行求和。最后,除以测试集样本数量test_x.shape[1]来计算准确率。 -
print("预测准确率是: " + str(...)): 这行代码将计算出的准确率以字符串的形式打印出来。
这段代码的目的是评估模型在测试集上的性能,以预测准确率的形式进行展示。这是衡量模型泛化能力的重要指标。
##############################################