整理桌面
This commit is contained in:
369
node_modules/neataptic/src/architecture/architect.js
generated
vendored
Normal file
369
node_modules/neataptic/src/architecture/architect.js
generated
vendored
Normal file
@@ -0,0 +1,369 @@
|
||||
/* Import */
|
||||
var methods = require('../methods/methods');
|
||||
var Network = require('./network');
|
||||
var Group = require('./group');
|
||||
var Layer = require('./layer');
|
||||
var Node = require('./node');
|
||||
|
||||
/*******************************************************************************
|
||||
architect
|
||||
*******************************************************************************/
|
||||
|
||||
var architect = {
|
||||
/**
|
||||
* Constructs a network from a given array of connected nodes
|
||||
*/
|
||||
Construct: function (list) {
|
||||
// Create a network
|
||||
var network = new Network(0, 0);
|
||||
|
||||
// Transform all groups into nodes
|
||||
var nodes = [];
|
||||
|
||||
var i;
|
||||
for (i = 0; i < list.length; i++) {
|
||||
let j;
|
||||
if (list[i] instanceof Group) {
|
||||
for (j = 0; j < list[i].nodes.length; j++) {
|
||||
nodes.push(list[i].nodes[j]);
|
||||
}
|
||||
} else if (list[i] instanceof Layer) {
|
||||
for (j = 0; j < list[i].nodes.length; j++) {
|
||||
for (var k = 0; k < list[i].nodes[j].nodes.length; k++) {
|
||||
nodes.push(list[i].nodes[j].nodes[k]);
|
||||
}
|
||||
}
|
||||
} else if (list[i] instanceof Node) {
|
||||
nodes.push(list[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Determine input and output nodes
|
||||
var inputs = [];
|
||||
var outputs = [];
|
||||
for (i = nodes.length - 1; i >= 0; i--) {
|
||||
if (nodes[i].type === 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length === 0) {
|
||||
nodes[i].type = 'output';
|
||||
network.output++;
|
||||
outputs.push(nodes[i]);
|
||||
nodes.splice(i, 1);
|
||||
} else if (nodes[i].type === 'input' || !nodes[i].connections.in.length) {
|
||||
nodes[i].type = 'input';
|
||||
network.input++;
|
||||
inputs.push(nodes[i]);
|
||||
nodes.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Input nodes are always first, output nodes are always last
|
||||
nodes = inputs.concat(nodes).concat(outputs);
|
||||
|
||||
if (network.input === 0 || network.output === 0) {
|
||||
throw new Error('Given nodes have no clear input/output node!');
|
||||
}
|
||||
|
||||
for (i = 0; i < nodes.length; i++) {
|
||||
let j;
|
||||
for (j = 0; j < nodes[i].connections.out.length; j++) {
|
||||
network.connections.push(nodes[i].connections.out[j]);
|
||||
}
|
||||
for (j = 0; j < nodes[i].connections.gated.length; j++) {
|
||||
network.gates.push(nodes[i].connections.gated[j]);
|
||||
}
|
||||
if (nodes[i].connections.self.weight !== 0) {
|
||||
network.selfconns.push(nodes[i].connections.self);
|
||||
}
|
||||
}
|
||||
|
||||
network.nodes = nodes;
|
||||
|
||||
return network;
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a multilayer perceptron (MLP)
|
||||
*/
|
||||
Perceptron: function () {
|
||||
// Convert arguments to Array
|
||||
var layers = Array.prototype.slice.call(arguments);
|
||||
if (layers.length < 3) {
|
||||
throw new Error('You have to specify at least 3 layers');
|
||||
}
|
||||
|
||||
// Create a list of nodes/groups
|
||||
var nodes = [];
|
||||
nodes.push(new Group(layers[0]));
|
||||
|
||||
for (var i = 1; i < layers.length; i++) {
|
||||
var layer = layers[i];
|
||||
layer = new Group(layer);
|
||||
nodes.push(layer);
|
||||
nodes[i - 1].connect(nodes[i], methods.connection.ALL_TO_ALL);
|
||||
}
|
||||
|
||||
// Construct the network
|
||||
return architect.Construct(nodes);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a randomly connected network
|
||||
*/
|
||||
Random: function (input, hidden, output, options) {
|
||||
options = options || {};
|
||||
|
||||
var connections = options.connections || hidden * 2;
|
||||
var backconnections = options.backconnections || 0;
|
||||
var selfconnections = options.selfconnections || 0;
|
||||
var gates = options.gates || 0;
|
||||
|
||||
var network = new Network(input, output);
|
||||
|
||||
var i;
|
||||
for (i = 0; i < hidden; i++) {
|
||||
network.mutate(methods.mutation.ADD_NODE);
|
||||
}
|
||||
|
||||
for (i = 0; i < connections - hidden; i++) {
|
||||
network.mutate(methods.mutation.ADD_CONN);
|
||||
}
|
||||
|
||||
for (i = 0; i < backconnections; i++) {
|
||||
network.mutate(methods.mutation.ADD_BACK_CONN);
|
||||
}
|
||||
|
||||
for (i = 0; i < selfconnections; i++) {
|
||||
network.mutate(methods.mutation.ADD_SELF_CONN);
|
||||
}
|
||||
|
||||
for (i = 0; i < gates; i++) {
|
||||
network.mutate(methods.mutation.ADD_GATE);
|
||||
}
|
||||
|
||||
return network;
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a long short-term memory network
|
||||
*/
|
||||
LSTM: function () {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
if (args.length < 3) {
|
||||
throw new Error('You have to specify at least 3 layers');
|
||||
}
|
||||
|
||||
var last = args.pop();
|
||||
|
||||
var outputLayer;
|
||||
if (typeof last === 'number') {
|
||||
outputLayer = new Group(last);
|
||||
last = {};
|
||||
} else {
|
||||
outputLayer = new Group(args.pop()); // last argument
|
||||
}
|
||||
|
||||
outputLayer.set({
|
||||
type: 'output'
|
||||
});
|
||||
|
||||
var options = {};
|
||||
options.memoryToMemory = last.memoryToMemory || false;
|
||||
options.outputToMemory = last.outputToMemory || false;
|
||||
options.outputToGates = last.outputToGates || false;
|
||||
options.inputToOutput = last.inputToOutput === undefined ? true : last.inputToOutput;
|
||||
options.inputToDeep = last.inputToDeep === undefined ? true : last.inputToDeep;
|
||||
|
||||
var inputLayer = new Group(args.shift()); // first argument
|
||||
inputLayer.set({
|
||||
type: 'input'
|
||||
});
|
||||
|
||||
var blocks = args; // all the arguments in the middle
|
||||
|
||||
var nodes = [];
|
||||
nodes.push(inputLayer);
|
||||
|
||||
var previous = inputLayer;
|
||||
for (var i = 0; i < blocks.length; i++) {
|
||||
var block = blocks[i];
|
||||
|
||||
// Init required nodes (in activation order)
|
||||
var inputGate = new Group(block);
|
||||
var forgetGate = new Group(block);
|
||||
var memoryCell = new Group(block);
|
||||
var outputGate = new Group(block);
|
||||
var outputBlock = i === blocks.length - 1 ? outputLayer : new Group(block);
|
||||
|
||||
inputGate.set({
|
||||
bias: 1
|
||||
});
|
||||
forgetGate.set({
|
||||
bias: 1
|
||||
});
|
||||
outputGate.set({
|
||||
bias: 1
|
||||
});
|
||||
|
||||
// Connect the input with all the nodes
|
||||
var input = previous.connect(memoryCell, methods.connection.ALL_TO_ALL);
|
||||
previous.connect(inputGate, methods.connection.ALL_TO_ALL);
|
||||
previous.connect(outputGate, methods.connection.ALL_TO_ALL);
|
||||
previous.connect(forgetGate, methods.connection.ALL_TO_ALL);
|
||||
|
||||
// Set up internal connections
|
||||
memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL);
|
||||
memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL);
|
||||
memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL);
|
||||
var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE);
|
||||
var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL);
|
||||
|
||||
// Set up gates
|
||||
inputGate.gate(input, methods.gating.INPUT);
|
||||
forgetGate.gate(forget, methods.gating.SELF);
|
||||
outputGate.gate(output, methods.gating.OUTPUT);
|
||||
|
||||
// Input to all memory cells
|
||||
if (options.inputToDeep && i > 0) {
|
||||
let input = inputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL);
|
||||
inputGate.gate(input, methods.gating.INPUT);
|
||||
}
|
||||
|
||||
// Optional connections
|
||||
if (options.memoryToMemory) {
|
||||
let input = memoryCell.connect(memoryCell, methods.connection.ALL_TO_ELSE);
|
||||
inputGate.gate(input, methods.gating.INPUT);
|
||||
}
|
||||
|
||||
if (options.outputToMemory) {
|
||||
let input = outputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL);
|
||||
inputGate.gate(input, methods.gating.INPUT);
|
||||
}
|
||||
|
||||
if (options.outputToGates) {
|
||||
outputLayer.connect(inputGate, methods.connection.ALL_TO_ALL);
|
||||
outputLayer.connect(forgetGate, methods.connection.ALL_TO_ALL);
|
||||
outputLayer.connect(outputGate, methods.connection.ALL_TO_ALL);
|
||||
}
|
||||
|
||||
// Add to array
|
||||
nodes.push(inputGate);
|
||||
nodes.push(forgetGate);
|
||||
nodes.push(memoryCell);
|
||||
nodes.push(outputGate);
|
||||
if (i !== blocks.length - 1) nodes.push(outputBlock);
|
||||
|
||||
previous = outputBlock;
|
||||
}
|
||||
|
||||
// input to output direct connection
|
||||
if (options.inputToOutput) {
|
||||
inputLayer.connect(outputLayer, methods.connection.ALL_TO_ALL);
|
||||
}
|
||||
|
||||
nodes.push(outputLayer);
|
||||
return architect.Construct(nodes);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a gated recurrent unit network
|
||||
*/
|
||||
GRU: function () {
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
if (args.length < 3) {
|
||||
throw new Error('not enough layers (minimum 3) !!');
|
||||
}
|
||||
|
||||
var inputLayer = new Group(args.shift()); // first argument
|
||||
var outputLayer = new Group(args.pop()); // last argument
|
||||
var blocks = args; // all the arguments in the middle
|
||||
|
||||
var nodes = [];
|
||||
nodes.push(inputLayer);
|
||||
|
||||
var previous = inputLayer;
|
||||
for (var i = 0; i < blocks.length; i++) {
|
||||
var layer = new Layer.GRU(blocks[i]);
|
||||
previous.connect(layer);
|
||||
previous = layer;
|
||||
|
||||
nodes.push(layer);
|
||||
}
|
||||
|
||||
previous.connect(outputLayer);
|
||||
nodes.push(outputLayer);
|
||||
|
||||
return architect.Construct(nodes);
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a hopfield network of the given size
|
||||
*/
|
||||
Hopfield: function (size) {
|
||||
var input = new Group(size);
|
||||
var output = new Group(size);
|
||||
|
||||
input.connect(output, methods.connection.ALL_TO_ALL);
|
||||
|
||||
input.set({
|
||||
type: 'input'
|
||||
});
|
||||
output.set({
|
||||
squash: methods.activation.STEP,
|
||||
type: 'output'
|
||||
});
|
||||
|
||||
var network = new architect.Construct([input, output]);
|
||||
|
||||
return network;
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a NARX network (remember previous inputs/outputs)
|
||||
*/
|
||||
NARX: function (inputSize, hiddenLayers, outputSize, previousInput, previousOutput) {
|
||||
if (!Array.isArray(hiddenLayers)) {
|
||||
hiddenLayers = [hiddenLayers];
|
||||
}
|
||||
|
||||
var nodes = [];
|
||||
|
||||
var input = new Layer.Dense(inputSize);
|
||||
var inputMemory = new Layer.Memory(inputSize, previousInput);
|
||||
var hidden = [];
|
||||
var output = new Layer.Dense(outputSize);
|
||||
var outputMemory = new Layer.Memory(outputSize, previousOutput);
|
||||
|
||||
nodes.push(input);
|
||||
nodes.push(outputMemory);
|
||||
|
||||
for (var i = 0; i < hiddenLayers.length; i++) {
|
||||
var hiddenLayer = new Layer.Dense(hiddenLayers[i]);
|
||||
hidden.push(hiddenLayer);
|
||||
nodes.push(hiddenLayer);
|
||||
if (typeof hidden[i - 1] !== 'undefined') {
|
||||
hidden[i - 1].connect(hiddenLayer, methods.connection.ALL_TO_ALL);
|
||||
}
|
||||
}
|
||||
|
||||
nodes.push(inputMemory);
|
||||
nodes.push(output);
|
||||
|
||||
input.connect(hidden[0], methods.connection.ALL_TO_ALL);
|
||||
input.connect(inputMemory, methods.connection.ONE_TO_ONE, 1);
|
||||
inputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL);
|
||||
hidden[hidden.length - 1].connect(output, methods.connection.ALL_TO_ALL);
|
||||
output.connect(outputMemory, methods.connection.ONE_TO_ONE, 1);
|
||||
outputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL);
|
||||
|
||||
input.set({
|
||||
type: 'input'
|
||||
});
|
||||
output.set({
|
||||
type: 'output'
|
||||
});
|
||||
|
||||
return architect.Construct(nodes);
|
||||
}
|
||||
};
|
||||
|
||||
/* Export */
|
||||
module.exports = architect;
|
49
node_modules/neataptic/src/architecture/connection.js
generated
vendored
Normal file
49
node_modules/neataptic/src/architecture/connection.js
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
/* Export */
|
||||
module.exports = Connection;
|
||||
|
||||
/*******************************************************************************
|
||||
CONNECTION
|
||||
*******************************************************************************/
|
||||
|
||||
function Connection (from, to, weight) {
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
this.gain = 1;
|
||||
|
||||
this.weight = (typeof weight === 'undefined') ? Math.random() * 0.2 - 0.1 : weight;
|
||||
|
||||
this.gater = null;
|
||||
this.elegibility = 0;
|
||||
|
||||
// For tracking momentum
|
||||
this.previousDeltaWeight = 0;
|
||||
|
||||
// Batch training
|
||||
this.totalDeltaWeight = 0;
|
||||
|
||||
this.xtrace = {
|
||||
nodes: [],
|
||||
values: []
|
||||
};
|
||||
}
|
||||
|
||||
Connection.prototype = {
|
||||
/**
|
||||
* Converts the connection to a json object
|
||||
*/
|
||||
toJSON: function () {
|
||||
var json = {
|
||||
weight: this.weight
|
||||
};
|
||||
|
||||
return json;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns an innovation ID
|
||||
* https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function)
|
||||
*/
|
||||
Connection.innovationID = function (a, b) {
|
||||
return 1 / 2 * (a + b) * (a + b + 1) + b;
|
||||
};
|
263
node_modules/neataptic/src/architecture/group.js
generated
vendored
Normal file
263
node_modules/neataptic/src/architecture/group.js
generated
vendored
Normal file
@@ -0,0 +1,263 @@
|
||||
/* Export */
|
||||
module.exports = Group;
|
||||
|
||||
/* Import */
|
||||
var methods = require('../methods/methods');
|
||||
var config = require('../config');
|
||||
var Layer = require('./layer');
|
||||
var Node = require('./node');
|
||||
|
||||
/*******************************************************************************
|
||||
Group
|
||||
*******************************************************************************/
|
||||
|
||||
function Group (size) {
|
||||
this.nodes = [];
|
||||
this.connections = {
|
||||
in: [],
|
||||
out: [],
|
||||
self: []
|
||||
};
|
||||
|
||||
for (var i = 0; i < size; i++) {
|
||||
this.nodes.push(new Node());
|
||||
}
|
||||
}
|
||||
|
||||
Group.prototype = {
|
||||
/**
|
||||
* Activates all the nodes in the group
|
||||
*/
|
||||
activate: function (value) {
|
||||
var values = [];
|
||||
|
||||
if (typeof value !== 'undefined' && value.length !== this.nodes.length) {
|
||||
throw new Error('Array with values should be same as the amount of nodes!');
|
||||
}
|
||||
|
||||
for (var i = 0; i < this.nodes.length; i++) {
|
||||
var activation;
|
||||
if (typeof value === 'undefined') {
|
||||
activation = this.nodes[i].activate();
|
||||
} else {
|
||||
activation = this.nodes[i].activate(value[i]);
|
||||
}
|
||||
|
||||
values.push(activation);
|
||||
}
|
||||
|
||||
return values;
|
||||
},
|
||||
|
||||
/**
|
||||
* Propagates all the node in the group
|
||||
*/
|
||||
propagate: function (rate, momentum, target) {
|
||||
if (typeof target !== 'undefined' && target.length !== this.nodes.length) {
|
||||
throw new Error('Array with values should be same as the amount of nodes!');
|
||||
}
|
||||
|
||||
for (var i = this.nodes.length - 1; i >= 0; i--) {
|
||||
if (typeof target === 'undefined') {
|
||||
this.nodes[i].propagate(rate, momentum, true);
|
||||
} else {
|
||||
this.nodes[i].propagate(rate, momentum, true, target[i]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Connects the nodes in this group to nodes in another group or just a node
|
||||
*/
|
||||
connect: function (target, method, weight) {
|
||||
var connections = [];
|
||||
var i, j;
|
||||
if (target instanceof Group) {
|
||||
if (typeof method === 'undefined') {
|
||||
if (this !== target) {
|
||||
if (config.warnings) console.warn('No group connection specified, using ALL_TO_ALL');
|
||||
method = methods.connection.ALL_TO_ALL;
|
||||
} else {
|
||||
if (config.warnings) console.warn('No group connection specified, using ONE_TO_ONE');
|
||||
method = methods.connection.ONE_TO_ONE;
|
||||
}
|
||||
}
|
||||
if (method === methods.connection.ALL_TO_ALL || method === methods.connection.ALL_TO_ELSE) {
|
||||
for (i = 0; i < this.nodes.length; i++) {
|
||||
for (j = 0; j < target.nodes.length; j++) {
|
||||
if (method === methods.connection.ALL_TO_ELSE && this.nodes[i] === target.nodes[j]) continue;
|
||||
let connection = this.nodes[i].connect(target.nodes[j], weight);
|
||||
this.connections.out.push(connection[0]);
|
||||
target.connections.in.push(connection[0]);
|
||||
connections.push(connection[0]);
|
||||
}
|
||||
}
|
||||
} else if (method === methods.connection.ONE_TO_ONE) {
|
||||
if (this.nodes.length !== target.nodes.length) {
|
||||
throw new Error('From and To group must be the same size!');
|
||||
}
|
||||
|
||||
for (i = 0; i < this.nodes.length; i++) {
|
||||
let connection = this.nodes[i].connect(target.nodes[i], weight);
|
||||
this.connections.self.push(connection[0]);
|
||||
connections.push(connection[0]);
|
||||
}
|
||||
}
|
||||
} else if (target instanceof Layer) {
|
||||
connections = target.input(this, method, weight);
|
||||
} else if (target instanceof Node) {
|
||||
for (i = 0; i < this.nodes.length; i++) {
|
||||
let connection = this.nodes[i].connect(target, weight);
|
||||
this.connections.out.push(connection[0]);
|
||||
connections.push(connection[0]);
|
||||
}
|
||||
}
|
||||
|
||||
return connections;
|
||||
},
|
||||
|
||||
/**
|
||||
* Make nodes from this group gate the given connection(s)
|
||||
*/
|
||||
gate: function (connections, method) {
|
||||
if (typeof method === 'undefined') {
|
||||
throw new Error('Please specify Gating.INPUT, Gating.OUTPUT');
|
||||
}
|
||||
|
||||
if (!Array.isArray(connections)) {
|
||||
connections = [connections];
|
||||
}
|
||||
|
||||
var nodes1 = [];
|
||||
var nodes2 = [];
|
||||
|
||||
var i, j;
|
||||
for (i = 0; i < connections.length; i++) {
|
||||
var connection = connections[i];
|
||||
if (!nodes1.includes(connection.from)) nodes1.push(connection.from);
|
||||
if (!nodes2.includes(connection.to)) nodes2.push(connection.to);
|
||||
}
|
||||
|
||||
switch (method) {
|
||||
case methods.gating.INPUT:
|
||||
for (i = 0; i < nodes2.length; i++) {
|
||||
let node = nodes2[i];
|
||||
let gater = this.nodes[i % this.nodes.length];
|
||||
|
||||
for (j = 0; j < node.connections.in.length; j++) {
|
||||
let conn = node.connections.in[j];
|
||||
if (connections.includes(conn)) {
|
||||
gater.gate(conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case methods.gating.OUTPUT:
|
||||
for (i = 0; i < nodes1.length; i++) {
|
||||
let node = nodes1[i];
|
||||
let gater = this.nodes[i % this.nodes.length];
|
||||
|
||||
for (j = 0; j < node.connections.out.length; j++) {
|
||||
let conn = node.connections.out[j];
|
||||
if (connections.includes(conn)) {
|
||||
gater.gate(conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case methods.gating.SELF:
|
||||
for (i = 0; i < nodes1.length; i++) {
|
||||
let node = nodes1[i];
|
||||
let gater = this.nodes[i % this.nodes.length];
|
||||
|
||||
if (connections.includes(node.connections.self)) {
|
||||
gater.gate(node.connections.self);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the value of a property for every node
|
||||
*/
|
||||
set: function (values) {
|
||||
for (var i = 0; i < this.nodes.length; i++) {
|
||||
if (typeof values.bias !== 'undefined') {
|
||||
this.nodes[i].bias = values.bias;
|
||||
}
|
||||
|
||||
this.nodes[i].squash = values.squash || this.nodes[i].squash;
|
||||
this.nodes[i].type = values.type || this.nodes[i].type;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Disconnects all nodes from this group from another given group/node
|
||||
*/
|
||||
disconnect: function (target, twosided) {
|
||||
twosided = twosided || false;
|
||||
|
||||
// In the future, disconnect will return a connection so indexOf can be used
|
||||
var i, j, k;
|
||||
if (target instanceof Group) {
|
||||
for (i = 0; i < this.nodes.length; i++) {
|
||||
for (j = 0; j < target.nodes.length; j++) {
|
||||
this.nodes[i].disconnect(target.nodes[j], twosided);
|
||||
|
||||
for (k = this.connections.out.length - 1; k >= 0; k--) {
|
||||
let conn = this.connections.out[k];
|
||||
|
||||
if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) {
|
||||
this.connections.out.splice(k, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (twosided) {
|
||||
for (k = this.connections.in.length - 1; k >= 0; k--) {
|
||||
let conn = this.connections.in[k];
|
||||
|
||||
if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) {
|
||||
this.connections.in.splice(k, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (target instanceof Node) {
|
||||
for (i = 0; i < this.nodes.length; i++) {
|
||||
this.nodes[i].disconnect(target, twosided);
|
||||
|
||||
for (j = this.connections.out.length - 1; j >= 0; j--) {
|
||||
let conn = this.connections.out[j];
|
||||
|
||||
if (conn.from === this.nodes[i] && conn.to === target) {
|
||||
this.connections.out.splice(j, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (twosided) {
|
||||
for (j = this.connections.in.length - 1; j >= 0; j--) {
|
||||
var conn = this.connections.in[j];
|
||||
|
||||
if (conn.from === target && conn.to === this.nodes[i]) {
|
||||
this.connections.in.splice(j, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear the context of this group
|
||||
*/
|
||||
clear: function () {
|
||||
for (var i = 0; i < this.nodes.length; i++) {
|
||||
this.nodes[i].clear();
|
||||
}
|
||||
}
|
||||
};
|
378
node_modules/neataptic/src/architecture/layer.js
generated
vendored
Normal file
378
node_modules/neataptic/src/architecture/layer.js
generated
vendored
Normal file
@@ -0,0 +1,378 @@
|
||||
/* Export */
|
||||
module.exports = Layer;
|
||||
|
||||
/* Import */
|
||||
var methods = require('../methods/methods');
|
||||
var Group = require('./group');
|
||||
var Node = require('./node');
|
||||
|
||||
/*******************************************************************************
|
||||
Group
|
||||
*******************************************************************************/
|
||||
|
||||
function Layer () {
|
||||
this.output = null;
|
||||
|
||||
this.nodes = [];
|
||||
this.connections = { in: [],
|
||||
out: [],
|
||||
self: []
|
||||
};
|
||||
}
|
||||
|
||||
Layer.prototype = {
|
||||
/**
|
||||
* Activates all the nodes in the group
|
||||
*/
|
||||
activate: function (value) {
|
||||
var values = [];
|
||||
|
||||
if (typeof value !== 'undefined' && value.length !== this.nodes.length) {
|
||||
throw new Error('Array with values should be same as the amount of nodes!');
|
||||
}
|
||||
|
||||
for (var i = 0; i < this.nodes.length; i++) {
|
||||
var activation;
|
||||
if (typeof value === 'undefined') {
|
||||
activation = this.nodes[i].activate();
|
||||
} else {
|
||||
activation = this.nodes[i].activate(value[i]);
|
||||
}
|
||||
|
||||
values.push(activation);
|
||||
}
|
||||
|
||||
return values;
|
||||
},
|
||||
|
||||
/**
|
||||
* Propagates all the node in the group
|
||||
*/
|
||||
propagate: function (rate, momentum, target) {
|
||||
if (typeof target !== 'undefined' && target.length !== this.nodes.length) {
|
||||
throw new Error('Array with values should be same as the amount of nodes!');
|
||||
}
|
||||
|
||||
for (var i = this.nodes.length - 1; i >= 0; i--) {
|
||||
if (typeof target === 'undefined') {
|
||||
this.nodes[i].propagate(rate, momentum, true);
|
||||
} else {
|
||||
this.nodes[i].propagate(rate, momentum, true, target[i]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Connects the nodes in this group to nodes in another group or just a node
|
||||
*/
|
||||
connect: function (target, method, weight) {
|
||||
var connections;
|
||||
if (target instanceof Group || target instanceof Node) {
|
||||
connections = this.output.connect(target, method, weight);
|
||||
} else if (target instanceof Layer) {
|
||||
connections = target.input(this, method, weight);
|
||||
}
|
||||
|
||||
return connections;
|
||||
},
|
||||
|
||||
/**
|
||||
* Make nodes from this group gate the given connection(s)
|
||||
*/
|
||||
gate: function (connections, method) {
|
||||
this.output.gate(connections, method);
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the value of a property for every node
|
||||
*/
|
||||
set: function (values) {
|
||||
for (var i = 0; i < this.nodes.length; i++) {
|
||||
var node = this.nodes[i];
|
||||
|
||||
if (node instanceof Node) {
|
||||
if (typeof values.bias !== 'undefined') {
|
||||
node.bias = values.bias;
|
||||
}
|
||||
|
||||
node.squash = values.squash || node.squash;
|
||||
node.type = values.type || node.type;
|
||||
} else if (node instanceof Group) {
|
||||
node.set(values);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Disconnects all nodes from this group from another given group/node
|
||||
*/
|
||||
disconnect: function (target, twosided) {
|
||||
twosided = twosided || false;
|
||||
|
||||
// In the future, disconnect will return a connection so indexOf can be used
|
||||
var i, j, k;
|
||||
if (target instanceof Group) {
|
||||
for (i = 0; i < this.nodes.length; i++) {
|
||||
for (j = 0; j < target.nodes.length; j++) {
|
||||
this.nodes[i].disconnect(target.nodes[j], twosided);
|
||||
|
||||
for (k = this.connections.out.length - 1; k >= 0; k--) {
|
||||
let conn = this.connections.out[k];
|
||||
|
||||
if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) {
|
||||
this.connections.out.splice(k, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (twosided) {
|
||||
for (k = this.connections.in.length - 1; k >= 0; k--) {
|
||||
let conn = this.connections.in[k];
|
||||
|
||||
if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) {
|
||||
this.connections.in.splice(k, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (target instanceof Node) {
|
||||
for (i = 0; i < this.nodes.length; i++) {
|
||||
this.nodes[i].disconnect(target, twosided);
|
||||
|
||||
for (j = this.connections.out.length - 1; j >= 0; j--) {
|
||||
let conn = this.connections.out[j];
|
||||
|
||||
if (conn.from === this.nodes[i] && conn.to === target) {
|
||||
this.connections.out.splice(j, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (twosided) {
|
||||
for (k = this.connections.in.length - 1; k >= 0; k--) {
|
||||
let conn = this.connections.in[k];
|
||||
|
||||
if (conn.from === target && conn.to === this.nodes[i]) {
|
||||
this.connections.in.splice(k, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear the context of this group
|
||||
*/
|
||||
clear: function () {
|
||||
for (var i = 0; i < this.nodes.length; i++) {
|
||||
this.nodes[i].clear();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Layer.Dense = function (size) {
|
||||
// Create the layer
|
||||
var layer = new Layer();
|
||||
|
||||
// Init required nodes (in activation order)
|
||||
var block = new Group(size);
|
||||
|
||||
layer.nodes.push(block);
|
||||
layer.output = block;
|
||||
|
||||
layer.input = function (from, method, weight) {
|
||||
if (from instanceof Layer) from = from.output;
|
||||
method = method || methods.connection.ALL_TO_ALL;
|
||||
return from.connect(block, method, weight);
|
||||
};
|
||||
|
||||
return layer;
|
||||
};
|
||||
|
||||
Layer.LSTM = function (size) {
|
||||
// Create the layer
|
||||
var layer = new Layer();
|
||||
|
||||
// Init required nodes (in activation order)
|
||||
var inputGate = new Group(size);
|
||||
var forgetGate = new Group(size);
|
||||
var memoryCell = new Group(size);
|
||||
var outputGate = new Group(size);
|
||||
var outputBlock = new Group(size);
|
||||
|
||||
inputGate.set({
|
||||
bias: 1
|
||||
});
|
||||
forgetGate.set({
|
||||
bias: 1
|
||||
});
|
||||
outputGate.set({
|
||||
bias: 1
|
||||
});
|
||||
|
||||
// Set up internal connections
|
||||
memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL);
|
||||
memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL);
|
||||
memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL);
|
||||
var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE);
|
||||
var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL);
|
||||
|
||||
// Set up gates
|
||||
forgetGate.gate(forget, methods.gating.SELF);
|
||||
outputGate.gate(output, methods.gating.OUTPUT);
|
||||
|
||||
// Add to nodes array
|
||||
layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock];
|
||||
|
||||
// Define output
|
||||
layer.output = outputBlock;
|
||||
|
||||
layer.input = function (from, method, weight) {
|
||||
if (from instanceof Layer) from = from.output;
|
||||
method = method || methods.connection.ALL_TO_ALL;
|
||||
var connections = [];
|
||||
|
||||
var input = from.connect(memoryCell, method, weight);
|
||||
connections = connections.concat(input);
|
||||
|
||||
connections = connections.concat(from.connect(inputGate, method, weight));
|
||||
connections = connections.concat(from.connect(outputGate, method, weight));
|
||||
connections = connections.concat(from.connect(forgetGate, method, weight));
|
||||
|
||||
inputGate.gate(input, methods.gating.INPUT);
|
||||
|
||||
return connections;
|
||||
};
|
||||
|
||||
return layer;
|
||||
};
|
||||
|
||||
Layer.GRU = function (size) {
|
||||
// Create the layer
|
||||
var layer = new Layer();
|
||||
|
||||
var updateGate = new Group(size);
|
||||
var inverseUpdateGate = new Group(size);
|
||||
var resetGate = new Group(size);
|
||||
var memoryCell = new Group(size);
|
||||
var output = new Group(size);
|
||||
var previousOutput = new Group(size);
|
||||
|
||||
previousOutput.set({
|
||||
bias: 0,
|
||||
squash: methods.activation.IDENTITY,
|
||||
type: 'constant'
|
||||
});
|
||||
memoryCell.set({
|
||||
squash: methods.activation.TANH
|
||||
});
|
||||
inverseUpdateGate.set({
|
||||
bias: 0,
|
||||
squash: methods.activation.INVERSE,
|
||||
type: 'constant'
|
||||
});
|
||||
updateGate.set({
|
||||
bias: 1
|
||||
});
|
||||
resetGate.set({
|
||||
bias: 0
|
||||
});
|
||||
|
||||
// Update gate calculation
|
||||
previousOutput.connect(updateGate, methods.connection.ALL_TO_ALL);
|
||||
|
||||
// Inverse update gate calculation
|
||||
updateGate.connect(inverseUpdateGate, methods.connection.ONE_TO_ONE, 1);
|
||||
|
||||
// Reset gate calculation
|
||||
previousOutput.connect(resetGate, methods.connection.ALL_TO_ALL);
|
||||
|
||||
// Memory calculation
|
||||
var reset = previousOutput.connect(memoryCell, methods.connection.ALL_TO_ALL);
|
||||
|
||||
resetGate.gate(reset, methods.gating.OUTPUT); // gate
|
||||
|
||||
// Output calculation
|
||||
var update1 = previousOutput.connect(output, methods.connection.ALL_TO_ALL);
|
||||
var update2 = memoryCell.connect(output, methods.connection.ALL_TO_ALL);
|
||||
|
||||
updateGate.gate(update1, methods.gating.OUTPUT);
|
||||
inverseUpdateGate.gate(update2, methods.gating.OUTPUT);
|
||||
|
||||
// Previous output calculation
|
||||
output.connect(previousOutput, methods.connection.ONE_TO_ONE, 1);
|
||||
|
||||
// Add to nodes array
|
||||
layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput];
|
||||
|
||||
layer.output = output;
|
||||
|
||||
layer.input = function (from, method, weight) {
|
||||
if (from instanceof Layer) from = from.output;
|
||||
method = method || methods.connection.ALL_TO_ALL;
|
||||
var connections = [];
|
||||
|
||||
connections = connections.concat(from.connect(updateGate, method, weight));
|
||||
connections = connections.concat(from.connect(resetGate, method, weight));
|
||||
connections = connections.concat(from.connect(memoryCell, method, weight));
|
||||
|
||||
return connections;
|
||||
};
|
||||
|
||||
return layer;
|
||||
};
|
||||
|
||||
Layer.Memory = function (size, memory) {
|
||||
// Create the layer
|
||||
var layer = new Layer();
|
||||
// Because the output can only be one group, we have to put the nodes all in óne group
|
||||
|
||||
var previous = null;
|
||||
var i;
|
||||
for (i = 0; i < memory; i++) {
|
||||
var block = new Group(size);
|
||||
|
||||
block.set({
|
||||
squash: methods.activation.IDENTITY,
|
||||
bias: 0,
|
||||
type: 'constant'
|
||||
});
|
||||
|
||||
if (previous != null) {
|
||||
previous.connect(block, methods.connection.ONE_TO_ONE, 1);
|
||||
}
|
||||
|
||||
layer.nodes.push(block);
|
||||
previous = block;
|
||||
}
|
||||
|
||||
layer.nodes.reverse();
|
||||
|
||||
for (i = 0; i < layer.nodes.length; i++) {
|
||||
layer.nodes[i].nodes.reverse();
|
||||
}
|
||||
|
||||
// Because output can only be óne group, fit all memory nodes in óne group
|
||||
var outputGroup = new Group(0);
|
||||
for (var group in layer.nodes) {
|
||||
outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes);
|
||||
}
|
||||
layer.output = outputGroup;
|
||||
|
||||
layer.input = function (from, method, weight) {
|
||||
if (from instanceof Layer) from = from.output;
|
||||
method = method || methods.connection.ALL_TO_ALL;
|
||||
|
||||
if (from.nodes.length !== layer.nodes[layer.nodes.length - 1].nodes.length) {
|
||||
throw new Error('Previous layer size must be same as memory size');
|
||||
}
|
||||
|
||||
return from.connect(layer.nodes[layer.nodes.length - 1], methods.connection.ONE_TO_ONE, 1);
|
||||
};
|
||||
|
||||
return layer;
|
||||
};
|
1341
node_modules/neataptic/src/architecture/network.js
generated
vendored
Normal file
1341
node_modules/neataptic/src/architecture/network.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
431
node_modules/neataptic/src/architecture/node.js
generated
vendored
Normal file
431
node_modules/neataptic/src/architecture/node.js
generated
vendored
Normal file
@@ -0,0 +1,431 @@
|
||||
/* Export */
|
||||
module.exports = Node;
|
||||
|
||||
/* Import */
|
||||
var methods = require('../methods/methods');
|
||||
var Connection = require('./connection');
|
||||
var config = require('../config');
|
||||
|
||||
/*******************************************************************************
|
||||
NODE
|
||||
*******************************************************************************/
|
||||
|
||||
function Node (type) {
|
||||
this.bias = (type === 'input') ? 0 : Math.random() * 0.2 - 0.1;
|
||||
this.squash = methods.activation.LOGISTIC;
|
||||
this.type = type || 'hidden';
|
||||
|
||||
this.activation = 0;
|
||||
this.state = 0;
|
||||
this.old = 0;
|
||||
|
||||
// For dropout
|
||||
this.mask = 1;
|
||||
|
||||
// For tracking momentum
|
||||
this.previousDeltaBias = 0;
|
||||
|
||||
// Batch training
|
||||
this.totalDeltaBias = 0;
|
||||
|
||||
this.connections = {
|
||||
in: [],
|
||||
out: [],
|
||||
gated: [],
|
||||
self: new Connection(this, this, 0)
|
||||
};
|
||||
|
||||
// Data for backpropagation
|
||||
this.error = {
|
||||
responsibility: 0,
|
||||
projected: 0,
|
||||
gated: 0
|
||||
};
|
||||
}
|
||||
|
||||
Node.prototype = {
|
||||
/**
|
||||
* Activates the node
|
||||
*/
|
||||
activate: function (input) {
|
||||
// Check if an input is given
|
||||
if (typeof input !== 'undefined') {
|
||||
this.activation = input;
|
||||
return this.activation;
|
||||
}
|
||||
|
||||
this.old = this.state;
|
||||
|
||||
// All activation sources coming from the node itself
|
||||
this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias;
|
||||
|
||||
// Activation sources coming from connections
|
||||
var i;
|
||||
for (i = 0; i < this.connections.in.length; i++) {
|
||||
var connection = this.connections.in[i];
|
||||
this.state += connection.from.activation * connection.weight * connection.gain;
|
||||
}
|
||||
|
||||
// Squash the values received
|
||||
this.activation = this.squash(this.state) * this.mask;
|
||||
this.derivative = this.squash(this.state, true);
|
||||
|
||||
// Update traces
|
||||
var nodes = [];
|
||||
var influences = [];
|
||||
|
||||
for (i = 0; i < this.connections.gated.length; i++) {
|
||||
let conn = this.connections.gated[i];
|
||||
let node = conn.to;
|
||||
|
||||
let index = nodes.indexOf(node);
|
||||
if (index > -1) {
|
||||
influences[index] += conn.weight * conn.from.activation;
|
||||
} else {
|
||||
nodes.push(node);
|
||||
influences.push(conn.weight * conn.from.activation +
|
||||
(node.connections.self.gater === this ? node.old : 0));
|
||||
}
|
||||
|
||||
// Adjust the gain to this nodes' activation
|
||||
conn.gain = this.activation;
|
||||
}
|
||||
|
||||
for (i = 0; i < this.connections.in.length; i++) {
|
||||
let connection = this.connections.in[i];
|
||||
|
||||
// Elegibility trace
|
||||
connection.elegibility = this.connections.self.gain * this.connections.self.weight *
|
||||
connection.elegibility + connection.from.activation * connection.gain;
|
||||
|
||||
// Extended trace
|
||||
for (var j = 0; j < nodes.length; j++) {
|
||||
let node = nodes[j];
|
||||
let influence = influences[j];
|
||||
|
||||
let index = connection.xtrace.nodes.indexOf(node);
|
||||
|
||||
if (index > -1) {
|
||||
connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight *
|
||||
connection.xtrace.values[index] + this.derivative * connection.elegibility * influence;
|
||||
} else {
|
||||
// Does not exist there yet, might be through mutation
|
||||
connection.xtrace.nodes.push(node);
|
||||
connection.xtrace.values.push(this.derivative * connection.elegibility * influence);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.activation;
|
||||
},
|
||||
|
||||
/**
|
||||
* Activates the node without calculating elegibility traces and such
|
||||
*/
|
||||
noTraceActivate: function (input) {
|
||||
// Check if an input is given
|
||||
if (typeof input !== 'undefined') {
|
||||
this.activation = input;
|
||||
return this.activation;
|
||||
}
|
||||
|
||||
// All activation sources coming from the node itself
|
||||
this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias;
|
||||
|
||||
// Activation sources coming from connections
|
||||
var i;
|
||||
for (i = 0; i < this.connections.in.length; i++) {
|
||||
var connection = this.connections.in[i];
|
||||
this.state += connection.from.activation * connection.weight * connection.gain;
|
||||
}
|
||||
|
||||
// Squash the values received
|
||||
this.activation = this.squash(this.state);
|
||||
|
||||
for (i = 0; i < this.connections.gated.length; i++) {
|
||||
this.connections.gated[i].gain = this.activation;
|
||||
}
|
||||
|
||||
return this.activation;
|
||||
},
|
||||
|
||||
/**
|
||||
* Back-propagate the error, aka learn
|
||||
*/
|
||||
propagate: function (rate, momentum, update, target) {
|
||||
momentum = momentum || 0;
|
||||
rate = rate || 0.3;
|
||||
|
||||
// Error accumulator
|
||||
var error = 0;
|
||||
|
||||
// Output nodes get their error from the enviroment
|
||||
if (this.type === 'output') {
|
||||
this.error.responsibility = this.error.projected = target - this.activation;
|
||||
} else { // the rest of the nodes compute their error responsibilities by backpropagation
|
||||
// error responsibilities from all the connections projected from this node
|
||||
var i;
|
||||
for (i = 0; i < this.connections.out.length; i++) {
|
||||
let connection = this.connections.out[i];
|
||||
let node = connection.to;
|
||||
// Eq. 21
|
||||
error += node.error.responsibility * connection.weight * connection.gain;
|
||||
}
|
||||
|
||||
// Projected error responsibility
|
||||
this.error.projected = this.derivative * error;
|
||||
|
||||
// Error responsibilities from all connections gated by this neuron
|
||||
error = 0;
|
||||
|
||||
for (i = 0; i < this.connections.gated.length; i++) {
|
||||
let conn = this.connections.gated[i];
|
||||
let node = conn.to;
|
||||
let influence = node.connections.self.gater === this ? node.old : 0;
|
||||
|
||||
influence += conn.weight * conn.from.activation;
|
||||
error += node.error.responsibility * influence;
|
||||
}
|
||||
|
||||
// Gated error responsibility
|
||||
this.error.gated = this.derivative * error;
|
||||
|
||||
// Error responsibility
|
||||
this.error.responsibility = this.error.projected + this.error.gated;
|
||||
}
|
||||
|
||||
if (this.type === 'constant') return;
|
||||
|
||||
// Adjust all the node's incoming connections
|
||||
for (i = 0; i < this.connections.in.length; i++) {
|
||||
let connection = this.connections.in[i];
|
||||
|
||||
let gradient = this.error.projected * connection.elegibility;
|
||||
|
||||
for (var j = 0; j < connection.xtrace.nodes.length; j++) {
|
||||
let node = connection.xtrace.nodes[j];
|
||||
let value = connection.xtrace.values[j];
|
||||
gradient += node.error.responsibility * value;
|
||||
}
|
||||
|
||||
// Adjust weight
|
||||
let deltaWeight = rate * gradient * this.mask;
|
||||
connection.totalDeltaWeight += deltaWeight;
|
||||
if (update) {
|
||||
connection.totalDeltaWeight += momentum * connection.previousDeltaWeight;
|
||||
connection.weight += connection.totalDeltaWeight;
|
||||
connection.previousDeltaWeight = connection.totalDeltaWeight;
|
||||
connection.totalDeltaWeight = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust bias
|
||||
var deltaBias = rate * this.error.responsibility;
|
||||
this.totalDeltaBias += deltaBias;
|
||||
if (update) {
|
||||
this.totalDeltaBias += momentum * this.previousDeltaBias;
|
||||
this.bias += this.totalDeltaBias;
|
||||
this.previousDeltaBias = this.totalDeltaBias;
|
||||
this.totalDeltaBias = 0;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates a connection from this node to the given node
|
||||
*/
|
||||
connect: function (target, weight) {
|
||||
var connections = [];
|
||||
if (typeof target.bias !== 'undefined') { // must be a node!
|
||||
if (target === this) {
|
||||
// Turn on the self connection by setting the weight
|
||||
if (this.connections.self.weight !== 0) {
|
||||
if (config.warnings) console.warn('This connection already exists!');
|
||||
} else {
|
||||
this.connections.self.weight = weight || 1;
|
||||
}
|
||||
connections.push(this.connections.self);
|
||||
} else if (this.isProjectingTo(target)) {
|
||||
throw new Error('Already projecting a connection to this node!');
|
||||
} else {
|
||||
let connection = new Connection(this, target, weight);
|
||||
target.connections.in.push(connection);
|
||||
this.connections.out.push(connection);
|
||||
|
||||
connections.push(connection);
|
||||
}
|
||||
} else { // should be a group
|
||||
for (var i = 0; i < target.nodes.length; i++) {
|
||||
let connection = new Connection(this, target.nodes[i], weight);
|
||||
target.nodes[i].connections.in.push(connection);
|
||||
this.connections.out.push(connection);
|
||||
target.connections.in.push(connection);
|
||||
|
||||
connections.push(connection);
|
||||
}
|
||||
}
|
||||
return connections;
|
||||
},
|
||||
|
||||
/**
|
||||
* Disconnects this node from the other node
|
||||
*/
|
||||
disconnect: function (node, twosided) {
|
||||
if (this === node) {
|
||||
this.connections.self.weight = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
for (var i = 0; i < this.connections.out.length; i++) {
|
||||
let conn = this.connections.out[i];
|
||||
if (conn.to === node) {
|
||||
this.connections.out.splice(i, 1);
|
||||
let j = conn.to.connections.in.indexOf(conn);
|
||||
conn.to.connections.in.splice(j, 1);
|
||||
if (conn.gater !== null) conn.gater.ungate(conn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (twosided) {
|
||||
node.disconnect(this);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Make this node gate a connection
|
||||
*/
|
||||
gate: function (connections) {
|
||||
if (!Array.isArray(connections)) {
|
||||
connections = [connections];
|
||||
}
|
||||
|
||||
for (var i = 0; i < connections.length; i++) {
|
||||
var connection = connections[i];
|
||||
|
||||
this.connections.gated.push(connection);
|
||||
connection.gater = this;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes the gates from this node from the given connection(s)
|
||||
*/
|
||||
ungate: function (connections) {
|
||||
if (!Array.isArray(connections)) {
|
||||
connections = [connections];
|
||||
}
|
||||
|
||||
for (var i = connections.length - 1; i >= 0; i--) {
|
||||
var connection = connections[i];
|
||||
|
||||
var index = this.connections.gated.indexOf(connection);
|
||||
this.connections.gated.splice(index, 1);
|
||||
connection.gater = null;
|
||||
connection.gain = 1;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Clear the context of the node
|
||||
*/
|
||||
clear: function () {
|
||||
for (var i = 0; i < this.connections.in.length; i++) {
|
||||
var connection = this.connections.in[i];
|
||||
|
||||
connection.elegibility = 0;
|
||||
connection.xtrace = {
|
||||
nodes: [],
|
||||
values: []
|
||||
};
|
||||
}
|
||||
|
||||
for (i = 0; i < this.connections.gated.length; i++) {
|
||||
let conn = this.connections.gated[i];
|
||||
conn.gain = 0;
|
||||
}
|
||||
|
||||
this.error.responsibility = this.error.projected = this.error.gated = 0;
|
||||
this.old = this.state = this.activation = 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Mutates the node with the given method
|
||||
*/
|
||||
mutate: function (method) {
|
||||
if (typeof method === 'undefined') {
|
||||
throw new Error('No mutate method given!');
|
||||
} else if (!(method.name in methods.mutation)) {
|
||||
throw new Error('This method does not exist!');
|
||||
}
|
||||
|
||||
switch (method) {
|
||||
case methods.mutation.MOD_ACTIVATION:
|
||||
// Can't be the same squash
|
||||
var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length];
|
||||
this.squash = squash;
|
||||
break;
|
||||
case methods.mutation.MOD_BIAS:
|
||||
var modification = Math.random() * (method.max - method.min) + method.min;
|
||||
this.bias += modification;
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if this node is projecting to the given node
|
||||
*/
|
||||
isProjectingTo: function (node) {
|
||||
if (node === this && this.connections.self.weight !== 0) return true;
|
||||
|
||||
for (var i = 0; i < this.connections.out.length; i++) {
|
||||
var conn = this.connections.out[i];
|
||||
if (conn.to === node) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if the given node is projecting to this node
|
||||
*/
|
||||
isProjectedBy: function (node) {
|
||||
if (node === this && this.connections.self.weight !== 0) return true;
|
||||
|
||||
for (var i = 0; i < this.connections.in.length; i++) {
|
||||
var conn = this.connections.in[i];
|
||||
if (conn.from === node) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Converts the node to a json object
|
||||
*/
|
||||
toJSON: function () {
|
||||
var json = {
|
||||
bias: this.bias,
|
||||
type: this.type,
|
||||
squash: this.squash.name,
|
||||
mask: this.mask
|
||||
};
|
||||
|
||||
return json;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert a json object to a node
|
||||
*/
|
||||
Node.fromJSON = function (json) {
|
||||
var node = new Node();
|
||||
node.bias = json.bias;
|
||||
node.type = json.type;
|
||||
node.mask = json.mask;
|
||||
node.squash = methods.activation[json.squash];
|
||||
|
||||
return node;
|
||||
};
|
11
node_modules/neataptic/src/config.js
generated
vendored
Normal file
11
node_modules/neataptic/src/config.js
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
/*******************************************************************************
|
||||
CONFIG
|
||||
*******************************************************************************/
|
||||
|
||||
// Config
|
||||
var config = {
|
||||
warnings: false
|
||||
};
|
||||
|
||||
/* Export */
|
||||
module.exports = config;
|
77
node_modules/neataptic/src/methods/activation.js
generated
vendored
Normal file
77
node_modules/neataptic/src/methods/activation.js
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
/*******************************************************************************
|
||||
ACTIVATION FUNCTIONS
|
||||
*******************************************************************************/
|
||||
|
||||
// https://en.wikipedia.org/wiki/Activation_function
|
||||
// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons
|
||||
var activation = {
|
||||
LOGISTIC: function (x, derivate) {
|
||||
var fx = 1 / (1 + Math.exp(-x));
|
||||
if (!derivate) return fx;
|
||||
return fx * (1 - fx);
|
||||
},
|
||||
TANH: function (x, derivate) {
|
||||
if (derivate) return 1 - Math.pow(Math.tanh(x), 2);
|
||||
return Math.tanh(x);
|
||||
},
|
||||
IDENTITY: function (x, derivate) {
|
||||
return derivate ? 1 : x;
|
||||
},
|
||||
STEP: function (x, derivate) {
|
||||
return derivate ? 0 : x > 0 ? 1 : 0;
|
||||
},
|
||||
RELU: function (x, derivate) {
|
||||
if (derivate) return x > 0 ? 1 : 0;
|
||||
return x > 0 ? x : 0;
|
||||
},
|
||||
SOFTSIGN: function (x, derivate) {
|
||||
var d = 1 + Math.abs(x);
|
||||
if (derivate) return x / Math.pow(d, 2);
|
||||
return x / d;
|
||||
},
|
||||
SINUSOID: function (x, derivate) {
|
||||
if (derivate) return Math.cos(x);
|
||||
return Math.sin(x);
|
||||
},
|
||||
GAUSSIAN: function (x, derivate) {
|
||||
var d = Math.exp(-Math.pow(x, 2));
|
||||
if (derivate) return -2 * x * d;
|
||||
return d;
|
||||
},
|
||||
BENT_IDENTITY: function (x, derivate) {
|
||||
var d = Math.sqrt(Math.pow(x, 2) + 1);
|
||||
if (derivate) return x / (2 * d) + 1;
|
||||
return (d - 1) / 2 + x;
|
||||
},
|
||||
BIPOLAR: function (x, derivate) {
|
||||
return derivate ? 0 : x > 0 ? 1 : -1;
|
||||
},
|
||||
BIPOLAR_SIGMOID: function (x, derivate) {
|
||||
var d = 2 / (1 + Math.exp(-x)) - 1;
|
||||
if (derivate) return 1 / 2 * (1 + d) * (1 - d);
|
||||
return d;
|
||||
},
|
||||
HARD_TANH: function (x, derivate) {
|
||||
if (derivate) return x > -1 && x < 1 ? 1 : 0;
|
||||
return Math.max(-1, Math.min(1, x));
|
||||
},
|
||||
ABSOLUTE: function (x, derivate) {
|
||||
if (derivate) return x < 0 ? -1 : 1;
|
||||
return Math.abs(x);
|
||||
},
|
||||
INVERSE: function (x, derivate) {
|
||||
if (derivate) return -1;
|
||||
return 1 - x;
|
||||
},
|
||||
// https://arxiv.org/pdf/1706.02515.pdf
|
||||
SELU: function (x, derivate) {
|
||||
var alpha = 1.6732632423543772848170429916717;
|
||||
var scale = 1.0507009873554804934193349852946;
|
||||
var fx = x > 0 ? x : alpha * Math.exp(x) - alpha;
|
||||
if (derivate) { return x > 0 ? scale : (fx + alpha) * scale; }
|
||||
return fx * scale;
|
||||
}
|
||||
};
|
||||
|
||||
/* Export */
|
||||
module.exports = activation;
|
19
node_modules/neataptic/src/methods/connection.js
generated
vendored
Normal file
19
node_modules/neataptic/src/methods/connection.js
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
/*******************************************************************************
|
||||
CONNECTION
|
||||
*******************************************************************************/
|
||||
|
||||
// Specifies in what manner two groups are connected
|
||||
var connection = {
|
||||
ALL_TO_ALL: {
|
||||
name: 'OUTPUT'
|
||||
},
|
||||
ALL_TO_ELSE: {
|
||||
name: 'INPUT'
|
||||
},
|
||||
ONE_TO_ONE: {
|
||||
name: 'SELF'
|
||||
}
|
||||
};
|
||||
|
||||
/* Export */
|
||||
module.exports = connection;
|
73
node_modules/neataptic/src/methods/cost.js
generated
vendored
Normal file
73
node_modules/neataptic/src/methods/cost.js
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
/*******************************************************************************
|
||||
COST FUNCTIONS
|
||||
*******************************************************************************/
|
||||
|
||||
// https://en.wikipedia.org/wiki/Loss_function
|
||||
var cost = {
|
||||
// Cross entropy error
|
||||
CROSS_ENTROPY: function (target, output) {
|
||||
var error = 0;
|
||||
for (var i = 0; i < output.length; i++) {
|
||||
// Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A
|
||||
error -= target[i] * Math.log(Math.max(output[i], 1e-15)) + (1 - target[i]) * Math.log(1 - Math.max(output[i], 1e-15));
|
||||
}
|
||||
return error / output.length;
|
||||
},
|
||||
// Mean Squared Error
|
||||
MSE: function (target, output) {
|
||||
var error = 0;
|
||||
for (var i = 0; i < output.length; i++) {
|
||||
error += Math.pow(target[i] - output[i], 2);
|
||||
}
|
||||
|
||||
return error / output.length;
|
||||
},
|
||||
// Binary error
|
||||
BINARY: function (target, output) {
|
||||
var misses = 0;
|
||||
for (var i = 0; i < output.length; i++) {
|
||||
misses += Math.round(target[i] * 2) !== Math.round(output[i] * 2);
|
||||
}
|
||||
|
||||
return misses;
|
||||
},
|
||||
// Mean Absolute Error
|
||||
MAE: function (target, output) {
|
||||
var error = 0;
|
||||
for (var i = 0; i < output.length; i++) {
|
||||
error += Math.abs(target[i] - output[i]);
|
||||
}
|
||||
|
||||
return error / output.length;
|
||||
},
|
||||
// Mean Absolute Percentage Error
|
||||
MAPE: function (target, output) {
|
||||
var error = 0;
|
||||
for (var i = 0; i < output.length; i++) {
|
||||
error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15));
|
||||
}
|
||||
|
||||
return error / output.length;
|
||||
},
|
||||
// Mean Squared Logarithmic Error
|
||||
MSLE: function (target, output) {
|
||||
var error = 0;
|
||||
for (var i = 0; i < output.length; i++) {
|
||||
error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15));
|
||||
}
|
||||
|
||||
return error;
|
||||
},
|
||||
// Hinge loss, for classifiers
|
||||
HINGE: function (target, output) {
|
||||
var error = 0;
|
||||
for (var i = 0; i < output.length; i++) {
|
||||
error += Math.max(0, 1 - target[i] * output[i]);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
};
|
||||
|
||||
/* Export */
|
||||
module.exports = cost;
|
24
node_modules/neataptic/src/methods/crossover.js
generated
vendored
Normal file
24
node_modules/neataptic/src/methods/crossover.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
/*******************************************************************************
|
||||
CROSSOVER
|
||||
*******************************************************************************/
|
||||
|
||||
// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm)
|
||||
var crossover = {
|
||||
SINGLE_POINT: {
|
||||
name: 'SINGLE_POINT',
|
||||
config: [0.4]
|
||||
},
|
||||
TWO_POINT: {
|
||||
name: 'TWO_POINT',
|
||||
config: [0.4, 0.9]
|
||||
},
|
||||
UNIFORM: {
|
||||
name: 'UNIFORM'
|
||||
},
|
||||
AVERAGE: {
|
||||
name: 'AVERAGE'
|
||||
}
|
||||
};
|
||||
|
||||
/* Export */
|
||||
module.exports = crossover;
|
19
node_modules/neataptic/src/methods/gating.js
generated
vendored
Normal file
19
node_modules/neataptic/src/methods/gating.js
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
/*******************************************************************************
|
||||
GATING
|
||||
*******************************************************************************/
|
||||
|
||||
// Specifies how to gate a connection between two groups of multiple neurons
|
||||
var gating = {
|
||||
OUTPUT: {
|
||||
name: 'OUTPUT'
|
||||
},
|
||||
INPUT: {
|
||||
name: 'INPUT'
|
||||
},
|
||||
SELF: {
|
||||
name: 'SELF'
|
||||
}
|
||||
};
|
||||
|
||||
/* Export */
|
||||
module.exports = gating;
|
17
node_modules/neataptic/src/methods/methods.js
generated
vendored
Normal file
17
node_modules/neataptic/src/methods/methods.js
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
/*******************************************************************************
|
||||
METHODS
|
||||
*******************************************************************************/
|
||||
|
||||
var methods = {
|
||||
activation: require('./activation'),
|
||||
mutation: require('./mutation'),
|
||||
selection: require('./selection'),
|
||||
crossover: require('./crossover'),
|
||||
cost: require('./cost'),
|
||||
gating: require('./gating'),
|
||||
connection: require('./connection'),
|
||||
rate: require('./rate')
|
||||
};
|
||||
|
||||
/** Export */
|
||||
module.exports = methods;
|
107
node_modules/neataptic/src/methods/mutation.js
generated
vendored
Normal file
107
node_modules/neataptic/src/methods/mutation.js
generated
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
/* Import */
|
||||
var activation = require('./activation');
|
||||
|
||||
/*******************************************************************************
|
||||
MUTATION
|
||||
*******************************************************************************/
|
||||
|
||||
// https://en.wikipedia.org/wiki/mutation_(genetic_algorithm)
|
||||
var mutation = {
|
||||
ADD_NODE: {
|
||||
name: 'ADD_NODE'
|
||||
},
|
||||
SUB_NODE: {
|
||||
name: 'SUB_NODE',
|
||||
keep_gates: true
|
||||
},
|
||||
ADD_CONN: {
|
||||
name: 'ADD_CONN'
|
||||
},
|
||||
SUB_CONN: {
|
||||
name: 'REMOVE_CONN'
|
||||
},
|
||||
MOD_WEIGHT: {
|
||||
name: 'MOD_WEIGHT',
|
||||
min: -1,
|
||||
max: 1
|
||||
},
|
||||
MOD_BIAS: {
|
||||
name: 'MOD_BIAS',
|
||||
min: -1,
|
||||
max: 1
|
||||
},
|
||||
MOD_ACTIVATION: {
|
||||
name: 'MOD_ACTIVATION',
|
||||
mutateOutput: true,
|
||||
allowed: [
|
||||
activation.LOGISTIC,
|
||||
activation.TANH,
|
||||
activation.RELU,
|
||||
activation.IDENTITY,
|
||||
activation.STEP,
|
||||
activation.SOFTSIGN,
|
||||
activation.SINUSOID,
|
||||
activation.GAUSSIAN,
|
||||
activation.BENT_IDENTITY,
|
||||
activation.BIPOLAR,
|
||||
activation.BIPOLAR_SIGMOID,
|
||||
activation.HARD_TANH,
|
||||
activation.ABSOLUTE,
|
||||
activation.INVERSE,
|
||||
activation.SELU
|
||||
]
|
||||
},
|
||||
ADD_SELF_CONN: {
|
||||
name: 'ADD_SELF_CONN'
|
||||
},
|
||||
SUB_SELF_CONN: {
|
||||
name: 'SUB_SELF_CONN'
|
||||
},
|
||||
ADD_GATE: {
|
||||
name: 'ADD_GATE'
|
||||
},
|
||||
SUB_GATE: {
|
||||
name: 'SUB_GATE'
|
||||
},
|
||||
ADD_BACK_CONN: {
|
||||
name: 'ADD_BACK_CONN'
|
||||
},
|
||||
SUB_BACK_CONN: {
|
||||
name: 'SUB_BACK_CONN'
|
||||
},
|
||||
SWAP_NODES: {
|
||||
name: 'SWAP_NODES',
|
||||
mutateOutput: true
|
||||
}
|
||||
};
|
||||
|
||||
mutation.ALL = [
|
||||
mutation.ADD_NODE,
|
||||
mutation.SUB_NODE,
|
||||
mutation.ADD_CONN,
|
||||
mutation.SUB_CONN,
|
||||
mutation.MOD_WEIGHT,
|
||||
mutation.MOD_BIAS,
|
||||
mutation.MOD_ACTIVATION,
|
||||
mutation.ADD_GATE,
|
||||
mutation.SUB_GATE,
|
||||
mutation.ADD_SELF_CONN,
|
||||
mutation.SUB_SELF_CONN,
|
||||
mutation.ADD_BACK_CONN,
|
||||
mutation.SUB_BACK_CONN,
|
||||
mutation.SWAP_NODES
|
||||
];
|
||||
|
||||
mutation.FFW = [
|
||||
mutation.ADD_NODE,
|
||||
mutation.SUB_NODE,
|
||||
mutation.ADD_CONN,
|
||||
mutation.SUB_CONN,
|
||||
mutation.MOD_WEIGHT,
|
||||
mutation.MOD_BIAS,
|
||||
mutation.MOD_ACTIVATION,
|
||||
mutation.SWAP_NODES
|
||||
];
|
||||
|
||||
/* Export */
|
||||
module.exports = mutation;
|
43
node_modules/neataptic/src/methods/rate.js
generated
vendored
Normal file
43
node_modules/neataptic/src/methods/rate.js
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
/*******************************************************************************
|
||||
RATE
|
||||
*******************************************************************************/
|
||||
|
||||
// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244
|
||||
var rate = {
|
||||
FIXED: function () {
|
||||
var func = function (baseRate, iteration) { return baseRate; };
|
||||
return func;
|
||||
},
|
||||
STEP: function (gamma, stepSize) {
|
||||
gamma = gamma || 0.9;
|
||||
stepSize = stepSize || 100;
|
||||
|
||||
var func = function (baseRate, iteration) {
|
||||
return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize));
|
||||
};
|
||||
|
||||
return func;
|
||||
},
|
||||
EXP: function (gamma) {
|
||||
gamma = gamma || 0.999;
|
||||
|
||||
var func = function (baseRate, iteration) {
|
||||
return baseRate * Math.pow(gamma, iteration);
|
||||
};
|
||||
|
||||
return func;
|
||||
},
|
||||
INV: function (gamma, power) {
|
||||
gamma = gamma || 0.001;
|
||||
power = power || 2;
|
||||
|
||||
var func = function (baseRate, iteration) {
|
||||
return baseRate * Math.pow(1 + gamma * iteration, -power);
|
||||
};
|
||||
|
||||
return func;
|
||||
}
|
||||
};
|
||||
|
||||
/* Export */
|
||||
module.exports = rate;
|
23
node_modules/neataptic/src/methods/selection.js
generated
vendored
Normal file
23
node_modules/neataptic/src/methods/selection.js
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
/*******************************************************************************
|
||||
SELECTION
|
||||
*******************************************************************************/
|
||||
|
||||
// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm)
|
||||
|
||||
var selection = {
|
||||
FITNESS_PROPORTIONATE: {
|
||||
name: 'FITNESS_PROPORTIONATE'
|
||||
},
|
||||
POWER: {
|
||||
name: 'POWER',
|
||||
power: 4
|
||||
},
|
||||
TOURNAMENT: {
|
||||
name: 'TOURNAMENT',
|
||||
size: 5,
|
||||
probability: 0.5
|
||||
}
|
||||
};
|
||||
|
||||
/* Export */
|
||||
module.exports = selection;
|
107
node_modules/neataptic/src/multithreading/multi.js
generated
vendored
Normal file
107
node_modules/neataptic/src/multithreading/multi.js
generated
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
/*******************************************************************************
|
||||
MULTITHREADING
|
||||
*******************************************************************************/
|
||||
|
||||
var multi = {
|
||||
/** Workers */
|
||||
workers: require('./workers/workers'),
|
||||
|
||||
/** Serializes a dataset */
|
||||
serializeDataSet: function (dataSet) {
|
||||
var serialized = [dataSet[0].input.length, dataSet[0].output.length];
|
||||
|
||||
for (var i = 0; i < dataSet.length; i++) {
|
||||
var j;
|
||||
for (j = 0; j < serialized[0]; j++) {
|
||||
serialized.push(dataSet[i].input[j]);
|
||||
}
|
||||
for (j = 0; j < serialized[1]; j++) {
|
||||
serialized.push(dataSet[i].output[j]);
|
||||
}
|
||||
}
|
||||
|
||||
return serialized;
|
||||
},
|
||||
|
||||
/** Activate a serialized network */
|
||||
activateSerializedNetwork: function (input, A, S, data, F) {
|
||||
for (var i = 0; i < data[0]; i++) A[i] = input[i];
|
||||
for (i = 2; i < data.length; i++) {
|
||||
let index = data[i++];
|
||||
let bias = data[i++];
|
||||
let squash = data[i++];
|
||||
let selfweight = data[i++];
|
||||
let selfgater = data[i++];
|
||||
|
||||
S[index] = (selfgater === -1 ? 1 : A[selfgater]) * selfweight * S[index] + bias;
|
||||
|
||||
while (data[i] !== -2) {
|
||||
S[index] += A[data[i++]] * data[i++] * (data[i++] === -1 ? 1 : A[data[i - 1]]);
|
||||
}
|
||||
A[index] = F[squash](S[index]);
|
||||
}
|
||||
|
||||
var output = [];
|
||||
for (i = A.length - data[1]; i < A.length; i++) output.push(A[i]);
|
||||
return output;
|
||||
},
|
||||
|
||||
/** Deserializes a dataset to an array of arrays */
|
||||
deserializeDataSet: function (serializedSet) {
|
||||
var set = [];
|
||||
|
||||
var sampleSize = serializedSet[0] + serializedSet[1];
|
||||
for (var i = 0; i < (serializedSet.length - 2) / sampleSize; i++) {
|
||||
let input = [];
|
||||
for (var j = 2 + i * sampleSize; j < 2 + i * sampleSize + serializedSet[0]; j++) {
|
||||
input.push(serializedSet[j]);
|
||||
}
|
||||
let output = [];
|
||||
for (j = 2 + i * sampleSize + serializedSet[0]; j < 2 + i * sampleSize + sampleSize; j++) {
|
||||
output.push(serializedSet[j]);
|
||||
}
|
||||
set.push(input);
|
||||
set.push(output);
|
||||
}
|
||||
|
||||
return set;
|
||||
},
|
||||
|
||||
/** A list of compiled activation functions in a certain order */
|
||||
activations: [
|
||||
function (x) { return 1 / (1 + Math.exp(-x)); },
|
||||
function (x) { return Math.tanh(x); },
|
||||
function (x) { return x; },
|
||||
function (x) { return x > 0 ? 1 : 0; },
|
||||
function (x) { return x > 0 ? x : 0; },
|
||||
function (x) { return x / (1 + Math.abs(x)); },
|
||||
function (x) { return Math.sin(x); },
|
||||
function (x) { return Math.exp(-Math.pow(x, 2)); },
|
||||
function (x) { return (Math.sqrt(Math.pow(x, 2) + 1) - 1) / 2 + x; },
|
||||
function (x) { return x > 0 ? 1 : -1; },
|
||||
function (x) { return 2 / (1 + Math.exp(-x)) - 1; },
|
||||
function (x) { return Math.max(-1, Math.min(1, x)); },
|
||||
function (x) { return Math.abs(x); },
|
||||
function (x) { return 1 - x; },
|
||||
function (x) {
|
||||
var a = 1.6732632423543772848170429916717;
|
||||
return (x > 0 ? x : a * Math.exp(x) - a) * 1.0507009873554804934193349852946;
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
multi.testSerializedSet = function (set, cost, A, S, data, F) {
|
||||
// Calculate how much samples are in the set
|
||||
var error = 0;
|
||||
for (var i = 0; i < set.length; i += 2) {
|
||||
let output = multi.activateSerializedNetwork(set[i], A, S, data, F);
|
||||
error += cost(set[i + 1], output);
|
||||
}
|
||||
|
||||
return error / (set.length / 2);
|
||||
};
|
||||
|
||||
/* Export */
|
||||
for (var i in multi) {
|
||||
module.exports[i] = multi[i];
|
||||
}
|
72
node_modules/neataptic/src/multithreading/workers/browser/testworker.js
generated
vendored
Normal file
72
node_modules/neataptic/src/multithreading/workers/browser/testworker.js
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
/* Export */
|
||||
module.exports = TestWorker;
|
||||
|
||||
/* Import */
|
||||
var multi = require('../../multi');
|
||||
|
||||
/*******************************************************************************
|
||||
WEBWORKER
|
||||
*******************************************************************************/
|
||||
|
||||
function TestWorker (dataSet, cost) {
|
||||
var blob = new Blob([this._createBlobString(cost)]);
|
||||
this.url = window.URL.createObjectURL(blob);
|
||||
this.worker = new Worker(this.url);
|
||||
|
||||
var data = { set: new Float64Array(dataSet).buffer };
|
||||
this.worker.postMessage(data, [data.set]);
|
||||
}
|
||||
|
||||
TestWorker.prototype = {
|
||||
evaluate: function (network) {
|
||||
return new Promise((resolve, reject) => {
|
||||
var serialized = network.serialize();
|
||||
|
||||
var data = {
|
||||
activations: new Float64Array(serialized[0]).buffer,
|
||||
states: new Float64Array(serialized[1]).buffer,
|
||||
conns: new Float64Array(serialized[2]).buffer
|
||||
};
|
||||
|
||||
this.worker.onmessage = function (e) {
|
||||
var error = new Float64Array(e.data.buffer)[0];
|
||||
resolve(error);
|
||||
};
|
||||
|
||||
this.worker.postMessage(data, [data.activations, data.states, data.conns]);
|
||||
});
|
||||
},
|
||||
|
||||
terminate: function () {
|
||||
this.worker.terminate();
|
||||
window.URL.revokeObjectURL(this.url);
|
||||
},
|
||||
|
||||
_createBlobString: function (cost) {
|
||||
var source = `
|
||||
var F = [${multi.activations.toString()}];
|
||||
var cost = ${cost.toString()};
|
||||
var multi = {
|
||||
deserializeDataSet: ${multi.deserializeDataSet.toString()},
|
||||
testSerializedSet: ${multi.testSerializedSet.toString()},
|
||||
activateSerializedNetwork: ${multi.activateSerializedNetwork.toString()}
|
||||
};
|
||||
|
||||
this.onmessage = function (e) {
|
||||
if(typeof e.data.set === 'undefined'){
|
||||
var A = new Float64Array(e.data.activations);
|
||||
var S = new Float64Array(e.data.states);
|
||||
var data = new Float64Array(e.data.conns);
|
||||
|
||||
var error = multi.testSerializedSet(set, cost, A, S, data, F);
|
||||
|
||||
var answer = { buffer: new Float64Array([error ]).buffer };
|
||||
postMessage(answer, [answer.buffer]);
|
||||
} else {
|
||||
set = multi.deserializeDataSet(new Float64Array(e.data.set));
|
||||
}
|
||||
};`;
|
||||
|
||||
return source;
|
||||
}
|
||||
};
|
42
node_modules/neataptic/src/multithreading/workers/node/testworker.js
generated
vendored
Normal file
42
node_modules/neataptic/src/multithreading/workers/node/testworker.js
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
/* Export */
|
||||
module.exports = TestWorker;
|
||||
|
||||
/* Import */
|
||||
var cp = require('child_process');
|
||||
var path = require('path');
|
||||
|
||||
/*******************************************************************************
|
||||
WEBWORKER
|
||||
*******************************************************************************/
|
||||
|
||||
function TestWorker (dataSet, cost) {
|
||||
this.worker = cp.fork(path.join(__dirname, '/worker'));
|
||||
|
||||
this.worker.send({ set: dataSet, cost: cost.name });
|
||||
}
|
||||
|
||||
TestWorker.prototype = {
|
||||
evaluate: function (network) {
|
||||
return new Promise((resolve, reject) => {
|
||||
var serialized = network.serialize();
|
||||
|
||||
var data = {
|
||||
activations: serialized[0],
|
||||
states: serialized[1],
|
||||
conns: serialized[2]
|
||||
};
|
||||
|
||||
var _that = this.worker;
|
||||
this.worker.on('message', function callback (e) {
|
||||
_that.removeListener('message', callback);
|
||||
resolve(e);
|
||||
});
|
||||
|
||||
this.worker.send(data);
|
||||
});
|
||||
},
|
||||
|
||||
terminate: function () {
|
||||
this.worker.kill();
|
||||
}
|
||||
};
|
20
node_modules/neataptic/src/multithreading/workers/node/worker.js
generated
vendored
Normal file
20
node_modules/neataptic/src/multithreading/workers/node/worker.js
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
var { multi, methods } = require('../../../neataptic');
|
||||
|
||||
var set = [];
|
||||
var cost;
|
||||
var F = multi.activations;
|
||||
|
||||
process.on('message', function (e) {
|
||||
if (typeof e.set === 'undefined') {
|
||||
var A = e.activations;
|
||||
var S = e.states;
|
||||
var data = e.conns;
|
||||
|
||||
var result = multi.testSerializedSet(set, cost, A, S, data, F);
|
||||
|
||||
process.send(result);
|
||||
} else {
|
||||
cost = methods.cost[e.cost];
|
||||
set = multi.deserializeDataSet(e.set);
|
||||
}
|
||||
});
|
15
node_modules/neataptic/src/multithreading/workers/workers.js
generated
vendored
Normal file
15
node_modules/neataptic/src/multithreading/workers/workers.js
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
/*******************************************************************************
|
||||
WORKERS
|
||||
*******************************************************************************/
|
||||
|
||||
var workers = {
|
||||
node: {
|
||||
TestWorker: require('./node/testworker')
|
||||
},
|
||||
browser: {
|
||||
TestWorker: require('./browser/testworker')
|
||||
}
|
||||
};
|
||||
|
||||
/** Export */
|
||||
module.exports = workers;
|
324
node_modules/neataptic/src/neat.js
generated
vendored
Normal file
324
node_modules/neataptic/src/neat.js
generated
vendored
Normal file
@@ -0,0 +1,324 @@
|
||||
/* Export */
|
||||
module.exports = Neat;
|
||||
|
||||
/* Import */
|
||||
var Network = require('./architecture/network');
|
||||
var methods = require('./methods/methods');
|
||||
var config = require('./config');
|
||||
|
||||
/* Easier variable naming */
|
||||
var selection = methods.selection;
|
||||
|
||||
/*******************************************************************************
|
||||
NEAT
|
||||
*******************************************************************************/
|
||||
|
||||
function Neat (input, output, fitness, options) {
|
||||
this.input = input; // The input size of the networks
|
||||
this.output = output; // The output size of the networks
|
||||
this.fitness = fitness; // The fitness function to evaluate the networks
|
||||
|
||||
// Configure options
|
||||
options = options || {};
|
||||
this.equal = options.equal || false;
|
||||
this.clear = options.clear || false;
|
||||
this.popsize = options.popsize || 50;
|
||||
this.elitism = options.elitism || 0;
|
||||
this.provenance = options.provenance || 0;
|
||||
this.mutationRate = options.mutationRate || 0.3;
|
||||
this.mutationAmount = options.mutationAmount || 1;
|
||||
|
||||
this.fitnessPopulation = options.fitnessPopulation || false;
|
||||
|
||||
this.selection = options.selection || methods.selection.POWER;
|
||||
this.crossover = options.crossover || [
|
||||
methods.crossover.SINGLE_POINT,
|
||||
methods.crossover.TWO_POINT,
|
||||
methods.crossover.UNIFORM,
|
||||
methods.crossover.AVERAGE
|
||||
];
|
||||
this.mutation = options.mutation || methods.mutation.FFW;
|
||||
|
||||
this.template = options.network || false;
|
||||
|
||||
this.maxNodes = options.maxNodes || Infinity;
|
||||
this.maxConns = options.maxConns || Infinity;
|
||||
this.maxGates = options.maxGates || Infinity;
|
||||
|
||||
// Custom mutation selection function if given
|
||||
this.selectMutationMethod = typeof options.mutationSelection === 'function' ? options.mutationSelection.bind(this) : this.selectMutationMethod;
|
||||
|
||||
// Generation counter
|
||||
this.generation = 0;
|
||||
|
||||
// Initialise the genomes
|
||||
this.createPool(this.template);
|
||||
}
|
||||
|
||||
Neat.prototype = {
|
||||
/**
|
||||
* Create the initial pool of genomes
|
||||
*/
|
||||
createPool: function (network) {
|
||||
this.population = [];
|
||||
|
||||
for (var i = 0; i < this.popsize; i++) {
|
||||
var copy;
|
||||
if (this.template) {
|
||||
copy = Network.fromJSON(network.toJSON());
|
||||
} else {
|
||||
copy = new Network(this.input, this.output);
|
||||
}
|
||||
copy.score = undefined;
|
||||
this.population.push(copy);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Evaluates, selects, breeds and mutates population
|
||||
*/
|
||||
evolve: async function () {
|
||||
// Check if evaluated, sort the population
|
||||
if (typeof this.population[this.population.length - 1].score === 'undefined') {
|
||||
await this.evaluate();
|
||||
}
|
||||
this.sort();
|
||||
|
||||
var fittest = Network.fromJSON(this.population[0].toJSON());
|
||||
fittest.score = this.population[0].score;
|
||||
|
||||
var newPopulation = [];
|
||||
|
||||
// Elitism
|
||||
var elitists = [];
|
||||
for (var i = 0; i < this.elitism; i++) {
|
||||
elitists.push(this.population[i]);
|
||||
}
|
||||
|
||||
// Provenance
|
||||
for (i = 0; i < this.provenance; i++) {
|
||||
newPopulation.push(Network.fromJSON(this.template.toJSON()));
|
||||
}
|
||||
|
||||
// Breed the next individuals
|
||||
for (i = 0; i < this.popsize - this.elitism - this.provenance; i++) {
|
||||
newPopulation.push(this.getOffspring());
|
||||
}
|
||||
|
||||
// Replace the old population with the new population
|
||||
this.population = newPopulation;
|
||||
this.mutate();
|
||||
|
||||
this.population.push(...elitists);
|
||||
|
||||
// Reset the scores
|
||||
for (i = 0; i < this.population.length; i++) {
|
||||
this.population[i].score = undefined;
|
||||
}
|
||||
|
||||
this.generation++;
|
||||
|
||||
return fittest;
|
||||
},
|
||||
|
||||
/**
|
||||
* Breeds two parents into an offspring, population MUST be surted
|
||||
*/
|
||||
getOffspring: function () {
|
||||
var parent1 = this.getParent();
|
||||
var parent2 = this.getParent();
|
||||
|
||||
return Network.crossOver(parent1, parent2, this.equal);
|
||||
},
|
||||
|
||||
/**
|
||||
* Selects a random mutation method for a genome according to the parameters
|
||||
*/
|
||||
selectMutationMethod: function (genome) {
|
||||
var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)];
|
||||
|
||||
if (mutationMethod === methods.mutation.ADD_NODE && genome.nodes.length >= this.maxNodes) {
|
||||
if (config.warnings) console.warn('maxNodes exceeded!');
|
||||
return;
|
||||
}
|
||||
|
||||
if (mutationMethod === methods.mutation.ADD_CONN && genome.connections.length >= this.maxConns) {
|
||||
if (config.warnings) console.warn('maxConns exceeded!');
|
||||
return;
|
||||
}
|
||||
|
||||
if (mutationMethod === methods.mutation.ADD_GATE && genome.gates.length >= this.maxGates) {
|
||||
if (config.warnings) console.warn('maxGates exceeded!');
|
||||
return;
|
||||
}
|
||||
|
||||
return mutationMethod;
|
||||
},
|
||||
|
||||
/**
|
||||
* Mutates the given (or current) population
|
||||
*/
|
||||
mutate: function () {
|
||||
// Elitist genomes should not be included
|
||||
for (var i = 0; i < this.population.length; i++) {
|
||||
if (Math.random() <= this.mutationRate) {
|
||||
for (var j = 0; j < this.mutationAmount; j++) {
|
||||
var mutationMethod = this.selectMutationMethod(this.population[i]);
|
||||
this.population[i].mutate(mutationMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Evaluates the current population
|
||||
*/
|
||||
evaluate: async function () {
|
||||
var i;
|
||||
if (this.fitnessPopulation) {
|
||||
if (this.clear) {
|
||||
for (i = 0; i < this.population.length; i++) {
|
||||
this.population[i].clear();
|
||||
}
|
||||
}
|
||||
await this.fitness(this.population);
|
||||
} else {
|
||||
for (i = 0; i < this.population.length; i++) {
|
||||
var genome = this.population[i];
|
||||
if (this.clear) genome.clear();
|
||||
genome.score = await this.fitness(genome);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sorts the population by score
|
||||
*/
|
||||
sort: function () {
|
||||
this.population.sort(function (a, b) {
|
||||
return b.score - a.score;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the fittest genome of the current population
|
||||
*/
|
||||
getFittest: function () {
|
||||
// Check if evaluated
|
||||
if (typeof this.population[this.population.length - 1].score === 'undefined') {
|
||||
this.evaluate();
|
||||
}
|
||||
if (this.population[0].score < this.population[1].score) {
|
||||
this.sort();
|
||||
}
|
||||
|
||||
return this.population[0];
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the average fitness of the current population
|
||||
*/
|
||||
getAverage: function () {
|
||||
if (typeof this.population[this.population.length - 1].score === 'undefined') {
|
||||
this.evaluate();
|
||||
}
|
||||
|
||||
var score = 0;
|
||||
for (var i = 0; i < this.population.length; i++) {
|
||||
score += this.population[i].score;
|
||||
}
|
||||
|
||||
return score / this.population.length;
|
||||
},
|
||||
|
||||
/**
|
||||
* Gets a genome based on the selection function
|
||||
* @return {Network} genome
|
||||
*/
|
||||
getParent: function () {
|
||||
var i;
|
||||
switch (this.selection) {
|
||||
case selection.POWER:
|
||||
if (this.population[0].score < this.population[1].score) this.sort();
|
||||
|
||||
var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length);
|
||||
return this.population[index];
|
||||
case selection.FITNESS_PROPORTIONATE:
|
||||
// As negative fitnesses are possible
|
||||
// https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values
|
||||
// this is unnecessarily run for every individual, should be changed
|
||||
|
||||
var totalFitness = 0;
|
||||
var minimalFitness = 0;
|
||||
for (i = 0; i < this.population.length; i++) {
|
||||
var score = this.population[i].score;
|
||||
minimalFitness = score < minimalFitness ? score : minimalFitness;
|
||||
totalFitness += score;
|
||||
}
|
||||
|
||||
minimalFitness = Math.abs(minimalFitness);
|
||||
totalFitness += minimalFitness * this.population.length;
|
||||
|
||||
var random = Math.random() * totalFitness;
|
||||
var value = 0;
|
||||
|
||||
for (i = 0; i < this.population.length; i++) {
|
||||
let genome = this.population[i];
|
||||
value += genome.score + minimalFitness;
|
||||
if (random < value) return genome;
|
||||
}
|
||||
|
||||
// if all scores equal, return random genome
|
||||
return this.population[Math.floor(Math.random() * this.population.length)];
|
||||
case selection.TOURNAMENT:
|
||||
if (this.selection.size > this.popsize) {
|
||||
throw new Error('Your tournament size should be lower than the population size, please change methods.selection.TOURNAMENT.size');
|
||||
}
|
||||
|
||||
// Create a tournament
|
||||
var individuals = [];
|
||||
for (i = 0; i < this.selection.size; i++) {
|
||||
let random = this.population[Math.floor(Math.random() * this.population.length)];
|
||||
individuals.push(random);
|
||||
}
|
||||
|
||||
// Sort the tournament individuals by score
|
||||
individuals.sort(function (a, b) {
|
||||
return b.score - a.score;
|
||||
});
|
||||
|
||||
// Select an individual
|
||||
for (i = 0; i < this.selection.size; i++) {
|
||||
if (Math.random() < this.selection.probability || i === this.selection.size - 1) {
|
||||
return individuals[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Export the current population to a json object
|
||||
*/
|
||||
export: function () {
|
||||
var json = [];
|
||||
for (var i = 0; i < this.population.length; i++) {
|
||||
var genome = this.population[i];
|
||||
json.push(genome.toJSON());
|
||||
}
|
||||
|
||||
return json;
|
||||
},
|
||||
|
||||
/**
|
||||
* Import population from a json object
|
||||
*/
|
||||
import: function (json) {
|
||||
var population = [];
|
||||
for (var i = 0; i < json.length; i++) {
|
||||
var genome = json[i];
|
||||
population.push(Network.fromJSON(genome));
|
||||
}
|
||||
this.population = population;
|
||||
this.popsize = population.length;
|
||||
}
|
||||
};
|
35
node_modules/neataptic/src/neataptic.js
generated
vendored
Normal file
35
node_modules/neataptic/src/neataptic.js
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
var Neataptic = {
|
||||
methods: require('./methods/methods'),
|
||||
Connection: require('./architecture/connection'),
|
||||
architect: require('./architecture/architect'),
|
||||
Network: require('./architecture/network'),
|
||||
config: require('./config'),
|
||||
Group: require('./architecture/group'),
|
||||
Layer: require('./architecture/layer'),
|
||||
Node: require('./architecture/node'),
|
||||
Neat: require('./neat'),
|
||||
multi: require('./multithreading/multi')
|
||||
};
|
||||
|
||||
// CommonJS & AMD
|
||||
if (typeof define !== 'undefined' && define.amd) {
|
||||
define([], function () { return Neataptic; });
|
||||
}
|
||||
|
||||
// Node.js
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = Neataptic;
|
||||
}
|
||||
|
||||
// Browser
|
||||
if (typeof window === 'object') {
|
||||
(function () {
|
||||
var old = window['neataptic'];
|
||||
Neataptic.ninja = function () {
|
||||
window['neataptic'] = old;
|
||||
return Neataptic;
|
||||
};
|
||||
})();
|
||||
|
||||
window['neataptic'] = Neataptic;
|
||||
}
|
Reference in New Issue
Block a user