Что значит обучить нейронную сеть

Здравствуйте и вновь добро пожаловать на занятия по теме «Глубокое обучение на языке Python, часть 1».

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

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

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

Итак, каковы же основные уже изученные нами понятия? Ну, в очень интуитивной форме мы определили функцию, названную функцией затрат. Как и всякий хороший предприниматель, мы желаем минимизировать наши затраты. Как нам это сделать? Конечно же, мы переносимся в сферу дифференциального счисления, поскольку оно предоставляет нам инструменты для нахождения минимумов и максимумов функций. В частности, мы используем метод, называемый градиентным спуском. Если вы не знаете, что это такое, то мы впервые рассмотрели его в моём курсе логистической регрессии. Вновь-таки, намного легче изучить его в том контексте, но на всякий случай в приложении рассмотрен простой пример градиентного спуска.

Следующее, о чём мы поговорим, – о том, как мы определяем нашу функцию затрат. Напомню, что в случае двоичной классификации это в точности то же, как если бы мы подсчитывали правдоподобие выпадения некоторой последовательности при броске монеты. К примеру, у вас выпало два орла и три решки. Тогда общее правдоподобие равно вероятности выпадения орла, умноженное на вероятность выпадения орла, умноженное на вероятность выпадения решки, умноженное на вероятность выпадения решки, умноженное на вероятность выпадения решки. Мы вправе перемножать вероятности, поскольку каждый бросок монеты независим относительно других. Другой способ это записать – обозначить через малое p вероятность выпадения орла: p = p(H). Тогда мы можем сказать, что правдоподобие равно p в степени количества выпавших орлов, умноженное на (1 – p) в степени количества выпавших решек:

Правдоподобие или, другими словами, вероятность нашей модели – это нечто такое, что мы хотели бы максимизировать. Но не забывайте, что мы сейчас рассматриваем функцию затрат, иначе говоря, нечто такое, что мы бы хотели минимизировать. Чтобы получить то, что мы называем функцией затрат, мы берём отрицательный логарифм функции правдоподобия. Он равен

Как вы помните из курса логистической регрессии, это то, что называется кросс-энтропийной функцией ошибок.

Мы можем выразить это же в понятиях исходящей вероятности модели логистической регрессии и целевых переменных, которые в двоичном случае могут принимать значение 0 и 1:

где yn – исходящая переменная логистической регрессии или нейронной сети, tn – целевая переменная (0 или 1).

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

В этом курсе, как вы понимаете, мы выполняем не двоичную, а мультиклассовую классификацию, способную обрабатывать любое количество исходящих переменных. Поэтому лучше будет рассматривать бросок кубика. Существует 6 возможных вариантов броска, но мы обозначим это количество через K. Обозначим через yk вероятность выпадения k-й грани и условимся, что tk равно единице, если выпала k-я грань, и нулю – если она не выпала. Тогда мы можем записать, что правдоподобие для N бросков кубика равно

Обратите внимание, что теперь y и t имеют теперь по два индекса каждый, при этом n соответствует номеру рассматриваемого наблюдения, а k соответствует рассматриваемому классу. Отметим также, что для любого конкретного n существует лишь одно tn,k, равное единице, все остальные должны быть равны нулю. Это потому, что если я брошу кубик и выпадет шестёрка, то, очевидно, в этом же броске не может быть другого результата. Другими словами, tn,k представляет собой «матрицу прямого кодирования», или матрицу показателей, состоящую из единиц и нулей.

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

Это выражение также называется кросс-энтропийной функцией, но для мультиклассовой классификации.

На следующих лекциях вы познакомитесь с тем, как реализуется градиентный спуск для такой функции затрат, а затем мы напишем её в коде. Некоторые недооценивают важность всего этого, поскольку полагают, что библиотека TensorFlow уже содержит, как вы увидите позже, соответствующую функцию. Однако учёные потратили десятилетия, пытаясь создать этот алгоритм, и было бы неплохо понимать его важность и как он работает. Это – «секретный соус» для нейронных сетей, поскольку мы используем тот же обучающий алгоритм вне зависимости от сложности нейронной сети. Будь то свёрточная нейронная сеть или рекуррентная, или автокодировщик, или что-нибудь ещё – все они используют один алгоритм.

Нейронные сети без математики

Поговорим о нейронных сетях, причём совсем без математики. Думаю, это будет замечательное упражнение, которое позволит вам получить интуитивное понимание работы нейронных сетей, не увязнув при этом в сложной теории.

Итак, с самой общей точки зрения, нейронные сети – это лишь другой способ проведения обучения с учителем. Все модели, включая логистическую регрессию, метод k ближайших соседей, наивный байесовский классификатор, метод опорных векторов, древа решений и нейронные сети, – выполняют две одинаковые основные функции. Первая – это обучение, когда происходит обучение параметров модели на учебном наборе данных, обычно обозначаемых через X и Y. Вторая функция – прогнозирование, когда мы пытаемся дать точный прогноз, используя параметры, обученные на учебном наборе. Как правило, при этом берётся X, а на выходе выдаётся ŷ.

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

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

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

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

В нейронных сетях обучение модели называется обратным распространением ошибки. Что это значит? Представьте себе, что у нас есть более одного скрытого слоя. Тогда ошибки будут распространяться на один уровень назад за раз, то есть второй набор весовых коэффициентов будет меняться в зависимости от ошибок в правом слое, а первый набор весовых коэффициентов будет меняться в зависимости от ошибок в среднем слое. На этом методе основаны многие нейронные сети, поэтому как только вы разберётесь с методом обратного распространения ошибки, вы можете быть уверенными, что основная часть учёбы позади.

Если у вас всё ещё будут вопросы, не стесняйтесь писать нам в твиттер по адресу @. Если же вы предпочитаете Фейсбук, то загляните на мою страницу и напишите нам.

Введение в проект интернет-магазина

На этой лекции мы ознакомимся с нашим курсовым проектом. Кроме того, на лекции вы ознакомитесь с данными, которые мы впоследствии используем, я расскажу вам, откуда они взялись, а также что мы будем делать и какова ценность этого проекта для бизнеса. Надеюсь, проект поможет вам полностью понять теорию и код и научиться применять их в реальной жизни. Очень важно уметь использовать реальные данные, которые могут быть в форме таблиц Excel, SQL-таблиц или просто log-файлами. Кроме того, важно уметь отформатировать их таким образом, чтобы они были пригодны для использования в вашем алгоритме глубокого обучения. Если вы не привыкли к таким вещам, этот проект определённо поможет вам.

Итак, перейдём к постановке задачи.

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

Вы сможете также увидеть, какие стороны вашего сайта слабы и должны быть улучшены. Например, вы можете посмотреть, когда люди начинают процесс оплаты, но не завершают его. Проанализировав причины такой ситуации, вы можете подправить свой сайт. Другой пример – возможно, ваше мобильное приложение неудобно для пользователей, и поэтому они вообще ничего не покупают, когда посещают мобильную версию вашего сайта.

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

Теперь посмотрим на наши данные. Они в формате CSV, с которым, надеюсь, вы уже знакомы. Это просто таблица, в которой каждый элемент в строке отделяется запятой.

Первая строка нашего файла – заголовок, показывающий, что означает каждый столбец.

Первым столбцом идёт Is_mobile. Этот столбец показывает, заходит ли пользователь на наш сайт с мобильного устройства или нет. Конечно же, он двоичный и принимает значения нуль, если пользователь заходит с мобильного устройства, и единица – если с мобильного.

Следующий столбец N_products_viewed. Он показывает количество товаров, которые просмотрел пользователь на протяжении сеанса, когда происходили действия пользователя (являющиеся меткой). Это числовые данные, состоящие из целых чисел, которые могут принимать значения только больше или равными нулю. Что с ними делать, мы обсудим позже.

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

Следующим столбцом идёт Is_returning_visitor. Это ещё одна двоичная переменная, принимающая значение нуль, если это новый посетитель, и единица, если пользователь уже бывал на сайте и возвращается.

Очередной столбец Time_of_day. Время – число, но мы его будем обрабатывать в качестве категории. В общем случае время обозначается числами по-разному, поскольку оно идёт по кругу. К примеру, 11 часов вечера наступают через 23 часа после предыдущей полуночи, но они же означают, что это час до следующей полуночи. Когда мы работаем с геометрическими понятиями, как в машинном обучении, это важно.

Есть простой способ обработки таких данных – разбить их по категориям. Так, мы используем значение 0 для обозначения времени от полуночи до 6 утра, значение 1 для времени от 6 утра до полудня, значение 2 для обозначения времени от полудня до 6 вечера, и значение 3 для обозначения времени от 6 вечера до полуночи. При этом предполагается, что пользователи в одной и той же категории ведут себя одинаково.

Последний столбец User_action является меткой. Она принимает четыре значения – bounce, add_to_cart, begin_checkout и finish_checkout. Bounce означает, что пользователь просто покинул сайт, add_to_cart означает, что он добавил товар в корзину, но не начал оплату, begin_checkout означает ситуацию, когда пользователь уже начал процесс оплаты, но так его и не завершил, finish_checkout означает, что пользователь оплатил товар, а вы успешно получили заказ.

Ясно, что это задача на классификацию, поэтому мы можем использовать логистическую регрессию и нейронные сети. В курсе логистической регрессии я покажу вам только двоичную классификацию, тогда как в курсе по глубокому обучению продемонстрирую, как классифицировать произвольное количество классов. Так сделано потому, что там математические выкладки несколько сложнее. Это значит, что в курсе логистической регрессии мы отбросим два последних класса меток и будем учиться прогнозировать только данные с метками bounce и add_to_cart. Конечно же, вы можете читать сразу дальше или создать множественные двоичные классификаторы. Мы всегда это только приветствуем. Практика – это хорошо.

Поговорим теперь об обработке данных. Конечно же, вы не можете использовать категории в вашей логистической модели или нейронной сети, поскольку они работают с числовыми векторами. Возможно, вы уже слышали о решении этой проблемы в моём курсе линейной регрессии, но будем считать, что нет. Это прямое кодирование (one-hot encoding).

Суть в том, что если у нас есть, скажем, три различных категории, мы используем три различных столбца для их отображения. Затем мы просто устанавливаем значение столбца, который отображает категорию в каждом наблюдении, равной единице.

Например, у нас есть четыре категории для времени: 0, 1, 2 и 3. Это значит, что у нас есть четыре столбца. Если значение категории равно 3, то пишем единицу в четвёртом столбце. Если значение категории равно 2, пишем единицу в третьем столбце и так далее. Естественно, что в любом наблюдении единица будет находиться лишь в одном из этих четырёх столбцов. В этом и заключается прямое кодирование в отношении показателя времени.

А что с Is_mobile и Visit_duration? Разве это не такие же категории? Да, категории, и технически мы можем преобразовать их в два столбца, но это совершенно необязательно. Не забывайте, что каждый весовой коэффициент показывает нам эффект действия переменной. Если у нас есть столбец с нулевым значением переменной, то весовой коэффициент этой размерности указывает на влияние нулевого значения этой переменной. Если же у нас нет такого столбца, то мы просто вводим эффект нулевого значения переменной в свободный член.

И наконец, давайте поговорим о числовых столбцах – N_products_viewed и Visit_duration. Мы знаем, что в обоих столбцах числа должны быть равны нулю или больше. По сути, N_products_viewed имеет значения целых чисел, что значит, что технически мы можем обрабатывать его как категорию, но лучше его рассматривать именно как число на числовой шкале, имеющее смысл. Мы знаем, что 0 ближе к 1, чем 2, что все они имеют смысл. Мы можем ожидать, что 1,5 будет иметь значение между 1 и 2. Предположим, например, что все пользователи, которые просмотрели три и меньше товаров, считаются не заинтересовавшимися, а все пользователи, просмотревшие более трёх товаров, – заинтересовавшимися; тогда пользователь, просмотревший 2,5 или 0,1 товара, также считается не заинтересовавшимися. Но, пользуясь вышеприведенным правилом, вы не ожидаете, что пользователь, просмотревший 0,5 товара, внезапно оказывается заинтересовавшимся, потому что 0,5 – это особое значение величины. Поэтому здесь очень важны масштаб и значение величины.

Одним из простейших способов обработки чисел – сначала их нормализовать. Это значит вычесть среднее значение и поделить на стандартное отклонение:

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

Это не очень хорошо, поэтому лучше сначала нормализовать данные.

Итак, как же этот проект будет включён в наш курс?

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

Сначала мы разберём прогнозирование, иначе говоря – как получить от модели значение исходящих данных. Поэтому как только мы изучим соответствующие теоретические основы, мы вернёмся к нашему проекту интернет-магазина, создадим модель и попробуем получить от неё прогноз.

Следующий раздел будет посвящён обучению, то есть как можно обучить модель, чтобы она давала действительно точные прогнозы и насколько точными они получатся. После изучения теории обучения, мы вновь вернёмся к проекту интернет-магазина, обучим модель и посмотрим, насколько точной она у нас получилось.

От логистической регрессии к нейронным сетям

Здравствуйте и вновь добро пожаловать на занятия по теме «Обработка данных: глубокое обучение на языке Python, часть 1».

В этой лекции мы плавно перейдём от логистической регрессии к нейронным сетям. Не забывайте, что логистическая регрессия – это и есть нейрон, а мы объединяем их вместе для создания сети нейронов. Самый простой способ для этого – метод прямого распространения, который вы изучите на этих занятиях.

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

после чего всё это подставляем в сигмоиду:

Это даёт нам вероятность того, что y = 1. Чтобы получился прогноз, мы просто округляем полученную вероятность.

Распространим теперь эту же идею на нейронные сети. По сути всё, что нам нужно сделать, – просто добавить больше слоёв логистической регрессии. В этом курсе мы будем работать преимущественно с одним дополнительным слоем, но вы можете добавлять произвольное количество слоёв. В последние годы исследователи добились больших успехов с помощью глубоких сетей – отсюда и термин «глубокое обучение», – но, конечно, на первом этапе достаточно добавления и одного слоя.

Как вы можете убедиться, вычисления абсолютно такие же, как и прежде – мы перемножаем каждую входную переменную на её весовой коэффициент, добавляем свободный член и подставляем всё это в сигмоиду. Именно так мы получаем значения каждого из узлов z:

Заметьте, что W теперь является матрицей, так как теперь нам нужны весовые коэффициенты для каждой пары входных и исходящих данных. Поэтому если, к примеру, есть две входящие переменные и три исходящие, то в итоге у нас будет шесть весовых коэффициентов. Обратите внимание, что каждый узел z имеет собственный свободный член bj.

Теперь давайте поговорим о нелинейности. Это именно то, что делает нейронные сети столь мощными, ведь они являются нелинейными классификаторами.

Мы уже знакомы с сигмоидой:

Кратко говоря, это S-образная кривая, имеющая значения функции в диапазоне от 0 до 1.

Другой популярной нелинейной функцией является гиперболический тангенс:

имеющий значения функции в диапазоне от -1 до 1. Заметьте, что функция имеет точно такую же S-образную форму, как и сигмоида. Попытайтесь в качестве упражнения найти математическую взаимосвязь между гиперболическим тангенсом и сигмоидой. Вы увидите, что гиперболический тангенс – это всего лишь та же сигмоида, растянутая по горизонтали и вертикали.

И наконец, у нас есть нелинейная функция relu(x). Она возвращает нуль при всех значениях аргумента, меньших нуля, и значение аргумента во всех остальных функциях:

relu(x) = max(0, x).

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

Разберём теперь численный пример. Пусть наши входные переменные имеют значения x1 = 1, x2 = 0; то же самое мы можем выразить в векторной форме, установив значение весовых коэффициентов, равными единице, а значение свободного члена – равным нулю. Вначале нам надо вычислить значения z. Получим:

Значения обоих z равны, так как они обе в качестве входных переменных имеют 0 и 1 с одинаковыми весовыми коэффициентами.

Далее мы вычисляем Y, что даёт нам значение около 0,8:

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

Не забывайте, что при использовании библиотеки Numpy всегда быстрее применять встроенные векторные и матричные операторы, нежели использовать обычные операторы цикла Python. Мы можем рассматривать наши x как вектор размерности D, а наши z – как вектор размерности M. В таком случае для вычисления результата работы нейронной сети мы использовать запись в векторной форме:

Мы даже можем пойти ещё дальше. Не забывайте, что у нас ожидается не одна единица входных данных, а множество их, а мы хотим, чтобы нейронная сеть одновременно корректно работала со всеми из них. Поэтому мы можем далее перевести наши вычисления в векторную форму, используя полную матрицу входных данных – это будет матрица размерности NxD, где N – количество примеров (наблюдений), а D – размерность входных данных. Поскольку мы будем вычислять всё одновременно, то z будет представлять собой матрицу размерности NxM, а наше исходящее Y – матрицу размерности Nx1. В случае мультиклассовой классификации, когда у нас будет K классов, наше Y будет представлять уже матрицу размерности NxK. В свою очередь, поскольку все члены должны корректно перемножаться по правилам матричного умножения, все одни должны иметь соответствующие размерности. Таким образом, W должно быть матрицей DxM, первый свободный член b должен иметь размерность Mx1, то есть вектором размерности M, исходящий весовой коэффициент v – иметь размерность Mx1, а исходящий свободный член – скалярной величиной.

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

Построение целой нейронной сети прямого распространения на Python

В этой лекции я покажу вам, как производить вычисления в нейронной сети методом прямого распространения с помощью библиотеки Numpy. Если вы не хотите писать код самостоятельно, то соответствующий файл называется forwardprop.py в репозитарии github.

Итак, как обычно, прежде всего мы импортируем библиотеки Numpy и Matplotlib.

import numpy as np

import matplotlib.pyplot as plt

Создадим по 500 примеров на класс.

Nclass = 500

Мы сгенерируем несколько гауссовых облаков, точнее, три гауссовых облака. Первое из них центрировано на координаты (0, -2), второе – на координаты (2, 2), а третье – на координаты (-2, 2).

X1 = np.random.randn(Nclass, 2) + np.array([0, -2])

X2 = np.random.randn(Nclass, 2) + np.array([2, 2])

X3 = np.random.randn(Nclass, 2) + np.array([-2, 2])

X = np.vstack([X1, X2, X3])

Далее создадим метки.

Y = np.array([0]*Nclass + [1]*Nclass + [2]*Nclass)

Мы можем отобразить получившееся графически.

plt.scatter(X[:,0], X[:, 1], c=Y, s=100, alpha=0.5)

plt.show()

Установим значения D = 2, M – это размер скрытого слоя – установим равным 3, и K – это количество классов – также равным 3.

D = 2

M = 3

K = 3

Инициируем теперь весовые коэффициенты. Как мы знаем, W1 должно иметь размерность DxM, b1 – размерность Mx1, W2 – размерность MxK, b2 – размерность Kx1.

W1 = np.random.randn(D, M)

b1 = np.random.randn(M)

W2 = np.random.randn(M, K)

b2 = np.random.randn(K)

Теперь определим функцию прямого распространения нейронной сети, причём в скрытом слое воспользуемся сигмоидой. Аргументами функции являются матрица данных X и значения весовых коэффициентов W1, b1, W2, b2. После этого мы можем рассчитать софтмакс следующего слоя.

def forward(X, W1, b1, W2, b2):

Z = 1 / (1 + np.exp(-X.dot(W1) – b1))

A = Z.dot(W2) + b2

expA = np.exp(A)

Y = expA / expA.sum(axis=1, keepdims=True)

return Y

Теперь напишем функцию для расчёта коэффициента классификации. Её аргументами являются целевая переменная Y и значения прогноза P.

def classification_rate(Y, P):

n_correct = 0

n_total = 0

for i in xrange(len(Y)):

n_total += 1

if Y[i] == P[i]:

n_correct += 1

return float(n_correct) / n_total

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

P_Y_given_X = forward(X, W1, b1, W2, b2)

P = np.argmax(P_Y_given_X, axis=1)

assert(len(P) == len(Y))

И, наконец, выведем на экран значение коэффициента классификации.

print ‘’Classification rate for randomly chosen weights:’’, classification_rate(Y, P)

Разумеется, классификация будет малоудачной, поскольку мы ещё не обучили нейронную сеть, но это демонстрирует использование прямого распространения в нейронной сети.

Итак, запустим файл.

Мы видим наши данные – три гауссовых облака. Коэффициент классификации оказался в точности таким, каким и ожидался, – одна третья.

Краткие итоги раздела обучения

В этой лекции мы обобщим всё, что узнали в этом разделе курса. Весь раздел был полностью посвящён тому, как обучить нейронную сеть. Как вы помните, любой алгоритм машинного обучения имеет две основные функции – обучение и прогнозирование. Первый раздел был посвящён исключительно прогнозированию, второй раздел – исключительно обучению.

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

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

Мы видели, что метод обратного распространения ошибок является рекурсивным, так что это лишь вопрос рекурсивного определения, если вы хотите обучить нейронную сеть с несколькими скрытыми слоями.

Далее мы следовали нашей обычной схеме написания кода сразу после обсуждения теории. Это один из основных приёмов всех моих курсов – сначала мы изучаем теорию, после чего закрепляем её, написав код. Этот приём используется всегда – сначала теория, потом код, теория – потом код. В частности, в первом разделе мы использовали простой двухмерный набор данных, состоявший из трёх «капель» на диаграмме. Этот пример очень важен, поскольку позволяет нам наглядно увидеть набор данных, которые мы пытаемся классифицировать. Важной особенностью этой реализации было то, что в ней использовались векторные операции библиотеки Numpy, что намного ускорило работу.

Далее мы применили алгоритм обучения к набору данных интернет-магазина. Так как до этого у нас не было возможности использовать софтмакс в курсе логистической регрессии – поскольку с самой функцией софтмакс вы познакомились только в этом курсе – мы воспользовались этой возможностью сейчас. Это также позволило нам сравнить точность модели логистической регрессии с точностью модели нейронной сети.

Понравилась статья? Поделить с друзьями:
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: