Конструкция адаптационного модуля для укладки двух CNN

#python #tensorflow #keras #neural-network #conv-neural-network

Вопрос:

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

Чтобы быть более точным, я хотел бы обучить модуль адаптации соединять два сверточных слоя:

  1. Слой A с выходной формой: (29,29,256)
  2. Слой B с входной формой: (8,8,384)

Итак, после слоя А я последовательно добавляю модуль адаптации, для которого выбираю:

  • Слой Conv2D с 384 фильтрами с размером ядра: (3,3) / Форма вывода: (29,29,384)
  • MaxPool2D с размером пула: (2,2), шагами: (4,4) и заполнением: «одинаковая» / Форма вывода: (8,384)

Наконец, я пытаюсь добавить слой B в модель, но получаю следующую ошибку от tensorflow:

 InvalidArgumentError: Dimensions must be equal, but are 384 and 288 for '{{node batch_normalization_159/FusedBatchNormV3}} = FusedBatchNormV3[T=DT_FLOAT, U=DT_FLOAT, data_format="NHWC", epsilon=0.001, exponential_avg_factor=1, is_training=false](Placeholder, batch_normalization_159/scale, batch_normalization_159/ReadVariableOp, batch_normalization_159/FusedBatchNormV3/ReadVariableOp, batch_normalization_159/FusedBatchNormV3/ReadVariableOp_1)' with input shapes: [?,8,8,384], [288], [288], [288], [288].
 

Есть минимальный воспроизводимый пример этого:

 from keras.applications.inception_resnet_v2 import InceptionResNetV2
from keras.applications.mobilenet import MobileNet
from keras.layers import Conv2D, MaxPool2D
from keras.models import Sequential

mobile_model = MobileNet(weights='imagenet')
server_model = InceptionResNetV2(weights='imagenet')

hybrid = Sequential()

for i, layer in enumerate(mobile_model.layers):
  if i <= 36:
    layer.trainable = False
    hybrid.add(layer)

hybrid.add(Conv2D(384, kernel_size=(3,3), padding='same'))
hybrid.add(MaxPool2D(pool_size=(2,2), strides=(4,4), padding='same'))

for i, layer in enumerate(server_model.layers):
  if i >= 610:
    layer.trainable = False
    hybrid.add(layer)
 

Ответ №1:

Последовательные модели поддерживают только модели, в которых слои расположены в виде связанного списка — каждый слой принимает выходные данные только одного слоя, а выходные данные каждого слоя подаются только в один слой. Ваши две базовые модели имеют остаточные блоки, что нарушает приведенное выше предположение и превращает архитектуру модели в ориентированный ациклический граф (DAG).

Чтобы сделать то, что вы хотите сделать, вам нужно будет использовать функциональный API. С помощью функционального API вы явно управляете промежуточными активациями, называемыми керастенсорами.

Для первой модели вы можете пропустить эту дополнительную работу и просто создать новую модель из подмножества существующего графика, как это

sub_mobile = keras.models.Model(mobile_model.inputs, mobile_model.layers[36].output)

Подключение некоторых слоев второй модели намного сложнее. Легко срезать конец модели keras — гораздо сложнее срезать начало из-за необходимости tf.keras.Заполнитель ввода. Чтобы сделать это успешно, вам нужно будет написать алгоритм обхода модели, который проходит через слои, отслеживает выходные КерасТенсоры, затем вызывает каждый слой с новыми входными данными для создания нового выходного керастенсора.

Вы могли бы избежать всей этой работы, просто найдя исходный код для сети InceptionResNet и добавив слои с помощью Python, а не углубляясь в существующую модель. Вот один, который может подойти по всем параметрам.

https://github.com/yuyang-huang/keras-inception-resnet-v2/blob/master/inception_resnet_v2.py

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

1. Спасибо за ваш ответ. Что меня беспокоит, так это то, что я хотел бы, чтобы InceptionResNet сохранял свой вес в imagenet. Можно ли добавлять слои через python и как-то настраивать их вес для imagenet?

2. Да, довольно просто. После создания модели просто создайте новую модель. слои[y].set_weights(original_model. слой[x].get_weights ()), где x и y индексируются в соответствующие слои.