共计 3066 个字符,预计需要花费 8 分钟才能阅读完成。
神经网络入门实战指南
作为 AI 领域的经典入门教程,Andrej Karpathy 的 ”Neural Networks: Zero to Hero” 系列以独特的教学视角帮助无数开发者跨入深度学习大门。本文将结合 PyTorch 框架,带大家用代码实现第一个能识别手写数字的神经网络。

一、神经网络核心概念速览
在开始写代码前,我们需要理解三个基本概念:
- 前向传播:数据从输入层流向输出层的过程,就像用公式计算预测值
- 反向传播:根据预测误差反向调整网络参数的神奇算法
- 损失函数:衡量预测结果与真实值差异的 ” 打分器 ”
用一个简单类比:神经网络就像学习骑自行车——前向传播是尝试骑行,损失函数是判断是否保持平衡,反向传播则是调整身体姿势的过程。
二、用 PyTorch 搭建第一个网络
让我们用经典的 MNIST 手写数字数据集实战。先准备好开发环境:
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
import matplotlib.pyplot as plt
数据预处理
好的数据准备是成功的一半:
transform = transforms.Compose([transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,))
])
train_set = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
train_loader = torch.utils.data.DataLoader(train_set, batch_size=64, shuffle=True)
定义网络结构
构建一个包含两个隐藏层的神经网络:
class SimpleNN(nn.Module):
def __init__(self):
super(SimpleNN, self).__init__()
self.fc1 = nn.Linear(28*28, 128) # 第一层:784 输入 -> 128 输出
self.fc2 = nn.Linear(128, 64) # 第二层:128 输入 -> 64 输出
self.fc3 = nn.Linear(64, 10) # 输出层:64 输入 -> 10 分类
def forward(self, x):
x = x.view(-1, 28*28) # 展平图片
x = torch.relu(self.fc1(x))
x = torch.relu(self.fc2(x))
x = self.fc3(x)
return x
训练循环实现
完整的训练流程包含以下步骤:
- 初始化模型和优化器
- 定义损失函数
- 前向传播计算预测值
- 反向传播更新权重
- 循环执行直到收敛
model = SimpleNN()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)
for epoch in range(10):
running_loss = 0.0
for images, labels in train_loader:
optimizer.zero_grad()
outputs = model(images)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
print(f'Epoch {epoch+1}, Loss: {running_loss/len(train_loader):.4f}')
三、模型评估与可视化
训练完成后,我们可以用测试集评估模型表现:
test_set = datasets.MNIST(root='./data', train=False, download=True, transform=transform)
test_loader = torch.utils.data.DataLoader(test_set, batch_size=64, shuffle=False)
correct = 0
total = 0
with torch.no_grad():
for images, labels in test_loader:
outputs = model(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print(f'Accuracy: {100 * correct / total:.2f}%')
可视化部分预测结果:
# 随机选取测试样本
images, labels = next(iter(test_loader))
outputs = model(images)
_, predicted = torch.max(outputs, 1)
# 绘制前 16 个样本
fig = plt.figure(figsize=(10,10))
for idx in range(16):
ax = fig.add_subplot(4, 4, idx+1)
ax.imshow(images[idx].numpy().squeeze(), cmap='gray')
ax.set_title(f'Pred: {predicted[idx]} | True: {labels[idx]}')
ax.axis('off')
plt.tight_layout()
plt.show()
四、常见问题解决方案
1. 梯度消失问题
- 症状:模型无法学习,损失几乎不下降
- 解决:使用 ReLU 激活函数,合理初始化权重
2. 过拟合问题
- 症状:训练集表现好但测试集差
- 解决:添加 Dropout 层,使用 L2 正则化
改进后的网络结构示例:
class ImprovedNN(nn.Module):
def __init__(self):
super(ImprovedNN, self).__init__()
self.fc1 = nn.Linear(28*28, 256)
self.dropout1 = nn.Dropout(0.5)
self.fc2 = nn.Linear(256, 128)
self.dropout2 = nn.Dropout(0.3)
self.fc3 = nn.Linear(128, 10)
def forward(self, x):
x = x.view(-1, 28*28)
x = torch.relu(self.fc1(x))
x = self.dropout1(x)
x = torch.relu(self.fc2(x))
x = self.dropout2(x)
x = self.fc3(x)
return x
五、进阶学习建议
- 扩展实验:
- 尝试不同的网络结构(增加 / 减少层数)
- 调整学习率观察训练效果变化
-
用其他数据集(如 FashionMNIST)测试模型泛化能力
-
推荐资源:
- Andrej Karpathy 原版视频教程
- 《Deep Learning with PyTorch》官方书籍
-
PyTorch 官方文档和教程案例
-
调试技巧:
- 使用 torchsummary 打印网络结构
- 在训练循环中添加验证集评估
- 使用 TensorBoard 可视化训练过程
结语
通过这个简单的 MNIST 分类任务,我们走完了神经网络从数据准备到模型训练的全流程。虽然现在的模型还很基础,但已经包含了深度学习的核心要素。建议读者在理解这些基础后,继续探索卷积神经网络 (CNN) 等更强大的模型结构。记住,在 AI 领域,持续的动手实践是最好的学习方式!
正文完
