共计 3788 个字符,预计需要花费 10 分钟才能阅读完成。
前馈神经网络简介
前馈神经网络(Feedforward Neural Network)是深度学习中最基础的网络结构之一,它的数据流向是单向的,从输入层经过隐藏层最终到达输出层。这种网络结构在图像分类、语音识别、推荐系统等领域有着广泛的应用。

相比于更复杂的网络结构(如 CNN、RNN),前馈神经网络结构简单,非常适合初学者理解神经网络的基本原理和工作机制。
3 层 vs 5 层网络性能对比
-
表达能力差异:理论上,5 层网络比 3 层网络具有更强的函数逼近能力。根据通用近似定理,具有单个隐藏层的网络就能近似任何函数,但更深的网络可以用更少的神经元达到相同的近似效果。
-
训练难度增加:
- 梯度消失问题:在深层网络中,反向传播时梯度会逐层衰减,导致前面层参数更新缓慢
- 训练时间更长:更多层意味着更多参数和更长的计算时间
-
更容易过拟合:模型复杂度增加可能导致对训练数据的过度拟合
-
实际表现:对于简单任务,3 层网络可能就足够;但对于复杂任务,5 层网络通常能获得更好的性能。
PyTorch 实现 5 层全连接网络
网络结构定义
import torch
import torch.nn as nn
import torch.nn.init as init
class FiveLayerNN(nn.Module):
def __init__(self, input_size, hidden_size, output_size):
super(FiveLayerNN, self).__init__()
# 输入层到第一隐藏层
self.fc1 = nn.Linear(input_size, hidden_size)
# 隐藏层之间连接
self.fc2 = nn.Linear(hidden_size, hidden_size)
self.fc3 = nn.Linear(hidden_size, hidden_size)
# 最后一层到输出层
self.fc4 = nn.Linear(hidden_size, output_size)
# 初始化权重
self.init_weights()
# ReLU 激活函数
self.relu = nn.ReLU()
def init_weights(self):
# Xavier/Glorot 初始化
for m in self.modules():
if isinstance(m, nn.Linear):
init.xavier_uniform_(m.weight)
init.zeros_(m.bias)
def forward(self, x):
x = self.relu(self.fc1(x))
x = self.relu(self.fc2(x))
x = self.relu(self.fc3(x))
x = self.fc4(x) # 输出层通常不加激活函数
return x
维度设计说明
-
输入层维度:取决于你的数据特征数量。例如,对于 MNIST 手写数字识别,输入维度是 784(28×28 像素展开)。
-
隐藏层维度:通常选择 2 的幂次方(如 64、128、256 等),这是为了 GPU 计算效率。隐藏层之间通常保持相同维度。
-
输出层维度:由任务决定。分类任务中等于类别数,回归任务中等于输出变量数。
完整训练流程
数据准备
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
# 数据转换
transform = transforms.Compose([transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,))
])
# 加载 MNIST 数据集
train_dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
test_dataset = datasets.MNIST(root='./data', train=False, download=True, transform=transform)
# 创建数据加载器
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)
训练循环
import matplotlib.pyplot as plt
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = FiveLayerNN(784, 256, 10).to(device)
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
# 记录训练过程
train_losses = []
test_accuracies = []
epochs = 10
for epoch in range(epochs):
model.train()
running_loss = 0.0
for images, labels in train_loader:
images = images.view(-1, 784).to(device)
labels = labels.to(device)
# 前向传播
outputs = model(images)
loss = criterion(outputs, labels)
# 反向传播和优化
optimizer.zero_grad()
loss.backward()
optimizer.step()
running_loss += loss.item()
# 记录训练损失
train_loss = running_loss / len(train_loader)
train_losses.append(train_loss)
# 验证集评估
model.eval()
correct = 0
total = 0
with torch.no_grad():
for images, labels in test_loader:
images = images.view(-1, 784).to(device)
labels = labels.to(device)
outputs = model(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
accuracy = 100 * correct / total
test_accuracies.append(accuracy)
print(f'Epoch [{epoch+1}/{epochs}], Loss: {train_loss:.4f}, Accuracy: {accuracy:.2f}%')
# 可视化训练过程
plt.figure(figsize=(12, 4))
plt.subplot(1, 2, 1)
plt.plot(train_losses, label='Training Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.subplot(1, 2, 2)
plt.plot(test_accuracies, label='Test Accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy (%)')
plt.legend()
plt.show()
避坑指南
学习率设置
-
常见问题:学习率太大导致震荡不收敛,太小导致训练过慢
-
经验值:
- Adam 优化器:1e- 3 到 1e-5
- SGD 优化器:0.1 到 0.001
-
可以先用一个中等值(如 0.001),观察训练情况再调整
-
学习率调度 :可以使用
torch.optim.lr_scheduler实现动态调整
Batch Size 选择
- 大 Batch Size(如 256+):
- 训练更稳定
- 计算效率更高
-
可能收敛到较差的局部最优
-
小 Batch Size(如 32-64):
- 引入更多噪声,可能有助于找到更好的解
- 需要更小的学习率
-
训练时间更长
-
建议:从 64 或 128 开始尝试,根据 GPU 内存调整
过拟合应对
-
识别过拟合:训练准确率远高于验证准确率
-
解决方法:
- 增加数据量(数据增强)
- 使用 Dropout 层
- L2 正则化(权重衰减)
- 早停(Early Stopping)
-
减少网络复杂度
-
Dropout 实现:
self.dropout = nn.Dropout(0.5) # 添加到__init__中 # 在 forward 中使用 x = self.dropout(self.relu(self.fc1(x)))
进阶思考
-
尝试在不同隐藏层使用不同大小的神经元数量,观察对性能的影响
-
将 ReLU 激活函数替换为 LeakyReLU 或 Sigmoid,比较训练效果
-
实验不同的权重初始化方法(如 Kaiming 初始化),分析收敛速度的变化
总结
通过本文,我们系统地学习了 5 层全连接前馈神经网络的原理和实现。从网络结构设计、PyTorch 实现到训练技巧,涵盖了构建深度神经网络的关键知识点。虽然全连接网络在图像等结构化数据上不如 CNN 高效,但它仍然是理解深度学习基础的重要模型。希望读者能通过实践加深理解,并尝试将其应用到自己的项目中。
