深度学习中数据加载(pytorch==1.3.0为例)

背景知识

    本篇blog和我的上一篇blog介绍tensorflow加载数据形成对比这两篇blog所用到的数据完全一致,只不过一个是使用tensorflow进行加载数据,一个使用pytorch进行加载数据。
    在 深度学习中, 数据的预处理占据了我们在训练过程中的一大部分,如何利用不同的库加载我们的数据显得尤为重要。因此本次blog将结合pytorch==1.3.0中数据加载部分官方文档讲述如何加载我们自己标注的数据和标签。
   这里为什么要以pytorch加载数据,是因为最近发现一个比较有趣的事情,在更新pytorch==1.3.0以后,发现在pytorch官方演示中可以直接得到向量对向量的导数,在之前版本只能是离散点(标量)对向量求导,可能是官方优化了变量的fn属性吧,官方介绍了是求解雅可比矩阵的形式。

# 这个代码在pytorch < 1.3.0时,会报错
import torch
x = torch.ones(3,requires_grad=True)
a = torch.tensor([1.,2,3],requires_grad=True)
y = torch.mul(x,a)
y.backward(x)
print(x.grad)

测试环境

  • 操作系统:Windows10
  • 深度学习框架:pytorch ==1.3.0 or plus
  • IDE: Pycharm

自定义数据格式介绍

    在 深度学习中, 本人感兴趣的是图像这一块的领域,因此数据将以图像分类为例,进行演示和说明。

数据下载的链接为  演示数据下载
   
简单看一下数据的存储的方式,数据存储的方式的目录结构为:
这里和上一篇blog的数据形式完全一致
在这里插入图片描述
可以看到每张图片的父节点目录就是他们分类的结果,而每个文件夹里面的内容就是分类的图片。在我们准备好数据之后就可以开始我们的数据加载部分的操作了。

自定义数据加载

在pytorch == 1.3.0中需要使用到的数据加载类/函数有:

# 需要继承自pytorch设置的类的Dataset 
from torch.utils.data import Dataset
# 设置打乱顺序和batch的DataLoader
from torch.utils.data import DataLoader
# 对图像处理中的预处理类对象设置(这里我们不是用这个,我们自定义的函数预处理函数)
from torchvision import transforms

这里注意一点,在继承Dataset时,一定需要实现两个虚函数

class CustomerDataset(Dataset):
    """Face Landmarks dataset."""

    def __init__(self):
    	pass
    def __len__(self):
        #return
    	pass
    def __getitem__(self, idx):
        # return
        pass

有了上面的函数介绍,现在开始介绍操作步骤:

  • 得到图像的路径和标签,
  • 实现数据读取sample操作
  • 打乱得到的数据并设置batch_size
from __future__ import print_function,absolute_import,unicode_literals,division
import torch
from torch.utils.data import Dataset,DataLoader
from torchvision import transforms,utils
from skimage import io,transform
import pathlib
import  numpy as np
# 自定数据集的设置
class CustomerDataset(Dataset):
    # 初始化路径,并得到相对应的图片路径 self.all_image_paths 和标签self.all_image_labels
    def __init__(self, root_dir,transform=None):
        self.root_dir = root_dir
        self.transform = transform
        data_root = pathlib.Path(self.root_dir)
        self.all_image_paths = list(data_root.glob("*/*"))
        self.all_image_paths = [str(path) for path in self.all_image_paths]
        label_names = sorted(item.name for item in data_root.glob("*/") if item.is_dir())
        label_to_index = dict((name, index) for index, name in enumerate(label_names))
        self.all_image_labels = [label_to_index[pathlib.Path(path).parent.name] for path in self.all_image_paths]

    def __len__(self):
        return len(self.all_image_paths)
    #读取图片并返回一个字典的sample
    def __getitem__(self, idx):
        if torch.is_tensor(idx):
            idx = idx.tolist()
        image = io.imread(self.all_image_paths[idx])
        label = self.all_image_labels[idx]
        label = np.array([label])
        sample = {'image':image,'label':label}

        if self.transform:
            sample = self.transform(sample)
        return sample

data_root = "C:\\Users\wu\\.keras\\datasets\\flower_photos"
dataset = CustomerDataset(root_dir=data_root)
'''
for i in range(len(dataset)):
    sample = dataset[i]
    print(i,sample['image'].shape,sample['label'].shape)
'''

# 图片放缩
class Rescale(object):
    def __init__(self, output_size):
        assert isinstance(output_size, (int, tuple))
        self.output_size = output_size

    def __call__(self, sample):
        image, label = sample['image'], sample['label']

        h, w = image.shape[:2]
        if isinstance(self.output_size, int):
            if h > w:
                new_h, new_w = self.output_size * h / w, self.output_size
            else:
                new_h, new_w = self.output_size, self.output_size * w / h
        else:
            new_h, new_w = self.output_size

        new_h, new_w = int(new_h), int(new_w)

        img = transform.resize(image, (new_h, new_w))

        # h and w are swapped for landmarks because for images,
        # x and y axes are axis 1 and 0 respectively
        #landmarks = landmarks * [new_w / w, new_h / h]
        return {'image': img, 'label': label}

# 图片随机裁剪
class RandomCrop(object):
    """Crop randomly the image in a sample.

    Args:
        output_size (tuple or int): Desired output size. If int, square crop
            is made.
    """

    def __init__(self, output_size):
        assert isinstance(output_size, (int, tuple))
        if isinstance(output_size, int):
            self.output_size = (output_size, output_size)
        else:
            assert len(output_size) == 2
            self.output_size = output_size

    def __call__(self, sample):
        image, label = sample['image'], sample['label']

        h, w = image.shape[:2]
        new_h, new_w = self.output_size

        top = np.random.randint(0, h - new_h)
        left = np.random.randint(0, w - new_w)

        image = image[top: top + new_h,
                      left: left + new_w]

        #landmarks = landmarks - [left, top]

        return {'image': image, 'label': label}

# 将图片转化成pytorch中的tensor
class ToTensor(object):
    """Convert ndarrays in sample to Tensors."""

    def __call__(self, sample):
        image, label = sample['image'], sample['label']

        # swap color axis because
        # numpy image: H x W x C
        # torch image: C X H X W
        #image = image.transpose((2, 0, 1))
        return {'image': torch.from_numpy(image),
                'label': torch.from_numpy(label)}

dataset = CustomerDataset(root_dir=data_root,transform=
                          transforms.Compose([Rescale(256),RandomCrop(224),ToTensor()]))


'''
for i in range(len(dataset)):
    sample = dataset[i]
    print(i,sample['image'].shape,sample['label'].shape)
'''

# 这里注意下windows下num_workers=0才能运行,在linux中无任何影响,大家课自行测试
dataloader = DataLoader(dataset, batch_size=4,
                        shuffle=True, num_workers=0)
for i_batch, sample_batched in enumerate(dataloader):
    print(i_batch,sample_batched['image'].shape,sample_batched['label'].shape)



注意两点

  • 使用自定义的类 RandomCrop(object)Rescale(object)ToTensor(object),这些过程需要自己编写,但是pytorch中提供了一些易用的这种函数在 torchvision
import torch
from torchvision import transforms, datasets



data_transform = transforms.Compose([
        transforms.RandomSizedCrop(224),
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor(),
        transforms.Normalize(mean=[0.485, 0.456, 0.406],
                             std=[0.229, 0.224, 0.225])
    ])
dataset = CustomerDataset(root_dir=data_root,transform=
                          data_transform))
  • 由于pytorch中函数封装比较完善,不需要用户编写过多的函数,因此可以借助pytorch封装好的函数进行数据导入操作。比如你可能使用到的深度学习框架不是pytorch,你也可以使用pytorch的数据导入操作,只需要把ToTensor改成ToArray类,然后强制转换成普遍使用到的Numpy数据格式。再把Numpy类型的数据转到你所需要输入的深度学习框架的类型

1.https://pytorch.org/tutorials/beginner/data_loading_tutorial.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值