当前位置: 首页 > article >正文

深度学习案例:一步步搭建多层神经网络以及应用

该案例来自吴恩达深度学习系列课程一《神经网络和深度学习》第四周编程作业,一步步搭建多层神经网络以及应用,作业内容是搭建一个能够识别猫的多层的神经网络。作业提供的资料包括:训练集(train_catvnoncat.h5)、测试集(test_catvnoncat.h5)、测试实例(testCases.py)、神经网络工具包(dnn_utils.py)、加载数据的工具包(lr_utils.py),下载请移步参考链接一。

文章目录

  • 1 介绍
    • 1.1 案例应用核心公式
    • 1.2 涉及库和主要接口
  • 2 编码
    • 2.1 数据初始化
    • 2.2 正向传播
      • 2.2.1 linear forward
      • 2.2.2 linear activation forward
      • 2.2.3 L model forward
    • 2.3 计算成本
    • 2.4 反向传播
      • 2.4.1 linear backward
      • 2.4.2 linear activation backward
      • 2.4.3 L model backward
    • 2.5 更新参数
    • 2.6 搭建多层神经网络
    • 2.7 结果预测
  • 3 测试
    • 3.1 数据集训练
    • 3.2 结果分析
  • 4 参考

1 介绍

1.1 案例应用核心公式

正向传播
Z [ l ] ( n [ l ] , m ) = W [ l ] ( n [ l ] , n [ l − 1 ] ) ⋅ A [ l − 1 ] ( n [ l − 1 ] , m ) + b [ l ] ( n [ l ] , 1 ) (1) \underset{(n^{[l]},m)}{{Z}^{[l]}}=\underset{(n^{[l]},n^{[l-1]})}{{W}^{[l]}}\cdot\underset{(n^{[l-1]},m)}{A^{[l-1]}}+\underset{(n^{[l]},1)}{{b}^{[l]}}\tag{1} (n[l],m)Z[l]=(n[l],n[l1])W[l](n[l1],m)A[l1]+(n[l],1)b[l](1)

A [ l ] ( n [ l ] , m ) = g [ l ] ( Z [ l ] ) ( n [ l ] , m ) (2) \underset{(n^{[l]},m)}{{A}^{[l]}}=\underset{(n^{[l]},m)}{g^{[l]}({Z}^{[l]})}\tag{2} (n[l],m)A[l]=(n[l],m)g[l](Z[l])(2)

计算成本
J = − 1 m ∑ i = 1 m ( Y ∗ log ⁡ ( A [ L ] ) + ( 1 − Y ) ∗ log ⁡ ( 1 − A [ L ] ) ) (3) J=-\frac{1}{m}\sum\limits_{i=1}^m{(Y*\log{(A^{[L]})}+(1-Y)*\log{(1-A^{[L]})})}\tag{3} J=m1i=1m(Ylog(A[L])+(1Y)log(1A[L]))(3)
反向传播
d Z [ l ] ( n [ l ] , m ) = d A [ l ] ( n [ l ] , m ) ∗ g [ l ] ′ ( Z [ l ] ) ( n [ l ] , m ) (4) \underset{(n^{[l]},m)}{\mathrm{d}{{Z}^{[l]}}}=\underset{(n^{[l]},m)}{\mathrm{d}{{A}^{[l]}}}*\underset{(n^{[l]},m)}{{{g}^{[ l]}}'({{Z}^{[l]}})}\tag{4} (n[l],m)dZ[l]=(n[l],m)dA[l](n[l],m)g[l](Z[l])(4)

d W [ l ] ( n [ l ] , n [ l − 1 ] ) = 1 m ⋅ d Z [ l ] ( n [ l ] , m ) ⋅ A [ l − 1 ] T ( m , n [ l − 1 ] ) (5) \underset{(n^{[l]},n^{[l-1]})}{\mathrm{d}{{W}^{[l]}}}=\frac{1}{m}\cdot \underset{(n^{[l]},m)}{\mathrm{d}{{Z}^{[l]}}}\cdot \underset{(m,n^{[l-1]})}{{A}^{[l-1]T}}\tag{5} (n[l],n[l1])dW[l]=m1(n[l],m)dZ[l](m,n[l1])A[l1]T(5)

d b [ l ] ( n [ l ] , 1 ) = 1 m ⋅   n p . s u m ( d Z [ l ] ( n [ l ] , m ) , a x i s = 1 , k e e p d i m s = T r u e ) (6) \underset{(n^{[l]},1)}{\mathrm{d}{{b}^{[l]}}}=\frac{1}{m}\cdot\text{ }np.sum(\underset{(n^{[l]},m)}{\mathrm{d}{{Z}^{[l]}}},axis=1,keepdims=True)\tag{6} (n[l],1)db[l]=m1 np.sum((n[l],m)dZ[l],axis=1,keepdims=True)(6)

d A [ l − 1 ] ( n [ l − 1 ] , m ) = W [ l ] T ( n [ l − 1 ] , n [ l ] ) ⋅ d Z [ l ] ( n [ l ] , m ) (7) \underset{(n^{[l-1]},m)}{\mathrm{d}{{A}^{[l-1]}}}=\underset{(n^{[l-1]},n^{[l]})}{{W}^{[l]T}}\cdot \underset{(n^{[l]},m)}{\mathrm{d}{{Z}^{[l]}}}\tag{7} (n[l1],m)dA[l1]=(n[l1],n[l])W[l]T(n[l],m)dZ[l](7)

更新参数
W [ l ] = W [ l ] − α ⋅ d W (8) W^{[l]}=W^{[l]}-\alpha \cdot \mathrm{d}W\tag{8} W[l]=W[l]αdW(8)

b [ l ] = b [ l ] − α ⋅ d b [ l ] (9) b^{[l]}=b^{[l]}-\alpha \cdot \mathrm{d}b^{[l]}\tag{9} b[l]=b[l]αdb[l](9)

1.2 涉及库和主要接口

numpy库:用于进行科学计算。

numpy.asarray:将输入转化为数组

numpy.where:返回根据条件选择的值

matplotlib库:用于绘制图表。

matplotlib.pyplot.subplot:将轴添加到当前图形或检索现有轴,创建子图

h5py库:与h5文件中存储的数据集进行交互。

dnn_utils:神经网络工具包。

lr_utils:加载数据工具包。


2 编码

import matplotlib.pyplot as plt
import numpy as np

import lr_utils
from dnn_utils import sigmoid, sigmoid_backward, relu, relu_backward

2.1 数据初始化

初始化多层网络参数。

参数

layers_dims:包含我们网络中每个图层的节点数量的列表

返回

parameters:包含权重矩阵W1, W2, … 和偏置量b1, b2, … 的字典。

def initialize_parameters_deep(layers_dims):
    
    parameters = {}
    L = len(layers_dims) - 1

    for l in range(1, L + 1):
        parameters["W" + str(l)] = np.random.randn(layers_dims[l], layers_dims[l - 1]) / np.sqrt(layers_dims[l - 1])
        parameters["b" + str(l)] = np.zeros((layers_dims[l], 1))

    return parameters

代码中的/ np.sqrt(layers_dims[l - 1])作用是对权重进行缩放,这是 He 初始化的一种变体,用于保持网络的输入和输出的方差一致,避免梯度爆炸或消失问题。

2.2 正向传播

实现多层网络的正向传播,具体通过三个函数实现:

  1. LINEAR:实现线性部分,即公式(1);

  2. LINEAR ->ACTIVATION:联立第一个函数,实现涉及激活函数的部分,即公式(2);

  3. [LINEAR -> RELU] ×(L-1) -> LINEAR -> SIGMOID:综合运用第二个函数实现多层网络正向传播。

在这里插入图片描述

2.2.1 linear forward

实现前向传播的线性部分,主要是公式(1),并返回相关值用于后续函数。

参数

A_prev:来自上一层或输入数据的激活,numpy数组,维度为 ( n [ l − 1 ] , m ) (n^{[l-1]},m) (n[l1],m)

W:权重矩阵,numpy数组,维度为 ( n [ l ] , n [ l − 1 ] ) (n^{[l]},n^{[l-1]}) (n[l],n[l1])

b:偏向量,numpy向量,维度为 ( n [ l ] , 1 ) (n^{[l]},1) (n[l],1)

返回

Z:公式(1)的结果,激活功能的输入,也称为预激活参数,维度为 ( n [ l ] , m ) (n^{[l]},m) (n[l],m)

cache:一个包含A_prevWb的元组

代码

def linear_forward(A_prev, W, b):
    
    Z = np.dot(W, A_prev) + b
    cache = (A_prev, W, b)

    return Z, cache

2.2.2 linear activation forward

实现涉及激活函数部分的前向传播,主要是公式(2),根据激活函数不同分情况调用dnn_utils中的对应函数,同时调用前一个函数,返回相关值用于后续函数。

参数

A_prev:来自上一层或输入数据的激活,numpy数组,维度为 ( n [ l − 1 ] , m ) (n^{[l-1]},m) (n[l1],m)

W:权重矩阵,numpy数组,维度为 ( n [ l ] , n [ l − 1 ] ) (n^{[l]},n^{[l-1]}) (n[l],n[l1])

b:偏向量,numpy向量,维度为 ( n [ l ] , 1 ) (n^{[l]},1) (n[l],1)

activation:在此层中使用的激活函数名,字符串

返回

A:公式(2)的结果,激活函数的输出,也称为激活后的值,numpy数组,维度为 ( n [ l ] , m ) (n^{[l]},m) (n[l],m)

cache:一个包含linear_cache(来自函数linear_forward返回的cache)和activation_cache(包含本层的Z)的元组

代码

def linear_activation_forward(A_prev, W, b, activation):

    Z, linear_cache = linear_forward(A_prev, W, b)
    if activation == "sigmoid":
        A, activation_cache = sigmoid(Z)
    elif activation == "relu":
        A, activation_cache = relu(Z)

    cache = (linear_cache, activation_cache)

    return A, cache

2.2.3 L model forward

综合调用第二个函数,根据需要实现多层网络正向传播,并返回相关值用于反向传播。此处前 L − 1 L-1 L1 层采用RELU激活函数,第 L L L 层采用SIGMOID激活函数。

参数

X:训练的数据,numpy数组,维度为 ( n x , m ) (n_x,m) (nx,m)

parameters:初始化的参数,字典,即函数initialize_parameters_deep()的输出

返回

AL:最后的激活值,numpy数组,维度为 ( n [ L ] , m ) (n^{[L]},m) (n[L],m) ,本例中即 ( 1 , m ) (1,m) (1,m)

caches:列表,包含根据需要采取不同激活函数后,每一层linear_activation_forward()函数返回的cache值

代码

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)], "relu")
        caches.append(cache)
        
    AL, cache = linear_activation_forward(A, parameters["W" + str(L)], parameters["b" + str(L)], "sigmoid")
    caches.append(cache)

    return AL, caches

2.3 计算成本

计算交叉熵成本,即公式(3)。

参数

AL:与标签预测相对应的概率向量,最后的激活值,numpy数组,维度为 ( 1 , m ) (1,m) (1,m)

Y:标签向量,维度为 ( 1 , m ) (1,m) (1,m) ,本例中如果是猫则为1,如果不是猫则为0

返回

cost:交叉熵成本,即公式(3)的运算结果

代码

def compute_cost(AL, Y):

    m = Y.shape[1]

    cost = (-1 / m) * np.sum(Y * np.log(AL) + (1 - Y) * np.log(1 - AL))
    cost = np.squeeze(cost)

    return cost

2.4 反向传播

实现多层网络的反向传播,具体通过三个函数实现:

  1. LINEAR:实现线性部分,即公式(5)(6)(7);

  2. LINEAR <- ACTIVATION:联立第一个函数,实现涉及激活函数的部分,即公式(4);

  3. [LINEAR <- RELU] ×(L-1) <- LINEAR <- SIGMOID:综合运用第二个函数实现多层网络反向传播。

在这里插入图片描述

2.4.1 linear backward

实现反向传播的线性部分,主要是公式(5)(6)(7),并返回相关值用于后续函数。

参数

dZ:当前第 l l l 层的线性输出的成本梯度,numpy数组,与 Z 维度相同

cache:来自当前层正向传播线性部分的cache值,包含A_prevWb

返回

dA_prev:第 l − 1 l-1 l1 层激活 A A A 的成本梯度,与 A p r e v A_{prev} Aprev 维度相同

dW:当前第 l l l 层的 W W W 的成本梯度,与 W W W 的维度相同

db:当前第 l l l 层的 b b b 的成本梯度,与 b b b 维度相同

代码

def linear_backward(dZ, cache):

    A_prev, W, b = cache
    m = A_prev.shape[1]
    
    dW = np.dot(dZ, A_prev.T) / m
    db = np.sum(dZ, axis=1, keepdims=True) / m
    dA_prev = np.dot(W.T, dZ)

    return dA_prev, dW, db

2.4.2 linear activation backward

实现涉及激活函数部分的后向传播,主要是公式(4),根据激活函数不同分情况调用dnn_utils中的对应函数,先计算出 d Z dZ dZ 后将参数导入前一个函数计算,返回相关值用于后续函数。

参数

dA:当前层 l l l 的激活后的梯度值,与 A A A 维度相同

cache:来自当前层正向传播线性激活部分的cache值,包含linear_cache(来自函数linear_forward返回的cache)和activation_cache(包含本层的Z

activation - 要在此层中使用的激活函数名,字符串类型,【“sigmoid” | “relu”】

返回

dA_prev:第 l − 1 l-1 l1 层激活 A A A 的成本梯度,与 A p r e v A_{prev} Aprev 维度相同

dW:当前第 l l l 层的 W W W 的成本梯度,与 W W W 的维度相同

db:当前第 l l l 层的 b b b 的成本梯度,与 b b b 维度相同

代码

def linear_activation_backward(dA, cache, activation="relu"):

    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

2.4.3 L model backward

综合调用第二个函数,根据需要实现多层网络反向传播,并返回梯度相关值用于参数更新。此处前 L − 1 L-1 L1 层采用RELU激活函数,第 L L L 层采用SIGMOID激活函数。

参数

AL:多层正向传播函数最后的激活值,当前权重和偏向量下预测的概率向量,numpy数组,维度为 ( 1 , m ) (1,m) (1,m)

Y:标签向量,维度为 ( 1 , m ) (1,m) (1,m) ,本例中如果是猫则为1,如果不是猫则为0

caches:对应多层正向传播函数最后返回的caches值,需要注意的是caches[i-1]实际为为第i层的cache值

返回

grads:具有梯度值的字典,包含dA1, dW1, db1, dA2, dW2, db2

代码

def L_model_backward(AL, Y, caches):

    grads = {}
    L = len(caches)
    m = AL.shape[1]
    Y = Y.reshape(AL.shape)
    
    dAL = -(np.divide(Y, AL) - np.divide(1 - Y, 1 - AL))
    grads["dA" + str(L)], grads["dW" + str(L)], grads["db" + str(L)] = linear_activation_backward(dAL, caches[L - 1], "sigmoid")
    
    for l in reversed(range(1, L)):
        dA_prev_temp, dW_temp, db_temp = linear_activation_backward(grads["dA" + str(l + 1)], caches[l - 1], "relu")
        grads["dA" + str(l)] = dA_prev_temp
        grads["dW" + str(l)] = dW_temp
        grads["db" + str(l)] = db_temp

    return grads

2.5 更新参数

利用公式(8)(9),使用梯度下降更新参数。

参数

parameters:包含参数W1, W2, … b1, b2, … 的字典,初值来自数据初始化的返回值,后续不断自我迭代

grads:包含梯度值的字典,是多层反向传播的输出

返回

parameters:梯度下降迭代后更新的参数字典

代码

def update_parameters(parameters, grads, learning_rate):

    L = len(parameters) // 2

    for l in range(L):
        parameters["W" + str(l + 1)] = parameters["W" + str(l + 1)] - learning_rate * grads["dW" + str(l + 1)]
        parameters["b" + str(l + 1)] = parameters["b" + str(l + 1)] - learning_rate * grads["db" + str(l + 1)]

    return parameters

2.6 搭建多层神经网络

实现一个L层神经网络参数。

参数

X:输入的数据,numpy数组,维度为 ( n x , m ) (n_x,m) (nx,m)

Y:标签向量,维度为 ( 1 , m ) (1,m) (1,m) ,本例中如果是猫则为1,如果不是猫则为0

layers_dims:包含我们网络中每个图层的节点数量的列表

learning_rate:学习率

num_iterations - 迭代的次数

print_cost:是否打印成本值,布尔值

isPlot:是否绘制出误差值的图谱,布尔值

返回

parameters:模型学习结束后的参数,可以用他们来预测。

代码

def L_layer_model(X, Y, layers_dims, learning_rate=0.0075, num_iterations=3000, print_cost=False, isPlot=True):

    costs = []
    parameters = initialize_parameters_deep(layers_dims)

    for i in range(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:
            costs.append(cost)
            if print_cost:
                print("第 %i 次迭代,成本值为: %f" % (i, cost))

    if isPlot:
        plt.plot(np.squeeze(costs))
        plt.ylabel('cost')
        plt.xlabel('iterations (per hundreds)')
        plt.title("Learning rate =" + str(learning_rate))
        plt.show()

    return parameters

2.7 结果预测

用于预测多层神经网络的结果,具体是将训练模型的参数和输入的数据进行一次正向传播,得到的激活值也就包含每个样例的预测,再将这些预测结果处理并与原标签比较后得到预测结果。

参数

X:输入的数据,numpy数组,维度为 ( n x , m ) (n_x,m) (nx,m)

Y:标签向量,维度为 ( 1 , m ) (1,m) (1,m) ,本例中如果是猫则为1,如果不是猫则为0

parameters:训练模型的参数

返回

P:对给定数据集 X X X 的预测结果

代码

def predict(X, Y, parameters):

    m = X.shape[1]
    P = np.zeros((1, m))

    probas, caches = L_model_forward(X, parameters)
    for i in range(m):
        if probas[0, i] > 0.5:
            P[0, i] = 1
        else:
            P[0, i] = 0

    print("准确率为:" + str(float(np.sum(P == Y) / m)))

    return P

3 测试

3.1 数据集训练

数据加载和预处理

train_set_x_orig, train_set_y, test_set_x_orig, test_set_y, classes = lr_utils.load_dataset()

train_x_flatten = train_set_x_orig.reshape(train_set_x_orig.shape[0], -1).T
test_x_flatten = test_set_x_orig.reshape(test_set_x_orig.shape[0], -1).T

train_x = train_x_flatten / 255
train_y = train_set_y
test_x = test_x_flatten / 255
test_y = test_set_y

神经网络训练和预测

layers_dims = [12288, 20, 7, 5, 1]
parameters = L_layer_model(train_x, train_y, layers_dims, num_iterations=2500, print_cost=True, isPlot=True)

pred_train = predict(train_x, train_y, parameters)
pred_test = predict(test_x, test_y, parameters)

3.2 结果分析

运行结果

在这里插入图片描述

在这里插入图片描述

打印预测错误图片

def print_mislabeled_images(classes, X, Y, P):

    mislabeled_indices = np.asarray(np.where(P + Y == 1))  # 二维数组,给出满足条件的元素所在的行和列
    plt.rcParams['figure.figsize'] = (40.0, 40.0)
    num_images = len(mislabeled_indices[0])
    for i in range(num_images):
        index = mislabeled_indices[1][i]
        plt.subplot(2, num_images, i + 1)
        plt.imshow(X[:, index].reshape(64, 64, 3), interpolation='nearest')
        plt.axis('off')
        plt.title(
            "Predicted: " + classes[int(P[0, index])].decode("utf-8") + "\n Class: " + classes[int(Y[0, index])].decode(
                "utf-8"))
    plt.show()


print_mislabeled_images(classes, test_x, test_y, pred_test)

在这里插入图片描述


4 参考

【中文】【吴恩达课后编程作业】Course 1 - 神经网络和深度学习 - 第四周作业(1&2)

NumPy reference — NumPy v2.1 Manual

API Reference — Matplotlib 3.9.2 documentation


http://www.kler.cn/a/379292.html

相关文章:

  • 鸿蒙进阶-AlphabetIndexer组件
  • Linux中断、软中断、MMU内存映射-深入理解
  • Linux操作系统 ------(3.文本编译器Vim)
  • 批量删除redis数据【亲测可用】
  • Java实现动态切换ubuntu壁纸功能
  • [MySQL]DQL语句(一)
  • 基于向量检索的RAG大模型
  • 探索设计模式:命令模式
  • 第三十二章 Vue组件分类及存放位置
  • 本质矩阵分解计算Rt
  • 宝塔FTP服务配置结合内网穿透实现安全便捷的远程文件管理和传输
  • 广东网站设计提升你网站在搜索引擎中的排名
  • 搭建支持国密GmSSL的Nginx环境
  • 【AI+教育】一些记录@2024.11.04
  • latex中公式之间的省略号
  • C++ 内存对齐:alignas 与 alignof
  • 基于Matlab 模拟停车位管理系统【源码 GUI】
  • Selenium的下载及chrome环境搭建
  • git入门教程14:Git与其他工具的集成
  • 构造有向(无向)加权图
  • 机器学习算法之回归算法
  • 来康生命科技有限公司心率监测解决方案在健身房与康养机构的应用探索
  • Docker Hub 镜像加速器
  • 鸿蒙Harmony-圆形绘制组件Circle使用详解
  • 基于python的机器学习(一)—— 基础知识(Scikit-learn安装)
  • JVM 类加载器