Основы машинного обучения (II): нейронные сети
В моем предыдущем посте я описал, как работает машинное обучение, продемонстрировав центральную роль, которую функции затрат и градиентный спуск играют в процессе обучения. Этот пост основан на этих концепциях, исследуя, как работают нейронные сети и глубокое обучение. В этом посте мало объяснений и много кода. Причина этого в том, что я не могу придумать какой-либо способ более четко разъяснить внутреннюю работу нейронной сети, чем невероятные видео, объединенные тремя синими и коричневыми - см. Полный плейлист здесь.
Эти видеоролики показывают, как нейронные сети могут получать необработанные данные, такие как изображения цифр, и могут выводить метки для этих изображений с удивительной точностью. В видеороликах очень доступным образом освещена математика, лежащая в основе нейронных сетей, а это означает, что даже те, у кого нет серьезного математического опыта, могут начать понимать, что происходит под капотом в глубоком обучении.
Этот пост задуман как дополнение к этим видеороликам (полные сценарии Tensorflow и Keras доступны в конце поста). Цель состоит в том, чтобы продемонстрировать, как нейронная сеть может быть определена и запущена в Tensorflow, чтобы она могла идентифицировать цифры, такие как показанные выше.
TensorFlow (для тех, кто не знает) - это библиотека глубокого обучения Google, и хотя она довольно низкоуровневая (я обычно использую библиотеку Keras более высокого уровня для своих проектов глубокого обучения), я думаю, что это отличный способ учиться. Это просто потому, что, хотя он делает невероятное количество волшебных вещей за кулисами, он требует, чтобы вы (да, вы!) Явно определяли архитектуру NN. Поступая так, вы лучше поймете, как работают эти сети.
Нейронные сети
Нейронные сети - это математические и вычислительные абстракции биологических процессов, происходящих в мозге. В частности, они слабо имитируют «запуск» взаимосвязанных нейтронов в ответ на стимулы, такие как новая поступающая информация. Я не считаю биологические аналогии особенно полезными для понимания нейронных сетей, поэтому я не буду продолжать этот путь.
Нейронные сети работают, вычисляя взвешенные суммы входных векторов, которые затем передаются через нелинейные функции активации, тем самым создавая отображение от входа к выходу через слой нелинейного преобразования. Веса (представленные нейтронами) в преобразованном или скрытом слое итеративно корректируются таким образом, что они представляют отношения в данных, которые сопоставляют входные данные с выходными.
Определение слоев и активаций
На первом этапе мы определяем архитектуру нашей сети. Мы создадим четырехуровневую сеть, состоящую из одного входного слоя, двух скрытых слоев и одного выходного слоя. Обратите внимание, как выходные данные одного слоя являются входными данными для следующего. Эта модель довольно проста в том, что касается нейронных сетей, она состоит из плотных или полносвязных слоев, но все же остается довольно мощной.
Входной слой - также иногда называемый видимым слоем - это слой модели, представляющий данные в необработанном виде. Например, для задачи классификации цифр видимый слой представлен числами, соответствующими значениям пикселей.
В TensorFlow (весь код ниже) нам нужно создать переменную-заполнитель для представления этих входных данных, мы также создадим переменную-заполнитель для правильной метки, соответствующей каждому входу. Это эффективно настраивает данные для обучения - значения X и метки y, которые мы будем использовать для обучения нейронной сети.
Скрытые слои позволяют нейронной сети создавать новые представления входных данных, которые модель использует для изучения сложных и абстрактных отношений между данными и метками. Каждый скрытый слой состоит из нейронов, каждый из которых представляет собой скалярное значение. Это скалярное значение используется для вычисления взвешенной суммы входных данных плюс смещение (по сути, y1 ~ wX + b) - создание линейного (или, точнее, аффинного) преобразования.
В Tensorflow вы должны явно определить переменные для весов и смещения, которые составляют этот слой. Мы делаем это, обертывая их в функции tf.Variable - они обертываются как переменные, потому что параметры будут обновляться по мере того, как модель узнает веса и смещение, которые лучше всего представляют отношения в данные. Мы инстанцируем весовые коэффициенты со случайными значениями с очень низкой дисперсией и заполняем переменную смещения нулями. Затем мы определяем умножение матриц, которое происходит в слое.
Это преобразование затем передается через функцию активации (здесь я использую ReLU или выпрямленные линейные блоки), чтобы сделать выходной сигнал линейного преобразования нелинейным. Это позволяет нейронной сети моделировать сложные нелинейные отношения между вводом и выводом - посмотрите превосходное видеообъяснение Сираджа Раваля по функциям активации здесь.
выходной слой является последним слоем в модели и в данном случае имеет размер десять, по одному узлу для каждой метки. Мы применяем активацию softmax к этому слою, чтобы он выводил значения от 0 до 1 по узлам последнего слоя, представляя вероятности по меткам.
Функция затрат и оптимизация
Теперь, когда архитектура нейронной сети определена, мы устанавливаем функцию стоимости и оптимизатор. Для этой задачи я использую категориальную кросс-энтропию. Я также определяю показатель точности, который можно использовать для оценки производительности модели. Наконец, я устанавливаю оптимизатор как стохастический градиентный спуск и вызываю его метод минимизации после его создания.
Наконец, модель может быть запущена - здесь выполняется 1000 итераций. На каждой итерации в модель подается минипакет данных, она делает прогнозы, вычисляет потери и посредством обратного распространения, обновляет веса и повторяет процесс.
** из трех синих, одного коричневого "Но что такое нейронная сеть?" видео **
Эта простая модель обеспечивает точность около 95,5% на тестовом наборе, что неплохо, но могло бы быть намного лучше. На графиках ниже вы можете увидеть точность и стоимость для каждой итерации модели, одна вещь, которая явно выделяется, - это несоответствие между производительностью на наборе поездов и производительностью на тестовом наборе.
Это указывает на переоснащение, то есть модель слишком хорошо изучает обучающие данные, что ограничивает ее обобщаемость. Мы можем справиться с переобучением, используя методы регуляризации, о которых я и расскажу в следующем посте.
Спасибо за чтение 🙂
P.S Полный скрипт Tensorflow можно найти здесь, а модель, определенную в Keras, здесь.
Первоначально опубликовано на сайте dataflume.wordpress.com 21 декабря 2017 г.