我不明白
Pytorch
中的标准化是如何工作的。
我想将形状为
0
的张量 1
中所有列的平均值设置为 x
,将标准差设置为 (2, 2, 3)
。
一个简单的例子:
>>> x = torch.tensor([[[ 1., 2., 3.],
[ 4., 5., 6.]],
[[ 7., 8., 9.],
[10., 11., 12.]]])
>>> norm = transforms.Normalize((0, 0), (1, 1))
>>> norm(x)
tensor([[[ 1., 2., 3.],
[ 4., 5., 6.]],
[[ 7., 8., 9.],
[10., 11., 12.]]])
所以应用归一化变换时没有任何变化。这是为什么?
torchvision.transforms.Normalize
并不像您预期的那样工作。那是因为它的目的不是:
标准化:(使您的数据范围在
[0, 1]
)也不
标准化:使您的数据的
mean=0
和std=1
(这就是您正在寻找的。
T.Normalize
执行的操作仅仅是移位尺度变换:
output[channel] = (input[channel] - mean[channel]) / std[channel]
参数名称
mean
和 std
似乎相当具有误导性,因为它并不是指所需的 output 统计数据,而是指任何任意值。没错,如果你输入mean=0
和std=1
,它会给你output = (input - 0) / 1 = input
。因此,当您期望分别获得均值和方差张量 norm
和 0
时,您收到的结果是函数 1
对张量值没有影响。
但是,提供正确的
mean
和 std
参数,i.e. 当 mean=mean(data)
和 std=std(data)
时,那么你最终会逐个通道计算数据通道的 z-score,这就是通常称为“标准化”。因此,为了真正获得 mean=0
和 std=1
,您首先需要计算数据的平均值和标准差。如果你这样做:
>>> mean, std = x.mean(), x.std()
(tensor(6.5000), tensor(3.6056))
它将分别为您提供全局平均值和全局标准差。
相反,您想要的是测量每个
通道的一阶和二阶统计数据。因此,我们需要在除torch.mean
之外的所有维度上应用 torch.std
dim=1
。这两个函数都可以接收维度的tuple:
>>> mean, std = x.mean((0,2)), x.std((0,2))
(tensor([5., 8.]), tensor([3.4059, 3.4059]))
以上是沿每个通道测量的 x
的正确平均值和标准差。从那里您可以继续使用 T.Normalize(mean, std)
使用正确的移位比例参数正确转换数据
x
。
>>> norm(x)
tensor([[[-1.5254, -1.2481, -0.9707],
[-0.6934, -0.4160, -0.1387]],
[[ 0.1387, 0.4160, 0.6934],
[ 0.9707, 1.2481, 1.5254]]])
参见 用平均值和标准差对张量图像进行归一化。给定均值: (mean[1],...,mean[n]) 和 std: (std[1],..,std[n]) 对于 n 个通道,这 变换将标准化输入火炬的每个通道。*张量,即 输出[通道] = (输入[通道] - 平均值[通道]) / std[通道]
和因此,如果您有
mean=0
std=1
,那么
output=(output - 0) / 1
不会改变。
扩展上述解释的示例:
from torchvision import transforms
import torch
norm = transforms.Normalize((0,0),(1,2))
x = torch.tensor([[[1.0,2,3],[4,5,6]],[[7,8,9],[10,11,12]]])
out = norm(x)
print(x)
print(out)
输出:
tensor([[[ 1., 2., 3.],
[ 4., 5., 6.]],
[[ 7., 8., 9.],
[10., 11., 12.]]])
tensor([[[1.0000, 2.0000, 3.0000],
[4.0000, 5.0000, 6.0000]],
[[3.5000, 4.0000, 4.5000],
[5.0000, 5.5000, 6.0000]]])
如您所见,第一个通道不变,第二个通道除以 2。