Обратное обучение

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

Я следил за учебниками на нескольких сайтах, следя за ними как можно ближе: http://galaxy.agh.edu.pl/~vlsi/AI/backp_t_en/backprop.html backpropagation

Вот ссылка на исходный код: http://jsfiddle.net/Wkrgu/5/

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

// Once all gradients are calculated, work forward and calculate
// the new weights. w = w + (lr * df/de * in)
for(i = 0; i < this._layers.length; i++) {

    // For each neuron in each layer, ...
    for(j = 0; j < this._layers[i]._neurons.length; j++) {
    neuron = this._layers[i]._neurons[j];
    // Modify the bias.
    neuron.bias += this.options.learningRate * neuron.gradient;

    // For each weight, ...
    for(k = 0; k < neuron.weights.length; k++) {

        // Modify the weight by multiplying the weight by the
        // learning rate and the input of the neuron preceding.
        // If no preceding layer, then use the input layer.
        neuron.deltas[k] = this.options.learningRate * neuron.gradient * (this._layers[i-1] ? this._layers[i-1]._neurons[k].input : input[k]);
        neuron.weights[k] += neuron.deltas[k];
        neuron.weights[k] += neuron.momentum * neuron.previousDeltas[k];

        }
        // Set previous delta values.
    neuron.previousDeltas = neuron.deltas.slice();
    }
}

Свойство градиента определяется как:

error = 0.0;

// So for every neuron in the following layer, get the 
// weight corresponding to this neuron.
for(k = 0; k < this._layers[i+1]._neurons.length; k++) {

    // And multiply it by that neuron gradient
    // and add it to the error calculation.
    error += this._layers[i+1]._neurons[k].weights[j] * this._layers[i+1]._neurons[k].gradient;
}

// Once you have the error calculation, multiply it by
// the derivative of the activation function to get
// the gradient of this neuron.
neuron.gradient = output * (1 - output) * error;

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

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

a.train([0,0], [0]);
a.train([0,1], [1]);
a.train([1,0], [1]);

console.log(a.input([0,0])); // [ 0.9960981505402279 ]
console.log(a.input([1,0])); // [ 0.9957925569461975 ]
console.log(a.input([0,1])); // [ 0.9964499429402672 ]
console.log(a.input([1,1])); // [ 0.996278252201647 ]

UPDATE: Вот ссылка на фиксированный код: http://jsfiddle.net/adamthorpeg/aUF4c/3/ Примечание. Не тренируется до тех пор, пока ошибка не допустима для каждого входа, поэтому иногда вы получаете неточные результаты, когда достигнете допустимой ошибки для одного идеального значения. Чтобы полностью обучить его, обучение должно продолжаться до тех пор, пока не будут допущены все ошибки.

Ответ 1

Я нашел ответ на свою проблему. Ответ двоякий:

Во-первых, сеть страдает от проблемы "катастрофического забывания". Я тренировал его на одной идеальной паре значений/входных данных за раз, а не на велосипеде по каждой паре и тренировал ее по одной эпохе за раз.

Во-вторых, в строке:

neuron.deltas[k] = this.options.learningRate * neuron.gradient * (this._layers[i-1] ? this._layers[i-1]._neurons[k].input : input[k]);

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

neuron.deltas[k] = this.options.learningRate * neuron.gradient * (this._layers[i-1] ? this._layers[i-1]._neurons[k].output : input[k]);

Этот ресурс был неоценим: http://blog.zabarauskas.com/backpropagation-tutorial/