1、定义LeNet-5模型,包括卷积层和全连接层。
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms# 导入必要的库# 定义 LeNet-5 模型
class LeNet5(nn.Module):def __init__(self):super(LeNet5, self).__init__()# 定义卷积层和全连接层self.conv1 = nn.Conv2d(1, 6, kernel_size=5) # 输入通道1,输出通道6,卷积核大小5x5self.conv2 = nn.Conv2d(6, 16, kernel_size=5) # 输入通道6,输出通道16,卷积核大小5x5self.fc1 = nn.Linear(16 * 4 * 4, 120) # 全连接层,输入维度为16*4*4,输出维度为120self.fc2 = nn.Linear(120, 84) # 全连接层,输入维度为120,输出维度为84self.fc3 = nn.Linear(84, 64) # 全连接层,输入维度为84,输出维度为64self.fc4 = nn.Linear(64, 10) # 全连接层,输入维度为64,输出维度为10def forward(self, x):x = torch.relu(self.conv1(x)) # 第一个卷积层后接ReLU激活函数x = torch.max_pool2d(x, 2) # 池化层,执行2x2的最大池化x = torch.relu(self.conv2(x)) # 第二个卷积层后接ReLU激活函数x = torch.max_pool2d(x, 2) # 池化层,执行2x2的最大池化x = x.view(-1, 16 * 4 * 4) # 数据展平,以便输入全连接层x = torch.relu(self.fc1(x)) # 第一个全连接层后接ReLU激活函数x = torch.relu(self.fc2(x)) # 第二个全连接层后接ReLU激活函数x = self.fc3(x) # 第三个全连接层return x
2、对MNIST数据集进行加载和预处理,包括将图像转换为张量和标准化。
# 加载 MNIST 训练集和测试集
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))])
# 定义数据预处理,包括转换为张量和标准化train_dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
test_dataset = datasets.MNIST(root='./data', train=False, download=True, transform=transform)
# 下载MNIST数据集,并应用数据预处理train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=64, shuffle=False)
# 创建训练和测试数据加载器
3、初始化模型和优化器,使用随机梯度下降(SGD)优化器。
# 初始化模型和优化器
model = LeNet5() # 创建LeNet-5模型
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9) # 使用随机梯度下降作为优化器# 训练模型
device = torch.device("cuda" if torch.cuda.is_available() else "cpu") # 检查是否支持GPU,如果支持则使用GPU
model.to(device) # 将模型移动到GPU或CPU
criterion = nn.CrossEntropyLoss() # 使用交叉熵损失函数
4、在每个训练周期内,进行前向传播、反向传播和参数更新。在训练集上进行精度测试,以评估模型性能。
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms# 导入必要的库# 定义 LeNet-5 模型
class LeNet5(nn.Module):def __init__(self):super(LeNet5, self).__init__()# 定义卷积层和全连接层self.conv1 = nn.Conv2d(1, 6, kernel_size=5) # 输入通道1,输出通道6,卷积核大小5x5self.conv2 = nn.Conv2d(6, 16, kernel_size=5) # 输入通道6,输出通道16,卷积核大小5x5self.fc1 = nn.Linear(16 * 4 * 4, 120) # 全连接层,输入维度为16*4*4,输出维度为120self.fc2 = nn.Linear(120, 84) # 全连接层,输入维度为120,输出维度为84self.fc3 = nn.Linear(84, 64) # 全连接层,输入维度为84,输出维度为64self.fc4 = nn.Linear(64, 10) # 全连接层,输入维度为64,输出维度为10def forward(self, x):x = torch.relu(self.conv1(x)) # 第一个卷积层后接ReLU激活函数x = torch.max_pool2d(x, 2) # 池化层,执行2x2的最大池化x = torch.relu(self.conv2(x)) # 第二个卷积层后接ReLU激活函数x = torch.max_pool2d(x, 2) # 池化层,执行2x2的最大池化x = x.view(-1, 16 * 4 * 4) # 数据展平,以便输入全连接层x = torch.relu(self.fc1(x)) # 第一个全连接层后接ReLU激活函数x = torch.relu(self.fc2(x)) # 第二个全连接层后接ReLU激活函数x = self.fc3(x) # 第三个全连接层return x# 加载 MNIST 训练集和测试集
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))])
# 定义数据预处理,包括转换为张量和标准化train_dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
test_dataset = datasets.MNIST(root='./data', train=False, download=True, transform=transform)
# 下载MNIST数据集,并应用数据预处理train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=64, shuffle=False)
# 创建训练和测试数据加载器# 初始化模型和优化器
model = LeNet5() # 创建LeNet-5模型
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9) # 使用随机梯度下降作为优化器# 训练模型
device = torch.device("cuda" if torch.cuda.is_available() else "cpu") # 检查是否支持GPU,如果支持则使用GPU
model.to(device) # 将模型移动到GPU或CPU
criterion = nn.CrossEntropyLoss() # 使用交叉熵损失函数for epoch in range(10):model.train() # 设置模型为训练模式running_loss = 0.0for images, labels in train_loader:images, labels = images.to(device), labels.to(device) # 将数据移动到GPU或CPUoptimizer.zero_grad() # 梯度清零outputs = model(images) # 前向传播loss = criterion(outputs, labels) # 计算损失loss.backward() # 反向传播optimizer.step() # 更新模型参数running_loss += loss.item()# 在训练集上进行精度测试model.eval() # 设置模型为评估模式correct = 0total = 0with torch.no_grad():for images, labels in test_loader:images, labels = images.to(device), labels.to(device) # 将数据移动到GPU或CPUoutputs = model(images) # 前向传播_, predicted = torch.max(outputs.data, 1) # 获取预测类别total += labels.size(0)correct += (predicted == labels).sum().item()accuracy = 100 * correct / totalprint('Epoch: %d, Loss: %.3f, Accuracy: %.2f%%' % (epoch+1, running_loss, accuracy))
5、实验步骤和关键要点:
-
模型定义:LeNet-5模型被定义为一个经典的卷积神经网络,包括卷积层和全连接层。模型结构包括两个卷积层、两个池化层和三个全连接层。
-
数据加载和预处理:MNIST数据集被加载并进行预处理。预处理包括将图像转换为张量,并进行标准化,以确保输入数据在训练期间具有相似的尺度和分布。
-
初始化模型和优化器:LeNet-5模型被初始化,并使用随机梯度下降(SGD)作为优化器。SGD用于在训练期间调整模型参数以最小化损失函数。
-
模型训练:模型被训练在训练集上进行了多个周期的训练。对于每个训练周期,执行以下步骤:
- 设置模型为训练模式。
- 对每个批次进行前向传播,计算损失,执行反向传播,更新模型参数。
- 记录每个训练周期的损失值。
-
模型测试:在每个训练周期结束后,模型在测试集上进行了精度测试。在测试期间,执行以下步骤:
- 设置模型为评估模式。
- 通过模型进行前向传播,计算测试集上的预测结果。
- 检查模型的准确性,计算正确分类的样本数量,并计算总样本数量。
- 记录每个训练周期的测试精度。
-
打印结果:在每个训练周期结束后,打印出训练周期的损失和测试精度,以便监控模型的性能。
这个实验展示了如何使用PyTorch框架构建、训练和测试深度学习模型。LeNet-5模型在MNIST数据集上取得了不错的手写数字识别性能。通过多个训练周期,模型的损失逐渐减小,测试精度逐渐增加,表明模型在训练过程中逐渐学习到了有效的特征表示,从而提高了在新样本上的分类准确性。