Трансферное обучение работает только с обучаемым, установленным на false

У меня есть две модели, инициализированные так

vgg19 = keras.applications.vgg19.VGG19(
  weights='imagenet',
  include_top=False,
  input_shape=(img_height, img_width, img_channels))

for layer in vgg19.layers:
  layer.trainable = False

model = Sequential(layers=vgg19.layers)
model.add(Flatten())
model.add(Dense(1024, activation='relu'))
model.add(Dense(512, activation='relu'))
model.add(Dense(10, activation='softmax'))

opt = Adam(learning_rate=0.001, beta_1=0.9)
model.compile(
    loss='categorical_crossentropy',
    optimizer=opt,
    metrics=['accuracy'])

а также

vgg19_2 = keras.applications.vgg19.VGG19(
    weights='imagenet',
    include_top=False,
    input_shape=(img_height, img_width, img_channels))

model2 = Sequential(layers=vgg19_2.layers)
model2.add(Dense(1024, activation='relu'))
model2.add(Dense(512, activation='relu'))
model2.add(Dense(10, activation='softmax'))

opt = Adam(learning_rate=0.001, beta_1=0.9)
model2.compile(
    loss='categorical_crossentropy',
    optimizer=opt,
    metrics=['accuracy'])

Другими словами, единственное отличие состоит в том, что вторая модель не устанавливает для обучаемого параметра слоев vgg19 значение false. К сожалению, модель с обучаемым значением true не изучает данные.

Когда я использую model.fit, я получаю

Trainable set to false:
Epoch 1/51
2500/2500 [==============================] - 49s 20ms/step - loss: 1.4319 - accuracy: 0.5466 - val_loss: 1.3951 - val_accuracy: 0.5693
Epoch 2/51
2500/2500 [==============================] - 47s 19ms/step - loss: 1.1508 - accuracy: 0.6009 - val_loss: 0.7832 - val_accuracy: 0.6023
Epoch 3/51
2500/2500 [==============================] - 48s 19ms/step - loss: 1.0816 - accuracy: 0.6256 - val_loss: 0.6782 - val_accuracy: 0.6153
Epoch 4/51
2500/2500 [==============================] - 47s 19ms/step - loss: 1.0396 - accuracy: 0.6450 - val_loss: 1.3045 - val_accuracy: 0.6103

Модель обучается с точностью около 65% в течение нескольких эпох. Однако, используя модель2, которая должна иметь возможность делать еще лучшие прогнозы (поскольку есть больше обучаемых параметров), я получаю:

Epoch 1/5
2500/2500 [==============================] - 226s 90ms/step - loss: 2.3028 - accuracy: 0.0980 - val_loss: 2.3038 - val_accuracy: 0.1008
Epoch 2/5
2500/2500 [==============================] - 311s 124ms/step - loss: 2.3029 - accuracy: 0.0980 - val_loss: 2.2988 - val_accuracy: 0.1017
Epoch 3/5
2500/2500 [==============================] - 306s 123ms/step - loss: 2.3029 - accuracy: 0.0980 - val_loss: 2.3052 - val_accuracy: 0.0997
Epoch 4/5
2500/2500 [==============================] - 321s 129ms/step - loss: 2.3029 - accuracy: 0.0972 - val_loss: 2.3028 - val_accuracy: 0.0997
Epoch 5/5
2500/2500 [==============================] - 300s 120ms/step - loss: 2.3028 - accuracy: 0.0988 - val_loss: 2.3027 - val_accuracy: 0.1007

Когда я затем пытаюсь вычислить градиенты весов в своих данных, я получаю только нули. Я понимаю, что обучение такой большой нейронной сети, как vgg, может занять много времени, но, учитывая, что расчетные градиенты для последних 3 слоев должны быть очень похожими в обоих случаях, почему точность такая низкая? Тренировка в течение большего количества времени не дает улучшения.


person YuseqYaseq    schedule 18.04.2020    source источник
comment
Возможно, вам нужна гораздо меньшая скорость обучения для предварительно обученных слоев и более высокая скорость для добавленных слоев. Похоже, здесь есть пакет для этого: pypi.org/project/keras-lr-multiplier   -  person chase    schedule 18.04.2020


Ответы (1)


Попробуй это:

  1. Обучите первую модель, которая устанавливает trainable в False. Вам не нужно тренировать его до насыщения, поэтому я бы начал с ваших 5 эпох.
  2. Вернитесь назад и установите trainable на True для всех vgg19 параметров. Затем, согласно документации, вы может перестроить и перекомпилировать модель, чтобы эти изменения вступили в силу.
  3. Продолжите обучение на перестроенной модели, которая теперь имеет все параметры, доступные для настройки.

В трансферном обучении очень часто полностью замораживают переданные слои, чтобы сохранить их. На ранних этапах обучения ваши дополнительные слои не знают, что делать. Это означает зашумленный градиент к тому времени, когда он доберется до переданных слоев, что быстро «расстроит» их от их ранее хорошо настроенных весов.

Объединив все это в некоторый код, это будет выглядеть примерно так.

# Original code. Transfer VGG and freeze the weights.
vgg19 = keras.applications.vgg19.VGG19(
  weights='imagenet',
  include_top=False,
  input_shape=(img_height, img_width, img_channels))

for layer in vgg19.layers:
  layer.trainable = False

model = Sequential(layers=vgg19.layers)
model.add(Flatten())
model.add(Dense(1024, activation='relu'))
model.add(Dense(512, activation='relu'))
model.add(Dense(10, activation='softmax'))

opt = Adam(learning_rate=0.001, beta_1=0.9)
model.compile(
    loss='categorical_crossentropy',
    optimizer=opt,
    metrics=['accuracy'])

model.fit()

# New second stage: unfreeze and continue training.
for layer in vgg19.layers:
  layer.trainable = True

full_model = Sequential(layers=model.layers)
full_model.compile(
    loss='categorical_crossentropy',
    optimizer=opt,
    metrics=['accuracy'])

full_model.fit()

Вы можете настроить скорость обучения на этапе тонкой настройки. Начинать не обязательно, просто нужно иметь в виду.


Третий вариант – использовать дифференцированные скорости обучения, как это было представлено Джереми Ховардом и Себастьяном Рудером в документе ULMFiT. . Идея состоит в том, что в трансферном обучении вы обычно хотите, чтобы более поздние слои обучались быстрее, чем более ранние, переданные слои. Таким образом, вы фактически устанавливаете разные скорости обучения для разных наборов слоев. В библиотеке fastai есть реализация PyTorch, которая работает путем разделения модели на «группы слоев» и разрешая разные параметры для каждой.

person mcskinner    schedule 18.04.2020
comment
Обучение 3 последних слоев со скоростью обучения = 0,001, а затем размораживание и установка lr = 0,00001 устранили проблему. Благодарю вас! - person YuseqYaseq; 19.04.2020