可以学习如下内容:
• 介绍神经网络核心组件。
• 如何构建一个神经网络。
• 详细介绍如何构建一个神经网络。
• 如何使用nn模块中Module及functional。
• 如何选择优化器。
• 动态修改学习率参数。
5.1 核心组件
神经网络核心组件不多,把这些组件确定后,这个神经网络基本就确定了。这些核心组件包括:
1)层:神经网络的基本结构,将输入张量转换为输出张量。
2)模型:层构成的网络。
3)损失函数:参数学习的目标函数,通过最小化损失函数来学习各种参数。
4)优化器:如何使损失函数最小,这就涉及优化器。
多个层链接在一起构成一个模型或网络,输入数据通过这个模型转换为预测值,然后损失函数把预测值与真实值进行比较,得到损失值(损失值可以是距离、概率值等),该损失值用于衡量预测值与目标结果的匹配或相似程度,优化器利用损失值更新权重参数,从而使损失值越来越小。这是一个循环过程,当损失值达到一个阀值或循环次数到达指定次数,循环结束。接下来利用PyTorch的nn工具箱,构建一个神经网络实例。nn中对这些组件都有现成包或类,可以直接使用,非常方便。
------------------------------实现神经网络实例
构建网络层可以基于Module类,或函数(nn.functional)。
nn.Module中的大多数层(Layer)在functional中都有与之对应的函数。
nn.functional中函数与nn.Module中的Layer的主要区别是后者继承Module类,会自动提取可学习的参数。
而nn.functional更像是纯函数。
两者功能相同,且性能也没有很大区别,那么如何选择呢?像卷积层、全连接层、Dropout层等因含有可学习参数,一般使用nn.Module,而激活函数、池化层不含可学习参数,可以使用nn.functional中对应的函数。
下面通过实例来说明如何使用nn构建一个网络模型。
这节将利用神经网络完成对手写数字进行识别的实例,来说明如何借助nn工具箱来实现一个神经网络,并对神经网络有个直观了解。在这个基础上,后续我们将对nn的各模块进行详细介绍。实例环境使用PyTorch1.0+,GPU或CPU,源数据集为MNIST。
主要步骤:
1)利用PyTorch内置函数mnist下载数据。
2)利用torchvision对数据进行预处理,调用torch.utils建立一个数据迭代器。
3)可视化源数据。
4)利用nn工具箱构建神经网络模型。
5)实例化模型,并定义损失函数及优化器。
6)训练模型。
7)可视化结果。

import numpy as np
import torch
from torchvision.datasets import mnist
#导入预处理模块
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
#导入nn及优化器
import torch.nn.functional as F
import torch.optim as optim
from torch import nn
接下来,定义一些超参数
train_batch_size=64
test_batch_size=128
learning_rate=0.01
num_epoches=20
lr=0.01
momentum=0.5
下载数据并对数据进行预处理
#定义预处理函数,这些预处理依次放在Compose函数中。
transform = transforms.Compose([transforms.ToTensor(),
transforms.Normalize([0.5], [0.5])])
#下载数据,并对数据进行预处理
train_dataset = mnist.MNIST('./data', train=True, transform=transform, download=True)
test_dataset = mnist.MNIST('./data', train=False, transform=transform)
#dataloader是一个可迭代对象,可以使用迭代器一样使用。
train_loader = DataLoader(train_dataset, batch_size=train_batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=test_batch_size, shuffle=False)
-
transforms.Compose
:Compose
是 PyTorch 中的一个工具,用于将多个预处理操作组合在一起,依次执行。
-
transforms.ToTensor()
:- 将 PIL 图像或 NumPy 数组转换为 PyTorch 张量(Tensor)。
- 同时会将图像的像素值从
[0, 255]
转换到[0, 1]
的范围。
-
transforms.Normalize([0.5], [0.5])
:- 对张量进行归一化处理。
- 归一化的公式是:
output = (input - mean) / std
。 - 这里的参数
[0.5]
表示均值(mean),[0.5]
表示标准差(std)。 - 因此,归一化后数据的范围会从
[0, 1]
变为[-1, 1]
-
DataLoader
是 PyTorch 提供的一个工具,用于将数据集分批加载,并支持多线程、打乱顺序等功能。
- 参数解释 :
train_dataset
和test_dataset
: 分别指定训练集和测试集。batch_size
: 每次加载的数据批量大小。train_batch_size
和test_batch_size
应该在代码其他地方定义。shuffle=True
: 是否在每个 epoch 开始时打乱数据顺序。通常在训练集上设置为True
,以增加模型的泛化能力。shuffle=False
: 测试集一般不需要打乱顺序。
------------------------------------------可视化源数据
import matplotlib.pyplot as plt
examples=enumerate(test_loader)
batch_idx,(example_data,example_targets)=next(examples)
fig=plt.figure()
for i in range(6):
plt.subplot(2,3,i+1)
plt.tight_layout()
plt.imshow(example_data[i][0],cmap="gray",interpolation='none')
plt.title("Ground Truth:{}".format(example_targets[i]))
plt.xticks([])
plt.yticks([])
_______________________构建模型
数据预处理结束后,开始构建模型
1)构建网络的类Net
class Net(nn.Module):
"""
使用sequential构建网络,Sequential()函数的功能是将网络的层组合到一起
"""
def __init__(self, in_dim, n_hidden_1, n_hidden_2, out_dim):
super(Net, self).__init__()
self.layer1 = nn.Sequential(nn.Linear(in_dim,
n_hidden_1),nn.BatchNorm1d(n_hidden_1))
self.layer2 = nn.Sequential(nn.Linear(n_hidden_1, n_hidden_2),nn.BatchNorm1d (n_hidden_2))
self.layer3 = nn.Sequential(nn.Linear(n_hidden_2, out_dim))
def forward(self, x):
x = F.relu(self.layer1(x))
x = F.relu(self.layer2(x))
x = self.layer3(x)
return x
2)创造实例
#检测是否有可用的GPU,有则使用,否则使用CPU
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
#实例化网络
model = Net(28 * 28, 300, 100, 10)
model.to(device)
# 定义损失函数criterion和优化器optimizer
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=lr, momentum=momentum)
以下内容为大语言模型生成:
这段代码实现了一个使用nn.Sequential
构建的三层全连接神经网络,包含批归一化和ReLU激活函数。以下是对代码的分析及优化建议:
代码结构分析
-
网络定义:
- Layer1 :线性层(
in_dim
→n_hidden_1
) + 批归一化。 - Layer2 :线性层(
n_hidden_1
→n_hidden_2
) + 批归一化。 - Layer3 :线性层(
n_hidden_2
→out_dim
),无批归一化和激活函数。
- Layer1 :线性层(
-
前向传播:
- 前两层使用ReLU激活,最后一层输出原始 logits(适用于分类任务结合
CrossEntropyLoss
或回归任务)。
- 前两层使用ReLU激活,最后一层输出原始 logits(适用于分类任务结合
------------------------训练模型
这里使用for循环进行迭代。其中包括对训练数据的训练模型,然后用测试数据的验证模型。
1.训练模型
import torch
import torch.nn as nn
from torch.utils.data import DataLoader
from torchvision import transforms
from tqdm import tqdm
# 假设已定义模型、数据集、损失函数和优化器
# model = Net(...)
# train_dataset = ...
# test_dataset = ...
# 数据预处理(展平)
class FlattenTransform:
def __call__(self, img):
return img.view(-1)
transform = transforms.Compose([
transforms.ToTensor(),
FlattenTransform()
])
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=64)
# 初始化
losses = []
acces = []
eval_losses = []
eval_acces = []
for epoch in range(num_epoches):
# 动态调整学习率
if epoch > 0 and epoch % 5 == 0:
for param_group in optimizer.param_groups:
new_lr = max(param_group['lr'] * 0.1, 1e-6)
param_group['lr'] = new_lr
print(f"Learning rate updated to {new_lr}")
# 训练阶段
model.train()
train_loss = 0
train_correct = 0
train_total = 0
for img, label in tqdm(train_loader, desc=f"Epoch {epoch+1} Training"):
img, label = img.to(device), label.to(device)
# 前向传播
output = model(img)
loss = criterion(output, label)
# 反向传播
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 记录指标
train_loss += loss.item()
_, pred = output.max(1)
train_correct += (pred == label).sum().item()
train_total += label.size(0)
# 计算平均指标
avg_train_loss = train_loss / len(train_loader)
avg_train_acc = train_correct / train_total
losses.append(avg_train_loss)
acces.append(avg_train_acc)
# 测试阶段
model.eval()
eval_loss, eval_acc = calculate_metrics(test_loader, model, criterion, device)
eval_losses.append(eval_loss)
eval_acces.append(eval_acc)
# 打印日志
print(f'Epoch {epoch+1}/{num_epoches}: '
f'Train Loss: {avg_train_loss:.4f}, Train Acc: {avg_train_acc:.4f}, '
f'Test Loss: {eval_loss:.4f}, Test Acc: {eval_acc:.4f}')
以下内容由大语言模型生成
为什么需要 model.eval()
?
在神经网络中,某些层(如 BatchNorm
、Dropout
)在训练(training)和推理(evaluation)阶段的行为不同:
-
BatchNorm 层:
- 训练阶段:使用当前 batch 的均值和方差进行标准化,并更新运行统计量(running mean/variance)。
- 推理阶段:使用训练阶段累积的运行统计量,而非当前 batch 的统计量。
- 若不调用
model.eval()
,推理时会继续更新统计量,导致结果不稳定。
-
Dropout 层:
- 训练阶段:随机丢弃部分神经元,防止过拟合。
- 推理阶段:关闭 Dropout,使用所有神经元的输出(权重按概率缩放)。
- 若不调用
model.eval()
,推理时会继续随机丢弃神经元,导致结果随机。
功能详解
调用 model.eval()
后:
- 关闭训练相关行为 :
BatchNorm
层停止计算均值/方差,使用累积的统计量。Dropout
层停止随机丢弃神经元。
- 不影响梯度计算 :
model.eval()
仅改变层的行为,不涉及梯度计算。如果需要禁用梯度,需配合torch.no_grad()
。