Сохранение/Загрузка модели Keras с lambda слоями
Изучая Keras, столкнулся с примером, где используется предварительно обученная на ImageNet модель VGG16.
conv_base = keras.applications.vgg16.VGG16(
weights="imagenet",
include_top=False
)
conv_base.trainable = False
data_augmentation = keras.Sequential(
[
layers.RandomFlip("horizontal"),
layers.RandomRotation(0.1),
layers.RandomZoom(0.2)
]
)
inputs = keras.Input(batch_size=32, shape=(180, 180, 3))
x = data_augmentation(inputs)
x = keras.applications.vgg16.preprocess_input(x)
x = conv_base(x)
x = layers.Flatten()(x)
x = layers.Dense(256)(x)
x = layers.Dropout(0.5)(x)
outputs = layers.Dense(1, activation="sigmoid")(x)
model = keras.Model(inputs, outputs)
model.compile(
loss="binary_crossentropy",
optimizer=keras.optimizers.RMSprop(learning_rate=1e-5),
metrics=["accuracy"]
)
Далее мы задаем обратный вызов для сохранения лучшего результата и обучаем.
callbacks = [
keras.callbacks.ModelCheckpoint(
filepath="fine_tuning.keras",
save_best_only=True,
monitor="val_loss"
)
]
history = model.fit(
train_dataset,
epochs=50,
validation_data=validation_dataset,
callbacks=callbacks
)
Ошибка возникает на этапе сохранения.
TypeError: Cannot serialize object Ellipsis of type <class 'ellipsis'>. To be serializable, a class must implement the `get_config()` method.
Проблема кроется в слое keras.applications.vgg16.preprocess_input(x). Я нашёл информацию, что имеет смысл использовать lambda-слой. Поэтому сделал вот так и обучение/сохранение проходят успешно:
x = layers.Lambda(lambda x: keras.applications.vgg16.preprocess_input(x))(x)
Но в этом случае я получаю ошибку при загрузке:
test_model = keras.models.load_model("fine_tuning.keras")
ValueError: The `{arg_name}` of this `Lambda` layer is a Python lambda. Deserializing it is unsafe. If you trust the source of the config artifact, you can override this error by passing `safe_mode=False` to `from_config()`, or calling `keras.config.enable_unsafe_deserialization().
Далее, я попробовал добавить safe_mode=False, но получаю это:
test_model = keras.models.load_model("fine_tuning.keras", safe_mode=False)
NotImplementedError: Exception encountered when calling Lambda.call().
We could not automatically infer the shape of the Lambda's output. Please specify the `output_shape` argument for this Lambda layer.
Arguments received by Lambda.call():
• args=('<KerasTensor shape=(32, 180, 180, 3), dtype=float32, sparse=False, name=keras_tensor_123>',)
• kwargs={'mask': 'None'}
Я пробовал задать Lambda-слою форму выходных данных, но либо я это делаю не правильно, либо не работает в принципе и получаю всё ту же ошибку.
Мучаюсь с этим второй день, очень хочется разобраться, что не так и как вообще сохранять/загружать модели с подобными слоями.
Я знаю, что в старой версии Keras это работало, но хочется использовать и изучать новую.