ttezel / nn

Fast and simple Neural Network for node.js
106 stars 19 forks source link

SGD #8

Open i-salameh95 opened 10 months ago

i-salameh95 commented 10 months ago

Hello, I have used this package, its awesome but I think there is an issue with NN.prototype.backPropagate in gradient descent u should use the derivative of the activation function of the hidden layer, but in the code u don't use differentiate at all from the file activation, it seems that u put the derivative of sigmoid, for both hidden and output layer.... which is not always nice.

take an example like x^2 : if u train it on the settings u provided it will fail, because we need the output to be as it is ..

i-salameh95 commented 10 months ago

this is the updated version: linear for output layer and activation from settings for the hidden layer

 NN.prototype.backPropagate = function (desiredOutput) {
        var self = this
        this.errorSigs = [];

        var outputLayerIndex = this.outputs.length - 1;
        var outputLayer = this.outputs[outputLayerIndex];
        var prevLayerOutput = this.outputs[outputLayerIndex - 1];

        var numOutputNodes = outputLayer.length

        this.errorSigs[outputLayerIndex] = [];

        // initialize changes array if needed
        if (!this.changes[outputLayerIndex])
            this.initializeChanges();

        // update weights for output layer
        for (var n = 0; n < numOutputNodes; n++) {

            var desiredOut = desiredOutput[n];
            var neuronOut = outputLayer[n];
            var neuronError = desiredOut - neuronOut;
            // determine error signal value
            var errorSig = neuronError; // this is updated by israa
            self.errorSigs[outputLayerIndex][n] = errorSig

            // update neuron connection weights
            for (var p = 0; p < prevLayerOutput.length; p++) {
                var change = self.changes[outputLayerIndex][n][p];
                var weightDelta = self.opts.learningRate * errorSig * prevLayerOutput[p];

                change = weightDelta + (self.opts.momentum * change)

                //console.log('L%s:N%s neuronError %s desiredOut %s, neuronOut %s, errorSig: %s, p: %s, change for p: %s', outputLayerIndex, n, neuronError, desiredOut, neuronOut, errorSig, p, change)

                this.weights[outputLayerIndex][n][p] += change
                this.changes[outputLayerIndex][n][p] = change
            }

            // update neuron bias
            var biasDelta = self.opts.learningRate * errorSig

            this.biases[outputLayerIndex][n] += biasDelta
        }

        var lastHiddenLayerNum = outputLayerIndex - 1

        // iterate backwords thru the rest of the hidden layers
        for (var layer = lastHiddenLayerNum; layer > 0; layer--) {
            var prevLayerOutput = this.outputs[layer - 1];
            var nextLayerSize = this.outputs[layer + 1].length;

            this.errorSigs[layer] = [];

            // determine error of each neuron's output
            for (var n = 0; n < this.outputs[layer].length; n++) {
                var neuronOut = this.outputs[layer][n];

                // determine weighted sum of next layer's errorSigs
                var nextLayerErrorSum = 0

                // determine errors for each connection to this neuron
                for (var d = 0; d < nextLayerSize; d++) {
                    nextLayerErrorSum += this.errorSigs[layer + 1][d] * (self.weights[layer + 1][d][n] || 0)
                }

                // determine error sig value for this neuron
                var errorSig = nextLayerErrorSum * activationFns[this.opts.activation].differentiate(this.netInput[layer][n]); // updated

                this.errorSigs[layer][n] = errorSig

                // update neuron connection weights
                for (var p = 0; p < prevLayerOutput.length; p++) {
                    var change = this.changes[layer][n][p];
                    var weightDelta = this.opts.learningRate * errorSig * prevLayerOutput[p];

                    change = weightDelta + (this.opts.momentum * change)

                    //console.log('change hidden layer L%s:N%s:p:%s : %s', layer, n, p, change)

                    this.weights[layer][n][p] += change;
                    this.changes[layer][n][p] = change;
                }

                // update neuron bias
                this.biases[layer][n] += this.opts.learningRate * errorSig
            }
        }
    }