CIFAR-10分类,步骤如下:
1)使用torchvision加载并预处理CIFAR-10数据集
2)定义网络
3)定义损失函数和优化器
4)训练网络并更新网络参数
5)测试网络
CIFAR-10数据加载及预处理
CIFAR-10是一个常用的彩色图片数据集,它有10个类别airplane、automobile、bird、cat、deer、dog、frog、horse、ship和truck。每张图片都是3*32*32,也就是3通道彩色图片,分辨率为32*32。
import torch as t
import torchvision as tv
import torchvision.transforms as transforms
from torchvision.transforms import ToPILImage
show = ToPILImage()#可以把Tensor转成Image,方便可视化
#第一次运行程序torchvision会自动下载CIFAR-10数据集
#大约100MB,需要花费一定的时间,
#如果已经下载有CIFAR-10,可通过root参数指定
#定义对于数据的预处理
transform=transforms.Compose([
transforms.ToTensor(),#转为Tensor
transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))#归一化
])
#训练集
trainset = tv.datasets.CIFAR10(
root='/B/CIFAR-10data/',
train=True,
download=True,
transform=transform
)
trainloader=t.utils.data.DataLoader(
trainset,
batch_size=4,
shuffle=True,
num_workers=2
)
#测试集
testset = tv.datasets.CIFAR10 (
'/B/CIFAR-10data/',
train=False,
download=True,
transform=transform
)
testloader = t.utils.data.DataLoader (
testset,
batch_size=4,
shuffle=False,
num_workers=2
)
classes=('airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
#定义网络
import torch.nn as nn
import torch.nn.functional as F
import time
start = time.time () # 计时
# 定义网络结构
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.fc1 = nn.Linear (16 * 5 * 5, 120)
self.fc2 = nn.Linear (120, 84)
self.fc3 = nn.Linear (84, 10)
def forward(self, x):
x = F.max_pool2d (F.relu (self.conv1 (x)), 2)
x = F.max_pool2d (F.relu (self.conv2 (x)), 2)
x = x.view (x.size ()[0], -1)
x = F.relu (self.fc1 (x))
x = F.relu (self.fc2 (x))
x = self.fc3 (x)
return x
net = Net ()
print (net)
#定义优化和损失
# 定义优化和损失
loss_func = nn.CrossEntropyLoss () # 交叉熵损失函数
optimizer = t.optim.SGD (net.parameters (), lr=0.001, momentum=0.9)
# 训练网络
for epoch in range (2):
running_loss = 0
for i, data in enumerate (trainloader, 0):
inputs, labels = data
outputs = net (inputs)
loss = loss_func (outputs, labels)
optimizer.zero_grad ()
loss.backward ()
optimizer.step ()
running_loss += loss.item ()
if i % 2000 == 1999:
print ('epoch:', epoch + 1, '|i:', i + 1, '|loss:%.3f' % (running_loss / 2000))
running_loss = 0.0
end = time.time ()
time_using = end - start
print ('finish training')
print ('time:', time_using)
#测试结果
correct = 0 #定义的预测正确的图片数
total = 0#总共图片个数
with t.no_grad():
for data in testloader:
images,labels = data
outputs = net(images)
_,predict = t.max(outputs,1)
total += labels.size(0)
correct += (predict == labels).sum()
print('测试集中的准确率为:%d%%'%(100*correct/total))
Dataloader是一个可迭代的对象,它将dataset返回的每一条数据样本拼接成一个batch,并提供多线程加速优化和数据打乱等操作。当程序对dataset的所有数据遍历完一遍之后,对Dataloader也完成了一次迭代。
此处训练了仅仅2个epoch(遍历完一遍数据集称为一个epoch),可观察网络是否有效。将测试图片输入网络,计算它的label,然后与实际label进行比较。
输出:
Files already downloaded and verified
Files already downloaded and verified
Net(
(conv1): Conv2d(3, 6, kernel_size=(5, 5), stride=(1, 1))
(conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
(fc1): Linear(in_features=400, out_features=120, bias=True)
(fc2): Linear(in_features=120, out_features=84, bias=True)
(fc3): Linear(in_features=84, out_features=10, bias=True)
)
epoch: 1 |i: 2000 |loss:2.156
epoch: 1 |i: 4000 |loss:1.826
epoch: 1 |i: 6000 |loss:1.693
epoch: 1 |i: 8000 |loss:1.574
epoch: 1 |i: 10000 |loss:1.527
epoch: 1 |i: 12000 |loss:1.476
epoch: 2 |i: 2000 |loss:1.391
epoch: 2 |i: 4000 |loss:1.360
epoch: 2 |i: 6000 |loss:1.349
epoch: 2 |i: 8000 |loss:1.326
epoch: 2 |i: 10000 |loss:1.300
epoch: 2 |i: 12000 |loss:1.291
finish training
time: 217.39351534843445
测试集中的准确率为:54%
我们已经可以看出效果,准确率为54%,但这只是一部分图片,我们再来看看在整个测试机上的效果。
训练的准确率远远比随机猜测的(准确率为10%)好,证明网络确实学到了东西。
在GPU上训练
就像之前把Tensor从CPU转到GPU一样,模型也可以从CPU转到GPU。
if t.cuda.is_available():
net.cuda()
images=images.cuda()
labels=labels.cuda()
output=net(Variable(images))
loss=criterion(output,Variable(labels))