torchvison:计算机视觉工具包
包含
- torchvison.transforms(常用的图像预处理方法);
- torchvision.datasets(常用数据集的dataset实现,MNIST,CIFAR-10,ImageNet等);
- torchvison.model(常用的模型预训练,AlexNet,VGG,ResNet,GoogleNet等)。
torchvision.transforms
常用的数据预处理方法,提升泛化能力。包括:数据中心化、数据标准化、缩放、裁剪、旋转、填充、噪声添加、灰度变换、线性变换、放射变换、亮度、饱和度和对比度变换等
数据标准化——transforms.Normalize
功能:逐channel的对图像进行标准化(均值变为0,标准差变为1),可以加快模型的收敛
- output=(input-mean)/std
- mean:各通道的均值
- std:各通道的标准差
- inplace:是否原地操作
问题:究竟是什么意思?(0.5,0.5,0.5),(0.5,0.5,0.5)又是怎么来的呢?
transform.ToTensor(),
transform.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))
1、transform.ToTensor()
原始的PILImage格式或者numpy.array格式的数据格式化为可被pytorch快速处理的张量类型
-
是将输入的数据shape W,H,C---> C,W,H。 从opencv读到的图片是通道数在第三个维度,现在经过ToTensor操作cv2图片变成了torch image类型,也就是通道在第一个维度。
-
将所有数除以255,将数据归一化到[0,1]
-
示例:
import torch
import numpy as np
from torchvision import transforms
import cv2
# 自定义图片数组,数据类型一定要转为‘uint8’,不然transforms.ToTensor()不会归一化
data = np.array([
[[1,1,1],[1,1,1],[1,1,1],[1,1,1],[1,1,1]],
[[2,2,2],[2,2,2],[2,2,2],[2,2,2],[2,2,2]],
[[3,3,3],[3,3,3],[3,3,3],[3,3,3],[3,3,3]],
[[4,4,4],[4,4,4],[4,4,4],[4,4,4],[4,4,4]],
[[5,5,5],[5,5,5],[5,5,5],[5,5,5],[5,5,5]]
],dtype='uint8')
print(data)
print(data.shape) #(5,5,3)
data = transforms.ToTensor()(data)
print(data)
print(data.shape) #(3,5,5)
输出:
tensor([[[0.0039, 0.0039, 0.0039, 0.0039, 0.0039],
[0.0078, 0.0078, 0.0078, 0.0078, 0.0078],
[0.0118, 0.0118, 0.0118, 0.0118, 0.0118],
[0.0157, 0.0157, 0.0157, 0.0157, 0.0157],
[0.0196, 0.0196, 0.0196, 0.0196, 0.0196]],
[[0.0039, 0.0039, 0.0039, 0.0039, 0.0039],
[0.0078, 0.0078, 0.0078, 0.0078, 0.0078],
[0.0118, 0.0118, 0.0118, 0.0118, 0.0118],
[0.0157, 0.0157, 0.0157, 0.0157, 0.0157],
[0.0196, 0.0196, 0.0196, 0.0196, 0.0196]],
[[0.0039, 0.0039, 0.0039, 0.0039, 0.0039],
[0.0078, 0.0078, 0.0078, 0.0078, 0.0078],
[0.0118, 0.0118, 0.0118, 0.0118, 0.0118],
[0.0157, 0.0157, 0.0157, 0.0157, 0.0157],
[0.0196, 0.0196, 0.0196, 0.0196, 0.0196]]])
2、 transforms.Normalize()
x = (x - mean) / std
即同一纬度的数据减去这一维度的平均值,再除以标准差,将归一化后的数据变换到[-1,1]之间。可真是这样吗??
- 求解mean和std
我们需要求得一批数据的mean和std,代码如下:
import torch
import numpy as np
from torchvision import transforms
# 这里以上述创建的单数据为例子
data = np.array([
[[1,1,1],[1,1,1],[1,1,1],[1,1,1],[1,1,1]],
[[2,2,2],[2,2,2],[2,2,2],[2,2,2],[2,2,2]],
[[3,3,3],[3,3,3],[3,3,3],[3,3,3],[3,3,3]],
[[4,4,4],[4,4,4],[4,4,4],[4,4,4],[4,4,4]],
[[5,5,5],[5,5,5],[5,5,5],[5,5,5],[5,5,5]]
],dtype='uint8')
#将数据转为C,W,H,并归一化到[0,1]
data = transforms.ToTensor()(data)
# 需要对数据进行扩维,增加batch维度
data = torch.unsqueeze(data,0)
nb_samples = 0.
#创建3维的空列表
channel_mean = torch.zeros(3) #tensor([0., 0., 0.])
channel_std = torch.zeros(3) #tensor([0., 0., 0.])
print(data.shape) # torch.Size([1,3,5,5])
# tensor([[[[0.0039, 0.0039, 0.0039, 0.0039, 0.0039],
[0.0078, 0.0078, 0.0078, 0.0078, 0.0078],
[0.0118, 0.0118, 0.0118, 0.0118, 0.0118],
[0.0157, 0.0157, 0.0157, 0.0157, 0.0157],
[0.0196, 0.0196, 0.0196, 0.0196, 0.0196]],
[[0.0039, 0.0039, 0.0039, 0.0039, 0.0039],
[0.0078, 0.0078, 0.0078, 0.0078, 0.0078],
[0.0118, 0.0118, 0.0118, 0.0118, 0.0118],
[0.0157, 0.0157, 0.0157, 0.0157, 0.0157],
[0.0196, 0.0196, 0.0196, 0.0196, 0.0196]],
[[0.0039, 0.0039, 0.0039, 0.0039, 0.0039],
[0.0078, 0.0078, 0.0078, 0.0078, 0.0078],
[0.0118, 0.0118, 0.0118, 0.0118, 0.0118],
[0.0157, 0.0157, 0.0157, 0.0157, 0.0157],
[0.0196, 0.0196, 0.0196, 0.0196, 0.0196]]]])
N, C, H, W = data.shape[:4] #N=1 C=3 H=5 W=5
data = data.view(N, C, -1) #将w,h维度的数据展平,为batch,channel,data,然后对三个维度上的数分别求和和标准差
print(data.shape) #torch.Size([1, 3, 25])
#tensor([[[0.0039, 0.0039, 0.0039, 0.0039, 0.0039, 0.0078, 0.0078, 0.0078,
0.0078, 0.0078, 0.0118, 0.0118, 0.0118, 0.0118, 0.0118, 0.0157,
0.0157, 0.0157, 0.0157, 0.0157, 0.0196, 0.0196, 0.0196, 0.0196,
0.0196],
[0.0039, 0.0039, 0.0039, 0.0039, 0.0039, 0.0078, 0.0078, 0.0078,
0.0078, 0.0078, 0.0118, 0.0118, 0.0118, 0.0118, 0.0118, 0.0157,
0.0157, 0.0157, 0.0157, 0.0157, 0.0196, 0.0196, 0.0196, 0.0196,
0.0196],
[0.0039, 0.0039, 0.0039, 0.0039, 0.0039, 0.0078, 0.0078, 0.0078,
0.0078, 0.0078, 0.0118, 0.0118, 0.0118, 0.0118, 0.0118, 0.0157,
0.0157, 0.0157, 0.0157, 0.0157, 0.0196, 0.0196, 0.0196, 0.0196,
0.0196]]])
#展平后,w,h属于第二维度,对他们求平均,sum(0)为将同一纬度的数据累加
channel_mean += data.mean(2).sum(0) #tensor([0.0118, 0.0118, 0.0118])
#展平后,w,h属于第二维度,对他们求标准差,sum(0)为将同一纬度的数据累加
channel_std += data.std(2).sum(0) #tensor([0.0057, 0.0057, 0.0057])
#获取所有batch的数据,这里为1
nb_samples += N
#获取同一batch的均值和标准差
channel_mean /= nb_samples
channel_std /= nb_samples
print(channel_mean, channel_std) #tensor([0.0118, 0.0118, 0.0118]) tensor([0.0057, 0.0057, 0.0057])
以此便可求得均值和标准差。我们再带入公式:
x = (x - mean) / std
- 自己实现:
data = np.array([
[[1,1,1],[1,1,1],[1,1,1],[1,1,1],[1,1,1]],
[[2,2,2],[2,2,2],[2,2,2],[2,2,2],[2,2,2]],
[[3,3,3],[3,3,3],[3,3,3],[3,3,3],[3,3,3]],
[[4,4,4],[4,4,4],[4,4,4],[4,4,4],[4,4,4]],
[[5,5,5],[5,5,5],[5,5,5],[5,5,5],[5,5,5]]
],dtype='uint8')
data = transforms.ToTensor()(data)
print(data)
#tensor([[[0.0039, 0.0039, 0.0039, 0.0039, 0.0039],
[0.0078, 0.0078, 0.0078, 0.0078, 0.0078],
[0.0118, 0.0118, 0.0118, 0.0118, 0.0118],
[0.0157, 0.0157, 0.0157, 0.0157, 0.0157],
[0.0196, 0.0196, 0.0196, 0.0196, 0.0196]],
[[0.0039, 0.0039, 0.0039, 0.0039, 0.0039],
[0.0078, 0.0078, 0.0078, 0.0078, 0.0078],
[0.0118, 0.0118, 0.0118, 0.0118, 0.0118],
[0.0157, 0.0157, 0.0157, 0.0157, 0.0157],
[0.0196, 0.0196, 0.0196, 0.0196, 0.0196]],
[[0.0039, 0.0039, 0.0039, 0.0039, 0.0039],
[0.0078, 0.0078, 0.0078, 0.0078, 0.0078],
[0.0118, 0.0118, 0.0118, 0.0118, 0.0118],
[0.0157, 0.0157, 0.0157, 0.0157, 0.0157],
[0.0196, 0.0196, 0.0196, 0.0196, 0.0196]]])
for i in range(3):
data[i,:,:] = (data[i,:,:] - channel_mean[i]) / channel_std[i]
print(data)
输出:
tensor([[[-1.3856, -1.3856, -1.3856, -1.3856, -1.3856],
[-0.6928, -0.6928, -0.6928, -0.6928, -0.6928],
[ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000],
[ 0.6928, 0.6928, 0.6928, 0.6928, 0.6928],
[ 1.3856, 1.3856, 1.3856, 1.3856, 1.3856]],
[[-1.3856, -1.3856, -1.3856, -1.3856, -1.3856],
[-0.6928, -0.6928, -0.6928, -0.6928, -0.6928],
[ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000],
[ 0.6928, 0.6928, 0.6928, 0.6928, 0.6928],
[ 1.3856, 1.3856, 1.3856, 1.3856, 1.3856]],
[[-1.3856, -1.3856, -1.3856, -1.3856, -1.3856],
[-0.6928, -0.6928, -0.6928, -0.6928, -0.6928],
[ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000],
[ 0.6928, 0.6928, 0.6928, 0.6928, 0.6928],
[ 1.3856, 1.3856, 1.3856, 1.3856, 1.3856]]])
- 官方实现
data = np.array([
[[1,1,1],[1,1,1],[1,1,1],[1,1,1],[1,1,1]],
[[2,2,2],[2,2,2],[2,2,2],[2,2,2],[2,2,2]],
[[3,3,3],[3,3,3],[3,3,3],[3,3,3],[3,3,3]],
[[4,4,4],[4,4,4],[4,4,4],[4,4,4],[4,4,4]],
[[5,5,5],[5,5,5],[5,5,5],[5,5,5],[5,5,5]]
],dtype='uint8')
data = transforms.ToTensor()(data)
data = transforms.Normalize(channel_mean, channel_std)(data)
print(data)
输出:
tensor([[[-1.3856, -1.3856, -1.3856, -1.3856, -1.3856],
[-0.6928, -0.6928, -0.6928, -0.6928, -0.6928],
[ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000],
[ 0.6928, 0.6928, 0.6928, 0.6928, 0.6928],
[ 1.3856, 1.3856, 1.3856, 1.3856, 1.3856]],
[[-1.3856, -1.3856, -1.3856, -1.3856, -1.3856],
[-0.6928, -0.6928, -0.6928, -0.6928, -0.6928],
[ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000],
[ 0.6928, 0.6928, 0.6928, 0.6928, 0.6928],
[ 1.3856, 1.3856, 1.3856, 1.3856, 1.3856]],
[[-1.3856, -1.3856, -1.3856, -1.3856, -1.3856],
[-0.6928, -0.6928, -0.6928, -0.6928, -0.6928],
[ 0.0000, 0.0000, 0.0000, 0.0000, 0.0000],
[ 0.6928, 0.6928, 0.6928, 0.6928, 0.6928],
[ 1.3856, 1.3856, 1.3856, 1.3856, 1.3856]]])
我们观察数据发现,通过求解的均值和标准差,求得的标准化的值,并非在[-1,1]
结论:
经过这样处理后的数据符合标准正态分布,即均值为0,标准差为1。使模型更容易收敛。并非是归于[-1,1]!!
Normalize之前,数据分布是在[0,1]
Normalize之后:
- ①如果mean = std=(0.5,0.5,0.5),那么Normalize之后,数据分布是【-1,1】;因为最小值=(0-mean)/std=(0-0.5)/0.5=-1。同理最大值的等于1。
- ②如果mean为数据的计算的mean,std也是数据计算的std。那么Normalize之后根据公式(x-mean)/std,结合均值和方差的性质,可以算出新数据的均值会变成0,方差会变成1。
总结:
如果是Normalize((0.5,0.5,0.5),(0.5,0.5,0.5)),确实是归一化到【-1,1】
如果是Normalize(channel_mean, channel_std),才是均值为0,标准差为1。
transforms 数据增强
数据增强又称为数据增广,数据扩增,它是对训练集进行变换,使训练集更丰富,从而让模型更具泛化能力。
transforms——裁剪
-
transforms.CenterCrop
- 功能:从图像中心裁剪图片
- size:所需裁剪图片尺寸
2、transforms.RandomCrop
- 功能:从图片中随机裁剪出尺寸为size的图片
- size:所需裁剪图片尺寸
- padding:设置填充大小。当为a时,上下左右均填充a个像素,当为(a,b)时,上下填充b个像素,左右填充a个像素。当为(a,b,c,d)时,左上右下分别填充abcd
- pad_if_need:若图像小于设定size,则填充
- padding_mode:填充模式:(1)constant像素值由fill设定(默认模式);(2)edge像素值由图像边缘像素决定(3)reflect镜像填充,最后一个像素不镜像,eg,[1,2,3,4]->[3,2,1,2,3,4,3,2];(4)symmetric镜像填充,最后一个像素镜像,eg,[1,2,3,4]->[2,1,1,2,3,4,4,3]
- fill:constant时,设置填充的像素值
transforms——翻转和旋转
- RandomHorizontalFlip 水平翻转
- RandomVerticalFlip 垂直翻转
- RandomRotation 随机旋转图像
自定义tansfroms方法
class Compose(object):
def __call__(self,img):
for t in self.transforms:
img = t(img)
return img
transforms方法是在Compose类的__call__方法中被调用的,对一组transforms方法进行for循环,每次循序的挑选并执行transforms方法。文章来源:https://www.toymoban.com/news/detail-444914.html
-
自定义transforms要素:
- 仅接收一个参数,返回一个参数
- 注意上下游的输出和输入,数据类型必须匹配
通过类实现多参数传入,下图为自定义transforms的基本参数,一个init,一个call文章来源地址https://www.toymoban.com/news/detail-444914.html
class YourTransforms(object):
def __init__(self,...):
...
def __call__(self,img):
...
return img
椒盐噪声
- 椒盐噪声又称为又称为脉冲噪声,是一种随机出现的白点或者黑点,白点称为盐噪声,黑点称为椒噪声。
- 信噪比(SNR):衡量噪声的比例,图像中为图像像素的占比
class AddPepperNoise(object):
def __init__(self, snr, p):
self.snr = snr
self.p = p
def __call__(self, img):
'''
添加椒盐噪声具体实现过程
'''
return img
到了这里,关于学习pytorch中归一化transforms.Normalize的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!