3.深度神经网络识别猫

发布时间 2023-08-31 17:28:46作者: 王哲MGG_AI

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脚本,用于初始化一些库和设置绘图参数。

  1. import numpy as np: 这里导入了NumPy库,并将其别名为np,以便在后续代码中使用更短的名称来引用NumPy函数和类。

  2. import h5py: 这是导入HDF5文件处理库,通常用于读取和写入大型数据集。

  3. import matplotlib.pyplot as plt: 这里导入了Matplotlib库,并将其别名为plt,以便在后续代码中使用更短的名称来创建和操作绘图。

  4. from testCases import *: 这是从一个名为testCases的模块中导入了所有内容(使用星号*)。这可能是测试用例的一部分,用于测试某些函数或代码的正确性。

  5. from dnn_utils import *: 类似地,这里从名为dnn_utils的模块中导入了所有内容。这可能包含与深度神经网络相关的实用函数。

  6. %matplotlib inline: 这是一个Jupyter Notebook魔法命令,用于在Notebook中内联显示绘图。

  7. plt.rcParams['figure.figsize'] = (5.0, 4.0): 这行代码设置Matplotlib的默认图形大小为宽度5.0和高度4.0。

  8. plt.rcParams['image.interpolation'] = 'nearest': 这行代码设置Matplotlib图像的插值方式为“nearest”,这意味着在绘制图像时,使用最近邻插值以获得像素之间的连续性。

  9. plt.rcParams['image.cmap'] = 'gray': 这行代码设置Matplotlib绘制图像时的颜色映射(colormap)为灰度,这意味着图像将以灰度色彩显示。

  10. 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),用于初始化深度神经网络的参数。让我为您逐行解释这个函数的工作原理:

  1. np.random.seed(1): 这行代码设置了随机数生成器的种子值为1,以确保在随机数生成过程中得到可重复的结果。

  2. parameters = {}: 这里创建了一个空字典 parameters,它将用于存储神经网络的权重矩阵和偏置向量。

  3. L = len(layer_dims): 这里计算了神经网络的层数,layer_dims 是一个包含每一层神经元数量的列表,它的长度就是网络的层数。

  4. for l in range(1, L):: 这是一个循环,从第2层(索引1,因为Python中索引从0开始)开始遍历到最后一层。

  5. parameters['W' + str(l)]: 在字典 parameters 中创建一个键,用于存储当前层的权重矩阵。'W' + str(l) 创建了一个唯一的键,例如,'W1' 表示第一层的权重。

  6. np.random.randn(layer_dims[l], layer_dims[l - 1]) / np.sqrt(layer_dims[l-1]): 这行代码使用均值为0、标准差为1的正态分布随机初始化权重矩阵,并通过 np.sqrt(layer_dims[l-1]) 进行缩放以控制权重的范围。这是一种常用的权重初始化方法,有助于训练过程更稳定。

  7. parameters['b' + str(l)]: 在字典 parameters 中创建一个键,用于存储当前层的偏置向量。'b' + str(l) 创建了一个唯一的键,例如,'b1' 表示第一层的偏置。

  8. np.zeros((layer_dims[l], 1)): 这行代码创建一个全零的偏置向量,其形状为 (layer_dims[l], 1),这个形状与当前层的神经元数量匹配。

  9. assert(parameters['W' + str(l)].shape == (layer_dims[l], layer_dims[l - 1]))assert(parameters['b' + str(l)].shape == (layer_dims[l], 1)): 这两行代码是断言语句,用于检查初始化的权重矩阵和偏置向量的形状是否与预期的形状相匹配。如果不匹配,将引发错误。

  10. 最后,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 函数来初始化深度神经网络的参数,并打印了部分初始化后的参数值。

  1. parameters = initialize_parameters_deep([5,4,3]): 这行代码调用了 initialize_parameters_deep 函数,传入一个包含 [5, 4, 3] 的列表作为参数。这个列表表示神经网络的结构,包含了3层,分别有5个输入神经元、4个隐藏层神经元和3个输出神经元。initialize_parameters_deep 函数将返回一个包含初始化后的参数的字典,并将其赋值给变量 parameters

  2. print("W1 = " + str(parameters["W1"])): 这行代码打印了第一层的权重矩阵 W1 的值。

  3. print("b1 = " + str(parameters["b1"])): 这行代码打印了第一层的偏置向量 b1 的值。

  4. print("W2 = " + str(parameters["W2"])): 这行代码打印了第二层的权重矩阵 W2 的值。

  5. 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),用于执行神经网络的线性前向传播步骤。

  1. Z = np.dot(W, A) + b: 这行代码计算线性变换的输出,其中 A 是输入矩阵,W 是权重矩阵,b 是偏置向量。这个计算通过矩阵乘法 np.dot(W, A) 来实现,然后加上偏置向量 b。结果存储在变量 Z 中,表示当前层的线性输出。

  2. assert(Z.shape == (W.shape[0], A.shape[1])): 这是一个断言语句,用于检查计算得到的 Z 的形状是否与预期的形状相匹配。具体来说,它检查 Z 的行数是否等于 W 的行数,以及 Z 的列数是否等于 A 的列数。这是为了确保矩阵维度匹配,以使后续计算能够正确进行。

  3. cache = (A, W, b): 这行代码创建了一个元组 cache,其中包含了输入矩阵 A、权重矩阵 W 和偏置向量 b。这个元组将用于后续的反向传播步骤,以保存这些值供后续使用。

  4. 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))

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

这段代码执行了线性前向传播的测试。

  1. A, W, b = linear_forward_test_case(): 这行代码调用了一个名为 linear_forward_test_case() 的测试用例函数,用于生成测试所需的输入矩阵 A、权重矩阵 W 和偏置向量 b。这些值将用于测试线性前向传播函数 linear_forward

  2. Z, linear_cache = linear_forward(A, W, b): 这行代码调用了之前定义的 linear_forward 函数,传入输入矩阵 A、权重矩阵 W 和偏置向量 b,并执行线性前向传播。函数返回线性变换的结果 Z 和缓存信息 linear_cache

  3. 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),用于执行带有激活函数的前向传播步骤。

  1. Z, linear_cache = linear_forward(A_prev, W, b): 这行代码调用了之前定义的 linear_forward 函数,传入输入矩阵 A_prev、权重矩阵 W 和偏置向量 b,执行线性前向传播。函数返回线性变换的结果 Z 和缓存信息 linear_cache

  2. if activation == "sigmoid":: 这是一个条件语句,检查激活函数的类型。如果 activation 的值是 "sigmoid",则执行以下代码块:

    • A = sigmoid(Z): 这里调用了 sigmoid 函数,对线性变换的结果 Z 进行了 sigmoid 激活,得到激活后的输出 A
  3. elif activation == "relu":: 如果激活函数的类型是 "relu",则执行以下代码块:

    • A = relu(Z): 这里调用了 relu 函数,对线性变换的结果 Z 进行了 ReLU 激活,得到激活后的输出 A
  4. assert (A.shape == (W.shape[0], A_prev.shape[1])): 这是一个断言语句,用于检查激活后的输出 A 的形状是否与预期的形状相匹配。具体来说,它检查 A 的行数是否等于 W 的行数,以及列数是否等于 A_prev 的列数。这是为了确保矩阵维度匹配,以使后续计算能够正确进行。

  5. cache = (linear_cache, Z): 最后,函数将缓存信息 linear_cache 和线性变换的结果 Z 存储在一个元组 cache 中,以供后续的反向传播步骤使用。

  6. 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 激活函数。

  1. A_prev, W, b = linear_activation_forward_test_case(): 这行代码调用了一个名为 linear_activation_forward_test_case() 的测试用例函数,用于生成测试所需的输入矩阵 A_prev、权重矩阵 W 和偏置向量 b。这些值将用于测试带有激活函数的前向传播函数 linear_activation_forward

  2. 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

  3. print("With sigmoid: A = " + str(A)): 这行代码打印了使用 sigmoid 激活函数后的输出 A

  4. A, linear_activation_cache = linear_activation_forward(A_prev, W, b, activation = "relu"): 这行代码再次调用 linear_activation_forward 函数,但这次传入了激活函数的类型 "relu"。函数执行线性前向传播,然后应用 ReLU 激活函数。它返回激活后的输出 A 和缓存信息 linear_activation_cache

  5. 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),用于执行深度神经网络的前向传播。

  1. caches = []: 这里创建一个空列表 caches,用于存储每一层的缓存信息,缓存将在反向传播中使用。

  2. A = X: 初始化输入数据 AX,其中 X 是神经网络的输入数据。

  3. L = len(parameters) // 2: 计算神经网络的总层数 Lparameters 是一个字典,包含了神经网络的权重矩阵和偏置向量,通过计算字典长度的一半,可以得到神经网络的总层数。

  4. for l in range(1, L):: 这是一个循环,从第1层遍历到倒数第二层(因为最后一层是 sigmoid 激活函数)。

  5. A_prev = A: 将当前层的激活值 A 存储为上一层的激活值 A_prev

  6. 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 列表中。

  7. AL, cache = linear_activation_forward(A, parameters['W' + str(L)], parameters['b' + str(L)], activation='sigmoid'): 这行代码执行神经网络的最后一层线性前向传播,并应用 sigmoid 激活函数。AL 存储了神经网络的输出,而 cache 存储了最后一层的缓存信息,并将其添加到 caches 列表中。

  8. assert(AL.shape == (1, X.shape[1])): 这是一个断言语句,用于检查神经网络的输出 AL 的形状是否与输入数据 X 的形状相匹配。具体来说,它检查输出的行数是否为1,列数是否与输入数据的列数相同。这是为了确保输出的形状正确。

  9. 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 的长度。

  1. X, parameters = L_model_forward_test_case(): 这行代码调用了一个名为 L_model_forward_test_case() 的测试用例函数,用于生成测试所需的输入数据 X 和参数 parametersX 是神经网络的输入数据,parameters 包含了神经网络的权重矩阵和偏置向量。

  2. AL, caches = L_model_forward(X, parameters): 这行代码调用了 L_model_forward 函数,传入输入数据 X 和参数 parameters,执行深度神经网络的前向传播。函数返回神经网络的输出 AL 和存储了每一层缓存信息的列表 caches

  3. print("AL = " + str(AL)): 这行代码打印了神经网络的输出 AL,它是网络的最终输出。

  4. 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),用于计算神经网络的成本(损失)函数。

  1. m = Y.shape[1]: 这行代码获取目标值 Y 的列数,其中 m 表示样本的数量。

  2. 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,并取负值。
  3. cost = np.squeeze(cost): 这行代码用于移除成本值 cost 的不必要的维度,以确保成本值是标量(一个单独的数值)。

  4. assert(cost.shape == ()): 这是一个断言语句,用于检查成本值 cost 的形状是否为一个标量。如果形状不是标量,将引发错误。

  5. return cost: 函数返回计算得到的成本值 cost

总之,这个函数的作用是计算神经网络的成本,使用交叉熵损失函数来衡量实际目标值 Y 与预测值 AL 之间的差异。

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

Y, AL = compute_cost_test_case()

print("cost = " + str(compute_cost(AL, Y)))

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

这段代码执行了成本函数的测试,并打印了计算得到的成本值 cost

  1. Y, AL = compute_cost_test_case(): 这行代码调用了一个名为 compute_cost_test_case() 的测试用例函数,用于生成测试所需的目标值 Y 和预测值 ALY 是实际目标值,AL 是神经网络的预测值。

  2. 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),用于计算神经网络中某一层的反向传播梯度。

  1. A_prev, W, b = cache: 这行代码从缓存 cache 中提取出上一层的激活值 A_prev、权重矩阵 W 和偏置向量 b,这些值是前向传播时存储的。

  2. m = A_prev.shape[1]: 这行代码获取样本数量 m,其中 A_prev 的列数表示样本数量。

  3. 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,以求得平均梯度。
  4. db = np.sum(dZ, axis=1, keepdims=True) / m: 这行代码计算偏置向量的梯度 db。具体来说,它执行以下操作:

    • dZ 是当前层的梯度。
    • np.sum(dZ, axis=1, keepdims=True)dZ 沿着列的方向进行求和,得到每个神经元的梯度总和。
    • 最后,将结果除以样本数量 m,以求得平均梯度,并使用 keepdims=True 保持结果的维度与 b 相同。
  5. dA_prev = np.dot(cache[1].T, dZ): 这行代码计算上一层的激活值的梯度 dA_prev。具体来说,它执行以下操作:

    • cache[1] 是当前层的权重矩阵 W,通过转置得到 W.T
    • np.dot(cache[1].T, dZ) 执行矩阵乘法,计算了 dA_prev
  6. assert (dA_prev.shape == A_prev.shape), assert (dW.shape == W.shape), assert (db.shape == b.shape): 这些是断言语句,用于检查计算得到的梯度的形状是否与相应的参数的形状相匹配。如果不匹配,将引发错误。

  7. 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_prevdWdb

  1. dZ, linear_cache = linear_backward_test_case(): 这行代码调用了一个名为 linear_backward_test_case() 的测试用例函数,用于生成测试所需的梯度 dZ 和缓存 linear_cachedZ 是当前层的梯度,linear_cache 包含了反向传播所需的信息,包括上一层的激活值 A_prev、权重矩阵 W 和偏置向量 b

  2. dA_prev, dW, db = linear_backward(dZ, linear_cache): 这行代码调用了 linear_backward 函数,传入梯度 dZ 和缓存信息 linear_cache,执行线性层的反向传播。函数返回上一层的梯度 dA_prev、权重矩阵的梯度 dW 和偏置向量的梯度 db

  3. print ("dA_prev = "+ str(dA_prev)): 这行代码打印了上一层的梯度 dA_prev,这是反向传播的输出,表示传递给前一层的梯度。

  4. print ("dW = " + str(dW)): 这行代码打印了权重矩阵的梯度 dW,表示该层权重的梯度。

  5. 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),用于计算带有激活函数的层级的反向传播梯度。

  1. linear_cache, activation_cache = cache: 这行代码从传入的缓存 cache 中分离出线性层的缓存信息 linear_cache 和激活函数的缓存信息 activation_cache

  2. if activation == "relu":: 这是一个条件语句,检查激活函数的类型。如果激活函数的类型是 "relu",则执行以下代码块:

    • dZ = relu_backward(dA, activation_cache): 这行代码调用了 relu_backward 函数,传入上一层的梯度 dA 和激活函数的缓存信息 activation_cache,以计算当前层的梯度 dZ
  3. elif activation == "sigmoid":: 如果激活函数的类型是 "sigmoid",则执行以下代码块:

    • dZ = sigmoid_backward(dA, activation_cache): 这行代码调用了 sigmoid_backward 函数,传入上一层的梯度 dA 和激活函数的缓存信息 activation_cache,以计算当前层的梯度 dZ
  4. dA_prev, dW, db = linear_backward(dZ, linear_cache): 这行代码调用了 linear_backward 函数,传入当前层的梯度 dZ 和线性层的缓存信息 linear_cache,以计算上一层的激活值的梯度 dA_prev、权重矩阵的梯度 dW 和偏置向量的梯度 db

  5. 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_prevdWdb,分别使用了 sigmoid 和 relu 激活函数。

  1. dAL, linear_activation_cache = linear_activation_backward_test_case(): 这行代码调用了一个名为 linear_activation_backward_test_case() 的测试用例函数,用于生成测试所需的上一层梯度 dAL 和缓存 linear_activation_cachedAL 是当前层的梯度,linear_activation_cache 包含了反向传播所需的信息,包括线性层和激活函数的缓存信息。

  2. 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

  3. print ("sigmoid:"): 这行代码打印了使用 sigmoid 激活函数时的输出标签,表示下面打印的是 sigmoid 激活函数的梯度值。

  4. print ("dA_prev = "+ str(dA_prev)): 这行代码打印了上一层的激活值的梯度 dA_prev,表示传递给前一层的梯度。

  5. print ("dW = " + str(dW)): 这行代码打印了权重矩阵的梯度 dW,表示该层权重的梯度。

  6. print ("db = " + str(db) + "\n"): 这行代码打印了偏置向量的梯度 db,表示该层偏置的梯度。\n 用于在输出中添加一个空行。

  7. 同样的过程重复一次,但这次使用了 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),用于计算整个深度神经网络的反向传播梯度。

  1. grads = {}: 这里创建一个空字典 grads,用于存储每一层的梯度。

  2. L = len(caches): 这行代码获取神经网络的总层数 L,通过缓存列表 caches 的长度来确定。

  3. Y = Y.reshape(AL.shape): 这行代码将目标值 Y 重塑为与预测值 AL 具有相同形状,以确保它们的维度匹配。

  4. dAL = - (np.divide(Y, AL) - np.divide(1 - Y, 1 - AL)): 这行代码计算输出层的梯度 dAL,使用交叉熵损失函数的导数计算方法。

  5. current_cache = caches[-1]: 这行代码获取最后一层的缓存信息 current_cache,以便后续计算输出层的梯度。

  6. 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)] 存储输出层偏置向量的梯度。
  7. for c in reversed(range(1,L)):: 这是一个循环,从倒数第二层(第 L-1 层)向第1层(第1层是输入层,不必计算梯度)遍历每一层。

  8. 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 层的偏置向量的梯度。
  9. 最后,函数返回包含每一层梯度的 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

  1. AL, Y_assess, caches = L_model_backward_test_case(): 这行代码调用了一个名为 L_model_backward_test_case() 的测试用例函数,用于生成测试所需的神经网络输出 AL、目标值 Y_assess 和缓存列表 cachesAL 是神经网络的输出,Y_assess 是实际目标值,caches 包含了每一层的缓存信息。

  2. grads = L_model_backward(AL, Y_assess, caches): 这行代码调用了 L_model_backward 函数,传入神经网络的输出 AL、实际目标值 Y_assess 和缓存列表 caches,执行整个深度神经网络的反向传播,计算梯度。结果存储在 grads 字典中。

  3. print ("dW1 = "+ str(grads["dW1"])): 这行代码打印了第一层的权重矩阵的梯度 dW1

  4. print ("db1 = "+ str(grads["db1"])): 这行代码打印了第一层的偏置向量的梯度 db1

  5. 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),用于更新神经网络的参数(权重和偏置)以进行梯度下降。

  1. L = len(parameters) // 2: 这行代码计算神经网络的层数 L,通过参数字典 parameters 中键的数量除以2。这是因为在 parameters 字典中,权重和偏置都以"W"和"b"为键,并且每一层都有一个"W"和一个"b"。

  2. for l in range(1, L+1):: 这是一个循环,从第一层到最后一层遍历神经网络的所有层。

  3. parameters["W" + str(l)] = parameters["W" + str(l)] - learning_rate * grads["dW" + str(l)]: 这行代码更新第 l 层的权重矩阵 W,使用梯度下降的规则。具体来说,它从原始权重矩阵中减去学习率 learning_rate 乘以相应的权重梯度 grads["dW" + str(l)]

  4. parameters["b" + str(l)] = parameters["b" + str(l)] - learning_rate * grads["db" + str(l)]: 这行代码更新第 l 层的偏置向量 b,使用梯度下降的规则。它从原始偏置向量中减去学习率 learning_rate 乘以相应的偏置梯度 grads["db" + str(l)]

  5. 最后,函数返回更新后的参数字典 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"]))

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

这段代码执行了参数更新的测试,并打印了更新后的参数值。

  1. parameters, grads = update_parameters_test_case(): 这行代码调用了一个名为 update_parameters_test_case() 的测试用例函数,用于生成测试所需的初始参数 parameters 和梯度 gradsparameters 包含了权重和偏置,grads 包含了相应的梯度。

  2. parameters = update_parameters(parameters, grads, 0.1): 这行代码调用了 update_parameters 函数,传入初始参数 parameters、梯度 grads,以及学习率 0.1,执行参数的更新。函数返回更新后的参数 parameters

  3. print ("W1 = " + str(parameters["W1"])): 这行代码打印了第一层的权重矩阵 W1 的更新后的值。

  4. print ("b1 = " + str(parameters["b1"])): 这行代码打印了第一层的偏置向量 b1 的更新后的值。

  5. print ("W2 = " + str(parameters["W2"])): 这行代码打印了第二层的权重矩阵 W2 的更新后的值。

  6. 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.

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

这段代码执行了一些数据预处理操作,准备了训练集和测试集,以便用于深度神经网络的训练和测试。

  1. train_x_orig, train_y, test_x_orig, test_y, classes = load_data(): 这行代码调用了一个名为 load_data() 的函数,从数据集中加载训练集和测试集,以及相关的类别信息。通常,train_x_origtest_x_orig 包含了原始图像数据,train_ytest_y 包含了相应的标签,classes 包含了类别名称。

  2. m_train = train_x_orig.shape[0]m_test = test_x_orig.shape[0]: 这两行代码分别计算了训练集和测试集的样本数量。train_x_orig.shape[0] 给出了训练集的样本数,而 test_x_orig.shape[0] 给出了测试集的样本数。

  3. num_px = test_x_orig.shape[1]: 这行代码计算了图像的像素尺寸。test_x_orig.shape[1] 给出了测试集中每个图像的像素宽度(假设图像是正方形的)。

  4. train_x_flatten = train_x_orig.reshape(train_x_orig.shape[0], -1).Ttest_x_flatten = test_x_orig.reshape(test_x_orig.shape[0], -1).T: 这两行代码将训练集和测试集的图像数据从二维数组形式(图像索引,像素索引)转换为一维数组形式(像素索引,图像索引)。这个操作通常被称为“展平”操作,将每个图像的像素值排列成一列。

  5. 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,它使用多个隐藏层进行前向传播、反向传播和参数更新,以便在训练数据上训练模型。

  1. np.random.seed(1): 这行代码设置了随机数种子,以确保在每次运行模型时都生成相同的随机数,以便结果的可复现性。

  2. costs = []: 这里创建一个空列表 costs,用于存储每次迭代的成本值,以便后续绘制成本曲线。

  3. parameters = initialize_parameters_deep(layers_dims): 这行代码调用了 initialize_parameters_deep 函数,根据神经网络的层数和每层的单元数量来初始化模型的参数(权重和偏置)。

  4. 进入迭代循环 (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 列表中,以便后续绘制成本曲线。

  5. 最后,代码绘制了成本曲线,显示模型的学习进度。然后返回训练后的参数 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 函数来训练一个具有多个隐藏层的深度神经网络。

  1. layers_dims = [12288, 20, 7, 5, 1]: 这是神经网络的架构,表示每个隐藏层的神经元数量。在这个架构中,输入层有12288个神经元,第一个隐藏层有20个,第二个隐藏层有7个,第三个隐藏层有5个,最后输出层有1个。这定义了神经网络的深度和宽度。

  2. 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次迭代后打印成本值。
  3. 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 来进行二分类预测。

  1. m = X.shape[1]: 这行代码获取输入数据 X 中的样本数量 m,即待预测的数据点个数。

  2. n = len(parameters) // 2: 这行代码计算神经网络的层数 n,通过参数字典 parameters 中键的数量除以2。这是因为在 parameters 字典中,权重和偏置都以"W"和"b"为键,并且每一层都有一个"W"和一个"b"。

  3. p = np.zeros((1,m)): 这里创建一个全零数组 p,用于存储预测结果,初始时将所有预测值设置为0。

  4. probas, caches = L_model_forward(X, parameters): 这行代码执行前向传播,计算模型在输入数据 X 上的预测概率 probas 和缓存列表 caches,其中 probas 包含每个样本的预测概率。

  5. 进入循环 (for i in range(0, probas.shape[1]):),遍历每个样本的预测概率。

  6. 如果某个样本的预测概率 probas[0,i] 大于0.5,则将 p[0,i] 设置为1,表示正类;否则,将 p[0,i] 设置为0,表示负类。这实现了二分类预测。

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

总之,这个函数的作用是使用训练好的深度神经网络参数来对输入数据进行二分类预测,并返回预测结果。

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

pred_train = predict(train_x,parameters)
print("预测准确率是: " + str(np.sum((pred_train == train_y) / train_x.shape[1])))

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

这段代码使用训练好的模型 parameters 对训练集 train_x 进行预测,并计算了预测的准确率。

  1. pred_train = predict(train_x, parameters): 这行代码调用了之前定义的 predict 函数,传入训练集 train_x 和训练好的模型参数 parameters,用于对训练集进行预测。pred_train 是包含了每个样本的预测标签的数组。

  2. np.sum((pred_train == train_y) / train_x.shape[1]): 这行代码计算了预测的准确率。具体做法是先比较预测值 pred_train 与真实标签 train_y 是否相等,得到一个布尔值数组,然后将 True 作为1、False 作为0进行求和。最后,除以训练集样本数量 train_x.shape[1] 来计算准确率。

  3. print("预测准确率是: " + str(...)): 这行代码将计算出的准确率以字符串的形式打印出来。

这段代码的目的是评估模型在训练集上的性能,以预测准确率的形式进行展示。

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

pred_test = predict(test_x,parameters)
print("预测准确率是: " + str(np.sum((pred_test == test_y) / test_x.shape[1])))

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

这段代码使用训练好的模型 parameters 对测试集 test_x 进行预测,并计算了测试的准确率。

  1. pred_test = predict(test_x, parameters): 这行代码调用了之前定义的 predict 函数,传入测试集 test_x 和训练好的模型参数 parameters,用于对测试集进行预测。pred_test 是包含了每个样本的预测标签的数组。

  2. np.sum((pred_test == test_y) / test_x.shape[1]): 这行代码计算了预测的准确率。具体做法是先比较预测值 pred_test 与真实标签 test_y 是否相等,得到一个布尔值数组,然后将 True 作为1、False 作为0进行求和。最后,除以测试集样本数量 test_x.shape[1] 来计算准确率。

  3. print("预测准确率是: " + str(...)): 这行代码将计算出的准确率以字符串的形式打印出来。

这段代码的目的是评估模型在测试集上的性能,以预测准确率的形式进行展示。这是衡量模型泛化能力的重要指标。

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