#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), результат, который мы получаем после слоя свертки, будет отличаться, давая разные / неожиданные результаты в качестве конечного результата после объединения.
Итак, чтобы получить желаемый результат здесь, вам также нужно перевернуть ядро.