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)

 

posted @ 2020-04-22 14:47  夕西行  阅读(471)  评论(0编辑  收藏  举报