pytorch数据处理

pytorch数据处理

在解决深度学习问题的过程中,往往需要花费大量的精力去处理数据,包括图像、文本、语音或其它二进制数据等。数据的处理对训练神经网络来说十分重要,良好的数据处理不仅会加速模型训练,更会提高模型效果。PyTorch提供了几个高效便捷的工具,以便使用者进行数据处理或增强等操作,同时可通过并行化加速数据加载。

数据加载

在PyTorch中,数据加载可通过自定义的数据集对象。数据集对象被抽象为Dataset类,实现自定义的数据集需要继承Dataset,并实现两个Python魔法方法:

getitem:返回一条数据,或一个样本。obj[index]等价于obj.getitem(index)
len:返回样本的数量。len(obj)等价于obj.len()

Kaggle经典挑战赛"Dogs vs. Cat"的数据为例,来详细讲解如何处理数据。"Dogs vs. Cats"是一个分类问题,判断一张图片是狗还是猫,其所有图片都存放在一个文件夹下,根据文件名的前缀判断是狗还是猫。

data/dogcat/
|-- cat.12484.jpg
|-- cat.12485.jpg
|-- cat.12486.jpg
|-- cat.12487.jpg
|-- dog.12496.jpg
|-- dog.12497.jpg
|-- dog.12498.jpg
`-- dog.12499.jpg

import torch as t
from torch.utils import data
import os
from PIL import  Image
import numpy as np

class DogCat(data.Dataset):
    def __init__(self, root):
        imgs = os.listdir(root)
        # 所有图片的绝对路径
        # 这里不实际加载图片,只是指定路径,当调用__getitem__时才会真正读图片
        self.imgs = [os.path.join(root, img) for img in imgs]
        
    def __getitem__(self, index):
        img_path = self.imgs[index]
        # dog->1, cat->0
        label = 1 if 'dog' in img_path.split('/')[-1] else 0
        pil_img = Image.open(img_path)
        array = np.asarray(pil_img)
        data = t.from_numpy(array)
        return data, label
    
    def __len__(self):
        return len(self.imgs)

调用该程序

dataset = DogCat('./data/dogcat/')
img, label = dataset[0] # 相当于调用dataset.__getitem__(0)
for img, label in dataset:
    print(img.size(), img.float().mean(), label)

(https://img-blog.csdnimg.cn/20181219152658954.png)
该程序如何自定义自己的数据集,并可以依次获取。但这里返回的数据不适合实际使用,因其具有如下两方面问题:

**

  • 返回样本的形状不一,因每张图片的大小不一样,这对于需要取batch训练的神经网络来说很不友好
  • 返回样本的数值较大,未归一化至[-1, 1]

**
针对上述问题,PyTorch提供了torchvision^1。它是一个视觉工具包,提供了很多视觉图像处理的工具,其中transforms模块提供了对PIL Image对象和Tensor对象的常用操作。

对PIL Image的操作包括:

  • Scale:调整图片尺寸,长宽比保持不变

  • CenterCrop、RandomCrop、RandomSizedCrop: 裁剪图片

  • Pad:填充 ToTensor:将PIL Image对象转成Tensor,会自动将[0, 255]归一化至[0, 1]

对Tensor的操作包括:

**Normalize:**标准化,即减均值,除以标准差
**ToPILImage:**将Tensor转为PIL Image对象
如果要对图片进行多个操作,可通过Compose函数将这些操作拼接起来,类似于nn.Sequential。注意,这些操作定义后是以函数的形式存在,真正使用时需调用它的__call__方法,这点类似于nn.Module。例如要将图片调整为 224×224 ,首先应构建这个操作trans = Resize((224, 224)),然后调用trans(img)。下面我们就用transforms的这些操作来优化上面实现的dataset。

import os
from PIL import  Image
import numpy as np
from torchvision import transforms as T

transform = T.Compose([
    T.Resize(224), # 缩放图片(Image),保持长宽比不变,最短边为224像素
    T.CenterCrop(224), # 从图片中间切出224*224的图片
    T.ToTensor(), # 将图片(Image)转成Tensor,归一化至[0, 1]
    T.Normalize(mean=[.5, .5, .5], std=[.5, .5, .5]) # 标准化至[-1, 1],规定均值和标准差
])

class DogCat(data.Dataset):
    def __init__(self, root, transforms=None):
        imgs = os.listdir(root)
        self.imgs = [os.path.join(root, img) for img in imgs]
        self.transforms=transforms
        
    def __getitem__(self, index):
        img_path = self.imgs[index]
        label = 0 if 'dog' in img_path.split('/')[-1] else 1
        data = Image.open(img_path)
        if self.transforms:
            data = self.transforms(data)
        return data, label
    
    def __len__(self):
        return len(self.imgs)

dataset = DogCat('./data/dogcat/', transforms=transform)
img, label = dataset[0]
for img, label in dataset:
    print(img.size(), label)

在这里插入图片描述

  1. torchvision.transforms.Compose(transforms)

功能:将多个transform组合起来使用
transforms: 由transform构成的列表
使用例子:

transforms.Compose([
     transforms.CenterCrop(224),
     transforms.ToTensor(),
 ])

2

CenterCrop(size)

功能:将给定的PIL.Image进行中心切割,得到给定的size。
size可以是tuple,(target_height, target_width)。
size也可以是一个Integer,在这种情况下,切出来的图片的形状是正方形。

3、RandomCrop(size, padding=0)
功能:切割中心点的位置随机选取。size可以是tuple也可以是Integer。

4、RandomHorizontalFlip
功能:随机水平翻转给定的PIL.Image,概率为0.5。即:一半的概率翻转,一半的概率不翻转。

5、RandomSizedCrop(size, interpolation=2)
功能:先将给定的PIL.Image随机切,然后再resize成给定的size大小。

6、Pad(padding, fill=0)
功能:将给定的PIL.Image的所有边用给定的pad value填充。

对Tensor进行变换

7、Normalize(mean, std)
功能:给定均值:(R,G,B) 方差:(R,G,B),将会把Tensor正则化。即:Normalized_image=(image-mean)/std。

8、ToTensor
功能:把一个取值范围是[0,255]的PIL.Image或者shape为(H,W,C)的numpy.ndarray,转换成形状为[C,H,W],取值范围是[0,1.0]的torch.FloadTensor

9、ToPILImage
功能:将shape为(C,H,W)的Tensor或shape为(H,W,C)的numpy.ndarray转换成PIL.Image,值不变。

10、Lambda(lambd)
功能:使用lambd作为转换器。

11、Scale(size, interpolation=2)
功能:将输入的Image重新改变大小成给定的size,size是最小边的边长。举个例子,如果原图的height>width,那么改变大小后的图片大小是(size*height/width, size)。

  1. pytorch中tensor和numpy的通道位置不同,numpy的通道在H,W之后,即(H,W,C),用np.shape(object)可以查看;而tensor的通道在H和W之前,即(C,H,W),用np.shape(object)或者object.shape可以查看;

所以,读取图像后得到numpy数组,要变成tensor进行数据处理,需要transpose操作,改变通道的位置;

  1. 处理针对的是tensor格式,需要通过from_numpy等方法,将输入图像时的numpy格式转换为tensor格式

  2. 进行Normalize等处理,需要数据类型为float

1.torchvision.transforms.ToTensor()
将PILImage或者numpy的ndarray转化成Tensor

对于PILImage转化的Tensor,其数据类型是torch.FloatTensor
对于ndarray的数据类型没有限制,但转化成的Tensor的数据类型是由ndarray的数据类型决定的。

把一个取值范围是[0,255]的PIL.Image 转换成 Tensor

from PIL import Image
img1 = Image.open('./1.jpg')
 
t_out = transforms.ToTensor()(img1)

shape为(H,W,C)的numpy.ndarray,转换成形状为[C,H,W],取值范围是[0,1.0]的Tensor

n_out = np.random.rand(100,100,3)
print(n_out.dtype)
 
t_out = transforms.ToTensor()(n_out)
print(t_out.type())

输出

float64
torch.DoubleTensor

2.torchvision.transforms.ToPILImage()

将Numpy的ndarray或者Tensor转化成PILImage类型【在数据类型上,两者都有明确的要求】

ndarray的数据类型要求dtype=uint8, range[0, 255] and shape H x W x C
Tensor 的shape为 C x H x W 要求是FloadTensor的,不允许DoubleTensor或者其他类型
# to a PIL.Image of range [0, 255]

将ndarray转化成PILImage
#初始化随机数种子

np.random.seed(0)
 
data = np.random.randint(0, 255, 300)
print(data.dtype)
n_out = data.reshape(10,10,3)



#强制类型转换
n_out = n_out.astype(np.uint8)
print(n_out.dtype)



img2 = transforms.ToPILImage()(n_out)
img2.show()

将Tensor转化成PILImage

t_out = torch.randn(3,10,10)
img1 = transforms.ToPILImage()(t_out)
img1.show()

因为要求是FloatTensor类型,所以最好是不管此时的tensor是不是FloatTensor类型,都加一个强制转换再传进去。

t_out = torch.randn(3,10,10)
img1 = transforms.ToPILImage()(t_out.float())
img1.show()

参考陈云深度学习框架pytorch入门与实践源代码

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值