zoukankan      html  css  js  c++  java
  • pytorch例子学习——TRAINING A CLASSIFIER

    参考:https://pytorch.org/tutorials/beginner/blitz/cifar10_tutorial.html#sphx-glr-beginner-blitz-cifar10-tutorial-py

    TRAINING A CLASSIFIER

    到这里,你已经知道怎么定义神经网络,计算损失和更新网络的权重

    现在你应该考虑:

    What about data?

    通常,当你必须要处理一些图片、文本、音频或视频数据时,你可以使用标准的python包去下载数据到一个numpy数组中。然后你可以转换该数组为torch.*Tensor

    • 对于图像,如Pillow、OpenCV这些包就很有用
    • 对于音频,如scipy、librosa这些包
    • 对于文本,要么是原始python,要么是基于下载的Cython,或者是NLTK和SpaCy也都很有用

    尤其是对于视图,我们创建了一个名为torchvision的包,有着用于如Imagenet、CIFAR10、MNIST等普通数据库的数据下载器和用于图像的数据转换器,即torchvision.datasets和torch.utils.data.DataLoader

    这提供了很大的便利,也防止编写样板代码

    在这个教程中,我们将使用CIFAR10数据集,它有着 ‘airplane’, ‘automobile’, ‘bird’, ‘cat’, ‘deer’, ‘dog’, ‘frog’, ‘horse’, ‘ship’, ‘truck’等类别,下面是CIFAR-10中大小为3*32*32的图像,即32*32像素大小的3通道颜色的图像

    Training an image classifier训练一个图像分类器

    我们将会按顺序进行下面的操作:

    1.使用torchvision下载和归一化训练和测试数据集

    2.定义卷积神经网络

    3.定义损失函数

    4.在训练数据中训练网络

    5.在测试数据中测试网络

    1. Loading and normalizing CIFAR10

    使用torchvision,它能很容易地去下载CIFAR10数据

    import torch
    import torchvision
    import torchvision.transforms as transforms

    torchvision数据集的输出是范围在[0,1]的PILImage图像。我们转换它们成有着标准化范围[-1,1]的张量

    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,  #是否随机打乱图片进行分批,是则为true
        num_workers=2  #获取数据的线程为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 = ('plane', 'car', 'bird', 'cat','deer', 'dog', 'frog', 'horse', 'ship', 'truck')

     运行后首先进行数据的下载:

    (deeplearning2) userdeMBP:classifier cifar user$ python cifar10_tutorial.py 
    Downloading https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz to ./data/cifar-10-python.tar.gz
    100.0%Files already downloaded and verified

    下面展示一些训练图像:

    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.imshow在显示时需要的输入是(imgsize,imgsieze,channels),但是这里是(channels,imgsize,imgsieze),所以需要将位置换换
        plt.show()
    
    
    # 随机得到一些训练图像
    dataiter = iter(trainloader) #生成迭代器
    images, labels = dataiter.next() #每次运行next()就会调用trainloader,获得一个之前定义的batch_size=4的批处理图片集,即4张图片
    
    # 展示图像
    imshow(torchvision.utils.make_grid(images)) #make_grid的作用是将若干幅图像拼成一幅图像,在想要展示一批数据的时候十分有用
    # 输出图像标签
    print(' '.join('%5s' % classes[labels[j]] for j in range(4)))

    然后点击关闭图片,就会继续向下运行,就能够得到预测的结果:

    horse horse  bird   car

    2. Define a Convolutional Neural Network定义一个卷积神经网络

    从之前的神经网络部分复制神经网络,并修改其应用于3通道图片(而不是之前的1通道图片)

    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) #卷积层,参数为(inchannel,outchannel=number of filter,siza of filter,stride,padding)
            self.pool = nn.MaxPool2d(2, 2)  #池化层
            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) #全连接层,最后输出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展平成16 * 5 * 5,然后就可以进行下面的全连接层操作
            x = F.relu(self.fc1(x))
            x = F.relu(self.fc2(x))
            x = self.fc3(x)
            return x
    
    
    net = Net()

    3. Define a Loss function and optimizer定义一个损失函数和优化器

    使用分类Cross-Entropy损失和带有动量的SGD优化

    import torch.optim as optim
    
    criterion = nn.CrossEntropyLoss()
    optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

    4. Train the network 训练网络

    循环数据迭代,并输入到网络,然后进行优化

    for epoch in range(2):  # 多次循环数据集,这里循环训练整个数据集两次
    
        running_loss = 0.0
        for i, data in enumerate(trainloader, 0): #enumerate枚举数据并从下标0开始
            # 得到输入数据
            inputs, labels = data
    
            # 将参数的梯度都设为0
            optimizer.zero_grad()
    
            # forward + backward + optimize
            outputs = net(inputs) #forward
            loss = criterion(outputs, labels) #计算损失
            loss.backward() #后向传播
            optimizer.step() #将优化后的参数输入网络,再次进行训练
    
            #打印数据
            running_loss += loss.item() #用于从tensor中获取python数字
            if i % 2000 == 1999:    # 每处理2000次小批处理数据后打印一次结果
                print('[%d, %5d] loss: %.3f' %(epoch + 1, i + 1, running_loss / 2000))
                running_loss = 0.0 #然后清0
    
    print('Finished Training')

     然后返回输出为:

    [1,  2000] loss: 2.195
    [1,  4000] loss: 1.848
    [1,  6000] loss: 1.654
    [1,  8000] loss: 1.578
    [1, 10000] loss: 1.511
    [1, 12000] loss: 1.459
    [2,  2000] loss: 1.382
    [2,  4000] loss: 1.375
    [2,  6000] loss: 1.344
    [2,  8000] loss: 1.314
    [2, 10000] loss: 1.317
    [2, 12000] loss: 1.284
    Finished Training

    5. Test the network on the test data在测试数据中测试网络

    我们对网络进行了两次遍历训练数据集的训练。但我们还是需要查看网络是否学习了所有的东西

    我们将会通过预测神经网络输出的类型标签来检查它,并与事实相对照。如果预测是正确的,我们将样本添加到正确预测列表中。

    好的,第一步,让我们从测试集中显示一个图像来熟悉它。

    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)))

     然后出现四张图片:

    然后点击关闭图片,就会返回实际该图片的标签:

    ('GroundTruth: ', '  cat  ship  ship plane')

    然后让我们看看神经网络认为上面的例子是什么:

    outputs = net(images)

    输出是这10个类的能量。一个类的能量越高,网络越认为图像属于特定的类。所以,让我们得到最高能量的指数:

    _, predicted = torch.max(outputs, 1)
    
    print('Predicted: ', ' '.join('%5s' % classes[predicted[j]] for j in range(4)))

     返回预测值:

    ('Predicted: ', '  cat plane truck plane')

    让我们看看网络在整个数据集中表现得怎么样

    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))

     ⚠️(predicted == labels).sum().item()作用:可见(predicted == labels).sum().item()作用

    返回:

    Accuracy of the network on the 10000 test images: 53 %

    这看起来比随机抽取10%的正确率(从10个类中随机抽取一个类)要好得多。看来网络学到了一些东西。
    那么是哪些类执行得好,哪些类执行得不好呢?

    class_correct = list(0. for i in range(10))
    class_total = list(0. for i in range(10))
    with torch.no_grad(): #设置在进行forward时不计算梯度
        for data in testloader:
            images, labels = data
            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]))

     返回:

    Accuracy of plane : 45 %
    Accuracy of   car : 67 %
    Accuracy of  bird : 45 %
    Accuracy of   cat : 31 %
    Accuracy of  deer : 53 %
    Accuracy of   dog : 24 %
    Accuracy of  frog : 66 %
    Accuracy of horse : 58 %
    Accuracy of  ship : 69 %
    Accuracy of truck : 77 %

    接下来就是设置运行在GPU上:

    就像你把张量传输到GPU上一样,你把神经网络传输到GPU上。
    让我们首先定义我们的设备为第一个可见的cuda设备,如果我们有cuda可用:

    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    
    # Assuming that we are on a CUDA machine, this should print a CUDA device:
    
    print(device)

    因为我是在CPU上运行的,所以这里print(device)会返回cpu

    本节的其余部分假设设备是CUDA设备。
    然后这些方法递归遍历所有模块,将它们的参数和缓冲区转换为CUDA张量:

    net.to(device)

    记住,你必须在每一步都把输入和目标值的发送到GPU中:

    inputs, labels = inputs.to(device), labels.to(device)

    为什么我没有注意到GPU与CPU相比的巨大加速?因为你的网络实在是太小了。


    练习:

    尝试增加网络的宽度(即第一个nn.Conv2d卷积层的参数2)和第二个nn.Conv2d卷积层的参数1 — 他们需要相同的数字,看看你得到什么样的加速。
    实现目标:

    • 高层次地理解PyTorch张量库和神经网络。
    • 训练一个小的神经网络对图像进行分类
  • 相关阅读:
    解决input获取焦点时底部菜单被顶上来问题
    JavaScript学习笔记
    JavaScript表单验证
    js 中{},[]中括号,大括号使用详解
    陀飞轮
    娱乐天空
    左右手
    软测 学习
    git 学习
    spring boot 学习
  • 原文地址:https://www.cnblogs.com/wanghui-garcia/p/10558805.html
Copyright © 2011-2022 走看看