Pytorch: изменение архитектуры VGG16
В настоящее время я пытаюсь изменить сетевую архитектуру VGG16, чтобы она могла принимать изображения размером 400x400 пикселей.
Исходя из литературы, которую я прочитал, способ сделать это состоит в том, чтобы преобразовать полностью соединенные (FC) слои в сверточные (CONV) слои. Это, по сути, "позволило бы сети эффективно" скользить "по большему входному изображению и выполнять множественные оценки различных частей изображения, включая всю доступную контекстную информацию". После этого слой Average Pooling используется для "усреднения множества векторов объектов в один вектор объектов, который суммирует входное изображение".
Я сделал это с помощью этой функции и придумал следующую сетевую архитектуру:
----------------------------------------------------------------
Layer (type) Output Shape Param #
================================================================
Conv2d-1 [-1, 64, 400, 400] 1,792
ReLU-2 [-1, 64, 400, 400] 0
Conv2d-3 [-1, 64, 400, 400] 36,928
ReLU-4 [-1, 64, 400, 400] 0
MaxPool2d-5 [-1, 64, 200, 200] 0
Conv2d-6 [-1, 128, 200, 200] 73,856
ReLU-7 [-1, 128, 200, 200] 0
Conv2d-8 [-1, 128, 200, 200] 147,584
ReLU-9 [-1, 128, 200, 200] 0
MaxPool2d-10 [-1, 128, 100, 100] 0
Conv2d-11 [-1, 256, 100, 100] 295,168
ReLU-12 [-1, 256, 100, 100] 0
Conv2d-13 [-1, 256, 100, 100] 590,080
ReLU-14 [-1, 256, 100, 100] 0
Conv2d-15 [-1, 256, 100, 100] 590,080
ReLU-16 [-1, 256, 100, 100] 0
MaxPool2d-17 [-1, 256, 50, 50] 0
Conv2d-18 [-1, 512, 50, 50] 1,180,160
ReLU-19 [-1, 512, 50, 50] 0
Conv2d-20 [-1, 512, 50, 50] 2,359,808
ReLU-21 [-1, 512, 50, 50] 0
Conv2d-22 [-1, 512, 50, 50] 2,359,808
ReLU-23 [-1, 512, 50, 50] 0
MaxPool2d-24 [-1, 512, 25, 25] 0
Conv2d-25 [-1, 512, 25, 25] 2,359,808
ReLU-26 [-1, 512, 25, 25] 0
Conv2d-27 [-1, 512, 25, 25] 2,359,808
ReLU-28 [-1, 512, 25, 25] 0
Conv2d-29 [-1, 512, 25, 25] 2,359,808
ReLU-30 [-1, 512, 25, 25] 0
MaxPool2d-31 [-1, 512, 12, 12] 0
Conv2d-32 [-1, 4096, 1, 1] 301,993,984
ReLU-33 [-1, 4096, 1, 1] 0
Dropout-34 [-1, 4096, 1, 1] 0
Conv2d-35 [-1, 4096, 1, 1] 16,781,312
ReLU-36 [-1, 4096, 1, 1] 0
Dropout-37 [-1, 4096, 1, 1] 0
Conv2d-38 [-1, 3, 1, 1] 12,291
AdaptiveAvgPool2d-39 [-1, 3, 1, 1] 0
Softmax-40 [-1, 3, 1, 1] 0
================================================================
Total params: 333,502,275
Trainable params: 318,787,587
Non-trainable params: 14,714,688
----------------------------------------------------------------
Input size (MB): 1.83
Forward/backward pass size (MB): 696.55
Params size (MB): 1272.21
Estimated Total Size (MB): 1970.59
----------------------------------------------------------------
Мой вопрос прост: необходимо ли использовать средний слой пула в конце? Похоже, что на последнем сверточном слое мы получаем изображение 1х1 с 3 каналами. Казалось бы, создание среднего пула не имеет никакого эффекта.
Если в моей логике / архитектуре есть что-то не так, пожалуйста, не стесняйтесь указывать на это. Спасибо!
2 ответа
Цель AdaptiveAvgPool2d
должен заставить коннет работать на вводе любого произвольного размера (и производить вывод фиксированного размера). В вашем случае, поскольку размер ввода фиксирован и равен 400x400, он вам, вероятно, не нужен.
Я думаю, что эта статья может дать вам лучшее представление об этом методе - https://arxiv.org/pdf/1406.4729v3.pdf
Как преобразовать VGG в, кроме входного размера 400 х 400?
Первый подход
Проблема с VGG
Архитектура стиля заключается в том, что мы жестко программируем количество входных и выходных функций в наших линейных слоях. т.е.
vgg.classifier[0]: Linear(in_features=25088, out_features=4096, bias=True)
Ожидается 25 088 входных функций.
Если мы передаем изображение размером (3, 224, 224)
через vgg.features
выходная карта объектов будет иметь размеры:
(512, 7, 7) => 512 * 7 * 7 => 25,088
Если мы изменим размер входного изображения на (3, 400, 400)
и пройти через vgg.features
выходная карта объектов будет иметь размеры:
(512, 12, 12) => 512 * 12 * 12 => 73,728
throws `sizemismatch` error.
Одним из способов решения этой проблемы является использование nn.AdaptiveAvgPool
на месте nn.AvgPool
, AdaptiveAvgPool помогает определить размер вывода слоя, который остается постоянным, независимо от размера ввода через vgg.features
слой.
например:
vgg.features[30] = nn.AdaptiveAvgPool(output_size=(7,7))
will make sure the final feature maps have a dimension of `(512, 7, 7)`
irrespective of the input size.
Вы можете прочитать больше об Adaptive Pooling здесь.
Второй подход
Если вы используете эту технику для преобразования ваших линейных слоев в сверточные слои, вам не нужно беспокоиться о входном измерении, однако вам придется изменить методы инициализации веса из-за изменения количества параметров.
Нужно ли использовать средний слой пула в конце?
Нет, в этом случае. Он не меняет размер входной карты объектов, следовательно, он не выполняет усреднение по набору узлов.