Comparar commits
9 Commits
master
...
typescript
| Autor | SHA1 | Data | |
|---|---|---|---|
| e669577218 | |||
| f0701c593c | |||
| ab5a872f19 | |||
| c70c076b41 | |||
| db0eca8385 | |||
| 02a9df3f8d | |||
| a5ad5b401b | |||
| 8ddc9a8f2c | |||
| 42264f3483 |
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"version": "0.1.0",
|
||||
"command": "gulp",
|
||||
"isShellCommand": true,
|
||||
"tasks": [
|
||||
{
|
||||
"taskName": "node",
|
||||
"problemMatcher": "$tsc"
|
||||
},
|
||||
{
|
||||
"taskName": "test",
|
||||
"isTestCommand": true,
|
||||
"problemMatcher": "$tsc"
|
||||
},
|
||||
{
|
||||
"isBuildCommand": true,
|
||||
"taskName": "build",
|
||||
"problemMatcher": "$tsc"
|
||||
},
|
||||
{
|
||||
"taskName": "default",
|
||||
"problemMatcher": "$tsc"
|
||||
},
|
||||
{
|
||||
"taskName": "min",
|
||||
"problemMatcher": "$tsc"
|
||||
},
|
||||
{
|
||||
"taskName": "debug",
|
||||
"problemMatcher": "$tsc"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -76,6 +76,7 @@ Now you can start to create networks, train them, or use built-in networks from
|
||||
- **gulp debug**: builds the bundle `/dist/synaptic.js` with sourcemaps.
|
||||
- **gulp dev**: same as `gulp debug`, but watches the source files and rebuilds when any change is detected.
|
||||
- **gulp test**: runs all the tests.
|
||||
- **gulp node**: builds the typescipt code into `/src`
|
||||
|
||||
###Examples
|
||||
|
||||
|
||||
externo
+8
@@ -0,0 +1,8 @@
|
||||
import hopfield = require('./architect/Hopfield');
|
||||
import lstm = require('./architect/LSTM');
|
||||
import lsm = require('./architect/Liquid');
|
||||
import perceptron = require('./architect/Perceptron');
|
||||
export declare var LSTM: typeof lstm.LSTM;
|
||||
export declare var Liquid: typeof lsm.Liquid;
|
||||
export declare var Hopfield: typeof hopfield.Hopfield;
|
||||
export declare var Perceptron: typeof perceptron.Perceptron;
|
||||
externo
+10
@@ -0,0 +1,10 @@
|
||||
var hopfield = require('./architect/Hopfield');
|
||||
var lstm = require('./architect/LSTM');
|
||||
var lsm = require('./architect/Liquid');
|
||||
var perceptron = require('./architect/Perceptron');
|
||||
exports.LSTM = lstm.LSTM;
|
||||
exports.Liquid = lsm.Liquid;
|
||||
exports.Hopfield = hopfield.Hopfield;
|
||||
exports.Perceptron = perceptron.Perceptron;
|
||||
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcmNoaXRlY3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsSUFBTyxRQUFRLFdBQVcsc0JBQXNCLENBQUMsQ0FBQztBQUNsRCxJQUFPLElBQUksV0FBVyxrQkFBa0IsQ0FBQyxDQUFDO0FBQzFDLElBQU8sR0FBRyxXQUFXLG9CQUFvQixDQUFDLENBQUM7QUFDM0MsSUFBTyxVQUFVLFdBQVcsd0JBQXdCLENBQUMsQ0FBQztBQUUzQyxZQUFJLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQztBQUNqQixjQUFNLEdBQUcsR0FBRyxDQUFDLE1BQU0sQ0FBQztBQUNwQixnQkFBUSxHQUFHLFFBQVEsQ0FBQyxRQUFRLENBQUM7QUFDN0Isa0JBQVUsR0FBRyxVQUFVLENBQUMsVUFBVSxDQUFDIiwiZmlsZSI6InNyYy9hcmNoaXRlY3QuanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgaG9wZmllbGQgPSByZXF1aXJlKCcuL2FyY2hpdGVjdC9Ib3BmaWVsZCcpO1xuaW1wb3J0IGxzdG0gPSByZXF1aXJlKCcuL2FyY2hpdGVjdC9MU1RNJyk7XG5pbXBvcnQgbHNtID0gcmVxdWlyZSgnLi9hcmNoaXRlY3QvTGlxdWlkJyk7XG5pbXBvcnQgcGVyY2VwdHJvbiA9IHJlcXVpcmUoJy4vYXJjaGl0ZWN0L1BlcmNlcHRyb24nKTtcblxuZXhwb3J0IHZhciBMU1RNID0gbHN0bS5MU1RNO1xuZXhwb3J0IHZhciBMaXF1aWQgPSBsc20uTGlxdWlkO1xuZXhwb3J0IHZhciBIb3BmaWVsZCA9IGhvcGZpZWxkLkhvcGZpZWxkO1xuZXhwb3J0IHZhciBQZXJjZXB0cm9uID0gcGVyY2VwdHJvbi5QZXJjZXB0cm9uO1xuIl0sInNvdXJjZVJvb3QiOiIvc291cmNlLyJ9
|
||||
externo
+12
@@ -0,0 +1,12 @@
|
||||
import network = require('../network');
|
||||
import trainer = require('../trainer');
|
||||
export declare class Hopfield extends network.Network {
|
||||
trainer: trainer.Trainer;
|
||||
constructor(size: number);
|
||||
learn(patterns: any): {
|
||||
error: number;
|
||||
iterations: number;
|
||||
time: number;
|
||||
};
|
||||
feed(pattern: any): any[];
|
||||
}
|
||||
externo
+47
@@ -0,0 +1,47 @@
|
||||
var __extends = this.__extends || function (d, b) {
|
||||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
|
||||
function __() { this.constructor = d; }
|
||||
__.prototype = b.prototype;
|
||||
d.prototype = new __();
|
||||
};
|
||||
var network = require('../network');
|
||||
var trainer = require('../trainer');
|
||||
var layer = require('../layer');
|
||||
var Hopfield = (function (_super) {
|
||||
__extends(Hopfield, _super);
|
||||
function Hopfield(size) {
|
||||
var inputLayer = new layer.Layer(size);
|
||||
var outputLayer = new layer.Layer(size);
|
||||
inputLayer.project(outputLayer, layer.Layer.connectionType.ALL_TO_ALL);
|
||||
_super.call(this, {
|
||||
input: inputLayer,
|
||||
hidden: [],
|
||||
output: outputLayer
|
||||
});
|
||||
this.trainer = new trainer.Trainer(this);
|
||||
}
|
||||
Hopfield.prototype.learn = function (patterns) {
|
||||
var set = [];
|
||||
for (var p in patterns)
|
||||
set.push({
|
||||
input: patterns[p],
|
||||
output: patterns[p]
|
||||
});
|
||||
return this.trainer.train(set, {
|
||||
iterations: 500000,
|
||||
error: .00005,
|
||||
rate: 1
|
||||
});
|
||||
};
|
||||
Hopfield.prototype.feed = function (pattern) {
|
||||
var output = this.activate(pattern);
|
||||
var patterns = [];
|
||||
for (var i in output)
|
||||
patterns[i] = output[i] > .5 ? 1 : 0;
|
||||
return patterns;
|
||||
};
|
||||
return Hopfield;
|
||||
})(network.Network);
|
||||
exports.Hopfield = Hopfield;
|
||||
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcmNoaXRlY3QvSG9wZmllbGQudHMiXSwibmFtZXMiOlsiSG9wZmllbGQiLCJIb3BmaWVsZC5jb25zdHJ1Y3RvciIsIkhvcGZpZWxkLmxlYXJuIiwiSG9wZmllbGQuZmVlZCJdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsSUFBTyxPQUFPLFdBQVksWUFBWSxDQUFDLENBQUM7QUFDeEMsSUFBTyxPQUFPLFdBQVksWUFBWSxDQUFDLENBQUM7QUFDeEMsSUFBTyxLQUFLLFdBQVksVUFBVSxDQUFDLENBQUM7QUFHcEMsSUFBYSxRQUFRO0lBQVNBLFVBQWpCQSxRQUFRQSxVQUF3QkE7SUFHM0NBLFNBSFdBLFFBQVFBLENBR1BBLElBQVlBO1FBQ3RCQyxJQUFJQSxVQUFVQSxHQUFHQSxJQUFJQSxLQUFLQSxDQUFDQSxLQUFLQSxDQUFDQSxJQUFJQSxDQUFDQSxDQUFDQTtRQUN2Q0EsSUFBSUEsV0FBV0EsR0FBR0EsSUFBSUEsS0FBS0EsQ0FBQ0EsS0FBS0EsQ0FBQ0EsSUFBSUEsQ0FBQ0EsQ0FBQ0E7UUFFeENBLFVBQVVBLENBQUNBLE9BQU9BLENBQUNBLFdBQVdBLEVBQUVBLEtBQUtBLENBQUNBLEtBQUtBLENBQUNBLGNBQWNBLENBQUNBLFVBQVVBLENBQUNBLENBQUNBO1FBRXZFQSxrQkFBTUE7WUFDSkEsS0FBS0EsRUFBRUEsVUFBVUE7WUFDakJBLE1BQU1BLEVBQUVBLEVBQUVBO1lBQ1ZBLE1BQU1BLEVBQUVBLFdBQVdBO1NBQ3BCQSxDQUFDQSxDQUFDQTtRQUVIQSxJQUFJQSxDQUFDQSxPQUFPQSxHQUFHQSxJQUFJQSxPQUFPQSxDQUFDQSxPQUFPQSxDQUFDQSxJQUFJQSxDQUFDQSxDQUFDQTtJQUMzQ0EsQ0FBQ0E7SUFFREQsd0JBQUtBLEdBQUxBLFVBQU1BLFFBQVFBO1FBQ1pFLElBQUlBLEdBQUdBLEdBQUdBLEVBQUVBLENBQUNBO1FBQ2JBLEdBQUdBLENBQUNBLENBQUNBLEdBQUdBLENBQUNBLENBQUNBLElBQUlBLFFBQVFBLENBQUNBO1lBQ3JCQSxHQUFHQSxDQUFDQSxJQUFJQSxDQUFDQTtnQkFDUEEsS0FBS0EsRUFBRUEsUUFBUUEsQ0FBQ0EsQ0FBQ0EsQ0FBQ0E7Z0JBQ2xCQSxNQUFNQSxFQUFFQSxRQUFRQSxDQUFDQSxDQUFDQSxDQUFDQTthQUNwQkEsQ0FBQ0EsQ0FBQ0E7UUFFTEEsTUFBTUEsQ0FBQ0EsSUFBSUEsQ0FBQ0EsT0FBT0EsQ0FBQ0EsS0FBS0EsQ0FBQ0EsR0FBR0EsRUFBRUE7WUFDN0JBLFVBQVVBLEVBQUVBLE1BQU1BO1lBQ2xCQSxLQUFLQSxFQUFFQSxNQUFNQTtZQUNiQSxJQUFJQSxFQUFFQSxDQUFDQTtTQUNSQSxDQUFDQSxDQUFDQTtJQUNMQSxDQUFDQTtJQUVERix1QkFBSUEsR0FBSkEsVUFBS0EsT0FBT0E7UUFDVkcsSUFBSUEsTUFBTUEsR0FBR0EsSUFBSUEsQ0FBQ0EsUUFBUUEsQ0FBQ0EsT0FBT0EsQ0FBQ0EsQ0FBQ0E7UUFFcENBLElBQUlBLFFBQVFBLEdBQUdBLEVBQUVBLENBQUNBO1FBQ2xCQSxHQUFHQSxDQUFDQSxDQUFDQSxHQUFHQSxDQUFDQSxDQUFDQSxJQUFJQSxNQUFNQSxDQUFDQTtZQUNuQkEsUUFBUUEsQ0FBQ0EsQ0FBQ0EsQ0FBQ0EsR0FBR0EsTUFBTUEsQ0FBQ0EsQ0FBQ0EsQ0FBQ0EsR0FBR0EsRUFBRUEsR0FBR0EsQ0FBQ0EsR0FBR0EsQ0FBQ0EsQ0FBQ0E7UUFFdkNBLE1BQU1BLENBQUNBLFFBQVFBLENBQUNBO0lBQ2xCQSxDQUFDQTtJQUNISCxlQUFDQTtBQUFEQSxDQTFDQSxBQTBDQ0EsRUExQzZCLE9BQU8sQ0FBQyxPQUFPLEVBMEM1QztBQTFDWSxnQkFBUSxHQUFSLFFBMENaLENBQUEiLCJmaWxlIjoic3JjL2FyY2hpdGVjdC9Ib3BmaWVsZC5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBuZXR3b3JrICA9IHJlcXVpcmUoJy4uL25ldHdvcmsnKTtcbmltcG9ydCB0cmFpbmVyICA9IHJlcXVpcmUoJy4uL3RyYWluZXInKTtcbmltcG9ydCBsYXllciAgPSByZXF1aXJlKCcuLi9sYXllcicpO1xuaW1wb3J0IG5ldXJvbiA9IHJlcXVpcmUoJy4uL25ldXJvbicpO1xuXG5leHBvcnQgY2xhc3MgSG9wZmllbGQgZXh0ZW5kcyBuZXR3b3JrLk5ldHdvcmsge1xuICB0cmFpbmVyOiB0cmFpbmVyLlRyYWluZXI7XG5cbiAgY29uc3RydWN0b3Ioc2l6ZTogbnVtYmVyKSB7XG4gICAgdmFyIGlucHV0TGF5ZXIgPSBuZXcgbGF5ZXIuTGF5ZXIoc2l6ZSk7XG4gICAgdmFyIG91dHB1dExheWVyID0gbmV3IGxheWVyLkxheWVyKHNpemUpO1xuXG4gICAgaW5wdXRMYXllci5wcm9qZWN0KG91dHB1dExheWVyLCBsYXllci5MYXllci5jb25uZWN0aW9uVHlwZS5BTExfVE9fQUxMKTtcblxuICAgIHN1cGVyKHtcbiAgICAgIGlucHV0OiBpbnB1dExheWVyLFxuICAgICAgaGlkZGVuOiBbXSxcbiAgICAgIG91dHB1dDogb3V0cHV0TGF5ZXJcbiAgICB9KTtcblxuICAgIHRoaXMudHJhaW5lciA9IG5ldyB0cmFpbmVyLlRyYWluZXIodGhpcyk7XG4gIH1cblxuICBsZWFybihwYXR0ZXJucykge1xuICAgIHZhciBzZXQgPSBbXTtcbiAgICBmb3IgKHZhciBwIGluIHBhdHRlcm5zKVxuICAgICAgc2V0LnB1c2goe1xuICAgICAgICBpbnB1dDogcGF0dGVybnNbcF0sXG4gICAgICAgIG91dHB1dDogcGF0dGVybnNbcF1cbiAgICAgIH0pO1xuXG4gICAgcmV0dXJuIHRoaXMudHJhaW5lci50cmFpbihzZXQsIHtcbiAgICAgIGl0ZXJhdGlvbnM6IDUwMDAwMCxcbiAgICAgIGVycm9yOiAuMDAwMDUsXG4gICAgICByYXRlOiAxXG4gICAgfSk7XG4gIH1cblxuICBmZWVkKHBhdHRlcm4pIHtcbiAgICB2YXIgb3V0cHV0ID0gdGhpcy5hY3RpdmF0ZShwYXR0ZXJuKTtcblxuICAgIHZhciBwYXR0ZXJucyA9IFtdO1xuICAgIGZvciAodmFyIGkgaW4gb3V0cHV0KVxuICAgICAgcGF0dGVybnNbaV0gPSBvdXRwdXRbaV0gPiAuNSA/IDEgOiAwO1xuXG4gICAgcmV0dXJuIHBhdHRlcm5zO1xuICB9XG59Il0sInNvdXJjZVJvb3QiOiIvc291cmNlLyJ9
|
||||
externo
+6
@@ -0,0 +1,6 @@
|
||||
import network = require('../network');
|
||||
import trainer = require('../trainer');
|
||||
export declare class LSTM extends network.Network {
|
||||
trainer: trainer.Trainer;
|
||||
constructor(...args: any[]);
|
||||
}
|
||||
externo
+122
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
externo
+6
@@ -0,0 +1,6 @@
|
||||
import network = require('../network');
|
||||
import trainer = require('../trainer');
|
||||
export declare class Liquid extends network.Network {
|
||||
trainer: trainer.Trainer;
|
||||
constructor(inputs: any, hidden: any, outputs: any, connections: any, gates: any);
|
||||
}
|
||||
externo
+51
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
+6
@@ -0,0 +1,6 @@
|
||||
import network = require('../network');
|
||||
import trainer = require('../trainer');
|
||||
export declare class Perceptron extends network.Network {
|
||||
trainer: trainer.Trainer;
|
||||
constructor(...args: number[]);
|
||||
}
|
||||
externo
+49
@@ -0,0 +1,49 @@
|
||||
var __extends = this.__extends || function (d, b) {
|
||||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
|
||||
function __() { this.constructor = d; }
|
||||
__.prototype = b.prototype;
|
||||
d.prototype = new __();
|
||||
};
|
||||
var network = require('../network');
|
||||
var trainer = require('../trainer');
|
||||
var layer = require('../layer');
|
||||
// Multilayer Perceptron
|
||||
var Perceptron = (function (_super) {
|
||||
__extends(Perceptron, _super);
|
||||
function Perceptron() {
|
||||
var args = [];
|
||||
for (var _i = 0; _i < arguments.length; _i++) {
|
||||
args[_i - 0] = arguments[_i];
|
||||
}
|
||||
if (args.length < 3)
|
||||
throw "Error: not enough layers (minimum 3) !!";
|
||||
var inputs = args.shift(); // first argument
|
||||
var outputs = args.pop(); // last argument
|
||||
var layers = args; // all the arguments in the middle
|
||||
var input = new layer.Layer(inputs);
|
||||
var hidden = [];
|
||||
var output = new layer.Layer(outputs);
|
||||
var previous = input;
|
||||
for (var level in layers) {
|
||||
var size = layers[level];
|
||||
var theLayer = new layer.Layer(size);
|
||||
hidden.push(theLayer);
|
||||
previous.project(theLayer);
|
||||
previous = theLayer;
|
||||
}
|
||||
previous.project(output);
|
||||
// set layers of the neural network
|
||||
_super.call(this, {
|
||||
input: input,
|
||||
hidden: hidden,
|
||||
output: output
|
||||
});
|
||||
// trainer for the network
|
||||
this.trainer = new trainer.Trainer(this);
|
||||
}
|
||||
return Perceptron;
|
||||
})(network.Network);
|
||||
exports.Perceptron = Perceptron;
|
||||
;
|
||||
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9hcmNoaXRlY3QvUGVyY2VwdHJvbi50cyJdLCJuYW1lcyI6WyJQZXJjZXB0cm9uIiwiUGVyY2VwdHJvbi5jb25zdHJ1Y3RvciJdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsSUFBTyxPQUFPLFdBQVksWUFBWSxDQUFDLENBQUM7QUFDeEMsSUFBTyxPQUFPLFdBQVksWUFBWSxDQUFDLENBQUM7QUFDeEMsSUFBTyxLQUFLLFdBQVksVUFBVSxDQUFDLENBQUM7QUFFcEMsQUFDQSx3QkFEd0I7SUFDWCxVQUFVO0lBQVNBLFVBQW5CQSxVQUFVQSxVQUF3QkE7SUFHN0NBLFNBSFdBLFVBQVVBO1FBR1RDLGNBQWlCQTthQUFqQkEsV0FBaUJBLENBQWpCQSxzQkFBaUJBLENBQWpCQSxJQUFpQkE7WUFBakJBLDZCQUFpQkE7O1FBRTNCQSxFQUFFQSxDQUFDQSxDQUFDQSxJQUFJQSxDQUFDQSxNQUFNQSxHQUFHQSxDQUFDQSxDQUFDQTtZQUNsQkEsTUFBTUEseUNBQXlDQSxDQUFDQTtRQUVsREEsSUFBSUEsTUFBTUEsR0FBR0EsSUFBSUEsQ0FBQ0EsS0FBS0EsRUFBRUEsRUFBRUEsaUJBQWlCQTtRQUM1Q0EsSUFBSUEsT0FBT0EsR0FBR0EsSUFBSUEsQ0FBQ0EsR0FBR0EsRUFBRUEsRUFBRUEsZ0JBQWdCQTtRQUMxQ0EsSUFBSUEsTUFBTUEsR0FBR0EsSUFBSUEsRUFBRUEsa0NBQWtDQTtRQUVyREEsSUFBSUEsS0FBS0EsR0FBR0EsSUFBSUEsS0FBS0EsQ0FBQ0EsS0FBS0EsQ0FBQ0EsTUFBTUEsQ0FBQ0EsQ0FBQ0E7UUFDcENBLElBQUlBLE1BQU1BLEdBQUdBLEVBQUVBLENBQUNBO1FBQ2hCQSxJQUFJQSxNQUFNQSxHQUFHQSxJQUFJQSxLQUFLQSxDQUFDQSxLQUFLQSxDQUFDQSxPQUFPQSxDQUFDQSxDQUFDQTtRQUV0Q0EsSUFBSUEsUUFBUUEsR0FBR0EsS0FBS0EsQ0FBQ0E7UUFHckJBLEdBQUdBLENBQUNBLENBQUNBLEdBQUdBLENBQUNBLEtBQUtBLElBQUlBLE1BQU1BLENBQUNBLENBQUNBLENBQUNBO1lBQ3pCQSxJQUFJQSxJQUFJQSxHQUFHQSxNQUFNQSxDQUFDQSxLQUFLQSxDQUFDQSxDQUFDQTtZQUN6QkEsSUFBSUEsUUFBUUEsR0FBR0EsSUFBSUEsS0FBS0EsQ0FBQ0EsS0FBS0EsQ0FBQ0EsSUFBSUEsQ0FBQ0EsQ0FBQ0E7WUFDckNBLE1BQU1BLENBQUNBLElBQUlBLENBQUNBLFFBQVFBLENBQUNBLENBQUNBO1lBQ3RCQSxRQUFRQSxDQUFDQSxPQUFPQSxDQUFDQSxRQUFRQSxDQUFDQSxDQUFDQTtZQUMzQkEsUUFBUUEsR0FBR0EsUUFBUUEsQ0FBQ0E7UUFDdEJBLENBQUNBO1FBQ0RBLFFBQVFBLENBQUNBLE9BQU9BLENBQUNBLE1BQU1BLENBQUNBLENBQUNBO1FBRXpCQSxBQUVBQSxtQ0FGbUNBO1FBRW5DQSxrQkFBTUE7WUFDSkEsS0FBS0EsRUFBRUEsS0FBS0E7WUFDWkEsTUFBTUEsRUFBRUEsTUFBTUE7WUFDZEEsTUFBTUEsRUFBRUEsTUFBTUE7U0FDZkEsQ0FBQ0EsQ0FBQ0E7UUFFSEEsQUFDQUEsMEJBRDBCQTtRQUMxQkEsSUFBSUEsQ0FBQ0EsT0FBT0EsR0FBR0EsSUFBSUEsT0FBT0EsQ0FBQ0EsT0FBT0EsQ0FBQ0EsSUFBSUEsQ0FBQ0EsQ0FBQ0E7SUFDM0NBLENBQUNBO0lBQ0hELGlCQUFDQTtBQUFEQSxDQXZDQSxBQXVDQ0EsRUF2QytCLE9BQU8sQ0FBQyxPQUFPLEVBdUM5QztBQXZDWSxrQkFBVSxHQUFWLFVBdUNaLENBQUE7QUFBQSxDQUFDIiwiZmlsZSI6InNyYy9hcmNoaXRlY3QvUGVyY2VwdHJvbi5qcyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBuZXR3b3JrICA9IHJlcXVpcmUoJy4uL25ldHdvcmsnKTtcbmltcG9ydCB0cmFpbmVyICA9IHJlcXVpcmUoJy4uL3RyYWluZXInKTtcbmltcG9ydCBsYXllciAgPSByZXF1aXJlKCcuLi9sYXllcicpO1xuaW1wb3J0IG5ldXJvbiA9IHJlcXVpcmUoJy4uL25ldXJvbicpO1xuLy8gTXVsdGlsYXllciBQZXJjZXB0cm9uXG5leHBvcnQgY2xhc3MgUGVyY2VwdHJvbiBleHRlbmRzIG5ldHdvcmsuTmV0d29yayB7XG4gIHRyYWluZXI6IHRyYWluZXIuVHJhaW5lcjtcblxuICBjb25zdHJ1Y3RvciguLi5hcmdzOiBudW1iZXJbXSkge1xuXG4gICAgaWYgKGFyZ3MubGVuZ3RoIDwgMylcbiAgICAgIHRocm93IFwiRXJyb3I6IG5vdCBlbm91Z2ggbGF5ZXJzIChtaW5pbXVtIDMpICEhXCI7XG5cbiAgICB2YXIgaW5wdXRzID0gYXJncy5zaGlmdCgpOyAvLyBmaXJzdCBhcmd1bWVudFxuICAgIHZhciBvdXRwdXRzID0gYXJncy5wb3AoKTsgLy8gbGFzdCBhcmd1bWVudFxuICAgIHZhciBsYXllcnMgPSBhcmdzOyAvLyBhbGwgdGhlIGFyZ3VtZW50cyBpbiB0aGUgbWlkZGxlXG4gIFxuICAgIHZhciBpbnB1dCA9IG5ldyBsYXllci5MYXllcihpbnB1dHMpO1xuICAgIHZhciBoaWRkZW4gPSBbXTtcbiAgICB2YXIgb3V0cHV0ID0gbmV3IGxheWVyLkxheWVyKG91dHB1dHMpO1xuXG4gICAgdmFyIHByZXZpb3VzID0gaW5wdXQ7XG4gIFxuICAgIC8vIGdlbmVyYXRlIGhpZGRlbiBsYXllcnNcbiAgICBmb3IgKHZhciBsZXZlbCBpbiBsYXllcnMpIHtcbiAgICAgIHZhciBzaXplID0gbGF5ZXJzW2xldmVsXTtcbiAgICAgIHZhciB0aGVMYXllciA9IG5ldyBsYXllci5MYXllcihzaXplKTtcbiAgICAgIGhpZGRlbi5wdXNoKHRoZUxheWVyKTtcbiAgICAgIHByZXZpb3VzLnByb2plY3QodGhlTGF5ZXIpO1xuICAgICAgcHJldmlvdXMgPSB0aGVMYXllcjtcbiAgICB9XG4gICAgcHJldmlvdXMucHJvamVjdChvdXRwdXQpO1xuICBcbiAgICAvLyBzZXQgbGF5ZXJzIG9mIHRoZSBuZXVyYWwgbmV0d29ya1xuICAgICAgXG4gICAgc3VwZXIoe1xuICAgICAgaW5wdXQ6IGlucHV0LFxuICAgICAgaGlkZGVuOiBoaWRkZW4sXG4gICAgICBvdXRwdXQ6IG91dHB1dFxuICAgIH0pO1xuICBcbiAgICAvLyB0cmFpbmVyIGZvciB0aGUgbmV0d29ya1xuICAgIHRoaXMudHJhaW5lciA9IG5ldyB0cmFpbmVyLlRyYWluZXIodGhpcyk7XG4gIH1cbn07ICJdLCJzb3VyY2VSb290IjoiL3NvdXJjZS8ifQ==
|
||||
externo
+49
@@ -0,0 +1,49 @@
|
||||
import neuron = require('./neuron');
|
||||
import Synaptic = require('./synaptic');
|
||||
/*******************************************************************************************
|
||||
LAYER
|
||||
*******************************************************************************************/
|
||||
export declare class Layer {
|
||||
list: neuron.Neuron[];
|
||||
label: string;
|
||||
connectedto: any[];
|
||||
size: number;
|
||||
constructor(size: number, label?: string);
|
||||
activate(input: any): any[];
|
||||
propagate(rate: any, target: any): void;
|
||||
project(layer: any, type?: any, weights?: any): Layer.LayerConnection;
|
||||
gate(connection: any, type: any): void;
|
||||
selfconnected(): boolean;
|
||||
connected(layer: any): string;
|
||||
clear(): void;
|
||||
reset(): void;
|
||||
neurons(): neuron.Neuron[];
|
||||
add(neuron: any): void;
|
||||
set(options: any): Layer;
|
||||
}
|
||||
export declare module Layer {
|
||||
var layerQty: number;
|
||||
function uid(): number;
|
||||
var connectionType: {
|
||||
ALL_TO_ALL: string;
|
||||
ONE_TO_ONE: string;
|
||||
ALL_TO_ELSE: string;
|
||||
};
|
||||
var gateType: {
|
||||
INPUT: string;
|
||||
OUTPUT: string;
|
||||
ONE_TO_ONE: string;
|
||||
};
|
||||
class LayerConnection {
|
||||
ID: number;
|
||||
from: Layer;
|
||||
to: Layer;
|
||||
selfconnection: boolean;
|
||||
type: string;
|
||||
connections: Synaptic.Dictionary<neuron.Neuron.Connection>;
|
||||
list: neuron.Neuron.Connection[];
|
||||
size: number;
|
||||
gatedfrom: any[];
|
||||
constructor(fromLayer: any, toLayer: any, type: any, weights: any);
|
||||
}
|
||||
}
|
||||
externo
+255
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
externo
+41
@@ -0,0 +1,41 @@
|
||||
import _neuron = require('./neuron');
|
||||
export declare class Network {
|
||||
optimized: any;
|
||||
layers: {
|
||||
input: any;
|
||||
hidden: {};
|
||||
output: any;
|
||||
};
|
||||
constructor(layers: any);
|
||||
activate(input: any): any;
|
||||
propagate(rate: number, target?: any): void;
|
||||
project(unit: any, type: any, weights: any): any;
|
||||
gate(connection: any, type: any): void;
|
||||
clear(): void;
|
||||
reset(): void;
|
||||
optimize(): void;
|
||||
restore(): void;
|
||||
neurons(): Network.INetworkNeuron[];
|
||||
inputs(): number;
|
||||
outputs(): number;
|
||||
set(layers: any): void;
|
||||
setOptimize(bool: any): void;
|
||||
toJSON(ignoreTraces: any): {
|
||||
neurons: any[];
|
||||
connections: any[];
|
||||
};
|
||||
toDot(edgeconnection: any): {
|
||||
code: string;
|
||||
link: string;
|
||||
};
|
||||
standalone(): any;
|
||||
worker(): Worker;
|
||||
clone(ignoreTraces: any): Network;
|
||||
static fromJSON(json: any): Network;
|
||||
}
|
||||
export declare module Network {
|
||||
interface INetworkNeuron {
|
||||
neuron: _neuron.Neuron;
|
||||
layer: string;
|
||||
}
|
||||
}
|
||||
externo
+492
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
externo
+67
@@ -0,0 +1,67 @@
|
||||
/// <reference path="synaptic.d.ts" />
|
||||
import Synaptic = require('./synaptic');
|
||||
import Squash = require('./squash');
|
||||
/******************************************************************************************
|
||||
NEURON
|
||||
*******************************************************************************************/
|
||||
export declare class Neuron {
|
||||
ID: number;
|
||||
label: any;
|
||||
connections: Neuron.INeuronConnections;
|
||||
error: {
|
||||
responsibility: number;
|
||||
projected: number;
|
||||
gated: number;
|
||||
};
|
||||
trace: {
|
||||
elegibility: {};
|
||||
extended: {};
|
||||
influences: {};
|
||||
};
|
||||
state: number;
|
||||
old: number;
|
||||
activation: number;
|
||||
selfconnection: Neuron.Connection;
|
||||
squash: typeof Squash.LOGISTIC;
|
||||
neighboors: {};
|
||||
bias: number;
|
||||
derivative: number;
|
||||
activate(input?: number): number;
|
||||
propagate(rate: number, target?: number): void;
|
||||
project(neuron: any, weight?: number): Neuron.Connection;
|
||||
gate(connection: any): void;
|
||||
selfconnected(): boolean;
|
||||
connected(neuron: any): {
|
||||
type: string;
|
||||
connection: Neuron.Connection;
|
||||
};
|
||||
clear(): void;
|
||||
reset(): void;
|
||||
optimize(optimized: any, layer: any): Synaptic.ICompiledParameters;
|
||||
}
|
||||
export declare module Neuron {
|
||||
interface INeuronConnections {
|
||||
inputs: Synaptic.Dictionary<Neuron.Connection>;
|
||||
projected: {};
|
||||
gated: {};
|
||||
}
|
||||
class Connection {
|
||||
ID: number;
|
||||
from: any;
|
||||
to: any;
|
||||
gain: number;
|
||||
weight: number;
|
||||
gater: any;
|
||||
constructor(from: any, to: any, weight?: number);
|
||||
}
|
||||
var neuronQty: number;
|
||||
function uid(): number;
|
||||
function quantity(): {
|
||||
neurons: number;
|
||||
connections: number;
|
||||
};
|
||||
}
|
||||
export declare module Neuron.Connection {
|
||||
var connectionQty: number;
|
||||
function uid(): number;
|
||||
}
|
||||
externo
+660
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
externo
+4
@@ -0,0 +1,4 @@
|
||||
export declare function LOGISTIC(x: number, derivate?: boolean): any;
|
||||
export declare function TANH(x: number, derivate?: boolean): any;
|
||||
export declare function IDENTITY(x: number, derivate?: boolean): number;
|
||||
export declare function HLIM(x: number, derivate?: boolean): number;
|
||||
externo
+26
@@ -0,0 +1,26 @@
|
||||
// squashing functions
|
||||
function LOGISTIC(x, derivate) {
|
||||
if (!derivate)
|
||||
return 1 / (1 + Math.exp(-x));
|
||||
var fx = LOGISTIC(x);
|
||||
return fx * (1 - fx);
|
||||
}
|
||||
exports.LOGISTIC = LOGISTIC;
|
||||
function TANH(x, derivate) {
|
||||
if (derivate)
|
||||
return 1 - Math.pow(TANH(x), 2);
|
||||
var eP = Math.exp(x);
|
||||
var eN = 1 / eP;
|
||||
return (eP - eN) / (eP + eN);
|
||||
}
|
||||
exports.TANH = TANH;
|
||||
function IDENTITY(x, derivate) {
|
||||
return derivate ? 1 : x;
|
||||
}
|
||||
exports.IDENTITY = IDENTITY;
|
||||
function HLIM(x, derivate) {
|
||||
return derivate ? 1 : +(x > 0);
|
||||
}
|
||||
exports.HLIM = HLIM;
|
||||
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9zcXVhc2gudHMiXSwibmFtZXMiOlsiTE9HSVNUSUMiLCJUQU5IIiwiSURFTlRJVFkiLCJITElNIl0sIm1hcHBpbmdzIjoiQUFFQSxBQUVBLHNCQUZzQjtTQUVOLFFBQVEsQ0FBQyxDQUFTLEVBQUUsUUFBa0I7SUFDckRBLEVBQUVBLENBQUNBLENBQUNBLENBQUNBLFFBQVFBLENBQUNBO1FBQ2JBLE1BQU1BLENBQUNBLENBQUNBLEdBQUdBLENBQUNBLENBQUNBLEdBQUdBLElBQUlBLENBQUNBLEdBQUdBLENBQUNBLENBQUNBLENBQUNBLENBQUNBLENBQUNBLENBQUNBO0lBQy9CQSxJQUFJQSxFQUFFQSxHQUFHQSxRQUFRQSxDQUFDQSxDQUFDQSxDQUFDQSxDQUFDQTtJQUNyQkEsTUFBTUEsQ0FBQ0EsRUFBRUEsR0FBR0EsQ0FBQ0EsQ0FBQ0EsR0FBR0EsRUFBRUEsQ0FBQ0EsQ0FBQ0E7QUFDdEJBLENBQUNBO0FBTGUsZ0JBQVEsR0FBUixRQUtmLENBQUE7QUFFRCxTQUFnQixJQUFJLENBQUMsQ0FBUyxFQUFFLFFBQWtCO0lBQ2pEQyxFQUFFQSxDQUFDQSxDQUFDQSxRQUFRQSxDQUFDQTtRQUNaQSxNQUFNQSxDQUFDQSxDQUFDQSxHQUFHQSxJQUFJQSxDQUFDQSxHQUFHQSxDQUFDQSxJQUFJQSxDQUFDQSxDQUFDQSxDQUFDQSxFQUFFQSxDQUFDQSxDQUFDQSxDQUFDQTtJQUNqQ0EsSUFBSUEsRUFBRUEsR0FBR0EsSUFBSUEsQ0FBQ0EsR0FBR0EsQ0FBQ0EsQ0FBQ0EsQ0FBQ0EsQ0FBQ0E7SUFDckJBLElBQUlBLEVBQUVBLEdBQUdBLENBQUNBLEdBQUdBLEVBQUVBLENBQUNBO0lBQ2hCQSxNQUFNQSxDQUFDQSxDQUFDQSxFQUFFQSxHQUFHQSxFQUFFQSxDQUFDQSxHQUFHQSxDQUFDQSxFQUFFQSxHQUFHQSxFQUFFQSxDQUFDQSxDQUFDQTtBQUM5QkEsQ0FBQ0E7QUFOZSxZQUFJLEdBQUosSUFNZixDQUFBO0FBRUQsU0FBZ0IsUUFBUSxDQUFDLENBQVMsRUFBRSxRQUFrQjtJQUNyREMsTUFBTUEsQ0FBQ0EsUUFBUUEsR0FBR0EsQ0FBQ0EsR0FBR0EsQ0FBQ0EsQ0FBQ0E7QUFDekJBLENBQUNBO0FBRmUsZ0JBQVEsR0FBUixRQUVmLENBQUE7QUFFRCxTQUFnQixJQUFJLENBQUMsQ0FBUyxFQUFFLFFBQWtCO0lBQ2pEQyxNQUFNQSxDQUFDQSxRQUFRQSxHQUFHQSxDQUFDQSxHQUFHQSxDQUFDQSxDQUFDQSxDQUFDQSxHQUFHQSxDQUFDQSxDQUFDQSxDQUFDQTtBQUNoQ0EsQ0FBQ0E7QUFGZSxZQUFJLEdBQUosSUFFZixDQUFBIiwiZmlsZSI6InNyYy9zcXVhc2guanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgU3luYXB0aWMgPSByZXF1aXJlKCcuL3N5bmFwdGljJyk7XG5cbi8vIHNxdWFzaGluZyBmdW5jdGlvbnNcblxuZXhwb3J0IGZ1bmN0aW9uIExPR0lTVElDKHg6IG51bWJlciwgZGVyaXZhdGU/OiBib29sZWFuKSB7XG5cdGlmICghZGVyaXZhdGUpXG5cdFx0cmV0dXJuIDEgLyAoMSArIE1hdGguZXhwKC14KSk7XG5cdHZhciBmeCA9IExPR0lTVElDKHgpO1xuXHRyZXR1cm4gZnggKiAoMSAtIGZ4KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIFRBTkgoeDogbnVtYmVyLCBkZXJpdmF0ZT86IGJvb2xlYW4pIHtcblx0aWYgKGRlcml2YXRlKVxuXHRcdHJldHVybiAxIC0gTWF0aC5wb3coVEFOSCh4KSwgMik7XG5cdHZhciBlUCA9IE1hdGguZXhwKHgpO1xuXHR2YXIgZU4gPSAxIC8gZVA7XG5cdHJldHVybiAoZVAgLSBlTikgLyAoZVAgKyBlTik7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBJREVOVElUWSh4OiBudW1iZXIsIGRlcml2YXRlPzogYm9vbGVhbikge1xuXHRyZXR1cm4gZGVyaXZhdGUgPyAxIDogeDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIEhMSU0oeDogbnVtYmVyLCBkZXJpdmF0ZT86IGJvb2xlYW4pIHtcblx0cmV0dXJuIGRlcml2YXRlID8gMSA6ICsoeCA+IDApO1xufVxuIl0sInNvdXJjZVJvb3QiOiIvc291cmNlLyJ9
|
||||
externo
+31
@@ -0,0 +1,31 @@
|
||||
import network = require('./network');
|
||||
import layer = require('./layer');
|
||||
import neuron = require('./neuron');
|
||||
import trainer = require('./trainer');
|
||||
import architect = require('./architect');
|
||||
import squash = require('./squash');
|
||||
declare module Synaptic {
|
||||
interface Dictionary<T> {
|
||||
[id: string]: T;
|
||||
}
|
||||
function ninja(): typeof Synaptic;
|
||||
interface ICompiledParameters {
|
||||
memory?: any;
|
||||
neurons?: number;
|
||||
inputs?: any[];
|
||||
outputs?: any[];
|
||||
targets?: any[];
|
||||
variables?: any;
|
||||
activation_sentences?: any[];
|
||||
trace_sentences?: any[];
|
||||
propagation_sentences?: any[];
|
||||
layers?: any;
|
||||
}
|
||||
var Neuron: typeof neuron.Neuron;
|
||||
var Layer: typeof layer.Layer;
|
||||
var Network: typeof network.Network;
|
||||
var Trainer: typeof trainer.Trainer;
|
||||
var Squash: typeof squash;
|
||||
var Architect: typeof architect;
|
||||
}
|
||||
export = Synaptic;
|
||||
externo
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
********************************************************************************************
|
||||
SYNAPTIC
|
||||
********************************************************************************************
|
||||
|
||||
Synaptic is a javascript neural network library for node.js and the browser, its generalized
|
||||
algorithm is architecture-free, so you can build and train basically any type of first order
|
||||
or even second order neural network architectures.
|
||||
|
||||
http://en.wikipedia.org/wiki/Recurrent_neural_network#Second_Order_Recurrent_Neural_Network
|
||||
|
||||
The library includes a few built-in architectures like multilayer perceptrons, multilayer
|
||||
long-short term memory networks (LSTM) or liquid state machines, and a trainer capable of
|
||||
training any given network, and includes built-in training tasks/tests like solving an XOR,
|
||||
passing a Distracted Sequence Recall test or an Embeded Reber Grammar test.
|
||||
|
||||
The algorithm implemented by this library has been taken from Derek D. Monner's paper:
|
||||
|
||||
A generalized LSTM-like training algorithm for second-order recurrent neural networks
|
||||
http://www.overcomplete.net/papers/nn2012.pdf
|
||||
|
||||
There are references to the equations in that paper commented through the source code.
|
||||
|
||||
|
||||
********************************************************************************************/
|
||||
var network = require('./network');
|
||||
var layer = require('./layer');
|
||||
var neuron = require('./neuron');
|
||||
var trainer = require('./trainer');
|
||||
var architect = require('./architect');
|
||||
var squash = require('./squash');
|
||||
var Synaptic;
|
||||
(function (Synaptic) {
|
||||
var oldSynaptic = typeof window != "undefined" && window && window['Synaptic'];
|
||||
function ninja() {
|
||||
window['synaptic'] = oldSynaptic;
|
||||
return Synaptic;
|
||||
}
|
||||
Synaptic.ninja = ninja;
|
||||
Synaptic.Neuron = neuron.Neuron;
|
||||
Synaptic.Layer = layer.Layer;
|
||||
Synaptic.Network = network.Network;
|
||||
Synaptic.Trainer = trainer.Trainer;
|
||||
Synaptic.Squash = squash;
|
||||
Synaptic.Architect = architect;
|
||||
})(Synaptic || (Synaptic = {}));
|
||||
if (typeof window != "undefined")
|
||||
window['synaptic'] = Synaptic;
|
||||
module.exports = Synaptic;
|
||||
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNyYy9zeW5hcHRpYy50cyJdLCJuYW1lcyI6WyJTeW5hcHRpYyIsIlN5bmFwdGljLm5pbmphIl0sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OzZGQXdCNkY7QUFJN0YsSUFBTyxPQUFPLFdBQVcsV0FBVyxDQUFDLENBQUM7QUFDdEMsSUFBTyxLQUFLLFdBQVcsU0FBUyxDQUFDLENBQUM7QUFDbEMsSUFBTyxNQUFNLFdBQVcsVUFBVSxDQUFDLENBQUM7QUFDcEMsSUFBTyxPQUFPLFdBQVcsV0FBVyxDQUFDLENBQUM7QUFDdEMsSUFBTyxTQUFTLFdBQVcsYUFBYSxDQUFDLENBQUM7QUFDMUMsSUFBTyxNQUFNLFdBQVcsVUFBVSxDQUFDLENBQUM7QUFJcEMsSUFBTyxRQUFRLENBK0JkO0FBL0JELFdBQU8sUUFBUSxFQUFDLENBQUM7SUFLaEJBLElBQUlBLFdBQVdBLEdBQUdBLE9BQU9BLE1BQU1BLElBQUlBLFdBQVdBLElBQUlBLE1BQU1BLElBQUlBLE1BQU1BLENBQUNBLFVBQVVBLENBQUNBLENBQUNBO0lBRS9FQSxTQUFnQkEsS0FBS0E7UUFDaEJDLE1BQU1BLENBQUNBLFVBQVVBLENBQUNBLEdBQUdBLFdBQVdBLENBQUNBO1FBQ2pDQSxNQUFNQSxDQUFDQSxRQUFRQSxDQUFDQTtJQUNyQkEsQ0FBQ0E7SUFIZUQsY0FBS0EsR0FBTEEsS0FHZkEsQ0FBQUE7SUFlVUEsZUFBTUEsR0FBR0EsTUFBTUEsQ0FBQ0EsTUFBTUEsQ0FBQ0E7SUFDdkJBLGNBQUtBLEdBQUdBLEtBQUtBLENBQUNBLEtBQUtBLENBQUNBO0lBQ3BCQSxnQkFBT0EsR0FBR0EsT0FBT0EsQ0FBQ0EsT0FBT0EsQ0FBQ0E7SUFDMUJBLGdCQUFPQSxHQUFHQSxPQUFPQSxDQUFDQSxPQUFPQSxDQUFDQTtJQUMxQkEsZUFBTUEsR0FBR0EsTUFBTUEsQ0FBQ0E7SUFDaEJBLGtCQUFTQSxHQUFHQSxTQUFTQSxDQUFDQTtBQUNsQ0EsQ0FBQ0EsRUEvQk0sUUFBUSxLQUFSLFFBQVEsUUErQmQ7QUFJRCxFQUFFLENBQUEsQ0FBQyxPQUFPLE1BQU0sSUFBSSxXQUFXLENBQUM7SUFDL0IsTUFBTSxDQUFDLFVBQVUsQ0FBQyxHQUFHLFFBQVEsQ0FBQztBQUgvQixpQkFBUyxRQUFRLENBQUMiLCJmaWxlIjoic3JjL3N5bmFwdGljLmpzIiwic291cmNlc0NvbnRlbnQiOlsiLypcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNZTkFQVElDXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5TeW5hcHRpYyBpcyBhIGphdmFzY3JpcHQgbmV1cmFsIG5ldHdvcmsgbGlicmFyeSBmb3Igbm9kZS5qcyBhbmQgdGhlIGJyb3dzZXIsIGl0cyBnZW5lcmFsaXplZFxuYWxnb3JpdGhtIGlzIGFyY2hpdGVjdHVyZS1mcmVlLCBzbyB5b3UgY2FuIGJ1aWxkIGFuZCB0cmFpbiBiYXNpY2FsbHkgYW55IHR5cGUgb2YgZmlyc3Qgb3JkZXJcbm9yIGV2ZW4gc2Vjb25kIG9yZGVyIG5ldXJhbCBuZXR3b3JrIGFyY2hpdGVjdHVyZXMuXG5cbmh0dHA6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUmVjdXJyZW50X25ldXJhbF9uZXR3b3JrI1NlY29uZF9PcmRlcl9SZWN1cnJlbnRfTmV1cmFsX05ldHdvcmtcblxuVGhlIGxpYnJhcnkgaW5jbHVkZXMgYSBmZXcgYnVpbHQtaW4gYXJjaGl0ZWN0dXJlcyBsaWtlIG11bHRpbGF5ZXIgcGVyY2VwdHJvbnMsIG11bHRpbGF5ZXJcbmxvbmctc2hvcnQgdGVybSBtZW1vcnkgbmV0d29ya3MgKExTVE0pIG9yIGxpcXVpZCBzdGF0ZSBtYWNoaW5lcywgYW5kIGEgdHJhaW5lciBjYXBhYmxlIG9mXG50cmFpbmluZyBhbnkgZ2l2ZW4gbmV0d29yaywgYW5kIGluY2x1ZGVzIGJ1aWx0LWluIHRyYWluaW5nIHRhc2tzL3Rlc3RzIGxpa2Ugc29sdmluZyBhbiBYT1IsXG5wYXNzaW5nIGEgRGlzdHJhY3RlZCBTZXF1ZW5jZSBSZWNhbGwgdGVzdCBvciBhbiBFbWJlZGVkIFJlYmVyIEdyYW1tYXIgdGVzdC5cblxuVGhlIGFsZ29yaXRobSBpbXBsZW1lbnRlZCBieSB0aGlzIGxpYnJhcnkgaGFzIGJlZW4gdGFrZW4gZnJvbSBEZXJlayBELiBNb25uZXIncyBwYXBlcjpcblxuQSBnZW5lcmFsaXplZCBMU1RNLWxpa2UgdHJhaW5pbmcgYWxnb3JpdGhtIGZvciBzZWNvbmQtb3JkZXIgcmVjdXJyZW50IG5ldXJhbCBuZXR3b3Jrc1xuaHR0cDovL3d3dy5vdmVyY29tcGxldGUubmV0L3BhcGVycy9ubjIwMTIucGRmXG5cblRoZXJlIGFyZSByZWZlcmVuY2VzIHRvIHRoZSBlcXVhdGlvbnMgaW4gdGhhdCBwYXBlciBjb21tZW50ZWQgdGhyb3VnaCB0aGUgc291cmNlIGNvZGUuXG5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cblxuXG5pbXBvcnQgbmV0d29yayA9IHJlcXVpcmUoJy4vbmV0d29yaycpO1xuaW1wb3J0IGxheWVyID0gcmVxdWlyZSgnLi9sYXllcicpO1xuaW1wb3J0IG5ldXJvbiA9IHJlcXVpcmUoJy4vbmV1cm9uJyk7XG5pbXBvcnQgdHJhaW5lciA9IHJlcXVpcmUoJy4vdHJhaW5lcicpO1xuaW1wb3J0IGFyY2hpdGVjdCA9IHJlcXVpcmUoJy4vYXJjaGl0ZWN0Jyk7XG5pbXBvcnQgc3F1YXNoID0gcmVxdWlyZSgnLi9zcXVhc2gnKTtcblxuZGVjbGFyZSB2YXIgd2luZG93O1xuXG5tb2R1bGUgU3luYXB0aWMge1xuXHRleHBvcnQgaW50ZXJmYWNlIERpY3Rpb25hcnk8VD4ge1xuXHRcdFtpZDogc3RyaW5nXSA6IFQ7XG5cdH1cblx0XG5cdHZhciBvbGRTeW5hcHRpYyA9IHR5cGVvZiB3aW5kb3cgIT0gXCJ1bmRlZmluZWRcIiAmJiB3aW5kb3cgJiYgd2luZG93WydTeW5hcHRpYyddO1xuXHRcblx0ZXhwb3J0IGZ1bmN0aW9uIG5pbmphKCkge1xuICAgICAgd2luZG93WydzeW5hcHRpYyddID0gb2xkU3luYXB0aWM7IFxuICAgICAgcmV0dXJuIFN5bmFwdGljO1xuXHR9XG5cdFxuXHRleHBvcnQgaW50ZXJmYWNlIElDb21waWxlZFBhcmFtZXRlcnMge1x0XG5cdFx0bWVtb3J5PzogYW55O1xuXHRcdG5ldXJvbnM/OiBudW1iZXI7XG5cdFx0aW5wdXRzPzogYW55W107XG5cdFx0b3V0cHV0cz86IGFueVtdO1xuXHRcdHRhcmdldHM/OiBhbnlbXTtcblx0XHR2YXJpYWJsZXM/OiBhbnk7XG5cdFx0YWN0aXZhdGlvbl9zZW50ZW5jZXM/OiBhbnlbXTtcblx0XHR0cmFjZV9zZW50ZW5jZXM/OiBhbnlbXTtcblx0XHRwcm9wYWdhdGlvbl9zZW50ZW5jZXM/OiBhbnlbXTtcblx0XHRsYXllcnM/OiBhbnk7XG5cdH1cblx0XG5cdGV4cG9ydCB2YXIgTmV1cm9uID0gbmV1cm9uLk5ldXJvbjtcblx0ZXhwb3J0IHZhciBMYXllciA9IGxheWVyLkxheWVyO1xuXHRleHBvcnQgdmFyIE5ldHdvcmsgPSBuZXR3b3JrLk5ldHdvcms7XG5cdGV4cG9ydCB2YXIgVHJhaW5lciA9IHRyYWluZXIuVHJhaW5lcjtcblx0ZXhwb3J0IHZhciBTcXVhc2ggPSBzcXVhc2g7XG5cdGV4cG9ydCB2YXIgQXJjaGl0ZWN0ID0gYXJjaGl0ZWN0O1xufVxuXG5leHBvcnQgPSBTeW5hcHRpYztcblxuaWYodHlwZW9mIHdpbmRvdyAhPSBcInVuZGVmaW5lZFwiKSBcblx0d2luZG93WydzeW5hcHRpYyddID0gU3luYXB0aWM7XG4iXSwic291cmNlUm9vdCI6Ii9zb3VyY2UvIn0=
|
||||
externo
+46
@@ -0,0 +1,46 @@
|
||||
import net = require('./network');
|
||||
/*******************************************************************************************
|
||||
TRAINER
|
||||
*******************************************************************************************/
|
||||
export declare class Trainer {
|
||||
network: net.Network;
|
||||
rate: any;
|
||||
iterations: number;
|
||||
error: number;
|
||||
cost: Trainer.ITrainerCostFn;
|
||||
schedule: any;
|
||||
constructor(network: net.Network, options?: any);
|
||||
train(set: any, options: any): {
|
||||
error: number;
|
||||
iterations: number;
|
||||
time: number;
|
||||
};
|
||||
workerTrain(set: any, callback: any, options: any): void;
|
||||
XOR(options: any): {
|
||||
error: number;
|
||||
iterations: number;
|
||||
time: number;
|
||||
};
|
||||
DSR(options: any): {
|
||||
iterations: number;
|
||||
success: number;
|
||||
error: number;
|
||||
time: number;
|
||||
};
|
||||
ERG(options: any): {
|
||||
iterations: number;
|
||||
error: number;
|
||||
time: number;
|
||||
test: (str: any) => boolean;
|
||||
generate: () => string;
|
||||
};
|
||||
}
|
||||
export declare module Trainer {
|
||||
interface ITrainerCostFn {
|
||||
(target: any, output: any): number;
|
||||
}
|
||||
var cost: {
|
||||
CROSS_ENTROPY: (target: any, output: any) => number;
|
||||
MSE: (target: any, output: any) => number;
|
||||
};
|
||||
}
|
||||
externo
+527
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
externo
+2307
-2613
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
externo
+2
-53
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
+35
-11
@@ -1,7 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
var license = '/*\n\nThe MIT License (MIT)\n\nCopyright (c) 2014 Juan Cazala - juancazala.com\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the "Software"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE\n\n\n\n********************************************************************************************\n SYNAPTIC\n********************************************************************************************\n\nSynaptic is a javascript neural network library for node.js and the browser, its generalized\nalgorithm is architecture-free, so you can build and train basically any type of first order\nor even second order neural network architectures.\n\nhttp://en.wikipedia.org/wiki/Recurrent_neural_network#Second_Order_Recurrent_Neural_Network\n\nThe library includes a few built-in architectures like multilayer perceptrons, multilayer\nlong-short term memory networks (LSTM) or liquid state machines, and a trainer capable of\ntraining any given network, and includes built-in training tasks/tests like solving an XOR,\npassing a Distracted Sequence Recall test or an Embeded Reber Grammar test.\n\nThe algorithm implemented by this library has been taken from Derek D. Monner\'s paper:\n\n\nA generalized LSTM-like training algorithm for second-order recurrent neural networks\nhttp://www.overcomplete.net/papers/nn2012.pdf\n\nThere are references to the equations in that paper commented through the source code.\n\n\n********************************************************************************************/\n'
|
||||
var globals = 'var Neuron = synaptic.Neuron, Layer = synaptic.Layer, Network = synaptic.Network, Trainer = synaptic.Trainer, Architect = synaptic.Architect;';
|
||||
var license = '/*\n\nThe MIT License (MIT)\n\nCopyright (c) 2014 Juan Cazala - juancazala.com\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the "Software"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE\n\n\n\n********************************************************************************************\n SYNAPTIC\n********************************************************************************************\n\nSynaptic is a javascript neural network library for node.js and the browser, its generalized\nalgorithm is architecture-free, so you can build and train basically any type of first order\nor even second order neural network architectures.\n\nhttp://en.wikipedia.org/wiki/Recurrent_neural_network#Second_Order_Recurrent_Neural_Network\n\nThe library includes a few built-in architectures like multilayer perceptrons, multilayer\nlong-short term memory networks (LSTM) or liquid state machines, and a trainer capable of\ntraining any given network, and includes built-in training tasks/tests like solving an XOR,\npassing a Distracted Sequence Recall test or an Embeded Reber Grammar test.\n\nThe algorithm implemented by this library has been taken from Derek D. Monner\'s paper:\n\n\nA generalized LSTM-like training algorithm for second-order recurrent neural networks\nhttp://www.overcomplete.net/papers/nn2012.pdf\n\nThere are references to the equations in that paper commented through the source code.\n\n\n********************************************************************************************/\n';
|
||||
var globals = 'var synaptic = synaptic || Synaptic;var Neuron = synaptic.Neuron, Layer = synaptic.Layer, Network = synaptic.Network, Trainer = synaptic.Trainer, Architect = synaptic.Architect;';
|
||||
|
||||
// import
|
||||
var gulp = require('gulp');
|
||||
@@ -12,13 +12,35 @@ var prepend = require('gulp-insert').prepend;
|
||||
var append = require('gulp-insert').append;
|
||||
var source = require('vinyl-source-stream');
|
||||
var buffer = require('vinyl-buffer');
|
||||
var ts = require('gulp-typescript');
|
||||
var merge2 = require('merge2');
|
||||
|
||||
var sm = require('gulp-sourcemaps');
|
||||
|
||||
// default task: runs all the tests, and builds all the files into dist (minified and unminifed)
|
||||
gulp.task('default', ['test', 'build', 'min']);
|
||||
gulp.task('default', ['test', 'build', 'min', 'node']);
|
||||
|
||||
|
||||
var tsProject = ts.createProject('tsconfig.json');
|
||||
|
||||
// build typescript sources
|
||||
gulp.task('node', function () {
|
||||
var tsResult = tsProject.src() // instead of gulp.src(...)
|
||||
.pipe(sm.init())
|
||||
.pipe(ts(tsProject));
|
||||
|
||||
return merge2([
|
||||
tsResult.js.pipe(sm.write()).pipe(gulp.dest('./dist')),
|
||||
tsResult.dts.pipe(gulp.dest('./dist'))
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
// build source into /dist for the web
|
||||
gulp.task('build', function () {
|
||||
return browserify({ entries: ['./src/synaptic.js'] })
|
||||
return browserify()
|
||||
.add('./src/synaptic.ts')
|
||||
.plugin('tsify')
|
||||
.bundle()
|
||||
.pipe(source('synaptic.js'))
|
||||
.pipe(buffer())
|
||||
@@ -28,34 +50,36 @@ gulp.task('build', function () {
|
||||
|
||||
// build source into /dist for web (minified)
|
||||
gulp.task('min', function () {
|
||||
return browserify({ entries: ['./src/synaptic.js'] })
|
||||
return browserify({})
|
||||
.add('./src/synaptic.ts')
|
||||
.plugin('tsify')
|
||||
.bundle()
|
||||
.pipe(source('synaptic.min.js'))
|
||||
.pipe(buffer())
|
||||
.pipe(uglify())
|
||||
.pipe(prepend(license))
|
||||
.pipe(append(globals))
|
||||
.pipe(gulp.dest('./dist'));
|
||||
});
|
||||
|
||||
// build source into /dist with sourcemaps for debugging
|
||||
gulp.task('debug', function () {
|
||||
return browserify({ entries: ['./src/synaptic.js'], debug: true })
|
||||
gulp.task('debug', ['tsc'], function () {
|
||||
return browserify({ debug: true })
|
||||
.add('./src/synaptic.ts')
|
||||
.plugin('tsify')
|
||||
.bundle()
|
||||
.pipe(source('synaptic.js'))
|
||||
.pipe(buffer())
|
||||
.pipe(prepend(license))
|
||||
.pipe(append(globals))
|
||||
.pipe(gulp.dest('./dist'));
|
||||
});
|
||||
|
||||
// run all the tests with mocha
|
||||
gulp.task('test', function () {
|
||||
gulp.task('test', ['node'], function () {
|
||||
return gulp.src('test/synaptic.js', {read: false})
|
||||
.pipe(mocha());
|
||||
});
|
||||
|
||||
// watch for changed and re-build (debug)
|
||||
gulp.task('dev', function () {
|
||||
gulp.watch('./src/*.js', ['debug']);
|
||||
gulp.watch('./src/*.ts', ['debug']);
|
||||
});
|
||||
|
||||
+13
-6
@@ -2,7 +2,7 @@
|
||||
"name": "synaptic",
|
||||
"version": "0.1.7",
|
||||
"description": "Architecture-free neural network library",
|
||||
"main": "./src/synaptic",
|
||||
"main": "./node-dist/src/synaptic",
|
||||
"scripts": {
|
||||
"test": "mocha test"
|
||||
},
|
||||
@@ -16,7 +16,11 @@
|
||||
"gulp-util": "^3.0.4",
|
||||
"vinyl-buffer": "^1.0.0",
|
||||
"vinyl-source-stream": "^1.1.0",
|
||||
"mocha": "^2.2.4"
|
||||
"mocha": "^2.2.4",
|
||||
"typescript": "^1.5.0-beta",
|
||||
"gulp-typescript": "*",
|
||||
"merge2": "*",
|
||||
"tsify": "*"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -30,10 +34,13 @@
|
||||
"architecture free"
|
||||
],
|
||||
"author": "Juan Cazala <juancazala@gmail.com> (http://juancazala.com/)",
|
||||
"license": {
|
||||
"type": "MIT",
|
||||
"url": "https://github.com/cazala/synaptic/blob/master/LICENSE"
|
||||
},
|
||||
"contributors": [
|
||||
{
|
||||
"name": "Agustin Mendez",
|
||||
"email": "agustin@soflex.com.ar"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/cazala/synaptic/issues"
|
||||
},
|
||||
|
||||
@@ -1,274 +0,0 @@
|
||||
// import
|
||||
var Layer = require('./layer'),
|
||||
Network = require('./network'),
|
||||
Trainer = require('./trainer');
|
||||
|
||||
/*******************************************************************************************
|
||||
ARCHITECT
|
||||
*******************************************************************************************/
|
||||
|
||||
// Colection of useful built-in architectures
|
||||
var Architect = {
|
||||
|
||||
// Multilayer Perceptron
|
||||
Perceptron: function Perceptron() {
|
||||
|
||||
var args = Array.prototype.slice.call(arguments); // convert arguments to Array
|
||||
if (args.length < 3)
|
||||
throw "Error: not enough layers (minimum 3) !!";
|
||||
|
||||
var inputs = args.shift(); // first argument
|
||||
var outputs = args.pop(); // last argument
|
||||
var layers = args; // all the arguments in the middle
|
||||
|
||||
var input = new Layer(inputs);
|
||||
var hidden = [];
|
||||
var output = new Layer(outputs);
|
||||
|
||||
var previous = input;
|
||||
|
||||
// generate hidden layers
|
||||
for (level in layers) {
|
||||
var size = layers[level];
|
||||
var layer = new Layer(size);
|
||||
hidden.push(layer);
|
||||
previous.project(layer);
|
||||
previous = layer;
|
||||
}
|
||||
previous.project(output);
|
||||
|
||||
// set layers of the neural network
|
||||
this.set({
|
||||
input: input,
|
||||
hidden: hidden,
|
||||
output: output
|
||||
});
|
||||
|
||||
// trainer for the network
|
||||
this.trainer = new Trainer(this);
|
||||
},
|
||||
|
||||
// Multilayer Long Short-Term Memory
|
||||
LSTM: function LSTM() {
|
||||
|
||||
var args = Array.prototype.slice.call(arguments); // convert arguments to array
|
||||
if (args.length < 3)
|
||||
throw "Error: not enough layers (minimum 3) !!";
|
||||
|
||||
var last = args.pop();
|
||||
var option = {
|
||||
peepholes: Layer.connectionType.ALL_TO_ALL,
|
||||
hiddentohidden: false,
|
||||
outtohidden: false,
|
||||
outtogates: false,
|
||||
intoout: true,
|
||||
};
|
||||
if (typeof last != 'number') {
|
||||
var outputs = args.pop();
|
||||
if (last.hasOwnProperty('peepholes'))
|
||||
option.peepholes = last.peepholes;
|
||||
if (last.hasOwnProperty('hiddentohidden'))
|
||||
option.hiddentohidden = last.hiddentohidden;
|
||||
if (last.hasOwnProperty('outtohidden'))
|
||||
option.outtohidden = last.outtohidden;
|
||||
if (last.hasOwnProperty('outtogates'))
|
||||
option.outtogates = last.outtogates;
|
||||
if (last.hasOwnProperty('intoout'))
|
||||
option.intoout = last.intoout;
|
||||
} else
|
||||
var outputs = last;
|
||||
|
||||
var inputs = args.shift();
|
||||
var layers = args;
|
||||
|
||||
var inputLayer = new Layer(inputs);
|
||||
var hiddenLayers = [];
|
||||
var outputLayer = new Layer(outputs);
|
||||
|
||||
var previous = null;
|
||||
|
||||
// generate layers
|
||||
for (var layer in layers) {
|
||||
// generate memory blocks (memory cell and respective gates)
|
||||
var size = layers[layer];
|
||||
|
||||
var inputGate = new Layer(size).set({
|
||||
bias: 1
|
||||
});
|
||||
var forgetGate = new Layer(size).set({
|
||||
bias: 1
|
||||
});
|
||||
var memoryCell = new Layer(size);
|
||||
var outputGate = new Layer(size).set({
|
||||
bias: 1
|
||||
});
|
||||
|
||||
hiddenLayers.push(inputGate);
|
||||
hiddenLayers.push(forgetGate);
|
||||
hiddenLayers.push(memoryCell);
|
||||
hiddenLayers.push(outputGate);
|
||||
|
||||
// connections from input layer
|
||||
var input = inputLayer.project(memoryCell);
|
||||
inputLayer.project(inputGate);
|
||||
inputLayer.project(forgetGate);
|
||||
inputLayer.project(outputGate);
|
||||
|
||||
// connections from previous memory-block layer to this one
|
||||
if (previous != null) {
|
||||
var cell = previous.project(memoryCell);
|
||||
previous.project(inputGate);
|
||||
previous.project(forgetGate);
|
||||
previous.project(outputGate);
|
||||
}
|
||||
|
||||
// connections from memory cell
|
||||
var output = memoryCell.project(outputLayer);
|
||||
|
||||
// self-connection
|
||||
var self = memoryCell.project(memoryCell);
|
||||
|
||||
// hidden to hidden recurrent connection
|
||||
if (option.hiddentohidden)
|
||||
memoryCell.project(memoryCell, Layer.connectionType.ALL_TO_ELSE);
|
||||
|
||||
// out to hidden recurrent connection
|
||||
if (option.outtohidden)
|
||||
outputLayer.project(memoryCell);
|
||||
|
||||
// out to gates recurrent connection
|
||||
if (option.outtogates) {
|
||||
outputLayer.project(inputGate);
|
||||
outputLayer.project(outputGate);
|
||||
outputLayer.project(forgetGate);
|
||||
}
|
||||
|
||||
// peepholes
|
||||
memoryCell.project(inputGate, option.peepholes);
|
||||
memoryCell.project(forgetGate, option.peepholes);
|
||||
memoryCell.project(outputGate, option.peepholes);
|
||||
|
||||
// gates
|
||||
inputGate.gate(input, Layer.gateType.INPUT);
|
||||
forgetGate.gate(self, Layer.gateType.ONE_TO_ONE);
|
||||
outputGate.gate(output, Layer.gateType.OUTPUT);
|
||||
if (previous != null)
|
||||
inputGate.gate(cell, Layer.gateType.INPUT);
|
||||
|
||||
previous = memoryCell;
|
||||
}
|
||||
|
||||
// input to output direct connection
|
||||
if (option.intoout)
|
||||
inputLayer.project(outputLayer);
|
||||
|
||||
// set the layers of the neural network
|
||||
this.set({
|
||||
input: inputLayer,
|
||||
hidden: hiddenLayers,
|
||||
output: outputLayer
|
||||
});
|
||||
|
||||
// trainer
|
||||
this.trainer = new Trainer(this);
|
||||
},
|
||||
|
||||
// Liquid State Machine
|
||||
Liquid: function Liquid(inputs, hidden, outputs, connections, gates) {
|
||||
|
||||
// create layers
|
||||
var inputLayer = new Layer(inputs);
|
||||
var hiddenLayer = new Layer(hidden);
|
||||
var outputLayer = new Layer(outputs);
|
||||
|
||||
// make connections and gates randomly among the neurons
|
||||
var neurons = hiddenLayer.neurons();
|
||||
var connectionList = [];
|
||||
|
||||
for (var i = 0; i < connections; i++) {
|
||||
// connect two random neurons
|
||||
var from = Math.random() * neurons.length | 0;
|
||||
var to = Math.random() * neurons.length | 0;
|
||||
var connection = neurons[from].project(neurons[to]);
|
||||
connectionList.push(connection);
|
||||
}
|
||||
|
||||
for (var j = 0; j < gates; j++) {
|
||||
// pick a random gater neuron
|
||||
var gater = Math.random() * neurons.length | 0;
|
||||
// pick a random connection to gate
|
||||
var connection = Math.random() * connectionList.length | 0;
|
||||
// let the gater gate the connection
|
||||
neurons[gater].gate(connectionList[connection]);
|
||||
}
|
||||
|
||||
// connect the layers
|
||||
inputLayer.project(hiddenLayer);
|
||||
hiddenLayer.project(outputLayer);
|
||||
|
||||
// set the layers of the network
|
||||
this.set({
|
||||
input: inputLayer,
|
||||
hidden: [hiddenLayer],
|
||||
output: outputLayer
|
||||
});
|
||||
|
||||
// trainer
|
||||
this.trainer = new Trainer(this);
|
||||
},
|
||||
|
||||
Hopfield: function Hopfield(size)
|
||||
{
|
||||
var inputLayer = new Layer(size);
|
||||
var outputLayer = new Layer(size);
|
||||
|
||||
inputLayer.project(outputLayer, Layer.connectionType.ALL_TO_ALL);
|
||||
|
||||
this.set({
|
||||
input: inputLayer,
|
||||
hidden: [],
|
||||
output: outputLayer
|
||||
});
|
||||
|
||||
var trainer = new Trainer(this);
|
||||
|
||||
var proto = Architect.Hopfield.prototype;
|
||||
|
||||
proto.learn = proto.learn || function(patterns)
|
||||
{
|
||||
var set = [];
|
||||
for (var p in patterns)
|
||||
set.push({
|
||||
input: patterns[p],
|
||||
output: patterns[p]
|
||||
});
|
||||
|
||||
return trainer.train(set, {
|
||||
iterations: 500000,
|
||||
error: .00005,
|
||||
rate: 1
|
||||
});
|
||||
}
|
||||
|
||||
proto.feed = proto.feed || function(pattern)
|
||||
{
|
||||
var output = this.activate(pattern);
|
||||
|
||||
var pattern = [];
|
||||
for (var i in output)
|
||||
pattern[i] = output[i] > .5 ? 1 : 0;
|
||||
|
||||
return pattern;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extend prototype chain (so every architectures is an instance of Network)
|
||||
for (var architecture in Architect) {
|
||||
Architect[architecture].prototype = new Network();
|
||||
Architect[architecture].prototype.constructor = Architect[architecture];
|
||||
}
|
||||
|
||||
// export
|
||||
if (module) module.exports = Architect;
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import hopfield = require('./architect/Hopfield');
|
||||
import lstm = require('./architect/LSTM');
|
||||
import lsm = require('./architect/Liquid');
|
||||
import perceptron = require('./architect/Perceptron');
|
||||
|
||||
export var LSTM = lstm.LSTM;
|
||||
export var Liquid = lsm.Liquid;
|
||||
export var Hopfield = hopfield.Hopfield;
|
||||
export var Perceptron = perceptron.Perceptron;
|
||||
@@ -0,0 +1,48 @@
|
||||
import network = require('../network');
|
||||
import trainer = require('../trainer');
|
||||
import layer = require('../layer');
|
||||
import neuron = require('../neuron');
|
||||
|
||||
export class Hopfield extends network.Network {
|
||||
trainer: trainer.Trainer;
|
||||
|
||||
constructor(size: number) {
|
||||
var inputLayer = new layer.Layer(size);
|
||||
var outputLayer = new layer.Layer(size);
|
||||
|
||||
inputLayer.project(outputLayer, layer.Layer.connectionType.ALL_TO_ALL);
|
||||
|
||||
super({
|
||||
input: inputLayer,
|
||||
hidden: [],
|
||||
output: outputLayer
|
||||
});
|
||||
|
||||
this.trainer = new trainer.Trainer(this);
|
||||
}
|
||||
|
||||
learn(patterns) {
|
||||
var set = [];
|
||||
for (var p in patterns)
|
||||
set.push({
|
||||
input: patterns[p],
|
||||
output: patterns[p]
|
||||
});
|
||||
|
||||
return this.trainer.train(set, {
|
||||
iterations: 500000,
|
||||
error: .00005,
|
||||
rate: 1
|
||||
});
|
||||
}
|
||||
|
||||
feed(pattern) {
|
||||
var output = this.activate(pattern);
|
||||
|
||||
var patterns = [];
|
||||
for (var i in output)
|
||||
patterns[i] = output[i] > .5 ? 1 : 0;
|
||||
|
||||
return patterns;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
import network = require('../network');
|
||||
import trainer = require('../trainer');
|
||||
import Layer = require('../layer');
|
||||
import neuron = require('../neuron');
|
||||
|
||||
export class LSTM extends network.Network {
|
||||
trainer: trainer.Trainer;
|
||||
|
||||
constructor(...args: any[]) {
|
||||
|
||||
if (args.length < 3)
|
||||
throw "Error: not enough layers (minimum 3) !!";
|
||||
|
||||
var last = args.pop();
|
||||
var option = {
|
||||
peepholes: Layer.Layer.connectionType.ALL_TO_ALL,
|
||||
hiddentohidden: false,
|
||||
outtohidden: false,
|
||||
outtogates: false,
|
||||
intoout: true,
|
||||
};
|
||||
|
||||
if (typeof last != 'number') {
|
||||
var outputs = args.pop();
|
||||
if (last.hasOwnProperty('peepholes'))
|
||||
option.peepholes = last.peepholes;
|
||||
if (last.hasOwnProperty('hiddentohidden'))
|
||||
option.hiddentohidden = last.hiddentohidden;
|
||||
if (last.hasOwnProperty('outtohidden'))
|
||||
option.outtohidden = last.outtohidden;
|
||||
if (last.hasOwnProperty('outtogates'))
|
||||
option.outtogates = last.outtogates;
|
||||
if (last.hasOwnProperty('intoout'))
|
||||
option.intoout = last.intoout;
|
||||
} else
|
||||
var outputs = last;
|
||||
|
||||
var inputs = args.shift();
|
||||
var layers = args;
|
||||
|
||||
var inputLayer = new Layer.Layer(inputs);
|
||||
var hiddenLayers = [];
|
||||
var outputLayer = new Layer.Layer(outputs);
|
||||
|
||||
var previous = null;
|
||||
|
||||
// generate layers
|
||||
for (var layer in layers) {
|
||||
// generate memory blocks (memory cell and respective gates)
|
||||
var size = layers[layer];
|
||||
|
||||
var inputGate = new Layer.Layer(size).set({
|
||||
bias: 1
|
||||
});
|
||||
var forgetGate = new Layer.Layer(size).set({
|
||||
bias: 1
|
||||
});
|
||||
var memoryCell = new Layer.Layer(size);
|
||||
var outputGate = new Layer.Layer(size).set({
|
||||
bias: 1
|
||||
});
|
||||
|
||||
hiddenLayers.push(inputGate);
|
||||
hiddenLayers.push(forgetGate);
|
||||
hiddenLayers.push(memoryCell);
|
||||
hiddenLayers.push(outputGate);
|
||||
|
||||
// connections from input layer
|
||||
var input = inputLayer.project(memoryCell);
|
||||
inputLayer.project(inputGate);
|
||||
inputLayer.project(forgetGate);
|
||||
inputLayer.project(outputGate);
|
||||
|
||||
// connections from previous memory-block layer to this one
|
||||
if (previous != null) {
|
||||
var cell = previous.project(memoryCell);
|
||||
previous.project(inputGate);
|
||||
previous.project(forgetGate);
|
||||
previous.project(outputGate);
|
||||
}
|
||||
|
||||
// connections from memory cell
|
||||
var output = memoryCell.project(outputLayer);
|
||||
|
||||
// self-connection
|
||||
var self = memoryCell.project(memoryCell);
|
||||
|
||||
// hidden to hidden recurrent connection
|
||||
if (option.hiddentohidden)
|
||||
memoryCell.project(memoryCell, Layer.Layer.connectionType.ALL_TO_ELSE);
|
||||
|
||||
// out to hidden recurrent connection
|
||||
if (option.outtohidden)
|
||||
outputLayer.project(memoryCell);
|
||||
|
||||
// out to gates recurrent connection
|
||||
if (option.outtogates) {
|
||||
outputLayer.project(inputGate);
|
||||
outputLayer.project(outputGate);
|
||||
outputLayer.project(forgetGate);
|
||||
}
|
||||
|
||||
// peepholes
|
||||
memoryCell.project(inputGate, option.peepholes);
|
||||
memoryCell.project(forgetGate, option.peepholes);
|
||||
memoryCell.project(outputGate, option.peepholes);
|
||||
|
||||
// gates
|
||||
inputGate.gate(input, Layer.Layer.gateType.INPUT);
|
||||
forgetGate.gate(self, Layer.Layer.gateType.ONE_TO_ONE);
|
||||
outputGate.gate(output, Layer.Layer.gateType.OUTPUT);
|
||||
if (previous != null)
|
||||
inputGate.gate(cell, Layer.Layer.gateType.INPUT);
|
||||
|
||||
previous = memoryCell;
|
||||
}
|
||||
|
||||
// input to output direct connection
|
||||
if (option.intoout)
|
||||
inputLayer.project(outputLayer);
|
||||
|
||||
// set the layers of the neural network
|
||||
super({
|
||||
input: inputLayer,
|
||||
hidden: hiddenLayers,
|
||||
output: outputLayer
|
||||
});
|
||||
|
||||
// trainer
|
||||
this.trainer = new trainer.Trainer(this);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,51 @@
|
||||
import network = require('../network');
|
||||
import trainer = require('../trainer');
|
||||
import layer = require('../layer');
|
||||
import neuron = require('../neuron');
|
||||
|
||||
export class Liquid extends network.Network {
|
||||
trainer: trainer.Trainer;
|
||||
|
||||
constructor(inputs, hidden, outputs, connections, gates) {
|
||||
|
||||
// create layers
|
||||
var inputLayer = new layer.Layer(inputs);
|
||||
var hiddenLayer = new layer.Layer(hidden);
|
||||
var outputLayer = new layer.Layer(outputs);
|
||||
|
||||
// make connections and gates randomly among the neurons
|
||||
var neurons = hiddenLayer.neurons();
|
||||
var connectionList: neuron.Neuron.Connection[] = [];
|
||||
|
||||
for (var i = 0; i < connections; i++) {
|
||||
// connect two random neurons
|
||||
var from = Math.random() * neurons.length | 0;
|
||||
var to = Math.random() * neurons.length | 0;
|
||||
var connection = neurons[from].project(neurons[to]);
|
||||
connectionList.push(connection);
|
||||
}
|
||||
|
||||
for (var j = 0; j < gates; j++) {
|
||||
// pick a random gater neuron
|
||||
var gater = Math.random() * neurons.length | 0;
|
||||
// pick a random connection to gate
|
||||
var connectionNumber = Math.random() * connectionList.length | 0;
|
||||
// let the gater gate the connection
|
||||
neurons[gater].gate(connectionList[connectionNumber]);
|
||||
}
|
||||
|
||||
// connect the layers
|
||||
inputLayer.project(hiddenLayer);
|
||||
hiddenLayer.project(outputLayer);
|
||||
|
||||
// set the layers of the network
|
||||
super({
|
||||
input: inputLayer,
|
||||
hidden: [hiddenLayer],
|
||||
output: outputLayer
|
||||
});
|
||||
|
||||
// trainer
|
||||
this.trainer = new trainer.Trainer(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import network = require('../network');
|
||||
import trainer = require('../trainer');
|
||||
import layer = require('../layer');
|
||||
import neuron = require('../neuron');
|
||||
// Multilayer Perceptron
|
||||
export class Perceptron extends network.Network {
|
||||
trainer: trainer.Trainer;
|
||||
|
||||
constructor(...args: number[]) {
|
||||
|
||||
if (args.length < 3)
|
||||
throw "Error: not enough layers (minimum 3) !!";
|
||||
|
||||
var inputs = args.shift(); // first argument
|
||||
var outputs = args.pop(); // last argument
|
||||
var layers = args; // all the arguments in the middle
|
||||
|
||||
var input = new layer.Layer(inputs);
|
||||
var hidden = [];
|
||||
var output = new layer.Layer(outputs);
|
||||
|
||||
var previous = input;
|
||||
|
||||
// generate hidden layers
|
||||
for (var level in layers) {
|
||||
var size = layers[level];
|
||||
var theLayer = new layer.Layer(size);
|
||||
hidden.push(theLayer);
|
||||
previous.project(theLayer);
|
||||
previous = theLayer;
|
||||
}
|
||||
previous.project(output);
|
||||
|
||||
// set layers of the neural network
|
||||
|
||||
super({
|
||||
input: input,
|
||||
hidden: hidden,
|
||||
output: output
|
||||
});
|
||||
|
||||
// trainer for the network
|
||||
this.trainer = new trainer.Trainer(this);
|
||||
}
|
||||
};
|
||||
-276
@@ -1,276 +0,0 @@
|
||||
// import
|
||||
var Neuron = require('./neuron');
|
||||
|
||||
/*******************************************************************************************
|
||||
LAYER
|
||||
*******************************************************************************************/
|
||||
|
||||
function Layer(size, label) {
|
||||
this.size = size | 0;
|
||||
this.list = [];
|
||||
this.label = label || null;
|
||||
this.connectedto = [];
|
||||
|
||||
while (size--) {
|
||||
var neuron = new Neuron();
|
||||
this.list.push(neuron);
|
||||
}
|
||||
}
|
||||
|
||||
Layer.prototype = {
|
||||
|
||||
// activates all the neurons in the layer
|
||||
activate: function(input) {
|
||||
|
||||
var activations = [];
|
||||
|
||||
if (typeof input != 'undefined') {
|
||||
if (input.length != this.size)
|
||||
throw "INPUT size and LAYER size must be the same to activate!";
|
||||
|
||||
for (var id in this.list) {
|
||||
var neuron = this.list[id];
|
||||
var activation = neuron.activate(input[id]);
|
||||
activations.push(activation);
|
||||
}
|
||||
} else {
|
||||
for (var id in this.list) {
|
||||
var neuron = this.list[id];
|
||||
var activation = neuron.activate();
|
||||
activations.push(activation);
|
||||
}
|
||||
}
|
||||
return activations;
|
||||
},
|
||||
|
||||
// propagates the error on all the neurons of the layer
|
||||
propagate: function(rate, target) {
|
||||
|
||||
if (typeof target != 'undefined') {
|
||||
if (target.length != this.size)
|
||||
throw "TARGET size and LAYER size must be the same to propagate!";
|
||||
|
||||
for (var id = this.list.length - 1; id >= 0; id--) {
|
||||
var neuron = this.list[id];
|
||||
neuron.propagate(rate, target[id]);
|
||||
}
|
||||
} else {
|
||||
for (var id = this.list.length - 1; id >= 0; id--) {
|
||||
var neuron = this.list[id];
|
||||
neuron.propagate(rate);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// projects a connection from this layer to another one
|
||||
project: function(layer, type, weights) {
|
||||
|
||||
if (layer instanceof require('./network'))
|
||||
layer = layer.layers.input;
|
||||
|
||||
if (layer instanceof Layer) {
|
||||
if (!this.connected(layer))
|
||||
return new Layer.connection(this, layer, type, weights);
|
||||
} else
|
||||
throw "Invalid argument, you can only project connections to LAYERS and NETWORKS!";
|
||||
|
||||
|
||||
},
|
||||
|
||||
// gates a connection betwenn two layers
|
||||
gate: function(connection, type) {
|
||||
|
||||
if (type == Layer.gateType.INPUT) {
|
||||
if (connection.to.size != this.size)
|
||||
throw "GATER layer and CONNECTION.TO layer must be the same size in order to gate!";
|
||||
|
||||
for (var id in connection.to.list) {
|
||||
var neuron = connection.to.list[id];
|
||||
var gater = this.list[id];
|
||||
for (var input in neuron.connections.inputs) {
|
||||
var gated = neuron.connections.inputs[input];
|
||||
if (gated.ID in connection.connections)
|
||||
gater.gate(gated);
|
||||
}
|
||||
}
|
||||
} else if (type == Layer.gateType.OUTPUT) {
|
||||
if (connection.from.size != this.size)
|
||||
throw "GATER layer and CONNECTION.FROM layer must be the same size in order to gate!";
|
||||
|
||||
for (var id in connection.from.list) {
|
||||
var neuron = connection.from.list[id];
|
||||
var gater = this.list[id];
|
||||
for (var projected in neuron.connections.projected) {
|
||||
var gated = neuron.connections.projected[projected];
|
||||
if (gated.ID in connection.connections)
|
||||
gater.gate(gated);
|
||||
}
|
||||
}
|
||||
} else if (type == Layer.gateType.ONE_TO_ONE) {
|
||||
if (connection.size != this.size)
|
||||
throw "The number of GATER UNITS must be the same as the number of CONNECTIONS to gate!";
|
||||
|
||||
for (var id in connection.list) {
|
||||
var gater = this.list[id];
|
||||
var gated = connection.list[id];
|
||||
gater.gate(gated);
|
||||
}
|
||||
}
|
||||
connection.gatedfrom.push({layer: this, type: type});
|
||||
},
|
||||
|
||||
// true or false whether the whole layer is self-connected or not
|
||||
selfconnected: function() {
|
||||
|
||||
for (var id in this.list) {
|
||||
var neuron = this.list[id];
|
||||
if (!neuron.selfconnected())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
// true of false whether the layer is connected to another layer (parameter) or not
|
||||
connected: function(layer) {
|
||||
// Check if ALL to ALL connection
|
||||
var connections = 0;
|
||||
for (var here in this.list) {
|
||||
for (var there in layer.list) {
|
||||
var from = this.list[here];
|
||||
var to = layer.list[there];
|
||||
var connected = from.connected(to);
|
||||
if (connected.type == 'projected')
|
||||
connections++;
|
||||
}
|
||||
}
|
||||
if (connections == this.size * layer.size)
|
||||
return Layer.connectionType.ALL_TO_ALL;
|
||||
|
||||
// Check if ONE to ONE connection
|
||||
connections = 0;
|
||||
for (var neuron in this.list) {
|
||||
var from = this.list[neuron];
|
||||
var to = layer.list[neuron];
|
||||
var connected = from.connected(to);
|
||||
if (connected.type == 'projected')
|
||||
connections++;
|
||||
}
|
||||
if (connections == this.size)
|
||||
return Layer.connectionType.ONE_TO_ONE;
|
||||
},
|
||||
|
||||
// clears all the neuorns in the layer
|
||||
clear: function() {
|
||||
for (var id in this.list) {
|
||||
var neuron = this.list[id];
|
||||
neuron.clear();
|
||||
}
|
||||
},
|
||||
|
||||
// resets all the neurons in the layer
|
||||
reset: function() {
|
||||
for (var id in this.list) {
|
||||
var neuron = this.list[id];
|
||||
neuron.reset();
|
||||
}
|
||||
},
|
||||
|
||||
// returns all the neurons in the layer (array)
|
||||
neurons: function() {
|
||||
return this.list;
|
||||
},
|
||||
|
||||
// adds a neuron to the layer
|
||||
add: function(neuron) {
|
||||
this.neurons[neuron.ID] = neuron || new Neuron();
|
||||
this.list.push(neuron);
|
||||
this.size++;
|
||||
},
|
||||
|
||||
set: function(options) {
|
||||
options = options || {};
|
||||
|
||||
for (var i in this.list) {
|
||||
var neuron = this.list[i];
|
||||
if (options.label)
|
||||
neuron.label = options.label + '_' + neuron.ID;
|
||||
if (options.squash)
|
||||
neuron.squash = options.squash;
|
||||
if (options.bias)
|
||||
neuron.bias = options.bias;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
// represents a connection from one layer to another, and keeps track of its weight and gain
|
||||
Layer.connection = function LayerConnection(fromLayer, toLayer, type, weights) {
|
||||
this.ID = Layer.connection.uid();
|
||||
this.from = fromLayer;
|
||||
this.to = toLayer;
|
||||
this.selfconnection = toLayer == fromLayer;
|
||||
this.type = type;
|
||||
this.connections = {};
|
||||
this.list = [];
|
||||
this.size = 0;
|
||||
this.gatedfrom = [];
|
||||
|
||||
if (typeof this.type == 'undefined')
|
||||
{
|
||||
if (fromLayer == toLayer)
|
||||
this.type = Layer.connectionType.ONE_TO_ONE;
|
||||
else
|
||||
this.type = Layer.connectionType.ALL_TO_ALL;
|
||||
}
|
||||
|
||||
if (this.type == Layer.connectionType.ALL_TO_ALL ||
|
||||
this.type == Layer.connectionType.ALL_TO_ELSE) {
|
||||
for (var here in this.from.list) {
|
||||
for (var there in this.to.list) {
|
||||
var from = this.from.list[here];
|
||||
var to = this.to.list[there];
|
||||
if(this.type == Layer.connectionType.ALL_TO_ELSE && from == to)
|
||||
continue;
|
||||
var connection = from.project(to, weights);
|
||||
|
||||
this.connections[connection.ID] = connection;
|
||||
this.size = this.list.push(connection);
|
||||
}
|
||||
}
|
||||
} else if (this.type == Layer.connectionType.ONE_TO_ONE) {
|
||||
|
||||
for (var neuron in this.from.list) {
|
||||
var from = this.from.list[neuron];
|
||||
var to = this.to.list[neuron];
|
||||
var connection = from.project(to, weights);
|
||||
|
||||
this.connections[connection.ID] = connection;
|
||||
this.size = this.list.push(connection);
|
||||
}
|
||||
}
|
||||
|
||||
fromLayer.connectedto.push(this);
|
||||
}
|
||||
|
||||
// types of connections
|
||||
Layer.connectionType = {};
|
||||
Layer.connectionType.ALL_TO_ALL = "ALL TO ALL";
|
||||
Layer.connectionType.ONE_TO_ONE = "ONE TO ONE";
|
||||
Layer.connectionType.ALL_TO_ELSE = "ALL TO ELSE";
|
||||
|
||||
// types of gates
|
||||
Layer.gateType = {};
|
||||
Layer.gateType.INPUT = "INPUT";
|
||||
Layer.gateType.OUTPUT = "OUTPUT";
|
||||
Layer.gateType.ONE_TO_ONE = "ONE TO ONE";
|
||||
|
||||
(function() {
|
||||
var connections = 0;
|
||||
Layer.connection.uid = function() {
|
||||
return connections++;
|
||||
}
|
||||
})();
|
||||
|
||||
// export
|
||||
if (module) module.exports = Layer;
|
||||
|
||||
+292
@@ -0,0 +1,292 @@
|
||||
import neuron = require('./neuron');
|
||||
import network = require('./network');
|
||||
import Synaptic = require('./synaptic');
|
||||
|
||||
/*******************************************************************************************
|
||||
LAYER
|
||||
*******************************************************************************************/
|
||||
export class Layer {
|
||||
list: neuron.Neuron[] = [];
|
||||
label: string = null;
|
||||
connectedto = [];
|
||||
size = 0;
|
||||
|
||||
constructor(size: number, label?: string) {
|
||||
this.size = size | 0;
|
||||
this.list = [];
|
||||
this.label = label || null;
|
||||
this.connectedto = [];
|
||||
|
||||
while (size--) {
|
||||
var theNeuron = new neuron.Neuron();
|
||||
this.list.push(theNeuron);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// activates all the neurons in the layer
|
||||
activate(input) {
|
||||
|
||||
var activations = [];
|
||||
|
||||
if (typeof input != 'undefined') {
|
||||
if (input.length != this.size)
|
||||
throw "INPUT size and LAYER size must be the same to activate!";
|
||||
|
||||
for (var id in this.list) {
|
||||
var neuron = this.list[id];
|
||||
var activation = neuron.activate(input[id]);
|
||||
activations.push(activation);
|
||||
}
|
||||
} else {
|
||||
for (var id in this.list) {
|
||||
var neuron = this.list[id];
|
||||
var activation = neuron.activate();
|
||||
activations.push(activation);
|
||||
}
|
||||
}
|
||||
return activations;
|
||||
}
|
||||
|
||||
// propagates the error on all the neurons of the layer
|
||||
propagate(rate, target) {
|
||||
|
||||
if (typeof target != 'undefined') {
|
||||
if (target.length != this.size)
|
||||
throw "TARGET size and LAYER size must be the same to propagate!";
|
||||
|
||||
for (var id = this.list.length - 1; id >= 0; id--) {
|
||||
var neuron = this.list[id];
|
||||
neuron.propagate(rate, target[id]);
|
||||
}
|
||||
} else {
|
||||
for (var id = this.list.length - 1; id >= 0; id--) {
|
||||
var neuron = this.list[id];
|
||||
neuron.propagate(rate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// projects a connection from this layer to another one
|
||||
project(layer, type?, weights?) {
|
||||
|
||||
if (layer instanceof network.Network)
|
||||
layer = layer.layers.input;
|
||||
|
||||
if (layer instanceof Layer) {
|
||||
if (!this.connected(layer))
|
||||
return new Layer.LayerConnection(this, layer, type, weights);
|
||||
} else
|
||||
throw "Invalid argument, you can only project connections to LAYERS and NETWORKS!";
|
||||
|
||||
|
||||
}
|
||||
|
||||
// gates a connection betwenn two layers
|
||||
gate(connection, type) {
|
||||
|
||||
if (type == Layer.gateType.INPUT) {
|
||||
if (connection.to.size != this.size)
|
||||
throw "GATER layer and CONNECTION.TO layer must be the same size in order to gate!";
|
||||
|
||||
for (var id in connection.to.list) {
|
||||
var neuron = connection.to.list[id];
|
||||
var gater = this.list[id];
|
||||
for (var input in neuron.connections.inputs) {
|
||||
var gated = neuron.connections.inputs[input];
|
||||
if (gated.ID in connection.connections)
|
||||
gater.gate(gated);
|
||||
}
|
||||
}
|
||||
} else if (type == Layer.gateType.OUTPUT) {
|
||||
if (connection.from.size != this.size)
|
||||
throw "GATER layer and CONNECTION.FROM layer must be the same size in order to gate!";
|
||||
|
||||
for (var id in connection.from.list) {
|
||||
var neuron = connection.from.list[id];
|
||||
var gater = this.list[id];
|
||||
for (var projected in neuron.connections.projected) {
|
||||
var gated = neuron.connections.projected[projected];
|
||||
if (gated.ID in connection.connections)
|
||||
gater.gate(gated);
|
||||
}
|
||||
}
|
||||
} else if (type == Layer.gateType.ONE_TO_ONE) {
|
||||
if (connection.size != this.size)
|
||||
throw "The number of GATER UNITS must be the same as the number of CONNECTIONS to gate!";
|
||||
|
||||
for (var id in connection.list) {
|
||||
var gater = this.list[id];
|
||||
var gated = connection.list[id];
|
||||
gater.gate(gated);
|
||||
}
|
||||
}
|
||||
connection.gatedfrom.push({ layer: this, type: type });
|
||||
}
|
||||
|
||||
// true or false whether the whole layer is self-connected or not
|
||||
selfconnected(): boolean {
|
||||
|
||||
for (var id in this.list) {
|
||||
var neuron = this.list[id];
|
||||
if (!neuron.selfconnected())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// true of false whether the layer is connected to another layer (parameter) or not
|
||||
connected(layer) {
|
||||
// Check if ALL to ALL connection
|
||||
var connections = 0;
|
||||
for (var here in this.list) {
|
||||
for (var there in layer.list) {
|
||||
var from = this.list[here];
|
||||
var to = layer.list[there];
|
||||
var connected = from.connected(to);
|
||||
if (connected && connected.type == 'projected')
|
||||
connections++;
|
||||
}
|
||||
}
|
||||
if (connections == this.size * layer.size)
|
||||
return Layer.connectionType.ALL_TO_ALL;
|
||||
|
||||
// Check if ONE to ONE connection
|
||||
connections = 0;
|
||||
for (var neuron in this.list) {
|
||||
var from = this.list[neuron];
|
||||
var to = layer.list[neuron];
|
||||
var connected = from.connected(to);
|
||||
if (connected && connected.type == 'projected')
|
||||
connections++;
|
||||
}
|
||||
if (connections == this.size)
|
||||
return Layer.connectionType.ONE_TO_ONE;
|
||||
}
|
||||
|
||||
// clears all the neuorns in the layer
|
||||
clear() {
|
||||
for (var id in this.list) {
|
||||
var neuron = this.list[id];
|
||||
neuron.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// resets all the neurons in the layer
|
||||
reset() {
|
||||
for (var id in this.list) {
|
||||
var neuron = this.list[id];
|
||||
neuron.reset();
|
||||
}
|
||||
}
|
||||
|
||||
// returns all the neurons in the layer (array)
|
||||
neurons() : neuron.Neuron[] {
|
||||
return this.list;
|
||||
}
|
||||
|
||||
// adds a neuron to the layer
|
||||
add(neuron) {
|
||||
neuron = neuron || new neuron.Neuron();
|
||||
this.neurons[neuron.ID] = neuron;
|
||||
this.list.push(neuron);
|
||||
this.size++;
|
||||
}
|
||||
|
||||
set(options) {
|
||||
options = options || {};
|
||||
|
||||
for (var i in this.list) {
|
||||
var neuron = this.list[i];
|
||||
if (options.label)
|
||||
neuron.label = options.label + '_' + neuron.ID;
|
||||
if (options.squash)
|
||||
neuron.squash = options.squash;
|
||||
if (options.bias)
|
||||
neuron.bias = options.bias;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export module Layer {
|
||||
export var layerQty = 0;
|
||||
export function uid() {
|
||||
return layerQty++;
|
||||
}
|
||||
|
||||
// types of connections
|
||||
export var connectionType = {
|
||||
ALL_TO_ALL: "ALL TO ALL",
|
||||
ONE_TO_ONE: "ONE TO ONE",
|
||||
ALL_TO_ELSE: "ALL TO ELSE"
|
||||
};
|
||||
|
||||
// types of gates
|
||||
export var gateType = {
|
||||
INPUT: "INPUT",
|
||||
OUTPUT: "OUTPUT",
|
||||
ONE_TO_ONE: "ONE TO ONE"
|
||||
};
|
||||
|
||||
// represents a connection from one layer to another, and keeps track of its weight and gain
|
||||
export class LayerConnection {
|
||||
ID = uid();
|
||||
from: Layer;
|
||||
to: Layer;
|
||||
selfconnection : boolean = false;
|
||||
type: string;
|
||||
connections: Synaptic.Dictionary<neuron.Neuron.Connection>;
|
||||
list: neuron.Neuron.Connection[];
|
||||
size = 0;
|
||||
gatedfrom = [];
|
||||
|
||||
constructor(fromLayer, toLayer, type, weights) {
|
||||
this.from = fromLayer;
|
||||
this.to = toLayer;
|
||||
this.selfconnection = toLayer == fromLayer;
|
||||
this.type = type;
|
||||
this.connections = {};
|
||||
this.list = [];
|
||||
this.size = 0;
|
||||
this.gatedfrom = [];
|
||||
|
||||
|
||||
if (typeof this.type == 'undefined') {
|
||||
if (fromLayer == toLayer)
|
||||
this.type = Layer.connectionType.ONE_TO_ONE;
|
||||
else
|
||||
this.type = Layer.connectionType.ALL_TO_ALL;
|
||||
}
|
||||
|
||||
if (this.type == Layer.connectionType.ALL_TO_ALL ||
|
||||
this.type == Layer.connectionType.ALL_TO_ELSE) {
|
||||
for (var here in this.from.list) {
|
||||
for (var there in this.to.list) {
|
||||
var from = this.from.list[here];
|
||||
var to = this.to.list[there];
|
||||
if (this.type == Layer.connectionType.ALL_TO_ELSE && from == to)
|
||||
continue;
|
||||
var connection = from.project(to, weights);
|
||||
|
||||
this.connections[connection.ID] = connection;
|
||||
this.size = this.list.push(connection);
|
||||
}
|
||||
}
|
||||
} else if (this.type == Layer.connectionType.ONE_TO_ONE) {
|
||||
|
||||
for (var neuron in this.from.list) {
|
||||
var from = this.from.list[neuron];
|
||||
var to = this.to.list[neuron];
|
||||
var connection = from.project(to, weights);
|
||||
|
||||
this.connections[connection.ID] = connection;
|
||||
this.size = this.list.push(connection);
|
||||
}
|
||||
}
|
||||
|
||||
fromLayer.connectedto.push(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,599 +0,0 @@
|
||||
// import
|
||||
var Neuron = require('./neuron'),
|
||||
Layer = require('./layer');
|
||||
|
||||
/*******************************************************************************************
|
||||
NETWORK
|
||||
*******************************************************************************************/
|
||||
|
||||
function Network(layers) {
|
||||
if (typeof layers != 'undefined') {
|
||||
this.layers = layers || {
|
||||
input: null,
|
||||
hidden: {},
|
||||
output: null
|
||||
};
|
||||
this.optimized = null;
|
||||
}
|
||||
}
|
||||
Network.prototype = {
|
||||
|
||||
// feed-forward activation of all the layers to produce an ouput
|
||||
activate: function(input) {
|
||||
|
||||
if (this.optimized === false)
|
||||
{
|
||||
this.layers.input.activate(input);
|
||||
for (var layer in this.layers.hidden)
|
||||
this.layers.hidden[layer].activate();
|
||||
return this.layers.output.activate();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.optimized == null)
|
||||
this.optimize();
|
||||
return this.optimized.activate(input);
|
||||
}
|
||||
},
|
||||
|
||||
// back-propagate the error thru the network
|
||||
propagate: function(rate, target) {
|
||||
|
||||
if (this.optimized === false)
|
||||
{
|
||||
this.layers.output.propagate(rate, target);
|
||||
var reverse = [];
|
||||
for (var layer in this.layers.hidden)
|
||||
reverse.push(this.layers.hidden[layer]);
|
||||
reverse.reverse();
|
||||
for (var layer in reverse)
|
||||
reverse[layer].propagate(rate);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.optimized == null)
|
||||
this.optimize();
|
||||
this.optimized.propagate(rate, target);
|
||||
}
|
||||
},
|
||||
|
||||
// project a connection to another unit (either a network or a layer)
|
||||
project: function(unit, type, weights) {
|
||||
|
||||
if (this.optimized)
|
||||
this.optimized.reset();
|
||||
|
||||
if (unit instanceof Network)
|
||||
return this.layers.output.project(unit.layers.input, type, weights);
|
||||
|
||||
if (unit instanceof Layer)
|
||||
return this.layers.output.project(unit, type, weights);
|
||||
|
||||
throw "Invalid argument, you can only project connections to LAYERS and NETWORKS!";
|
||||
},
|
||||
|
||||
// let this network gate a connection
|
||||
gate: function(connection, type) {
|
||||
if (this.optimized)
|
||||
this.optimized.reset();
|
||||
this.layers.output.gate(connection, type);
|
||||
},
|
||||
|
||||
// clear all elegibility traces and extended elegibility traces (the network forgets its context, but not what was trained)
|
||||
clear: function() {
|
||||
|
||||
this.restore();
|
||||
|
||||
var inputLayer = this.layers.input,
|
||||
outputLayer = this.layers.output;
|
||||
|
||||
inputLayer.clear();
|
||||
for (var layer in this.layers.hidden) {
|
||||
var hiddenLayer = this.layers.hidden[layer];
|
||||
hiddenLayer.clear();
|
||||
}
|
||||
outputLayer.clear();
|
||||
|
||||
if (this.optimized)
|
||||
this.optimized.reset();
|
||||
},
|
||||
|
||||
// reset all weights and clear all traces (ends up like a new network)
|
||||
reset: function() {
|
||||
|
||||
this.restore();
|
||||
|
||||
var inputLayer = this.layers.input,
|
||||
outputLayer = this.layers.output;
|
||||
|
||||
inputLayer.reset();
|
||||
for (var layer in this.layers.hidden) {
|
||||
var hiddenLayer = this.layers.hidden[layer];
|
||||
hiddenLayer.reset();
|
||||
}
|
||||
outputLayer.reset();
|
||||
|
||||
if (this.optimized)
|
||||
this.optimized.reset();
|
||||
},
|
||||
|
||||
// hardcodes the behaviour of the whole network into a single optimized function
|
||||
optimize: function() {
|
||||
|
||||
var that = this;
|
||||
var optimized = {};
|
||||
var neurons = this.neurons();
|
||||
|
||||
for (var i in neurons) {
|
||||
var neuron = neurons[i].neuron;
|
||||
var layer = neurons[i].layer;
|
||||
while (neuron.neuron)
|
||||
neuron = neuron.neuron;
|
||||
optimized = neuron.optimize(optimized, layer);
|
||||
}
|
||||
for (var i in optimized.propagation_sentences)
|
||||
optimized.propagation_sentences[i].reverse();
|
||||
optimized.propagation_sentences.reverse();
|
||||
|
||||
var hardcode = "";
|
||||
hardcode += "var F = Float64Array ? new Float64Array(" + optimized.memory +
|
||||
") : []; ";
|
||||
for (var i in optimized.variables)
|
||||
hardcode += "F[" + optimized.variables[i].id + "] = " + (optimized.variables[
|
||||
i].value || 0) + "; ";
|
||||
hardcode += "var activate = function(input){\n";
|
||||
hardcode += "influences = [];";
|
||||
for (var i in optimized.inputs)
|
||||
hardcode += "F[" + optimized.inputs[i] + "] = input[" + i + "]; ";
|
||||
for (var currentLayer in optimized.activation_sentences) {
|
||||
if (optimized.activation_sentences[currentLayer].length > 0) {
|
||||
for (var currentNeuron in optimized.activation_sentences[currentLayer]) {
|
||||
hardcode += optimized.activation_sentences[currentLayer][currentNeuron].join(" ");
|
||||
hardcode += optimized.trace_sentences[currentLayer][currentNeuron].join(" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
hardcode += " var output = []; "
|
||||
for (var i in optimized.outputs)
|
||||
hardcode += "output[" + i + "] = F[" + optimized.outputs[i] + "]; ";
|
||||
hardcode += "return output; }; "
|
||||
hardcode += "var propagate = function(rate, target){\n";
|
||||
hardcode += "F[" + optimized.variables.rate.id + "] = rate; ";
|
||||
for (var i in optimized.targets)
|
||||
hardcode += "F[" + optimized.targets[i] + "] = target[" + i + "]; ";
|
||||
for (var currentLayer in optimized.propagation_sentences)
|
||||
for (var currentNeuron in optimized.propagation_sentences[currentLayer])
|
||||
hardcode += optimized.propagation_sentences[currentLayer][currentNeuron].join(" ") + " ";
|
||||
hardcode += " };\n";
|
||||
hardcode +=
|
||||
"var ownership = function(memoryBuffer){\nF = memoryBuffer;\nthis.memory = F;\n};\n";
|
||||
hardcode +=
|
||||
"return {\nmemory: F,\nactivate: activate,\npropagate: propagate,\nownership: ownership\n};";
|
||||
hardcode = hardcode.split(";").join(";\n");
|
||||
|
||||
var constructor = new Function(hardcode);
|
||||
|
||||
var network = constructor();
|
||||
network.data = {
|
||||
variables: optimized.variables,
|
||||
activate: optimized.activation_sentences,
|
||||
propagate: optimized.propagation_sentences,
|
||||
trace: optimized.trace_sentences,
|
||||
inputs: optimized.inputs,
|
||||
outputs: optimized.outputs,
|
||||
check_activation: this.activate,
|
||||
check_propagation: this.propagate
|
||||
}
|
||||
|
||||
network.reset = function() {
|
||||
if (that.optimized) {
|
||||
that.optimized = null;
|
||||
that.activate = network.data.check_activation;
|
||||
that.propagate = network.data.check_propagation;
|
||||
}
|
||||
}
|
||||
|
||||
this.optimized = network;
|
||||
this.activate = network.activate;
|
||||
this.propagate = network.propagate;
|
||||
},
|
||||
|
||||
// restores all the values from the optimized network the their respective objects in order to manipulate the network
|
||||
restore: function() {
|
||||
if (!this.optimized)
|
||||
return;
|
||||
|
||||
var optimized = this.optimized;
|
||||
|
||||
var getValue = function() {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
|
||||
var unit = args.shift();
|
||||
var prop = args.pop();
|
||||
|
||||
var id = prop + '_';
|
||||
for (var property in args)
|
||||
id += args[property] + '_';
|
||||
id += unit.ID;
|
||||
|
||||
var memory = optimized.memory;
|
||||
var variables = optimized.data.variables;
|
||||
|
||||
if (id in variables)
|
||||
return memory[variables[id].id];
|
||||
return 0;
|
||||
}
|
||||
|
||||
var list = this.neurons();
|
||||
|
||||
// link id's to positions in the array
|
||||
var ids = {};
|
||||
for (var i in list) {
|
||||
var neuron = list[i].neuron;
|
||||
while (neuron.neuron)
|
||||
neuron = neuron.neuron;
|
||||
|
||||
neuron.state = getValue(neuron, 'state');
|
||||
neuron.old = getValue(neuron, 'old');
|
||||
neuron.activation = getValue(neuron, 'activation');
|
||||
neuron.bias = getValue(neuron, 'bias');
|
||||
|
||||
for (var input in neuron.trace.elegibility)
|
||||
neuron.trace.elegibility[input] = getValue(neuron, 'trace',
|
||||
'elegibility', input);
|
||||
|
||||
for (var gated in neuron.trace.extended)
|
||||
for (var input in neuron.trace.extended[gated])
|
||||
neuron.trace.extended[gated][input] = getValue(neuron, 'trace',
|
||||
'extended', gated, input);
|
||||
}
|
||||
|
||||
// get connections
|
||||
for (var i in list) {
|
||||
var neuron = list[i].neuron;
|
||||
while (neuron.neuron)
|
||||
neuron = neuron.neuron;
|
||||
|
||||
for (var j in neuron.connections.projected) {
|
||||
var connection = neuron.connections.projected[j];
|
||||
connection.weight = getValue(connection, 'weight');
|
||||
connection.gain = getValue(connection, 'gain');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// returns all the neurons in the network
|
||||
neurons: function() {
|
||||
|
||||
var neurons = [];
|
||||
|
||||
var inputLayer = this.layers.input.neurons(),
|
||||
outputLayer = this.layers.output.neurons();
|
||||
|
||||
for (var neuron in inputLayer)
|
||||
neurons.push({
|
||||
neuron: inputLayer[neuron],
|
||||
layer: 'input'
|
||||
});
|
||||
|
||||
for (var layer in this.layers.hidden) {
|
||||
var hiddenLayer = this.layers.hidden[layer].neurons();
|
||||
for (var neuron in hiddenLayer)
|
||||
neurons.push({
|
||||
neuron: hiddenLayer[neuron],
|
||||
layer: layer
|
||||
});
|
||||
}
|
||||
for (var neuron in outputLayer)
|
||||
neurons.push({
|
||||
neuron: outputLayer[neuron],
|
||||
layer: 'output'
|
||||
});
|
||||
|
||||
return neurons;
|
||||
},
|
||||
|
||||
// returns number of inputs of the network
|
||||
inputs: function() {
|
||||
return this.layers.input.size;
|
||||
},
|
||||
|
||||
// returns number of outputs of hte network
|
||||
outputs: function() {
|
||||
return this.layers.output.size;
|
||||
},
|
||||
|
||||
// sets the layers of the network
|
||||
set: function(layers) {
|
||||
|
||||
this.layers = layers;
|
||||
if (this.optimized)
|
||||
this.optimized.reset();
|
||||
},
|
||||
|
||||
setOptimize: function(bool){
|
||||
this.restore();
|
||||
if (this.optimized)
|
||||
this.optimized.reset();
|
||||
this.optimized = bool? null : false;
|
||||
},
|
||||
|
||||
// returns a json that represents all the neurons and connections of the network
|
||||
toJSON: function(ignoreTraces) {
|
||||
|
||||
this.restore();
|
||||
|
||||
var list = this.neurons();
|
||||
var neurons = [];
|
||||
var connections = [];
|
||||
|
||||
// link id's to positions in the array
|
||||
var ids = {};
|
||||
for (var i in list) {
|
||||
var neuron = list[i].neuron;
|
||||
while (neuron.neuron)
|
||||
neuron = neuron.neuron;
|
||||
ids[neuron.ID] = i;
|
||||
|
||||
var copy = {
|
||||
trace: {
|
||||
elegibility: {},
|
||||
extended: {}
|
||||
},
|
||||
state: neuron.state,
|
||||
old: neuron.old,
|
||||
activation: neuron.activation,
|
||||
bias: neuron.bias,
|
||||
layer: list[i].layer
|
||||
};
|
||||
|
||||
copy.squash = neuron.squash == Neuron.squash.LOGISTIC ? "LOGISTIC" :
|
||||
neuron.squash == Neuron.squash.TANH ? "TANH" :
|
||||
neuron.squash == Neuron.squash.IDENTITY ? "IDENTITY" :
|
||||
neuron.squash == Neuron.squash.HLIM ? "HLIM" :
|
||||
null;
|
||||
|
||||
neurons.push(copy);
|
||||
}
|
||||
|
||||
if (!ignoreTraces)
|
||||
for (var i in neurons) {
|
||||
var copy = neurons[i];
|
||||
|
||||
for (var input in neuron.trace.elegibility)
|
||||
copy.trace.elegibility[input] = neuron.trace.elegibility[input];
|
||||
|
||||
for (var gated in neuron.trace.extended) {
|
||||
copy.trace.extended[gated] = {};
|
||||
for (var input in neuron.trace.extended[gated])
|
||||
copy.trace.extended[ids[gated]][input] = neuron.trace.extended[
|
||||
gated][input];
|
||||
}
|
||||
}
|
||||
|
||||
// get connections
|
||||
for (var i in list) {
|
||||
var neuron = list[i].neuron;
|
||||
while (neuron.neuron)
|
||||
neuron = neuron.neuron;
|
||||
|
||||
for (var j in neuron.connections.projected) {
|
||||
var connection = neuron.connections.projected[j];
|
||||
connections.push({
|
||||
from: ids[connection.from.ID],
|
||||
to: ids[connection.to.ID],
|
||||
weight: connection.weight,
|
||||
gater: connection.gater ? ids[connection.gater.ID] : null,
|
||||
});
|
||||
}
|
||||
if (neuron.selfconnected())
|
||||
connections.push({
|
||||
from: ids[neuron.ID],
|
||||
to: ids[neuron.ID],
|
||||
weight: neuron.selfconnection.weight,
|
||||
gater: neuron.selfconnection.gater ? ids[neuron.selfconnection.gater
|
||||
.ID] : null,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
neurons: neurons,
|
||||
connections: connections
|
||||
}
|
||||
},
|
||||
|
||||
// export the topology into dot language which can be visualized as graphs using dot
|
||||
/* example: ... console.log(net.toDotLang());
|
||||
$ node example.js > example.dot
|
||||
$ dot example.dot -Tpng > out.png
|
||||
*/
|
||||
toDot: function(edgeconnection) {
|
||||
if (! typeof edgeconnection)
|
||||
edgeconnection = false;
|
||||
var code = "digraph nn {\n rankdir = BT\n";
|
||||
var layers = [this.layers.input].concat(this.layers.hidden, this.layers.output);
|
||||
for (var layer in layers) {
|
||||
for (var to in layers[layer].connectedto) { // projections
|
||||
var connection = layers[layer].connectedto[to];
|
||||
var layerto = connection.to;
|
||||
var size = connection.size;
|
||||
var layerID = layers.indexOf(layers[layer]);
|
||||
var layertoID = layers.indexOf(layerto);
|
||||
/* http://stackoverflow.com/questions/26845540/connect-edges-with-graph-dot
|
||||
* DOT does not support edge-to-edge connections
|
||||
* This workaround produces somewhat weird graphs ...
|
||||
*/
|
||||
if ( edgeconnection) {
|
||||
if (connection.gatedfrom.length) {
|
||||
var fakeNode = "fake" + layerID + "_" + layertoID;
|
||||
code += " " + fakeNode +
|
||||
" [label = \"\", shape = point, width = 0.01, height = 0.01]\n";
|
||||
code += " " + layerID + " -> " + fakeNode + " [label = " + size + ", arrowhead = none]\n";
|
||||
code += " " + fakeNode + " -> " + layertoID + "\n";
|
||||
} else
|
||||
code += " " + layerID + " -> " + layertoID + " [label = " + size + "]\n";
|
||||
for (var from in connection.gatedfrom) { // gatings
|
||||
var layerfrom = connection.gatedfrom[from].layer;
|
||||
var type = connection.gatedfrom[from].type;
|
||||
var layerfromID = layers.indexOf(layerfrom);
|
||||
code += " " + layerfromID + " -> " + fakeNode + " [color = blue]\n";
|
||||
}
|
||||
} else {
|
||||
code += " " + layerID + " -> " + layertoID + " [label = " + size + "]\n";
|
||||
for (var from in connection.gatedfrom) { // gatings
|
||||
var layerfrom = connection.gatedfrom[from].layer;
|
||||
var type = connection.gatedfrom[from].type;
|
||||
var layerfromID = layers.indexOf(layerfrom);
|
||||
code += " " + layerfromID + " -> " + layertoID + " [color = blue]\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
code += "}\n";
|
||||
return {
|
||||
code: code,
|
||||
link: "https://chart.googleapis.com/chart?chl=" + escape(code.replace("/ /g", "+")) + "&cht=gv"
|
||||
}
|
||||
},
|
||||
|
||||
// returns a function that works as the activation of the network and can be used without depending on the library
|
||||
standalone: function() {
|
||||
if (!this.optimized)
|
||||
this.optimize();
|
||||
|
||||
var data = this.optimized.data;
|
||||
|
||||
// build activation function
|
||||
var activation = "function (input) {\n";
|
||||
|
||||
// build inputs
|
||||
for (var i in data.inputs)
|
||||
activation += "F[" + data.inputs[i] + "] = input[" + i + "];\n";
|
||||
|
||||
// build network activation
|
||||
for (var neuron in data.activate) { // shouldn't this be layer?
|
||||
for (var sentence in data.activate[neuron])
|
||||
activation += data.activate[neuron][sentence] + "\n";
|
||||
}
|
||||
|
||||
// build outputs
|
||||
activation += "var output = [];\n";
|
||||
for (var i in data.outputs)
|
||||
activation += "output[" + i + "] = F[" + data.outputs[i] + "];\n";
|
||||
activation += "return output;\n}";
|
||||
|
||||
// reference all the positions in memory
|
||||
var memory = activation.match(/F\[(\d+)\]/g);
|
||||
var dimension = 0;
|
||||
var ids = {};
|
||||
for (var address in memory) {
|
||||
var tmp = memory[address].match(/\d+/)[0];
|
||||
if (!(tmp in ids)) {
|
||||
ids[tmp] = dimension++;
|
||||
}
|
||||
}
|
||||
var hardcode = "F = {\n";
|
||||
for (var i in ids)
|
||||
hardcode += ids[i] + ": " + this.optimized.memory[i] + ",\n";
|
||||
hardcode = hardcode.substring(0, hardcode.length - 2) + "\n};\n";
|
||||
hardcode = "var run = " + activation.replace(/F\[(\d+)]/g, function(
|
||||
index) {
|
||||
return 'F[' + ids[index.match(/\d+/)[0]] + ']'
|
||||
}).replace("{\n", "{\n" + hardcode + "") + ";\n";
|
||||
hardcode += "return run";
|
||||
|
||||
// return standalone function
|
||||
return new Function(hardcode)();
|
||||
},
|
||||
|
||||
worker: function() {
|
||||
if (!this.optimized)
|
||||
this.optimize();
|
||||
|
||||
var hardcode = "var inputs = " + this.optimized.data.inputs.length +
|
||||
";\n";
|
||||
hardcode += "var outputs = " + this.optimized.data.outputs.length +
|
||||
";\n";
|
||||
hardcode += "var F = null;\n";
|
||||
hardcode += "var activate = " + this.optimized.activate.toString() +
|
||||
";\n";
|
||||
hardcode += "var propagate = " + this.optimized.propagate.toString() +
|
||||
";\n";
|
||||
hardcode += "onmessage = function(e){\n";
|
||||
hardcode += "F = e.data.memoryBuffer;\n";
|
||||
hardcode += "if (e.data.action == 'activate'){\n";
|
||||
hardcode += "if (e.data.input.length == inputs){\n";
|
||||
hardcode +=
|
||||
"postMessage( { action: 'activate', output: activate(e.data.input), memoryBuffer: F }, [F.buffer]);\n";
|
||||
hardcode += "}\n}\nelse if (e.data.action == 'propagate'){\n";
|
||||
hardcode += "propagate(e.data.rate, e.data.target);\n";
|
||||
hardcode +=
|
||||
"postMessage({ action: 'propagate', memoryBuffer: F }, [F.buffer]);\n";
|
||||
hardcode += "}\n}\n";
|
||||
|
||||
var blob = new Blob([hardcode]);
|
||||
var blobURL = window.URL.createObjectURL(blob);
|
||||
|
||||
return new Worker(blobURL);
|
||||
},
|
||||
|
||||
// returns a copy of the network
|
||||
clone: function(ignoreTraces) {
|
||||
return Network.fromJSON(this.toJSON(ignoreTraces));
|
||||
}
|
||||
}
|
||||
|
||||
// rebuild a network that has been stored in a json using the method toJson()
|
||||
Network.fromJSON = function(json) {
|
||||
|
||||
var neurons = [];
|
||||
|
||||
var layers = {
|
||||
input: new Layer(),
|
||||
hidden: [],
|
||||
output: new Layer()
|
||||
}
|
||||
|
||||
for (var i in json.neurons) {
|
||||
var config = json.neurons[i];
|
||||
|
||||
var neuron = new Neuron();
|
||||
neuron.trace.elegibility = config.trace.elegibility;
|
||||
neuron.trace.extended = config.trace.extended;
|
||||
neuron.state = config.state;
|
||||
neuron.old = config.old;
|
||||
neuron.activation = config.activation;
|
||||
neuron.bias = config.bias;
|
||||
neuron.squash = config.squash in Neuron.squash ? Neuron.squash[config.squash] :
|
||||
Neuron.squash.LOGISTIC;
|
||||
neurons.push(neuron);
|
||||
|
||||
if (config.layer == 'input')
|
||||
layers.input.add(neuron);
|
||||
else if (config.layer == 'output')
|
||||
layers.output.add(neuron);
|
||||
else {
|
||||
if (typeof layers.hidden[config.layer] == 'undefined')
|
||||
layers.hidden[config.layer] = new Layer();
|
||||
layers.hidden[config.layer].add(neuron);
|
||||
}
|
||||
}
|
||||
|
||||
for (var i in json.connections) {
|
||||
var config = json.connections[i];
|
||||
var from = neurons[config.from];
|
||||
var to = neurons[config.to];
|
||||
var weight = config.weight
|
||||
var gater = neurons[config.gater];
|
||||
|
||||
var connection = from.project(to, weight);
|
||||
if (gater)
|
||||
gater.gate(connection);
|
||||
}
|
||||
|
||||
return new Network(layers);
|
||||
}
|
||||
|
||||
// export
|
||||
if (module) module.exports = Network;
|
||||
|
||||
@@ -0,0 +1,631 @@
|
||||
import layer = require('./layer');
|
||||
import Squash = require('./squash');
|
||||
import Synaptic = require('./synaptic');
|
||||
import _neuron = require('./neuron');
|
||||
|
||||
/*******************************************************************************************
|
||||
NETWORK
|
||||
*******************************************************************************************/
|
||||
|
||||
declare function escape(a: string): string;
|
||||
|
||||
|
||||
export class Network {
|
||||
optimized = null;
|
||||
layers = {
|
||||
input: null,
|
||||
hidden: {},
|
||||
output: null
|
||||
};
|
||||
constructor(layers) {
|
||||
if (typeof layers != 'undefined') {
|
||||
this.layers = layers || {
|
||||
input: null,
|
||||
hidden: {},
|
||||
output: null
|
||||
};
|
||||
this.optimized = null;
|
||||
}
|
||||
}
|
||||
|
||||
// feed-forward activation of all the layers to produce an ouput
|
||||
activate(input) {
|
||||
|
||||
if (this.optimized === false) {
|
||||
this.layers.input.activate(input);
|
||||
for (var layer in this.layers.hidden)
|
||||
this.layers.hidden[layer].activate();
|
||||
return this.layers.output.activate();
|
||||
}
|
||||
else {
|
||||
if (this.optimized == null)
|
||||
this.optimize();
|
||||
return this.optimized.activate(input);
|
||||
}
|
||||
}
|
||||
|
||||
// back-propagate the error thru the network
|
||||
propagate(rate: number, target?) {
|
||||
|
||||
if (this.optimized === false) {
|
||||
this.layers.output.propagate(rate, target);
|
||||
var reverse = [];
|
||||
for (var layer in this.layers.hidden)
|
||||
reverse.push(this.layers.hidden[layer]);
|
||||
reverse.reverse();
|
||||
for (var layer in reverse)
|
||||
reverse[layer].propagate(rate);
|
||||
}
|
||||
else {
|
||||
if (this.optimized == null)
|
||||
this.optimize();
|
||||
this.optimized.propagate(rate, target);
|
||||
}
|
||||
}
|
||||
|
||||
// project a connection to another unit (either a network or a layer)
|
||||
project(unit, type, weights) {
|
||||
|
||||
if (this.optimized)
|
||||
this.optimized.reset();
|
||||
|
||||
if (unit instanceof Network)
|
||||
return this.layers.output.project(unit.layers.input, type, weights);
|
||||
|
||||
if (unit instanceof layer.Layer)
|
||||
return this.layers.output.project(unit, type, weights);
|
||||
|
||||
throw "Invalid argument, you can only project connections to LAYERS and NETWORKS!";
|
||||
}
|
||||
|
||||
// let this network gate a connection
|
||||
gate(connection, type) {
|
||||
if (this.optimized)
|
||||
this.optimized.reset();
|
||||
this.layers.output.gate(connection, type);
|
||||
}
|
||||
|
||||
// clear all elegibility traces and extended elegibility traces (the network forgets its context, but not what was trained)
|
||||
clear() {
|
||||
|
||||
this.restore();
|
||||
|
||||
var inputLayer = this.layers.input,
|
||||
outputLayer = this.layers.output;
|
||||
|
||||
inputLayer.clear();
|
||||
for (var layer in this.layers.hidden) {
|
||||
var hiddenLayer = this.layers.hidden[layer];
|
||||
hiddenLayer.clear();
|
||||
}
|
||||
outputLayer.clear();
|
||||
|
||||
if (this.optimized)
|
||||
this.optimized.reset();
|
||||
}
|
||||
|
||||
// reset all weights and clear all traces (ends up like a new network)
|
||||
reset() {
|
||||
|
||||
this.restore();
|
||||
|
||||
var inputLayer = this.layers.input,
|
||||
outputLayer = this.layers.output;
|
||||
|
||||
inputLayer.reset();
|
||||
for (var layer in this.layers.hidden) {
|
||||
var hiddenLayer = this.layers.hidden[layer];
|
||||
hiddenLayer.reset();
|
||||
}
|
||||
outputLayer.reset();
|
||||
|
||||
if (this.optimized)
|
||||
this.optimized.reset();
|
||||
}
|
||||
|
||||
// hardcodes the behaviour of the whole network into a single optimized function
|
||||
optimize() {
|
||||
|
||||
var that = this;
|
||||
var optimized: Synaptic.ICompiledParameters = {};
|
||||
var neurons = this.neurons();
|
||||
|
||||
for (var i in neurons) {
|
||||
var neuron = neurons[i].neuron;
|
||||
var layer = neurons[i].layer;
|
||||
/*
|
||||
FIXME: does this worked once?
|
||||
|
||||
while (neuron.neuron)
|
||||
neuron = neuron.neuron;
|
||||
*/
|
||||
|
||||
optimized = neuron.optimize(optimized, layer);
|
||||
}
|
||||
|
||||
for (var i in optimized.propagation_sentences)
|
||||
optimized.propagation_sentences[i].reverse();
|
||||
optimized.propagation_sentences.reverse();
|
||||
|
||||
var hardcode = "";
|
||||
hardcode += "var F = Float64Array ? new Float64Array(" + optimized.memory +
|
||||
") : []; ";
|
||||
for (var i in optimized.variables)
|
||||
hardcode += "F[" + optimized.variables[i].id + "] = " + (optimized.variables[
|
||||
i].value || 0) + "; ";
|
||||
hardcode += "var activate = function(input){\n";
|
||||
hardcode += "influences = [];";
|
||||
for (var i in optimized.inputs)
|
||||
hardcode += "F[" + optimized.inputs[i] + "] = input[" + i + "]; ";
|
||||
for (var currentLayer in optimized.activation_sentences) {
|
||||
if (optimized.activation_sentences[currentLayer].length > 0) {
|
||||
for (var currentNeuron in optimized.activation_sentences[currentLayer]) {
|
||||
hardcode += optimized.activation_sentences[currentLayer][currentNeuron].join(" ");
|
||||
hardcode += optimized.trace_sentences[currentLayer][currentNeuron].join(" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
hardcode += " var output = []; "
|
||||
for (var i in optimized.outputs)
|
||||
hardcode += "output[" + i + "] = F[" + optimized.outputs[i] + "]; ";
|
||||
hardcode += "return output; }; "
|
||||
hardcode += "var propagate = function(rate, target){\n";
|
||||
hardcode += "F[" + optimized.variables.rate.id + "] = rate; ";
|
||||
for (var i in optimized.targets)
|
||||
hardcode += "F[" + optimized.targets[i] + "] = target[" + i + "]; ";
|
||||
for (var currentLayer in optimized.propagation_sentences)
|
||||
for (var currentNeuron in optimized.propagation_sentences[currentLayer])
|
||||
hardcode += optimized.propagation_sentences[currentLayer][currentNeuron].join(" ") + " ";
|
||||
hardcode += " };\n";
|
||||
hardcode +=
|
||||
"var ownership = function(memoryBuffer){\nF = memoryBuffer;\nthis.memory = F;\n};\n";
|
||||
hardcode +=
|
||||
"return {\nmemory: F,\nactivate: activate,\npropagate: propagate,\nownership: ownership\n};";
|
||||
hardcode = hardcode.split(";").join(";\n");
|
||||
|
||||
var constructor = new Function(hardcode);
|
||||
|
||||
var network = constructor();
|
||||
|
||||
network.data = {
|
||||
variables: optimized.variables,
|
||||
activate: optimized.activation_sentences,
|
||||
propagate: optimized.propagation_sentences,
|
||||
trace: optimized.trace_sentences,
|
||||
inputs: optimized.inputs,
|
||||
outputs: optimized.outputs,
|
||||
check_activation: this.activate,
|
||||
check_propagation: this.propagate
|
||||
}
|
||||
|
||||
network.reset = function() {
|
||||
if (that.optimized) {
|
||||
that.optimized = null;
|
||||
that.activate = network.data.check_activation;
|
||||
that.propagate = network.data.check_propagation;
|
||||
}
|
||||
}
|
||||
|
||||
this.optimized = network;
|
||||
this.activate = network.activate;
|
||||
this.propagate = network.propagate;
|
||||
}
|
||||
|
||||
// restores all the values from the optimized network the their respective objects in order to manipulate the network
|
||||
restore() {
|
||||
if (!this.optimized)
|
||||
return;
|
||||
|
||||
var optimized = this.optimized;
|
||||
|
||||
var getValue = function(...args: any[]) {
|
||||
var unit = args.shift();
|
||||
var prop = args.pop();
|
||||
|
||||
var id = prop + '_';
|
||||
for (var property in args)
|
||||
id += args[property] + '_';
|
||||
id += unit.ID;
|
||||
|
||||
var memory = optimized.memory;
|
||||
var variables = optimized.data.variables;
|
||||
|
||||
if (id in variables)
|
||||
return memory[variables[id].id];
|
||||
return 0;
|
||||
}
|
||||
|
||||
var list = this.neurons();
|
||||
|
||||
// link id's to positions in the array
|
||||
var ids = {};
|
||||
for (var i in list) {
|
||||
var neuron = list[i].neuron;
|
||||
/*
|
||||
FIXME: does this worked once?
|
||||
|
||||
while (neuron.neuron)
|
||||
neuron = neuron.neuron;
|
||||
*/
|
||||
|
||||
neuron.state = getValue(neuron, 'state');
|
||||
neuron.old = getValue(neuron, 'old');
|
||||
neuron.activation = getValue(neuron, 'activation');
|
||||
neuron.bias = getValue(neuron, 'bias');
|
||||
|
||||
for (var input in neuron.trace.elegibility)
|
||||
neuron.trace.elegibility[input] = getValue(neuron, 'trace',
|
||||
'elegibility', input);
|
||||
|
||||
for (var gated in neuron.trace.extended)
|
||||
for (var input in neuron.trace.extended[gated])
|
||||
neuron.trace.extended[gated][input] = getValue(neuron, 'trace',
|
||||
'extended', gated, input);
|
||||
}
|
||||
|
||||
// get connections
|
||||
for (var i in list) {
|
||||
var neuron = list[i].neuron;
|
||||
/*
|
||||
FIXME: does this worked once?
|
||||
|
||||
while (neuron.neuron)
|
||||
neuron = neuron.neuron;
|
||||
*/
|
||||
|
||||
for (var j in neuron.connections.projected) {
|
||||
var connection = neuron.connections.projected[j];
|
||||
connection.weight = getValue(connection, 'weight');
|
||||
connection.gain = getValue(connection, 'gain');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// returns all the neurons in the network
|
||||
neurons(): Network.INetworkNeuron[] {
|
||||
var neurons: Network.INetworkNeuron[] = [];
|
||||
|
||||
var inputLayer = this.layers.input.neurons(),
|
||||
outputLayer = this.layers.output.neurons();
|
||||
|
||||
for (var neuron in inputLayer)
|
||||
neurons.push({
|
||||
neuron: inputLayer[neuron],
|
||||
layer: 'input'
|
||||
});
|
||||
|
||||
for (var layer in this.layers.hidden) {
|
||||
var hiddenLayer = this.layers.hidden[layer].neurons();
|
||||
for (var neuron in hiddenLayer)
|
||||
neurons.push({
|
||||
neuron: hiddenLayer[neuron],
|
||||
layer: layer
|
||||
});
|
||||
}
|
||||
for (var neuron in outputLayer)
|
||||
neurons.push({
|
||||
neuron: outputLayer[neuron],
|
||||
layer: 'output'
|
||||
});
|
||||
|
||||
return neurons;
|
||||
}
|
||||
|
||||
// returns number of inputs of the network
|
||||
inputs(): number {
|
||||
return this.layers.input.size;
|
||||
}
|
||||
|
||||
// returns number of outputs of hte network
|
||||
outputs(): number {
|
||||
return this.layers.output.size;
|
||||
}
|
||||
|
||||
// sets the layers of the network
|
||||
set(layers) {
|
||||
|
||||
this.layers = layers;
|
||||
if (this.optimized)
|
||||
this.optimized.reset();
|
||||
}
|
||||
|
||||
setOptimize(bool) {
|
||||
this.restore();
|
||||
if (this.optimized)
|
||||
this.optimized.reset();
|
||||
this.optimized = bool ? null : false;
|
||||
}
|
||||
|
||||
// returns a json that represents all the neurons and connections of the network
|
||||
toJSON(ignoreTraces) {
|
||||
|
||||
this.restore();
|
||||
|
||||
var list = this.neurons();
|
||||
var neurons = [];
|
||||
var connections = [];
|
||||
|
||||
// link id's to positions in the array
|
||||
var ids = {};
|
||||
for (var i in list) {
|
||||
var neuron = list[i].neuron;
|
||||
/*
|
||||
FIXME: does this worked once?
|
||||
|
||||
while (neuron.neuron)
|
||||
neuron = neuron.neuron;
|
||||
*/
|
||||
|
||||
ids[neuron.ID] = i;
|
||||
|
||||
var copy = {
|
||||
trace: {
|
||||
elegibility: {},
|
||||
extended: {}
|
||||
},
|
||||
state: neuron.state,
|
||||
old: neuron.old,
|
||||
activation: neuron.activation,
|
||||
bias: neuron.bias,
|
||||
layer: list[i].layer,
|
||||
squash: null
|
||||
};
|
||||
|
||||
copy.squash = neuron.squash == Squash.LOGISTIC ? "LOGISTIC" :
|
||||
neuron.squash == Squash.TANH ? "TANH" :
|
||||
neuron.squash == Squash.IDENTITY ? "IDENTITY" :
|
||||
neuron.squash == Squash.HLIM ? "HLIM" :
|
||||
null;
|
||||
|
||||
neurons.push(copy);
|
||||
}
|
||||
|
||||
if (!ignoreTraces)
|
||||
for (var i in neurons) {
|
||||
var copiedNeuron = neurons[i];
|
||||
|
||||
for (var input in neuron.trace.elegibility)
|
||||
copiedNeuron.trace.elegibility[input] = neuron.trace.elegibility[input];
|
||||
|
||||
for (var gated in neuron.trace.extended) {
|
||||
copiedNeuron.trace.extended[gated] = {};
|
||||
for (var input in neuron.trace.extended[gated])
|
||||
copiedNeuron.trace.extended[ids[gated]][input] = neuron.trace.extended[
|
||||
gated][input];
|
||||
}
|
||||
}
|
||||
|
||||
// get connections
|
||||
for (var i in list) {
|
||||
var neuron = list[i].neuron;
|
||||
|
||||
/*
|
||||
FIXME: does this worked once?
|
||||
|
||||
while (neuron.neuron)
|
||||
neuron = neuron.neuron;
|
||||
*/
|
||||
|
||||
for (var j in neuron.connections.projected) {
|
||||
var connection = neuron.connections.projected[j];
|
||||
connections.push({
|
||||
from: ids[connection.from.ID],
|
||||
to: ids[connection.to.ID],
|
||||
weight: connection.weight,
|
||||
gater: connection.gater ? ids[connection.gater.ID] : null,
|
||||
});
|
||||
}
|
||||
if (neuron.selfconnected())
|
||||
connections.push({
|
||||
from: ids[neuron.ID],
|
||||
to: ids[neuron.ID],
|
||||
weight: neuron.selfconnection.weight,
|
||||
gater: neuron.selfconnection.gater ? ids[neuron.selfconnection.gater
|
||||
.ID] : null,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
neurons: neurons,
|
||||
connections: connections
|
||||
}
|
||||
}
|
||||
|
||||
// export the topology into dot language which can be visualized as graphs using dot
|
||||
/* example: ... console.log(net.toDotLang());
|
||||
$ node example.js > example.dot
|
||||
$ dot example.dot -Tpng > out.png
|
||||
*/
|
||||
toDot(edgeconnection) {
|
||||
if (! typeof edgeconnection)
|
||||
edgeconnection = false;
|
||||
var code = "digraph nn {\n rankdir = BT\n";
|
||||
var layers = [this.layers.input].concat(this.layers.hidden, this.layers.output);
|
||||
for (var layer in layers) {
|
||||
for (var to in layers[layer].connectedto) { // projections
|
||||
var connection = layers[layer].connectedto[to];
|
||||
var layerto = connection.to;
|
||||
var size = connection.size;
|
||||
var layerID = layers.indexOf(layers[layer]);
|
||||
var layertoID = layers.indexOf(layerto);
|
||||
/* http://stackoverflow.com/questions/26845540/connect-edges-with-graph-dot
|
||||
* DOT does not support edge-to-edge connections
|
||||
* This workaround produces somewhat weird graphs ...
|
||||
*/
|
||||
if (edgeconnection) {
|
||||
if (connection.gatedfrom.length) {
|
||||
var fakeNode = "fake" + layerID + "_" + layertoID;
|
||||
code += " " + fakeNode +
|
||||
" [label = \"\", shape = point, width = 0.01, height = 0.01]\n";
|
||||
code += " " + layerID + " -> " + fakeNode + " [label = " + size + ", arrowhead = none]\n";
|
||||
code += " " + fakeNode + " -> " + layertoID + "\n";
|
||||
} else
|
||||
code += " " + layerID + " -> " + layertoID + " [label = " + size + "]\n";
|
||||
for (var from in connection.gatedfrom) { // gatings
|
||||
var layerfrom = connection.gatedfrom[from].layer;
|
||||
var type = connection.gatedfrom[from].type;
|
||||
var layerfromID = layers.indexOf(layerfrom);
|
||||
code += " " + layerfromID + " -> " + fakeNode + " [color = blue]\n";
|
||||
}
|
||||
} else {
|
||||
code += " " + layerID + " -> " + layertoID + " [label = " + size + "]\n";
|
||||
for (var from in connection.gatedfrom) { // gatings
|
||||
var layerfrom = connection.gatedfrom[from].layer;
|
||||
var type = connection.gatedfrom[from].type;
|
||||
var layerfromID = layers.indexOf(layerfrom);
|
||||
code += " " + layerfromID + " -> " + layertoID + " [color = blue]\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
code += "}\n";
|
||||
return {
|
||||
code: code,
|
||||
link: "https://chart.googleapis.com/chart?chl=" + escape(code.replace("/ /g", "+")) + "&cht=gv"
|
||||
}
|
||||
}
|
||||
|
||||
// returns a function that works as the activation of the network and can be used without depending on the library
|
||||
standalone() {
|
||||
if (!this.optimized)
|
||||
this.optimize();
|
||||
|
||||
var data = this.optimized.data;
|
||||
|
||||
// build activation function
|
||||
var activation = "function (input) {\n";
|
||||
|
||||
// build inputs
|
||||
for (var i in data.inputs)
|
||||
activation += "F[" + data.inputs[i] + "] = input[" + i + "];\n";
|
||||
|
||||
// build network activation
|
||||
for (var neuron in data.activate) { // shouldn't this be layer?
|
||||
for (var sentence in data.activate[neuron])
|
||||
activation += data.activate[neuron][sentence] + "\n";
|
||||
}
|
||||
|
||||
// build outputs
|
||||
activation += "var output = [];\n";
|
||||
for (var i in data.outputs)
|
||||
activation += "output[" + i + "] = F[" + data.outputs[i] + "];\n";
|
||||
activation += "return output;\n}";
|
||||
|
||||
// reference all the positions in memory
|
||||
var memory = activation.match(/F\[(\d+)\]/g);
|
||||
var dimension = 0;
|
||||
var ids = {};
|
||||
for (var address in memory) {
|
||||
var tmp = memory[address].match(/\d+/)[0];
|
||||
if (!(tmp in ids)) {
|
||||
ids[tmp] = dimension++;
|
||||
}
|
||||
}
|
||||
var hardcode = "F = {\n";
|
||||
for (var i in ids)
|
||||
hardcode += ids[i] + ": " + this.optimized.memory[i] + ",\n";
|
||||
hardcode = hardcode.substring(0, hardcode.length - 2) + "\n};\n";
|
||||
hardcode = "var run = " + activation.replace(/F\[(\d+)]/g, function(
|
||||
index) {
|
||||
return 'F[' + ids[index.match(/\d+/)[0]] + ']'
|
||||
}).replace("{\n", "{\n" + hardcode + "") + ";\n";
|
||||
hardcode += "return run";
|
||||
|
||||
// return standalone function
|
||||
return new Function(hardcode)();
|
||||
}
|
||||
|
||||
worker() {
|
||||
if (!this.optimized)
|
||||
this.optimize();
|
||||
|
||||
var hardcode = "var inputs = " + this.optimized.data.inputs.length +
|
||||
";\n";
|
||||
hardcode += "var outputs = " + this.optimized.data.outputs.length +
|
||||
";\n";
|
||||
hardcode += "var F = null;\n";
|
||||
hardcode += "var activate = " + this.optimized.activate.toString() +
|
||||
";\n";
|
||||
hardcode += "var propagate = " + this.optimized.propagate.toString() +
|
||||
";\n";
|
||||
hardcode += "onmessage = function(e){\n";
|
||||
hardcode += "F = e.data.memoryBuffer;\n";
|
||||
hardcode += "if (e.data.action == 'activate'){\n";
|
||||
hardcode += "if (e.data.input.length == inputs){\n";
|
||||
hardcode +=
|
||||
"postMessage( { action: 'activate', output: activate(e.data.input), memoryBuffer: F }, [F.buffer]);\n";
|
||||
hardcode += "}\n}\nelse if (e.data.action == 'propagate'){\n";
|
||||
hardcode += "propagate(e.data.rate, e.data.target);\n";
|
||||
hardcode +=
|
||||
"postMessage({ action: 'propagate', memoryBuffer: F }, [F.buffer]);\n";
|
||||
hardcode += "}\n}\n";
|
||||
|
||||
var blob = new Blob([hardcode]);
|
||||
var blobURL = (<any>window).URL.createObjectURL(blob);
|
||||
|
||||
return new Worker(blobURL);
|
||||
}
|
||||
|
||||
// returns a copy of the network
|
||||
clone(ignoreTraces) {
|
||||
return Network.fromJSON(this.toJSON(ignoreTraces));
|
||||
}
|
||||
|
||||
static fromJSON(json) {
|
||||
|
||||
var neurons = [];
|
||||
|
||||
var layers = {
|
||||
input: new layer.Layer(0),
|
||||
hidden: [],
|
||||
output: new layer.Layer(0)
|
||||
}
|
||||
|
||||
|
||||
for (var i in json.neurons) {
|
||||
var config = json.neurons[i];
|
||||
|
||||
var neuron = new _neuron.Neuron();
|
||||
neuron.trace.elegibility = config.trace.elegibility;
|
||||
neuron.trace.extended = config.trace.extended;
|
||||
neuron.state = config.state;
|
||||
neuron.old = config.old;
|
||||
neuron.activation = config.activation;
|
||||
neuron.bias = config.bias;
|
||||
neuron.squash = config.squash in Squash ? Squash[config.squash] :
|
||||
Squash.LOGISTIC;
|
||||
neurons.push(neuron);
|
||||
|
||||
if (config.layer == 'input')
|
||||
layers.input.add(neuron);
|
||||
else if (config.layer == 'output')
|
||||
layers.output.add(neuron);
|
||||
else {
|
||||
if (typeof layers.hidden[config.layer] == 'undefined')
|
||||
layers.hidden[config.layer] = new layer.Layer(0);
|
||||
layers.hidden[config.layer].add(neuron);
|
||||
}
|
||||
}
|
||||
|
||||
for (var i in json.connections) {
|
||||
var config = json.connections[i];
|
||||
var from = neurons[config.from];
|
||||
var to = neurons[config.to];
|
||||
var weight = config.weight
|
||||
var gater = neurons[config.gater];
|
||||
|
||||
var connection = from.project(to, weight);
|
||||
if (gater)
|
||||
gater.gate(connection);
|
||||
}
|
||||
|
||||
return new Network(layers);
|
||||
}
|
||||
}
|
||||
|
||||
export module Network {
|
||||
export interface INetworkNeuron {
|
||||
neuron: _neuron.Neuron;
|
||||
layer: string;
|
||||
}
|
||||
}
|
||||
-801
@@ -1,801 +0,0 @@
|
||||
/******************************************************************************************
|
||||
NEURON
|
||||
*******************************************************************************************/
|
||||
|
||||
function Neuron() {
|
||||
this.ID = Neuron.uid();
|
||||
this.label = null;
|
||||
this.connections = {
|
||||
inputs: {},
|
||||
projected: {},
|
||||
gated: {}
|
||||
};
|
||||
this.error = {
|
||||
responsibility: 0,
|
||||
projected: 0,
|
||||
gated: 0
|
||||
};
|
||||
this.trace = {
|
||||
elegibility: {},
|
||||
extended: {},
|
||||
influences: {}
|
||||
};
|
||||
this.state = 0;
|
||||
this.old = 0;
|
||||
this.activation = 0;
|
||||
this.selfconnection = new Neuron.connection(this, this, 0); // weight = 0 -> not connected
|
||||
this.squash = Neuron.squash.LOGISTIC;
|
||||
this.neighboors = {};
|
||||
this.bias = Math.random() * .2 - .1;
|
||||
}
|
||||
|
||||
Neuron.prototype = {
|
||||
|
||||
// activate the neuron
|
||||
activate: function(input) {
|
||||
// activation from enviroment (for input neurons)
|
||||
if (typeof input != 'undefined') {
|
||||
this.activation = input;
|
||||
this.derivative = 0;
|
||||
this.bias = 0;
|
||||
return this.activation;
|
||||
}
|
||||
|
||||
// old state
|
||||
this.old = this.state;
|
||||
|
||||
// eq. 15
|
||||
this.state = this.selfconnection.gain * this.selfconnection.weight *
|
||||
this.state + this.bias;
|
||||
|
||||
for (var i in this.connections.inputs) {
|
||||
var input = this.connections.inputs[i];
|
||||
this.state += input.from.activation * input.weight * input.gain;
|
||||
}
|
||||
|
||||
// eq. 16
|
||||
this.activation = this.squash(this.state);
|
||||
|
||||
// f'(s)
|
||||
this.derivative = this.squash(this.state, true);
|
||||
|
||||
// update traces
|
||||
var influences = [];
|
||||
for (var id in this.trace.extended) {
|
||||
// extended elegibility trace
|
||||
var xtrace = this.trace.extended[id];
|
||||
var neuron = this.neighboors[id];
|
||||
|
||||
// if gated neuron's selfconnection is gated by this unit, the influence keeps track of the neuron's old state
|
||||
var influence = neuron.selfconnection.gater == this ? neuron.old : 0;
|
||||
|
||||
// index runs over all the incoming connections to the gated neuron that are gated by this unit
|
||||
for (var incoming in this.trace.influences[neuron.ID]) { // captures the effect that has an input connection to this unit, on a neuron that is gated by this unit
|
||||
influence += this.trace.influences[neuron.ID][incoming].weight *
|
||||
this.trace.influences[neuron.ID][incoming].from.activation;
|
||||
}
|
||||
influences[neuron.ID] = influence;
|
||||
}
|
||||
|
||||
for (var i in this.connections.inputs) {
|
||||
var input = this.connections.inputs[i];
|
||||
|
||||
// elegibility trace - Eq. 17
|
||||
this.trace.elegibility[input.ID] = this.selfconnection.gain * this.selfconnection
|
||||
.weight * this.trace.elegibility[input.ID] + input.gain * input.from
|
||||
.activation;
|
||||
|
||||
for (var id in this.trace.extended) {
|
||||
// extended elegibility trace
|
||||
var xtrace = this.trace.extended[id];
|
||||
var neuron = this.neighboors[id];
|
||||
var influence = influences[neuron.ID];
|
||||
|
||||
// eq. 18
|
||||
xtrace[input.ID] = neuron.selfconnection.gain * neuron.selfconnection
|
||||
.weight * xtrace[input.ID] + this.derivative * this.trace.elegibility[
|
||||
input.ID] * influence;
|
||||
}
|
||||
}
|
||||
|
||||
// update gated connection's gains
|
||||
for (var connection in this.connections.gated) {
|
||||
this.connections.gated[connection].gain = this.activation;
|
||||
}
|
||||
|
||||
return this.activation;
|
||||
},
|
||||
|
||||
// back-propagate the error
|
||||
propagate: function(rate, target) {
|
||||
// error accumulator
|
||||
var error = 0;
|
||||
|
||||
// whether or not this neuron is in the output layer
|
||||
var isOutput = typeof target != 'undefined';
|
||||
|
||||
// output neurons get their error from the enviroment
|
||||
if (isOutput)
|
||||
this.error.responsibility = this.error.projected = target - this.activation; // Eq. 10
|
||||
|
||||
else // the rest of the neuron compute their error responsibilities by backpropagation
|
||||
{
|
||||
// error responsibilities from all the connections projected from this neuron
|
||||
for (var id in this.connections.projected) {
|
||||
var connection = this.connections.projected[id];
|
||||
var neuron = connection.to;
|
||||
// Eq. 21
|
||||
error += neuron.error.responsibility * connection.gain * connection.weight;
|
||||
}
|
||||
|
||||
// projected error responsibility
|
||||
this.error.projected = this.derivative * error;
|
||||
|
||||
error = 0;
|
||||
// error responsibilities from all the connections gated by this neuron
|
||||
for (var id in this.trace.extended) {
|
||||
var neuron = this.neighboors[id]; // gated neuron
|
||||
var influence = neuron.selfconnection.gater == this ? neuron.old : 0; // if gated neuron's selfconnection is gated by this neuron
|
||||
|
||||
// index runs over all the connections to the gated neuron that are gated by this neuron
|
||||
for (var input in this.trace.influences[id]) { // captures the effect that the input connection of this neuron have, on a neuron which its input/s is/are gated by this neuron
|
||||
influence += this.trace.influences[id][input].weight * this.trace.influences[
|
||||
neuron.ID][input].from.activation;
|
||||
}
|
||||
// eq. 22
|
||||
error += neuron.error.responsibility * influence;
|
||||
}
|
||||
|
||||
// gated error responsibility
|
||||
this.error.gated = this.derivative * error;
|
||||
|
||||
// error responsibility - Eq. 23
|
||||
this.error.responsibility = this.error.projected + this.error.gated;
|
||||
}
|
||||
|
||||
// learning rate
|
||||
rate = rate || .1;
|
||||
|
||||
// adjust all the neuron's incoming connections
|
||||
for (var id in this.connections.inputs) {
|
||||
var input = this.connections.inputs[id];
|
||||
|
||||
// Eq. 24
|
||||
var gradient = this.error.projected * this.trace.elegibility[input.ID];
|
||||
for (var id in this.trace.extended) {
|
||||
var neuron = this.neighboors[id];
|
||||
gradient += neuron.error.responsibility * this.trace.extended[
|
||||
neuron.ID][input.ID];
|
||||
}
|
||||
input.weight += rate * gradient; // adjust weights - aka learn
|
||||
}
|
||||
|
||||
// adjust bias
|
||||
this.bias += rate * this.error.responsibility;
|
||||
},
|
||||
|
||||
project: function(neuron, weight) {
|
||||
// self-connection
|
||||
if (neuron == this) {
|
||||
this.selfconnection.weight = 1;
|
||||
return this.selfconnection;
|
||||
}
|
||||
|
||||
// check if connection already exists
|
||||
var connected = this.connected(neuron);
|
||||
if (connected && connected.type == "projected") {
|
||||
// update connection
|
||||
if (typeof weight != 'undefined')
|
||||
connected.connection.weight = weight;
|
||||
// return existing connection
|
||||
return connected.connection;
|
||||
} else {
|
||||
// create a new connection
|
||||
var connection = new Neuron.connection(this, neuron, weight);
|
||||
}
|
||||
|
||||
// reference all the connections and traces
|
||||
this.connections.projected[connection.ID] = connection;
|
||||
this.neighboors[neuron.ID] = neuron;
|
||||
neuron.connections.inputs[connection.ID] = connection;
|
||||
neuron.trace.elegibility[connection.ID] = 0;
|
||||
|
||||
for (var id in neuron.trace.extended) {
|
||||
var trace = neuron.trace.extended[id];
|
||||
trace[connection.ID] = 0;
|
||||
}
|
||||
|
||||
return connection;
|
||||
},
|
||||
|
||||
gate: function(connection) {
|
||||
// add connection to gated list
|
||||
this.connections.gated[connection.ID] = connection;
|
||||
|
||||
var neuron = connection.to;
|
||||
if (!(neuron.ID in this.trace.extended)) {
|
||||
// extended trace
|
||||
this.neighboors[neuron.ID] = neuron;
|
||||
var xtrace = this.trace.extended[neuron.ID] = {};
|
||||
for (var id in this.connections.inputs) {
|
||||
var input = this.connections.inputs[id];
|
||||
xtrace[input.ID] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// keep track
|
||||
if (neuron.ID in this.trace.influences)
|
||||
this.trace.influences[neuron.ID].push(connection);
|
||||
else
|
||||
this.trace.influences[neuron.ID] = [connection];
|
||||
|
||||
// set gater
|
||||
connection.gater = this;
|
||||
},
|
||||
|
||||
// returns true or false whether the neuron is self-connected or not
|
||||
selfconnected: function() {
|
||||
return this.selfconnection.weight !== 0;
|
||||
},
|
||||
|
||||
// returns true or false whether the neuron is connected to another neuron (parameter)
|
||||
connected: function(neuron) {
|
||||
var result = {
|
||||
type: null,
|
||||
connection: false
|
||||
};
|
||||
|
||||
if (this == neuron) {
|
||||
if (this.selfconnected()) {
|
||||
result.type = 'selfconnection';
|
||||
result.connection = this.selfconnection;
|
||||
return result;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var type in this.connections) {
|
||||
for (var connection in this.connections[type]) {
|
||||
var connection = this.connections[type][connection];
|
||||
if (connection.to == neuron) {
|
||||
result.type = type;
|
||||
result.connection = connection;
|
||||
return result;
|
||||
} else if (connection.from == neuron) {
|
||||
result.type = type;
|
||||
result.connection = connection;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
// clears all the traces (the neuron forgets it's context, but the connections remain intact)
|
||||
clear: function() {
|
||||
|
||||
for (var trace in this.trace.elegibility)
|
||||
this.trace.elegibility[trace] = 0;
|
||||
|
||||
for (var trace in this.trace.extended)
|
||||
for (var extended in this.trace.extended[trace])
|
||||
this.trace.extended[trace][extended] = 0;
|
||||
|
||||
this.error.responsibility = this.error.projected = this.error.gated = 0;
|
||||
},
|
||||
|
||||
// all the connections are randomized and the traces are cleared
|
||||
reset: function() {
|
||||
this.clear();
|
||||
|
||||
for (var type in this.connections)
|
||||
for (var connection in this.connections[type])
|
||||
this.connections[type][connection].weight = Math.random() * .2 - .1;
|
||||
this.bias = Math.random() * .2 - .1;
|
||||
|
||||
this.old = this.state = this.activation = 0;
|
||||
},
|
||||
|
||||
// hardcodes the behaviour of the neuron into an optimized function
|
||||
optimize: function(optimized, layer) {
|
||||
|
||||
optimized = optimized || {};
|
||||
var that = this;
|
||||
var store_activation = [];
|
||||
var store_trace = [];
|
||||
var store_propagation = [];
|
||||
var varID = optimized.memory || 0;
|
||||
var neurons = optimized.neurons || 1;
|
||||
var inputs = optimized.inputs || [];
|
||||
var targets = optimized.targets || [];
|
||||
var outputs = optimized.outputs || [];
|
||||
var variables = optimized.variables || {};
|
||||
var activation_sentences = optimized.activation_sentences || [];
|
||||
var trace_sentences = optimized.trace_sentences || [];
|
||||
var propagation_sentences = optimized.propagation_sentences || [];
|
||||
var layers = optimized.layers || { __count: 0, __neuron: 0 };
|
||||
|
||||
// allocate sentences
|
||||
var allocate = function(store){
|
||||
var allocated = layer in layers && store[layers.__count];
|
||||
if (!allocated)
|
||||
{
|
||||
layers.__count = store.push([]) - 1;
|
||||
layers[layer] = layers.__count;
|
||||
}
|
||||
}
|
||||
allocate(activation_sentences);
|
||||
allocate(trace_sentences);
|
||||
allocate(propagation_sentences);
|
||||
var currentLayer = layers.__count;
|
||||
|
||||
// get/reserve space in memory by creating a unique ID for a variablel
|
||||
var getVar = function() {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
|
||||
if (args.length == 1) {
|
||||
if (args[0] == 'target') {
|
||||
var id = 'target_' + targets.length;
|
||||
targets.push(varID);
|
||||
} else
|
||||
var id = args[0];
|
||||
if (id in variables)
|
||||
return variables[id];
|
||||
return variables[id] = {
|
||||
value: 0,
|
||||
id: varID++
|
||||
};
|
||||
} else {
|
||||
var extended = args.length > 2;
|
||||
if (extended)
|
||||
var value = args.pop();
|
||||
|
||||
var unit = args.shift();
|
||||
var prop = args.pop();
|
||||
|
||||
if (!extended)
|
||||
var value = unit[prop];
|
||||
|
||||
var id = prop + '_';
|
||||
for (var property in args)
|
||||
id += args[property] + '_';
|
||||
id += unit.ID;
|
||||
if (id in variables)
|
||||
return variables[id];
|
||||
|
||||
return variables[id] = {
|
||||
value: value,
|
||||
id: varID++
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// build sentence
|
||||
var buildSentence = function() {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
var store = args.pop();
|
||||
var sentence = "";
|
||||
for (var i in args)
|
||||
if (typeof args[i] == 'string')
|
||||
sentence += args[i];
|
||||
else
|
||||
sentence += 'F[' + args[i].id + ']';
|
||||
|
||||
store.push(sentence + ';');
|
||||
}
|
||||
|
||||
// helper to check if an object is empty
|
||||
var isEmpty = function(obj) {
|
||||
for (var prop in obj) {
|
||||
if (obj.hasOwnProperty(prop))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// characteristics of the neuron
|
||||
var noProjections = isEmpty(this.connections.projected);
|
||||
var noGates = isEmpty(this.connections.gated);
|
||||
var isInput = layer == 'input' ? true : isEmpty(this.connections.inputs);
|
||||
var isOutput = layer == 'output' ? true : noProjections && noGates;
|
||||
|
||||
// optimize neuron's behaviour
|
||||
var rate = getVar('rate');
|
||||
var activation = getVar(this, 'activation');
|
||||
if (isInput)
|
||||
inputs.push(activation.id);
|
||||
else {
|
||||
activation_sentences[currentLayer].push(store_activation);
|
||||
trace_sentences[currentLayer].push(store_trace);
|
||||
propagation_sentences[currentLayer].push(store_propagation);
|
||||
var old = getVar(this, 'old');
|
||||
var state = getVar(this, 'state');
|
||||
var bias = getVar(this, 'bias');
|
||||
if (this.selfconnection.gater)
|
||||
var self_gain = getVar(this.selfconnection, 'gain');
|
||||
if (this.selfconnected())
|
||||
var self_weight = getVar(this.selfconnection, 'weight');
|
||||
buildSentence(old, ' = ', state, store_activation);
|
||||
if (this.selfconnected())
|
||||
if (this.selfconnection.gater)
|
||||
buildSentence(state, ' = ', self_gain, ' * ', self_weight, ' * ',
|
||||
state, ' + ', bias, store_activation);
|
||||
else
|
||||
buildSentence(state, ' = ', self_weight, ' * ', state, ' + ',
|
||||
bias, store_activation);
|
||||
else
|
||||
buildSentence(state, ' = ', bias, store_activation);
|
||||
for (var i in this.connections.inputs) {
|
||||
var input = this.connections.inputs[i];
|
||||
var input_activation = getVar(input.from, 'activation');
|
||||
var input_weight = getVar(input, 'weight');
|
||||
if (input.gater)
|
||||
var input_gain = getVar(input, 'gain');
|
||||
if (this.connections.inputs[i].gater)
|
||||
buildSentence(state, ' += ', input_activation, ' * ',
|
||||
input_weight, ' * ', input_gain, store_activation);
|
||||
else
|
||||
buildSentence(state, ' += ', input_activation, ' * ',
|
||||
input_weight, store_activation);
|
||||
}
|
||||
var derivative = getVar(this, 'derivative');
|
||||
switch (this.squash) {
|
||||
case Neuron.squash.LOGISTIC:
|
||||
buildSentence(activation, ' = (1 / (1 + Math.exp(-', state, ')))',
|
||||
store_activation);
|
||||
buildSentence(derivative, ' = ', activation, ' * (1 - ',
|
||||
activation, ')', store_activation);
|
||||
break;
|
||||
case Neuron.squash.TANH:
|
||||
var eP = getVar('aux');
|
||||
var eN = getVar('aux_2');
|
||||
buildSentence(eP, ' = Math.exp(', state, ')', store_activation);
|
||||
buildSentence(eN, ' = 1 / ', eP, store_activation);
|
||||
buildSentence(activation, ' = (', eP, ' - ', eN, ') / (', eP, ' + ', eN, ')', store_activation);
|
||||
buildSentence(derivative, ' = 1 - (', activation, ' * ', activation, ')', store_activation);
|
||||
break;
|
||||
case Neuron.squash.IDENTITY:
|
||||
buildSentence(activation, ' = ', state, store_activation);
|
||||
buildSentence(derivative, ' = 1', store_activation);
|
||||
break;
|
||||
case Neuron.squash.HLIM:
|
||||
buildSentence(activation, ' = +(', state, ' > 0)',
|
||||
store_activation);
|
||||
buildSentence(derivative, ' = 1', store_activation);
|
||||
break;
|
||||
}
|
||||
|
||||
influences = [];
|
||||
for (var id in this.trace.extended) {
|
||||
// calculate extended elegibility traces in advance
|
||||
|
||||
var xtrace = this.trace.extended[id];
|
||||
var neuron = this.neighboors[id];
|
||||
var influence = getVar('aux');
|
||||
var neuron_old = getVar(neuron, 'old');
|
||||
var initialized = false;
|
||||
if (neuron.selfconnection.gater == this)
|
||||
{
|
||||
buildSentence(influence, ' = ', neuron_old, store_trace);
|
||||
initialized = true;
|
||||
}
|
||||
for (var incoming in this.trace.influences[neuron.ID]) {
|
||||
var incoming_weight = getVar(this.trace.influences[neuron.ID]
|
||||
[incoming], 'weight');
|
||||
var incoming_activation = getVar(this.trace.influences[neuron.ID]
|
||||
[incoming].from, 'activation');
|
||||
|
||||
if (initialized)
|
||||
buildSentence(influence, ' += ', incoming_weight, ' * ',
|
||||
incoming_activation, store_trace);
|
||||
else {
|
||||
buildSentence(influence, ' = ', incoming_weight, ' * ',
|
||||
incoming_activation, store_trace);
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
influences.push(neuron.ID);
|
||||
buildSentence("influences[" + (influences.length - 1) + "] = ", influence, store_trace);
|
||||
}
|
||||
|
||||
for (var i in this.connections.inputs) {
|
||||
var input = this.connections.inputs[i];
|
||||
if (input.gater)
|
||||
var input_gain = getVar(input, 'gain');
|
||||
var input_activation = getVar(input.from, 'activation');
|
||||
var trace = getVar(this, 'trace', 'elegibility', input.ID, this.trace
|
||||
.elegibility[input.ID]);
|
||||
if (this.selfconnected()) {
|
||||
if (this.selfconnection.gater) {
|
||||
if (input.gater)
|
||||
buildSentence(trace, ' = ', self_gain, ' * ', self_weight,
|
||||
' * ', trace, ' + ', input_gain, ' * ', input_activation,
|
||||
store_trace);
|
||||
else
|
||||
buildSentence(trace, ' = ', self_gain, ' * ', self_weight,
|
||||
' * ', trace, ' + ', input_activation, store_trace);
|
||||
} else {
|
||||
if (input.gater)
|
||||
buildSentence(trace, ' = ', self_weight, ' * ', trace, ' + ',
|
||||
input_gain, ' * ', input_activation, store_trace);
|
||||
else
|
||||
buildSentence(trace, ' = ', self_weight, ' * ', trace, ' + ',
|
||||
input_activation, store_trace);
|
||||
}
|
||||
} else {
|
||||
if (input.gater)
|
||||
buildSentence(trace, ' = ', input_gain, ' * ', input_activation,
|
||||
store_trace);
|
||||
else
|
||||
buildSentence(trace, ' = ', input_activation, store_trace);
|
||||
}
|
||||
for (var id in this.trace.extended) {
|
||||
// extended elegibility trace
|
||||
var xtrace = this.trace.extended[id];
|
||||
var neuron = this.neighboors[id];
|
||||
var influence = getVar('aux');
|
||||
var neuron_old = getVar(neuron, 'old');
|
||||
|
||||
var trace = getVar(this, 'trace', 'elegibility', input.ID, this.trace
|
||||
.elegibility[input.ID]);
|
||||
var xtrace = getVar(this, 'trace', 'extended', neuron.ID, input.ID,
|
||||
this.trace.extended[neuron.ID][input.ID]);
|
||||
if (neuron.selfconnected())
|
||||
var neuron_self_weight = getVar(neuron.selfconnection, 'weight');
|
||||
if (neuron.selfconnection.gater)
|
||||
var neuron_self_gain = getVar(neuron.selfconnection, 'gain');
|
||||
if (neuron.selfconnected())
|
||||
if (neuron.selfconnection.gater)
|
||||
buildSentence(xtrace, ' = ', neuron_self_gain, ' * ',
|
||||
neuron_self_weight, ' * ', xtrace, ' + ', derivative, ' * ',
|
||||
trace, ' * ', "influences[" + influences.indexOf(neuron.ID) + "]", store_trace);
|
||||
else
|
||||
buildSentence(xtrace, ' = ', neuron_self_weight, ' * ',
|
||||
xtrace, ' + ', derivative, ' * ', trace, ' * ',
|
||||
"influences[" + influences.indexOf(neuron.ID) + "]", store_trace);
|
||||
else
|
||||
buildSentence(xtrace, ' = ', derivative, ' * ', trace, ' * ',
|
||||
"influences[" + influences.indexOf(neuron.ID) + "]", store_trace);
|
||||
}
|
||||
}
|
||||
for (var connection in this.connections.gated) {
|
||||
var gated_gain = getVar(this.connections.gated[connection], 'gain');
|
||||
buildSentence(gated_gain, ' = ', activation, store_activation);
|
||||
}
|
||||
}
|
||||
if (!isInput) {
|
||||
var responsibility = getVar(this, 'error', 'responsibility', this.error
|
||||
.responsibility);
|
||||
if (isOutput) {
|
||||
var target = getVar('target');
|
||||
buildSentence(responsibility, ' = ', target, ' - ', activation,
|
||||
store_propagation);
|
||||
for (var id in this.connections.inputs) {
|
||||
var input = this.connections.inputs[id];
|
||||
var trace = getVar(this, 'trace', 'elegibility', input.ID, this.trace
|
||||
.elegibility[input.ID]);
|
||||
var input_weight = getVar(input, 'weight');
|
||||
buildSentence(input_weight, ' += ', rate, ' * (', responsibility,
|
||||
' * ', trace, ')', store_propagation);
|
||||
}
|
||||
outputs.push(activation.id);
|
||||
} else {
|
||||
if (!noProjections && !noGates) {
|
||||
var error = getVar('aux');
|
||||
for (var id in this.connections.projected) {
|
||||
var connection = this.connections.projected[id];
|
||||
var neuron = connection.to;
|
||||
var connection_weight = getVar(connection, 'weight');
|
||||
var neuron_responsibility = getVar(neuron, 'error',
|
||||
'responsibility', neuron.error.responsibility);
|
||||
if (connection.gater) {
|
||||
var connection_gain = getVar(connection, 'gain');
|
||||
buildSentence(error, ' += ', neuron_responsibility, ' * ',
|
||||
connection_gain, ' * ', connection_weight,
|
||||
store_propagation);
|
||||
} else
|
||||
buildSentence(error, ' += ', neuron_responsibility, ' * ',
|
||||
connection_weight, store_propagation);
|
||||
}
|
||||
var projected = getVar(this, 'error', 'projected', this.error.projected);
|
||||
buildSentence(projected, ' = ', derivative, ' * ', error,
|
||||
store_propagation);
|
||||
buildSentence(error, ' = 0', store_propagation);
|
||||
for (var id in this.trace.extended) {
|
||||
var neuron = this.neighboors[id];
|
||||
var influence = getVar('aux_2');
|
||||
var neuron_old = getVar(neuron, 'old');
|
||||
if (neuron.selfconnection.gater == this)
|
||||
buildSentence(influence, ' = ', neuron_old, store_propagation);
|
||||
else
|
||||
buildSentence(influence, ' = 0', store_propagation);
|
||||
for (var input in this.trace.influences[neuron.ID]) {
|
||||
var connection = this.trace.influences[neuron.ID][input];
|
||||
var connection_weight = getVar(connection, 'weight');
|
||||
var neuron_activation = getVar(connection.from, 'activation');
|
||||
buildSentence(influence, ' += ', connection_weight, ' * ',
|
||||
neuron_activation, store_propagation);
|
||||
}
|
||||
var neuron_responsibility = getVar(neuron, 'error',
|
||||
'responsibility', neuron.error.responsibility);
|
||||
buildSentence(error, ' += ', neuron_responsibility, ' * ',
|
||||
influence, store_propagation);
|
||||
}
|
||||
var gated = getVar(this, 'error', 'gated', this.error.gated);
|
||||
buildSentence(gated, ' = ', derivative, ' * ', error,
|
||||
store_propagation);
|
||||
buildSentence(responsibility, ' = ', projected, ' + ', gated,
|
||||
store_propagation);
|
||||
for (var id in this.connections.inputs) {
|
||||
var input = this.connections.inputs[id];
|
||||
var gradient = getVar('aux');
|
||||
var trace = getVar(this, 'trace', 'elegibility', input.ID, this
|
||||
.trace.elegibility[input.ID]);
|
||||
buildSentence(gradient, ' = ', projected, ' * ', trace,
|
||||
store_propagation);
|
||||
for (var id in this.trace.extended) {
|
||||
var neuron = this.neighboors[id];
|
||||
var neuron_responsibility = getVar(neuron, 'error',
|
||||
'responsibility', neuron.error.responsibility);
|
||||
var xtrace = getVar(this, 'trace', 'extended', neuron.ID,
|
||||
input.ID, this.trace.extended[neuron.ID][input.ID]);
|
||||
buildSentence(gradient, ' += ', neuron_responsibility, ' * ',
|
||||
xtrace, store_propagation);
|
||||
}
|
||||
var input_weight = getVar(input, 'weight');
|
||||
buildSentence(input_weight, ' += ', rate, ' * ', gradient,
|
||||
store_propagation);
|
||||
}
|
||||
|
||||
} else if (noGates) {
|
||||
buildSentence(responsibility, ' = 0', store_propagation);
|
||||
for (var id in this.connections.projected) {
|
||||
var connection = this.connections.projected[id];
|
||||
var neuron = connection.to;
|
||||
var connection_weight = getVar(connection, 'weight');
|
||||
var neuron_responsibility = getVar(neuron, 'error',
|
||||
'responsibility', neuron.error.responsibility);
|
||||
if (connection.gater) {
|
||||
var connection_gain = getVar(connection, 'gain');
|
||||
buildSentence(responsibility, ' += ', neuron_responsibility,
|
||||
' * ', connection_gain, ' * ', connection_weight,
|
||||
store_propagation);
|
||||
} else
|
||||
buildSentence(responsibility, ' += ', neuron_responsibility,
|
||||
' * ', connection_weight, store_propagation);
|
||||
}
|
||||
buildSentence(responsibility, ' *= ', derivative,
|
||||
store_propagation);
|
||||
for (var id in this.connections.inputs) {
|
||||
var input = this.connections.inputs[id];
|
||||
var trace = getVar(this, 'trace', 'elegibility', input.ID, this
|
||||
.trace.elegibility[input.ID]);
|
||||
var input_weight = getVar(input, 'weight');
|
||||
buildSentence(input_weight, ' += ', rate, ' * (',
|
||||
responsibility, ' * ', trace, ')', store_propagation);
|
||||
}
|
||||
} else if (noProjections) {
|
||||
buildSentence(responsibility, ' = 0', store_propagation);
|
||||
for (var id in this.trace.extended) {
|
||||
var neuron = this.neighboors[id];
|
||||
var influence = getVar('aux');
|
||||
var neuron_old = getVar(neuron, 'old');
|
||||
if (neuron.selfconnection.gater == this)
|
||||
buildSentence(influence, ' = ', neuron_old, store_propagation);
|
||||
else
|
||||
buildSentence(influence, ' = 0', store_propagation);
|
||||
for (var input in this.trace.influences[neuron.ID]) {
|
||||
var connection = this.trace.influences[neuron.ID][input];
|
||||
var connection_weight = getVar(connection, 'weight');
|
||||
var neuron_activation = getVar(connection.from, 'activation');
|
||||
buildSentence(influence, ' += ', connection_weight, ' * ',
|
||||
neuron_activation, store_propagation);
|
||||
}
|
||||
var neuron_responsibility = getVar(neuron, 'error',
|
||||
'responsibility', neuron.error.responsibility);
|
||||
buildSentence(responsibility, ' += ', neuron_responsibility,
|
||||
' * ', influence, store_propagation);
|
||||
}
|
||||
buildSentence(responsibility, ' *= ', derivative,
|
||||
store_propagation);
|
||||
for (var id in this.connections.inputs) {
|
||||
var input = this.connections.inputs[id];
|
||||
var gradient = getVar('aux');
|
||||
buildSentence(gradient, ' = 0', store_propagation);
|
||||
for (var id in this.trace.extended) {
|
||||
var neuron = this.neighboors[id];
|
||||
var neuron_responsibility = getVar(neuron, 'error',
|
||||
'responsibility', neuron.error.responsibility);
|
||||
var xtrace = getVar(this, 'trace', 'extended', neuron.ID,
|
||||
input.ID, this.trace.extended[neuron.ID][input.ID]);
|
||||
buildSentence(gradient, ' += ', neuron_responsibility, ' * ',
|
||||
xtrace, store_propagation);
|
||||
}
|
||||
var input_weight = getVar(input, 'weight');
|
||||
buildSentence(input_weight, ' += ', rate, ' * ', gradient,
|
||||
store_propagation);
|
||||
}
|
||||
}
|
||||
}
|
||||
buildSentence(bias, ' += ', rate, ' * ', responsibility,
|
||||
store_propagation);
|
||||
}
|
||||
return {
|
||||
memory: varID,
|
||||
neurons: neurons + 1,
|
||||
inputs: inputs,
|
||||
outputs: outputs,
|
||||
targets: targets,
|
||||
variables: variables,
|
||||
activation_sentences: activation_sentences,
|
||||
trace_sentences: trace_sentences,
|
||||
propagation_sentences: propagation_sentences,
|
||||
layers: layers
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// represents a connection between two neurons
|
||||
Neuron.connection = function Connection(from, to, weight) {
|
||||
|
||||
if (!from || !to)
|
||||
throw "Connection Error: Invalid neurons";
|
||||
|
||||
this.ID = Neuron.connection.uid();
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.weight = typeof weight == 'undefined' ? Math.random() * .2 - .1 :
|
||||
weight;
|
||||
this.gain = 1;
|
||||
this.gater = null;
|
||||
}
|
||||
|
||||
|
||||
// squashing functions
|
||||
Neuron.squash = {};
|
||||
|
||||
// eq. 5 & 5'
|
||||
Neuron.squash.LOGISTIC = function(x, derivate) {
|
||||
if (!derivate)
|
||||
return 1 / (1 + Math.exp(-x));
|
||||
var fx = Neuron.squash.LOGISTIC(x);
|
||||
return fx * (1 - fx);
|
||||
};
|
||||
Neuron.squash.TANH = function(x, derivate) {
|
||||
if (derivate)
|
||||
return 1 - Math.pow(Neuron.squash.TANH(x), 2);
|
||||
var eP = Math.exp(x);
|
||||
var eN = 1 / eP;
|
||||
return (eP - eN) / (eP + eN);
|
||||
};
|
||||
Neuron.squash.IDENTITY = function(x, derivate) {
|
||||
return derivate ? 1 : x;
|
||||
};
|
||||
Neuron.squash.HLIM = function(x, derivate) {
|
||||
return derivate ? 1 : +(x > 0);
|
||||
};
|
||||
|
||||
// unique ID's
|
||||
(function() {
|
||||
var neurons = 0;
|
||||
var connections = 0;
|
||||
Neuron.uid = function() {
|
||||
return neurons++;
|
||||
}
|
||||
Neuron.connection.uid = function() {
|
||||
return connections++;
|
||||
}
|
||||
Neuron.quantity = function() {
|
||||
return {
|
||||
neurons: neurons,
|
||||
connections: connections
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
// export
|
||||
if (module) module.exports = Neuron;
|
||||
|
||||
+796
@@ -0,0 +1,796 @@
|
||||
/// <reference path="synaptic.ts" />
|
||||
|
||||
import Synaptic = require('./synaptic');
|
||||
import Squash = require('./squash');
|
||||
|
||||
/******************************************************************************************
|
||||
NEURON
|
||||
*******************************************************************************************/
|
||||
|
||||
/* TS CHANGES:
|
||||
|
||||
Now Neuron.connected(neuron) returns null instead of false
|
||||
|
||||
*/
|
||||
|
||||
export class Neuron {
|
||||
ID = Neuron.uid();
|
||||
label = null;
|
||||
connections: Neuron.INeuronConnections = {
|
||||
inputs: {},
|
||||
projected: {},
|
||||
gated: {}
|
||||
};
|
||||
error = {
|
||||
responsibility: 0,
|
||||
projected: 0,
|
||||
gated: 0
|
||||
};
|
||||
trace = {
|
||||
elegibility: {},
|
||||
extended: {},
|
||||
influences: {}
|
||||
};
|
||||
state = 0;
|
||||
old = 0;
|
||||
activation = 0;
|
||||
selfconnection = new Neuron.Connection(this, this, 0); // weight = 0 -> not connected
|
||||
squash = Squash.LOGISTIC;
|
||||
neighboors = {};
|
||||
bias = Math.random() * .2 - .1;
|
||||
derivative = 0;
|
||||
|
||||
// activate the neuron
|
||||
activate(input?: number) {
|
||||
// activation from enviroment (for input neurons)
|
||||
if (typeof input != 'undefined') {
|
||||
this.activation = input;
|
||||
this.derivative = 0;
|
||||
this.bias = 0;
|
||||
return this.activation;
|
||||
}
|
||||
|
||||
// old state
|
||||
this.old = this.state;
|
||||
|
||||
// eq. 15
|
||||
this.state = this.selfconnection.gain * this.selfconnection.weight *
|
||||
this.state + this.bias;
|
||||
|
||||
for (var i in this.connections.inputs) {
|
||||
var theInput = this.connections.inputs[i];
|
||||
this.state += theInput.from.activation * theInput.weight * theInput.gain;
|
||||
}
|
||||
|
||||
// eq. 16
|
||||
this.activation = this.squash(this.state);
|
||||
|
||||
// f'(s)
|
||||
this.derivative = this.squash(this.state, true);
|
||||
|
||||
// update traces
|
||||
var influences = [];
|
||||
for (var id in this.trace.extended) {
|
||||
// extended elegibility trace
|
||||
var xtrace = this.trace.extended[id];
|
||||
var neuron = this.neighboors[id];
|
||||
|
||||
// if gated neuron's selfconnection is gated by this unit, the influence keeps track of the neuron's old state
|
||||
var influence = neuron.selfconnection.gater == this ? neuron.old : 0;
|
||||
|
||||
// index runs over all the incoming connections to the gated neuron that are gated by this unit
|
||||
for (var incoming in this.trace.influences[neuron.ID]) { // captures the effect that has an input connection to this unit, on a neuron that is gated by this unit
|
||||
influence += this.trace.influences[neuron.ID][incoming].weight *
|
||||
this.trace.influences[neuron.ID][incoming].from.activation;
|
||||
}
|
||||
influences[neuron.ID] = influence;
|
||||
}
|
||||
|
||||
for (var i in this.connections.inputs) {
|
||||
var theInput = this.connections.inputs[i];
|
||||
|
||||
// elegibility trace - Eq. 17
|
||||
this.trace.elegibility[theInput.ID] = this.selfconnection.gain * this.selfconnection
|
||||
.weight * this.trace.elegibility[theInput.ID] + theInput.gain * theInput.from
|
||||
.activation;
|
||||
|
||||
for (var id in this.trace.extended) {
|
||||
// extended elegibility trace
|
||||
var xtrace = this.trace.extended[id];
|
||||
var neuron = this.neighboors[id];
|
||||
var influence = influences[neuron.ID];
|
||||
|
||||
// eq. 18
|
||||
xtrace[theInput.ID] = neuron.selfconnection.gain * neuron.selfconnection
|
||||
.weight * xtrace[theInput.ID] + this.derivative * this.trace.elegibility[
|
||||
theInput.ID] * influence;
|
||||
}
|
||||
}
|
||||
|
||||
// update gated connection's gains
|
||||
for (var connection in this.connections.gated) {
|
||||
this.connections.gated[connection].gain = this.activation;
|
||||
}
|
||||
|
||||
return this.activation;
|
||||
}
|
||||
|
||||
// back-propagate the error
|
||||
propagate(rate: number, target?: number) {
|
||||
// error accumulator
|
||||
var error = 0;
|
||||
|
||||
// whether or not this neuron is in the output layer
|
||||
var isOutput = typeof target != 'undefined' && target != null;
|
||||
|
||||
// output neurons get their error from the enviroment
|
||||
if (isOutput)
|
||||
this.error.responsibility = this.error.projected = target - this.activation; // Eq. 10
|
||||
|
||||
else // the rest of the neuron compute their error responsibilities by backpropagation
|
||||
{
|
||||
// error responsibilities from all the connections projected from this neuron
|
||||
for (var id in this.connections.projected) {
|
||||
var connection = this.connections.projected[id];
|
||||
var neuron = connection.to;
|
||||
// Eq. 21
|
||||
error += neuron.error.responsibility * connection.gain * connection.weight;
|
||||
}
|
||||
|
||||
// projected error responsibility
|
||||
this.error.projected = this.derivative * error;
|
||||
|
||||
error = 0;
|
||||
// error responsibilities from all the connections gated by this neuron
|
||||
for (var id in this.trace.extended) {
|
||||
var neuron = this.neighboors[id]; // gated neuron
|
||||
var influence = neuron.selfconnection.gater == this ? neuron.old : 0; // if gated neuron's selfconnection is gated by this neuron
|
||||
|
||||
// index runs over all the connections to the gated neuron that are gated by this neuron
|
||||
for (var input in this.trace.influences[id]) { // captures the effect that the input connection of this neuron have, on a neuron which its input/s is/are gated by this neuron
|
||||
influence += this.trace.influences[id][input].weight * this.trace.influences[
|
||||
neuron.ID][input].from.activation;
|
||||
}
|
||||
// eq. 22
|
||||
error += neuron.error.responsibility * influence;
|
||||
}
|
||||
|
||||
// gated error responsibility
|
||||
this.error.gated = this.derivative * error;
|
||||
|
||||
// error responsibility - Eq. 23
|
||||
this.error.responsibility = this.error.projected + this.error.gated;
|
||||
}
|
||||
|
||||
// learning rate
|
||||
rate = rate || .1;
|
||||
|
||||
// adjust all the neuron's incoming connections
|
||||
for (var id in this.connections.inputs) {
|
||||
var theInput = this.connections.inputs[id];
|
||||
|
||||
// Eq. 24
|
||||
var gradient = this.error.projected * this.trace.elegibility[theInput.ID];
|
||||
for (var id in this.trace.extended) {
|
||||
var neuron = this.neighboors[id];
|
||||
gradient += neuron.error.responsibility * this.trace.extended[
|
||||
neuron.ID][theInput.ID];
|
||||
}
|
||||
theInput.weight += rate * gradient; // adjust weights - aka learn
|
||||
}
|
||||
|
||||
// adjust bias
|
||||
this.bias += rate * this.error.responsibility;
|
||||
}
|
||||
|
||||
project(neuron, weight?: number): Neuron.Connection {
|
||||
// self-connection
|
||||
if (neuron == this) {
|
||||
this.selfconnection.weight = 1;
|
||||
return this.selfconnection;
|
||||
}
|
||||
|
||||
// check if connection already exists
|
||||
var connected = this.connected(neuron);
|
||||
if (connected && connected.type == "projected") {
|
||||
// update connection
|
||||
if (typeof weight != 'undefined')
|
||||
connected.connection.weight = weight;
|
||||
// return existing connection
|
||||
return connected.connection;
|
||||
} else {
|
||||
// create a new connection
|
||||
var connection = new Neuron.Connection(this, neuron, weight);
|
||||
}
|
||||
|
||||
// reference all the connections and traces
|
||||
this.connections.projected[connection.ID] = connection;
|
||||
this.neighboors[neuron.ID] = neuron;
|
||||
neuron.connections.inputs[connection.ID] = connection;
|
||||
neuron.trace.elegibility[connection.ID] = 0;
|
||||
|
||||
for (var id in neuron.trace.extended) {
|
||||
var trace = neuron.trace.extended[id];
|
||||
trace[connection.ID] = 0;
|
||||
}
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
gate(connection) {
|
||||
// add connection to gated list
|
||||
this.connections.gated[connection.ID] = connection;
|
||||
|
||||
var neuron = connection.to;
|
||||
if (!(neuron.ID in this.trace.extended)) {
|
||||
// extended trace
|
||||
this.neighboors[neuron.ID] = neuron;
|
||||
var xtrace = this.trace.extended[neuron.ID] = {};
|
||||
for (var id in this.connections.inputs) {
|
||||
var input = this.connections.inputs[id];
|
||||
xtrace[input.ID] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// keep track
|
||||
if (neuron.ID in this.trace.influences)
|
||||
this.trace.influences[neuron.ID].push(connection);
|
||||
else
|
||||
this.trace.influences[neuron.ID] = [connection];
|
||||
|
||||
// set gater
|
||||
connection.gater = this;
|
||||
}
|
||||
|
||||
// returns true or false whether the neuron is self-connected or not
|
||||
selfconnected() {
|
||||
return this.selfconnection.weight !== 0;
|
||||
}
|
||||
|
||||
// returns true or false whether the neuron is connected to another neuron (parameter)
|
||||
connected(neuron) {
|
||||
var result: {
|
||||
type: string;
|
||||
connection: Neuron.Connection;
|
||||
} = {
|
||||
type: null,
|
||||
connection: null
|
||||
};
|
||||
|
||||
if (this == neuron) {
|
||||
if (this.selfconnected()) {
|
||||
result.type = 'selfconnection';
|
||||
result.connection = this.selfconnection;
|
||||
return result;
|
||||
} else
|
||||
return null;
|
||||
}
|
||||
|
||||
for (var type in this.connections) {
|
||||
for (var connection in this.connections[type]) {
|
||||
var connection = this.connections[type][connection];
|
||||
if (connection.to == neuron) {
|
||||
result.type = type;
|
||||
result.connection = connection;
|
||||
return result;
|
||||
} else if (connection.from == neuron) {
|
||||
result.type = type;
|
||||
result.connection = connection;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// clears all the traces (the neuron forgets it's context, but the connections remain intact)
|
||||
clear() {
|
||||
|
||||
for (var trace in this.trace.elegibility)
|
||||
this.trace.elegibility[trace] = 0;
|
||||
|
||||
for (var trace in this.trace.extended)
|
||||
for (var extended in this.trace.extended[trace])
|
||||
this.trace.extended[trace][extended] = 0;
|
||||
|
||||
this.error.responsibility = this.error.projected = this.error.gated = 0;
|
||||
}
|
||||
|
||||
// all the connections are randomized and the traces are cleared
|
||||
reset() {
|
||||
this.clear();
|
||||
|
||||
for (var type in this.connections)
|
||||
for (var connection in this.connections[type])
|
||||
this.connections[type][connection].weight = Math.random() * .2 - .1;
|
||||
this.bias = Math.random() * .2 - .1;
|
||||
|
||||
this.old = this.state = this.activation = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// hardcodes the behaviour of the neuron into an optimized function
|
||||
optimize(optimized, layer): Synaptic.ICompiledParameters {
|
||||
|
||||
optimized = optimized || {};
|
||||
var that = this;
|
||||
var store_activation = [];
|
||||
var store_trace = [];
|
||||
var store_propagation = [];
|
||||
var varID = optimized.memory || 0;
|
||||
var neurons = optimized.neurons || 1;
|
||||
var inputs = optimized.inputs || [];
|
||||
var targets = optimized.targets || [];
|
||||
var outputs = optimized.outputs || [];
|
||||
var variables = optimized.variables || {};
|
||||
var activation_sentences = optimized.activation_sentences || [];
|
||||
var trace_sentences = optimized.trace_sentences || [];
|
||||
var propagation_sentences = optimized.propagation_sentences || [];
|
||||
var layers = optimized.layers || { __count: 0, __neuron: 0 };
|
||||
|
||||
// allocate sentences
|
||||
var allocate = function(store) {
|
||||
var allocated = layer in layers && store[layers.__count];
|
||||
if (!allocated) {
|
||||
layers.__count = store.push([]) - 1;
|
||||
layers[layer] = layers.__count;
|
||||
}
|
||||
}
|
||||
allocate(activation_sentences);
|
||||
allocate(trace_sentences);
|
||||
allocate(propagation_sentences);
|
||||
var currentLayer = layers.__count;
|
||||
|
||||
// get/reserve space in memory by creating a unique ID for a variablel
|
||||
var getVar = function(...args: any[]) {
|
||||
var id;
|
||||
if (args.length == 1) {
|
||||
|
||||
if (args[0] == 'target') {
|
||||
id = 'target_' + targets.length;
|
||||
targets.push(varID);
|
||||
} else
|
||||
id = args[0];
|
||||
if (id in variables)
|
||||
return variables[id];
|
||||
return variables[id] = {
|
||||
value: 0,
|
||||
id: varID++
|
||||
};
|
||||
} else {
|
||||
var extended = args.length > 2;
|
||||
if (extended)
|
||||
var value = args.pop();
|
||||
|
||||
var unit = args.shift();
|
||||
var prop = args.pop();
|
||||
|
||||
if (!extended)
|
||||
var value = unit[prop];
|
||||
|
||||
id = prop + '_';
|
||||
for (var property in args)
|
||||
id += args[property] + '_';
|
||||
id += unit.ID;
|
||||
if (id in variables)
|
||||
return variables[id];
|
||||
|
||||
return variables[id] = {
|
||||
value: value,
|
||||
id: varID++
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// build sentence
|
||||
var buildSentence = function(...args: any[]) {
|
||||
var store = args.pop();
|
||||
var sentence = "";
|
||||
for (var i in args)
|
||||
if (typeof args[i] == 'string')
|
||||
sentence += args[i];
|
||||
else
|
||||
sentence += 'F[' + args[i].id + ']';
|
||||
|
||||
store.push(sentence + ';');
|
||||
}
|
||||
|
||||
// helper to check if an object is empty
|
||||
var isEmpty = function(obj) {
|
||||
for (var prop in obj) {
|
||||
if (obj.hasOwnProperty(prop))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// characteristics of the neuron
|
||||
var noProjections = isEmpty(this.connections.projected);
|
||||
var noGates = isEmpty(this.connections.gated);
|
||||
var isInput = layer == 'input' ? true : isEmpty(this.connections.inputs);
|
||||
var isOutput = layer == 'output' ? true : noProjections && noGates;
|
||||
|
||||
// optimize neuron's behaviour
|
||||
var rate = getVar('rate');
|
||||
var activation = getVar(this, 'activation');
|
||||
if (isInput)
|
||||
inputs.push(activation.id);
|
||||
else {
|
||||
activation_sentences[currentLayer].push(store_activation);
|
||||
trace_sentences[currentLayer].push(store_trace);
|
||||
propagation_sentences[currentLayer].push(store_propagation);
|
||||
var old = getVar(this, 'old');
|
||||
var state = getVar(this, 'state');
|
||||
var bias = getVar(this, 'bias');
|
||||
if (this.selfconnection.gater)
|
||||
var self_gain = getVar(this.selfconnection, 'gain');
|
||||
if (this.selfconnected())
|
||||
var self_weight = getVar(this.selfconnection, 'weight');
|
||||
buildSentence(old, ' = ', state, store_activation);
|
||||
if (this.selfconnected())
|
||||
if (this.selfconnection.gater)
|
||||
buildSentence(state, ' = ', self_gain, ' * ', self_weight, ' * ',
|
||||
state, ' + ', bias, store_activation);
|
||||
else
|
||||
buildSentence(state, ' = ', self_weight, ' * ', state, ' + ',
|
||||
bias, store_activation);
|
||||
else
|
||||
buildSentence(state, ' = ', bias, store_activation);
|
||||
for (var i in this.connections.inputs) {
|
||||
var input = this.connections.inputs[i];
|
||||
var input_activation = getVar(input.from, 'activation');
|
||||
var input_weight = getVar(input, 'weight');
|
||||
if (input.gater)
|
||||
var input_gain = getVar(input, 'gain');
|
||||
if (this.connections.inputs[i].gater)
|
||||
buildSentence(state, ' += ', input_activation, ' * ',
|
||||
input_weight, ' * ', input_gain, store_activation);
|
||||
else
|
||||
buildSentence(state, ' += ', input_activation, ' * ',
|
||||
input_weight, store_activation);
|
||||
}
|
||||
var derivative = getVar(this, 'derivative');
|
||||
switch (this.squash) {
|
||||
case Squash.LOGISTIC:
|
||||
buildSentence(activation, ' = (1 / (1 + Math.exp(-', state, ')))',
|
||||
store_activation);
|
||||
buildSentence(derivative, ' = ', activation, ' * (1 - ',
|
||||
activation, ')', store_activation);
|
||||
break;
|
||||
case Squash.TANH:
|
||||
var eP = getVar('aux');
|
||||
var eN = getVar('aux_2');
|
||||
buildSentence(eP, ' = Math.exp(', state, ')', store_activation);
|
||||
buildSentence(eN, ' = 1 / ', eP, store_activation);
|
||||
buildSentence(activation, ' = (', eP, ' - ', eN, ') / (', eP, ' + ', eN, ')', store_activation);
|
||||
buildSentence(derivative, ' = 1 - (', activation, ' * ', activation, ')', store_activation);
|
||||
break;
|
||||
case Squash.IDENTITY:
|
||||
buildSentence(activation, ' = ', state, store_activation);
|
||||
buildSentence(derivative, ' = 1', store_activation);
|
||||
break;
|
||||
case Squash.HLIM:
|
||||
buildSentence(activation, ' = +(', state, ' > 0)',
|
||||
store_activation);
|
||||
buildSentence(derivative, ' = 1', store_activation);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
var influences = [];
|
||||
for (var id in this.trace.extended) {
|
||||
// calculate extended elegibility traces in advance
|
||||
|
||||
var xtrace = this.trace.extended[id];
|
||||
var neuron = this.neighboors[id];
|
||||
var influence = getVar('aux');
|
||||
var neuron_old = getVar(neuron, 'old');
|
||||
var initialized = false;
|
||||
if (neuron.selfconnection.gater == this) {
|
||||
buildSentence(influence, ' = ', neuron_old, store_trace);
|
||||
initialized = true;
|
||||
}
|
||||
for (var incoming in this.trace.influences[neuron.ID]) {
|
||||
var incoming_weight = getVar(this.trace.influences[neuron.ID]
|
||||
[incoming], 'weight');
|
||||
var incoming_activation = getVar(this.trace.influences[neuron.ID]
|
||||
[incoming].from, 'activation');
|
||||
|
||||
if (initialized)
|
||||
buildSentence(influence, ' += ', incoming_weight, ' * ',
|
||||
incoming_activation, store_trace);
|
||||
else {
|
||||
buildSentence(influence, ' = ', incoming_weight, ' * ',
|
||||
incoming_activation, store_trace);
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
influences.push(neuron.ID);
|
||||
buildSentence("influences[" + (influences.length - 1) + "] = ", influence, store_trace);
|
||||
}
|
||||
|
||||
for (var i in this.connections.inputs) {
|
||||
var input = this.connections.inputs[i];
|
||||
if (input.gater)
|
||||
var input_gain = getVar(input, 'gain');
|
||||
var input_activation = getVar(input.from, 'activation');
|
||||
var trace = getVar(this, 'trace', 'elegibility', input.ID, this.trace
|
||||
.elegibility[input.ID]);
|
||||
if (this.selfconnected()) {
|
||||
if (this.selfconnection.gater) {
|
||||
if (input.gater)
|
||||
buildSentence(trace, ' = ', self_gain, ' * ', self_weight,
|
||||
' * ', trace, ' + ', input_gain, ' * ', input_activation,
|
||||
store_trace);
|
||||
else
|
||||
buildSentence(trace, ' = ', self_gain, ' * ', self_weight,
|
||||
' * ', trace, ' + ', input_activation, store_trace);
|
||||
} else {
|
||||
if (input.gater)
|
||||
buildSentence(trace, ' = ', self_weight, ' * ', trace, ' + ',
|
||||
input_gain, ' * ', input_activation, store_trace);
|
||||
else
|
||||
buildSentence(trace, ' = ', self_weight, ' * ', trace, ' + ',
|
||||
input_activation, store_trace);
|
||||
}
|
||||
} else {
|
||||
if (input.gater)
|
||||
buildSentence(trace, ' = ', input_gain, ' * ', input_activation,
|
||||
store_trace);
|
||||
else
|
||||
buildSentence(trace, ' = ', input_activation, store_trace);
|
||||
}
|
||||
for (var id in this.trace.extended) {
|
||||
// extended elegibility trace
|
||||
var xtrace = this.trace.extended[id];
|
||||
var neuron = this.neighboors[id];
|
||||
var influence = getVar('aux');
|
||||
var neuron_old = getVar(neuron, 'old');
|
||||
|
||||
var trace = getVar(this, 'trace', 'elegibility', input.ID, this.trace
|
||||
.elegibility[input.ID]);
|
||||
var xtrace = getVar(this, 'trace', 'extended', neuron.ID, input.ID,
|
||||
this.trace.extended[neuron.ID][input.ID]);
|
||||
if (neuron.selfconnected())
|
||||
var neuron_self_weight = getVar(neuron.selfconnection, 'weight');
|
||||
if (neuron.selfconnection.gater)
|
||||
var neuron_self_gain = getVar(neuron.selfconnection, 'gain');
|
||||
if (neuron.selfconnected())
|
||||
if (neuron.selfconnection.gater)
|
||||
buildSentence(xtrace, ' = ', neuron_self_gain, ' * ',
|
||||
neuron_self_weight, ' * ', xtrace, ' + ', derivative, ' * ',
|
||||
trace, ' * ', "influences[" + influences.indexOf(neuron.ID) + "]", store_trace);
|
||||
else
|
||||
buildSentence(xtrace, ' = ', neuron_self_weight, ' * ',
|
||||
xtrace, ' + ', derivative, ' * ', trace, ' * ',
|
||||
"influences[" + influences.indexOf(neuron.ID) + "]", store_trace);
|
||||
else
|
||||
buildSentence(xtrace, ' = ', derivative, ' * ', trace, ' * ',
|
||||
"influences[" + influences.indexOf(neuron.ID) + "]", store_trace);
|
||||
}
|
||||
}
|
||||
for (var connection in this.connections.gated) {
|
||||
var gated_gain = getVar(this.connections.gated[connection], 'gain');
|
||||
buildSentence(gated_gain, ' = ', activation, store_activation);
|
||||
}
|
||||
}
|
||||
if (!isInput) {
|
||||
var responsibility = getVar(this, 'error', 'responsibility', this.error
|
||||
.responsibility);
|
||||
if (isOutput) {
|
||||
var target = getVar('target');
|
||||
buildSentence(responsibility, ' = ', target, ' - ', activation,
|
||||
store_propagation);
|
||||
for (var id in this.connections.inputs) {
|
||||
var input = this.connections.inputs[id];
|
||||
var trace = getVar(this, 'trace', 'elegibility', input.ID, this.trace
|
||||
.elegibility[input.ID]);
|
||||
var input_weight = getVar(input, 'weight');
|
||||
buildSentence(input_weight, ' += ', rate, ' * (', responsibility,
|
||||
' * ', trace, ')', store_propagation);
|
||||
}
|
||||
outputs.push(activation.id);
|
||||
} else {
|
||||
if (!noProjections && !noGates) {
|
||||
var error = getVar('aux');
|
||||
for (var id in this.connections.projected) {
|
||||
var connection = this.connections.projected[id];
|
||||
var neuron = connection.to;
|
||||
var connection_weight = getVar(connection, 'weight');
|
||||
var neuron_responsibility = getVar(neuron, 'error',
|
||||
'responsibility', neuron.error.responsibility);
|
||||
if (connection.gater) {
|
||||
var connection_gain = getVar(connection, 'gain');
|
||||
buildSentence(error, ' += ', neuron_responsibility, ' * ',
|
||||
connection_gain, ' * ', connection_weight,
|
||||
store_propagation);
|
||||
} else
|
||||
buildSentence(error, ' += ', neuron_responsibility, ' * ',
|
||||
connection_weight, store_propagation);
|
||||
}
|
||||
var projected = getVar(this, 'error', 'projected', this.error.projected);
|
||||
buildSentence(projected, ' = ', derivative, ' * ', error,
|
||||
store_propagation);
|
||||
buildSentence(error, ' = 0', store_propagation);
|
||||
for (var id in this.trace.extended) {
|
||||
var neuron = this.neighboors[id];
|
||||
var influence = getVar('aux_2');
|
||||
var neuron_old = getVar(neuron, 'old');
|
||||
if (neuron.selfconnection.gater == this)
|
||||
buildSentence(influence, ' = ', neuron_old, store_propagation);
|
||||
else
|
||||
buildSentence(influence, ' = 0', store_propagation);
|
||||
for (var influenceInput in this.trace.influences[neuron.ID]) {
|
||||
var connection = this.trace.influences[neuron.ID][influenceInput];
|
||||
var connection_weight = getVar(connection, 'weight');
|
||||
var neuron_activation = getVar(connection.from, 'activation');
|
||||
buildSentence(influence, ' += ', connection_weight, ' * ',
|
||||
neuron_activation, store_propagation);
|
||||
}
|
||||
var neuron_responsibility = getVar(neuron, 'error',
|
||||
'responsibility', neuron.error.responsibility);
|
||||
buildSentence(error, ' += ', neuron_responsibility, ' * ',
|
||||
influence, store_propagation);
|
||||
}
|
||||
var gated = getVar(this, 'error', 'gated', this.error.gated);
|
||||
buildSentence(gated, ' = ', derivative, ' * ', error,
|
||||
store_propagation);
|
||||
buildSentence(responsibility, ' = ', projected, ' + ', gated,
|
||||
store_propagation);
|
||||
for (var id in this.connections.inputs) {
|
||||
var input = this.connections.inputs[id];
|
||||
var gradient = getVar('aux');
|
||||
var trace = getVar(this, 'trace', 'elegibility', input.ID, this
|
||||
.trace.elegibility[input.ID]);
|
||||
buildSentence(gradient, ' = ', projected, ' * ', trace,
|
||||
store_propagation);
|
||||
for (var id in this.trace.extended) {
|
||||
var neuron = this.neighboors[id];
|
||||
var neuron_responsibility = getVar(neuron, 'error',
|
||||
'responsibility', neuron.error.responsibility);
|
||||
var xtrace = getVar(this, 'trace', 'extended', neuron.ID,
|
||||
input.ID, this.trace.extended[neuron.ID][input.ID]);
|
||||
buildSentence(gradient, ' += ', neuron_responsibility, ' * ',
|
||||
xtrace, store_propagation);
|
||||
}
|
||||
var input_weight = getVar(input, 'weight');
|
||||
buildSentence(input_weight, ' += ', rate, ' * ', gradient,
|
||||
store_propagation);
|
||||
}
|
||||
|
||||
} else if (noGates) {
|
||||
buildSentence(responsibility, ' = 0', store_propagation);
|
||||
for (var id in this.connections.projected) {
|
||||
var connection = this.connections.projected[id];
|
||||
var neuron = connection.to;
|
||||
var connection_weight = getVar(connection, 'weight');
|
||||
var neuron_responsibility = getVar(neuron, 'error',
|
||||
'responsibility', neuron.error.responsibility);
|
||||
if (connection.gater) {
|
||||
var connection_gain = getVar(connection, 'gain');
|
||||
buildSentence(responsibility, ' += ', neuron_responsibility,
|
||||
' * ', connection_gain, ' * ', connection_weight,
|
||||
store_propagation);
|
||||
} else
|
||||
buildSentence(responsibility, ' += ', neuron_responsibility,
|
||||
' * ', connection_weight, store_propagation);
|
||||
}
|
||||
buildSentence(responsibility, ' *= ', derivative,
|
||||
store_propagation);
|
||||
for (var id in this.connections.inputs) {
|
||||
var input = this.connections.inputs[id];
|
||||
var trace = getVar(this, 'trace', 'elegibility', input.ID, this
|
||||
.trace.elegibility[input.ID]);
|
||||
var input_weight = getVar(input, 'weight');
|
||||
buildSentence(input_weight, ' += ', rate, ' * (',
|
||||
responsibility, ' * ', trace, ')', store_propagation);
|
||||
}
|
||||
} else if (noProjections) {
|
||||
buildSentence(responsibility, ' = 0', store_propagation);
|
||||
for (var id in this.trace.extended) {
|
||||
var neuron = this.neighboors[id];
|
||||
var influence = getVar('aux');
|
||||
var neuron_old = getVar(neuron, 'old');
|
||||
if (neuron.selfconnection.gater == this)
|
||||
buildSentence(influence, ' = ', neuron_old, store_propagation);
|
||||
else
|
||||
buildSentence(influence, ' = 0', store_propagation);
|
||||
for (var influenceInput in this.trace.influences[neuron.ID]) {
|
||||
var connection = this.trace.influences[neuron.ID][influenceInput];
|
||||
var connection_weight = getVar(connection, 'weight');
|
||||
var neuron_activation = getVar(connection.from, 'activation');
|
||||
buildSentence(influence, ' += ', connection_weight, ' * ',
|
||||
neuron_activation, store_propagation);
|
||||
}
|
||||
var neuron_responsibility = getVar(neuron, 'error',
|
||||
'responsibility', neuron.error.responsibility);
|
||||
buildSentence(responsibility, ' += ', neuron_responsibility,
|
||||
' * ', influence, store_propagation);
|
||||
}
|
||||
buildSentence(responsibility, ' *= ', derivative,
|
||||
store_propagation);
|
||||
for (var id in this.connections.inputs) {
|
||||
var input = this.connections.inputs[id];
|
||||
var gradient = getVar('aux');
|
||||
buildSentence(gradient, ' = 0', store_propagation);
|
||||
for (var id in this.trace.extended) {
|
||||
var neuron = this.neighboors[id];
|
||||
var neuron_responsibility = getVar(neuron, 'error',
|
||||
'responsibility', neuron.error.responsibility);
|
||||
var xtrace = getVar(this, 'trace', 'extended', neuron.ID,
|
||||
input.ID, this.trace.extended[neuron.ID][input.ID]);
|
||||
buildSentence(gradient, ' += ', neuron_responsibility, ' * ',
|
||||
xtrace, store_propagation);
|
||||
}
|
||||
var input_weight = getVar(input, 'weight');
|
||||
buildSentence(input_weight, ' += ', rate, ' * ', gradient,
|
||||
store_propagation);
|
||||
}
|
||||
}
|
||||
}
|
||||
buildSentence(bias, ' += ', rate, ' * ', responsibility,
|
||||
store_propagation);
|
||||
}
|
||||
return {
|
||||
memory: varID,
|
||||
neurons: neurons + 1,
|
||||
inputs: inputs,
|
||||
outputs: outputs,
|
||||
targets: targets,
|
||||
variables: variables,
|
||||
activation_sentences: activation_sentences,
|
||||
trace_sentences: trace_sentences,
|
||||
propagation_sentences: propagation_sentences,
|
||||
layers: layers
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export module Neuron {
|
||||
|
||||
export interface INeuronConnections {
|
||||
inputs: Synaptic.Dictionary<Neuron.Connection>;
|
||||
projected: {};
|
||||
gated: {};
|
||||
}
|
||||
|
||||
export class Connection {
|
||||
ID = Connection.uid();
|
||||
from;
|
||||
to;
|
||||
gain: number = 1;
|
||||
weight: number = 0;
|
||||
gater: any = null;
|
||||
constructor(from, to, weight?: number) {
|
||||
if (!from || !to)
|
||||
throw "Connection Error: Invalid neurons";
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.weight = typeof weight == 'undefined' || isNaN(weight) ? Math.random() * .2 - .1 :
|
||||
weight;
|
||||
}
|
||||
}
|
||||
|
||||
export var neuronQty = 0;
|
||||
export function uid(): number {
|
||||
return neuronQty++;
|
||||
}
|
||||
|
||||
export function quantity() {
|
||||
return {
|
||||
neurons: neuronQty,
|
||||
connections: Connection.connectionQty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export module Neuron.Connection {
|
||||
export var connectionQty = 0;
|
||||
export function uid(): number {
|
||||
return connectionQty++;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import Synaptic = require('./synaptic');
|
||||
|
||||
// squashing functions
|
||||
|
||||
export function LOGISTIC(x: number, derivate?: boolean) {
|
||||
if (!derivate)
|
||||
return 1 / (1 + Math.exp(-x));
|
||||
var fx = LOGISTIC(x);
|
||||
return fx * (1 - fx);
|
||||
}
|
||||
|
||||
export function TANH(x: number, derivate?: boolean) {
|
||||
if (derivate)
|
||||
return 1 - Math.pow(TANH(x), 2);
|
||||
var eP = Math.exp(x);
|
||||
var eN = 1 / eP;
|
||||
return (eP - eN) / (eP + eN);
|
||||
}
|
||||
|
||||
export function IDENTITY(x: number, derivate?: boolean) {
|
||||
return derivate ? 1 : x;
|
||||
}
|
||||
|
||||
export function RELU(x: number, derivate?: boolean) {
|
||||
if (derivate)
|
||||
return x <= 0 ? 0 : 1;
|
||||
return x <= 0 ? 0 : x;
|
||||
}
|
||||
|
||||
export function LEAKY_RELU(x: number, derivate?: boolean) {
|
||||
if (derivate)
|
||||
return x <= 0 ? 0 : 1;
|
||||
return x <= 0 ? 0.01 * x : x;
|
||||
}
|
||||
|
||||
export function SOFTPLUS(x: number, derivate?: boolean) {
|
||||
if (derivate)
|
||||
return 1 / (1 + Math.exp(-x));
|
||||
return Math.log(1 + Math.exp(x));
|
||||
}
|
||||
|
||||
export function HLIM(x: number, derivate?: boolean) {
|
||||
return derivate ? 1 : +(x > 0);
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Juan Cazala - juancazala.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE
|
||||
|
||||
|
||||
|
||||
********************************************************************************************
|
||||
SYNAPTIC
|
||||
********************************************************************************************
|
||||
|
||||
Synaptic is a javascript neural network library for node.js and the browser, its generalized
|
||||
algorithm is architecture-free, so you can build and train basically any type of first order
|
||||
or even second order neural network architectures.
|
||||
|
||||
http://en.wikipedia.org/wiki/Recurrent_neural_network#Second_Order_Recurrent_Neural_Network
|
||||
|
||||
The library includes a few built-in architectures like multilayer perceptrons, multilayer
|
||||
long-short term memory networks (LSTM) or liquid state machines, and a trainer capable of
|
||||
training any given network, and includes built-in training tasks/tests like solving an XOR,
|
||||
passing a Distracted Sequence Recall test or an Embeded Reber Grammar test.
|
||||
|
||||
The algorithm implemented by this library has been taken from Derek D. Monner's paper:
|
||||
|
||||
A generalized LSTM-like training algorithm for second-order recurrent neural networks
|
||||
http://www.overcomplete.net/papers/nn2012.pdf
|
||||
|
||||
There are references to the equations in that paper commented through the source code.
|
||||
|
||||
|
||||
********************************************************************************************/
|
||||
|
||||
var Synaptic = {
|
||||
Neuron: require('./neuron'),
|
||||
Layer: require('./layer'),
|
||||
Network: require('./network'),
|
||||
Trainer: require('./trainer'),
|
||||
Architect: require('./architect')
|
||||
};
|
||||
|
||||
// CommonJS & AMD
|
||||
if (typeof define !== 'undefined' && define.amd)
|
||||
{
|
||||
define([], function(){ return Synaptic });
|
||||
}
|
||||
|
||||
// Node.js
|
||||
if (typeof module !== 'undefined' && module.exports)
|
||||
{
|
||||
module.exports = Synaptic;
|
||||
}
|
||||
|
||||
// Browser
|
||||
if (typeof window == 'object')
|
||||
{
|
||||
(function(){
|
||||
var oldSynaptic = window['synaptic'];
|
||||
Synaptic.ninja = function(){
|
||||
window['synaptic'] = oldSynaptic;
|
||||
return Synaptic;
|
||||
};
|
||||
})();
|
||||
|
||||
window['synaptic'] = Synaptic;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
********************************************************************************************
|
||||
SYNAPTIC
|
||||
********************************************************************************************
|
||||
|
||||
Synaptic is a javascript neural network library for node.js and the browser, its generalized
|
||||
algorithm is architecture-free, so you can build and train basically any type of first order
|
||||
or even second order neural network architectures.
|
||||
|
||||
http://en.wikipedia.org/wiki/Recurrent_neural_network#Second_Order_Recurrent_Neural_Network
|
||||
|
||||
The library includes a few built-in architectures like multilayer perceptrons, multilayer
|
||||
long-short term memory networks (LSTM) or liquid state machines, and a trainer capable of
|
||||
training any given network, and includes built-in training tasks/tests like solving an XOR,
|
||||
passing a Distracted Sequence Recall test or an Embeded Reber Grammar test.
|
||||
|
||||
The algorithm implemented by this library has been taken from Derek D. Monner's paper:
|
||||
|
||||
A generalized LSTM-like training algorithm for second-order recurrent neural networks
|
||||
http://www.overcomplete.net/papers/nn2012.pdf
|
||||
|
||||
There are references to the equations in that paper commented through the source code.
|
||||
|
||||
|
||||
********************************************************************************************/
|
||||
|
||||
|
||||
|
||||
import network = require('./network');
|
||||
import layer = require('./layer');
|
||||
import neuron = require('./neuron');
|
||||
import trainer = require('./trainer');
|
||||
import architect = require('./architect');
|
||||
import squash = require('./squash');
|
||||
|
||||
declare var window;
|
||||
|
||||
module Synaptic {
|
||||
export interface Dictionary<T> {
|
||||
[id: string] : T;
|
||||
}
|
||||
|
||||
var oldSynaptic = typeof window != "undefined" && window && window['Synaptic'];
|
||||
|
||||
export function ninja() {
|
||||
window['synaptic'] = oldSynaptic;
|
||||
return Synaptic;
|
||||
}
|
||||
|
||||
export interface ICompiledParameters {
|
||||
memory?: any;
|
||||
neurons?: number;
|
||||
inputs?: any[];
|
||||
outputs?: any[];
|
||||
targets?: any[];
|
||||
variables?: any;
|
||||
activation_sentences?: any[];
|
||||
trace_sentences?: any[];
|
||||
propagation_sentences?: any[];
|
||||
layers?: any;
|
||||
}
|
||||
|
||||
export var Neuron = neuron.Neuron;
|
||||
export var Layer = layer.Layer;
|
||||
export var Network = network.Network;
|
||||
export var Trainer = trainer.Trainer;
|
||||
export var Squash = squash;
|
||||
export var Architect = architect;
|
||||
}
|
||||
|
||||
export = Synaptic;
|
||||
|
||||
if(typeof window != "undefined")
|
||||
window['synaptic'] = Synaptic;
|
||||
+127
-119
@@ -1,23 +1,31 @@
|
||||
import net =require('./network');
|
||||
|
||||
/*******************************************************************************************
|
||||
TRAINER
|
||||
*******************************************************************************************/
|
||||
|
||||
function Trainer(network, options) {
|
||||
options = options || {};
|
||||
this.network = network;
|
||||
this.rate = options.rate || .2;
|
||||
this.iterations = options.iterations || 100000;
|
||||
this.error = options.error || .005
|
||||
this.cost = options.cost || Trainer.cost.CROSS_ENTROPY;
|
||||
}
|
||||
export class Trainer {
|
||||
network: net.Network;
|
||||
rate: any = .2;
|
||||
iterations = 100000;
|
||||
error = .005;
|
||||
cost: Trainer.ITrainerCostFn;
|
||||
schedule: any;
|
||||
|
||||
Trainer.prototype = {
|
||||
constructor(network: net.Network, options?: any) {
|
||||
options = options || {};
|
||||
this.network = network;
|
||||
this.rate = options.rate || .2;
|
||||
this.iterations = options.iterations || 100000;
|
||||
this.error = options.error || .005
|
||||
this.cost = options.cost || Trainer.cost.CROSS_ENTROPY;
|
||||
}
|
||||
|
||||
// trains any given set to a network
|
||||
train: function(set, options) {
|
||||
train(set, options) {
|
||||
|
||||
var error = 1;
|
||||
var iterations = bucketSize = 0;
|
||||
var iterations = 0, bucketSize = 0;
|
||||
var abort_training = false;
|
||||
var input, output, target, currentRate;
|
||||
|
||||
@@ -42,7 +50,7 @@ Trainer.prototype = {
|
||||
this.cost = options.cost;
|
||||
if (options.schedule)
|
||||
this.schedule = options.schedule;
|
||||
if (options.customLog){
|
||||
if (options.customLog) {
|
||||
// for backward compatibility with code that used customLog
|
||||
console.log('Deprecated: use schedule instead of customLog')
|
||||
this.schedule = options.customLog;
|
||||
@@ -50,7 +58,7 @@ Trainer.prototype = {
|
||||
}
|
||||
|
||||
currentRate = this.rate;
|
||||
if(Array.isArray(this.rate)) {
|
||||
if (Array.isArray(this.rate)) {
|
||||
bucketSize = Math.floor(this.iterations / this.rate.length);
|
||||
}
|
||||
|
||||
@@ -58,7 +66,7 @@ Trainer.prototype = {
|
||||
while (!abort_training && iterations < this.iterations && error > this.error) {
|
||||
error = 0;
|
||||
|
||||
if(bucketSize > 0) {
|
||||
if (bucketSize > 0) {
|
||||
var currentBucket = Math.floor(iterations / bucketSize);
|
||||
currentRate = this.rate[currentBucket];
|
||||
}
|
||||
@@ -100,14 +108,14 @@ Trainer.prototype = {
|
||||
}
|
||||
|
||||
return results;
|
||||
},
|
||||
}
|
||||
|
||||
// trains any given set to a network using a WebWorker
|
||||
workerTrain: function(set, callback, options) {
|
||||
workerTrain(set, callback, options) {
|
||||
|
||||
var that = this;
|
||||
var error = 1;
|
||||
var iterations = bucketSize = 0;
|
||||
var iterations = 0, bucketSize = 0;
|
||||
var input, output, target, currentRate;
|
||||
var length = set.length;
|
||||
var abort_training = false;
|
||||
@@ -120,7 +128,7 @@ Trainer.prototype = {
|
||||
//@ http://jsfromhell.com/array/shuffle [v1.0]
|
||||
function shuffle(o) { //v1.0
|
||||
for (var j, x, i = o.length; i; j = Math.floor(Math.random() *
|
||||
i), x = o[--i], o[i] = o[j], o[j] = x);
|
||||
i), x = o[--i], o[i] = o[j], o[j] = x);
|
||||
return o;
|
||||
};
|
||||
}
|
||||
@@ -137,12 +145,12 @@ Trainer.prototype = {
|
||||
if (options.customLog)
|
||||
// for backward compatibility with code that used customLog
|
||||
console.log('Deprecated: use schedule instead of customLog')
|
||||
this.schedule = options.customLog;
|
||||
this.schedule = options.customLog;
|
||||
}
|
||||
|
||||
// dynamic learning rate
|
||||
currentRate = this.rate;
|
||||
if(Array.isArray(this.rate)) {
|
||||
if (Array.isArray(this.rate)) {
|
||||
bucketSize = Math.floor(this.iterations / this.rate.length);
|
||||
}
|
||||
|
||||
@@ -150,89 +158,84 @@ Trainer.prototype = {
|
||||
var worker = this.network.worker();
|
||||
|
||||
// activate the network
|
||||
function activateWorker(input)
|
||||
{
|
||||
worker.postMessage({
|
||||
action: "activate",
|
||||
input: input,
|
||||
memoryBuffer: that.network.optimized.memory
|
||||
}, [that.network.optimized.memory.buffer]);
|
||||
function activateWorker(input) {
|
||||
worker.postMessage({
|
||||
action: "activate",
|
||||
input: input,
|
||||
memoryBuffer: that.network.optimized.memory
|
||||
}, [that.network.optimized.memory.buffer]);
|
||||
}
|
||||
|
||||
// backpropagate the network
|
||||
function propagateWorker(target){
|
||||
if(bucketSize > 0) {
|
||||
var currentBucket = Math.floor(iterations / bucketSize);
|
||||
currentRate = this.rate[currentBucket];
|
||||
}
|
||||
worker.postMessage({
|
||||
action: "propagate",
|
||||
target: target,
|
||||
rate: currentRate,
|
||||
memoryBuffer: that.network.optimized.memory
|
||||
}, [that.network.optimized.memory.buffer]);
|
||||
function propagateWorker(target) {
|
||||
if (bucketSize > 0) {
|
||||
var currentBucket = Math.floor(iterations / bucketSize);
|
||||
currentRate = this.rate[currentBucket];
|
||||
}
|
||||
worker.postMessage({
|
||||
action: "propagate",
|
||||
target: target,
|
||||
rate: currentRate,
|
||||
memoryBuffer: that.network.optimized.memory
|
||||
}, [that.network.optimized.memory.buffer]);
|
||||
}
|
||||
|
||||
// train the worker
|
||||
worker.onmessage = function(e){
|
||||
// give control of the memory back to the network
|
||||
that.network.optimized.ownership(e.data.memoryBuffer);
|
||||
worker.onmessage = function(e) {
|
||||
// give control of the memory back to the network
|
||||
that.network.optimized.ownership(e.data.memoryBuffer);
|
||||
|
||||
if (e.data.action == "propagate")
|
||||
{
|
||||
if (index >= length)
|
||||
{
|
||||
index = 0;
|
||||
iterations++;
|
||||
error /= set.length;
|
||||
if (e.data.action == "propagate") {
|
||||
if (index >= length) {
|
||||
index = 0;
|
||||
iterations++;
|
||||
error /= set.length;
|
||||
|
||||
// log
|
||||
if (options) {
|
||||
if (this.schedule && this.schedule.every && iterations % this.schedule.every == 0)
|
||||
abort_training = this.schedule.do({
|
||||
error: error,
|
||||
iterations: iterations
|
||||
});
|
||||
else if (options.log && iterations % options.log == 0) {
|
||||
console.log('iterations', iterations, 'error', error);
|
||||
};
|
||||
if (options.shuffle)
|
||||
shuffle(set);
|
||||
}
|
||||
// log
|
||||
if (options) {
|
||||
if (this.schedule && this.schedule.every && iterations % this.schedule.every == 0)
|
||||
abort_training = this.schedule.do({
|
||||
error: error,
|
||||
iterations: iterations
|
||||
});
|
||||
else if (options.log && iterations % options.log == 0) {
|
||||
console.log('iterations', iterations, 'error', error);
|
||||
};
|
||||
if (options.shuffle)
|
||||
shuffle(set);
|
||||
}
|
||||
|
||||
if (!abort_training && iterations < that.iterations && error > that.error)
|
||||
{
|
||||
activateWorker(set[index].input);
|
||||
} else {
|
||||
// callback
|
||||
callback({
|
||||
error: error,
|
||||
iterations: iterations,
|
||||
time: Date.now() - start
|
||||
})
|
||||
}
|
||||
error = 0;
|
||||
} else {
|
||||
activateWorker(set[index].input);
|
||||
}
|
||||
if (!abort_training && iterations < that.iterations && error > that.error) {
|
||||
activateWorker(set[index].input);
|
||||
} else {
|
||||
// callback
|
||||
callback({
|
||||
error: error,
|
||||
iterations: iterations,
|
||||
time: Date.now() - start
|
||||
})
|
||||
}
|
||||
error = 0;
|
||||
} else {
|
||||
activateWorker(set[index].input);
|
||||
}
|
||||
}
|
||||
|
||||
if (e.data.action == "activate")
|
||||
{
|
||||
error += that.cost(set[index].output, e.data.output);
|
||||
propagateWorker(set[index].output);
|
||||
index++;
|
||||
}
|
||||
if (e.data.action == "activate") {
|
||||
error += that.cost(set[index].output, e.data.output);
|
||||
propagateWorker(set[index].output);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
// kick it
|
||||
var index = 0;
|
||||
var iterations = 0;
|
||||
activateWorker(set[index].input);
|
||||
},
|
||||
}
|
||||
|
||||
// trains an XOR to the network
|
||||
XOR: function(options) {
|
||||
XOR(options) {
|
||||
|
||||
if (this.network.inputs() != 2 || this.network.outputs() != 1)
|
||||
throw "Error: Incompatible network (2 inputs, 1 output)";
|
||||
@@ -252,19 +255,19 @@ Trainer.prototype = {
|
||||
input: [0, 0],
|
||||
output: [0]
|
||||
}, {
|
||||
input: [1, 0],
|
||||
output: [1]
|
||||
}, {
|
||||
input: [0, 1],
|
||||
output: [1]
|
||||
}, {
|
||||
input: [1, 1],
|
||||
output: [0]
|
||||
}], defaults);
|
||||
},
|
||||
input: [1, 0],
|
||||
output: [1]
|
||||
}, {
|
||||
input: [0, 1],
|
||||
output: [1]
|
||||
}, {
|
||||
input: [1, 1],
|
||||
output: [0]
|
||||
}], defaults);
|
||||
}
|
||||
|
||||
// trains the network to pass a Distracted Sequence Recall test
|
||||
DSR: function(options) {
|
||||
DSR(options) {
|
||||
options = options || {};
|
||||
|
||||
var targets = options.targets || [2, 4, 7, 8];
|
||||
@@ -276,8 +279,10 @@ Trainer.prototype = {
|
||||
var rate = options.rate || .1;
|
||||
var log = options.log || 0;
|
||||
var schedule = options.schedule || {};
|
||||
|
||||
var trial = correct = i = j = success = 0,
|
||||
var correct = 0;
|
||||
var i = 0;
|
||||
var success = 0;
|
||||
var trial = i = correct = j = success = 0,
|
||||
error = 1,
|
||||
symbols = targets.length + distractors.length + prompts.length;
|
||||
|
||||
@@ -320,6 +325,7 @@ Trainer.prototype = {
|
||||
}
|
||||
|
||||
//train sequence
|
||||
var distractorsCorrect;
|
||||
var targetsCorrect = distractorsCorrect = 0;
|
||||
error = 0;
|
||||
for (i = 0; i < length; i++) {
|
||||
@@ -389,10 +395,10 @@ Trainer.prototype = {
|
||||
error: error,
|
||||
time: Date.now() - start
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// train the network to learn an Embeded Reber Grammar
|
||||
ERG: function(options) {
|
||||
ERG(options) {
|
||||
|
||||
options = options || {};
|
||||
var iterations = options.iterations || 150000;
|
||||
@@ -580,27 +586,29 @@ Trainer.prototype = {
|
||||
generate: generate
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Built-in cost functions
|
||||
Trainer.cost = {
|
||||
// Eq. 9
|
||||
CROSS_ENTROPY: function(target, output)
|
||||
{
|
||||
var crossentropy = 0;
|
||||
for (var i in output)
|
||||
crossentropy -= (target[i] * Math.log(output[i]+1e-15)) + ((1-target[i]) * Math.log((1+1e-15)-output[i])); // +1e-15 is a tiny push away to avoid Math.log(0)
|
||||
return crossentropy;
|
||||
},
|
||||
MSE: function(target, output)
|
||||
{
|
||||
var mse = 0;
|
||||
for (var i in output)
|
||||
mse += Math.pow(target[i] - output[i], 2);
|
||||
return mse / output.length;
|
||||
}
|
||||
}
|
||||
|
||||
// export
|
||||
if (module) module.exports = Trainer;
|
||||
export module Trainer {
|
||||
// Built-in cost functions
|
||||
|
||||
export interface ITrainerCostFn {
|
||||
(target, output): number;
|
||||
}
|
||||
|
||||
export var cost = {
|
||||
// Eq. 9
|
||||
CROSS_ENTROPY: function(target, output) {
|
||||
var crossentropy = 0;
|
||||
for (var i in output)
|
||||
crossentropy -= (target[i] * Math.log(output[i] + 1e-15)) + ((1 - target[i]) * Math.log((1 + 1e-15) - output[i])); // +1e-15 is a tiny push away to avoid Math.log(0)
|
||||
return crossentropy;
|
||||
},
|
||||
MSE: function(target, output) {
|
||||
var mse = 0;
|
||||
for (var i in output)
|
||||
mse += Math.pow(target[i] - output[i], 2);
|
||||
return mse / output.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
// import
|
||||
|
||||
var assert = require('assert'),
|
||||
synaptic = require('../src/synaptic');
|
||||
synaptic = require('../dist/src/synaptic');
|
||||
|
||||
var Perceptron = synaptic.Architect.Perceptron,
|
||||
LSTM = synaptic.Architect.LSTM,
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"preserveConstEnums": true,
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"target": "ES5",
|
||||
"outDir": "./dist"
|
||||
},
|
||||
"files": [
|
||||
"src/synaptic.ts",
|
||||
"src/squash.ts",
|
||||
"src/neuron.ts",
|
||||
"src/layer.ts",
|
||||
"src/network.ts",
|
||||
"src/trainer.ts",
|
||||
"src/architect.ts",
|
||||
"src/architect/Perceptron.ts",
|
||||
"src/architect/LSTM.ts",
|
||||
"src/architect/Liquid.ts",
|
||||
"src/architect/Hopfield.ts"
|
||||
]
|
||||
}
|
||||
Referência em uma Nova Issue
Bloquear um usuário