BP神经网络前向计算与误差反向传播更新机制图解:从数学原理到实现细节

1次阅读
没有评论

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

image.webp

从单层感知机到神经网络

在机器学习中,单层感知机是最简单的神经网络模型。它只能处理线性可分的问题,对于复杂的非线性问题无能为力。这就是为什么我们需要多层神经网络,而多层网络就需要反向传播算法来训练。

BP 神经网络前向计算与误差反向传播更新机制图解:从数学原理到实现细节

前向计算过程详解

  1. 加权求和 :每个神经元的输入是前一层所有神经元输出的加权和
    $$z_j = \sum_{i} w_{ji}x_i + b_j$$

  2. 激活函数 :通过非线性激活函数转换
    $$a_j = \sigma(z_j)$$

常用的激活函数包括 Sigmoid、ReLU 和 Tanh 等。

误差反向传播机制

反向传播的核心是链式法则。我们通过计算损失函数对权重的梯度来更新权重:

  1. 输出层误差:
    $$\delta_k = (y_k – t_k)\sigma'(z_k)$$

  2. 隐藏层误差:
    $$\delta_j = \sigma'(z_j)\sum_k w_{kj}\delta_k$$

  3. 权重更新:
    $$\Delta w_{ji} = -\eta \delta_j x_i$$

Python 实现代码

import numpy as np

class NeuralNetwork:
    def __init__(self, layers):
        # 网络初始化
        self.weights = []
        self.biases = []
        for i in range(len(layers)-1):
            # 使用 Xavier 初始化
            w = np.random.randn(layers[i+1], layers[i]) * np.sqrt(1/layers[i])
            b = np.zeros((layers[i+1], 1))
            self.weights.append(w)
            self.biases.append(b)

    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 backward(self, x, y, learning_rate):
        # 反向传播
        # 保存各层激活值
        activations = [x]
        zs = []

        # 前向传播
        a = x
        for w, b in zip(self.weights, self.biases):
            z = np.dot(w, a) + b
            zs.append(z)
            a = self.sigmoid(z)
            activations.append(a)

        # 计算输出层误差
        delta = (activations[-1] - y) * self.sigmoid_derivative(zs[-1])

        # 更新权重和偏置
        for l in range(len(self.weights)-1, -1, -1):
            # 计算梯度
            dw = np.dot(delta, activations[l].T)
            db = delta

            # 更新参数
            self.weights[l] -= learning_rate * dw
            self.biases[l] -= learning_rate * db

            # 如果不是第一层,计算前一层的误差
            if l > 0:
                delta = np.dot(self.weights[l].T, delta) * self.sigmoid_derivative(zs[l-1])

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

    def sigmoid_derivative(self, z):
        s = self.sigmoid(z)
        return s * (1-s)

实际应用注意事项

  1. 学习率选择
  2. 太大可能导致震荡
  3. 太小收敛缓慢
  4. 可以使用学习率衰减策略

  5. 梯度消失 / 爆炸

  6. 使用 ReLU 等激活函数缓解
  7. 采用批标准化
  8. 使用残差连接

  9. 激活函数选择

  10. Sigmoid 容易导致梯度消失
  11. ReLU 计算简单但可能有 ” 死亡神经元 ” 问题
  12. Leaky ReLU 是较好的折中方案

思考题

  1. 如何改进基础 BP 算法来加速收敛?
  2. 引入动量项
  3. 使用自适应学习率方法 (如 Adam)

  4. 批量训练与在线训练的利弊分析

  5. 批量训练更稳定但计算量大
  6. 在线训练可以实时更新但波动较大
  7. 小批量训练是常用折中方案

通过这篇文章,相信你已经对 BP 神经网络的工作原理有了深入理解。在实际应用中,建议从简单的网络结构开始,逐步增加复杂度,并注意监控训练过程中的损失和准确率变化。

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