Глубокое обучение для новичков: тонкая настройка нейронной сети |
||
МЕНЮ Искусственный интеллект Поиск Регистрация на сайте Помощь проекту ТЕМЫ Новости ИИ Искусственный интеллект Разработка ИИГолосовой помощник Городские сумасшедшие ИИ в медицине ИИ проекты Искусственные нейросети Слежка за людьми Угроза ИИ ИИ теория Внедрение ИИКомпьютерные науки Машинное обуч. (Ошибки) Машинное обучение Машинный перевод Реализация ИИ Реализация нейросетей Создание беспилотных авто Трезво про ИИ Философия ИИ Big data Работа разума и сознаниеМодель мозгаРобототехника, БПЛАТрансгуманизмОбработка текстаТеория эволюцииДополненная реальностьЖелезоКиберугрозыНаучный мирИТ индустрияРазработка ПОТеория информацииМатематикаЦифровая экономика
Генетические алгоритмы Капсульные нейросети Основы нейронных сетей Распознавание лиц Распознавание образов Распознавание речи Техническое зрение Чат-боты Авторизация |
2017-01-02 22:49 Введение Представляем третью (и последнюю) статью в серии, задуманной, чтобы помочь быстро разобраться в технологии глубокого обучения; мы будем двигаться от базовых принципов к нетривиальным особенностям с целью получить достойную производительность на двух наборах данных: MNIST (классификация рукописных цифр) и CIFAR-10 (классификация небольших изображений по десяти классам: самолет, автомобиль, птица, кошка, олень, собака, лягушка, лошадь, корабль и грузовик).Теперь вы обладаете базовыми навыками, необходимыми для применения глубокого обучения к большинству интересных задач (исключение составляет задача обработки нелинейных временных рядов, рассмотрение которой выходит за рамки этого руководства и для решения которой обычно предпочительней рекуррентые нейронные сети (RNN). Завершающая часть этого руководства будет содержать то, что очень важно, но часто упускается в подобных статьях — приемы и хитрости тонкой настройки модели, чтобы научить ее обобщать лучше, чем та базовая модель, с которой вы начали. Эта часть руководства предполагает знакомство с первой и второй статьями цикла. Настройка гиперпараметров и базовая модель Обычно процесс разработки нейронной сети начинается с разработки какой-либо простой сети, либо непосредственно применяя те архитектуры, которые уже успешно применялись для решения подобных задач, либо используя те гиперпараметры, которые раньше уже давали неплохие результаты. В конечном итоге, надеемся, мы достигнем такого уровня производительности, который послужит хорошей отправной точкой, после которой мы можем попробовать поизменять все зафиксированные параметры и извлечь из сети максимальную производительность. Этот процесс обычно называют настройкой гиперпараметров, потому что он включает изменение компонентов сети, которые должны быть установлены до начала обучения.Хотя описанный здесь метод может дать более ощутимые преимущества на CIFAR-10, из-за относительной сложности быстрого создания прототипа на нем в отсутствие графического процессора мы сосредоточимся на улучшении его производительности на MNIST. Конечно, если ресурсы позволяют, я призываю вас опробовать подобные методы на CIFAR и своими глазами увидеть, насколько они выигрывают по сравнению со стандартным подходом CNN. Отправной точкой для нас будет служить исходная CNN, представленная ниже. Если какие-то фрагменты кода кажутся вам непонятными, предлагаю ознакомиться с предыдущими двумя частями этого цикла, где описаны все базовые принципы. Код базовой модели Листинг обучения Как видно, наша модель достигает точности 99.12% на тестовом множестве. Это немного лучше, чем результаты MLP, рассмотренной в первой части, но нам еще есть куда расти! В данном руководстве мы поделимся способами улучшения таких “базовых” нейронных сетей (не отступая от архитектуры CNN), а затем оценим прирост производительности, который мы получим. -регуляризация В предыдущей статье мы рассказывали, что одной из основных проблем машинного обучения является проблема переобучения (overfitting), когда модель в погоне за минимизацией затрат на обучение теряет способность к обобщению.Но есть и другие регуляризаторы, которые можно применить к нашей сети. Возможно, самый популярный из них — -регуляризация (также называемая сокращением весов, англ. weight decay), которая использует более прямой подход к регуляризации, чем dropout. Обычно первопричиной переобучения является сложность модели (в смысле количества ее параметров), слишком высокая для решаемой задачи и имеющегося обучающего множества. В некотором смысле, задача регуляризатора — понизить сложность модели, сохранив количество ее параметров. -регуляризация выполняется посредством наложения штрафов (penalising) на веса с наибольшими значениями, минимизируя их -норму с использованием параметра ? — коэффициент регуляризации, выражающий предпочтение минимизации нормы относительно минимизации потерь на обучающем множестве. То есть, для каждого веса ? мы прибавляем к целевой функции слагаемое (множитель ? используется для того, чтобы градиент этого слагаемого по параметру ? равнялся ??, а не 2?? — для удобства применения метода обратного распространения ошибки). Обратите внимание, что крайне важно правильно выбрать ?. Если коэффициент слишком мал, то эффект от регуляризации будет ничтожен, если же слишком велик — модель обнулит все веса. Здесь мы возьмем ? = 0.0001; чтобы добавить этот метод регуляризации в нашу модель, нам понадобится еще один импорт, после чего достаточно всего лишь добавить параметр W_regularizer к каждому слою, где мы хотим применять регуляризацию.
Инициализация сети Один из моментов, который мы упустили из виду в предыдущей статье — принцип выбора начальных значений весов для слоев, составляющих модель. Очевидно, что этот вопрос очень важен: установка всех весов в 0 будет серьезным препятствием для обучения, так как ни один из весов изначально не будет активен. Присваивать весам значения из интервала ±1 — тоже обычно не лучший вариант — на самом деле, иногда (в зависимости от задачи и сложности модели) от правильной инициализации модели может зависеть, достигнет она высочайшей производительности или вообще не будет сходиться. Даже если задача не предполагает такой крайности, удачно выбранный способ инициализации весов может значительно влиять на способность модели к обучению, так как он предустанавливает параметры модели с учетом функции потерь.Здесь я приведу два наиболее интересных метода. Метод инициализации Завьера (Xavier) (иногда — метод Glorot’а). Основная идея этого метода — упростить прохождение сигнала через слой во время как прямого, так и обратного распространения ошибки для линейной функции активации (этот метод также хорошо работает для сигмоидной функции, так как участок, где она ненасыщена, также имеет линейный характер). При вычислении весов этот метод опирается на вероятностное распределение (равномерное или нормальное) с дисперсией, равной , где и — количества нейронов в предыдущем и последующем слоях соответственно. Метод инициализации Ге (He) — это вариация метода Завьера, больше подходящая функции активации ReLU, компенсирующая тот факт, что эта функция возвращает нуль для половины области определения. А именно, в этом случае Чтобы получить требуемую дисперсию для инициализации Завьера, рассмотрим, что происходит с дисперсией выходных значений линейного нейрона (без составляющей смещения), предполагая, что веса и входные значения не коррелируют и имеют нулевое матожидание: Из этого следует, что, чтобы сохранить дисперсию входных данных после прохождения через слой, необходимо, чтобы дисперсия была . Мы можем применить этот же аргумент при обратном распространении ошибки, чтобы получить . Так как обычно мы не можем удовлетворить обоим этим требованиям, мы выбираем дисперсию весов как их среднее: , что на практике, как правило, работает прекрасно. Два этих метода подойдут для большинства примеров, с которыми вы столкнетесь (хотя исследования также заслуживает метод ортогональной инициализации (orthogonal initialization), особенно применительно к рекуррентным сетям). Указать способ инициализации для слоя не сложно: вам всего лишь надо указать параметр init , как описано ниже. Мы будем использовать равномерную инициализацию Ге (he_uniform ) для всех слоев ReLU и равномерную инициализацию Завьера (glorot_uniform ) для выходного softmax слоя (так как по сути он представляет собой обобщение логистической функции на множественные сходные данные).
Батч-нормализация (batch normalization) Батч-нормализация — метод ускорения глубокого обучения, предложенный Ioffe и Szegedy в начале 2015 года, уже процитированный на arXiv 560 раз! Метод решает следующую проблему, препятствующую эффективному обучению нейронных сетей: по мере распространения сигнала по сети, даже если мы нормализовали его на входе, пройдя через внутренние слои, он может сильно исказиться как по матожиднию, так и по дисперсии (данное явление называется внутренним ковариационным сдвигом), что чревато серьезными несоответствиями между градиентами на различных уровнях. Поэтому нам приходится использовать более сильные регуляризаторы, замедляя тем самым темп обучения.Батч-нормализация -предлагает весьма простое решение данной проблемы: нормализовать входные данные таким образом, чтобы получить нулевое матожидание и единичную дисперсию. Нормализация выполняется перед входом в каждый слой. Это значит, что во время обучения мы нормализуем batch_size примеров, а во время тестирования мы нормализуем статистику, полученную на основе всего обучающего множества, так как увидеть заранее тестовые данные мы не можем. А именно, мы вычисляем матожидание и дисперсию для определенного батча (пакета) следующим образом:С помощью этих статистических характеристик мы преобразуем функцию активации таким образом, чтобы она имела нулевое матожидание и единичную дисперсию на всем батче: где ? >0 — параметр, защищающий нас от деления на 0 (в случае, если среднеквадратичное отклонение батча очень мало или даже равно нулю). Наконец, чтобы получить окончательную функцию активации y, нам надо убедиться, что во время нормализации мы не потеряли способности к обобщению, и так как к исходным данным мы применили операции масштабирования и сдвига, мы можем позволить произвольные масштабирование и сдвиг нормализованных значений, получив окончательную функцию активации: Где ? и ? — параметры батч-нормализации, которым системы можно обучить (их можно оптимизировать методом градиентного спуска на обучающих данных). Это обобщение также означает, что батч-нормализацию может быть полезно применять непосредственно к входным данным нейронной сети. Этот метод в применении к глубоким сверточным сетям почти всегда успешно достигает своей цели — ускорить обучение. Более того, он может случить отличным регуляризатором, позволяя не так осмотрительно выбирать темп обучения, мощность -регуляризатора и dropout (иногда необходимость в них совсем отпадает). Регуляризация здесь — следствие того факта, что результат работы сети для определенного примера больше не детерминировано (он зависит от всего батча, в рамках которого данный результат получен), что упрощает обобщение. И наконец, хотя авторы метода рекомендуют применять батч-нормализацию до функции активации нейрона, последние исследования показывают, что если не полезнее, то по крайней мере так же выгодно использовать ее после активации, что мы и сделаем в рамках этого руководства. В Keras добавить батч-нормализацию к вашей сети очень просто: за нее отвечает слой BatchNormalization , которому мы передадим несколько параметров, самый важный из которых — axis (вдоль какой оси данных будут вычислять статистические характеристики). В частности, во время работы со сверточными слоями, нам лучше нормализовать вдоль отдельных каналов, следовательно, выбираем axis=1 .
Расширение обучающего множества (data augmentation) В то время как описанные выше методы касались в основном тонкой настройки самой модели, бывает полезно изучить варианты настройки данных, особенно когда речь идет о задачах распознавания изображений.Представим, что мы обучили нейронную сеть распознавать рукописные цифры, которые были примерно одного размера и были аккуратно выровнены. Теперь давайте представим, что случится, если кто-то даст этой сети на тестирование слегка сдвинутые цифры разного размера и наклона — тогда ее уверенность в правильном классе резко упадет. В идеале хорошо бы уметь так обучать сеть, чтобы она оставалась устойчивой к подобным искажениям, но наша модель может обучаться только на основе тех образцов, которые мы ей предоставили, при том что она проводит в некотором роде статистический анализ обучающего множества и экстраполирует его. К счастью, для этой проблемы существует решение, простое, но эффективное, особенно на задачах по распознаванию изображений: искусственно расширьте обучающие данные искаженными версиями во время обучения! Это означает следующее: перед тем, как подать пример на вход модели, мы применим к нему все трансформации, которые сочтем нужными, а потом позволим сети напрямую наблюдать, какой эффект имеет применение их к данным и обучая ее “хорошо вести себя” и на этих примерах. Например, вот несколько примеров сдвинутых, масштабированных, деформированных, наклоненных цифр из набора MNIST. Keras предоставляет замечательный интерфейс для расширения обучающего множества — класс ImageDataGenerator . Мы инициализируем класс, сообщая ему, какие виды трансформации мы хотим применять к изображениям, а затем прогоняем обучающие данные через генератор, вызывая метод fit , а затем метод flow , получая непрерывно расширяющийся итератор по тем батчам, которые мы пополняем. Есть даже специальный метод model.fit_generator , который проведет обучение нашей модели, использую этот итератор, что существенно упрощает код. Существует небольшой недостаток: так мы теряем параметр validation_split , а значит, нам придется отделять валидационное подмножество данных самим, но это займет всего четыре строчки кода.Здесь мы будем использовать случайные горизонтальные и вертикальные сдвиги. ImageDataGenerator также предоставляет нам возможность выполнять случайные повороты, масштабирование, деформацию и зеркальное отражение. Все эти трансформации также стоит попробовать, кроме разве что зеркального отражения, так как в реальной жизни мы вряд ли встретим развернутые таким образом рукописные цифры.
Ансамбли (ensembles) Одна интересная особенность нейронных сетей, которую можно заметить, когда они используются для распределения данных на более чем два класса — это то, что при различных начальных условиях обучения им легче дается распределение по одним классам, в то время как другие приводят в замешательство. На примере MNIST можно обнаружить, что отдельно взятая нейронная сеть прекрасно умеет отличать тройки от пятерок, но не учится правильно отделять единицы от семерок, в то время как с деля с другой сетью обстоят наоборот. С этим несоответствием можно бороться с помощью метода статистических ансамблей — место одной сети постройте несколько ее копий с разными начальными значениями и вычислите их средний результат на одних и тех же входных данных. Здесь мы будем строить три отдельных модели. Различия между ними можно легко представить в виде диаграммы, построенной также в Keras.Базовая сеть Ансамбль И снова Keras позволяет осуществить задуманное, добавив минимальное количество кода — обернем метод построения составных частей модели в цикл, объединяя их результаты в последнем слое merge .
Ранняя остановка (early stopping) Опишу здесь еще один метод в качестве введения в более широкую область оптимизации гиперпараметров. Пока что мы использовали валидационное множество данных исключительно для контроля за ходом обучения, что, без сомнения, не рационально (так как эти данные не используются в конструктивных целях). На самом же деле валидационное множество может служить базой для оценки гиперпараметров сети (таких, как глубина, количество нейронов/ядер, параметры регуляризации и т.д.). Представьте, что сеть прогоняется с различными комбинациями гиперпараметров, а затем решение принимается на основе их производительности на валидационном множестве. Обратите внимание, что мы не должны знать ничего о тестовом множестве до того как окончательно определимся с гиперпараметрами, так как иначе признаки тестового множества непроизвольно вольются в процесс обучения. Этот принцип также известен как золотое правило машинного обучения, и нарушалось во многих ранних подходах.Возможно, самый простой способ использования валидационного множества — настройка количества “эпох” (циклов) с помощью процедуры, известной как ранняя остановка — просто остановите процесс обучения, если за заданное количество эпох (параметр patience) потери не начинают уменьшаться. Так как наш набор данных относительно невелик и насыщается быстро, мы установим patience равным пяти эпохам, а максимальное количество эпох увеличим до 50 (вряд ли это число когда-либо будет достигнуто). Механизм ранней остановки реализован в Keras посредством класса функций обратного вызова EarlyStopping . Функции обратного вызова вызываются после каждой эпохи обучения с помощью параметра callbacks , передаваемого методам fit или fit_generator . Как обычно, все очень компактно: наша программа увеличивается лишь на одну строчку кода.
Просто покажите мне код После применения шести вышеописанных приемов оптимизации, код нашей нейронной сети будет выглядеть следующим образом.Код Листинг обучения
Наша модель после обновления достигает точности 99.47% на тестовом наборе данных, а это значительный прирост по сравнению с начальной производительностью 99.12%. Конечно, для такого маленького и относительно простого набора данных, как MNIST, выгода не кажется столь значительной. Применив те же приемы к задаче распознавания CIFAR-10, при наличии необходимых ресурсов, вы сможете получить более ощутимое преимущество. Предлагаю вам дальше поработать с этой моделью: в частности, попытайтесь использовать валидационные данные не только для приема ранней остановки, но еще и для оценки размерности и количества ядер, размеров скрытых слоев, стратегий оптимизации, функций активации, количества сетей в ансамбле, и сравните результаты с лучшими из лучших (в момент написания этого поста лучшая модель достигала точности 99.79% на MNIST). Заключение В данной статье мы рассмотрели шесть приемов для тонкой настройки нейронных сетей, описанных в предыдущих постах: -регуляриацияИнициализация Батч-нормализация Расширение обучающего множества Метод ансамблей Ранняя остановка И успешно применили их к глубокой сверточной сети, построенной в Keras, что позволило достигнуть значительного увеличения точности на MNIST и заняло менее 90 строк кода. Это была завершающая статья цикла. Прочесть предыдущие две части можно здесь и здесь. Надеюсь, полученные вами знания станут тем стимулом, который в сочетании с необходимыми ресурсами позволит вам стать наикрутейшими инженерами сетей глубокого обучения. Спасибо!
Источник: habrahabr.ru Комментарии: |
|