transforms.ToTensor
最近看pytorch时,遇到了对图像数据的归一化,如下图所示:
transforms.ToTensor()
transforms.ToTensor()transforms.ToTensor()
先导入一些包
import cv2 import numpy as np import torch from torchvision import transforms
定义一个数组模型图片,注意数组数据类型需要时np.uint8【官方图示中给出】
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的shape,注意现在为(W H C)。
transforms.ToTensor()
data = transforms.ToTensor()(data)
这时候我们来看看data中的数据及shape。
很明显,数据现在都映射到了[0, 1]之间,并且data的shape发生了变换。
**注意:不知道大家是如何理解三维数组的,这里提供我的一个方法。**???
?原始的data的shape为(5,5,3),则其表示有5个(5 , 3)的二维数组,即我们把最外层的[]去掉就得到了5个五行三列的数据。
?同样的,变换后data的shape为(3,5,5),则其表示有3个(5 , 5)的二维数组,即我们把最外层的[]去掉就得到了3个五行五列的数据。
transforms.Normalize?
transforms.ToTensortransforms.Normalize
output[channel] = (input[channel] - mean[channel]) / std[channel]
这里的第一个参数(0.5,0.5,0.5)表示每个通道的均值都是0.5,第二个参数(0.5,0.5,0.5)表示每个通道的方差都为0.5。【因为图像一般是三个通道,所以这里的向量都是1x3的???】有了这两个参数后,当我们传入一个图像时,就会按照上面的公式对图像进行变换。【注意:这里说图像其实也不够准确,因为这个函数传入的格式不能为PIL Image,我们应该先将其转换为Tensor格式】
output =(0 - 0.5)/ 0.5 = -1output =(1 - 0.5)/ 0.5 = 1
读到这里大家是不是以为就完了呢?这里还想和大家唠上一唠???上面的两个参数(0.5,0.5,0.5)是怎么得来的呢?这是根据数据集中的数据计算出的均值和标准差,所以往往不同的数据集这两个值是不同的???这里再举一个例子帮助大家理解其计算过程。同样采用上文例子中提到的数据。
上文已经得到了经ToTensor转换后的数据,现需要求出该数据每个通道的mean和std。【这一部分建议大家自己运行看看每一步的结果???】
# 需要对数据进行扩维,增加batch维度 data = torch.unsqueeze(data,0) #在pytorch中一般都是(batch,C,H,W) nb_samples = 0. #创建3维的空列表 channel_mean = torch.zeros(3) channel_std = torch.zeros(3) N, C, H, W = data.shape[:4] data = data.view(N, C, -1) #将数据的H,W合并 #展平后,w,h属于第2维度,对他们求平均,sum(0)为将同一纬度的数据累加 channel_mean += data.mean(2).sum(0) #展平后,w,h属于第2维度,对他们求标准差,sum(0)为将同一纬度的数据累加 channel_std += data.std(2).sum(0) #获取所有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])
将上述得到的mean和std带入公式,计算输出。
for i in range(3): data[i] = (data[i] - channel_mean[i]) / channel_std[i] print(data)
输出结果:
从结果可以看出,我们计算的mean和std并不是0.5,且最后的结果也没有在[-1,1]之间。
input = std*output + mean