вычисление среднего и стандартного значений для массива тензоров факела

#python #numpy #deep-learning #pytorch #torch

#python #numpy #глубокое обучение #pytorch #torch

Вопрос:

Я пытаюсь вычислить среднее и std для массива тензоров факела. Мой набор данных содержит 720 обучающих изображений, и каждое из этих изображений имеет 4 ориентира, где X и Y представляют 2D-точку на изображении.

 to_tensor = transforms.ToTensor()

landmarks_arr = []

for i in range(len(train_dataset)):
    landmarks_arr.append(to_tensor(train_dataset[i]['landmarks']))
                     
mean = torch.mean(torch.stack(landmarks_arr, dim=0))#, dim=(0, 2, 3))
std = torch.std(torch.stack(landmarks_arr, dim=0)) #, dim=(0, 2, 3))



print(mean.shape)
print("mean is {} and std is {}".format(mean, std))
  

Результат:

 torch.Size([])
mean is nan and std is nan
  

Существует пара проблем, описанных выше:

  1. Почему to_tensor не преобразует значения между 0 и 1?
  2. как правильно вычислить среднее значение?
  3. Должен ли я делить на 255 и где?

У меня есть:

 len(landmarks_arr)
    
720
  

и

 landmarks_arr[0].shape

torch.Size([1, 4, 2])
  

и

 landmarks_arr[0]

tensor([[[502.2869, 240.4949],
         [688.0000, 293.0000],
         [346.0000, 317.0000],
         [560.8283, 322.6830]]], dtype=torch.float64)
  

Ответ №1:

  1. Из документов pytorch ToTensor():

Преобразует PIL-изображение или numpy.ndarray (H x W x C) в диапазоне [0, 255] в torch.Плавающий тензор формы (C x H x W) в диапазоне [0.0, 1.0], если PIL-изображение принадлежит одному из режимов (L, LA, P, I, F, RGB, YCbCr, RGBA, CMYK, 1) или если numpy.ndarray имеет dtype = np.uint8

В других случаях тензоры возвращаются без масштабирования.

Поскольку ваши значения ориентиров не являются PIL-изображением и не находятся в пределах [0, 255], масштабирование не применяется.

  1. Ваш расчет кажется правильным. Кажется, что у вас может быть некоторое значение NaN в ваших данных.

Вы можете попробовать что-то вроде

 for i in range(len(train_dataset)):
    landmarks = to_tensor(train_dataset[i]['landmarks'])
    landmarks[landmarks != landmarks] = 0  # this will set all nan to zero
    landmarks_arr.append(landmarks)
  

в вашем цикле. Или assert для nan в цикле, чтобы найти виновника (ов):

 for i in range(len(train_dataset)):
    landmarks = to_tensor(train_dataset[i]['landmarks'])
    assert(not torch.isnan(landmarks).any()), f'nan encountered in sample {i}'  # will trigger if a landmark contains nan
    landmarks_arr.append(landmarks)
  
  1. Нет, см. 1). Вы можете разделить на максимальные координаты ориентиров, хотя и ограничить их [0, 1], если вы того пожелаете.

введите описание изображения здесь

Комментарии:

1. почему я должен делить на максимальную координату, если to_tensor уже помещает их между [0, 1]?

2. потому toTensor что помещает изображения PIL между [0,1]. Ваша цель / ориентиры останутся неизменными. Итак, если вы хотите нормализовать свой ориентир на [0,1], вы можете разделить на максимальную координату.

3. ————————————————————————— Трассировка ошибки утверждения (последний последний вызов) <ipython-input-20-19e49f3367ed> в <модуле> 7 для i в диапазоне (len(train_dataset)): 8 ориентиров = to_tensor(train_dataset[i][‘ориентиры’]) —-> 9 assert(не torch.isnan(ориентиры).any()), f’nan, встречающиеся в образце {i}’ #, будут срабатывать, если ориентир содержит nan 10 landmarks_arr.append(ориентиры) 11 Ошибка утверждения: nan встречается в образце 56

4. Безусловно, было бы более эффективно вычислять максимум по всему массиву, а не перебирать отдельные записи.