目录
dataset
dataset从磁盘中读取数据,然后进行预处理,最后通过getitem返回一组训练样本。
dataset用来处理单个训练样本,从磁盘中读取训练数据集(特征、标签)映射成x,y。
dataloader是对于多个样本而言的,变成随机梯度下降的minibatches的形式。多个样本组成一个minibatch,
官方文档:
如何编写自己的dataset类,怎么基于自己的dataset放到dataloader中,进行小批次的神经网络的训练。
编写自己的dataset需要继承官方的dataset类
需要实现:_ _getitem_ _函数:基于一个索引,返回一个训练样本。
_ _init_ _函数,一般是需要告诉文件存储位置、
_ _len_ _函数:数据集的大小。
官方文档的例子:
从磁盘中读取训练数据,然后在_ _getitem_ _中,基于索引能够返回对应样本。
import os
import pandas as pd
from torchvision.io import read_image
# transform=None, target_transform=None 分别对特征和标签进行预处理的函数
class CustomImageDataset(Dataset):
def __init__(self, annotations_file, img_dir, transform=None, target_transform=None):
self.img_labels = pd.read_csv(annotations_file)
self.img_dir = img_dir
self.transform = transform
self.target_transform = target_transform
def __len__(self):
return len(self.img_labels)
def __getitem__(self, idx): # 对指定的索引,返回当前的训练样本
img_path = os.path.join(self.img_dir, self.img_labels.iloc[idx, 0])
image = read_image(img_path)
label = self.img_labels.iloc[idx, 1] #idx行, 第1列存储了label
if self.transform:
image = self.transform(image)
if self.target_transform:
label = self.target_transform(label)
return image, label
dataset有两种类型:map是通过index或者key进行随机访问的数据集,iterable类似于单链表不太适合随机访问
dataloader
对单个样本组成一个minibatches
dataset每次处理一个样本,返回一个特征和该特征对应对应的标签,但是当我们训练模型的时候,我们通常是一次训练一批样本。使训练效率更高,抗噪效率更好。
在每一个训练周期完成以后,对数据进行一个打乱reshuffle,可以降低模型过拟合的可能性,
多进程处理multiprocessing加载数据。num_worker在windows中必须为0,不然会报错。
dataloader使用方法:
先对创建的dataset类实例化一下,传入到dataloader中,
from torch.utils.data import DataLoader
train_dataloader = DataLoader(training_data, batch_size=64, shuffle=True)
test_dataloader = DataLoader(test_data, batch_size=64, shuffle=True)
test一般不需要shuffle,test不参与梯度更新,只是做一下前向运算。
如果batch_size=64,那我们就得到64个特征和64个标签。shuffle=True在每遍历完所有的batch后,数据就会被打乱一遍。
iter(train_dataloader)把dataloader变成一个迭代器,通过next()函数生成一个一个批次。
深入剖析dataloader
把单个样本组成一批次,然后在用神经网络训练。
dataloader参数说明:
- # 通过自定义的dataset一个类,通过实例化一个对象,就可以放在dataloader中,
- # batch_size、shuffle都要改。
- # sampler决定我们可以自定义的方式去从dataset当中取样本。shuffler就不用设置了。对构建minibatches有什么特定需求,就可以自己设定一个samper
- # num_workerss多进程的
- # collate_fn:聚集函数,一般对一个batch进行后处理的
def __init__(self, dataset: Dataset[T_co], batch_size: Optional[int] = 1,
shuffle: Optional[bool] = None, sampler: Union[Sampler, Iterable, None] = None,
batch_sampler: Union[Sampler[Sequence], Iterable[Sequence], None] = None,
num_workers: int = 0, collate_fn: Optional[_collate_fn_t] = None,
pin_memory: bool = False, drop_last: bool = False,
timeout: float = 0, worker_init_fn: Optional[_worker_init_fn_t] = None,
multiprocessing_context=None, generator=None,
*, prefetch_factor: int = 2,
persistent_workers: bool = False,
pin_memory_device: str = ""):
class具体的工作原理
对成员变量进行一个设置:
self.dataset = dataset
self.num_workers = num_workers
self.prefetch_factor = prefetch_factor
self.pin_memory = pin_memory
self.pin_memory_device = pin_memory_device
self.timeout = timeout
self.worker_init_fn = worker_init_fn
self.multiprocessing_context = multiprocessing_context
sampler 、shuffle同时定义就没意义了:样本级别的采样
if sampler is not None and shuffle: raise ValueError('sampler option is mutually exclusive with ' 'shuffle')
batch级别的的采样batch_samper:
batch_size != 1 or 设置了shuffle or sampler is not None or drop_last都不行,都与batch_samper互斥 batch_samper 不用设置batch_size了