通过实例实验去学习怎样读取数据。
一、人民币二分类
训练一个模型,使得它可以对第四套人民币的一元和一百元进行分类。实现将一张一元或一百元的人民币输入给模型,模型给出分类,是类别0或是类别1。
这里我们可以把人民币想象成自变量x,类别输出是因变量y,而模型就是将自变量x映射到因变量y。
那怎么训练一个机器学习的模型呢?
回顾之前学习的机器学习训练模型的五大步骤:
今天主要学习数据模块的数据读取。
数据模块通常还会分为四个子模块,分别是收集、读取、划分、预处理。
在进行实验之前,一定会先收集一批实验数据,数据有原始样本和标签。接着,对数据集进行划分,划分为训练集、验证集、测试集,三个数据集有其各自的作用,训练集用来训练模型;验证集用来验证模型是否过拟合,也可以理解为用验证集来挑选模型,挑选那些还没有过拟合时的模型;测试集用来测试挑选出来的模型,测试它们的性能。
然后是数据读取,就是今天要学习的DataLoader,pytorch中数据读取的核心是DataLoader。DataLoader还会分为两个子模块,Sampler的功能是生成索引,也就是样本的序号;DataSet是根据索引去读取图片、标签。
最后,将数据读取进来往往需要一系列的数据预处理,比如数据的中心化、标准化、旋转、翻转等等。在pytorch中通过tranforms实现。
二、Dataloader与Dataset
DataLoader
torch.utils.data.DataLoader
功能:构建可迭代的数据装载器(在训练时,每一个for循环,每一次Iteration,就是从DataLoader中去获取一个batchsize大小的数据)
- dataset: Dataset类, 决定数据从哪读取及如何读取
- batchsize:批大小
- num_ works:是否多进程读取数据(可以减少读取数据的时间、加速模型训练,若设备条件允许通常会开启多个进程读取数据)
- shuffle:每个epoch是否乱序
- drop_ last:当样本数不能被batchsize整除时,是否舍弃最后一批数据
Epoch:所有训练样本都已输入到模型中,称为一个Epoch
Iteration:一批样本输入到模型中,称之为一个Iteration(迭代)
Batchsize:批大小,决定一个Epoch有多少个Iteration
样本总数:80 , Batchsize:8
1 Epoch = 10 Iteration
样本总数:87, Batchsize:8
1 Epoch = 10 Iteration ? drop_ last = True
1 Epoch = 11 Iteration ?drop_ last = False
Dataset
Dataset用来定义数据从哪里读取以及如何读取的问题。
torch.utils.data.Dataset
功能:Dataset抽象类, 所有自定义的Dataset需要继承它,并且复写
_ _ getitem_ _ ()
getitem :接收一个索引,返回一个样本
看代码前,带着三个问题分析数据读取机制:
1.读取哪些数据?具体说就是在每一次Iteration该读取哪一些数据,每个 Iteration读取一个Batchsize大小,假如有80个样本,当我们从中读取8个样本,该读取哪8个样本
2.从哪读数据?也就是在硬盘当中,该怎么找我们的数据,在哪里去设置这一参数
3.怎么读数据?
从代码中进行学习,代码略(因为实在是太长),这三个问题可从代码调试过程中进行解答,调试过程略。
问题一:Index是从Sampler给出的,因此读哪些数据是由Sampler告诉我们的。
问题二:在Dataset中设置一个参数(Dataset是用户自己构建的),有data_dir告诉数据是在硬盘中的哪个文件夹。
问题三:在getitem中实现根据索引去读取数据。
将这一过程用流程图表示
过程流程图:
首先,在for循环中去使用DataLoader,进入DataLoader后根据是否采用多进程,即进入我们是采用多进程还是单进程的DataLoaderiter,之后使用Sampler去获取Index即索引,拿到索引后给到给到DatasetFetche,在这里面会调用DataSet,DataSet根据我们给定的索引在getitem中从硬盘里去读取实际图像和标签,在读取一个Batchsize大小的数据之后,通过一个collate_fn将这些数据进行整理,整理成一个BatchData的形式,然后就可以输入到模型中进行训练了。
作业:采用步进(Step into)的调试方法从 for i, data in enumerate(train_loader) 这一行代码开始,进入到每一个被调用函数,直到进入RMBDataset类中的__getitem__函数,记录从 for循环到RMBDataset的__getitem__所设计的类与函数?
例如:第一步:for i, data in enumerate(train_loader)
第二步:DataLoader类,__iter__函数
第三步: ***类, ***函数
第n步:RMBDataset类,__getitem__函数
答:读取数据步骤为
第1步:for i, data in enumerate(train_loader)(从DataLoader这个迭代器中不停地获取一个Batchsize大小的数据)
第2步:DataLoader类,_ _ iter_ _函数。简单的if循环判断,用来判断是否采用多进程,若采用多进程则有多进程的读取机制_MultiProcessingDataLoaderIter(self),单进程则有单进程的读取机制_SingleProcessDataLoaderIter(self),以单进程为例。
第3步:_SingleProcessDataLoaderIter类, _ _init _ _函数
第4步: _ BaseDataLoaderIter类, _ _ init _ _ 函数
第5步: _ DatasetKind类,create_fetcher函数
第6步:_MapDatasetFetcher类, _ _ init _ _ 函数
第7步:_SingleProcessDataLoaderIter类, _ _ next _ _ 函数,在next中获取Index和data
第8步:_BaseDataLoaderIter类, _ next_index函数,执行完这步后,Index就挑选出来了,形成一个列表,并且长度为16(因为一个Batchsize为16)
第9步:进入到sampler中,它就是一个采样器,用来告诉我们每一个Batchsize该读取哪些数据,BatchSampler类,_ _ iter_ _函数
第10步:RandomSampler类,_ _ iter_ _函数
第11步:RMBDataset类,_ _ len_ _函数
第12步:_MapDatasetFetcher类,fetch函数,在这一类中实现具体数据读取,在fetch函数中,调用dataset,并对dataset输入一个index作为一个索引,这样就会返回data,我们把这一系列data拼接成一个list
第13步:RMBDataset类,_ _ getitem_ _函数(Dataset的最主要最核心函数)实现数据读取与标签获取