2.2 使用Pytorch构建一个分类器
学习目标
- 了解分类器的任务和数据样式
- 掌握如何使用Pytorch实现一个分类器
分类器任务和数据介绍
- 构建一个将不同图像进行分类的神经网络分类器,对输入的图片进行判断并完成分类
- 本案例采用CIFAR0数据集作为原始图片数据
CIFAR10数据集介绍
- 数据集中每张图片的尺寸是33232,代表彩色3通道
- CIFAR10数据集共有10种不同的分类,分别是:airplane automobile bird cat deer dog frog horse ship truck
训练分类器步骤
- 1:使用torchvision下载CIFAR10数据集
- 2:定义卷积神经网络
- 3:定义损失函数
- 4:在训练集上训练模型
- 5:在测试集上测试模型
1:使用torchvision下载CIFAR10数据集
import torch
import torchvision
import torchvision.transforms as transforms
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
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=True,transform=transform)
trainloader=torch.utils.data.DataLoader(trainset,batch_size=4,shuffle=True,num_workers=2)
testset=torchvision.datasets.CIFAR10(root='./data',train=False,download=True,transform=transform)
testloader=torch.utils.data.DataLoader(testset,batch_size=4,shuffle=False,num_workers=2)
classes=('airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
Downloading https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz to ./data\cifar-10-python.tar.gz
100.0%
Extracting ./data\cifar-10-python.tar.gz to ./data
Files already downloaded and verified
注意:
可能存在的两个问题:
- windows系统下运行上述代码,并且出现报错信息“BrokenPipeError”时,可以尝试将torch.utils.DataLoader()中的num_workers设置为0
- 下载CIFAR10数据集报错:urllib.error.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certi
- 尽量使用linux系统学习深度学习
展示若干训练集的图片
在此处遇到问题可以访问我之前写的一篇文章
import torch
import torchvision
import torchvision.transforms as transforms
import ssl
import torch.utils.data as Data
ssl._create_default_https_context = ssl._create_unverified_context
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=True,transform=transform)
trainloader=torch.utils.data.DataLoader(dataset=trainset,batch_size=4,shuffle=True,num_workers=2)
testset=torchvision.datasets.CIFAR10(root='./data',train=False,download=True,transform=transform)
testloader=torch.utils.data.DataLoader(dataset=testset,batch_size=4,shuffle=False,num_workers=2)
classes=('airplane', 'automobile', '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()
plt.imshow(np.transpose(npimg,(1,2,0)))
plt.show()
if __name__ == '__main__':
try:
dataiter = iter(trainloader)
images, labels = dataiter.next()
imShow(torchvision.utils.make_grid(images))
print(' '.join('%5s' % classes[labels[j]] for j in range(4)))
except Exception as e:
print(e)
dog horse cat cat
定义卷积神经网络
仿照2.1节中的类来构造此处的类,唯一的区别在于次数采用的三通道 3-channel
import torch.nn as nn
import torch.nn.functional as F
class Net(nn.Module):
def __init__(self):
super(Net,self).__init__()
self.conv1=nn.Conv2d(3,6,5)
self.conv2=nn.Conv2d(6,16,5)
self.pool = nn.MaxPool2d(2, 2)
self.fc1=nn.Linear(16*5*5,120)
self.fc2=nn.Linear(120,84)
self.fc3=nn.Linear(84,10)
def forward(self,x):
x=self.pool(F.relu(self.conv1(x)))
x=self.pool(F.relu(self.conv2(x)))
x=x.view(-1,16*5*5)
x=F.relu(self.fc1(x))
x=F.relu(self.fc2(x))
x=self.fc3(x)
return x
net=Net()
print(net)
3: 定义损失函数
采用交叉熵损失函数和随机梯度下降优化器
import torch.optim as optim
criterion=nn.CrossEntropyLoss()
optimizer=optim.SGD(net.parameters(),lr=0.001,momentum=0.9)
4: 在训练集上训练模型
采用基于梯度下降的优化算法,都需要很多个轮次的迭代训练
import torch.nn as nn
import torch.nn.functional as F
import torchvision
import torch
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=True,transform=transform)
trainloader=torch.utils.data.DataLoader(trainset,batch_size=4,shuffle=True,num_workers=0)
class Net(nn.Module):
def __init__(self):
super(Net,self).__init__()
self.conv1=nn.Conv2d(3,6,5)
self.conv2=nn.Conv2d(6,16,5)
self.pool = nn.MaxPool2d(2, 2)
self.fc1=nn.Linear(16*5*5,120)
self.fc2=nn.Linear(120,84)
self.fc3=nn.Linear(84,10)
def forward(self,x):
x=self.pool(F.relu(self.conv1(x)))
x=self.pool(F.relu(self.conv2(x)))
x=x.view(-1,16*5*5)
x=F.relu(self.fc1(x))
x=F.relu(self.fc2(x))
x=self.fc3(x)
return x
net=Net()
print(net)
import torch.optim as optim
criterion=nn.CrossEntropyLoss()
optimizer=optim.SGD(net.parameters(),lr=0.001,momentum=0.9)
for epoch in range(2):
running_loss=0.0
for i ,data in enumerate(trainloader,0):
inputs,labels=data
optimizer.zero_grad()
outputs=net(inputs)
loss=criterion(outputs,labels)
loss.backward()
optimizer.step()
running_loss+=loss.item()
if (i+1)%2000==0:
print('[%d , %5d] loss: %.3f'%(epoch+1,i+1,running_loss/2000))
running_loss=0.0
print("Finished Training")
[1 , 2000] loss: 2.220
[1 , 4000] loss: 1.859
[1 , 6000] loss: 1.658
[1 , 8000] loss: 1.570
[1 , 10000] loss: 1.512
[1 , 12000] loss: 1.436
[2 , 2000] loss: 1.373
[2 , 4000] loss: 1.367
[2 , 6000] loss: 1.340
[2 , 8000] loss: 1.303
[2 , 10000] loss: 1.312
[2 , 12000] loss: 1.277
Finished Training
PATH='./cifar_net.pth'
torch.save(net.state_dict(),PATH)
5:在测试集上测试模型
dataiter=iter(testloader)
images,labels=dataiter.next()
imShow(torchvision.utils.make_grid(images))
print('GroundTruth:',' '.join('%5s' %classes[labels[j]] for j in range(4)))
【完整版本代码】
import torch.nn as nn
import torch.nn.functional as F
import torchvision
import torch
import numpy as np
import matplotlib.pyplot as plt
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=True,transform=transform)
trainloader=torch.utils.data.DataLoader(trainset,batch_size=4,shuffle=True,num_workers=0)
testset=torchvision.datasets.CIFAR10(root='./data',train=False,download=True,transform=transform)
testloader=torch.utils.data.DataLoader(testset,batch_size=4,shuffle=True,num_workers=0)
classes=('airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
def imShow(img):
img=img/2+0.5
npimg=img.numpy()
plt.imshow(np.transpose(npimg,(1,2,0)))
plt.show()
class Net(nn.Module):
def __init__(self):
super(Net,self).__init__()
self.conv1=nn.Conv2d(3,6,5)
self.conv2=nn.Conv2d(6,16,5)
self.pool = nn.MaxPool2d(2, 2)
self.fc1=nn.Linear(16*5*5,120)
self.fc2=nn.Linear(120,84)
self.fc3=nn.Linear(84,10)
def forward(self,x):
x=self.pool(F.relu(self.conv1(x)))
x=self.pool(F.relu(self.conv2(x)))
x=x.view(-1,16*5*5)
x=F.relu(self.fc1(x))
x=F.relu(self.fc2(x))
x=self.fc3(x)
return x
net=Net()
print(net)
import torch.optim as optim
criterion=nn.CrossEntropyLoss()
optimizer=optim.SGD(net.parameters(),lr=0.001,momentum=0.9)
dataiter=iter(testloader)
images,labels=dataiter.next()
imShow(torchvision.utils.make_grid(images))
print('GroundTruth:',' '.join('%5s' %classes[labels[j]] for j in range(4)))
import torch.nn as nn
import torch.nn.functional as F
import torchvision
import torch
import numpy as np
import matplotlib.pyplot as plt
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=True,transform=transform)
trainloader=torch.utils.data.DataLoader(trainset,batch_size=4,shuffle=True,num_workers=0)
testset=torchvision.datasets.CIFAR10(root='./data',train=False,download=True,transform=transform)
testloader=torch.utils.data.DataLoader(testset,batch_size=4,shuffle=True,num_workers=0)
classes=('airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
def imShow(img):
img=img/2+0.5
npimg=img.numpy()
plt.imshow(np.transpose(npimg,(1,2,0)))
plt.show()
class Net(nn.Module):
def __init__(self):
super(Net,self).__init__()
self.conv1=nn.Conv2d(3,6,5)
self.conv2=nn.Conv2d(6,16,5)
self.pool = nn.MaxPool2d(2, 2)
self.fc1=nn.Linear(16*5*5,120)
self.fc2=nn.Linear(120,84)
self.fc3=nn.Linear(84,10)
def forward(self,x):
x=self.pool(F.relu(self.conv1(x)))
x=self.pool(F.relu(self.conv2(x)))
x=x.view(-1,16*5*5)
x=F.relu(self.fc1(x))
x=F.relu(self.fc2(x))
x=self.fc3(x)
return x
import torch.optim as optim
criterion=nn.CrossEntropyLoss()
PATH='./cifar_net.pth'
dataiter=iter(testloader)
images,labels=dataiter.next()
imShow(torchvision.utils.make_grid(images))
print('GroundTruth:',' '.join('%5s' %classes[labels[j]] for j in range(4)))
net=Net()
net.load_state_dict(torch.load(PATH))
outputs=net(images)
_,predicted=torch.max(outputs,1)
print("predicted:",predicted)
print("Predicted:",' '.join('%5s' % classes[predicted[j]] for j in range(4)))
GroundTruth: ship frog bird automobile
predicted: tensor([0, 2, 8, 1])
Predicted: airplane bird ship automobile
correct=0
total=0
with torch.no_grad():
for data in testloader:
images,labels=data
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))
Accuracy of the network on the 10000 test images:56 %
- 分析:对于拥有10个类被的数据集,随机猜测的准确率是10%,模型达到了53%,说明模型学到了真实的东西。
上面计算的是模型在总体测试集上的准确率,为了更加细致多看一些模型在哪些类别上表现更好,在哪些类别上表现更差,可以对每个类别的准确率进行计算。
correct=0
total=0
class_correct=[0. for i in range(10)]
class_total=[0 for i in range(10)]
max_index=-1
min_index=1000
with torch.no_grad():
for data in testloader:
images,labels=data
outputs=net(images)
_,predicted=torch.max(outputs.data,1)
total+=labels.size(0)
correct+=(predicted==labels).sum().item()
for i in range(labels.size(0)):
class_correct[labels[i]]+=(predicted[i]==labels[i])
class_total[labels[i]]+=1
print("Accuracy of the network on the 10000 test images:%d %%"%(100*correct/total))
for i in range(10):
print("Accuracy of ",classes[i], ":",100*class_correct[i].item()/class_total[i],"%")
Accuracy of the network on the 10000 test images:56 %
Accuracy of airplane : 59.4 %
Accuracy of automobile : 70.2 %
Accuracy of bird : 30.1 %
Accuracy of cat : 38.6 %
Accuracy of deer : 59.1 %
Accuracy of dog : 35.4 %
Accuracy of frog : 70.7 %
Accuracy of horse : 68.3 %
Accuracy of ship : 69.2 %
Accuracy of truck : 67.6 %
在GPU上训练模型
为了真正利用Pytorch中Tensor的优秀属性,加速模型的训练,可以将训练过程转移到GPU上进行。 首先,定义设备,如果CUDA是可用的则被定义成GPU,否则被定义成CPU 将模型放在GPU上训练分两步走: 1:将模型转移到GPU上 2:将数据转移到GPU上
device=torch.device('cuda:0' if torch.cuda.is_available() else "cpu")
print(device)
net.to(device)
inputs,labels=data[0].to(device),data[1].to(device)
【小节总结】
学习了分类器的任务和数据样式
- 将不同图像进行分类的神经网络分类器,对输入的图片进行判断并完成分类
- 采用CIFAR10数据集作为原始图片数据,CIFAR10数据集拥有10个类别的33232彩色图片
学习了训练分类器的步骤
- 使用torchvision下载CIFAR10数据集
- 定义卷积神经网络
- 定义损失函数
- 在训练集上训练模型
- 在测试集上测试模型
学习了在GPU上训练模型
- 首先需要定义设备,CPU和GPU二选一
device=torch.device('cuda:0' if torch.cuda.is_available() else "cpu") - 然后将模型转移到GPU上去
net.to(device) - 最后在迭代训练的过程中,每一步都将图片和标签张量转移到GPU上去
inputs,labels=data[0].to(device),data[1].to(device)
|