BP神经网络公式详解:从数学推导到Python实现

1次阅读
没有评论

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

image.webp

BP 神经网络是深度学习的基础构件,理解它的误差反向传播机制是掌握现代神经网络的关键。本文将用「公式推导 + 代码实现」的双视角,带新手彻底弄懂这个核心算法。

BP 神经网络公式详解:从数学推导到 Python 实现

一、数学推导:从输入到权重更新

1. 前向传播计算

设网络有 L 层,第 l 层的权重矩阵 $W^{(l)}$,偏置 $b^{(l)}$,激活函数 $f(·)$,则:

$$
\begin{aligned}
z^{(l)} &= W^{(l)}a^{(l-1)} + b^{(l)} \
a^{(l)} &= f(z^{(l)})
\end{aligned}
$$

其中 $a^{(0)}=x$ 为输入,$a^{(L)}$ 为最终输出。

2. 误差反向传播

使用均方误差损失 $E=\frac{1}{2}(y-a^{(L)})^2$,通过链式法则逐层计算梯度:

  • 输出层误差:
    $$
    \delta^{(L)} = (a^{(L)} – y) \odot f'(z^{(L)})
    $$
  • 隐藏层误差(反向传播):
    $$
    \delta^{(l)} = (W^{(l+1)T}\delta^{(l+1)}) \odot f'(z^{(l)})
    $$
  • 权重梯度:
    $$
    \frac{\partial E}{\partial W^{(l)}} = \delta^{(l)}a^{(l-1)T}
    $$

3. 权重更新

采用梯度下降:
$$
W^{(l)} \leftarrow W^{(l)} – \eta \frac{\partial E}{\partial W^{(l)}}
$$

二、Python 实现关键代码

import numpy as np

class NeuralNetwork:
    def __init__(self, layers):
        self.weights = [np.random.randn(y, x) * 0.1 
                        for x, y in zip(layers[:-1], layers[1:])]
        self.biases = [np.zeros((y, 1)) for y in layers[1:]]

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

    def sigmoid_prime(self, z):
        return self.sigmoid(z) * (1 - self.sigmoid(z))

    def forward(self, x):
        a = x
        for w, b in zip(self.weights, self.biases):
            z = np.dot(w, a) + b
            a = self.sigmoid(z)
        return a

    def train(self, x, y, lr=0.1):
        # 前向传播
        activations = [x]
        zs = []
        for w, b in zip(self.weights, self.biases):
            z = np.dot(w, activations[-1]) + b
            zs.append(z)
            activations.append(self.sigmoid(z))

        # 反向传播
        delta = (activations[-1] - y) * self.sigmoid_prime(zs[-1])
        for l in range(len(self.weights)-1, -1, -1):
            # 计算梯度并更新
            grad_w = np.dot(delta, activations[l].T)
            self.weights[l] -= lr * grad_w
            self.biases[l] -= lr * delta

            if l > 0:  # 继续反向传播
                delta = np.dot(self.weights[l].T, delta) * self.sigmoid_prime(zs[l-1])

三、避坑指南

  1. 学习率选择:过大(如 >0.5)会导致损失震荡,过小(如 <0.001)收敛缓慢。建议从 0.1 开始尝试

  2. 输入归一化 :未归一化的数据可能导致梯度爆炸。标准化到[0,1] 或使用 Z -score 归一化

  3. 激活函数陷阱:Sigmoid 在深层网络易引发梯度消失。可尝试 ReLU 或 LeakyReLU

四、延伸思考

  • 将代码中的 sigmoid 替换为 np.maximum(0, z) 即可实现 ReLU
  • 批量训练需累计多个样本的梯度后统一更新,比在线训练更稳定但需要更多内存

理解 BP 神经网络的数学本质后,你会发现各种复杂网络结构都是在这个基础上的扩展。建议亲手调试代码观察参数变化,这是掌握算法最有效的方式。

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