Перевод “рецепта обучения нейронной сети” (с комментариями и замечаниями) – статьи из блога Andrej Karpathy О хакерском руководстве по нейронным сетям.
Пожалуй, это лучший практический материал по нейронным сетям в 2019 году. Рекомендуем к изучению и практическому использованию!
Несколько недель назад я опубликовал твит о «самых распространенных ошибках при обучении нейронных сетей», перечислив некоторые из них. Твит получил намного больший отклик, чем я ожидал (включая вебинар :)). Очевидно, что многие люди лично сталкивались с большим разрывом между утверждениями «вот как работает сверточная сеть» и «наша сеть достигает выдающихся результатов».
Поэтому я подумал, что было бы забавно отмахнуться от моего пыльного блога, и расширить мой твит до полной формы, которой заслуживает эта тема. При этом я не буду углубляться в перечисление наиболее распространенных ошибок или конкретизировать их. Вместо этого, я хотел бы копнуть немного глубже и поговорить о том, как можно вообще избежать этих ошибок (или исправить их очень быстро).
Рецепт заключается в том, чтобы следовать определенному процессу, который, насколько я могу судить, не очень часто документируется. Но сначала давайте начнем с двух важных наблюдений, которые это подтверждают.
1) Обучение нейронной сети – это уплывающая абстракция
Считается, что обучение нейронной сети легко начать. Многочисленные библиотеки и фреймворки гордятся 30-строчными чудо-фрагментами кода. Они решают ваши проблемы с данными, создавая ложное впечатление, что все это работает как «включи и играй».
>>> your_data = # вставьте свой потрясающий набор данных сюда
>>> model = SuperCrossValidator (SuperDuper.fit , your_data , ResNet50, SGDOptimizer)
# завоевать мир здесь
Эти библиотеки и примеры активируют ту часть нашего мозга, которая знакома со стандартным программированием, где часто используются чистые API и абстракции. Вам приводят библиотеку для демонстрации:
>>> r = reports.get (‘ https://api.github.com/user ‘, auth = (‘user’, ‘pass’))
>>> r.status_code
200
Это круто! Смелый разработчик взял на себя бремя понимания строк запросов, URL-адресов, запросов GET / POST, HTTP-соединений и т.д. И в значительной степени скрыл сложность за несколькими строками кода. Это то, что мы видим и ожидаем, но, к сожалению, нейронные сети работают не так. Они не являются готовой технологией, если вы немного отклонитесь от обучения классификатора ImageNet. Я попытался подчеркнуть это в своем посте «Да, вы должны понимать backprop», назвав backpropagation «уплывающей абстракцией».
К сожалению, ситуация гораздо более сложная. Backprop + SGD волшебным образом не заставят вашу сеть работать. Batchnorm волшебным образом не заставят сеть сходиться быстрее. RNN волшебным образом не позволит вам «получить» текст. И только потому, что вы можете сформулировать свою проблему как RL (Reinforcement Learning – обучение с подкреплением), не означает, что вы должны это делать. Если вы используете технологию, не понимая, как она работает, вы, скорее всего, потерпите неудачу. Что приводит меня к …
2) Обучение нейронной сети проваливается незаметно…
Когда в стандартном программировании вы нарушаете или неправильно конфигурируете код, вы обычно получаете сообщение об ошибке, как то: вы использовали целое число там, где ожидалась строка; функция имеет только три аргумента; импорт не удался; ключ не существует; количество элементов в двух списках разное. Кроме того, вы часто можете создать модульные тесты для тестирования функциональности.
В случае же обучения нейронных сетей это только начало. Синтаксически все может быть правильным, но все не правильно организовано, и это действительно трудно заметить. «Пространство возможных ошибок» является большим, логичным (в отличие от синтаксических) и очень сложным для модульного тестирования. Например, возможно, вы забыли перевернуть метки, когда вы переворачивали изображение влево-вправо во время аугментации данных. Ваша сеть все еще может (шокирующе) работать довольно хорошо, потому что ваша сеть может научиться обнаруживать перевернутые изображения, и также перевернуть свои прогнозы влево-вправо. Или, возможно, ваша авто-регрессионная модель случайно принимает то, что она пытается предсказать, в качестве входных данных из-за ошибки off-by-one (неучтенной единицы). Или вы пытались обрезать свои градиенты, но вместо этого обрезали loss, в результате чего во время тренировки игнорировались выбросы. Или вы инициализировали свои веса с предварительно обученной контрольной точки, но не использовали исходное среднее значение. Или вы просто испортили настройки регуляризации, скорости обучения, скорости затухания, размера модели и т.д. Поэтому ваша неправильно сконфигурированная нейронная сеть будет генерировать исключения, и то, если вам повезет. Она будет продолжать тренироваться, но незаметно будет работать все хуже и хуже.
В результате (и это reeaally трудно оценить) «быстрый и напористый» подход к обучению нейронных сетей не работает и приводит к ненужным мучениям. И эти мучения в итоге становятся естественной частью обучения нейронной сети. Но их можно уменьшить, если быть тщательным, параноидальным и одержимым визуализацией практически всего. По моему опыту, наиболее сильно коррелируют с успехами в глубоком обучении – это терпение и внимание к деталям.
Рецепт
В свете вышеупомянутых двух фактов я разработал для себя особый процесс, которому я следую, применяя нейронную сеть к новой проблеме. Вы увидите, что к двум вышеизложенным наблюдениям надо относиться очень серьезно. В частности, рецепт всегда строится от простого к сложному. На каждом этапе мы выдвигаем конкретные гипотезы о том, что произойдет, а затем либо проверяем их экспериментом, либо исследуем, пока не обнаружим какую-то проблему. То, что мы пытаемся предотвратить очень сложно, – это введение большого количества «непроверенных» усложнений одновременно, что неизбежно приводит к ошибкам / неправильной конфигурации. Чтобы написание кода нейронной сети было действительно похоже на обучение, нужно использовать очень небольшую скорость обучения и проводить полный набор тестов после каждой итерации.
1. Сроднитесь с данными
Первый шаг к обучению нейронной сети состоит в том, чтобы вообще не касаться кода нейронной сети, а вместо этого начать с тщательного изучения данных. Этот шаг очень важен. Мне нравится тратить огромное количество времени (измеряемое часами) на просмотр тысяч примеров, понимание их распределения и поиск шаблонов. К счастью, ваш мозг очень хорош в этом. Однажды я обнаружил, что данные содержат дубликаты примеров. В другой раз я нашел поврежденные изображения / метки. Я ищу дисбалансы данных и отклонения. Обычно я также применяю свой собственный процесс классификации данных, который намекает на типы архитектур, которые мы в конечном итоге рассмотрим. Например, достаточно ли локальных функций или нам нужен глобальный контекст? Сколько существует вариаций и в какой форме? Какой вариант является ложным и может быть предварительно отброшен? Имеет ли значение пространственное распределение или мы можем усреднить его? Насколько важны детали и как сильно мы можем уменьшить изображение? Насколько зашумлены метки?
Кроме того, поскольку нейронная сеть фактически является сжатой / скомпилированной версией вашего набора данных, вы сможете посмотреть на свои сетевые (неправильные) прогнозы и понять, откуда они могут исходить. И если ваша сеть дает вам какой-то прогноз, который не соответствует тому, что вы видели в данных, что-то не так.
Как только у вас появляется качественное понимание данных, также хорошей идеей является написание простого кода для поиска / фильтрации / сортировки по параметрам, которые вы только можете придумать (например, тип метки, размер аннотаций, количество аннотаций и т.д.). Визуализируйте их распределение и выбросы вдоль какой-либо оси. Выбросы почти всегда обнаруживают некоторые ошибки в качестве данных или предварительной обработке.
2. Настройте сквозной скелет обучения / оценки + установите базовые ориентиры
Теперь, когда мы понимаем наши данные, можем ли мы обратиться к нашему сверхумному мультимасштабному ASPP FPN ResNet и начать обучение потрясающих моделей? Ещё нет. Это будет дорога к мучениям. Наш следующий шаг – создать полный скелет обучения и оценки и обрести уверенность в его правильности с помощью серии экспериментов. На этом этапе лучше выбрать какую-нибудь простую модель, которую вы, возможно, не могли бы испортить, например, линейный классификатор или очень крошечный ConvNet. Мы хотим обучить его, визуализировать функцию потерь, любые другие метрики (например, точность), предсказания модели и выполнить серию отсекающих экспериментов с явными гипотезами.
Советы и рекомендации для этого этапа:
- Зафиксируйте random seed. Всегда используйте фиксированное случайное начальное число, чтобы гарантировать, что при повторном запуске вы получите тот же результат. Это устраняет фактор случайной вариации и удерживает нас в рамках здравого смысла. [Прим. Id-lab. Это, безусловно, полезно при тестировании / настройке вашей модели. Не забудьте только перед началом “боевого” обучения убрать фиксацию random seed. Иначе, обучение вашей сеть будет “страдать” от отсутствия вариативности.]
- Упрощайте. Обязательно отключите любые ненужные улучшения. В частности, обязательно отключите любую аугментацию данных на этом этапе. Аугментация данных – это стратегия регуляризации, которую мы можем использовать позже, но пока это еще одна возможность привнести какую-нибудь глупую ошибку.
- Делайте eval на значимом наборе тестовых данных. При построении функции потерь на тестовых данных выполните оценку по всему (большому) тестовому набору. Не смотрите тестовые потери только на партии (batch), полагаясь на их сглаживание в Tensorboard. Мы стремимся к правильности и очень хотим потратить время, чтобы оставаться в рамках здравого смысла.
- Подтвердите loss @ init. Убедитесь, что ваша функция потерь стартует с правильного значения. Например, если вы правильно инициализируете свой последний слой, вы должны получить -ln(1/n_classes) на моделях с softmax при инициализации. Те же значения по умолчанию могут быть получены для регрессии L2, функции Хьюбера и т.д.
- Инициализируйте верно. Инициализируйте веса последнего слоя правильно. Например, если вы регрессируете некоторые значения, которые имеют среднее значение 50, инициализируйте смещение (bias) последнего слоя значением 50. Если у вас есть несбалансированный набор данных с соотношением 1:10 положительных: отрицательных значений, установите смещение в logits так, чтобы ваша сеть предсказывала вероятность 0,1 при инициализации. Правильная их установка ускорит конвергенцию и устранит фактор «хоккейной клюшки», когда в течение первых нескольких итераций ваша сеть просто ищет правильное смещение (bias). [Прим. Id-lab. Верную начальную инициализацию весов и смещения сложно переоценить. Это важно не только для быстрой начальной сходимости модели. Неверная инициализация коэффициентов может в целом привести к фатальной ошибке, загнав модель в локальный минимум или «посадить» ее на плато, из которых невозможно выбраться. Также возможно получить слишком малые или слишком большие градиенты при backprop, что не позволит модели обучаться. Необходимо правильно установить начальный bias последнего слоя (bias внутренних слоёв можно инициализировать нулями) и веса всех уровней модели. Если ваши данные не содержат каких-либо особенностей и нормализованы со средним значением ноль, то веса также лучше инициализировать распределениями с нулевым средним. В частности, для нормализованных изображений очень хорошо подходит he_uniform. Для правильной установки смещения последнего слоя автор обоснованно предлагает использовать следующие соображения. Для задач классификации c выходной функцией активации softmax, когда все классы сбалансированы, при первом прогоне модель должна логично предсказывать для каждого класса значение 1/[число классов]. Для несбалансированной выборки оценку bias можно вывести из ожидаемого предсказания позитивного – pos (обычно меньшего, несбалансированного) класса: pos/(pos+neg) = 1/(1+exp(-bias)); bias = ln(pos/neg). Здесь мы разумно предполагаем, что при первом прогоне, модель должна просто транслировать на выход особенности входных данных x и выдать усредненные к нулю значения ядра: w.T * x. В этом случае именно bias последнего слоя должен определить верное значение z = w.T * x + bias для начального значения аргумента функции потерь.]
- Человеческий ориентир. Мониторьте показатели, помимо функции потерь, которые можно интерпретировать и проверить (например, точность). По возможности оцените свою (человеческую) точность и сравните с ней. В качестве альтернативы, аннотируйте тестовые данные дважды и для каждого примера рассматривайте одну аннотацию как прогноз, а другую как базис (ground truth).
- Исходно-независимая базовая линия. Обучите независимую от входа базовую линию (например, проще всего просто установить все ваши входы на ноль). Это должно работать хуже, чем когда вы фактически подключаете свои данные, не обнуляя их. Так ли это? Т.е. научилась ли ваша модель извлекать какую-либо информацию из входных данных вообще?
- Переобучите одну партию. Переобучите одну партию из нескольких примеров (например, всего двух). Для этого мы увеличиваем емкость нашей модели (например, добавляем слои или фильтры) и проверяем, что мы можем достичь наименьших достижимых потерь (например, ноль). Мне также нравится визуализировать на одном графике как метку, так и прогноз, и убедиться, что они в итоге выровняются идеально, как только мы достигнем минимальной потери. Если этого не происходит, где-то есть ошибка, и мы не можем перейти к следующему этапу.
- Проверьте уменьшение функции потерь при обучении. Надеемся, что на этом этапе вы будете не до обучать на своем наборе данных, поскольку работаете с игрушечной моделью. Попробуйте немного увеличить её мощность. Снизилась ли ваша функция потерь при обучении, как следовало бы?
- Визуализируйте данные прямо на входе сети. Однозначно правильное место для визуализации ваших данных находится непосредственно перед вашим y_hat = model(x) (или sess.run в tf ). То есть – вы хотите визуализировать именно то , что входит в вашу сеть, расшифровывая этот сырой тензор данных и меток в визуализации. Это единственный «источник правды». Я не могу сосчитать, сколько раз это спасло меня и выявило проблемы с предварительной обработкой и аугментации данных.
- Визуализируйте динамику прогнозирования. Мне нравится визуализировать прогнозы моделей для фиксированной тестовой партии в ходе обучения. «Динамика» того, как изменяются эти прогнозы, даст вам невероятно хорошую интуицию в том, как проходит обучение. Много раз можно почувствовать, что сеть «изо всех сил» приспосабливается к вашим данным, если она каким-то образом колеблется, выявляя нестабильность. Очень низкие или очень высокие показатели обучения также легко заметны по дрожанию.
- Используйте backprop для построения графиков зависимостей. Ваш код глубокого обучения часто будет содержать сложные, векторные и транслируемые операции. Относительно распространенная ошибка, с которой я сталкивался несколько раз, заключается в том, что люди ошибаются (например, они используют представление вместо транспонирования / перестановки где-либо) и непреднамеренно смешивают информацию в измерении пакета. Удручает тот факт, что ваша сеть, как правило, все еще работает нормально, потому что она научится игнорировать данные из других примеров. Один из способов отладки этого (и других связанных с этим проблем) состоит в том, чтобы установить потерю как нечто тривиальное, например, сумму всех выходных данных примера i, выполнить обратный проход до входа и убедиться, что вы получаете ненулевое значение градиента только на i-м входе. Та же самая стратегия может использоваться, например, чтобы гарантировать, что ваша модель авторегрессии в момент времени t зависит только от 1..t-1. В целом, градиенты дают вам информацию о том, что зависит от того, что находится в вашей сети, что может быть полезно для отладки.
- Обобщайте частный случай. Это немного более общий совет по кодированию, но я часто видел, как люди делают ошибки, когда они откусывают больше, чем могут прожевать, пишут относительно общую функциональность с нуля. Мне нравится писать очень специфическую функцию для того, что я делаю сейчас, заставить это работать, а затем обобщать ее позже, чтобы убедиться, что я получаю тот же результат. Часто это относится к векторному коду, где я почти всегда сначала записываю полностью зацикленную версию, а только затем преобразую ее в векторный код по одному циклу за раз.
3. Переобучение
На этом этапе у нас должно быть хорошее понимание набора данных, и у нас работает полный конвейер обучения и оценки. Для любой данной модели мы можем (воспроизводимо) вычислить метрики, которым мы доверяем. Мы также вооружены нашей производительностью для независимой от ввода базовой линии, производительностью нескольких простых базовых линий (мы должны улучшить их). У нас также есть грубое представление о производительности человека (мы надеемся его достичь). Теперь всё настроено для итераций на хорошей модели.
Подход, который я предпочитаю использовать для поиска хорошей модели, состоит из двух этапов: сначала постройте модель, достаточно большую, чтобы она смогла переобучиться (то есть сосредоточьтесь на функции потерь при обучении). И затем упорядочьте ее (регуляризуйте), улучшив функцию потерь при валидации (validation loss) в ущерб функции потерь при обучении (training loss). Причина, по которой мне нравятся эти два этапа, заключается в том, что если мы вообще не cможем достичь низкого уровня ошибок с какой-либо моделью, это может снова указать на некоторые проблемы, ошибки или неправильную конфигурацию.
Несколько советов и рекомендаций для этого этапа:
- Выбирая модель . Чтобы достичь правильных значений функции потери при обучении, вы должны выбрать подходящую архитектуру модели. Когда дело доходит до этого выбора, мой совет № 1: не будь героем. Я видел много людей, которые хотят стать сумасшедшими и креативными, собирая лего-блоки из набора инструментов нейронной сети в различных экзотических архитектурах, которые имеют для них какой-то смысл. Сильно сопротивляйтесь этому искушению на ранних стадиях вашего проекта. Я всегда советую людям просто найти наиболее подходящую статью и скопировать оттуда простейшую архитектуру, которая обеспечивает хорошую производительность. Например, если вы классифицируете изображения, не будьте героем, просто скопируйте и вставьте ResNet-50 для первого запуска. Позже вы можете сделать что-то более нестандартное и улучшить результат.
- Адам это безопасно. На ранних этапах определения базовых уровней мне нравится использовать оптимизатор Адама со скоростью обучения (learning rate) 3e-4. По моему опыту, Адам гораздо более терпим к гиперпараметрам, в том числе к плохой скорости обучения. Для ConvNets хорошо настроенный SGD почти всегда немного опережает Адама, но область оптимальной скорости обучения гораздо более узкая и специфическая для задачи. (Примечание. Если вы используете RNN и связанные с ними модели последовательностей, то лучше пользуетесь Адамом. На начальном этапе вашего проекта, опять же, не будьте героем и следуйте тому, что предлагают в большинстве статей.)
- По одному усложнению за раз. Если у вас есть несколько сигналов для подключения к вашему классификатору, я бы посоветовал вам подключать их по одному. И каждый раз проверять, что вы получаете повышение производительности, которое ожидаете. Не топите вашу модель в сложностях с самого начала. Существуют и другие способы наращивания сложности – например, вы можете сначала попытаться использовать изображения меньшего размера, а потом увеличить их и т.д.
- Не используйте затухание для скорости обучения (learning rate) по умолчанию. Если вы используете код из какого-либо другого домена, всегда будьте очень осторожны с затуханием скорости обучения. Вы не только захотите использовать другой график затухания для своей задачи. В оригинальной реализации график основан на определенном количестве эпох, которое может сильно варьироваться в зависимости от размера вашего набора данных. Например, ImageNet будет затухать в 10 раз на каждой 30-й эпохе. Если вы не тренируете ImageNet, то вы почти наверняка этого не хотите. Если вы не будете осторожны, ваш код может незаметно снизить скорость обучения до нуля слишком рано, не позволяя вашей модели сойтись. В своей работе я всегда полностью отключаю затухание скорости обучения (использую постоянный learning rate) и настраиваю это только в самом конце.
4. Регуляризация
В идеале, мы сейчас находимся на этапе, где у нас есть большая модель, которая хорошо обучается на тренировочных данных. Теперь пришло время его регуляризовать и улучшить точность валидации, ухудшив точность обучения. Некоторые советы и рекомендации:
- Увеличьте набор данных. Во-первых, самый лучший и предпочтительный способ регуляризовать модель с практической точки зрения – это добавить больше реальных данных для обучения. Это очень распространенная ошибка – тратить много инженерных циклов, пытаясь выжать сок из небольшого набора данных, когда вместо этого нужно собрать больше данных. Насколько я знаю, добавление большего количества данных – это практически единственный гарантированный способ монотонного повышения производительности хорошо сконфигурированной нейронной сети практически до бесконечности. Другой будет ансамбль (если вы можете себе это позволить), но это возможно только после примерно 5 моделей.
- Аугментация данных. Следующее лучшее, что можно сделать после увеличения реальных данных, – это синтезировать наполовину фальшивые данные – попробуйте более агрессивную аугментацию данных.
- Креативная аугментация. Если наполовину фальшивых данных недостаточно, фальшивые данные тоже могут помочь. Люди находят творческие способы расширения наборов данных. Например, рандомизация доменов, использование симуляции, умные гибриды, такие как вставка (потенциально симулированная) данных в сцены или даже GAN.
- Предобученная сеть. Очень часто помогает использовать предварительно обученную сеть, даже если у вас достаточно данных.
- Используйте обучение с учителем. Не увлекайтесь неконтролируемым обучением (без учителя). Несмотря на то, что утверждается в том известном посте за 2008 год, насколько я знаю, ни одна из последующих реализаций не добилась сильных результатах в современном компьютерном зрении (хотя NLP, похоже, в настоящее время неплохо справляется с BERT и подобными сетями, вероятно, из-за более предопределенного характера текстовых данных и более высокого отношения сигнал / шум).
- Меньшая размерность входных данных. Удалите функции, которые могут содержать ложный сигнал. Любые добавленные ложные данные – это просто еще одна возможность переобучения, если ваш набор данных небольшой. Точно так же, если детали низкого уровня не имеют большого значения, попробуйте использовать изображения меньшего размера.
- Меньший размер модели. Во многих случаях вы можете использовать знание ограничений предметной области, чтобы уменьшить размер сети. Например, раньше было модно использовать слои Fully Connected в верхней части магистралей для ImageNet, но с тех пор они были заменены простым средним пулированием, что исключило кучу ненужных параметров из процесса.
- Меньший размер партии (batch). Из-за нормализации, применяемой внутри партии, меньший размер партии в некоторой степени соответствует более сильной регуляризации. Это связано с тем, что эмпирическое среднее значение / отклонение партии являются приблизительной версией полного среднего значения / отклонения, поэтому масштаб и смещение «раскачивают» вашу партию сильнее.
[Прим. Id–lab. Эта рекомендация несколько противоречит общепринятой практике использовать партии максимально возможного размера. Больший размер партии, очевидно, способствует более быстрой сходимости сети. В тоже время, уменьшение размера партии заставляет сеть обучаться медленнее, но из-за более сильной «раскачки» это может привести в итоге к лучшему результату.]
- Используйте drop. Применяйте dropout2d (пространственное выпадение) для ConvNets. Делайте это экономно / осторожно, потому что выпадение не очень хорошо сочетается с нормализацией партии.
- Затухание весов. Увеличьте штраф за затухание весов.
- Ранняя остановка (Early stopping). Прекращайте обучение, основываясь на изменениях функции потерь при валидации, чтобы поймать вашу модель, как только она собирается переобучиться.
- Попробуйте большую модель. Я упоминаю об этом в последний раз и только после средства ранней остановки. Но в прошлом я несколько раз обнаруживал, что большие модели в конечном итоге, могут переобучаться гораздо легче, но их «ранняя остановка» часто намного лучше, чем у меньших моделей.
Наконец, чтобы получить дополнительную уверенность в том, что ваша сеть является разумным классификатором, мне нравится визуализировать веса первого уровня сети и убедиться, что вы получите хорошие параметры, которые имеют смысл. Если ваши фильтры первого слоя выглядят как шум, значит, что-то не так. Аналогичным образом, уровни активация внутри сети могут иногда отображать странные артефакты и указывать на проблемы.
5. Настройка
На этом этапе вы должны полностью владеть вашим набором данных, исследовав широкий набор возможных моделей, которые дают низкое значение функции потерь при валидации. Вот несколько советов для этого шага:
- Случайный поиск по сетке. Для одновременной настройки нескольких гипер-параметров может показаться заманчивым использование поиска по сетке для обеспечения охвата всех настроек, но имейте в виду, что вместо этого лучше использовать случайный поиск. Интуитивно это объясняется тем, что нейронные сети часто гораздо более чувствительны к одним параметрам, чем к другим. Например, если параметр a имеет значение, а изменение b недает никакого эффекта, вы бы предпочли более точную настройку по a, чем в нескольких фиксированных точках.
- Оптимизация гипер-параметров. Есть большое количество привлекательных байесовских наборов инструментов для оптимизации гипер-параметров, и некоторые из моих друзей говорили об успехе при работе с ними. Мой личный опыт заключается в том, что современный подход к исследованию широкого пространства моделей и гипер-параметров это использовать стажера :). Просто шучу.
6. Последняя капля
Когда вы уже нашли лучшие типы архитектур и гипер-параметров, вы все равно можете использовать еще несколько приемов, чтобы выжать из системы последние капли сока:
- Ансамбли. Модельные ансамбли – это в значительной степени гарантированный способ улучшить точность на 2% по всем показателям. Если вы не можете позволить себе вычисления во время тестирования, изучите возможность объединения вашего ансамбля в сеть с использованием темных знаний .
- Продолжайте обучение. Я часто видел людей, прекращающих обучение модели, когда функция потерь при валидации перестает уменьшаться. По моему опыту, сети продолжают тренироваться интуитивно долгое время. Однажды я случайно оставил модель обучаться на время зимних каникул, и когда я вернулся в январе, это был шедевр.
Вывод
Раз вы добрались до этого этапа, у вас должны быть все составляющие для успеха: у вас есть глубокое понимание технологии, набора данных и задачи, вы создали всю инфраструктуру обучения / оценки и достигли высокой уверенности в ее точности. Вы исследовали разные сложные модели, улучшая производительность способами, которые вы контролировали на каждом этапе. Теперь вы готовы прочитать много статей, провести большое количество экспериментов и получить результаты на уровне произведений искусства. Удачи!