В Части 1 я описал, как спроектировать пользовательскую сеть в tfjs. Теперь пришло время подготовить его к производству.
Во-первых, давайте взглянем на топологию ResNet и попытаемся понять, что делать и как действовать дальше.
Это примеры архитектуры ResNet. Если вы понимаете эту картинку и имеете четкое видение, как ее реализовать, то вы профи в ОД, в этой статье я не смогу вам рассказать то, чего вы не знаете и можете не читать здесь :)
Если вы все еще читаете, вы можете спросить, где остаточные связи? В ответ на это у меня есть еще одна фотография ResNet-18.
Вы можете заметить здесь те же числа, что и в столбце «18 слоев» в предыдущей таблице. Более того, здесь мы видим стрелки с правой стороны, обозначающие остаточную связь. В конце статьи я покажу, как это выглядит в коде.
Здесь вы видите загадочные символы, такие как 64, /2 — сначала я не понял, что это значит. Также мне было любопытно, как здесь происходит субдискретизация, когда я начал с машинного обучения в 2016 году, мы использовали для этого MaxPool и AvgPool, как здесь:
Ответ на оба вопроса был следующим: вместо пула предлагается использовать stride=2 в первом слое каждого остаточного блока, и именно это /2 означает. Круто, да?
Хорошо, теперь мы знаем, какие сверточные слои нам нужны. Но этого недостаточно для готовой к производству модели. Вы, наверное, уже слышали о таких методах, как пакетная нормализация, отсев и ReLU. И есть картинка, отвечающая на вопрос, какие их комбинации вы, возможно, захотите использовать в остаточной сети, вот так:
Обратите внимание, что вы сначала применяете ReLU и только потом суммируете матрицы. В противном случае результатом ReLU будет матрица из единиц :)
Только представьте, [1,1,1,1,1,1,1…] и ваша модель постоянно дает точность 50%. Стабильная это хорошо, а тут как бы русская стабильная, так что наверное не хочется. Вот почему, еще раз, правило состоит в том, что ReLU сначала, а остаточное соединение после него.
И вот мы собрали все вместе в коде: