PyTorch学习笔记6—PyTorch深度学习入门(四)—入门实例

本篇是pytorch学习笔记系列第六篇,这一系列博客应该大多会来自于开源教程书:pytorch中文手册(pytorch handbook),其github网址为:https://github.com/zergtant/pytorch-handbook 本篇博客内容来自于这一手册以及pytorch官方的教程 ,感兴趣的观众门可以去自行下载

4. 实例:训练cifar10图像分类器

4.1 前言:关于数据

一般情况下处理图像,文本,音频和视频数据时,可以使用标准的Python包来加载数据到一个numpy数组中. 然后把这个数组转换成 torch.*Tensor。其中:

  • 图像可以使用 Pillow, OpenCV
  • 音频可以使用 scipy , librosa
  • 文本可以使用原始Python和Cython来加载,或者使用 NLTK或 SpaCy 处理

4.1.1 Dataset

Dataset是一个抽象类, 为了能够方便的读取,需要将要使用的数据包装为Dataset类。 自定义的Dataset需要继承它并且实现两个成员方法:

getitem() :该方法定义每次怎么获取数据
len() :该方法返回数据集的总长度

下面我们使用kaggle上的一个竞赛bluebook for bulldozers自定义一个数据集,为了方便介绍,我们使用里面的数据字典来做说明(因为条数少)
下面我们使用kaggle上的一个竞赛bluebook for bulldozers自定义一个数据集,为了方便介绍,我们使用里面的数据字典来做说明(因为条数少)

from torch.utils.data import Dataset
import pandas as pd
#定义一个数据集
class BulldozerDataset(Dataset):
    """ 数据集演示 """
    def __init__(self, csv_file):
        """实现初始化方法,在初始化的时候将数据读载入"""
        self.df=pd.read_csv(csv_file)
    def __len__(self):
        '''
        返回df的长度
        '''
        return len(self.df)
    def __getitem__(self, idx):
        '''
        根据IDX返回一列数据
        '''
        return self.df.iloc[idx].SalePrice

至此,我们的数据集已经定义完成了,我们可以实例话一个对象访问他

ds_demo= BulldozerDataset('median_benchmark.csv')
len(ds_demo)#实现了__len__ 方法所以可以直接使用len获取数据总数
ds_demo[0]#用索引可以直接访问对应的数据

得到以下输出:

11573
24000.0

4.1.2 Datalorder

DataLoader为我们提供了对Dataset的读取操作,常用参数有:batch_size(每个batch的大小), shuffle(是否进行shuffle操作), num_workers(加载数据的时候使用几个子进程),下面做一个简单的操作

dl = torch.utils.data.DataLoader(ds_demo, batch_size=10, shuffle=True, num_workers=0)DataLoader #返回的是一个迭代器,我们可以使用迭代器分次获取数据
idata=iter(dl)
print(next(idata))
for i, data in enumerate(dl):
    print(i,data)
    #这里只循环一遍
    break

输出结果:

tensor([24000., 24000., 24000., 24000., 24000., 24000., 24000., 24000., 24000.,
        24000.], dtype=torch.float64)

0 tensor([24000., 24000., 24000., 24000., 24000., 24000., 24000., 24000., 24000.,
        24000.], dtype=torch.float64)

可以看到:我们已经可以通过dataset定义数据集,并使用Datalorder载入和遍历数据集,

4.1.3 torchvision 包

特别的,对于图像任务, pytorch创建了一个包 torchvision,它包含了处理一些基本图像数据集的方法,主要包括几个模块:图像转换器torchvision.transforms、数据集torchvision.datasets 和 数据集加载torch.utils.data.DataLoader.

4.1.3.1 transforms

transforms 模块提供了一般的图像转换操作类,用作数据的处理和增广,如下例定义了一个图像转换器:

from torchvision import transforms as transforms
transform = transforms.Compose([
    transforms.RandomCrop(32, padding=4),  #先四周填充0,在吧图像随机裁剪成32*32
    transforms.RandomHorizontalFlip(),  #图像一半的概率翻转,一半的概率不翻转
    transforms.RandomRotation((-45,45)), #随机旋转
    transforms.ToTensor(),
    transforms.Normalize((0.4914, 0.4822, 0.4465), (0.229, 0.224, 0.225)), #R,G,B每层的归一化用到的均值和方差
])

肯定有人会问:(0.485, 0.456, 0.406), (0.2023, 0.1994, 0.2010) 这几个数字是什么意思?

官方的这个帖子有详细的说明: https://discuss.pytorch.org/t/normalization-in-the-mnist-example/457/21 这些都是根据ImageNet训练的归一化参数,可以直接使用,pytorch认为这个是固定值就可以

4.1.3.2 datasets

torchvision.datasets包包含很多数据集,可以理解为PyTorch团队自定义的dataset,这些dataset帮我们提前处理好了很多的图片数据集,我们拿来就可以直接使用:

  • MNIST
  • COCO
  • Captions
  • Detection
  • LSUN
  • ImageFolder
  • Imagenet-12
  • CIFAR
  • STL10
  • SVHN
  • PhotoTour

如下例所示导入了MNIST数据集

import torchvision.datasets as datasets
trainset = datasets.MNIST(root='./data', # 表示 MNIST 数据的加载的目录
                                      train=True,  # 表示是否加载数据库的训练集,false的时候加载测试集
                                      download=True, # 表示是否自动下载 MNIST 数据集
                                      transform=None) # 表示是否需要对数据进行预处理,none为不进行预处理
4.1.3.3 models

torchvision不仅提供了常用图片数据集,还提供了训练好的模型,可以加载之后,直接使用,或者在进行迁移学习 torchvision.models模块的 子模块中包含以下模型结构。

  • AlexNet
  • VGG
  • ResNet
  • SqueezeNet
  • DenseNet

我们直接可以使用训练好的模型,当然这个与datasets相同,都是需要从服务器下载的

如下例所示将导入resnet18这个网络模型

import torchvision.models as models
resnet18 = models.resnet18(pretrained=True)

所以说,torchvision包不仅提供了巨大的便利,也避免了代码的重复.

4.2 实例代码

在这个实例中,我们使用CIFAR10数据集,它有如下10个类别:‘airplane’, ‘automobile’, ‘bird’, ‘cat’, ‘deer’, ‘dog’, ‘frog’, ‘horse’, ‘ship’, ‘truck’. CIFAR-10的图像都是 3x32x32大小的,即3颜色通道,32*32像素.

训练一个图像分类器,将依次按照下列顺序进行:

  1. 使用torchvision加载和归一化CIFAR10训练集和测试集
  2. 定义一个卷积神经网络
  3. 定义损失函数
  4. 在训练集上训练网络
  5. 在测试集上测试网络
import torch
import torchvision
import torchvision.transforms as transforms

import matplotlib.pyplot as plt
import numpy as np

import torch.nn as nn

import torch.optim as optim

import time
start =time.process_time()


# 展示图像的函数
def imshow(img):
    img = img / 2 + 0.5     # unnormalize
    npimg = img.cpu().numpy()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))
    plt.show()

'''1.读取数据集'''
#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))])
#print(transform)
#读取数据集
trainset = torchvision.datasets.CIFAR10(root='./data', train=True,download=False, 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=False, num_workers=0)
classes = ('plane', 'car', 'bird', 'cat','deer', 'dog', 'frog', 'horse', 'ship', 'truck')

'''测试数据集是否可用'''
# 获取随机数据
dataiter = iter(trainloader)
images, labels = dataiter.next()

# 展示图像
imshow(torchvision.utils.make_grid(images))
# 显示图像标签
print(' '.join('%5s' % classes[labels[j]] for j in range(4)))

# 确认我们的电脑支持 CUDA ,然后显示CUDA信息:
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(device)

'''2.定义卷积神经网络'''
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        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)

    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 = Net()
#将递归遍历所有模块并将模块的参数和缓冲区 转换成CUDA张量的:
net.to(device)

'''3.定义损失函数和优化器
使用交叉熵作为损失函数,使用带动量的随机梯度下降'''
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)


'''4.训练网路'''
for epoch in range(2):  # 多批次循环

    running_loss = 0.0
    for i, data in enumerate(trainloader, 0):
        # 获取输入
        inputs, labels = data
        # inputs 和targets 也要转换
        inputs, labels = inputs.to(device), labels.to(device)
        # 梯度置0
        optimizer.zero_grad()

        # 正向传播,反向传播,优化
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        # 打印状态信息
        running_loss += loss.item()
        if i % 2000 == 1999:    # 每2000批次打印一次
            print('[%d, %5d] loss: %.3f' %
                  (epoch + 1, i + 1, running_loss / 2000))
            running_loss = 0.0

print('Finished Training')

'''5.测试集测试网络'''
dataiter = iter(testloader)
images, labels = dataiter.next()
images, labels = images.to(device), labels.to(device)

#5.1 用几张图片来测试
# 显示图片和标签
imshow(torchvision.utils.make_grid(images))
print('GroundTruth: ', ' '.join('%5s' % classes[labels[j]] for j in range(4)))
#神经网络的预测结果
outputs = net(images)
_, predicted = torch.max(outputs, 1)
print('Predicted: ', ' '.join('%5s' % classes[predicted[j]] for j in range(4)))

#5.2 查看网络在测试集上的准确率
correct = 0
total = 0
with torch.no_grad():
    for data in testloader:
        images, labels = data
        # inputs 和targets 也要转换
        images, labels = images.to(device), labels.to(device)
        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))

#5.3 查看网络在各个类别测试的准确率
class_correct = list(0. for i in range(10))
class_total = list(0. for i in range(10))
with torch.no_grad():
    for data in testloader:
        images, labels = data
        # inputs 和targets 也要转换
        images, labels = images.to(device), labels.to(device)
        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]))

#输出程序运行时间
end = time.process_time()
print('Running time: %s Seconds'%(end-start))

上例的代码是在GPU中运行的,若要改成CPU运行,需将其中的.to方法去掉

如果有多个GPU,需要数据并行,则在定义网络对象后,可以使用DataParallel方法让模型并行运行在多个GPU上。

net= nn.DataParallel(net)

至此,我们已经使用pytorch完成了一个深度学习的编程全过程,进行了初步的入门:使用torchvision加载和归一化CIFAR10训练集和测试集、定义一个卷积神经网络、定义损失函数、在训练集上训练网络、在测试集上测试网络。

更加深入的的案例,比如其他神经网络、其他损失函数和优化器,将在之后的学习笔记中记录。

本篇完…

本系列已更新的学习笔记:
PyTorch学习笔记1—PyTorch简介
PyTorch学习笔记2—win10下pytorch-gpu安装以及CUDA安装记录
PyTorch学习笔记3—PyTorch深度学习入门(一)—基本方法
PyTorch学习笔记4—PyTorch深度学习入门(二)—自动求导
PyTorch学习笔记5—PyTorch深度学习入门(三)—神经网络
PyTorch学习笔记6—PyTorch深度学习入门(四)—入门实例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值