Почему перелистывание изображений изменяет вывод пула CNN

#image-processing #deep-learning #conv-neural-network #data-augmentation

#обработка изображений #глубокое обучение #conv-нейронная сеть #увеличение данных

Вопрос:

Я смотрю на вложения изображений и задаюсь вопросом, почему переключение изображений изменяет вывод. Рассмотрим, например, resnet18 с удаленной головкой:

 import torch
import torch.nn as nn
import torchvision.models as models
device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu")

model = models.resnet18(pretrained=True)
model.fc = nn.Identity()
model = model.to(device)
model.eval()

x = torch.randn(20, 3, 128, 128).to(device)
with torch.no_grad():
    y1 = model(x)
    y2 = model(x.flip(-1))
    y3 = model(x.flip(-2))
  

Последний слой выглядит следующим образом и, что наиболее важно, имеет a AdaptiveAveragePooling в качестве последнего слоя, где пиксели / объекты объединены в 1 пиксель:
введите описание изображения здесь

Согласно тому, как я думаю, поскольку у нас просто есть свертки поверх свертки, перед объединением, все, что произойдет, это то, что карта объектов будет переворачиваться в соответствии с тем, как перевернуто изображение. Среднее объединение просто усредняет последнюю карту объектов (вдоль каждого канала) и не зависит от ее ориентации. AdaptiveMaxPool должно было быть то же самое.

Ключевое различие между «обычными» сетями заключается в том, что мы объединяем / усредняем до ширины в один пиксель.

Однако, когда я смотрю на y1-y2 , y1-y3 , y2-y3 значения значительно отличаются от нуля. О чем я думаю неправильно?

Ответ №1:

Я думаю, что выходные данные пула изменены, потому что входные данные для уровня пула передаются не так, как мы ожидаем.

Краткий ответ: входные данные переворачиваются, но не веса слоев Conv2d. Эти веса ядра также необходимо перевернуть в соответствии с перелистыванием входных данных, чтобы получить ожидаемый результат.

Длинный ответ: здесь, в соответствии с хвостом модели, вывод Conv2d передается AdaptiveAveragePooling . Давайте пока просто проигнорируем BatchNorm ради понимания.

Для простоты давайте рассмотрим входной тензор как x = [1, 3, 5, 4, 7] и ядро k =[0.3, 0.5, 0.8] . Когда он переворачивает ввод, вывод для позиции [0,0] будет [0.3*1 0.5*3 0.8*5] = 6.8 и [0,2] будет [0.3*5 0.5*4 0.8*7]=9.3 обдумывая stride=1 .

Теперь, если вход перевернут x_flip = [7, 4, 5, 3, 1] , вывод для позиции [0,0] будет [0.3*7 0.5*4 0.8*5] = 8.1 и [0,2] будет [0.3*5 0.5*3 0.8*1] = 3.8.

Поскольку начало и конец выходных данных различны в обоих сценариях (8.1 ! = 9.3 и 6.8 ! = 3.8), результат, который мы получаем после слоя свертки, будет отличаться, давая разные / неожиданные результаты в качестве конечного результата после объединения.

Итак, чтобы получить желаемый результат здесь, вам также нужно перевернуть ядро.