src/network.js
/**
     * Do a full supervised training round of the network. Does a forward pass, calculates error, and does a backpropagation of errors. NOTE: Lots of side-effects here!
     * @param {Array.<number>} input The input for the network
     * @param {Array.<number>} target The correct output for the given input, i.e. the target towards which the network should learn
     * @param {number} learningRate Learning rate of the network, typically 1e-x where x ~= 2..5
     */
Do a full supervised training round of the network. Does a forward pass, calculates error, and does a backpropagation of errors. NOTE: Lots of side-effects here.
@param {Array.} input The input for the network
@param {Array.} target The correct output for the given input, i.e. the target towards which the network should learn
@param {number} learningRate Learning rate of the network, typically 1e-x where x ~= 2..5
Do a full supervised training round of the network . Does a forward pass calculates error and does a backpropagation of errors . NOTE : Lots of side - effects here . @param { Array . } input The input for the network @param { Array . } target The correct output for the given input i . e . the target towards which the network should learn @param { number } learningRate Learning rate of the network typically 1e - x where x ~ = 2 .. 5
doTrainingRound(input, target, learningRate) {
        let predictions = this.forwardPass(input); 
        let partials = (layer, nextLayer) =>
            layer.map((neuron, index) => {
                let error;
                if (nextLayer) {
                    error = nextLayer
                        .map(
                            neuron =>
                                neuron.weights[index] * neuron.getPartial()
                        )
                        .reduce((sum, value) => sum + value);
                } else {
                    error = predictions[index] - target[index];
                }
                let partial =
                    error *
                    neuron.nonlinearity.backward(neuron.getActivation());
                neuron.setPartial(partial);
            });
        partials(this.outputLayer, null); 
        for (let index = this.hiddenLayers.length - 1; index >= 0; index--) {
            if (index === this.hiddenLayers.length - 1) {
                partials(this.hiddenLayers[index], this.outputLayer);
            } else {
                partials(
                    this.hiddenLayers[index],
                    this.hiddenLayers[index + 1]
                );
            }
        }
        let updateWeights = layer =>
            layer.map(neuron => {
                neuron.setWeights(
                    neuron.weights.map((weight, index) => {
                        return (
                            weight +
                            -1 *
                                learningRate *
                                neuron.getInputs()[index] *
                                neuron.getPartial()
                        );
                    })
                );
                neuron.setBias(
                    neuron.bias + -1 * learningRate * neuron.getPartial()
                );
            });
        updateWeights(this.outputLayer);
        this.hiddenLayers.forEach(updateWeights);
        let totalError =
            1 /
            predictions.length *
            _.sum(
                predictions.map((value, index) => {
                    return Math.pow(value - target[index], 2);
                })
            );
        return totalError;
    }
doTrainingRound ( input , target , learningRate ) { let predictions = this . forwardPass ( input ) ; let partials = ( layer , nextLayer ) => layer . map ( ( neuron , index ) => { let error ; if ( nextLayer ) { error = nextLayer . map ( neuron => neuron . weights [ index ] * neuron . getPartial ( ) ) . reduce ( ( sum , value ) => sum + value ) ; } else { error = predictions [ index ] - target [ index ] ; } let partial = error * neuron . nonlinearity . backward ( neuron . getActivation ( ) ) ; neuron . setPartial ( partial ) ; } ) ; partials ( this . outputLayer , null ) ; for ( let index = this . hiddenLayers . length - 1 ; index >= 0 ; index -- ) { if ( index === this . hiddenLayers . length - 1 ) { partials ( this . hiddenLayers [ index ] , this . outputLayer ) ; } else { partials ( this . hiddenLayers [ index ] , this . hiddenLayers [ index + 1 ] ) ; } } let updateWeights = layer => layer . map ( neuron => { neuron . setWeights ( neuron . weights . map ( ( weight , index ) => { return ( weight + - 1 * learningRate * neuron . getInputs ( ) [ index ] * neuron . getPartial ( ) ) ; } ) ) ; neuron . setBias ( neuron . bias + - 1 * learningRate * neuron . getPartial ( ) ) ; } ) ; updateWeights ( this . outputLayer ) ; this . hiddenLayers . forEach ( updateWeights ) ; let totalError = 1 / predictions . length * _ . sum ( predictions . map ( ( value , index ) => { return Math . pow ( value - target [ index ] , 2 ) ; } ) ) ; return totalError ; }
Do a full supervised training round of the network.
Do a full supervised training round of the network .
// returns array of final output layer activations // Calculate partial derivatives for the layer's neurons with respect to the error // On hidden layer: // assume partial term saved on neuron state on previous backprop // On output layer: // ugly side-effect code! // Last hidden layer, use output layer // Else, in general case, use the next layer // We now have the partials, let's update the weights to fix errors // Start with output layer alone