Как работает torchvision.transformes.Работает Normalize?

#pytorch #torchvision

#pytorch #torchvision

Вопрос:

Я не понимаю, как 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.]]])
 

Таким образом, ничего не изменилось при применении преобразования нормализации. Почему это так?

Ответ №1:

Чтобы дать ответ на ваш вопрос, теперь вы поняли, что torchvision.transforms.Normalize это работает не так, как вы ожидали. Это потому, что это не предназначено для:

  • нормализовать: (ввод вашего диапазона данных [0, 1] ) ни
  • стандартизация: создание ваших данных mean=0 и std=1 (что вы ищете.

Операция, выполняемая с помощью T.Normalize , является просто преобразованием масштаба сдвига:

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

Имена параметров mean и std , что кажется довольно вводящим в заблуждение, зная, что оно предназначено не для ссылки на желаемую статистику вывода, а для любых произвольных значений. Правильно, если вы введете mean=0 и std=1 , это даст вам output = (input - 0) / 1 = input . Следовательно, результат, который вы получили, где функция norm не повлияла на ваши значения тензора, когда вы ожидали получить тензор среднего и дисперсии 0 и 1 , соответственно.

Однако, предоставляя правильные mean std параметры и, то есть когда mean=mean(data) и std=std(data) , вы в конечном итоге вычисляете z-оценку вашего канала данных по каналам, что обычно называется «стандартизацией». Итак, чтобы на самом деле получить mean=0 и std=1 , вам сначала нужно вычислить среднее и стандартное отклонение ваших данных.

Если вы делаете:

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

Это даст вам глобальное среднее значение и глобальное стандартное отклонение соответственно.

Вместо этого вы хотите измерить статистику 1-го и 2-го порядка для каждого канала. Поэтому нам нужно применить torch.mean и torch.std ожидать во всех измерениях dim=1 . Обе эти функции могут получать кортеж измерений:

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

Ответ №2:

Следуйте объяснению в документации torchvision.transformes.Нормализовать:

Нормализуйте тензорное изображение со средним и стандартным отклонением. Учитывая среднее значение: (среднее значение [1], …, среднее значение [n]) и std: (std [1], ..,std [n]) для n каналов, это преобразование нормализует каждый канал входного факела.* Тензор, т.е. Выходной [канал] = (входной [канал] — среднее значение [канал]) / std[канал]

Так что если у вас есть mead=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.