Я пытаюсь обучить классификатор на основе архитектуры InceptionV3 в Керасе. Для этого я загрузил предварительно обученную модель InceptionV3 без вершины и добавил последний полностью связанный слой для классов моей задачи классификации. В первом обучении я заморозил базовую модель InceptionV3 и обучил только последний полностью связанный слой.
На втором этапе я хочу точно настроить сеть, разморозив часть модели InceptionV3. Теперь я знаю, что модель InceptionV3 широко использует слои BatchNorm. Рекомендуется (ссылка на документацию), когда слои BatchNorm размораживаются для точной настройки при передаче обучения, чтобы сохранить фиксированными среднее значение и отклонения, вычисленные слоями BatchNorm. Это должно быть сделано путем установки слоев BatchNorm в режим вывода вместо режима обучения. См. Также: В чем разница между аргументом обучения в call () и атрибутом обучаемого?
Теперь мой главный вопрос: как установить ТОЛЬКО слои BatchNorm модели InceptionV3 в режим вывода?
В настоящее время я установил всю базовую модель InceptionV3 в режим вывода, установив аргумент обучения при сборке сети:
inputs = keras.Input(shape=input_shape)
# Scale the 0-255 RGB values to 0.0-1.0 RGB values
x = layers.experimental.preprocessing.Rescaling(1./255)(inputs)
# Set include_top to False so that the final fully connected (with pre-loaded weights) layer is not included.
# We will add our own fully connected layer for our own set of classes to the network.
base_model = keras.applications.InceptionV3(input_shape=input_shape, weights='imagenet', include_top=False)
x = base_model(x, training=False)
# Classification block
x = layers.GlobalAveragePooling2D(name='avg_pool')(x)
x = layers.Dense(num_classes, activation='softmax', name='predictions')(x)
model = keras.Model(inputs=inputs, outputs=x)
Что мне не нравится в этом, так это то, что таким образом я установил всю модель в режим вывода, который может установить некоторые слои в режим вывода, которого не должно быть.
Вот часть кода, которая загружает веса из начального обучения, которое я сделал, и код, который замораживает первые 150 слоев и размораживает остальные слои части InceptionV3:
model.load_weights(load_model_weight_file_name)
for layer in base_model.layers[: 150]:
layer.trainable = False
for layer in base_model.layers[ 150:]:
layer.trainable = True
Остальная часть моего кода (здесь не показана) представляет собой обычные вызовы компиляции и подгонки.
Выполнение этого кода, похоже, приводит к тому, что сеть на самом деле не обучается (потери и точность остаются примерно такими же). Я пробовал разные порядки величины шага оптимизации, но, похоже, это не помогает.
Еще я заметил, что когда я делаю всю часть InceptionV3 обучаемой
base_model.trainable = True
что обучение начинается с серверной точностью на порядки меньшей, чем была завершена моя первая тренировка (и, конечно, с гораздо более высокими потерями). Может кто-то объяснить это мне? Я бы по крайней мере ожидал, что тренировка продолжится, если бы она была прервана с точки зрения точности и потерь.