数据预处理

概述

torchvision.transform是一个包含了常用图像变化方法的工具包. 该工具包主要用于图像的预处理,数据增强等工作之中. 本节我们将详细介绍torchvision.transforms中常用的数据处理函数

知识点:

  1. 预处理的批操作
  2. 葡萄酒数据的预处理
  3. 图像数据的预处理

数据的预处理

Compose

首先让我们先来学习torchvision.transforms.Compose(), 它的参数是一个由多个transforms包中的方法组成的列表. 简单的说, 该函数的主要目的就是将所有的预处理操作进行打包, 当有数据来时, 我们只需要将数据传入该函数中,就能一次性对数据进行所有预处理操作

  1. import torch
  2. import torchvision
  3. class ToTensor:
  4. def __call__(self,x):
  5. return torch.from_numpy(x)
  6. class MulTransform:
  7. def __call__(self,x):
  8. x*=2
  9. return x
  10. composed = torchvision.transforms.Compose([ToTensor(),MulTransform()])
  11. print(composed)

上面我们定义了一个预处理的集合器, 我们只需要将数据传入composed中,PyTorch就会自动对数据进行ToTensor()和MulTransform()操作.

  1. import numpy as np
  2. data = np.array([1,2,3])
  3. composed(data)

从结果可以看出, 尽管我们的数据需要进行很多次的预处理, 但是我们只需要将这些预处理全部放入Compose中进行打包,就能形成一个数据预处理结合.

当我们需要处理某些数据时, 只需要简单的将数据传入这个集合即可.

接下来, 我们以葡萄酒的数据预处理为例,修改上一个实验的WineDataset类, 使其能够输出归一化后的Tensor数据集.

葡萄酒数据的预处理

首先, 还是让我们先来定义数据集合:

  1. # 我们自己封装一个Dataset类
  2. from torch.utils.data import Dataset
  3. import pandas as pd
  4. class WineDataset(Dataset):
  5. # 建立一个数据集合继承Dataset
  6. def __init__(self,transform):
  7. # 加载wine.csv中的数据
  8. xy = pd.read_csv("./wine.csv")
  9. # 采样数据
  10. self.samples_num = xy.shape[0]
  11. # 将pandas类型数据转成tensor类型
  12. self.datas = xy.values[:,1:]
  13. self.labels = xy.values[:,0].reshape(-1,1)
  14. # 数据的预处理
  15. self.transform = transform
  16. def __getitem__(self,index):
  17. sample = self.datas[index],self.labels[index]
  18. if self.transform:
  19. return self.transform(sample)
  20. return sample
  21. def __len__(self):
  22. return self.samples_num

可以看出WineDataset类中的代码和上一个案例大致相同, 我们只是多加了一个transform变量,即数据预处理操作的集合. 该变量并没有在WineDataset类中被定义,只是作为一个参数被传入.

这样做有一个好处就是, 当我们需要在原来基础上添加新的预处理操作时, 我们只需要在模型外重新定义transform变量即可. 无需修改原来类中的代码.

接下来, 就让我们来定义预处理操作了.

首先,让我们来定义数据归一化操作,我们这里使用最大最小归一化

  1. # 为了便于计算,我们将数据进行归一化操作
  2. class Normalization:
  3. def __call__(self,sample):
  4. inputs,targets = sample
  5. amin,amax = inputs.min(),inputs.max()
  6. inputs = (inputs - amin)/(amax - amin)
  7. return inputs,targets
  8. # 测试代码
  9. a = 10 * np.random.random((5,5))
  10. print(a)
  11. # 前4列表示数据,最后1列表示标签
  12. asample = [a[:,0:4],a[:,4]]
  13. Normalization()(asample)

接下来, 让我们来定义数据的转化操作,即将原数据类型转为Tensor:

  1. class ToTensor:
  2. def __call__(self, sample):
  3. inputs, targets = sample
  4. return torch.from_numpy(inputs),torch.from_numpy(targets)
  5. # 测试代码
  6. a = 10 * np.random.random((5,5))
  7. # 测试数据,前4列表示特征, 最后一列表示标签
  8. data = [a[:,0:4],a[:,4]]
  9. ToTensor()(data)

最后, 让我们使用这两个预处理的操作, 来处理葡萄酒数据.

我们无需修改上面的代码, 只需将其封装到Compose中, 再传入即可.

  1. # 最后无需修改上面的代码,我们将其封装到compose中
  2. composed = torchvision.transforms.Compose([Normalization(),ToTensor()])
  3. # 传入该参数
  4. wineData = WineDataset(transform=composed)
  5. # 第一条数据
  6. features,labels = wineData[0]
  7. # 打印输出类型
  8. print(type(features),type(labels))

图像的预处理

transform中有很多关于图像的预处理

  1. import torchvision.transforms as transforms
  2. from PIL import Image
  3. import matplotlib.pyplot as plt
  4. %matplotlib inline
  5. import cv2 as cv
  6. img = Image.open("bozai.jpg")
  7. plt.imshow(img)

11_数据预处理-transform - 图1
11_数据预处理-transform - 图2

裁剪图片

  1. transform = torchvision.transforms.CenterCrop((64,200))
  2. new_img = transform(img)
  3. plt.imshow(new_img)

11_数据预处理-transform - 图3
11_数据预处理-transform - 图4

  1. # 改变图片的亮度,对比度和饱和度
  2. plt.subplot(221)
  3. plt.imshow(img)
  4. # 随机改变亮度
  5. img1 = torchvision.transforms.ColorJitter((0.5,0.6))(img)
  6. plt.subplot(222)
  7. plt.imshow(img1)
  8. # 随机改变对比度
  9. img2 = torchvision.transforms.ColorJitter(0,(0.5,0.6))(img)
  10. plt.subplot(223)
  11. plt.imshow(img2)
  12. # 随机改变饱和度
  13. img3 = torchvision.transforms.ColorJitter(0,0,(0.5,0.6))(img)
  14. plt.subplot(224)
  15. plt.imshow(img3)

11_数据预处理-transform - 图5
11_数据预处理-transform - 图6

  1. # 图像的灰度处理
  2. plt.subplot(131)
  3. plt.imshow(img)
  4. img1 = torchvision.transforms.Grayscale(1)(img)
  5. plt.subplot(132)
  6. plt.imshow(img1,"gray")
  7. img2 = torchvision.transforms.Grayscale(3)(img)
  8. plt.subplot(133)
  9. plt.imshow(img2)

11_数据预处理-transform - 图7
11_数据预处理-transform - 图8

  1. # 给PIL图像进行填充
  2. plt.subplot(121)
  3. plt.imshow(img)
  4. # 四周加边界
  5. img1 = torchvision.transforms.Pad(padding=20,fill=(0,255,255),padding_mode="constant")(img)
  6. plt.subplot(122).set_title("pad")
  7. plt.imshow(img1)

11_数据预处理-transform - 图9
11_数据预处理-transform - 图10

  1. # 保持图像中心不变的仿射变换,,在空余位置补0
  2. img1 = torchvision.transforms.RandomAffine(60)(img)
  3. plt.subplot(221).set_title("rotate_only")
  4. plt.imshow(img1)
  5. img2 = torchvision.transforms.RandomAffine(60,translate=(0.3,0.3))(img)
  6. plt.subplot(222).set_title("rotate_translate")
  7. plt.imshow(img2)
  8. img3 = torchvision.transforms.RandomAffine(60,scale=(2.0,2.3))(img)
  9. plt.subplot(223).set_title("rotate_scale")
  10. plt.imshow(img3)
  11. img4 = torchvision.transforms.RandomAffine(60,shear=60)(img)
  12. plt.subplot(224).set_title("shear_only")
  13. plt.imshow(img4)
  14. plt.tight_layout()

11_数据预处理-transform - 图11
11_数据预处理-transform - 图12

  1. # 将原图像进行随机裁剪,裁剪后重新缩放size大小
  2. img1 = torchvision.transforms.RandomResizedCrop((128,128),scale=(0.08,1.0),ratio=(0.75,1.33),interpolation=2)(img)
  3. plt.imshow(img1)

11_数据预处理-transform - 图13
11_数据预处理-transform - 图14

小结

本节我们阐述了torchvision.transforms的使用方法和torchvision.transforms中内置的处理函数,这些预处理操作是非常重要的, 一系列好的数据预处理操作,可以大大的加快模型收敛速度,提高模型的准确率和鲁棒性/