本文在前节程序基础上,实现对CIFAR-10的训练与测试,以加深对LeNet-5网络的理解 。
首先,要了解LeNet-5并不适合训练 CIFAR-10 , 最后的正确率不会太理想 。
CIFAR-10是一个常用的图像分类数据集,由10类共计60,000张32x32大小的彩色图像组成,每类包含6,000张图像。这些图像被平均分为了5个训练批次和1个测试批次,每个批次包含10,000张图像。CIFAR-10数据集中的10个类别分别为:飞机、汽车、鸟类、猫、鹿、狗、青蛙、马、船和卡车。
相比之下,MNIST是一个手写数字分类数据集,由10个数字(0-9)共计60,000个训练样本和10,000个测试样本组成,每个样本是一个28x28的灰度图像。
与MNIST相比,CIFAR-10更具挑战性,因为它是一个彩色图像数据集,每张图像包含更多的信息和细节,难度更高。此外,CIFAR-10的类别也更加多样化,更加贴近实际应用场景。因此,CIFAR-10更适合用于测试和评估具有更高难度的图像分类模型,而MNIST则更适合用于介绍和入门级别的模型训练和测试。
PyTorch中的transforms是用于对数据进行预处理和增强的工具,主要用于图像数据的处理,它可以方便地对数据进行转换,使其符合神经网络的输入要求。
transforms的方法:
使用transforms可以方便地进行数据预处理和增强,提高模型的鲁棒性和泛化能力。在实际应用中,可以根据具体问题和需求进行选择和组合。
下面定义加载CIFAR-10数据集,首先会对图片进行一些处理:
对数据的处理可以增加数据的多样性和丰富性,以提高神经网络的泛化能力和准确率。
transform = transforms.Compose([transforms.RandomHorizontalFlip(),transforms.RandomCrop(32, padding=4),transforms.ToTensor(),transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])trainset = torchvision.datasets.CIFAR10(root='./data', train=True,download=True, transform=transform)
train_loader = torch.utils.data.DataLoader(trainset, batch_size=32,shuffle=True, num_workers=2)testset = torchvision.datasets.CIFAR10(root='./data', train=False,download=True, transform=transform)
test_loader = torch.utils.data.DataLoader(testset, batch_size=32,shuffle=False, num_workers=2)
class LeNet5(nn.Module):def __init__(self):super(LeNet5, self).__init__()# 定义卷积层C1,输入通道数为1,输出通道数为6,卷积核大小为5x5self.conv1 = nn.Conv2d(3, 6, kernel_size=5, stride=1)# 定义池化层S2,池化核大小为2x2,步长为2self.pool1 = nn.AvgPool2d(kernel_size=2, stride=2)# 定义卷积层C3,输入通道数为6,输出通道数为16,卷积核大小为5x5self.conv2 = nn.Conv2d(6, 16, kernel_size=5, stride=1)# 定义池化层S4,池化核大小为2x2,步长为2self.pool2 = nn.AvgPool2d(kernel_size=2, stride=2)# 定义全连接层F5,输入节点数为16x4x4=256,输出节点数为120self.fc1 = nn.Linear(16 * 5 * 5, 120)# 定义全连接层F6,输入节点数为120,输出节点数为84self.fc2 = nn.Linear(120, 84)# 定义输出层,输入节点数为84,输出节点数为10self.fc3 = nn.Linear(84, 10)def forward(self, x):# 卷积层C1x = self.conv1(x)# 池化层S2x = self.pool1(torch.relu(x))# 卷积层C3x = self.conv2(x)# 池化层S4x = self.pool2(torch.relu(x))# 全连接层F5x = x.view(-1, 16 * 5 * 5)x = self.fc1(x)x = torch.relu(x)# 全连接层F6x = self.fc2(x)x = torch.relu(x)# 输出层x = self.fc3(x)return x
和上节类似 , 这个模型定义了经典的 LeNet-5。它由两个卷积层、两个池化层和三个全连接层组成,层间通过一定的非线性激活函数进行连接。
最后,网络输出了分类结果。在前向传播过程中,经过卷积、池化、全连接等操作,每层的输出都要经过一定的非线性激活函数,这里使用的是 ReLU 函数(即 Rectified Linear Unit)。
model = LeNet5()
optimizer = optim.SGD(model.parameters(), lr=learning_rate)
criterion = nn.CrossEntropyLoss()
if __name__ == '__main__':# 定义模型保存路径和文件名model_path = 'model.pth'if os.path.exists(model_path):# 存在,直接加载模型model.load_state_dict(torch.load(model_path))print('Loaded model from', model_path)else:# 训练模型for epoch in range(epochs):model.train()for images, labels in train_loader:# 将数据放入模型optimizer.zero_grad()outputs = model(images)loss = criterion(outputs, labels)loss.backward()optimizer.step()# 在测试集上测试模型model.eval()correct = 0with torch.no_grad():for images, labels in test_loader:# 将数据放入模型outputs = model(images)_, predicted = torch.max(outputs, 1)correct += (predicted == labels).sum().item()accuracy = 100 * correct / len(testset)print('Epoch [{}/{}], Loss: {:.4f}, Accuracy: {:.2f}%'.format(epoch + 1, epochs, loss.item(), accuracy))torch.save(model.state_dict(), 'model.pth')for i in range(10):img, label = next(iter(test_loader))img = img[i].unsqueeze(0)# 使用模型进行预测model.eval()with torch.no_grad():output = model(img)# 解码预测结果pred = output.argmax(dim=1).item()print(f'Predicted class: {pred}, actual value: {label[i]}')
import osimport torch
import torch.nn as nn
import torch.optim as optim
import torchvision
from torchvision import datasets, transforms
from torch.utils.data import DataLoader# 定义 LeNet-5 模型
class LeNet5(nn.Module):def __init__(self):super(LeNet5, self).__init__()# 定义卷积层C1,输入通道数为1,输出通道数为6,卷积核大小为5x5self.conv1 = nn.Conv2d(3, 6, kernel_size=5, stride=1)# 定义池化层S2,池化核大小为2x2,步长为2self.pool1 = nn.AvgPool2d(kernel_size=2, stride=2)# 定义卷积层C3,输入通道数为6,输出通道数为16,卷积核大小为5x5self.conv2 = nn.Conv2d(6, 16, kernel_size=5, stride=1)# 定义池化层S4,池化核大小为2x2,步长为2self.pool2 = nn.AvgPool2d(kernel_size=2, stride=2)# 定义全连接层F5,输入节点数为16x4x4=256,输出节点数为120self.fc1 = nn.Linear(16 * 5 * 5, 120)# 定义全连接层F6,输入节点数为120,输出节点数为84self.fc2 = nn.Linear(120, 84)# 定义输出层,输入节点数为84,输出节点数为10self.fc3 = nn.Linear(84, 10)def forward(self, x):# 卷积层C1x = self.conv1(x)# print('卷积层C1后的形状:', x.shape)# 池化层S2x = self.pool1(torch.relu(x))# print('池化层S2后的形状:', x.shape)# 卷积层C3x = self.conv2(x)# print('卷积层C3后的形状:', x.shape)# 池化层S4x = self.pool2(torch.relu(x))# print('池化层S4后的形状:', x.shape)# 全连接层F5x = x.view(-1, 16 * 5 * 5)x = self.fc1(x)# print('全连接层F5后的形状:', x.shape)x = torch.relu(x)# 全连接层F6x = self.fc2(x)# print('全连接层F6后的形状:', x.shape)x = torch.relu(x)# 输出层x = self.fc3(x)# print('输出层后的形状:', x.shape)return x# 设置超参数
batch_size = 128
learning_rate = 0.01
epochs = 10# CIFAR-10
# 准备数据
transform = transforms.Compose([transforms.RandomHorizontalFlip(),transforms.RandomCrop(32, padding=4),transforms.ToTensor(),transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])trainset = torchvision.datasets.CIFAR10(root='./data', train=True,download=True, transform=transform)
train_loader = torch.utils.data.DataLoader(trainset, batch_size=32,shuffle=True, num_workers=2)testset = torchvision.datasets.CIFAR10(root='./data', train=False,download=True, transform=transform)
test_loader = torch.utils.data.DataLoader(testset, batch_size=32,shuffle=False, num_workers=2)# 实例化模型和优化器
model = LeNet5()
optimizer = optim.SGD(model.parameters(), lr=learning_rate)
criterion = nn.CrossEntropyLoss()
if __name__ == '__main__':# 定义模型保存路径和文件名model_path = 'model.pth'if os.path.exists(model_path):# 存在,直接加载模型model.load_state_dict(torch.load(model_path))print('Loaded model from', model_path)else:# 训练模型for epoch in range(epochs):model.train()for images, labels in train_loader:# 将数据放入模型optimizer.zero_grad()outputs = model(images)loss = criterion(outputs, labels)loss.backward()optimizer.step()# 在测试集上测试模型model.eval()correct = 0with torch.no_grad():for images, labels in test_loader:# 将数据放入模型outputs = model(images)_, predicted = torch.max(outputs, 1)correct += (predicted == labels).sum().item()accuracy = 100 * correct / len(testset)print('Epoch [{}/{}], Loss: {:.4f}, Accuracy: {:.2f}%'.format(epoch + 1, epochs, loss.item(), accuracy))torch.save(model.state_dict(), 'model.pth')for i in range(10):img, label = next(iter(test_loader))img = img[i].unsqueeze(0)# 使用模型进行预测model.eval()with torch.no_grad():output = model(img)# 解码预测结果pred = output.argmax(dim=1).item()print(f'Predicted class: {pred}, actual value: {label[i]}')
最后训练准确率仅有47.13%。
上一篇:算法 - 滑动窗口