CIFAR-10
首先说一下CIFAR-10,它是一个数据集。由10个类的60000个32×32彩色图像组成。每个类有6000个图像。共有50000个训练图像和10000个测试图像。
- 加载数据并导入库
import torch
import torchvision
import torchvision.transforms as transforms
transform = transforms.Compose(
[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=False,transform=transform)
trainloader = torch.utils.data.DataLoader(trainset,batch_size=4,shuffle=True)
testset = torchvision.datasets.CIFAR10(root='./data',train=False,download=False,transform=transform)
testloader = torch.utils.data.DataLoader(testset,batch_size=4,shuffle=False)
classes = ('plane','car','bird','cat','deer','dog','frog','horse','ship','truck')
这里我们还是进行方法整合,接着导入数据。这里是数据在当前目录下的data目录下。如果已经有数据则设置download为false,没有则参数download=True,一般会自动下载。但也可能会出现下载较慢的情况。这里直接附上我已经下载好的数据集资源。
链接:https://pan.baidu.com/s/1a4FSB3_9nzZ7KPtFxlU-WA
提取码:bzgy
- 随机查看部分数据。显示图片。
import matplotlib.pyplot as plt
import numpy as np
#显示图像
def imshow(img):
img = img/2+0.5
npimg = img.numpy()
plt.imshow(np.transpose(npimg,(1,2,0)))
plt.show()
#随机获取部分训练数据
dataiter = iter(trainloader)
images,labels = dataiter.next()
#显示图像
imshow(torchvision.utils.make_grid(images))
#打印标签
print(' '.join('%5s' % classes[labels[j]] for j in range(4)))
这里会发现图片是彩色的,且比较模糊,这是因为这些图片是32×32的,所以像素较低,只能用于训练学习。与前面的手写数字识别案例相比较,这里的彩色图片。因此我们知道了神经网络的输入高度是RGB三通道。
3.构建神经网络。
import torch.nn as nn
import torch.nn.functional as F
device = torch.device("cpu")
class CNNNet(nn.Module):
def __init__(self):
super(CNNNet,self).__init__()
# 32×32×3 输入
self.conv1 = nn.Conv2d(in_channels=3,out_channels=16,kernel_size=5,stride=1)
# 16×28×28 第一次卷积后
self.pooll = nn.MaxPool2d(kernel_size=2,stride=2)
# 16×14×14 第一次池化
self.conv2 = nn.Conv2d(in_channels=16,out_channels=36,kernel_size=5,stride=1)
# 36×10×10 第二次卷积
self.pool2 = nn.MaxPool2d(2,2)
# 36×5×5 第二次池化
# 开始全连接
self.fc1 = nn.Linear(36*5*5,120)
self.fc2 = nn.Linear(120,84)
self.fc3 = nn.Linear(84,10)
def forward(self,x):
x = self.pooll(F.relu(self.conv1(x)))
x = self.pool2(F.relu(self.conv2(x)))
#print(x.shape)
x = x.view(-1,36*5*5)
x = F.relu(self.fc2(F.relu(self.fc1(x))))
x = self.fc3(x)
return x
net = CNNNet()
net = net.to(device)
这里依旧采用简单的卷积池化,经历了两次卷积,两次池化,三次全连接。
4.选择优化器,损失函数,开始训练。
import torch.optim as optim
#选择优化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(),lr=0.001,momentum=0.9)
#训练模型
for epoch in range(20):
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.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')
这里依旧采用交叉熵损失函数,使用SGD过滤器。训练20次,每次训练2000张图片看一下准确率
5.测试数据并查看每个类的正确率
correct = 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.data,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]))
6.结果
这是一个简单的分类案例,由于我们的数据并不多,所以最终的模型正确率也并不高,因此我们需要采用迁移学习或数据增强来提高我们的模型,增大我们的数据,以获得更高准确率的模型。