#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.