共计 2438 个字符,预计需要花费 7 分钟才能阅读完成。
神经网络基础与实现意义
神经网络作为深度学习的核心架构,其通过多层非线性变换实现复杂函数的逼近能力。理解前向传播、反向传播的数学原理和代码实现,是掌握深度学习的关键基础。本文将从零开始实现一个双层神经网络,涵盖矩阵运算、梯度计算和参数更新全过程,帮助读者建立对神经网络工作机制的直观认知。

技术实现详解
1. 前向传播实现
前向传播本质是逐层的矩阵乘法与激活函数变换。以下是用 NumPy 实现的全连接层示例:
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.a1 = self.sigmoid(self.z1)
# 第二层计算
self.z2 = np.dot(self.a1, self.W2) + self.b2
self.a2 = self.sigmoid(self.z2)
return self.a2
关键点说明:
- 矩阵乘法使用
np.dot实现维度变换 - Sigmoid 激活函数将线性变换转为非线性
- 每层输出保留为类变量,供反向传播使用
2. 反向传播推导
反向传播通过链式法则计算损失函数对参数的梯度。以均方误差损失为例:
-
输出层梯度计算:
$$\frac{\partial L}{\partial z_2} = (a_2 – y) \odot \sigma'(z_2)$$ -
隐藏层梯度计算:
$$\frac{\partial L}{\partial W_2} = a_1^T \frac{\partial L}{\partial z_2}$$
$$\frac{\partial L}{\partial a_1} = \frac{\partial L}{\partial z_2} W_2^T$$
$$\frac{\partial L}{\partial z_1} = \frac{\partial L}{\partial a_1} \odot \sigma'(z_1)$$
代码实现:
def backward(self, X, y, output):
m = X.shape[0] # 样本数量
# 输出层梯度
dZ2 = (output - y) * self.sigmoid(self.z2) * (1 - self.sigmoid(self.z2))
dW2 = np.dot(self.a1.T, dZ2) / m
db2 = np.sum(dZ2, axis=0, keepdims=True) / m
# 隐藏层梯度
dA1 = np.dot(dZ2, self.W2.T)
dZ1 = dA1 * self.sigmoid(self.z1) * (1 - self.sigmoid(self.z1))
dW1 = np.dot(X.T, dZ1) / m
db1 = np.sum(dZ1, axis=0, keepdims=True) / m
return dW1, db1, dW2, db2
3. 参数更新与训练
使用随机梯度下降 (SGD) 更新参数:
def update_params(self, grads, learning_rate=0.1):
dW1, db1, dW2, db2 = grads
self.W1 -= learning_rate * dW1
self.b1 -= learning_rate * db1
self.W2 -= learning_rate * dW2
self.b2 -= learning_rate * db2
完整训练流程:
def train(self, X, y, epochs=1000, lr=0.1):
for epoch in range(epochs):
# 前向传播
output = self.forward(X)
# 计算损失(均方误差)loss = np.mean((output - y) ** 2)
# 反向传播
grads = self.backward(X, y, output)
# 参数更新
self.update_params(grads, lr)
if epoch % 100 == 0:
print(f'Epoch {epoch}, Loss: {loss:.4f}')
实践陷阱与解决方案
1. 梯度消失 / 爆炸
现象:深层网络训练时梯度指数级减小或增大
解决方案:
- 使用 ReLU 等修正激活函数
- 采用 Xavier/Glorot 初始化
- 添加梯度裁剪(gradient clipping)
2. 参数初始化
错误示例:全零初始化会导致对称性问题
推荐方法:
# Xavier 初始化(适合 Sigmoid/Tanh)self.W1 = np.random.randn(input_size, hidden_size) / np.sqrt(input_size)
# He 初始化(适合 ReLU)self.W1 = np.random.randn(input_size, hidden_size) * np.sqrt(2/input_size)
3. 学习率调整
静态学习率的改进方案:
# 指数衰减
learning_rate = 0.1 * (0.95 ** epoch)
# 阶梯衰减
if epoch % 100 == 0:
learning_rate *= 0.5
思考与扩展
- 批量训练实现:修改前向 / 反向传播中的矩阵运算维度,支持 mini-batch 输入
- 激活函数对比:ReLU 的梯度计算为
dZ = dA * (Z > 0),避免 Sigmoid 的梯度饱和 - L2 正则化:在损失函数中添加
0.5 * reg * (np.sum(W1**2) + np.sum(W2**2)),梯度计算相应增加reg * W1项
正文完
