5、实战:CIFAR-10分类
与其他教程不一样的地方是加载的本地已下载数据(代码中下载速度太慢)。关于数据集的说明点击此链接。
1、下载数据集,复制此链接到迅雷下载 http://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz
2、解压到E:/data目录中,
3、jupyter中撸代码
【说明】
① Dataloader是一个可迭代的对象,它将datasets返回的每一条数据样本拼接成一个batch,并可以多线程加速优化、数据打乱等操作。
当datasets的所有数据遍历一遍之后,对Dataloader也完成了一次迭代。
② Dataloader类型与datasets一样返回数据、标签索引,不过Dataloader是以batch为单位返回的,即batch_size个元素组成的向量。
【步骤】
1、使用torchvision加载并预处理数据集
2、定义网络
3、定义损失函数和优化器
4、训练网络并更新网络参数
5、测试网络
######################################## 1、使用torchvision加载并预处理数据集 import torch as t import torchvision as tv import torchvision.transforms as transforms from torchvision.transforms import ToPILImage #定义对数据的预处理 transform=transforms.Compose([ transforms.ToTensor(), #转为Tensor transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))]) #归一化,到[-1,1] #训练集 #torchvision datasets 的输出是 PILImage 类型的 images, 像素取值范围在 [0, 1]。 #我们将其变换为归一化范围在[-1 , 1] 的 Tensors 类型 trainset=tv.datasets.CIFAR10( root="E:/data", #注意我的路径 train=True, download=False, #注意不下载 transform=transform) #载入数据的时候,转换为Tensor类型,并归一化到[-1,1] trainloader=t.utils.data.DataLoader( trainset, batch_size=4, #batch大小 shuffle=True, #打乱 num_workers=2) #2个线程 #测试集 testset=tv.datasets.CIFAR10( root="E:/data", train=False, download=False, transform=transform) testloader=t.utils.data.DataLoader( testset, batch_size=4, shuffle=False, num_workers=2) #类别标签 classes=("plane","car","bird","cat","deer","dog","frog","horse","ship","truck")
显示datasets中的第一幅图
(data,label)=trainset[0] #获取数据集的第一个元素,返回数据和标签索引 print(classes[label]) #label是6 show=ToPILImage() #把Tensor转成Image,方便可视化 show((data+1)/2).resize((100,100)) #(data+1)/2反归一化[-1,1]为[0,1],resize把32×32图变为100×100
显示Dataloader中的第一批图(4幅图为1个batch)
# 随机获取4张训练集图片(trainloader中4个元素为一批(batch)) dataiter = iter(trainloader) (images, labels) = dataiter.next() #以batch为单位,Dataloader类型与datasets一样返回数据、标签索引 print(labels) # 输出对应的标签 print(' '.join('%s' % classes[labels[j]] for j in range(4))) # 显示图像 show(tv.utils.make_grid((images+1)/2)).resize((400,100)) #显示4个图 #show((images[0]+1)/2).resize((100,100)) #显示第一个图
######################################## 2、定义网络 import torch.nn as nn import torch.nn.functional as F class Net(nn.Module): #定义网络类,继承自nn.Module def __init__(self): #类的构造函数 super(Net,self).__init__() #执行一次父类的构造函数(硬性要求),等价于 nn.Module.__init__(self) ## 卷积层 self.conv1=nn.Conv2d(3,6,5) #输入图像 3 个通道, 6 个输出通道, 5x5 方形卷积核 self.conv2=nn.Conv2d(6,16,5) #上层的6作为此层的输入,输出16通道,5x5 ## 仿射层/全连接层,y=Wx+b self.fc1=nn.Linear(16*5*5,120) self.fc2=nn.Linear(120,84) self.fc3=nn.Linear(84,10) def forward(self, x): #卷积→激活→池化 # 最大池化的窗口大小(2, 2) x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2)) # 如果池化窗口是方形的,你只需要指定单个数字 x = F.max_pool2d(F.relu(self.conv2(x)), 2) #-1代表自适应,reshape 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)
######################################## 3、定义损失函数和优化器 from torch import optim criterion=nn.CrossEntropyLoss() #交叉熵损失函数 optimizer=optim.SGD(net.parameters(),lr=0.001,momentum=0.9) #随机梯度下降法,指定要调整的参数和学习率,动量算法加速更新权重
所有网络的训练流程都类似,流程如下:
输入数据
前向传播+反向传播
更新参数
######################################## 4、训练网络并更新网络参数 for epoch in range(2): # 在整个数据集上轮番训练多次,轮训一次叫一个回合(epoch) running_loss = 0.0 for i, data in enumerate(trainloader, 0): # 输入数据 inputs, labels = data # 梯度清零 optimizer.zero_grad() # forward + backward outputs = net(inputs) loss = criterion(outputs, labels) loss.backward() #更新参数 optimizer.step() # 打印一些关于训练的统计信息 running_loss += loss.item() if i % 2000 == 1999: # 每 2000 个batch打印一次 print('[%d, %5d] loss: %.3f' % (epoch + 1, i + 1, running_loss / 2000)) running_loss = 0.0 print('Finished Training')
训练了2个回合,下面进行测试,输入图片,预测label与真实label比较
######################################## 5、测试网络
#获取datasets测试集中的前4幅图,并输出标签 dataiter = iter(testloader) (images, labels) = dataiter.next() #返回1个batch(4张图) # 输出图像和正确的类标签 print('实际的label:', ' '.join('%5s' % classes[labels[j]] for j in range(4))) show(tv.utils.make_grid((images+1)/2)).resize((400,100))
#测试上述的4幅图,并输出标签 outputs = net(images) #预测上边得到的batch(4张图),返回得分(每一类都打分) _, predicted = t.max(outputs, 1) #每1张图得分最高的那个类的下标 print(outputs) print(predicted) print('预测结果:', ' '.join('%5s' % classes[predicted[j]] for j in range(4)))
#测试整个测试集 correct = 0 #预测正确的图片数 total = 0 #总共的图片数 with t.no_grad(): for data in testloader: images, labels = data outputs = net(images) _, predicted = t.max(outputs.data, 1) total += labels.size(0) correct += (predicted == labels).sum().item() print('10000张测试集中的准确率: %d %%' % (100 * correct / total))
在GPU上训练
######################################## 在GPU上训练 if t.cuda.is_available(): net.cuda() #net、images、labels都要迁移到GPU上 images=images.cuda() labels=labels.cuda() output=net(images) loss=criterion(output,labels) #用上文选定的损失函数计算损失 print(loss)