共计 1477 个字符,预计需要花费 4 分钟才能阅读完成。
为什么需要多层神经网络?
单层感知机(Perceptron)的局限性在于它只能解决线性可分问题。例如,它无法处理异或(XOR)这样简单的非线性问题。多层神经网络通过引入隐藏层和非线性激活函数,能够学习更复杂的模式。

反向传播的数学原理
反向传播的核心是链式法则。我们以均方误差(MSE)作为损失函数,Sigmoid 作为激活函数,推导权重更新的过程。
-
定义损失函数 :
[E = \frac{1}{2} \sum_{k}(y_k – t_k)^2]
其中,(y_k) 是输出层的第 k 个神经元的输出,(t_k) 是对应的目标值。 -
输出层的梯度计算 :
[\frac{\partial E}{\partial w_{jk}} = \frac{\partial E}{\partial y_k} \cdot \frac{\partial y_k}{\partial z_k} \cdot \frac{\partial z_k}{\partial w_{jk}}]
其中,(z_k) 是加权输入。 -
隐藏层的梯度计算 :
类似地,隐藏层的梯度需要通过链式法则从输出层反向传播:
[\frac{\partial E}{\partial w_{ij}} = \frac{\partial E}{\partial h_j} \cdot \frac{\partial h_j}{\partial z_j} \cdot \frac{\partial z_j}{\partial w_{ij}}]
Python 实现
以下是使用 NumPy 实现的一个简单反向传播示例:
import numpy as np
# Sigmoid 激活函数
def sigmoid(x):
return 1 / (1 + np.exp(-x))
# 均方误差损失函数
def mse_loss(y_true, y_pred):
return np.mean((y_true - y_pred) ** 2)
# 初始化权重
input_size = 2
hidden_size = 3
output_size = 1
W1 = np.random.randn(input_size, hidden_size)
W2 = np.random.randn(hidden_size, output_size)
# 前向传播
def forward(X):
z1 = np.dot(X, W1)
h = sigmoid(z1)
z2 = np.dot(h, W2)
y = sigmoid(z2)
return y, h
# 反向传播
def backward(X, y_true, y_pred, h):
# 输出层梯度
dE_dy = y_pred - y_true
dy_dz2 = y_pred * (1 - y_pred)
dz2_dW2 = h
# 隐藏层梯度
dz2_dh = W2
dh_dz1 = h * (1 - h)
dz1_dW1 = X
# 更新权重
global W1, W2
W2 -= learning_rate * np.dot(h.T, dE_dy * dy_dz2)
W1 -= learning_rate * np.dot(X.T, np.dot(dE_dy * dy_dz2, dz2_dh.T) * dh_dz1)
避坑指南
-
梯度消失问题 :
Sigmoid 激活函数在输入值较大或较小时梯度接近于 0,导致梯度消失。可以通过使用 ReLU 激活函数或批归一化(Batch Normalization)来缓解。 -
学习率设置 :
学习率过大可能导致震荡,过小则收敛缓慢。建议从 0.01 开始尝试,逐步调整。 -
权重初始化 :
权重初始化为 0 会导致所有神经元更新相同。通常使用随机初始化,如 Xavier 初始化。
思考题
- 如何用 ReLU 激活函数修改本代码?
- 批量训练与在线训练的梯度计算差异是什么?
希望这篇内容能帮助你理解反向传播的原理和实现。如果有任何问题,欢迎在评论区讨论!
