一张正常的图,或者说是人眼习惯的图是这样的:
但是,为了神经网络更快收敛,我们在深度学习网络过程中通常需要将读取的图片转为tensor并归一化(此处的归一化指transforms.Normalize()操作)输入到网络中进行系列操作。
如果将转成的tensor再直接转为图片,就会变成下图,和我们眼睛看到是不一样感觉。
这是因为,将图片转为tensor并归一化,tensor之中会有负值,和我们正常看到的是不一样的,如果不进行反归一化到 [0,1],就会变成下图,会觉得变扭。
我们正常看到的图片tensor是[0,255]或者[0,1]
解释:transforms.Normalize()归一化后的图像,满足均值为0方差为1,被限定在一定的数值内,一般的数值为[-1,1]。
这个过程中,我们需要进行如下操作,才能把图片转为tensor操作再转为图片(人眼习惯的)。这里的tensor操作是transforms系列操作。
归一化的目的:使得预处理的数据被限定在一定的范围内,从而消除奇异样本数据导致的不良影响。数据归一化处理后,可以加快梯度下降求最优解的速度,且有可能提高精度(如KNN)。
反归一化的目的:为了还原原来人眼可以识别的图。
归一化
一幅图片的格式为【批数据的数量× 通道数× 高× 宽】:
接下来开始计算mean 和 std:
nb_samples = 0
#创建3维的空列表
channel_mean = torch.zeros(3)
channel_std = torch.zeros(3)
print(image.shape)
N, C, H, W = image.shape[:4]
image = image.view(N, C, -1) #将w,h维度的数据展平,为batch,channel,data,然后对三个维度上的数分别求和和标准差
print(image.shape)
#展平后,w,h属于第二维度,对他们求平均,sum(0)为将同一纬度的数据累加
channel_mean += image.mean(2).sum(0)
#展平后,w,h属于第二维度,对他们求标准差,sum(0)为将同一纬度的数据累加
channel_std += image.std(2).sum(0)
#获取所有batch的数据,这里为1
nb_samples += N
#获取同一batch的均值和标准差
channel_mean /= nb_samples
channel_std /= nb_samples
print(channel_mean, channel_std)
然后利用transforms.Normalize
进行转换:
normalizer = transforms.Normalize(mean=channel_mean, std=channel_std)
# 归一化后得到可处理的值
data = normalizer(image)
反归一化
根据归一化计算得到的mean和std,我们可以反推出反归一化的 mean 和 std,从而利用 transforms.Normalize
进行转换,计算方法如下:
MEAN是指归一化时计算出来的均值,de_MEAN是计算出来反归一化的均值,后面需要用。
综合上面的讲解及代码,整合最后的代码为下:
# 定义一个image图像,torch.Size([1, 3, 319, 256])
image = torch.rand([1,3,319,256])
# 计算原图的 mean 和std
nb_samples = 0
#创建3维的空列表
channel_mean = torch.zeros(3)
channel_std = torch.zeros(3)
print(image.shape)
N, C, H, W = image.shape[:4]
#将w,h维度的数据展平,为batch,channel,data,然后对三个维度上的数分别求和和标准差
image = image.view(N, C, -1)
print(image.shape)
#展平后,w,h属于第二维度,对他们求平均,sum(0)为将同一纬度的数据累加
channel_mean += image.mean(2).sum(0)
#展平后,w,h属于第二维度,对他们求标准差,sum(0)为将同一纬度的数据累加
channel_std += image.std(2).sum(0)
#获取所有batch的数据,这里为1
nb_samples += N
#获取同一batch的均值和标准差
channel_mean /= nb_samples
channel_std /= nb_samples
print(channel_mean, channel_std)
# 这是归一化的 mean 和std
channel_mean = torch.tensor([-0.5321, -0.8102, -0.5532])
channel_std = torch.tensor([1.2582, 1.0009, 0.9211])
# 这是反归一化的 mean 和std
MEAN = [-mean/std for mean, std in zip(channel_mean, channel_std)]
STD = [1/std for std in channel_std]
# 归一化和反归一化生成器
normalizer = transforms.Normalize(mean=channel_mean, std=channel_std)
denormalizer = transforms.Normalize(mean=MEAN, std=STD)
# 归一化得到可处理的值
data = normalizer(image)
# 反归一化得到原图
image2 = denormalizer(data)
image ≈ image2
因为浮点数计算有误差,所以不会完全一样,但是问题不大~
这样就可以得到tensor转换后的原图了。
好了,大功告成,完结撒花!
欢迎关注、点赞、收藏、评论、分享给好友,一起学习有趣的新知识!!!