CIFAR-10简介
CIFAR-10是一个常用的图像分类数据集,每张图片都是 3×32×32,3通道彩色图片,分辨率为 32×32。
它包含了10个不同类别,每个类别有6000张图像,其中5000张用于训练,1000张用于测试。这10个类别分别为:飞机、汽车、鸟类、猫、鹿、狗、青蛙、马、船和卡车。CIFAR-10分类任务是将这些图像正确地分类到它们所属的类别中。对于这个任务,可以使用深度学习模型,如卷积神经网络(CNN)来实现高效的分类。
一、数据加载及预处理(实现数据加载及预处理、归一化的理解、访问数据集、Dataset对象、Dataloader对象)
# 导包
import torchimport torchvision
import torchvision.transforms as transforms
# 定义对数据的预处理transform = transforms.Compose( [transforms.ToTensor(), # 转为Tensor格式 transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]) #归一化
# 训练集
trainset=torchvision.datasets.CIFAR10(root='./data', train=True, download=False, transform=transform)
# PyTorch提供的CIFAR-10数据集的类,用于加载CIFAR-10数据集
# root:数据集存储的根目录
# train:指定加载的是CIFAR-10的训练集
# transform:数据集的预处理方式
数据加载器trainloader = torch.utils.data.DataLoader(trainset, batch_size=4, shuffle=True,num_workers=0)
# torch.utils.data.DataLoader 创建一个数据加载器
# batch_size=4 表示每个批次包含4个样本# shuffle=True 表示在每个epoch对数据进行打乱
# num_workers=0 表示不使用多进程加载数据
# 测试集
testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=False, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=4, shuffle=False, num_workers=0)
# train=False 表示加载测试集
# shuffle=False 表示测试集不需要打乱。
# 定义类别标签:定义CIFAR-10数据集中10个类别的名称classes = ('plane','car','bird','cat', 'deer','dog','frog','horse','ship','truck')
import matplotlib.pyplot as plt
import numpy as np
# 定义图像显示函数
def imshow(img): img = img / 2 + 0.5 # 对图像进行反归一化处理,恢复到原始的像素值范围
npimg = img.numpy() # 将PyTorch张量转换为NumPy数组,方便matplotlib处理 plt.imshow(np.transpose(npimg, (1, 2, 0))) #彩色图像,三个通道:R G B
plt.show() # 显示图像
dataiter = iter(trainloader)
# 随机获取部分训练数据(获取训练数据迭代器)
for images, labels in dataiter: # 使用for循环来迭代数据 imshow(torchvision.utils.make_grid(images))
# 显示图像
print(' '.join('%5s' % classes[labels[j]] for j in range(4))) # 打印标签
二、定义网络
import torch.nn as nn
import torch.nn.functional as Fdevice = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# 判断是否有可用的CUDA设备,如果有使用GPU版本,没有使用CPU版本
class CNNNet(nn.Module): #定义一个名为CNNNet的类
def __init__(self):
super(CNNNet, self).__init__()
# 调用初始化函数
self.conv1 = nn.Conv2d(in_channels=3,out_channels=16,kernel_size=5,stride=1)
# 卷积层:输入三个通道 输出16个特征图 卷积核大小为5 步长为1
self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2) # 最大池化层
self.conv2 = nn.Conv2d(in_channels=16,out_channels=36,kernel_size=3, stride=1)# 卷积层
self.pool2 = nn.MaxPool2d(kernel_size=2, stride=2) #最大池化层
def forward(self, x):
x = self.pool1(F.relu(self.conv1(x)))
x = self.pool2(F.relu(self.conv2(x))) # 卷积、激活函数、池化 # print(x.shape)
x = x.view(-1,36*6*6) # 拉平成一维向
x = F.relu(self.fc2(F.relu(self.fc1(x)))) return x# 创建网络实例并打印参数数量
net = CNNNet()
print("net have {} paramerters in total".format(sum(x.numel() for x in net.parameters())))import torch.optim as optim # 导入优化器模块
三、定义损失函数和优化器(loss和optimizer)
LR = 0.001 # 定义学习率为0.001
criterion = nn.CrossEntropyLoss()
# 定义损失函数,适用于多分类问题
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)# net.parameters()表示要优化的模型参数,即神经网络中的权重和偏置。
# lr=0.001是学习率(learning rate),控制每次参数更新的步长大小。
# momentum=0.9表示动量(momentum)参数,用于加速优化过程并避免陷入局部最优解。
print(net) # 打印网络结构nn.Sequential(*list(net.children())[:4]) # 取模型中的前四层
四、训练网络并更新网络参数
for epoch in range(10):
#指定训练的轮数为10轮(epoch),即遍历整个数据集十次。
running_loss = 0.0 # 记录当前训练阶段的损失值
for i, data in enumerate(trainloader,0): # 内层批次循环
# 获取训练数据
inputs, labels = data
inputs, labels = inputs.to(device), labels.to(device)
optimizer.zero_grad() # 权重参数梯度清零
# 正向及反向传播
outputs = net(inputs) loss = criterion(outputs, labels)
# 进行前向传播,然后计算损失函数
loss loss.backward() # 自动计算损失函数相对于模型参数的梯度
optimizer.step() # 使用优化器 optimizer 来更新模型的权重和偏置,以最小化损失函数
# 显示损失值 running_loss += loss.item()
if i % 2000 == 1999:
print('[%d, %5d] loss: %.3f' %(epoch + 1, i + 1, running_loss / 2000))
running_loss = 0.0
print('Finished Training') # 训练结束提示
五、测试网络
dataiter =iter(testloader) # 测试数据加载器for i,(images,labels) in enumerate(dataiter): # 使用enumerate函数遍历迭代器 imshow(torchvision.utils.make_grid(images))
print('GroundTruth',''.join('%5s' %classes[labels[j]] for j in range(4)))
print("==================================================================")
images,labels=images.to(device),labels.to(device)
outputs=net(images)
_, predicted = torch.max(outputs, 1)
print('Predicted',''.join('%5s' %classes[predicted[j]] for j in range(4)))
correct=0 # 用于记录模型在测试集中预测正确的样本数量,初始化为0
total=0 # 用于记录测试集的样本总数
with torch.no_grad():
for data in testloader:
images, labels = data
images, labels = images.to(device), labels.to(device)
outputs=net(images)
_, predicted = torch.max(outputs, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
print('Accuracy of the network on the 10000 test images: %d %%' % (100 * correct/total))
class_correct=list(0. for i in range(10)) # 创建列表,用于记录每个类别的正确预测数量class_total=list(0. for i in range(10)) # 创建列表,用于记录每个类别的总预测数量
with torch.no_grad():
for data in testloader:
images,labels = data
images,labels = images.to(device), labels.to(device)
outputs = net(images)
_, predicted=torch.max(outputs,1)
c = (predicted == labels).squeeze()
for i in range(4):
label = labels[i]
class_correct[label] += c[i].item() class_total[label] += 1
for i in range(10):
print('Accuracy of %5s : %2d %%' %( classes[i],100 * class_correct[i] / class_total[i]))
全局平均池化层
import torch.nn as nn #导包
import torch.nn.functional as F
device = torch.device("cuda:0" if torch.cuda.is_available() else 'cpu') #检查cuda版本是否可用
class Net(nn.Module): #定义神经网络类,继承自nn.Module(pytorch中所有神经网络模型的基类
def __init__(self):类的初始化方法 super(Net,self).__init__()父类nn.Module self.conv1 = nn.Conv2d(3,16,5) #定义第一个卷积层,输入通道数为3(彩色图像三个通道,输出通道数为16,卷积核大小为5x5
self.pool1 = nn.MaxPool2d(2,2) #定义第一个最大池化层,池化窗口大小为2x2
self.conv2 = nn.Conv2d(16,36,5) #定义第二个卷积层,输入通道数为16.输出通道为36,卷积核大小为5x5
self.pool2 = nn.MaxPool2d(2,2) #定义第二层最大池化层,池化窗口为2x2 self.aap=nn.AdaptiveAvgPool2d(1) #定义自适应平均池化层,输出大小为1x1
self.fc3 = nn.Linear(36,10) #定义全连接层,输出特征数为36,输出特征数为10
def forward(self,x): #定义前向传播方法
x = self.pool1(F.relu(self.conv1(x))) 对输入的进行第一次卷积操作,然后应用relu激活函数,然后进行最大池化
x = self.pool2(F.relu(self.conv2(x)))对输入的进行第二次卷积操作,然后应用relu激活函数,然后第二次进行最大池化
x = self.aap(x) #进行自适应平均池化
x = x.view(x.shape[0],-1) #将池化后的输出展平为一维向量
x = self.fc3(x) 通过全连接层得到最终输出 return x
net = Net()
net = net.to(device)
print("net_gvp have {} paramerters in total".format(sum(x.numel() for x in net.parameters()))) #计算并打印网络学习中所有可学习参数的总数
import torch.optim as optim
LR=0.001学习率,criterion=nn.CrossEntropyLoss()交叉熵损失函数,方便计算模型输出和真实标签的损失值optimizer = optim.SGD(net.parameters(),lr=0.001,momentum=0.9)随机梯度下降SGD优化器
训练模型
for epoch in range(10):
running_loss=0.0初始化
for i, data in enumerate(trainloader,0):
#trainloader数据加载器,enumerate用于同时获取数据的索引i和数据data获取训练数据 inputs,labels = data
inputs,labels = inputs.to(device),labels.to(device)
#权重参数梯度清零
optimizer.zero_grad() #将优化器的梯度清零,避免梯度累加
#正向及反向传播
outputs = net(inputs)
loss = criterion(outputs,labels)计算网络输出outputs和labels之间的损失值 loss.backward()
optimizer.step()
#显示损失值
running_loss += loss.item()
if i % 2000 == 1999:
print('[%d,%5d] loss:%.3f' %(epoch+1,i+1,running_loss / 2000)) running_loss=0.0
print('Finished Training')