共计 2542 个字符,预计需要花费 7 分钟才能阅读完成。
神经网络基础概念
神经网络是模拟生物神经元连接方式的计算模型。最简单的神经网络形式是感知机(Perceptron),它由输入层和输出层组成,只能解决线性可分问题。而多层神经网络(如 BP 神经网络)通过引入隐藏层和非线性激活函数,能够学习复杂的非线性关系。

- 感知机局限 :无法解决异或(XOR) 等非线性问题
- 多层网络优势:通过隐藏层组合特征,理论上可逼近任何连续函数
- 激活函数作用:引入非线性,常见的有 Sigmoid、ReLU、Tanh 等
BP 算法数学推导
前向传播
前向传播是数据从输入层流向输出层的过程:
- 输入层接收特征向量 $x$
- 隐藏层计算:$h = \sigma(W_1x + b_1)$,其中 $\sigma$ 是激活函数
- 输出层计算:$\hat{y} = \sigma(W_2h + b_2)$
损失函数
常用均方误差 (MSE) 作为损失函数:
$L = \frac{1}{2}(y – \hat{y})^2$
对于分类问题,常用交叉熵损失:
$L = -[y\ln\hat{y} + (1-y)\ln(1-\hat{y})]$
反向传播推导
反向传播通过链式法则计算梯度:
-
输出层梯度:
$\frac{\partial L}{\partial W_2} = \frac{\partial L}{\partial \hat{y}}\frac{\partial \hat{y}}{\partial z_2}\frac{\partial z_2}{\partial W_2}$
其中 $z_2 = W_2h + b_2$ -
隐藏层梯度:
$\frac{\partial L}{\partial W_1} = \frac{\partial L}{\partial h}\frac{\partial h}{\partial z_1}\frac{\partial z_1}{\partial W_1}$
其中 $z_1 = W_1x + b_1$
权重更新
使用梯度下降更新参数:
$W \leftarrow W – \eta \frac{\partial L}{\partial W}$
其中 $\eta$ 是学习率。
Python 实现
import numpy as np
class NeuralNetwork:
def __init__(self, input_size, hidden_size, output_size):
# 初始化权重
self.W1 = np.random.randn(input_size, hidden_size) * 0.01
self.b1 = np.zeros((1, hidden_size))
self.W2 = np.random.randn(hidden_size, output_size) * 0.01
self.b2 = np.zeros((1, output_size))
def sigmoid(self, x):
return 1 / (1 + np.exp(-x))
def forward(self, X):
# 前向传播
self.z1 = np.dot(X, self.W1) + self.b1
self.h = self.sigmoid(self.z1)
self.z2 = np.dot(self.h, self.W2) + self.b2
self.y_hat = self.sigmoid(self.z2)
return self.y_hat
def backward(self, X, y, learning_rate):
# 反向传播
m = X.shape[0]
# 输出层梯度
dL_dy_hat = -(y - self.y_hat)
dy_hat_dz2 = self.y_hat * (1 - self.y_hat)
dz2_dW2 = self.h
dL_dW2 = np.dot(dz2_dW2.T, dL_dy_hat * dy_hat_dz2) / m
dL_db2 = np.sum(dL_dy_hat * dy_hat_dz2, axis=0, keepdims=True) / m
# 隐藏层梯度
dL_dh = np.dot(dL_dy_hat * dy_hat_dz2, self.W2.T)
dh_dz1 = self.h * (1 - self.h)
dz1_dW1 = X
dL_dW1 = np.dot(dz1_dW1.T, dL_dh * dh_dz1) / m
dL_db1 = np.sum(dL_dh * dh_dz1, axis=0, keepdims=True) / m
# 更新权重
self.W2 -= learning_rate * dL_dW2
self.b2 -= learning_rate * dL_db2
self.W1 -= learning_rate * dL_dW1
self.b1 -= learning_rate * dL_db1
def train(self, X, y, epochs, learning_rate):
for i in range(epochs):
y_hat = self.forward(X)
self.backward(X, y, learning_rate)
loss = np.mean((y - y_hat)**2)
if i % 100 == 0:
print(f'Epoch {i}, Loss: {loss}')
# MNIST 示例
# 这里省略数据加载和预处理代码
# nn = NeuralNetwork(784, 128, 10)
# nn.train(X_train, y_train, 1000, 0.1)
关键问题讨论
学习率选择
- 太大:可能导致震荡甚至发散
- 太小:收敛速度过慢
- 解决方案:使用学习率衰减或自适应优化器(Adam)
梯度消失
深层网络中梯度可能指数级减小:
- 原因:Sigmoid 导数最大值为 0.25,多次连乘后梯度趋近 0
- 解决方案:使用 ReLU 激活函数、残差连接、批归一化
过拟合
模型在训练集表现好但泛化能力差:
- 解决方案:
- 增加训练数据
- 使用 L1/L2 正则化
- Dropout 技术
- 早停(Early Stopping)
避坑指南
- 初始化问题:权重初始化为小随机数,避免全零初始化
- 输入归一化:将特征缩放到相似范围(如 0 -1)
- 梯度检查:实现反向传播后,使用数值梯度验证
- 损失不下降:检查学习率、网络结构、数据预处理
- 输出饱和:Sigmoid 输出接近 0 / 1 时梯度很小,可尝试交叉熵损失
总结
BP 神经网络通过前向传播和反向传播的交替进行实现参数学习。理解其数学本质有助于调试网络和解决实际问题。虽然现在有更先进的网络结构,但 BP 算法仍然是深度学习的基础。建议读者从简单网络开始,逐步增加复杂度,在实践中积累经验。
