torchvision.transforms.Normalize 是如何运作的?

How does torchvision.transforms.Normalize operates?

我不明白 Pytorch 中的规范化是如何工作的。

我想将形状为 (2, 2, 3).[=17= 的张量 x 中所有列的均值设置为 0,标准差设置为 1 ]

一个简单的例子:

>>> 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.]]])

所以在应用归一化变换时没有任何改变。这是为什么?

按照documentation of torchvision.transforms.Normalize的解释:

Normalize a tensor image with mean and standard deviation. Given mean: (mean[1],...,mean[n]) and std: (std[1],..,std[n]) for n channels, this transform will normalize each channel of the input torch.*Tensor i.e., output[channel] = (input[channel] - mean[channel]) / std[channel]

因此,如果您有 mead=0std=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.

实际回答您的问题。您现在已经意识到 torchvision.transforms.Normalize 并不像您期望的那样工作。那是因为它不是为了

  • normalize: (使你的数据范围在[0, 1]) nor

  • 标准化:使数据的 mean=0std=1(这就是你在找

T.Normalize执行的操作仅仅是一个平移变换:

output[channel] = (input[channel] - mean[channel]) / std[channel]

给定参数meanstd,调用函数Normalize及其参数[=22=感觉违反直觉]和"std"...自然地,如果你输入mean=0std=1,它会给你output = (input - 0) / 1 = input。因此你得到的结果是:norm 没有效果。

但是,如果您提供 mean=mean(data)std=std(data) 作为参数,那么您最终会逐个通道计算数据通道的 z-score,这通常称为 'standardization'。因此,为了实际获得 mean=0std=1,您首先需要计算数据的均值和标准差。

如果你这样做:

>>> mean, std = x.mean(), x.std()
(tensor(6.5000), tensor(3.6056))

它将分别为您提供全球平均值和全球标准差。

相反,您想要的是测量每个每个通道。所以我们想在 dim=1 上的所有维度上应用 torch.mean and torch.std。这两个函数都可以接收维度为 的元组

>>> mean, std = flattened.mean((0,2)), flattened.std((0,2))
(tensor([5., 8.]), tensor([3.4059, 3.4059]))

以上是 x 沿每个通道测量的正确平均值和标准偏差。从那里你可以继续使用 torchvision.transforms.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]]])