BP神经网络结构图解析:从数学原理到Python实现

1次阅读
没有评论

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

image.webp

1. 认识 BP 神经网络基础结构

先看最简单的三层网络示意图(输入层 - 隐藏层 - 输出层):

BP 神经网络结构图解析:从数学原理到 Python 实现

输入层(x)      隐藏层(h)      输出层(y)
○---w1--->○---w2--->○
○---w1--->○---w2--->○ 
○---w1--->○---w2--->○
  • 维度关系:若输入 3 个特征,隐藏层 2 个神经元,输出 1 个值,则:
  • w1.shape = (3,2)
  • w2.shape = (2,1)
  • 前向传播公式:
    $$h = \sigma(x \cdot w1 + b1)$$
    $$y = \sigma(h \cdot w2 + b2)$$

2. 数学推导:误差是如何反向传播的?

以均方误差损失函数为例:
$$L = \frac{1}{2}(y_{true} – y_{pred})^2$$

关键推导步骤:
1. 输出层权重梯度:
$$\frac{\partial L}{\partial w2} = \underbrace{-(y_{true}-y)}{\text{误差项}} \cdot \underbrace{\sigma'(z2)}$$}} \cdot \underbrace{h}_{\text{前一层的输出}

  1. 隐藏层权重梯度(链式法则典型应用):
    $$\frac{\partial L}{\partial w1} = \frac{\partial L}{\partial y} \cdot \frac{\partial y}{\partial h} \cdot \frac{\partial h}{\partial w1}$$

3. Python 实现核心代码

import numpy as np

# 激活函数与导数
def sigmoid(x):
    return 1 / (1 + np.exp(-x))

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

# 网络初始化
input_size = 3
hidden_size = 2 
output_size = 1
w1 = np.random.randn(input_size, hidden_size) * 0.01
w2 = np.random.randn(hidden_size, output_size) * 0.01

# 前向传播
def forward(x):
    h = sigmoid(np.dot(x, w1))
    y = sigmoid(np.dot(h, w2))
    return h, y

# 反向传播
def backward(x, y_true, h, y, lr=0.1):
    # 输出层误差
    dy = (y - y_true) * sigmoid_derivative(y)
    grad_w2 = np.dot(h.T, dy)

    # 隐藏层误差
    dh = np.dot(dy, w2.T) * sigmoid_derivative(h)
    grad_w1 = np.dot(x.T, dh)

    # 更新权重
    w2 -= lr * grad_w2
    w1 -= lr * grad_w1

4. 性能优化实战技巧

训练策略选择

  • 批量训练:更稳定的梯度方向,适合 GPU 并行
  • 在线训练:更快响应数据变化,适合流式数据

超参数设置经验

  • 隐藏层神经元数量参考公式:
    $$N_{hidden} = \sqrt{N_{input} \cdot N_{output}} + \alpha$$
    (α 通常取 10-20)

梯度检查实现(调试必备)

def gradient_check(x, y_true, eps=1e-7):
    _, y = forward(x)
    original_loss = 0.5 * (y_true - y)**2

    # 检查 w2 的梯度
    numeric_grad = np.zeros_like(w2)
    for i in range(w2.shape[0]):
        for j in range(w2.shape[1]):
            w2[i,j] += eps
            _, y_perturb = forward(x)
            perturb_loss = 0.5 * (y_true - y_perturb)**2
            numeric_grad[i,j] = (perturb_loss - original_loss) / eps
            w2[i,j] -= eps  # 恢复

    # 与反向传播结果对比
    print("数值梯度:", numeric_grad)
    print("解析梯度:", grad_w2)

5. 新手避坑指南

数据预处理

  • 标准化 :将输入缩放到[-1,1] 或[0,1]范围
    X = (X - np.mean(X, axis=0)) / np.std(X, axis=0)

权重初始化

  • Xavier 初始化(适合 Sigmoid):
    $$W \sim U(-\sqrt{6/(n_{in}+n_{out})}, \sqrt{6/(n_{in}+n_{out})})$$

学习率调参

  • 损失曲线震荡 → 学习率过大
  • 收敛速度过慢 → 学习率过小
  • 推荐初始值:0.01-0.1

6. 拓展思考

  1. 多分类改造:
  2. 输出层改用 Softmax
  3. 损失函数换成交叉熵

  4. 激活函数对比:

  5. ReLU 在反向传播时梯度为 1 或 0,缓解梯度消失
  6. Sigmoid 容易饱和导致梯度消失

建议尝试:用相同的网络结构,仅替换激活函数,观察训练收敛速度差异

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