Эксперименты с разными архитектурами - VGG16, Resnet50 и InceptionV3 - для улучшения вашей модели (с использованием TensorFlow и Keras)

Распространенный сценарий TL использует ConvNet, обученную на большом наборе данных, для классификации домена с похожим, но меньшим набором данных (хорошее резюме других сценариев можно найти здесь). Приемлемым подходом в этом сценарии будет либо использование ConvNet в качестве экстрактора фиксированных функций, либо точная настройка ConvNet. На практике это не случай либо-либо, а спектр, который может отличаться от наиболее строгого метода plug-and-play, когда только последний слой FC удаляется из ConvNet (вверху) и заменяется линейным классификатор, который соответствует новой задаче - к некоторым более свободным методам, в которых мы обучаем некоторые из слоев ConvNet или замораживаем их, или любую другую их комбинацию.

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

  1. Какой ConvNet мне выбрать - как подобрать архитектуру для моей конкретной задачи? В большинстве случаев кажется, что архитектура выбирается произвольно из доступных вариантов фреймворка.
  2. что такое маленький и что аналогичный - это относительные термины. По сравнению с ImageNet мой набор данных, вероятно, всегда будет небольшим, или, может быть, маленький связан с размером архитектуры, которую я выберу? То же самое и с подобием: ImageNet имеет тысячу категорий, если я хочу классифицировать только людей, насколько похожи эти домены?

Если вы хотите перейти непосредственно к документации по коду и экспериментам, они находятся здесь.

Задача под рукой

В одном из моих предыдущих проектов я использовал простую модель CNN для классификации двоичных изображений. Задача заключалась в классификации двух конкретных человеческих лиц, и, следовательно, набор данных был небольшим (~ 1350 изображений). Результаты были хорошими, но не отличными, точность ~ 0,9. У меня нет возможности улучшить его, расширив набор данных, поскольку он был построен на ограниченных ресурсах информации. Я постараюсь ответить на вопросы выше, используя этот тестовый пример. Используя три предварительно обученных ConvNet - VGG16, ResNet50 и InceptionV3 - давайте рассмотрим случай и установим некоторые основные практические правила при реализации Transfer Learning.

VGG16 - Эпоха невинности

VGG16 - это, по сути, набор слоев Conv, наложенных друг на друга, что больше всего похоже на мою простую CNN. Давайте сначала попробуем самый простой подход: мы будем использовать его как есть, со всеми предварительно обученными весами ImageNet, заморозив все слои, удалив последний слой FC (ImageNet имеет классификатор на 1000 категорий) и заменяет его двоичным классификатором.

Я предполагаю, что, поскольку моя область - изображения человеческих лиц - очень похожа на область ImageNet - изображения всех видов объектов - для моей задачи актуальны даже функции самого высокого уровня. Но, увы, мы видим некоторое совпадение потерь, но этого недостаточно для того, чтобы точность была значимой. Это почему? Прежде чем мы попытаемся ответить на этот вопрос, давайте проведем еще один эксперимент. На этот раз мы переобучаем всю сеть, без предварительно натренированных весов.

И все же в какой-то момент потери стабилизируются, а точность остается неизменной. Хорошо, теперь давайте попробуем понять, почему. Возможные причины, о которых я могу думать:

  1. Набор данных слишком мал
  2. Набор данных не похож на ImageNet
  3. Архитектура не подходит.

Я не думаю, что мои данные слишком малы (1), поскольку в этой архитектуре не намного больше обучаемых параметров, чем в моем простом CNN. Возможно, область данных не похожа (2), по крайней мере, на верхних уровнях, это необходимо протестировать. А может дело в архитектуре (3). Он похож на мой, но в нем гораздо больше слоев Conv, что может привести к другим проблемам.

попробуем определиться с объяснением (2). Я заморозю некоторые из нижних слоев, пытаясь сохранить низкоуровневые функции, и обучу верхние слои, пытаясь подогнать их под свои данные.

Давайте заморозим первые шесть слоев (первые две стопки) и потренируем остальные. Обратите внимание, что способ точной настройки - это обучить только верхнюю часть, а затем разморозить необходимые слои и повторно обучить.

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

Итак, дело не в размере (1), не в сходстве (2), а в архитектуре (3). Я до сих пор не могу объяснить почему, но могу попытаться это доказать. Давайте попробуем еще один и сравним результаты.

ResNet50 - Остаточная стоимость

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

наконец-то какой-то прогресс. Точность обучения составляет ~ 0,97, и похоже, что модель наконец-то чему-то научилась. Точность проверки плоская 0,5

Кажется, что, поскольку я тренирую только верхнюю часть тела, я, вероятно, слишком хорошо приспособлен к своему тренировочному набору. Давайте продолжим и разморозим все слои, как мы делали с VGG, и посмотрим, поможет ли это.

Я реинициализирую модель и на этот раз ничего не замораживаю.

Что здесь случилось? В какой-то момент после ~ 21 эпохи потеря валидации упала, а точность подскочила до 0,91, что примерно соответствует результатам, которые я получил с моим простым CNN, но намного лучше, чем VGG. Еще один важный момент, который следует отметить, заключается в том, что, хотя сеть полностью переобучена, начальные веса являются весами «ImageNet», а не случайными. это имеет значение, и, вероятно, это то, что дало модели импульс.

После всех этих экспериментов я хочу отметить следующее:

Выбор правильной архитектуры - важная часть использования трансферного обучения.

Сейчас я не согласен с моей исходной моделью CNN, но в чем преимущество трансферного обучения? можно выжать больше сока из ResNet или попробовать другую архитектуру? Я бы попробовал заморозить только части модели и даже удалить верхний слой, но не слишком далеко. Думаю, я перейду к архитектуре Inception и посмотрю, пойдет ли все гладко

InceptionV3 - Разделяй и властвуй

Начало - это очередная эволюция классификаторов CNN. Здесь я буду использовать V3, это не последняя версия, но она все еще очень развита.

Я быстро провел два эксперимента, как и с двумя предыдущими архитектурами - заморозить все слои и освободить все слои - в обоих я получил ~ 0,7 на проверочном наборе, что очень похоже на результаты ResNet, но тенденция все еще не выглядит хорошей.

Я хочу попробовать что-то новое: Inception - очень большая сеть, давайте попробуем удалить часть слоев и использовать только часть сети - в частности, я удалю верхние стеки слоев Conv и обучу нижние слои.

Мотивация к настоящему времени ясна - использование более низких функций сети и точная настройка на мою проблему. Я должен сказать, что это была игра методом проб и ошибок, но с некоторой логикой. Если вы посмотрите на начальную архитектуру слева, вы увидите, что она построена из объединенных блоков. Поэтому имеет смысл «разрезать» сеть в одной из этих точек и вставить классификатор. даже кажется, что он был создан для этого. Понимание этого делает игру методом проб и ошибок намного проще. Итак, что я собираюсь сделать, так это найти лучший блок, из которого я разделю сеть, и попытаюсь настроить его с этой точки.

После некоторых испытаний я обнаружил, что при использовании «mixed_5» - это имя объединенных слоев, вы можете увидеть это при использовании model.summary () метод - дает наилучшие результаты. Еще несколько оптимизаций параметров, и я получил точность валидации до ~ 0,97.

Это большое улучшение, кажется, что архитектура Inception лучше всего подходит для моей задачи до сих пор или, может быть, это просто самая развитая из тех, что я использовал до сих пор, я пока не могу исключить такой вывод. Прежде чем я подведу итоги, давайте попробуем еще одну настройку: лучшая эпоха последнего эксперимента была на 11-м месте из 50. После этого валидация медленно снижалась, что свидетельствует о чрезмерной подгонке. Предполагая, что мы попробовали настроить все параметры, давайте попробуем разморозить некоторые слои. Мы пробовали это с ResNet, и это не сработало, возможно, архитектура Inception будет более терпимой. Я разморозю все слои от «смешанного_4» до «смешанного_5», что означает один объединенный стек. это позволит верхним слоям новой модели тренироваться на новых данных и, надеюсь, повысит точность.

Точность проверки наивысшая на данный момент ~ 0,98.

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

Давайте подумаем, что можно улучшить в следующем проекте. Что можно вычесть?

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

Поделитесь своими мыслями, код и документация здесь. Следите за мной в Medium или Twitter, чтобы следить за обновлениями моих сообщений в блоге!