#python #tensorflow #keras #neural-network #conv-neural-network
Вопрос:
Я пытаюсь сложить два разных CNN, используя модуль адаптации, чтобы соединить их, но мне трудно правильно определить гиперпараметры слоев модуля адаптации.
Чтобы быть более точным, я хотел бы обучить модуль адаптации соединять два сверточных слоя:
- Слой A с выходной формой: (29,29,256)
- Слой 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 индексируются в соответствующие слои.