Pytorch:torchvision.transforms

torchvision.transforms是专门用来对数据进行各种的处理。包括如下操作:

  • 归一化
  • PIL.Image / numpy.ndarray 与Tensor的相互转化
  • 对PIL.Image进行裁剪、缩放等操作

通常,在使用torchvision.transforms,我们通常使用transforms.Compose将transforms组合在一起。

1 torchvision.transforms.ToTensor()

对于一个图片img,调用ToTensor转化成张量的形式,发生的不是将图片的RGB三维信道矩阵变成tensor。图片在内存中以bytes的形式存储,转化过程的步骤是:

  • img.tobytes()  将图片转化成内存中的存储格式
  • torch.BytesStorage.frombuffer(img.tobytes() )  将字节以流的形式输入,转化成一维的张量
  • 对张量进行reshape
  • 对张量进行permute(2,0,1)
  • 将当前张量的每个元素除以255
  • 输出张量
  • 把shape=(H,W,C)的像素值范围为[0, 255]的PIL.Image或者numpy.ndarray转换成shape=(C,H,W)的像素值范围为[0, 1.0]的torch.FloatTensor。
  • 通道的顺序与你读取图片所用的工具有关:cv2:(B,G,R)、PIL.Image:(R,G,B)

栗子:

import torch
from PIL import Image
import cv2
 
from torchvision import transforms
import numpy
 
 
img_PIL = Image.open("000001.jpg")  # PIL的JpegImageFile格式(size=(W,H))
img_cv2 = cv2.imread("000001.jpg")  # numpy数组格式(H,W,C=3),通道顺序(B,G,R)
print(img_PIL.size)  # (W,H)
print(img_cv2.shape)  # (H,W,C)
 
img_PIL_np = numpy.array(img_PIL)  # 转为numpy后,变为HWC
print(img_PIL_np.shape)  # (H,W,C)
 
# 将numpy数组或PIL.Image读的图片转换成(C,H, W)的Tensor格式且/255归一化到[0,1.0]之间
tran = transforms.ToTensor()  # 注意用这种写法
img_PIL_tensor = tran(img_PIL)
img_cv2_tensor = tran(img_cv2)
 
print(img_PIL_tensor.size())  #(C,H,W) 通道顺序(R,G,B)
print(img_cv2_tensor.size())  #(C,H,W) 通道顺序(B,G,R)
 
 
输出结果:
(409, 687)
(687, 409, 3)
 
(687, 409, 3)
 
torch.Size([3, 687, 409])
torch.Size([3, 687, 409])

注:当使用PIL.Image.open()打开图片后,如果要使用img.shape函数,需要先将image形式转换成array数组

2 torchvision.transforms.Normalize(mean, std)

对Tensor类型数据进行变换,处理的数据要求是Tensor类型的。给定(R,G,B)均值mean和方差std,将会把Tensor正则化。即:

Normalized_image=(image-mean)/std

在很多代码中,经常会看到:

from torchvision import transforms

normalize = transforms.Normalize(mean = [0.485, 0.456, 0.406], 
                               std = [0.229, 0.224, 0.225])

图片的RGB的范围不是[0,255]吗,那么图片的3个通道的像素值均值不应该是127吗?那么用这样的归一化参数怎么能归一化到[-1,1]呢?

这是由于:

  • 在加载数据集的时候就已经将图片的值范围转换为[0,1],如ImageNet数据集,就是在加载ImageNet的数据的时候就转换成[0,1.0]。
  • 操作之前就用了torchvision.transforms.ToTensor,其一个作用是将数据的范围转换到[0,1.0]。通常这两个类一起使用。使用torchvision.transforms.Compose(transforms)的时候要注意将这个类放在torchvision.transforms.ToTensor()后面。
  • [0.485, 0.456, 0.406]这一组平均值是从Imagenet训练集中抽样算出来的。

3 torchvision.transforms.Compose(transforms)

其作用是:将多个transform组合起来使用。

栗子:

from torchvision import transforms 

transform = transforms.Compose([
    transforms.RandomCrop(32, padding=4),  # 先四周填充0,在吧图像随机裁剪成32*32
    transforms.RandomHorizontalFlip(),  # 图像一半的概率翻转,一半的概率不翻转
    transforms.RandomRotation((-45,45)),  # 随机旋转
    transforms.ToTensor(),
    transforms.Normalize((0.4914, 0.4822, 0.4465), (0.229, 0.224, 0.225)),  #R,G,B每层的归一化用到的均值和方差
])

执行的时候会按照顺序执行,先执行transforms.RandomCrop(32, padding=4),最后执行transforms.Normalize((0.4914, 0.4822, 0.4465), (0.229, 0.224, 0.225))所以这里一定要注意类型的问题,这些方法有的使用的是Tensor类型,有些是PIL.Image的类型。

归一化对神经网络的训练是非常重要的,基本都会将数据归一化到[-1.0,1.0],是神经网络中的必须步骤:

from torchvision import transforms

transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(mean = [0.485, 0.456, 0.406], std = [0.229, 0.224, 0.225])
    ]
)

注:

  • 这两行使用时顺序不可以颠倒,因为归一化需要的是Tensor型的数据,所以要先将数据转化为Tensor型才可以进行归一化。
  • 一般情况下我们将对图片的变换操作放到torchvision.transforms.Compose()进行组组合变换。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值