BP前馈神经网络原理详解:从数学推导到Python实现

1次阅读
没有评论

共计 2165 个字符,预计需要花费 6 分钟才能阅读完成。

image.webp

背景介绍

前馈神经网络(Feedforward Neural Network)是深度学习的基础架构,就像盖楼要先打好地基。1986 年 Rumelhart 提出的反向传播算法(Backpropagation,简称 BP)让神经网络有了 ” 学习 ” 的能力,相当于教会了网络如何通过错误来调整自己。现在虽然有了更复杂的网络结构,但 BP 算法仍然是理解神经网络的必修课。

BP 前馈神经网络原理详解:从数学推导到 Python 实现

数学原理

前向传播

前向传播就是数据从输入层流向输出层的过程,就像流水线上的零件加工。以单隐藏层网络为例:

[h = \sigma(W_1 x + b_1) ]
[\hat{y} = \sigma(W_2 h + b_2) ]

其中 $\sigma$ 是激活函数,常见的 Sigmoid 函数长这样:

[\sigma(z) = \frac{1}{1+e^{-z}} ]

反向传播

反向传播就像老师批改作业后把错误反馈给学生。我们用链式法则计算梯度:

  1. 输出层误差:

[\delta_2 = (\hat{y} – y) \odot \sigma'(z_2) ]

  1. 隐藏层误差:

[\delta_1 = (W_2^T \delta_2) \odot \sigma'(z_1) ]

  1. 权重更新(η 是学习率):

[W_2 \leftarrow W_2 – \eta \delta_2 h^T]
[W_1 \leftarrow W_1 – \eta \delta_1 x^T]

Python 实现

import numpy as np

class NeuralNetwork:
    def __init__(self, input_size, hidden_size, output_size):
        # 参数初始化(这里用 Xavier 初始化)self.W1 = np.random.randn(input_size, hidden_size) / np.sqrt(input_size)
        self.b1 = np.zeros(hidden_size)
        self.W2 = np.random.randn(hidden_size, output_size) / np.sqrt(hidden_size)
        self.b2 = np.zeros(output_size)

    def sigmoid(self, z):
        return 1 / (1 + np.exp(-z))

    def forward(self, x):
        self.h = self.sigmoid(np.dot(x, self.W1) + self.b1)
        return self.sigmoid(np.dot(self.h, self.W2) + self.b2)

    def train(self, X, y, epochs=1000, lr=0.1):
        for epoch in range(epochs):
            # 前向传播
            output = self.forward(X)

            # 计算损失(MSE)loss = np.mean((output - y) ** 2)

            # 反向传播
            d_output = (output - y) * output * (1 - output)
            d_hidden = np.dot(d_output, self.W2.T) * self.h * (1 - self.h)

            # 更新参数
            self.W2 -= lr * np.dot(self.h.T, d_output)
            self.b2 -= lr * np.sum(d_output, axis=0)
            self.W1 -= lr * np.dot(X.T, d_hidden)
            self.b1 -= lr * np.sum(d_hidden, axis=0)

实战优化

学习率调整

固定学习率就像用固定步伐下山,容易错过谷底。试试这些策略:

  1. 阶梯下降:每 N 个 epoch 学习率减半
  2. 指数衰减:lr = lr0 * e^(-kt)
  3. Adam 优化器:自适应调整学习率

解决梯度消失

Sigmoid 在深层网络中容易导致梯度消失(导数最大值只有 0.25)。改用 ReLU 激活函数:

def relu(z):
    return np.maximum(0, z)

L2 正则化

防止过拟合的 ” 紧箍咒 ”,在损失函数中加入权重惩罚项:

# 在损失计算中加入
loss += lambda * (np.sum(self.W1**2) + np.sum(self.W2**2))

避坑指南

  1. 参数初始化 :千万别全零初始化!推荐 Xavier 或 He 初始化
  2. 批量归一化 :在激活函数前加入 BN 层,效果立竿见影
  3. 早停技巧 :验证集损失连续 N 次不下降就停止训练

MNIST 实战

from sklearn.datasets import fetch_openml
from sklearn.preprocessing import MinMaxScaler

# 加载数据
mnist = fetch_openml('mnist_784')
X, y = mnist.data / 255.0, mnist.target.astype(int)

# 简单二分类(识别数字 0)y_binary = (y == 0).astype(int)

# 训练网络
nn = NeuralNetwork(784, 128, 1)
nn.train(X, y_binary.reshape(-1,1), epochs=50, lr=0.1)

思考题

BP 算法在 CNN 中如何应用?提示:卷积层本质也是线性变换,但需要处理局部连接和参数共享的特性。

总结

通过这次手写实现,我发现 BP 算法就像教小孩学走路:前向传播是让网络尝试迈步,反向传播是根据摔倒姿势调整平衡。虽然现在有各种深度学习框架,但理解底层原理就像知道汽车发动机的工作原理,能让你的调参更有方向感。

正文完
 0
评论(没有评论)