原文:https://likewind.top/2019/02/01/Pytorch-dataprocess/javascript
Pytorch系列:html
参考:java
本文首先介绍了有关预处理包的源码,接着介绍了在数据处理中的具体应用; 其主要目录以下:git
torch.utils.data脚本码源github
1 class torch.utils.data.Dataset
表示Dataset的抽象类。全部其余数据集都应该进行子类化。 全部子类应该override__len__
和__getitem__
,前者提供了数据集的大小,后者支持整数索引,范围从0到len(self)。网络
class Dataset(object): # 强制全部的子类override getitem和len两个函数,不然就抛出错误; # 输入数据索引,输出为索引指向的数据以及标签; def __getitem__(self, index): raise NotImplementedError # 输出数据的长度 def __len__(self): raise NotImplementedError def __add__(self, other): return ConcatDataset([self, other])
class torch.utils.data.TensorDataset(*tensors)
Dataset的子类。包装tensors数据集;输入输出都是元组; 经过沿着第一个维度索引一个张量来回复每一个样本。 我的感受比较适用于数字类型的数据集,好比线性回归等。dom
class TensorDataset(Dataset): def __init__(self, *tensor): assert all(tensors[0].size(0) == tensor.size(0) for tensor in tensors) self.tensors = tensors def __getitem__(self, index): return tuple(tensor[index] for tensor in tensors def __len__(self): return self.tensors[0].size(0)
class torch.utils.data.ConcatDateset(datasets)
链接多个数据集。 目的:组合不一样的数据集,多是大规模数据集,由于连续操做是随意链接的。 datasets的参数:要链接的数据集列表 datasets的样式:iterableasync
class ConcatDataset(Dataset): @staticmethod def cumsum(sequence): # sequence是一个列表,e.g. [[1,2,3], [a,b], [4,h]] # return 一个数据大小列表,[3, 5, 7], 明显看的出来包含数据多少,第一个表明第一个数据的大小,第二个表明第一个+第二数据的大小,最后表明全部的数据大学; ... def __getitem__(self, idx): # 主要是这个函数,经过bisect的类实现了任意索引数据的输出; dataset_idx = bisect.bisect_right(self.cumulative_size, idx) if dataset_idx == 0: sample_idx == idx else: sample_idx = idx - self.cumulative_sizes[dataset_idx -1] return self.datasets[dataset_idx][sample_idx] ...
class torch.utils.data.Subset(dataset, indices)
选取特殊索引下的数据子集; dataset:数据集; indices:想要选取的数据的索引;ide
class torch.utils.data.random_split(dataset, lengths):
随机不重复分割数据集; dataset:要被分割的数据集 lengths:长度列表,e.g. [7, 3], 保证7+3=len(dataset)函数
class torch.utils.data.DataLoader(dataset, batch_size=1, shuffle=False, sampler=None, batch_sampler=None, num_workers=0, collate_fn=<function default_collate>, pin_memory=False, drop_last=False, timeout=0, worker_init_fn=None)
数据加载器。 组合数据集和采样器,并在数据集上提供单进程或多进程迭代器。 参数:
None
, this will be called on each worker subprocess with the worker id (an int in [0, num_workers - 1]
) as input, after seeding and before data loading. (default: None
)特别重要:DataLoader中是不断调用DataLoaderIter
class _DataLoaderIter(loader)
从DataLoader’s数据中迭代一次。其上面DataLoader
功能都在这里; 插个眼,有空在分析这个
class torch.utils.data.sampler.Sampler(data_source)
全部采样器的基础类; 每一个采样器子类必须提供一个__iter__
方法,提供一种迭代数据集元素的索引的方法,以及返回迭代器长度__len__
方法。
class Sampler(object): def __init__(self, data_source): pass def __iter__(self): raise NotImplementedError def __len__(self): raise NotImplementedError
class torch.utils.data.SequentialSampler(data_source)
样本元素顺序排列,始终以相同的顺序。 参数:-data_source (Dataset) - 采样的数据
class torch.utils.data.RandomSampler(data_source, replacement=False, num_samples=None)
样本随机排列,若是没有Replacement,将会从打乱的数据采样,不然,。。 参数:
class torch.utils.data.SubsetRandomSampler(indices)
从给出的索引中随机采样,without replacement。 参数:
class torch.utils.data.BatchSampler(sampler, batch_size, drop_last)
将采样封装到批处理索引。 参数:
class torch.utils.data.WeightedRandomSampler(weights, num_samples, replacement=True)
样本元素来自[0,…,len(weights)-1], 给定几率(权重)。 参数:
class torch.utils.data.distributed.DistributedSampler(dataset, num_replicas=None, rank=None)
????没读呢
计算机视觉用到的库,文档以及码源以下:
具备一下图像数据以下表示:
但愿可以训练模型,使得可以识别tumor, normal两类,将tumor–>1, normal–>0。
在PyTorch中数据的读取借口须要通过,Dataset和DatasetLoader (DatasetloaderIter)。下面就此分别介绍。
首先导入必要的包。
import os import numpy as np from torch.utils.data import Dataset from PIL import Image np.random.seed(0)
其次定义MyDataset类,为了代码整洁精简,将没必要要的操做全删,e.g. 图像剪切等。
class MyDataset(Dataset): def __init__(self, root, size=229, ): """ Initialize the data producer """ self._root = root self._size = size self._num_image = len(os.listdir(root)) self._img_name = os.listdir(root) def __len__(self): return self._num_image def __getitem__(self, index): img = Image.open(os.path.join(self._root, self._img_name[index])) # PIF image: H × W × C # torch image: C × H × W img = np.array(img, dtype-np.float32).transpose((2, 0, 1)) return img
将MyDataset封装到loader器中。
from torch.utils.data import DataLoader # 实例化MyData dataset_tumor_train = MyDataset(root=/img/train/tumor/) dataset_normal_train = MyDataset(root=/img/train/normal/) dataset_tumor_validation = MyDataset(root=/img/validation/tumor/) dataset_normal_validation = MyDataset(root=/img/validation/normal/) # 封装到loader dataloader_tumor_train = DataLoader(dataset_tumor_train, batch_size=10) dataloader_normal_train = DataLoader(dataset_normal_train, batch_size=10) dataloader_tumor_validation = DataLoader(dataset_tumor_validation, batch_size=10) dataloader_normal_validation = DataLoader(dataset_normal_validation, batch_size=10)
简单将数据流接口与训练链接起来
def train_epoch(model, loss_fn, optimizer, dataloader_tumor, dataloader_normal): model.train() # 因为tumor图像和normal图像同样多,因此将tumor,normal链接起来,steps=len(tumor_loader)=len(normal_loader) steps = len(dataloader_tumor) batch_size = dataloader_tumor.batch_size dataiter_tumor = iter(dataloader_tumor) dataiter_normal = iter(dataloader_normal) for step in range(steps): data_tumor = next(dataiter_tumor) target_tumor = [1, 1,..,1] # 和data_tumor长度相同的tensor data_tumor = Variable(data_tumor.cuda(async=True)) target_tumor = Variable(target_tumor.cuda(async=True)) data_normal = next(dataiter_normal) target_normal = [0, 0,..,0] # data_normal = Variable(data_normal.cuda(async=True)) target_normal = Variable(target_normal.cuda(async=True)) idx_rand = Variable(torch.randperm(batch_size*2).cuda(async=True)) data = torch.cat([data_tumor, data_normal])[idx_rand] target = torch.cat([target_tumor, target_normal])[idx_rand] output = model(data) loss = loss_fn(output, target) optimizer.zero_grad() loss.backward() optimizer.step() probs = output.sigmoid()