Рецепт обучения нейронных сетей

МЕНЮ


Искусственный интеллект
Поиск
Регистрация на сайте
Помощь проекту

ТЕМЫ


Новости ИИРазработка ИИВнедрение ИИРабота разума и сознаниеМодель мозгаРобототехника, БПЛАТрансгуманизмОбработка текстаТеория эволюцииДополненная реальностьЖелезоКиберугрозыНаучный мирИТ индустрияРазработка ПОТеория информацииМатематикаЦифровая экономика

Авторизация



RSS


RSS новости


Несколько недель назад я опубликовал твит о “самых распространенных ошибках нейронной сети”, перечисляя несколько общих gotchas, связанных с обучением нейронных сетей. Твит получил гораздо больше участия, чем я ожидал (включая вебинар :)). Очевидно, что многие люди лично столкнулись с большим разрывом между “вот как работает сверточный слой” и “наш convnet достигает современных результатов”.

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

1) обучение нейронной сети-это дырявая абстракция

Якобы легко начать с обучения нейронных сетей. Многочисленные библиотеки и фреймворки гордятся отображением 30-строчных фрагментов miracle, которые решают ваши проблемы с данными, создавая (ложное) впечатление, что это подключи и играй. It's common see things like:

>>> your_data = # plug your awesome dataset here >>> model = SuperCrossValidator(SuperDuper.fit, your_data, ResNet50, SGDOptimizer) # conquer world here 

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

>>> r = requests.get('https://api.github.com/user', auth=('user', 'pass')) >>> r.status_code 200 

Это круто! Смелый разработчик взял на себя бремя понимания строк запросов, URL-адресов, запросов GET/POST, HTTP-соединений и так далее от вас и в значительной степени скрыл сложность за несколькими строками кода. Это то, что мы знаем и ожидаем. К сожалению, нейронные сети совсем не такие. Они не являются "готовыми" технологиями в ту секунду, когда вы немного отклоняетесь от обучения классификатора ImageNet. Я пытался сделать это в своем посте " да, вы должны понять backprop” к сожалению, ситуация гораздо хуже. Backprop + SGD не волшебным образом делает вашу сеть работать. Пакетная норма магически не заставляет ее сходиться быстрее. Rnn не позволяют волшебным образом "подключить" текст. И только потому, что вы можете сформулировать свою проблему как RL, не означает, что вы должны. Если вы настаиваете на использовании технологии, не понимая, как она работает, вы, скорее всего, потерпите неудачу. Что приводит меня к…

2) Тренировка нейронной сети терпит неудачу молча

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

Это только начало, когда дело доходит до обучения нейронных сетей. Все может быть правильно синтаксически, но все это не устроено должным образом, и это действительно трудно сказать. "Поверхность возможной ошибки" большая, логическая (в отличие от синтаксической) и очень сложная для юнит-теста. Например, возможно, вы забыли перевернуть надписи, Когда вы перевернули изображение влево-вправо во время увеличения данных. Ваша сеть все еще может (шокирующе) работать довольно хорошо, потому что ваша сеть может внутренне научиться обнаруживать перевернутые изображения, а затем она слева направо переворачивает свои предсказания. Или, может быть, ваша авторегрессионная модель случайно принимает вещь, которую она пытается предсказать, как входные данные из-за ошибки off-by-one. Или вы пытались обрезать градиенты, но вместо этого обрезали потерю, в результате чего более яркие примеры игнорировались во время тренировки. Или вы инициализировали свои веса из предварительно подготовленной контрольной точки, но не использовали исходное среднее. Или вы просто напортачили с настройками для регуляризации сильных сторон, скорости обучения, ее скорости распада, размера модели и т. д. Таким образом, неправильно настроенная нейронная сеть будет создавать исключения только в том случае, если Вам ПОВЕЗЕТ; Большую часть времени он будет тренироваться, но молча работать немного хуже.

В результате (и это очень трудно переоценить) “быстрый и яростный” подход к обучению нейронных сетей не работает и только приводит к страданиям. Так вот, страдание-это совершенно естественная часть хорошей работы нейронной сети, но его можно смягчить, будучи тщательным, защитным, параноидальным и одержимым визуализацией практически всех возможных вещей. Качества, которые в моем опыте наиболее сильно коррелируют с успехом в глубоком обучении, - это терпение и внимание к деталям.

Рецепт

В свете вышеизложенных двух фактов я разработал для себя особый процесс, которому следую при применении нейронной сети к новой задаче, которую попытаюсь описать. Вы увидите, что он очень серьезно относится к двум вышеприведенным принципам. В частности, он строится от простого к сложному, и на каждом этапе мы делаем конкретные гипотезы о том, что произойдет, а затем либо подтверждаем их экспериментом, либо исследуем, пока не найдем какую-то проблему. То, что мы стараемся предотвратить очень трудно, это введение много “непроверенной” сложности Сразу, который обязан ввести ошибки/неправильные конфигурации, которые будут принимать навсегда, чтобы найти (если когда-либо). Если бы написание кода нейронной сети было похоже на обучение, вы бы хотели использовать очень небольшую скорость обучения и угадывать, а затем оценивать полный набор тестов после каждой итерации.

1. Станьте единым целым с данными

Первый шаг к обучению нейронной сети состоит в том, чтобы вообще не касаться кода нейронной сети и вместо этого начать с тщательного изучения ваших данных. Этот шаг имеет решающее значение. Мне нравится тратить огромное количество времени (измеряемое в единицах часов), просматривая тысячи примеров, понимая их распределение и ища закономерности. К счастью, ваш мозг довольно хорош в этом. Однажды я обнаружил, что данные содержат повторяющиеся примеры. В другой раз я нашел поврежденные изображения / метки. Я ищу дисбалансы данных и предубеждения. Обычно я также обращаю внимание на свой собственный процесс классификации данных, который намекает на типы архитектур, которые мы в конечном итоге рассмотрим. В качестве примера-достаточно ли локальных особенностей или нам нужен глобальный контекст? Насколько велика вариация и какую форму она принимает? Какая вариация является паразитной и может быть предварительно обработана? Имеет ли значение пространственное положение или мы хотим усреднить его? Насколько важна детализация и насколько мы можем позволить себе опустить сравнение изображений? Насколько шумны этикетки?

Кроме того, поскольку нейронная сеть является фактически сжатой/скомпилированной версией вашего набора данных, вы сможете посмотреть на ваши сетевые прогнозы (mis)и понять, откуда они могут исходить. И если ваша сеть дает вам какое-то предсказание, которое не согласуется с тем, что вы видели в данных, что-то не так.

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

2. Настройка сквозного обучения / оценки скелета + получить тупые базовые показатели

Теперь, когда мы понимаем наши данные, можем ли мы дотянуться до нашей супер причудливой Многомасштабной ASP FPN ResNet и начать обучение потрясающим моделям? Наверняка нет. Это путь к страданию. Наш следующий шаг состоит в том, чтобы создать полный скелет обучения + оценки и получить доверие к его правильности с помощью серии экспериментов. На этом этапе лучше всего выбрать какую - то простую модель, которую вы не могли каким-то образом испортить-например, линейный классификатор или очень крошечный ConvNet. Мы хотим тренировать его, визуализировать потери, любые другие показатели (например, точность), предсказания модели, и выполнить серию экспериментов по абляции с явными гипотезами по пути.

Советы и рекомендации для этого этапа:

  • исправить случайное семя . Всегда используйте фиксированное случайное семя, чтобы гарантировать, что при выполнении кода дважды вы получите тот же результат. Это устраняет фактор вариации и поможет вам сохранить рассудок.
  • упрощение . Убедитесь, что отключены любые ненужные причуды. Например, на этом этапе обязательно отключите любое увеличение данных. Увеличение данных - это стратегия регуляризации, которую мы можем включить позже, но сейчас это просто еще одна возможность ввести какую-то глупую ошибку.
  • добавьте значимые цифры в eval . При построении графика потери теста выполните оценку по всему (большому) набору тестов. Не просто стройте тестовые потери по партиям, а затем полагайтесь на сглаживание их в Tensorboard. Мы в погоне за правильностью и очень готовы отказаться от времени, чтобы оставаться в здравом уме.
  • проверить потерю @ init . Убедитесь, что ваша потеря начинается с правильного значения потери. Например. если вы правильно инициализируете конечный слой, то при инициализации необходимо выполнить измерения -log(1/n_classes)на softmax. Те же значения по умолчанию могут быть получены для регрессии L2,потерь Huber и т.д.
  • init хорошо . Правильно инициализируйте вес конечного слоя. Например. при регрессии некоторых значений, имеющих среднее значение 50, инициализируйте окончательное смещение до 50. Если у вас есть несбалансированный набор данных с соотношением 1:10 положительных и отрицательных значений, установите смещение логитов таким образом, чтобы ваша сеть предсказывала вероятность 0,1 при инициализации. Установка их правильно ускорит конвергенцию и устранит кривые потерь “хоккейной клюшки”, где в первых нескольких итерациях ваша сеть в основном только учится смещению.
  • человеческая основа . Мониторинг метрик, отличных от потерь, которые интерпретируются и проверяются человеком (например, точность). По возможности оцените свою собственную (человеческую) точность и сравните с ней. Кроме того, дважды аннотируйте тестовые данные и для каждого примера обрабатывайте одну аннотацию как предсказание, а вторую как основную истину.
  • input-независимая базовая линия . Тренируйте независимую от входа базовую линию (например, проще всего установить все ваши входы на ноль). Это должно работать хуже, чем когда вы фактически подключаете свои данные, не обнуляя их. Не так ли? т. е. учится ли ваша модель извлекать какую-либо информацию из входных данных вообще?
  • overfit одна серия . Приспособьте одиночную серию только немного примеров (например как немногая как 2). Для этого мы увеличиваем емкость нашей модели (например, добавляем слои или фильтры) и проверяем, что мы можем достичь самых низких достижимых потерь (например, ноль). Мне также нравится визуализировать на одном и том же графике как метку, так и предсказание и гарантировать, что они идеально выровняются, как только мы достигнем минимальных потерь. Если нет, где-то есть ошибка, и мы не можем перейти к следующему этапу.
  • проверьте уменьшение потери тренировки . На этом этапе вы, надеюсь, будете недооценивать свой набор данных, потому что вы работаете с игрушечной моделью. Попробуйте немного увеличить его емкость. Ваши потери на тренировках прошли нормально?
  • визуализируйте непосредственно перед сетью . Однозначно правильное место для визуализации данных находится непосредственно перед вами y_hat = model(x)(или sess.runв tf). То есть-вы хотите визуализировать именно то, что входит в вашу сеть, декодируя этот необработанный тензор данных и меток в визуализации. Это единственный "источник истины". Я не могу сосчитать, сколько раз это спасло меня и выявило проблемы в предварительной обработке и увеличении данных.
  • визуализация динамики прогнозирования . Мне нравится визуализировать предсказания модели на фиксированной тестовой партии во время обучения. "Динамика" движения этих предсказаний даст вам невероятно хорошую интуицию для того, как продвигается тренировка. Много раз можно почувствовать, как сеть “борется” за то, чтобы соответствовать вашим данным, если она слишком сильно извивается, обнаруживая нестабильность. Очень низкие или очень высокие скорости обучения также легко заметны в количестве дрожания.
  • используйте backprop для построения графиков зависимостей . Код глубокого обучения часто содержит сложные, векторизованные и транслируемые операции. Относительно распространенная ошибка, с которой я сталкивался несколько раз, заключается в том, что люди получают это неправильно (например, они используют viewвместо transpose/permuteгде-то) и непреднамеренно смешивают информацию по измерению пакета. Это удручающий факт, что ваша сеть, как правило, все еще будет хорошо тренироваться, потому что она научится игнорировать данные из других примеров. Один из способов отладки этой (и других связанных проблем) - установить потерю для некоторого примера i чтобы быть 1.0, запустите обратный проход до самого входа и убедитесь, что вы получаете ненулевой градиент только на i-ом примере. В более общем случае градиенты дают информацию о том, что зависит от того, что в вашей сети, что может быть полезно для отладки.
  • обобщите частный случай . Это немного более общий совет по кодированию, но я часто видел, как люди создают ошибки, когда они откусывают больше, чем они могут жевать, написав относительно общую функциональность с нуля. Мне нравится писать очень конкретную функцию для того, что я делаю прямо сейчас, заставить ее работать, а затем обобщить ее позже, убедившись, что я получаю тот же результат. Часто это относится к векторизации кода, где я почти всегда сначала пишу полностью циклическую версию и только затем преобразую ее в векторизированный код по одному циклу за раз.

3. Overfit

На этом этапе мы должны иметь хорошее понимание набора данных, и у нас есть полный конвейер обучения + оценки работы. Для любой заданной модели мы можем (воспроизводимо) вычислить метрику, которой мы доверяем. Мы также вооружены нашей производительностью для независимой от входных данных базовой линии, производительности нескольких тупых базовых линий (мы лучше обыграем их), и у нас есть грубое чувство производительности человека (мы надеемся достичь этого). Этап теперь установлен для итерации на хорошей модели.

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

Несколько советов и трюков для этого этапа:

  • выбор модели . Для достижения хороших потерь при обучении необходимо выбрать соответствующую архитектуру данных. Когда дело доходит до выбора этого мой # 1 совет: Не будьте героем. Я видел много людей, которые стремятся стать сумасшедшими и творческими в штабелировании блоков lego нейронной сети toolbox в различных экзотических архитектурах, которые имеют смысл для них. Сопротивляйтесь этому искушению на ранних стадиях вашего проекта. Я всегда советую людям просто найти наиболее связанные бумаги и скопировать вставить их простейшую архитектуру, которая обеспечивает хорошую производительность. Например. если вы классифицируете изображения, не будьте героем и просто скопируйте вставку ResNet-50 для первого запуска. Вы можете сделать что-то более обычай позже и бить это.
  • Адам в безопасности . На ранних стадиях установки базовых показателей мне нравится использовать Adam со скоростью обучения 3e-4 . По моему опыту, Адам гораздо более снисходителен к гиперпараметрам, включая плохую скорость обучения. Для ConvNets хорошо настроенный SGD почти всегда будет немного превосходить Adam, но оптимальная область скорости обучения гораздо более узкая и проблемная. (Примечание: Если вы используете RNN и связанные модели последовательностей, чаще всего используется Adam. На начальном этапе вашего проекта, опять же, не будьте героем и следите за тем, что делают самые связанные с этим документы.)
  • комплексировать только по одному за раз . Если у вас есть несколько сигналов для подключения к классификатору, я бы посоветовал вам подключать их один за другим и каждый раз гарантировать, что вы получите повышение производительности, которое вы ожидаете. Не бросайте кухонную раковину на вашу модель в начале. Есть и другие способы создания сложности-например, вы можете попытаться сначала подключить меньшие изображения, а затем сделать их больше и т. д.
  • не доверяйте значениям по умолчанию снижения скорости обучения . Если вы повторно назначаете код из какого-то другого домена, всегда будьте очень осторожны с падением скорости обучения. Мало того, что вы хотите использовать разные графики распада для разных задач, но - что еще хуже - в типичной реализации расписание будет основываться на текущем номере эпохи, который может сильно варьироваться просто в зависимости от размера вашего набора данных. Например. ImageNet распадется к 10 на 30. Если вы не тренируете ImageNet, то вы почти наверняка не хотите этого. Если вы не будете осторожны, ваш код может тайно довести скорость обучения до нуля слишком рано, не позволяя вашей модели сходиться. В моей собственной работе я всегда отключаю скорость обучения распадается полностью (я использую постоянный LR) и настроить это весь путь в самом конце.

4. Упорядочивать

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

  • получить больше данных . Во-первых, самый лучший и предпочтительный способ упорядочить модель в любой практической обстановке-это добавить больше реальных обучающих данных. Это очень распространенная ошибка-тратить много инженерных циклов, пытаясь выжать сок из небольшого набора данных, когда вы могли бы вместо этого собирать больше данных. Насколько я знаю, добавление большего количества данных является практически единственным гарантированным способом монотонно улучшить производительность хорошо настроенной нейронной сети почти на неопределенный срок. Другим были бы ансамбли (если вы можете их себе позволить), но это заканчивается после ~5 моделей.
  • увеличение данных . Следующая лучшая вещь для реальных данных-наполовину поддельные данные-попробуйте более агрессивное увеличение данных.
  • творческое увеличение . Если наполовину поддельные данные не делают этого, поддельные данные также могут что-то сделать. Люди находят творческие способы расширения наборов данных; например, рандомизация доменов , использование моделирования , умные гибриды, такие как вставка (потенциально моделируемых) данных в сцены или даже Gan.
  • pretrain. Это редко когда вредно использовать предварительно подготовленную сеть, если вы можете, даже если у вас есть достаточно данных.
  • придерживайтесь контролируемого обучения . Не переусердствуйте из-за неконтролируемого pretraining. В отличие от того, что говорится в этом блоге 2008 года, насколько я знаю, ни одна его версия не сообщила о сильных результатах в современном компьютерном зрении (хотя НЛП, кажется, довольно хорошо работает с Бертом и друзьями в эти дни, скорее всего, из-за более продуманной природы текста и более высокого отношения сигнал / шум).
  • меньшая размерность входного сигнала . Удалите объекты, которые могут содержать ложный сигнал. Любые добавленные ложные входные данные - это просто еще одна возможность для подгонки, если ваш набор данных мал. Аналогично, если детали низкого уровня не имеют большого значения, попробуйте ввести меньшее изображение.
  • меньший размер модели . Во многих случаях для уменьшения размера сети можно использовать ограничения знаний домена. Например, раньше было модно использовать полностью Соединенные слои в верхней части позвоночника для ImageNet, но с тех пор они были заменены на простое среднее объединение, устраняя тонну параметров в процессе.
  • уменьшите размер пакета . За счет нормализации внутри партии норму меньших размеров партии несколько соответствует более сильная регуляризация. Это связано с тем, что эмпирическое среднее/std партии являются более приблизительными версиями полного среднего/std, поэтому масштаб & смещение “качает” вашу партию вокруг больше.
  • drop. Добавить отсев. Используйте dropout2d (пространственный dropout) для ConvNets. Используйте это экономно / осторожно, потому что отсев, похоже, не играет хорошо с пакетной нормализацией.
  • распад веса . Увеличьте штраф за распад веса.
  • ранняя остановка . Остановите тренировку основанную на вашей измеренной потере утверждения для того чтобы уловить вашу модель как раз по мере того как она около overfit.
  • попробуйте более крупную модель . Я упоминаю об этом в последний раз и только после ранней остановки, но я обнаружил, что несколько раз в прошлом, что большие модели, конечно, будут более приспособлены в конечном итоге, но их “ранняя остановка” часто может быть намного лучше, чем у меньших моделей.

Наконец, чтобы получить дополнительную уверенность в том, что ваша сеть является разумным классификатором, мне нравится визуализировать весы первого слоя сети и гарантировать, что вы получите хорошие края, которые имеют смысл. Если ваши фильтры первого слоя выглядят как шум, то что-то может быть выключено. Аналогично, активации внутри сети могут иногда отображать нечетные артефакты и намекать на проблемы.

5. Мелодия

Теперь вы должны быть “в цикле” с вашим набором данных, исследуя широкое пространство модели для архитектур, которые достигают низких потерь проверки. Несколько советов и трюков для этого шага:

  • случайный поиск по сетке . Для одновременной настройки нескольких гиперпараметров может показаться заманчивым использовать поиск по сетке, чтобы обеспечить охват всех настроек, но имейте в виду, что лучше использовать случайный поиск . Интуитивно это объясняется тем, что нейронные сети часто гораздо более чувствительны к некоторым параметрам, чем другие. В пределе, если параметр a имеет значение, но изменение b не имеет эффекта, то вы бы предпочли образец более тщательно, чем в нескольких фиксированных точках несколько раз.
  • оптимизация гиперпараметров . Существует большое количество причудливых байесовских наборов инструментов оптимизации гиперпараметров вокруг, и несколько моих друзей также сообщили об успехе с ними, но мой личный опыт заключается в том, что современный подход к исследованию хорошего и широкого пространства моделей и гиперпараметров заключается в использовании стажера :). Шучу.

6. Выжать сок

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

  • ансамбли . Модельные ансамбли являются довольно гарантированным способом получить 2% точности на что-либо. Если вы не можете позволить себе вычисления во время тестирования, посмотрите на перегон вашего ансамбля в сеть с использованием темных знаний .
  • оставьте это обучение . Я часто видел людей, искушенных остановить обучение модели, когда потеря валидации, кажется, выравнивается. По моему опыту, сети тренируются непреднамеренно долго. Однажды во время зимних каникул я случайно покинул тренировку модели, и когда я вернулся в январе, это была SOTA (“state of the art”).

Вывод

Как только вы сделаете это здесь, у вас будут все ингредиенты для успеха: у вас есть глубокое понимание технологии, набора данных и проблемы, вы настроили всю инфраструктуру обучения/оценки и достигли высокой уверенности в ее точности, и вы исследовали все более сложные модели, получая улучшения производительности способами, которые вы предсказывали каждый шаг пути. Теперь вы готовы прочитать много статей, попробовать большое количество экспериментов и получить свои результаты SOTA. Удачи!


Источник: karpathy.github.io

Комментарии: