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

  • 18.02.2022

Мое знакомство с нейронными сетями произошло, когда вышло приложение Prisma. Оно обрабатывает любую фотографию, с помощью нейронных сетей, и воспроизводит ее с нуля, используя выбранный стиль. Заинтересовавшись этим, я бросился искать статьи и «туториалы», в первую очередь, на Хабре. И к моему великому удивлению, я не нашел ни одну статью, которая четко и поэтапно расписывала алгоритм работы нейронных сетей. Информация была разрознена и в ней отсутствовали ключевые моменты. Также, большинство авторов бросается показывать код на том или ином языке программирования, не прибегая к детальным объяснениям.

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

Соответственно, нейронная сеть берет на вход два числа и должна на выходе дать другое число - ответ. Теперь о самих нейронных сетях.

Что такое нейронная сеть?

Нейронная сеть - это последовательность нейронов, соединенных между собой синапсами. Структура нейронной сети пришла в мир программирования прямиком из биологии. Благодаря такой структуре, машина обретает способность анализировать и даже запоминать различную информацию. Нейронные сети также способны не только анализировать входящую информацию, но и воспроизводить ее из своей памяти. Заинтересовавшимся обязательно к просмотру 2 видео из TED Talks: Видео 1 , Видео 2 ). Другими словами, нейросеть это машинная интерпретация мозга человека, в котором находятся миллионы нейронов передающих информацию в виде электрических импульсов.

Какие бывают нейронные сети?

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

Для чего нужны нейронные сети?

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

Классификация - распределение данных по параметрам. Например, на вход дается набор людей и нужно решить, кому из них давать кредит, а кому нет. Эту работу может сделать нейронная сеть, анализируя такую информацию как: возраст, платежеспособность, кредитная история и тд.

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

Распознавание - в настоящее время, самое широкое применение нейронных сетей. Используется в Google, когда вы ищете фото или в камерах телефонов, когда оно определяет положение вашего лица и выделяет его и многое другое.

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

Что такое нейрон?

Нейрон - это вычислительная единица, которая получает информацию, производит над ней простые вычисления и передает ее дальше. Они делятся на три основных типа: входной (синий), скрытый (красный) и выходной (зеленый). Также есть нейрон смещения и контекстный нейрон о которых мы поговорим в следующей статье. В том случае, когда нейросеть состоит из большого количества нейронов, вводят термин слоя. Соответственно, есть входной слой, который получает информацию, n скрытых слоев (обычно их не больше 3), которые ее обрабатывают и выходной слой, который выводит результат. У каждого из нейронов есть 2 основных параметра: входные данные (input data) и выходные данные (output data). В случае входного нейрона: input=output. В остальных, в поле input попадает суммарная информация всех нейронов с предыдущего слоя, после чего, она нормализуется, с помощью функции активации (пока что просто представим ее f(x)) и попадает в поле output.

Важно помнить , что нейроны оперируют числами в диапазоне или [-1,1]. А как же, вы спросите, тогда обрабатывать числа, которые выходят из данного диапазона? На данном этапе, самый простой ответ - это разделить 1 на это число. Этот процесс называется нормализацией, и он очень часто используется в нейронных сетях. Подробнее об этом чуть позже.

Что такое синапс?

Синапс это связь между двумя нейронами. У синапсов есть 1 параметр - вес. Благодаря ему, входная информация изменяется, когда передается от одного нейрона к другому. Допустим, есть 3 нейрона, которые передают информацию следующему. Тогда у нас есть 3 веса, соответствующие каждому из этих нейронов. У того нейрона, у которого вес будет больше, та информация и будет доминирующей в следующем нейроне (пример - смешение цветов). На самом деле, совокупность весов нейронной сети или матрица весов - это своеобразный мозг всей системы. Именно благодаря этим весам, входная информация обрабатывается и превращается в результат.

Важно помнить , что во время инициализации нейронной сети, веса расставляются в случайном порядке.

Как работает нейронная сеть?

В данном примере изображена часть нейронной сети, где буквами I обозначены входные нейроны, буквой H - скрытый нейрон, а буквой w - веса. Из формулы видно, что входная информация - это сумма всех входных данных, умноженных на соответствующие им веса. Тогда дадим на вход 1 и 0. Пусть w1=0.4 и w2 = 0.7 Входные данные нейрона Н1 будут следующими: 1*0.4+0*0.7=0.4. Теперь когда у нас есть входные данные, мы можем получить выходные данные, подставив входное значение в функцию активации (подробнее о ней далее). Теперь, когда у нас есть выходные данные, мы передаем их дальше. И так, мы повторяем для всех слоев, пока не дойдем до выходного нейрона. Запустив такую сеть в первый раз мы увидим, что ответ далек от правильно, потому что сеть не натренирована. Чтобы улучшить результаты мы будем ее тренировать. Но прежде чем узнать как это делать, давайте введем несколько терминов и свойств нейронной сети.

Функция активации

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

Линейная функция

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

Сигмоид

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

Гиперболический тангенс

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

Тренировочный сет

Тренировочный сет - это последовательность данных, которыми оперирует нейронная сеть. В нашем случае исключающего или (xor) у нас всего 4 разных исхода то есть у нас будет 4 тренировочных сета: 0xor0=0, 0xor1=1, 1xor0=1,1xor1=0.

Итерация

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

Эпоха

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

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

Ошибка

Ошибка - это процентная величина, отражающая расхождение между ожидаемым и полученным ответами. Ошибка формируется каждую эпоху и должна идти на спад. Если этого не происходит, значит, вы что-то делаете не так. Ошибку можно вычислить разными путями, но мы рассмотрим лишь три основных способа: Mean Squared Error (далее MSE), Root MSE и Arctan. Здесь нет какого-либо ограничения на использование, как в функции активации, и вы вольны выбрать любой метод, который будет приносить вам наилучший результат. Стоит лишь учитывать, что каждый метод считает ошибки по разному. У Arctan, ошибка, почти всегда, будет больше, так как он работает по принципу: чем больше разница, тем больше ошибка. У Root MSE будет наименьшая ошибка, поэтому, чаще всего, используют MSE, которая сохраняет баланс в вычислении ошибки.

Root MSE

Arctan

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

Задача

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

Данные:

I1=1, I2=0, w1=0.45, w2=0.78 ,w3=-0.12 ,w4=0.13 ,w5=1.5 ,w6=-2.3.

Решение

H1input = 1*0.45+0*-0.12=0.45

H1output = sigmoid(0.45)=0.61

H2input = 1*0.78+0*0.13=0.78

H2output = sigmoid(0.78)=0.69

O1input = 0.61*1.5+0.69*-2.3=-0.672

O1output = sigmoid(-0.672)=0.33

O1ideal = 1 (0xor1=1)

Error = ((1-0.33)^2)/1=0.45

Результат - 0.33, ошибка - 45%.

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

Использованные ресурсы:

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

Искусственная нейронная сеть обычно обучается с учителем. Это означает наличие обучающего набора (датасета), который содержит примеры с истинными значениями: тегами, классами, показателями.

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

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

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

Искусственная нейронная сеть состоит из трех компонентов:

  • Входной слой;
  • Скрытые (вычислительные) слои;
  • Выходной слой.

Обучение нейросетей происходит в два этапа:

  • Обратное распространение ошибки.

Во время прямого распространения ошибки делается предсказание ответа. При обратном распространении ошибка между фактическим ответом и предсказанным минимизируется.


Прямое распространение

Зададим начальные веса случайным образом:

Умножим входные данные на веса для формирования скрытого слоя:

  • h1 = (x1 * w1) + (x2 * w1)
  • h2 = (x1 * w2) + (x2 * w2)
  • h3 = (x1 * w3) + (x2 * w3)

Выходные данные из скрытого слоя передается через нелинейную функцию (функцию активации), для получения выхода сети:

  • y_ = fn(h1 , h2, h3)

Обратное распространение

  • Суммарная ошибка (total_error) вычисляется как разность между ожидаемым значением «y» (из обучающего набора) и полученным значением «y_» (посчитанное на этапе прямого распространения ошибки), проходящих через функцию потерь (cost function).
  • Частная производная ошибки вычисляется по каждому весу (эти частные дифференциалы отражают вклад каждого веса в общую ошибку (total_loss)).
  • Затем эти дифференциалы умножаются на число, называемое скорость обучения или learning rate (η).

Полученный результат затем вычитается из соответствующих весов.

В результате получатся следующие обновленные веса:

  • w1 = w1 — (η * ∂(err) / ∂(w1))
  • w2 = w2 — (η * ∂(err) / ∂(w2))
  • w3 = w3 — (η * ∂(err) / ∂(w3))

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


Популярный мем о том, как Карлсон стал Data Science разработчиком

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

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

Частные производные

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

Разберем необходимость частных производных на примере.

Предположим, детей попросили бросить дротик в мишень, целясь в центр. Вот результаты:

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

Ошибка нескольких детей может уменьшиться, но общая ошибка все еще увеличивается.

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

Гиперпараметры

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

Скорость обучения (learning rate)

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

С другой стороны, если скорость обучения слишком высока, то сеть очень быстро выдаст ответы. Получится следующее:

Функция активации (activation function)

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

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

Функция потери (loss function)

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

Функция потерь измеряет «насколько хороша» нейронная сеть в отношении данной обучающей выборки и ожидаемых ответов. Она также может зависеть от таких переменных, как веса и смещения.

Функция потерь одномерна и не является вектором, поскольку она оценивает, насколько хорошо нейронная сеть работает в целом.

Некоторые известные функции потерь:

  • Квадратичная (среднеквадратичное отклонение);
  • Кросс-энтропия;
  • Экспоненциальная (AdaBoost);
  • Расстояние Кульбака - Лейблера или прирост информации.

Cреднеквадратичное отклонение – самая простая фукция потерь и наиболее часто используемая. Она задается следующим образом:

Функция потерь в нейронной сети должна удовлетворять двум условиям:

  • Функция потерь должна быть записана как среднее;
  • Функция потерь не должна зависеть от каких-либо активационных значений нейронной сети, кроме значений, выдаваемых на выходе.

Глубокие нейронные сети

Глубокое обучение (deep learning) – это класс алгоритмов машинного обучения, которые учатся глубже (более абстрактно) понимать данные. Популярные алгоритмы нейронных сетей глубокого обучения представлены на схеме ниже.

Популярные алгоритмы нейронных сетей (http://www.asimovinstitute.org/neural-network-zoo)

Более формально в deep learning:

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

Пример

Рассмотрим однослойную нейронную сеть:

Здесь, обучается первый слой (зеленые нейроны), он просто передается на выход.

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

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

Не следует путать с широкой нейронной сетью.

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

Пример:

Изучая английскую грамматику, требуется знать огромное число понятий. В этом случае однослойная широкая нейронная сеть работает намного лучше, чем глубокая нейронная сеть, которая значительно меньше.

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

Главное — баланс

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

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

Проклятье размерности

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

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

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

Компромисс

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

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

Действительно,

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

Следовательно, как правило, невозможно иметь маленькое смещение и маленькую дисперсию одновременно.

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

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

И тут возникает собственно самое важное, что вам для этого потребуется: ДАННЫЕ. Много примеров задач, которые будут подаваться на вход нейросети, и правильные ответы на эти задачи. Нейросеть будет на этом учиться самостоятельно давать эти правильные ответы.

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

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

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

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

Что мы будем делать? Мы попробуем создать простую и совсем маленькую нейронную сеть , которую мы объясним и научим что-нибудь различать. При этом не будем вдаваться в историю и математические дебри (такую информацию найти очень легко) — вместо этого постараемся объяснить задачу (не факт, что удастся) вам и самим себе рисунками и кодом.
Многие из терминов в нейронных сетях связаны с биологией, поэтому давайте начнем с самого начала:

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

Возбудитель может быть и внутренним (например, образ или идея):

А теперь взглянем на основные и упрощенные части мозга :

Мозг вообще похож на кабельную сеть.

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

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

Разумеется, это всё упрощения и обобщения, но благодаря им мы можем описать простую
нейронную сеть:

И описать её формализовано с помощью графа:

Тут требуются некоторые пояснения. Кружки — это нейроны, а линии — это связи между ними, и, чтобы не усложнять на этом этапе, взаимосвязи представляют собой прямое передвижение информации слева направо . Первый нейрон в данный момент активен и выделен серым. Также мы присвоили ему число (1 — если он работает, 0 — если нет). Числа между нейронами показывают вес связи.

Графы выше показывают момент времени сети, для более точного отображения, нужно разделить его на временные отрезки:

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

Когда на них направляют безопасную струю воздуха, кролики, как и люди, моргают:

Эту модель поведения можно нарисовать графами:

Как и в предыдущей схеме, эти графы показывают только тот момент, когда кролик чувствует дуновение, и мы таким образом кодируем дуновение как логическое значение. Помимо этого мы вычисляем, срабатывает ли второй нейрон, основываясь на значении веса. Если он равен 1, то сенсорный нейрон срабатывает, мы моргаем; если вес меньше 1, мы не моргаем: у второго нейрона предел — 1.

Введем еще один элемент — безопасный звуковой сигнал:

Мы можем смоделировать заинтересованность кролика так:

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

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

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

Чтобы обучить кролика, повторим действия:

Для первых трех попыток схемы будут выглядеть так:

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

Мы убрали воздействие воздухом, но кролик все еще моргает, услышав звуковой сигнал! Объяснить это поведение может наша последняя схемка:

Мы обучили кролика реагировать на звук морганием.

В условиях реального эксперимента такого рода может потребоваться более 60 повторений для достижения результата.

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

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

Мы можем изобразить (схематично), что делает кнопка при нажатии следующим образом:

Такую задачу лучше решать целиком, поэтому давайте посмотрим на все возможные результаты, включая правильный:

Нажмите на 3-ю кнопку, чтобы получить свой ужин.

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

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

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

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

Var inputs = ; var weights = ; // Для удобства эти векторы можно назвать

Следующий шаг — создание функции, которая собирает входные значения и веса и рассчитывает значение на выходе:

Function evaluateNeuralNetwork(inputVector, weightVector){ var result = 0; inputVector.forEach(function(inputValue, weightIndex) { layerValue = inputValue*weightVector; result += layerValue; }); return (result.toFixed(2)); } // Может казаться комплексной, но все, что она делает — это сопоставляет пары вес/ввод и добавляет результат

Как и ожидалось, если мы запустим этот код, то получим такой же результат, как в нашей модели или графике…

EvaluateNeuralNetwork(inputs, weights); // 0.00

Живой пример: Neural Net 001 . Следующим шагом в усовершенствовании нашей нейросети будет способ проверки её собственных выходных или результирующих значений сопоставимо реальной ситуации, давайте сначала закодируем эту конкретную реальность в переменную:

Чтобы обнаружить несоответствия (и сколько их), мы добавим функцию ошибки:

Error = Reality - Neural Net Output

С ней мы можем оценивать работу нашей нейронной сети:

Но что более важно — как насчет ситуаций, когда реальность дает положительный результат?

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

Error = Desired Output - Neural Net Output

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

Var input = ; var weights = ; var desiredResult = 1;

И новую функцию:

Function evaluateNeuralNetError(desired,actual) { return (desired — actual); } // After evaluating both the Network and the Error we would get: // "Neural Net output: 0.00 Error: 1"

Живой пример: Neural Net 002 . Подведем промежуточный итог . Мы начали с задачи, сделали её простую модель в виде биологической нейронной сети и получили способ измерения её производительности по сравнению с реальностью или желаемым результатом. Теперь нам нужно найти способ исправления несоответствия — процесс, который как и для компьютеров, так и для людей можно рассматривать как обучение.

Как обучать нейронную сеть?

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

В природе под алгоритмами обучения понимаются изменения физических или химических
характеристик нейронов после проведения экспериментов:

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

Var learningRate = 0.20; // Чем больше значение, тем быстрее будет процесс обучения:)

И что это изменит?

Это изменит веса (прям как у кролика!), особенно вес вывода, который мы хотим получить:

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

Function learn(inputVector, weightVector) { weightVector.forEach(function(weight, index, weights) { if (inputVector > 0) { weights = weight + learningRate; } }); }

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

// Original weight vector: // Neural Net output: 0.00 Error: 1 learn(input, weights); // New Weight vector: // Neural Net output: 0.20 Error: 0.8 // Если это не очевидно, вывод нейронной сети близок к 1 (выдача курицы) — то, чего мы и хотели, поэтому можно сделать вывод, что мы движемся в правильном направлении

Живой пример: Neural Net 003 . Окей, теперь, когда мы движемся в верном направлении, последней деталью этой головоломки будет внедрение повторов .

Это не так уж и сложно, в природе мы просто делаем одно и то же снова и снова, а в коде мы просто указываем количество повторов:

Var trials = 6;

И внедрение в нашу обучающую нейросеть функции количества повторов будет выглядеть так:

Function train(trials) { for (i = 0; i < trials; i++) { neuralNetResult = evaluateNeuralNetwork(input, weights); learn(input, weights); } }

Ну и наш окончательный отчет:

Neural Net output: 0.00 Error: 1.00 Weight Vector: Neural Net output: 0.20 Error: 0.80 Weight Vector: Neural Net output: 0.40 Error: 0.60 Weight Vector: Neural Net output: 0.60 Error: 0.40 Weight Vector: Neural Net output: 0.80 Error: 0.20 Weight Vector: Neural Net output: 1.00 Error: 0.00 Weight Vector: // Chicken Dinner !

Живой пример: Neural Net 004 . Теперь у нас есть вектор веса, который даст только один результат (курицу на ужин), если входной вектор соответствует реальности (нажатие на третью кнопку). Так что же такое классное мы только что сделали?

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

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

  • Механизм хранения изученных весов не предусмотрен, поэтому данная нейронная сеть забудет всё, что знает. При обновлении или повторном запуске кода нужно не менее шести успешных повторов, чтобы сеть полностью обучилась, если вы считаете, что человек или машина будут нажимать на кнопки в случайном порядке… Это займет какое-то время.
  • Биологические сети для обучения важным вещам имеют скорость обучения 1, поэтому нужен будет только один успешный повтор.
  • Существует алгоритм обучения, который очень напоминает биологические нейроны, у него броское название: правило widroff-hoff , или обучение widroff-hoff .
  • Пороги нейронов (1 в нашем примере) и эффекты переобучения (при большом количестве повторов результат будет больше 1) не учитываются, но они очень важны в природе и отвечают за большие и сложные блоки поведенческих реакций. Как и отрицательные веса.

Заметки и список литературы для дальнейшего чтения

Я пытался избежать математики и строгих терминов, но если вам интересно, то мы построили перцептрон , который определяется как алгоритм контролируемого обучения (обучение с учителем) двойных классификаторов — тяжелая штука. Биологическое строение мозга — тема не простая, отчасти из-за неточности, отчасти из-за его сложности. Лучше начинать с Neuroscience (Purves) и Cognitive Neuroscience (Gazzaniga). Я изменил и адаптировал пример с кроликом из Gateway to Memory (Gluck), которая также является прекрасным проводником в мир графов. Еще один шикарный ресурс An Introduction to Neural Networks (Gurney), подойдет для всех ваших нужд, связанных с ИИ.
А теперь на Python! Спасибо Илье Андшмидту за предоставленную версию на Python:

Inputs = weights = desired_result = 1 learning_rate = 0.2 trials = 6 def evaluate_neural_network(input_array, weight_array): result = 0 for i in range(len(input_array)): layer_value = input_array[i] * weight_array[i] result += layer_value print("evaluate_neural_network: " + str(result)) print("weights: " + str(weights)) return result def evaluate_error(desired, actual): error = desired - actual print("evaluate_error: " + str(error)) return error def learn(input_array, weight_array): print("learning...") for i in range(len(input_array)): if input_array[i] > 0: weight_array[i] += learning_rate def train(trials): for i in range(trials): neural_net_result = evaluate_neural_network(inputs, weights) learn(inputs, weights) train(trials)

А теперь на GO! За эту версию благодарю Кирана Мэхера.

Package main import ("fmt" "math") func main() { fmt.Println("Creating inputs and weights ...") inputs:= float64{0.00, 0.00, 1.00, 0.00} weights:= float64{0.00, 0.00, 0.00, 0.00} desired:= 1.00 learningRate:= 0.20 trials:= 6 train(trials, inputs, weights, desired, learningRate) } func train(trials int, inputs float64, weights float64, desired float64, learningRate float64) { for i:= 1; i < trials; i++ { weights = learn(inputs, weights, learningRate) output:= evaluate(inputs, weights) errorResult:= evaluateError(desired, output) fmt.Print("Output: ") fmt.Print(math.Round(output*100) / 100) fmt.Print(" Error: ") fmt.Print(math.Round(errorResult*100) / 100) fmt.Print(" ") } } func learn(inputVector float64, weightVector float64, learningRate float64) float64 { for index, inputValue:= range inputVector { if inputValue > 0.00 { weightVector = weightVector + learningRate } } return weightVector } func evaluate(inputVector float64, weightVector float64) float64 { result:= 0.00 for index, inputValue:= range inputVector { layerValue:= inputValue * weightVector result = result + layerValue } return result } func evaluateError(desired float64, actual float64) float64 { return desired - actual }

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

Немного истории

Впервые понятие искусственных нейронных сетей (ИНС) возникло при попытке смоделировать процессы головного мозга. Первым серьезным прорывом в этой сфере можно считать создание модели нейронных сетей МакКаллока-Питтса в 1943 году. Учеными впервые была разработана модель искусственного нейрона. Ими также была предложена конструкция сети из этих элементов для выполнения логических операций. Но самое главное, учеными было доказано, что подобная сеть способна обучаться.

Следующим важным шагом стала разработка Дональдом Хеббом первого алгоритма вычисления ИНС в 1949 году, который стал основополагающем на несколько последующих десятилетий. В 1958 году Фрэнком Розенблаттом был разработан парцептрон - система, имитирующая процессы головного мозга. В свое время технология не имела аналогов и до сих пор является основополагающей в нейронных сетях. В 1986 году практически одновременно, независимо друг от друга американскими и советскими учеными был существенно доработан основополагающий метод обучения многослойного перцептрона . В 2007 году нейронные сети перенесли второе рождение. Британский информатик Джеффри Хинтоном впервые разработал алгоритм глубокого обучения многослойных нейронных сетей, который сейчас, например, используется для работы беспилотных автомобилей.

Коротко о главном

В общем смысле слова, нейронные сети - это математические модели, работающие по принципу сетей нервных клеток животного организма. ИНС могут быть реализованы как в программируемые, так и в аппаратные решения. Для простоты восприятия нейрон можно представить, как некую ячейку, у которой имеется множество входных отверстий и одно выходное. Каким образом многочисленные входящие сигналы формируются в выходящий, как раз и определяет алгоритм вычисления. На каждый вход нейрона подаются действенные значения, которые затем распространяются по межнейронным связям (синопсисам). У синапсов есть один параметр - вес, благодаря которому входная информация изменяется при переходе от одного нейрона к другому. Легче всего принцип работы нейросетей можно представить на примере смешения цветов. Синий, зеленый и красный нейрон имеют разные веса. Информация того нейрона, вес которого больше будет доминирующей в следующем нейроне.

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

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

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

Сегодняшнее положение

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

На сегодняшний день рынок нейронных сетей огромен - это миллиарды и миллиарды долларов. Как показывает практика, большинство технологий нейросетей по всему миру мало отличаются друг от друга. Однако применение нейросетей - это очень затратное занятие, которое в большинстве случаев могут позволить себе только крупные компании. Для разработки, обучения и тестирования нейронных сетей требуются большие вычислительные мощности, очевидно, что этого в достатке имеется у крупных игроков на рынке ИТ. Среди основных компаний, ведущих разработки в этой области можно отметить подразделение Google DeepMind, подразделение Microsoft Research, компании IBM, Facebook и Baidu.

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

Почему нейросети еще далеки до человеческого мозга?

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

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

Итог

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

Для тех, кто хочет знать больше

  • Большая нейронная война: что на самом деле затевает Google
  • Как когнитивные компьютеры могут изменить наше будущее