共计 2352 个字符,预计需要花费 6 分钟才能阅读完成。
神经网络基础概念
在开始讨论 BP 神经网络之前,我们先了解一下神经网络的基本结构。神经网络是一种模仿人脑神经元连接方式的计算模型,它由多个层次组成:输入层、隐藏层和输出层。输入层接收原始数据,隐藏层负责特征提取和转换,输出层给出最终结果。

正向传播的数学推导
正向传播是指数据从输入层流向输出层的过程。在这个过程中,每一层的神经元都会对前一层的输出进行加权求和,并通过激活函数进行非线性转换。
- 加权求和 :对于第 l 层的第 j 个神经元,其输入为前一层的输出与权重的乘积之和加上偏置。数学表达式为:
z_j^l = \sum_{i} w_{ji}^l a_i^{l-1} + b_j^l
- 激活函数计算 :激活函数引入非线性,使神经网络能够拟合复杂函数。常用的激活函数有 Sigmoid、ReLU 和 Tanh。数学表达式为:
a_j^l = \sigma(z_j^l)
反向传播算法
反向传播是通过计算损失函数的梯度来调整网络权重和偏置的过程。它主要包括以下步骤:
-
损失函数计算 :损失函数衡量预测值与真实值之间的差距。常用的损失函数有均方误差(MSE)和交叉熵(Cross-Entropy)。
-
梯度下降 :通过计算损失函数对权重和偏置的梯度,沿着梯度的反方向更新参数,以最小化损失函数。数学表达式为:
w_{ji}^l = w_{ji}^l - \eta \frac{\partial L}{\partial w_{ji}^l}
- 链式法则 :反向传播的核心是链式法则,用于计算梯度。对于输出层的梯度:
\delta_j^L = \frac{\partial L}{\partial a_j^L} \sigma'(z_j^L)
对于隐藏层的梯度:
\delta_j^l = \sum_k w_{kj}^{l+1} \delta_k^{l+1} \sigma'(z_j^l)
Python 实现代码
下面是一个使用 NumPy 实现的 BP 神经网络的简单示例,用于解决一个二分类问题。
import numpy as np
class NeuralNetwork:
def __init__(self, input_size, hidden_size, output_size):
self.weights1 = np.random.randn(input_size, hidden_size)
self.weights2 = np.random.randn(hidden_size, output_size)
self.bias1 = np.zeros(hidden_size)
self.bias2 = np.zeros(output_size)
def sigmoid(self, x):
return 1 / (1 + np.exp(-x))
def sigmoid_derivative(self, x):
return x * (1 - x)
def forward(self, X):
self.hidden = self.sigmoid(np.dot(X, self.weights1) + self.bias1)
self.output = self.sigmoid(np.dot(self.hidden, self.weights2) + self.bias2)
return self.output
def backward(self, X, y, output, learning_rate):
output_error = y - output
output_delta = output_error * self.sigmoid_derivative(output)
hidden_error = np.dot(output_delta, self.weights2.T)
hidden_delta = hidden_error * self.sigmoid_derivative(self.hidden)
self.weights2 += learning_rate * np.dot(self.hidden.T, output_delta)
self.bias2 += learning_rate * np.sum(output_delta, axis=0)
self.weights1 += learning_rate * np.dot(X.T, hidden_delta)
self.bias1 += learning_rate * np.sum(hidden_delta, axis=0)
def train(self, X, y, epochs, learning_rate):
for epoch in range(epochs):
output = self.forward(X)
self.backward(X, y, output, learning_rate)
if epoch % 1000 == 0:
loss = np.mean(np.square(y - output))
print(f'Epoch {epoch}, Loss: {loss}')
# 示例数据
X = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y = np.array([[0], [1], [1], [0]])
# 创建并训练网络
nn = NeuralNetwork(2, 4, 1)
nn.train(X, y, 10000, 0.1)
避坑指南
-
梯度消失 / 爆炸 :当梯度值过小或过大时,会导致训练不稳定。解决方法包括使用 ReLU 激活函数、梯度裁剪和批归一化。
-
学习率选择 :学习率过大可能导致震荡,过小则收敛慢。可以使用学习率衰减或自适应优化器如 Adam。
-
激活函数选择 :不同激活函数适用于不同场景。Sigmoid 适合输出层,ReLU 适合隐藏层,Tanh 在中间层表现良好。
思考题
- 如何改进基础 BP 算法提高收敛速度?
- 批量训练与在线训练的优劣比较?
- 不同优化器(如 Adam)的实现原理是什么?
希望通过这篇文章,你能对 BP 神经网络的正向传播和反向传播有一个清晰的理解,并能够动手实现一个简单的神经网络模型。
正文完
