我们都知道 当图像数据输入时 需要对图像数据进行预处理 常用的预处理方法 本文不再赘述 本文重在讲讲transform.ToTensor和transforms.Normalize。
问题transform.ToTensor(), transform.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))
究竟是什么意思 (0.5,0.5,0.5),(0.5,0.5,0.5)又是怎么来的呢
transform.ToTensor() 是将输入的数据shape W H C —— C W H将所有数除以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]]])transforms.Normalize()
看了许多文章 都是说 transform.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) channel_std torch.zeros(3) print(data.shape) N, C, H, W data.shape[:4] data data.view(N, C, -1) #将w,h维度的数据展平 为batch channel,data,然后对三个维度上的数分别求和和标准差 print(data.shape) #展平后 w,h属于第二维度 对他们求平均 sum(0)为将同一纬度的数据累加 channel_mean data.mean(2).sum(0) #展平后 w,h属于第二维度 对他们求标准差 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)
以此便可求得均值和标准差。我们再带入公式
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) 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】



