Нейронные сети — XOR [JS]

в 18:03, , рубрики: javascript, нейронные сети, Учебный процесс в IT

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

image

О задаче

Часто, для того чтобы продемонстрировать ограниченные возможности однослойных персептронов при решении задач прибегают к рассмотрению так называемой проблемы XOR – исключающего ИЛИ. Данная логическая функция принимает два аргумента, которые могут быть 1 или 0. Функция принимает значение 1 когда один из двух аргументов 1, а другой 0. Если же оба равняются 0 или 1, то в результате мы получаем 0. На такое однослойная НС не способна.

image

Модель

Посмотрите внимательно на данную картинку.
Нейронные сети — XOR [JS] - 3

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

Программируем

Программировать будем на JavaScript.
Для начала нам необходимо написать все необходимые массивы и переменные: синапсы, входы, выход и нейроны.

{
var enters = new Array(2); // 2 входа
var hidden_layer = new Array(2); // два скрытых нейрона
var synapses_hidden = [[0.3, 1.3], [0.5,0.1]]; // от входов к скрытым нейронам
var synapses_output = [0.5, 0.1]; // от скрытых нейронов к выходу
var output = 0; // выход

Теперь создадим матрицу обучения сети.

var learn = [[0,0],[0,1],[1,0],[1,1]];
var learn_answers = [0,1,1,0];    
}

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

function sum(){
    for ( var i = 0; i < hidden_layer.length; i++ ){
        hidden_layer[i] = 0;
        for ( var j = 0; j < enters.length; j++ )
            hidden_layer[i] += synapses_hidden[j][i] * enters[j];
        if ( hidden_layer[i] > 0.5 ) hidden_layer[i] = 1; else hidden_layer[i] = 0;
    }
    output = 0;
    for ( var i = 0; i < hidden_layer.length; i++ )
        output += synapses_output[i] * hidden_layer[i];
    if ( output > 0.5 ) output = 1; else output = 0;
}
Обратное распространение ошибки

Уйдём ненадолго от программирования. Метод обратного распространения ошибки похож на delta правило. То есть сначала мы вычисляем ошибку(правильный ответ минус ответ сети), и затем меняем веса по формуле: w = w_last + err * n * x
Где w_last — прошлый вес, err — ошибка, n — скорость обучения и x — входной сигнал
В данном случае мы передаём ошибку по таким же связям, откуда пришёл сигнал. То есть от выхода к входу. Ещё необходимо завести счётчик ошибок обрабатывающего слоя и глобальную ошибку(gError = Math.abs(lErr))

var gError = 0; // глобальная ошибка
var errors = new Array(hidden_layer.length); // слой ошибок
do {
    gError = 0; // обнуляем
    for ( var p = 0; p < learn.length; p++ ){
        for ( var i = 0; i < enters.length; i++ )
            enters[i] = learn[p][i]; // подаём об.входы на входы сети
        sum(); // запускаем распространение сигнала
        var error = learn_answers[p] - output; // получаем ошибку
        gError += Math.abs(error); // записываем в глобальную
        for ( var i = 0; i < errors.length; i++ ) 
            errors[i] = error * synapses_output[i]; // передаём ошибку на слой ошибок
          // по связям к выходу
        for ( var i = 0; i < enters.length; i++ ){
            for ( var j = 0; j < hidden_layer.length; j++ )
                synapses_hidden[i][j] += 0.1 * errors[i] * enters[j]; // меняем веса
        }
        for ( var i = 0; i < synapses_output.length; i++ )
            synapses_output[i] += 0.1 * error * hidden_layer[i]; // меняем веса
    } 
} while(gError != 0);

Теперь пишем скрипт на запуск сети:

for ( var p = 0; p < learn.length; p++ ){
    for ( var i = 0; i < enters.length; i++ )
        enters[i] = learn[p][i]; // записываем входы
    sum(); // распространяем сигнал
    document.write(output + "<br/>"); // выводим ответы
}

Мы получим такой результат:
0 1 1 0

Если вам интересно — демонстрация обучения и написание сети на видео: youtu.be/8OmeeBu6B78

Финал

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

Автор: EmeraldSoft

Источник

Поделиться

* - обязательные к заполнению поля