Это руководство поможет вам создать модель ResNet с любой желаемой глубиной / слоем с нуля.

ResNet всегда была одной из моих любимых архитектур, и я много раз использовал ее основную идею пропуска соединения. Сейчас он довольно старый, поскольку оба ResNetV1 (Deep Residual Learning for Image Recognition) и ResNetV2 (Identity Mappings in Deep Residual Networks) появились в 2015 и 2016 годах, но до сих пор его основная концепция широко используется. Итак, вы, должно быть, думаете ... почему этот учебник в 2020 году.

Это руководство вызвано двумя основными причинами:

  1. Создайте ResNetV2 с любой желаемой глубиной, а не только ResNet50, ResNet101 или ResNet152 (как включено в приложение keras)
  2. Использование Tensorflow 2.xx

Это руководство разделено на две части. В первой части кратко обсуждается ResNet, а во второй части основное внимание уделяется кодированию. Имейте в виду, что основная цель этого руководства - продемонстрировать кодирование при построении модели ResNet с любой желаемой глубиной / слоем с нуля.

Часть 1: Краткое описание ResNet

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

Итак, вопрос в том, как ResNet решает проблему?

Я постараюсь выразить это простыми словами. Основная идея ResNet основана на пропуске соединения, то есть позволяет брать активацию с одного уровня и передавать ее на будущий уровень (может быть намного глубже). Рассмотрим проблему исчезающего градиента: когда мы пойдем глубже, некоторые нейроны ничего не внесут, потому что их веса значительно уменьшились. Но теперь, если мы перенесем активацию из более раннего слоя и добавим к текущему слою перед активацией, теперь это, безусловно, внесет свой вклад.

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

Теперь, не теряя времени, перейдем к кодированию.

Часть 2: Кодирование

Примечание: я опубликовал репо, содержащее весь код, и его можно найти здесь.

  1. Во-первых, мы должны создать остаточный блок, который является строительным блоком ResNet. Он используется как соединитель скипа. ResNetV2 внес одну небольшую модификацию, в отличие от сверточного слоя V1, который используется сначала, а затем пакетная нормализация.

Иногда внутри сети сначала не используется сверточный слой, поэтому мы должны использовать цикл if-else.

2. Далее добавляем слои. Мы будем использовать функциональный API Keras для той же цели.

Давайте сделаем это построчно

→ В строке №7 мы принимаем ввод

→ строка №10 используется для создания сверточного слоя перед разделением на два пути. Здесь мы используем тот же остаточный блок, который мы создали ранее.

→ строки 13–55 используются для создания стопки остаточных единиц. Обсудим это подробнее. После строки № 10 сеть делится на две части, и позже добавляются. Теперь в первой части выполняются три операции:

норма партии → активация → Конв.

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

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

Пора углубиться в код… немного… :)

→ строка №13 начинает добавление стеков остаточного блока в цикл for. (Простой способ пропустить нужный слой - это начало цикла в этом диапазоне)

→ строка № 30–44 используется для добавления сверточного слоя в одну из подсетей после выполнения разделения.

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

→ Строка № 45–53: после выполнения разделения вторая подсеть должна быть сверточным слоем, который можно пропустить и добавить позже.

→ строка №54 - это то место, где происходит вся магия :). Здесь мы добавляем обе наши подсети.

3. Последняя часть - подключить полностью подключенный слой поверх сети.

Вы можете настроить эту деталь по своему желанию.

Некоторые ключевые моменты, на которые следует обратить внимание

  1. Я написал комментарий «глубина должна быть 9n + 2», потому что здесь я пропускаю три активации и для соответствия тензорной форме до и после разделения, глубина должна быть выбрана в соответствии с формулой.
  2. Большая часть корректировок выполняется шагами и размером ядра, чтобы соответствовать форме тензора. Я бы посоветовал вам записать одну петлю на бумаге, чтобы увидеть всю настройку и понять ее более тщательно.
  3. Не запутайтесь в пропущенных разъемах или остаточном блоке. Связь между ними следующая: после выполнения разделения создаются два пути. первый путь будет иметь три слоя или три остаточных блока, а второй путь будет иметь один слой или один остаточный блок ( теперь этот блок такой же, как и до раскола). Теперь этот остаточный блок из пути два будет перенесен на путь один и добавлен перед активацией. Таким образом, этот блок перескочил или пропустил три блока и, таким образом, стал соединителем пропуска.

Часть 3: Конечные примечания и некоторые дополнения

Я бы посоветовал вам ознакомиться с моим репозиторием на GitHub ResNet-builder, поскольку он включает гораздо больше API, которые, как я думал, могут выйти за рамки этого блога. Этот блог был ограничен построением сети ResNet. Но для создания полной системы ResNet нам потребуется гораздо больше функций, таких как загрузчик данных, генератор выводов, визуализация производительности модели и т. Д. Я включил все эти API.

Репо также поддерживает множество конфигураций для построения модели.

Я постарался сделать API как можно более интуитивно понятным, хотя, если у вас возникнут затруднения, вы можете связаться со мной через Linkedin.