layer-oriented-deep-learning-network-js
Version:
A feed-forward neural network with injectable layers, activation functions, and optimizers.
93 lines (79 loc) • 4.51 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var OutputLayer = function () {
function OutputLayer(nodeCount, activationFunction, optimizer) {
_classCallCheck(this, OutputLayer);
this.nodeCount = nodeCount;
this.outputs = new Float64Array(nodeCount);
this.activationFunction = activationFunction.xToY;
this.activationFunctionDerivative = activationFunction.yToSlope;
this.errorGradients = new Float64Array(nodeCount);
this.optimizer = optimizer;
}
_createClass(OutputLayer, [{
key: "setInputLayer",
value: function setInputLayer(inputLayer) {
this.inputLayer = inputLayer;
this.inputCount = inputLayer.nodeCount;
this.inputNodeCount = this.inputCount + 1; //Add 1 for the bias node
this.weights = new Float64Array(this.nodeCount * this.inputNodeCount);
this.weightErrorGradients = new Float64Array(this.nodeCount * this.inputNodeCount);
for (var weightI = 0, weightLen = this.weights.length; weightI < weightLen; weightI++) {
this.weights[weightI] = Math.random() - 0.5; //@TODO would a gaussian distribution work better?
}
}
}, {
key: "feedForward",
value: function feedForward() {
this.inputs = this.inputLayer.outputs;
//Defining these locally speeds up the loop below by reducing object property access
var inputNodeCount = this.inputNodeCount;
var weights = this.weights;
var inputs = this.inputs;
var activationFunction = this.activationFunction;
var outputs = this.outputs;
var nodeCount = this.nodeCount;
var inputCount = this.inputCount;
for (var neuronI = 0; neuronI < nodeCount; neuronI++) {
var sum = 0;
for (var inputI = 0; inputI < inputCount; inputI++) {
sum += inputs[inputI] * weights[neuronI * inputNodeCount + inputI];
}
sum += weights[neuronI * inputNodeCount + inputCount]; //Bias node that always inputs "1"
outputs[neuronI] = activationFunction(sum);
}
return outputs;
}
}, {
key: "backPropagateCalculateErrorGradient",
value: function backPropagateCalculateErrorGradient(targetOutputs) {
//Defining these locally speeds up the loop below by reducing object property access
var nodeCount = this.nodeCount;
var errorGradients = this.errorGradients;
var outputs = this.outputs;
var activationFunctionDerivative = this.activationFunctionDerivative;
var inputNodeCount = this.inputNodeCount;
var inputCount = this.inputCount;
var inputs = this.inputs;
for (var neuronI = 0; neuronI < nodeCount; neuronI++) {
var activationErrorGradient = (outputs[neuronI] - targetOutputs[neuronI]) * activationFunctionDerivative(outputs[neuronI]);
errorGradients[neuronI] = activationErrorGradient;
for (var inputI = 0; inputI < inputCount; inputI++) {
this.weightErrorGradients[neuronI * inputNodeCount + inputI] = inputs[inputI] * activationErrorGradient;
}
this.weightErrorGradients[neuronI * inputNodeCount + inputI] = activationErrorGradient; //Bias node
}
}
}, {
key: "backPropagateOptimize",
value: function backPropagateOptimize() {
this.optimizer.optimizeWeights(this.weights, this.weightErrorGradients);
}
}]);
return OutputLayer;
}();
exports.default = OutputLayer;