В этой статье будет показано, как создать и обучить нейронную сеть на JavaScript, используя Synaptic.js. Этот пакет позволяет реализовывать глубокое обучение в Node.js и в браузере. Будет создана простейшая возможная нейронная сеть — та, которой удается выполнить XOR операцию.
Перевод статьи «How to create a Neural Network in JavaScript in only 30 lines of code». Автор — Per Harald Borgen. Ссылка на оригинал — в подвале статьи.
Вы можете видеть созданный мною интерактивный Scrimba туториал:
В Scribma туториале вы можете поиграться с сетью. Но перед тем, как посмотреть на код, давайте вспомним основы нейронных сетей.
Нейроны и синапсы
Самый первый строительный элемент любой нейронной сети — нейрон. Он похож на функцию — берет несколько входных значений и возвращает результат алгебраических действий над ними.
Существует множество типов нейронов. Наша сеть использует нейрон с сигмоидной функцией активации, которая принимает любое число и трансформирует его в значение, лежащее в диапазоне от 0 до 1.
Круг ниже показывает сигмоидный нейрон. На входе — 5, на выходе — 1. Стрелочки называются синапсами, они соединяют нейрон с другими слоями в нейросети.
Почему красное число это 5? Это сумма из трех синапсов, которые соединены с нейроном. Это показано тремя стрелочками слева от нейрона. Поясню сказанное.
Слева можно видеть два плюс одно значения. Зеленые числа — значения 1 и 0. Параметр сдвига -2 — коричневое число. Сначала входные числа умножаются на соответствующие им веса 7 и 3 соответственно. Значения весов представляют синие числа.
Наконец мы добавляем параметр сдвига и получаем итоговой результат 5 — красное число. Это и есть вход для нашего искусственного нейрона.
Такак мы работаем с сигмоидным нейроном, который переводит любое входное значение на отрезок от 0 до 1, выход преобразуется в 1.
Если соединить нейроны друг с другом, получится нейронная сеть. Прямое прохождение от входа к выходу осуществляется при помощи соединенных друг с другом через синапсы нейронов. Это выглядит следующим образом.
Задача нейронной сети — обучаться находить общие признаки в данных, например, распознавать рукописные символы или спам на электронной почте. Чтобы осуществить эту задачу, требуется точная настройка весов и параметров сдвига во всей сети. Это синие и коричневые числа в примере сверху.
Во время тренировки мы просто показываем сети большое количество примеров — рукописных символов или просто картинок. На основе этого сеть предсказывает ответ.
После каждого предсказания высчитываем, насколько правильным оно оказалось. В соответствии с этим корректируем значения весов и параметров сдвига так, чтобы в следующий раз сеть была более точна. Такая схема называется обратным распространением. Если сделать это тысячи раз, ваша сеть будет обобщать хорошо.
Подробное техническое рассмотрение обратного распространения ошибки.
Код нейросети JavaScript
Вы получили базовое представление о нейронных сетях, теперь самое время посмотреть на реализацию. Первое, что необходимо сделать, это создать слои. Это делается при помощи функции new Layer в synaptic. Число в скобках определяет, сколько каждый слой должен содержать нейронов.
Если вам трудно представить, что такое слой, посмотрите еще на скринкаст.
const { Layer, Network } = window.synaptic;
var inputLayer = new Layer(2); var hiddenLayer = new Layer(3); var outputLayer = new Layer(1);
Далее соединяем эти слои вместе и создаем инстанс новой сети, как показано ниже:
inputLayer.project(hiddenLayer); hiddenLayer.project(outputLayer);
var myNetwork = new Network({ input: inputLayer, hidden: [hiddenLayer], output: outputLayer });
У нас получилась сеть с 2-3-1 нейронами в входном, скрытом и выходном слое, соответственно. Архитектура этой сети показана ниже:
Теперь давайте обучим нашу сеть:
// train the network - learn XOR
var learningRate = .3;
for (var i = 0; i < 20000; i++) { // 0,0 => 0 myNetwork.activate([0,0]); myNetwork.propagate(learningRate, [0]);
// 0,1 => 1 myNetwork.activate([0,1]); myNetwork.propagate(learningRate, [1]);
// 1,0 => 1 myNetwork.activate([1,0]); myNetwork.propagate(learningRate, [1]);
// 1,1 => 0 myNetwork.activate([1,1]); myNetwork.propagate(learningRate, [0]); }
Запускаем сеть 20 000 раз. Каждый раз распространяемся в прямом и обратном направлении четыре раза, проходя через четыре возможных входа для этой сети: [0,0], [0,1], [1,0], [1,1].
Начинаем с команды myNetwork.activate([0,0]), где [0,0] — данные, которые посылаются в сеть. Это прямое распространение, которое также называется активизацией сети. После каждого прямого распространения требуется сделать и обратное, тогда сеть обновит свои веса и свдиг.
Обратное распротстранение осуществляется командой myNetwork.propagate(learningRate, [0]). Параметр learningRate — константа, которая говорит сети, насколько каждый раз нужно изменять веса. Второй параметр — 0 представляет корректный ответ для заданного входа [0,0].
Далее сеть сравнивает свое предсказание с правильной меткой. На этом шаге определяется, было ли предсказание сделано правильно.
Сеть использует сравнение в качестве базиса для корректировки значений весов и сдвига. Поэтому в следующий раз предсказание будет немного точнее.
После выполнения 20 000 итераций в цикле for мы можем посмотреть, насколько хорошо обучилась сеть, при помощи активизации сети со всеми четырьмя возможными входами:
console.log(myNetwork.activate([0,0])); -> [0.015020775950893527]
console.log(myNetwork.activate([0,1])); ->[0.9815816381088985]
console.log(myNetwork.activate([1,0])); -> [0.9871822457132193]
console.log(myNetwork.activate([1,1])); -> [0.012950087641929467]
Если округлить эти значения до ближайшего целого числа, получим корректные ответы для XOR операций!
Как-то так. Хотя мы только немного коснулись нейронных сетей, этой статьи должно быть достаточно, чтобы поиграться с Synaptic и начать изучение области самостоятельно. Этот репозиторий содержит много хороших туториалов.
Наконец, когда выучите что-нибудь новое, обязательно поделитесь звоими знаниями с помощью скринкаста Scrimba и написания статьи!
Хуета