授课语音

实践:实现一个简单的前馈神经网络用于分类任务

在这部分实践中,我们将构建一个简单的前馈神经网络(Feedforward Neural Network, FNN),用于解决分类任务。我们将使用Python和NumPy库来实现神经网络,并通过前向传播和反向传播来训练网络。

1. 问题描述

我们将使用一个简单的分类任务,假设我们有一个二分类问题,目标是根据输入的特征来预测类别。比如,通过两维数据(例如:身高和体重)来预测某人是否患有某种疾病(1为患病,0为健康)。

2. 神经网络架构

我们的神经网络将包含以下结构:

  • 输入层:2个输入节点(代表两个特征:身高和体重)。
  • 隐藏层:1个隐藏层,包含3个神经元,使用ReLU激活函数。
  • 输出层:1个输出节点,输出类别,使用Sigmoid激活函数。

3. 前向传播与反向传播

我们将使用 ReLU 作为隐藏层的激活函数,Sigmoid 作为输出层的激活函数,损失函数使用 二元交叉熵(Binary Cross-Entropy),并使用 梯度下降 来更新权重。

4. 代码实现

import numpy as np

# 激活函数
def relu(x):
    return np.maximum(0, x)

def sigmoid(x):
    return 1 / (1 + np.exp(-x))

def sigmoid_derivative(x):
    return x * (1 - x)

def relu_derivative(x):
    return np.where(x > 0, 1, 0)

# 初始化权重和偏置
def initialize_weights(input_size, hidden_size, output_size):
    np.random.seed(42)  # 固定种子,确保结果可复现
    weights_1 = np.random.randn(input_size, hidden_size)  # 输入到隐藏层的权重
    bias_1 = np.zeros((1, hidden_size))  # 隐藏层的偏置
    weights_2 = np.random.randn(hidden_size, output_size)  # 隐藏层到输出层的权重
    bias_2 = np.zeros((1, output_size))  # 输出层的偏置
    return weights_1, bias_1, weights_2, bias_2

# 前向传播
def forward_propagation(X, weights_1, bias_1, weights_2, bias_2):
    z1 = np.dot(X, weights_1) + bias_1
    a1 = relu(z1)  # 隐藏层激活
    z2 = np.dot(a1, weights_2) + bias_2
    output = sigmoid(z2)  # 输出层激活
    return a1, output

# 反向传播
def backpropagation(X, y, a1, output, weights_1, weights_2, bias_1, bias_2, learning_rate):
    m = X.shape[0]
    
    # 计算输出层的误差
    error_output = output - y
    d_weights_2 = np.dot(a1.T, error_output) / m
    d_bias_2 = np.sum(error_output, axis=0, keepdims=True) / m

    # 计算隐藏层的误差
    error_hidden = np.dot(error_output, weights_2.T) * relu_derivative(a1)
    d_weights_1 = np.dot(X.T, error_hidden) / m
    d_bias_1 = np.sum(error_hidden, axis=0, keepdims=True) / m
    
    # 更新权重和偏置
    weights_1 -= learning_rate * d_weights_1
    bias_1 -= learning_rate * d_bias_1
    weights_2 -= learning_rate * d_weights_2
    bias_2 -= learning_rate * d_bias_2
    
    return weights_1, bias_1, weights_2, bias_2

# 训练神经网络
def train_neural_network(X, y, input_size, hidden_size, output_size, epochs, learning_rate):
    weights_1, bias_1, weights_2, bias_2 = initialize_weights(input_size, hidden_size, output_size)
    
    for epoch in range(epochs):
        # 前向传播
        a1, output = forward_propagation(X, weights_1, bias_1, weights_2, bias_2)
        
        # 计算损失(交叉熵)
        loss = -np.mean(y * np.log(output) + (1 - y) * np.log(1 - output))
        
        # 反向传播
        weights_1, bias_1, weights_2, bias_2 = backpropagation(X, y, a1, output, weights_1, weights_2, bias_1, bias_2, learning_rate)
        
        # 每1000次迭代输出一次损失
        if epoch % 1000 == 0:
            print(f"Epoch {epoch}, Loss: {loss:.4f}")
    
    return weights_1, bias_1, weights_2, bias_2

# 预测函数
def predict(X, weights_1, bias_1, weights_2, bias_2):
    _, output = forward_propagation(X, weights_1, bias_1, weights_2, bias_2)
    return (output > 0.5).astype(int)  # 将输出转换为0或1

# 示例数据(假设为身高和体重来预测是否患病)
X = np.array([[1.7, 65], [1.8, 80], [1.6, 55], [1.7, 70], [1.75, 75], [1.8, 90]])  # 输入特征
y = np.array([[0], [1], [0], [0], [1], [1]])  # 输出标签,0表示健康,1表示患病

# 训练模型
input_size = X.shape[1]  # 输入特征数
hidden_size = 3  # 隐藏层神经元数量
output_size = 1  # 输出层神经元数量
epochs = 10000  # 训练轮数
learning_rate = 0.01  # 学习率

weights_1, bias_1, weights_2, bias_2 = train_neural_network(X, y, input_size, hidden_size, output_size, epochs, learning_rate)

# 预测
predictions = predict(X, weights_1, bias_1, weights_2, bias_2)
print(f"Predictions: {predictions.T}")

5. 代码解释

  • 激活函数

    • relu(x):ReLU激活函数,用于隐藏层。
    • sigmoid(x):Sigmoid激活函数,用于输出层。
    • sigmoid_derivative(x)relu_derivative(x):分别用于计算Sigmoid和ReLU的导数,供反向传播使用。
  • 初始化权重和偏置

    • initialize_weights()函数随机初始化网络的权重和偏置。
  • 前向传播

    • forward_propagation()函数用于计算前向传播,输出每一层的激活值,最终得到输出层的预测值。
  • 反向传播

    • backpropagation()函数计算损失函数对每一层的权重和偏置的梯度,并使用梯度下降法更新权重。
  • 训练函数

    • train_neural_network()函数使用前向传播和反向传播训练神经网络,并且每隔1000次迭代输出损失值。
  • 预测

    • predict()函数根据训练后的网络权重预测新样本的分类。

6. 结果展示

运行代码后,训练过程中的损失值会逐步下降,最后输出每个样本的预测结果。例如:

Epoch 0, Loss: 0.6901
Epoch 1000, Loss: 0.6882
Epoch 2000, Loss: 0.6859
...
Predictions: [[0 1 0 0 1 1]]

这些预测值表示每个输入样本的分类结果,0表示健康,1表示患病。

7. 总结

  • 我们实现了一个简单的前馈神经网络,通过前向传播和反向传播算法进行训练,并使用梯度下降法优化网络的权重。
  • 通过这种方式,我们可以使用神经网络来处理分类问题,并根据输入特征预测类别。
  • 这种简单的网络为我们进一步理解和扩展更复杂的神经网络模型(如卷积神经网络、循环神经网络等)奠定了基础。

这个实践提供了神经网络训练的基本框架,并能帮助学员掌握前馈神经网络的核心概念。

去1:1私密咨询

系列课程: