Этот пост, кажется, указывает на то, что то, чего я хочу достичь, невозможно. Однако я не уверен в этом - учитывая то, что я уже сделал, я не понимаю, почему то, что я хочу сделать, не может быть достигнуто ...
У меня есть два набора данных изображений, где у одного есть изображения формы (480, 720, 3), а у другого - изображения формы (540, 960, 3).
Я инициализировал модель, используя следующий код:
input = Input(shape=(480, 720, 3), name='image_input')
initial_model = VGG16(weights='imagenet', include_top=False)
for layer in initial_model.layers:
layer.trainable = False
x = Flatten()(initial_model(input))
x = Dense(1000, activation='relu')(x)
x = BatchNormalization()(x)
x = Dropout(0.5)(x)
x = Dense(1000, activation='relu')(x)
x = BatchNormalization()(x)
x = Dropout(0.5)(x)
x = Dense(14, activation='linear')(x)
model = Model(inputs=input, outputs=x)
model.compile(loss='mse', optimizer='adam', metrics=['mae'])
Теперь, когда я натренировал эту модель на предыдущем наборе данных, я хотел бы отключить слой входного тензора и добавить в модель новый входной тензор с формой, которая соответствует размерам изображения последнего набора данных.
model = load_model('path/to/my/trained/model.h5')
old_input = model.pop(0)
new_input = Input(shape=(540, 960, 3), name='image_input')
x = model(new_input)
m = Model(inputs=new_input, outputs=x)
m.save('transfer_model.h5')
что приводит к этой ошибке:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/aicg2/.local/lib/python2.7/site-packages/keras/engine/topology.py", line 2506, in save
save_model(self, filepath, overwrite, include_optimizer)
File "/home/aicg2/.local/lib/python2.7/site-packages/keras/models.py", line 106, in save_model
'config': model.get_config()
File "/home/aicg2/.local/lib/python2.7/site-packages/keras/engine/topology.py", line 2322, in get_config
layer_config = layer.get_config()
File "/home/aicg2/.local/lib/python2.7/site-packages/keras/engine/topology.py", line 2370, in get_config
new_node_index = node_conversion_map[node_key]
KeyError: u'image_input_ib-0'
В сообщении, которое я связал, maz утверждает, что существует несоответствие размеров, которое не позволяет изменить входной слой модели - если это так, то как мне поместить (480, 720, 3) входной слой перед модели VGG16, которая ожидает (224, 224, 3) изображения?
Я думаю, что более вероятная проблема заключается в том, что результаты моей бывшей модели ожидают чего-то другого, чем то, что я даю, основываясь на том, что fchollet говорит в этом посте . Я синтаксически запутался, но я полагаю, что весь x = Layer()(x)
сегмент строит слой слой за куском из input-> output, и просто выбрасывая другой вход вперед, это ломает его.
Я действительно понятия не имею, хотя ...
Может кто-нибудь объяснить мне, как выполнить то, что я пытаюсь сделать, или, если это невозможно, объяснить, почему нет?
Ответы:
Вы можете сделать это, создав новый экземпляр модели VGG16 с новой формой ввода
new_shape
и скопировав все веса слоев. Код примерноисточник
Traceback (most recent call last): File "predict_video11.py", line 67, in <module> new_layer.set_weights(layer.get_weights()) File "/usr/local/lib/python2.7/dist-packages/keras/engine/base_layer.py", line 1057, in set_weights 'provided weight shape ' + str(w.shape)) ValueError: Layer weight shape (3, 3, 33, 64) not compatible with provided weight shape (3, 3, 9, 64)
и что такое входной слой, так что используйте[2:]
?Ширина и высота вывода выходных размеров VGGnet являются фиксированной частью ширины и высоты ввода, поскольку единственными слоями, которые изменяют эти размеры, являются слои пула. Количество каналов на выходе фиксируется количеством фильтров в последнем сверточном слое. Сглаженный слой изменит это, чтобы получить одно измерение с формой:
((input_width * x) * (input_height * x) * channels)
где х - десятичное число <1.
Суть в том, что форма входных данных для плотных слоев зависит от ширины и высоты входных данных для всей модели. Ввод формы в плотный слой не может измениться, поскольку это будет означать добавление или удаление узлов из нейронной сети.
Один из способов избежать этого - использовать глобальный слой пула, а не плоский слой (обычно GlobalAveragePooling2D), в котором будет найдено среднее значение для каждого канала, в результате чего форма входа в плотные слои будет просто такой,
(channels,)
которая не зависит от формы входа для вся модель.Как только это будет сделано, ни один из слоев в сети не будет зависеть от ширины и высоты входных данных, поэтому входной слой можно изменить с помощью чего-то вроде
источник
model.layers[0] = input_layer
не работает для меня в TF 2.1. Там нет ошибки, но слой на самом деле не заменен. Похоже, что копирование весов может быть более надежным (см. Другие ответы).Вот еще одно решение, не характерное для модели VGG.
Обратите внимание, что веса плотного слоя не могут быть скопированы (и, следовательно, будут заново инициализированы). Это имеет смысл, потому что форма весов отличается в старой и новой модели.
источник
Это должно быть довольно легко
kerassurgeon
. Сначала вам нужно установить библиотеку; в зависимости от того, используете ли вы Keras через TensorFlow (с tf 2.0 и выше) или Keras как отдельную библиотеку, его необходимо устанавливать по-разному.Для Keras в TF:
pip install tfkerassurgeon
( https://github.com/Raukk/tf-keras-surgeon ). Для автономного Keras:pip install kerassurgeon
( https://github.com/BenWhetton/keras-surgeon )Чтобы заменить ввод (например, TF 2.0; текущий непроверенный код):
источник
Ответ @gebbissimo работал для меня в TF2 с небольшими изменениями, которые я разделяю ниже в одной функции:
источник
Вот как я изменяю размер ввода в модели Keras. У меня есть две модели CNN, одна с размером входного сигнала [None, None, 3], а другая с размером входного сигнала [512,512,3]. Обе модели имеют одинаковый вес. Используя set_weights (model.get_weights ()), веса модели 1 можно перенести в модель 2
источник