Keras заменяет входной слой
Код, который у меня есть (который я не могу изменить), использует Resnet с my_input_tensor
в качестве input_tensor.
model1 = keras.applications.resnet50.ResNet50(input_tensor=my_input_tensor, weights='imagenet')
Исследуя исходный код, функция ResNet50 создает новый входной слой keras с my_input_tensor
, а затем создает остальную часть модели. Это поведение, которое я хочу скопировать с моей собственной моделью. Я загружаю свою модель из файла h5.
model2 = keras.models.load_model('my_model.h5')
Поскольку в этой модели уже есть входной слой, я хочу заменить его новым входным слоем, определенным с помощью my_input_tensor
.
Как я могу заменить входной слой?
Ответы
Ответ 1
Когда вы сохранили свою модель, используя:
old_model.save('my_model.h5')
он сохранит следующее:
- Архитектура модели, позволяющая создать модель.
- Вес модели.
- Конфигурация обучения модели (потеря, оптимизатор).
- Состояние оптимизатора, позволяющее возобновить обучение с того места, где вы раньше.
Итак, когда вы загружаете модель:
res50_model = load_model('my_model.h5')
вы должны вернуть ту же модель, вы можете проверить то же самое:
res50_model.summary()
res50_model.get_weights()
Теперь вы можете добавить слой ввода и добавить свой собственный:
res50_model.layers.pop(0)
res50_model.summary()
добавить новый уровень ввода:
newInput = Input(batch_shape=(0,299,299,3)) # let us say this new InputLayer
newOutputs = res50_model(newInput)
newModel = Model(newInput, newOutputs)
newModel.summary()
res50_model.summary()
Ответ 2
Решение от @MilindDeore у меня не сработало, к сожалению. Несмотря на то, что я могу напечатать сводку по новой модели, я получаю сообщение об ошибке "Размер матрицы несовместим" при прогнозировании. Я думаю, это имеет смысл, поскольку новая входная форма плотного слоя не соответствует форме весов старого плотного слоя.
Итак, вот еще одно решение. Ключом для меня было использование "_layers" вместо "layer". Последний, кажется, только возвращает копию.
import keras
import numpy as np
def get_model():
old_input_shape = (20, 20, 3)
model = keras.models.Sequential()
model.add(keras.layers.Conv2D(9, (3, 3), padding="same", input_shape=old_input_shape))
model.add(keras.layers.MaxPooling2D((2, 2)))
model.add(keras.layers.Flatten())
model.add(keras.layers.Dense(1, activation="sigmoid"))
model.compile(loss='binary_crossentropy', optimizer=keras.optimizers.Adam(lr=0.0001), metrics=['acc'], )
model.summary()
return model
def change_model(model, new_input_shape=(None, 40, 40, 3)):
# replace input shape of first layer
model._layers[1].batch_input_shape = new_input_shape
# feel free to modify additional parameters of other layers, for example...
model._layers[2].pool_size = (8, 8)
model._layers[2].strides = (8, 8)
# rebuild model architecture by exporting and importing via json
new_model = keras.models.model_from_json(model.to_json())
new_model.summary()
# copy weights from old model to new one
for layer in new_model.layers:
try:
layer.set_weights(model.get_layer(name=layer.name).get_weights())
except:
print("Could not transfer weights for layer {}".format(layer.name))
# test new model on a random input image
X = np.random.rand(10, 40, 40, 3)
y_pred = new_model.predict(X)
print(y_pred)
return new_model
if __name__ == '__main__':
model = get_model()
new_model = change_model(model)
Ответ 3
Layers.pop(0) или что-то подобное не работает.
У вас есть два варианта, которые вы можете попробовать:
1.
Вы можете создать новую модель с необходимыми слоями.
Относительно простой способ сделать это - i) извлечь конфигурацию json модели, ii) изменить ее соответствующим образом, iii) создать из нее новую модель, а затем iv) скопировать весовые коэффициенты. Я просто покажу основную идею.
я) извлечь конфигурацию
model_config = model.get_config()
ii) изменить конфигурацию
input_layer_name = model_config['layers'][0]['name']
model_config['layers'][0] = {
'name': 'new_input',
'class_name': 'InputLayer',
'config': {
'batch_input_shape': (None, 300, 300),
'dtype': 'float32',
'sparse': False,
'name': 'new_input'
},
'inbound_nodes': []
}
model_config['layers'][1]['inbound_nodes'] = [[['new_input', 0, 0, {}]]]
model_config['input_layers'] = [['new_input', 0, 0]]
ii) создать новую модель
new_model = model.__class__.from_config(model_config, custom_objects={}) # change custom objects if necessary
ii) копирование весов
# iterate over all the layers that we want to get weights from
weights = [layer.get_weights() for layer in model.layers[1:]]
for layer, weight in zip(new_model.layers[1:], weights):
layer.set_weights(weight)
2.
Вы можете попробовать библиотеку вроде kerassurgeon (я ссылаюсь на форк, который работает с версией tenorflow keras). Обратите внимание, что операции вставки и удаления работают только при определенных условиях, таких как совместимые размеры.
from kerassurgeon.operations import delete_layer, insert_layer
model = delete_layer(model, layer_1)
# insert new_layer_1 before layer_2 in a model
model = insert_layer(model, layer_2, new_layer_3)