数据预处理
概述
torchvision.transform是一个包含了常用图像变化方法的工具包. 该工具包主要用于图像的预处理,数据增强等工作之中. 本节我们将详细介绍torchvision.transforms中常用的数据处理函数
知识点:
- 预处理的批操作
- 葡萄酒数据的预处理
- 图像数据的预处理
数据的预处理
Compose
首先让我们先来学习torchvision.transforms.Compose(), 它的参数是一个由多个transforms包中的方法组成的列表. 简单的说, 该函数的主要目的就是将所有的预处理操作进行打包, 当有数据来时, 我们只需要将数据传入该函数中,就能一次性对数据进行所有预处理操作
import torch
import torchvision
class ToTensor:
def __call__(self,x):
return torch.from_numpy(x)
class MulTransform:
def __call__(self,x):
x*=2
return x
composed = torchvision.transforms.Compose([ToTensor(),MulTransform()])
print(composed)
上面我们定义了一个预处理的集合器, 我们只需要将数据传入composed中,PyTorch就会自动对数据进行ToTensor()和MulTransform()操作.
import numpy as np
data = np.array([1,2,3])
composed(data)
从结果可以看出, 尽管我们的数据需要进行很多次的预处理, 但是我们只需要将这些预处理全部放入Compose中进行打包,就能形成一个数据预处理结合.
当我们需要处理某些数据时, 只需要简单的将数据传入这个集合即可.
接下来, 我们以葡萄酒的数据预处理为例,修改上一个实验的WineDataset类, 使其能够输出归一化后的Tensor数据集.
葡萄酒数据的预处理
首先, 还是让我们先来定义数据集合:
# 我们自己封装一个Dataset类
from torch.utils.data import Dataset
import pandas as pd
class WineDataset(Dataset):
# 建立一个数据集合继承Dataset
def __init__(self,transform):
# 加载wine.csv中的数据
xy = pd.read_csv("./wine.csv")
# 采样数据
self.samples_num = xy.shape[0]
# 将pandas类型数据转成tensor类型
self.datas = xy.values[:,1:]
self.labels = xy.values[:,0].reshape(-1,1)
# 数据的预处理
self.transform = transform
def __getitem__(self,index):
sample = self.datas[index],self.labels[index]
if self.transform:
return self.transform(sample)
return sample
def __len__(self):
return self.samples_num
可以看出WineDataset类中的代码和上一个案例大致相同, 我们只是多加了一个transform变量,即数据预处理操作的集合. 该变量并没有在WineDataset类中被定义,只是作为一个参数被传入.
这样做有一个好处就是, 当我们需要在原来基础上添加新的预处理操作时, 我们只需要在模型外重新定义transform变量即可. 无需修改原来类中的代码.
接下来, 就让我们来定义预处理操作了.
首先,让我们来定义数据归一化操作,我们这里使用最大最小归一化
# 为了便于计算,我们将数据进行归一化操作
class Normalization:
def __call__(self,sample):
inputs,targets = sample
amin,amax = inputs.min(),inputs.max()
inputs = (inputs - amin)/(amax - amin)
return inputs,targets
# 测试代码
a = 10 * np.random.random((5,5))
print(a)
# 前4列表示数据,最后1列表示标签
asample = [a[:,0:4],a[:,4]]
Normalization()(asample)
接下来, 让我们来定义数据的转化操作,即将原数据类型转为Tensor:
class ToTensor:
def __call__(self, sample):
inputs, targets = sample
return torch.from_numpy(inputs),torch.from_numpy(targets)
# 测试代码
a = 10 * np.random.random((5,5))
# 测试数据,前4列表示特征, 最后一列表示标签
data = [a[:,0:4],a[:,4]]
ToTensor()(data)
最后, 让我们使用这两个预处理的操作, 来处理葡萄酒数据.
我们无需修改上面的代码, 只需将其封装到Compose中, 再传入即可.
# 最后无需修改上面的代码,我们将其封装到compose中
composed = torchvision.transforms.Compose([Normalization(),ToTensor()])
# 传入该参数
wineData = WineDataset(transform=composed)
# 第一条数据
features,labels = wineData[0]
# 打印输出类型
print(type(features),type(labels))
图像的预处理
transform中有很多关于图像的预处理
import torchvision.transforms as transforms
from PIL import Image
import matplotlib.pyplot as plt
%matplotlib inline
import cv2 as cv
img = Image.open("bozai.jpg")
plt.imshow(img)
裁剪图片
transform = torchvision.transforms.CenterCrop((64,200))
new_img = transform(img)
plt.imshow(new_img)
# 改变图片的亮度,对比度和饱和度
plt.subplot(221)
plt.imshow(img)
# 随机改变亮度
img1 = torchvision.transforms.ColorJitter((0.5,0.6))(img)
plt.subplot(222)
plt.imshow(img1)
# 随机改变对比度
img2 = torchvision.transforms.ColorJitter(0,(0.5,0.6))(img)
plt.subplot(223)
plt.imshow(img2)
# 随机改变饱和度
img3 = torchvision.transforms.ColorJitter(0,0,(0.5,0.6))(img)
plt.subplot(224)
plt.imshow(img3)
# 图像的灰度处理
plt.subplot(131)
plt.imshow(img)
img1 = torchvision.transforms.Grayscale(1)(img)
plt.subplot(132)
plt.imshow(img1,"gray")
img2 = torchvision.transforms.Grayscale(3)(img)
plt.subplot(133)
plt.imshow(img2)
# 给PIL图像进行填充
plt.subplot(121)
plt.imshow(img)
# 四周加边界
img1 = torchvision.transforms.Pad(padding=20,fill=(0,255,255),padding_mode="constant")(img)
plt.subplot(122).set_title("pad")
plt.imshow(img1)
# 保持图像中心不变的仿射变换,,在空余位置补0
img1 = torchvision.transforms.RandomAffine(60)(img)
plt.subplot(221).set_title("rotate_only")
plt.imshow(img1)
img2 = torchvision.transforms.RandomAffine(60,translate=(0.3,0.3))(img)
plt.subplot(222).set_title("rotate_translate")
plt.imshow(img2)
img3 = torchvision.transforms.RandomAffine(60,scale=(2.0,2.3))(img)
plt.subplot(223).set_title("rotate_scale")
plt.imshow(img3)
img4 = torchvision.transforms.RandomAffine(60,shear=60)(img)
plt.subplot(224).set_title("shear_only")
plt.imshow(img4)
plt.tight_layout()
# 将原图像进行随机裁剪,裁剪后重新缩放size大小
img1 = torchvision.transforms.RandomResizedCrop((128,128),scale=(0.08,1.0),ratio=(0.75,1.33),interpolation=2)(img)
plt.imshow(img1)
小结
本节我们阐述了torchvision.transforms的使用方法和torchvision.transforms中内置的处理函数,这些预处理操作是非常重要的, 一系列好的数据预处理操作,可以大大的加快模型收敛速度,提高模型的准确率和鲁棒性/