使用NumPy从头开始实现神经网络

  • Post category:Python

这里是使用NumPy从头开始实现神经网络的完整攻略。本文将涵盖构建神经网络所需的所有基础知识以及一些示例说明。我们将深入了解神经网络的架构、激活函数、损失函数、反向传播算法等方面的知识。

基础知识

在开始构建神经网络之前,我们需要对一些基础知识有一些了解。

神经网络的架构

神经网络主要由以下几部分构成:

  • 输入层:接收外部输入数据,每个神经元对应一个输入值。
  • 隐藏层:隐藏层对输入数据进行加权求和并应用激活函数(如ReLU、Sigmoid、tanh等),输出结果传递给下一层。
  • 输出层:输出层接收来自隐层的信号进行处理,并且输出最终结果。

激活函数

神经网络中的激活函数主要有以下几种:

  • ReLU(Rectified Linear Unit)
  • Sigmoid
  • tanh

损失函数

为了评估目标值和预测值之间的误差,我们需要使用一个损失函数来表示两者之间的差异。我们常用的损失函数有以下几种:

  • 均方误差(MSE)
  • 交叉熵
  • 对数损失

反向传播算法

反向传播算法是神经网络中训练模型的关键方法。反向传播算法的基本思路是,通过逆向传递误差信息,对神经网络的权重和偏置进行更新,从而使模型的预测结果更加准确。

神经网络示例说明

下面,我们将用两个示例来展示如何使用NumPy实现神经网络。假设我们要使用神经网络对简单的二分类问题进行分类。

示例1

首先,我们需要导入NumPy并定义训练数据和目标实际值:

import numpy as np

# 定义训练数据
X = np.array([
    [1, 0, 0],
    [1, 0, 1],
    [1, 1, 0],
    [1, 1, 1]
])

# 定义实际输出值
y = np.array([
    [0],
    [1],
    [1],
    [0]
])

然后,我们需要定义神经网络模型的参数:

# 定义神经网络的参数
input_size = 3
hidden_size = 4
output_size = 1

# 初始化权重和偏置
w1 = np.random.randn(input_size, hidden_size)
b1 = np.zeros((1, hidden_size))
w2 = np.random.randn(hidden_size, output_size)
b2 = np.zeros((1, output_size))

# 定义学习率和迭代次数
learning_rate = 0.1
num_iterations = 5000

接着,我们需要实现前向传播和反向传播的函数:

# 定义前向传播函数
def forward(X, w1, b1, w2, b2):
    # 隐藏层的输出
    z1 = np.dot(X, w1) + b1
    a1 = np.tanh(z1)

    # 输出层的输出
    z2 = np.dot(a1, w2) + b2
    a2 = sigmoid(z2)

    return z1, a1, z2, a2

# 定义反向传播函数
def backward(X, y, z1, a1, z2, a2, w1, w2):
    # 计算输出层的误差
    delta2 = (a2 - y) * sigmoid_prime(z2)

    # 计算隐藏层的误差
    delta1 = np.dot(delta2, w2.T) * tanh_prime(z1)

    # 更新权重和偏置
    w2 -= learning_rate * np.dot(a1.T, delta2)
    b2 -= learning_rate * np.sum(delta2, axis=0, keepdims=True)
    w1 -= learning_rate * np.dot(X.T, delta1)
    b1 -= learning_rate * np.sum(delta1, axis=0)

最后,我们可以训练模型并输出预测结果:

# 训练模型
for i in range(num_iterations):
    z1, a1, z2, a2 = forward(X, w1, b1, w2, b2)
    backward(X, y, z1, a1, z2, a2, w1, w2)

# 预测结果
_, _, _, y_pred = forward(X, w1, b1, w2, b2)
print(y_pred)

示例2

接下来,我们将使用另一个示例来展示如何使用NumPy实现神经网络。假设我们要使用神经网络对手写数字进行分类。

首先,我们需要导入MNIST数据集并将其转换为NumPy数组:

# 导入MNIST数据集
from tensorflow.keras.datasets import mnist

(X_train, y_train), (X_test, y_test) = mnist.load_data()

# 数据预处理
X_train = X_train.reshape(60000, 784)
X_test = X_test.reshape(10000, 784)
X_train = X_train / 255.
X_test = X_test / 255.

# 将目标变量转换为独热编码
y_train_onehot = np.eye(10)[y_train]
y_test_onehot = np.eye(10)[y_test]

接着,我们需要定义神经网络模型的参数:

# 定义神经网络的参数
input_size = 784
hidden_size = 512
output_size = 10

# 初始化权重和偏置
w1 = np.random.randn(input_size, hidden_size)
b1 = np.zeros((1, hidden_size))
w2 = np.random.randn(hidden_size, output_size)
b2 = np.zeros((1, output_size))

# 定义学习率和迭代次数
learning_rate = 0.5
num_iterations = 1000

然后,我们需要实现前向传播和反向传播的函数:

# 定义前向传播函数
def forward(X, w1, b1, w2, b2):
    # 隐藏层的输出
    z1 = np.dot(X, w1) + b1
    a1 = np.tanh(z1)

    # 输出层的输出
    z2 = np.dot(a1, w2) + b2
    a2 = softmax(z2)

    return z1, a1, z2, a2

# 定义反向传播函数
def backward(X, y, z1, a1, z2, a2, w1, w2):
    # 计算输出层的误差
    delta2 = (a2 - y) / len(X)

    # 计算隐藏层的误差
    delta1 = np.dot(delta2, w2.T) * tanh_prime(z1)

    # 更新权重和偏置
    w2 -= learning_rate * np.dot(a1.T, delta2)
    b2 -= learning_rate * np.sum(delta2, axis=0, keepdims=True)
    w1 -= learning_rate * np.dot(X.T, delta1)
    b1 -= learning_rate * np.sum(delta1, axis=0)

最后,我们可以训练模型并输出预测结果:

# 训练模型
for i in range(num_iterations):
    z1, a1, z2, a2 = forward(X_train, w1, b1, w2, b2)
    backward(X_train, y_train_onehot, z1, a1, z2, a2, w1, w2)

# 预测结果
_, _, _, y_pred = forward(X_test, w1, b1, w2, b2)
y_pred_labels = np.argmax(y_pred, axis=1)
accuracy = np.sum(y_pred_labels == y_test) / len(y_test)
print("Accuracy:", accuracy)

总结

本文介绍了使用NumPy从头开始实现神经网络的完整攻略,包括神经网络的架构、激活函数、损失函数和反向传播算法等。同时,我们也给出了两个示例,分别是二分类问题和手写数字分类问题。这些示例可以帮助您更好地理解如何使用NumPy构建神经网络。