使用numpy搭建神经网络并完成图像分类任务

本项目为神经网络课程的课设,做总结加深印象之用,欢迎大家指出不足之处

正文:

导入numpy库(简言之,numpy就是把各种用python写的(核心运算用其他语言写以优化性能,因为python较慢)可以处理不同数组运算的函数打包为一个库,如各种n维数组的创建,转置,乘积等线性代数中 学习的知识,使用者如需要使用相关函数可以下载该库并导入到相应文件中,方便处理相关数据和运算)

import numpy as np

定义两种常见的激活函数(简言之,激活函数就是使上层节点的输出和下层节点的输入之间具有一个函数关系,如果没有激活函数,只有简单的加权求和那么无论有多少层的神经网络,输入和输出都是可知的线性关系 ,那么该网络的能力就十分有限难以逼近复杂的非线性关系,使用激活函数就可以使该网络能力更加强大,更能逼近输入与输出之间的关系)

def sigmoid(Z):
    A = 1 / (1 + np.exp(-Z))
    cache = Z
    return A, cache

def relu(Z):
    A = np.maximum(0, Z)
    cache = Z
    return A, cache
 定义激活函数的反向传播算法,反向传播算法用于计算损失函数关于网络参数的梯度,以便通过梯度下降等方法更新这些参数,接受激活函数关于激活值A的梯度dA以及激活函数中用于存储相应数据的cache,返回损失函数关于激活函数输入Z 的梯度用于计算网络中前一层参数的梯度。
def sigmoid_backward(dA, cache):
    Z = cache
    s = 1 / (1 + np.exp(-Z))
    dZ = dA * s * (1 - s)
    return dZ

def relu_backward(dA, cache):
    Z = cache
    dZ = np.array(dA, copy=True)
    dZ[Z <= 0] = 0
    return dZ

初始化一个两层的神经网络,神经网络通常包含权重(W)和偏置(b)作为可学习的参数。这些参数在训练开始前被随机初始化,以便在训练过程中通过反向传播算法进行更新。

def initialize_parameters(n_x, n_h, n_y):
    np.random.seed(1)
    W1 = np.random.randn(n_h, n_x) * 0.01
    b1 = np.zeros((n_h, 1))
    W2 = np.random.randn(n_y, n_h) * 0.01
    b2 = np.zeros((n_y, 1))

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

    return parameters

初始化 L 层神经网络参数

def initialize_parameters_deep(layers_dims):#layers_dims是个列表,包含每一层神经元的数量
    #确保每次调用该函数时都能生成相同的随机数,这有助于调试和复现结果。
    np.random.seed(3)
    parameters = {}
    L = len(layers_dims)

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

    return parameters

前向传播(加权求和以及激活)

# 前向传播线性部分
def linear_forward(A, W, b):
    Z = np.dot(W, A) + b
    cache = (A, W, b)
    return Z, cache
# 前向传播线性->激活
def linear_activation_forward(A_prev, W, b, activation):
    if activation == "sigmoid":
        Z, linear_cache = linear_forward(A_prev, W, b)
        A, activation_cache = sigmoid(Z)
    elif activation == "relu":
        Z, linear_cache = linear_forward(A_prev, W, b)
        A, activation_cache = relu(Z)

    cache = (linear_cache, activation_cache)
    return A, cache
# 前向传播 L 层模型
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)

    return AL, caches

用交叉熵损失函数计算损失值

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

反向传播(在神经网络中,通过计算损失函数关于各层参数的梯度,逐层更新参数以最小化损失函数。

  • dA_prev:前一层的激活值的梯度,将用于前一层的反向传播。
  • dW:当前层权重的梯度,将用于更新当前层的权重。
  • db:当前层偏置的梯度,将用于更新当前层的偏置。
def linear_backward(dZ, cache):
    A_prev, W, b = cache
    m = A_prev.shape[1]

    dW = (1 / m) * np.dot(dZ, A_prev.T)
    db = (1 / m) * np.sum(dZ, axis=1, keepdims=True)
    dA_prev = np.dot(W.T, dZ)

    return dA_prev, dW, db
# 反向传播 L 层模型
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))

    current_cache = caches[L - 1]
    grads["dA" + str(L - 1)], grads["dW" + str(L)], grads["db" + str(L)] = linear_activation_backward(dAL,current_cache,activation="sigmoid")

    for l in reversed(range(L - 1)):
        current_cache = caches[l]
        dA_prev_temp, dW_temp, db_temp = linear_activation_backward(grads["dA" + str(l + 1)], current_cache,
                                                                    activation="relu")
        grads["dA" + str(l)] = dA_prev_temp
        grads["dW" + str(l + 1)] = dW_temp
        grads["db" + str(l + 1)] = db_temp

    return grads

更新参数

接受的参数有所有层的w和b,所有层w和b的梯度,学习率(控制更新步长)。返回所有层更新后的权重和偏置

def update_parameters(parameters, grads, learning_rate):
    L = len(parameters) // 2

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

    return parameters

整合所有模块

def L_layer_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 print_cost and i % 100 == 0:
            print(f"Cost after iteration {i}: {cost}")
            costs.append(cost)

    return parameters

模拟训练

if __name__ == "__main__":
    # 假设 X 是输入数据,Y 是标签,生成标准正太分布的随机数
    X = np.random.randn(12288, 209)
    Y = (np.random.randn(1, 209) > 0).astype(int)#0或1

    layers_dims = [12288, 20, 7, 5, 1]
    parameters = L_layer_model(X, Y, layers_dims, num_iterations=2000, print_cost=True)

得到结果

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值