数据对于深度学习而言是至关重要的, 丰富、 完整、 规范的数据集往往能训练出效果更佳的网络模型。 本节将首先介绍当前较为主流的公开数据集, 然后从数据的加载、 数据的GPU加速、 数据的可视化3个方面介绍PyTorch的使用方法。
1. 主流公开数据集
深度学习能够取得快速发展的一个原因是建立在大量数据的基础上, “数据为王”毫不夸张。 世界上一些先进的研究机构与公司开源了一些公开数据集, 这些数据集规模较大, 质量较高, 一方面方便研究者利用这些数据训练自己的模型, 同时也为先进的论文研究提供了标准的评测平台。
数据集随着深度学习算法的提升, 其规模也不断变大, 任务也渐渐地由简单到复杂。 下面简要介绍在物体检测领域较为重要的3个公开数据集。
1)ImageNet数据集
ImageNet数据集首次在2009年计算机视觉与模式识别(CVPR) 会 议上发布, 其目的是促进计算机图像识别的技术发展。 ImageNet数据集
从问世以来, 一直被作为计算机视觉领域最重要的数据集之一, 任何基于ImageNet的技术上的进步都会对计算机视觉领域产生重要的影响。
ImageNet数据集一共有1400多万张图片, 共计2万多个类别, 超过百万的图片有明确的类别标注, 以及图像中物体的位置信息, 如图2.6所示。
与ImageNet数据集对应的有一个享誉全球的ImageNet国际计算机视觉挑战赛(ILSVRC) , 该竞赛包含了图像分类、 物体检测与定位、 视
频物体识别等多个领域。 在2012年, Hinton带领的团队利用深度学习算法在分类竞赛中完胜其他对手, 在计算机领域引起了轰动, 进而掀起了
深度学习的浪潮。
随后的几年中, 众多公司与知名研究机构展开了激烈的角逐, 陆续诞生了众多先进的算法, 而在2017年的比赛则是最后一届, 以后会往更高的理解层发展。 值得一提的是, 通常我们在训练自己的模型时也经常使用从ImageNet上预训练得到的模型。
2. PASCAL VOC数据集
PASCAL VOC为图像分类与物体检测提供了一整套标准的数据集,并从2005年到2012年每年都举行一场图像检测竞赛。 PASCAL全称为Pattern Analysis,Statistical Modelling and Computational Learning, 其中常用的数据集主要有VOC 2007与VOC 2012两个版本, VOC 2007中包含了9963张标注过的图片及24640个物体标签。 在VOC 2007之上, VOC2012进一步升级了数据集, 一共有11530张图片, 包含人、 狗、 椅子和桌子等20个物体类别, 图片大小约500×375像素。 VOC整体图像质量较 好, 标注比较完整, 非常适合进行模型的性能测试, 如图2.7所示。
PASCAL VOC的另一个贡献在于提供了一套标准的数据集格式, 尤其是对于物体检测领域, 大部分的开源物体检测算法都提供了PASCALVOC的数据接口。 对于物体检测, 有3个重要的文件夹, 具体如下:
·JPEGImages: 包含所有训练与测试的图片。
·Annotations: 存放XML格式的标签数据, 每一个XML文件都对应于JPEGImages文件夹下的一张图片。
·ImageSets: 对于物体检测只需要Main子文件夹, 并在Main文件夹中建立Trainval.txt、 train.txt、 val.txt及test.txt, 在各文件中记录相应的图片名即可。
3) COCO(Common Objects in Context) 数据集
COCO是由微软赞助的一个大型数据集, 针对物体检测、 分割、 图 像语义理解和人体关节点等, 拥有超过30万张图片, 200万多个实例及80个物体类别。 在ImageNet竞赛停办后, COCO挑战赛成为了当前物体检测领域最权威的一个标杆。 相比PASCAL VOC, COCO数据集难度更大, 其拥有的小物体更多, 物体大小的跨度也更大, 如图2.8所示
。
与PASCAL VOC一样, 众多的开源算方法也通常会提供以COCO格式为标准的数据加载方式。 为了更好地使用数据集, COCO也提供了基于Lua、 Python及MATLAB的API, 具体使用方法可以参考开源代码。
当然, 随着自动驾驶领域的快速发展, 也出现了众多自动驾驶领域的数据集, 如KITTI、 Cityscape和Udacity等, 具体使用方法可以查看相关数据集官网。
2. 数据加载
PyTorch将数据集的处理过程标准化, 提供了Dataset基本的数据类, 并在torchvision中提供了众多数据变换函数, 数据加载的具体过程主要分为3步, 如图2.9所示
。
这3步的具体功能与实现如下 :
2.1 继承Dataset类
对于数据集的处理, PyTorch提供了torch.utils.data.Dataset这个抽象类, 在使用时只需要继承该类, 并重写__len__()和__getitem()__函数,即可以方便地进行数据集的迭代
1 from torch.utils.data import Dataset 2 3 class my_data(Dataset): 4 5 def __init__(self, image_path, annotation_path, transform =None): 6 # 初始化,读取数据集 7 8 def __len__(self): 9 # 获取数据集的总大小 10 11 def __getitem__(self, id): 12 # 对于指定的id, 读取该数据并返回
对上述类进行实例化, 即可进行迭代如下:
dataset = my_data("your image path", "your annotation path") # 实例化该类 for data in dataset: print(data)
2.2 数据变换与增强: torchvision.transforms
第一步虽然将数据集加载到了实例中, 但在实际应用时, 数据集中的图片有可能存在大小不一的情况, 并且原始图片像素RGB值较大( 0~255) , 这些都不利于神经网络的训练收敛, 因此还需要进行一些图像变换工作。 PyTorch为此提供了torchvision.transforms工具包, 可以方便地进行图像缩放、 裁剪、 随机翻转、 填充及张量的归一化等操作,操作对象是PIL的Image或者Tensor。
如果需要进行多个变换功能, 可以利用transforms.Compose将多个变换整合起来, 并且在实际使用时, 通常会将变换操作集成到Dataset的继承类中。 具体示例如下:
1 from torchvision import transforms 2 # 将transforms集成到Dataset类中, 使用Compose将多个变换整合到一起 3 dataset = my_data("your image path", "your annotation path",transforms = 4 transforms.Compose([ 5 transforms.Resize(256) # 将图像最短边缩小至256, 宽高比例不变 6 # 以0.5的概率随机翻转指定的PIL图像 7 transforms.RandomHorizontalFlip() 8 # 将PIL图像转为Tensor, 元素区间从[0, 255]归一到[0, 1] 9 transforms.ToTensor() 10 # 进行mean与std为0.5的标准化 11 transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]) 12 ] 13 ) 14 )
2.3 继承dataloader
经过前两步已经可以获取每一个变换后的样本, 但是仍然无法进行批量处理、 随机选取等操作, 因此还需torch.utils.data.Dataloader类进一步进行封装, 使用方法如下例所示, 该类需要4个参数, 第1个参数是之前继承了Dataset的实例, 第2个参数是批量batch的大小, 第3个参数是是否打乱数据参数, 第4个参数是使用几个线程来加载数据
。
1 from torch.utils.data import DataLoader 2 3 dataloader = DataLoader(dataset, batch_size=4, 4 shuffle=True, num_workers=4) 5
dataloader是一个可迭代对象, 对该实例进行迭代即可用于训练过程。
1 data_iter = iter(dataloader) 2 for step in range(iters_per_epoch): 3 data = next(data_iter) 4 # 将data用于训练网络即可
3. GPU加速
PyTorch为数据在GPU上运行提供了非常便利的操作。 首先可以使用torch.cuda.is_available()来判断当前环境下GPU是否可用, 其次是对于Tensor和模型, 可以直接调用cuda()方法将数据转移到GPU上运行, 并且可以输入数字来指定具体转移到哪块GPU上运行
.
1 import torch 2 from torchvision import models 3 4 a = torch.randn(3,3) 5 b = models.vgg16() 6 7 if torch.cuda.is_available(): 8 a = a.cuda() 9 10 b = b.cuda(1) 11 12 device = torch.device("cuda: 0") 13 c = torch.randn(3, 3, device=device, requires_grad= True)
对于在全局指定使用哪一块GPU, 官方给出了两种方法, 首先是在终端执行脚本时直接指定GPU的方式, 如下 :
1 CUDA_VISIBLE_DEVICES=2 python3 train.py
其次是在脚本中利用函数指定, 如下:
1 import torch 2 torch.cuda.set_device(1)
官方建议使用第一种方法, 即CUDA_VISIBLE_DEVICE的方式。
在工程应用中, 通常使用torch.nn.DataParallel(module,device_ids)函数来处理多GPU并行计算的问题。 示例如下
:
1 model_gpu = nn.DataParallel(model, device_ids=[0,1]) 2 output = model_gpu(input)
多GPU处理的实现方式是, 首先将模型加载到主GPU上, 然后复制模型到各个指定的GPU上, 将输入数据按batch的维度进行划分, 分配每个GPU上独立进行前向计算, 再将得到的损失求和并反向传播更新单个GPU上的参数, 最后将更新后的参数复制到各个GPU上 。