В этом посте я хотел бы показать, как использовать предварительно обученную современную модель для классификации изображений для классификации пользовательских данных. Я покажу, как применить трансферное обучение в Keras с помощью модели Effectivenet от Google для классификации изображений автомобилей из стэнфордского набора данных об автомобилях. Полный блокнот jupyter можно найти в моем репозитории github.

Эффективная сеть

Начиная с изначально простой сверточной нейронной сети (CNN), точность и эффективность модели обычно можно повышать шаг за шагом путем произвольного масштабирования таких параметров сети, как ширина, глубина и разрешение. Увеличение количества используемых слоев или использование изображений с более высоким разрешением для обучения моделей обычно требует больших ручных усилий. Исследователи из Google AI выпустили EfficientNet, подход к масштабированию, основанный на фиксированном наборе коэффициентов масштабирования и достижениях в AutoML и других методах (например, свертка с разделением по глубине, активация взмахом, удаление соединения). Вместо независимой оптимизации отдельных измерений сети, как это было раньше, EfficientNet теперь ищет сбалансированный процесс масштабирования по всем измерениям сети.

С EfficientNet количество параметров уменьшается на величину, в то же время достигая самых современных результатов на ImageNet, эталоне для таких приложений.

Трансферное обучение

В то время как EfficientNet уменьшает количество параметров, обучение сверточных сетей по-прежнему требует много времени. Чтобы еще больше сократить время обучения, мы можем использовать методы трансферного обучения.

Перенос обучения означает, что мы используем предварительно обученную модель и точно настраиваем модель на новых данных. При классификации изображений мы можем думать о разделении модели на две части. Одна часть модели отвечает за извлечение ключевых характеристик из изображений, таких как края, общие шаблоны и т. д., а другая часть использует эти функции для фактической классификации.

Обычно CNN строится из сложенных сверточных блоков, уменьшающих размер изображения при одновременном увеличении количества обучаемых функций (фильтров), и в конце все объединяется в полностью связанный слой, который выполняет классификацию. Идея трансферного обучения состоит в том, чтобы сделать первую часть переносимой, чтобы ее можно было использовать для разных задач, заменив только полностью связанный слой (часто называемый просто «верхним»).

Выполнение

Эта реализация keras Efficientnet (pip install efficiencynet) поставляется с предварительно обученными моделями для всех размеров (B0-B7), где мы можем просто добавить наш пользовательский слой классификации сверху. С weights='imagenet' мы получаем предварительно обученную модель. Этот фрагмент примерно показывает, как это работает (полный пример см. в Jupyter Notebook):

base_model = EfficientNetB5(include_top=False, weights='imagenet')
x = base_model.output
x = GlobalAveragePooling2D()(x)
predictions = Dense(num_classes, activation='softmax')(x)
model = Model(inputs=base_model.input, outputs=predictions)
# fix the feature extraction part of the model
for layer in base_model.layers:
    layer.trainable = False
model.summary()
--------
Total params: 28,615,970
Trainable params: 102,450
Non-trainable params: 28,513,520

У нас всего 100 тысяч обучаемых параметров, а у полной сети 28 миллионов. С этим сокращенным набором бесплатных параметров мы можем обучить последний слой на наших пользовательских данных, в то время как слои извлечения признаков используют веса из imageNet.

После обучения модели мы можем увидеть такой результат:

Странность пакетной нормализации

Это странное поведение происходит из слоя BatchNormalization. Похоже, есть баг при использовании keras (2.2.4) и tensorflow 1.x. Проблема, по-видимому, в том, что слой нормализации замороженных пакетов также замораживает параметры нормализации. (Подробнее о различных слоях нормализации читайте здесь). Чтобы исправить это, мы можем сделать слой BatchNormalization обучаемым:

for layer in base_model.layers:
    if isinstance(layer, BatchNormalization):
        layer.trainable = True
    else:
        layer.trainable = False

К сожалению, мы теряем возможность использовать больший размер batch_size, кажется, что keras требуется больше памяти для модели, когда мы делаем BatchNormaliation обучаемым.

В качестве альтернативы, мы могли бы игнорировать странные оценки сверху, потому что наш слой все еще учится, как мы можем видеть в потерях / точности обучения, а позже мы все равно обучаем всю сеть с помощью обучаемой пакетной нормализации. Однако вот оценки модели, когда BN обучаем:

У нас все еще есть преимущества при обучении только последних слоев. Например, у нас меньше обучаемых параметров, что означает более быстрое время вычислений. Для больших наборов данных я бы предпочел проигнорировать оценки проверки и воспользоваться преимуществами большего размера пакета, полностью заморозив базовую модель, включая BN.

Высвободите всю мощь сети

В какой-то момент обучения модель больше не улучшается, и пришло время открыть остальную часть сети для точной настройки части извлечения признаков. Поэтому мы делаем все слои обучаемыми и снова подгоняем модель. Теперь у нас есть более 28 миллионов параметров, и обучение занимает гораздо больше времени, но, поскольку мы уже обучили последний слой, у нас гораздо лучшая отправная точка.

for layer in model.layers:
    layer.trainable = True
model.summary()
--------
Total params: 28,615,970
Trainable params: 28,443,234
Non-trainable params: 172,736

Предостережение: важно избегать ранней переобучения модели, потому что модели может быть трудно выйти за локальные минимумы, поэтому мы обязательно открываем сеть лучше раньше, чем позже для полного обучения. Также не забудьте настроить batch_size, иначе запустим OOM. Чтобы получить оценку памяти, требуемой моделью, посмотрите здесь (stackoverflow). Я также предлагаю использовать раннюю остановку.

После вызова fit() во второй раз мы получаем еще лучшую модель:

Наконец, мы обучили современную модель эффективной сети на пользовательских данных. Чтобы подготовить эту модель к производству, предстоит еще некоторая работа. Если вам интересно, как развернуть такую ​​модель, вы можете прочитать эту статью.

Этот пост был впервые опубликован в моем личном блоге здесь.