UNPKG

pi-emergence

Version:
237 lines (188 loc) 7.8 kB
import ActivationFunction from "../components/activation-function.js"; import App from "../../common/app.js"; import MatrixNeuroApp from "./app.matrix-neuro.js"; import NeuronLayer from "../components/neuron-layer.js"; import Neuron from "../components/neuron.js"; import NeuronRunner from "../components/neuron-runner.js"; import NeuronConnector from "../components/neuron-connector.js"; import FeedForwardNueralNetwork from "../networks/feed-forward.js"; /** * @fileoverview Neuro App * @version 1.0.0 * @license MIT - Just give me some street cred * * @description * This class is analogous to the Controller. It handles input (data and events) and passes data to * the underlying network (this.network) and view. It also handles the logic of the app. */ class NeuroApp extends App { static retry = 0; static init(NeuronDrawer) { if (!!NeuronDrawer) { if (typeof NeuronDrawer.drawNeuron !== "function") throw new Error("NeuronApp.init: NeuronDrawer.drawNeuron is not a function."); Neuron.defaultDrawer.draw = NeuronDrawer.drawNeuron; if (typeof NeuronDrawer.drawNeuronConnector !== "function") console.warn("NeuronApp.init: NeuronDrawer.drawNeuronConnector is not a function. Neuron connectors will not be displayed."); else NeuronConnector.defaultDrawer.draw = NeuronDrawer.drawNeuronConnector; if (typeof NeuronDrawer.drawNeuronRunner !== "function") console.warn("NeuronApp.init: NeuronDrawer.drawNeuronRunner is not a function. Neuron runners will not be displayed."); else NeuronRunner.defaultDrawer.draw = NeuronDrawer.drawNeuronRunner; return true; } console.warn("No drawer initialized."); return false; } constructor(options, ...args) { super(options, args); if (!options) options = { name: "Unnamed" }; this.name = options?.name || "Neuro App"; const sig = new ActivationFunction(ActivationFunction.sigmoid, ActivationFunction.sigmoidPrime, "Sigmoid");; this.network = new FeedForwardNueralNetwork(this, { squashFunction: sig }); this.text = "Feed-Forward Neural Network"; this.isAuto = false; this.isSetup = false; this.selectedNeurons = []; this.selectedKeys = {}; this.messages = []; this.results = []; this.vectorHandler = options.vectorHandler; if (typeof document === "undefined") return; if (!document.getElementById(this.elementId)) { NeuroApp.retry++; if (NeuroApp.retry > 1) console.error("No canvas found with id: " + this.elementId + ". Aborting setup."); return; } this.updateCanvasSize(); this.getInputValues = (sender) => { console.warn("No input values provided because the getInputValues() method was not set. Returning empty array."); return []; } } initWithLayerNeuronCounts(...layerNeuronCounts) { const nn = new MatrixNeuroApp(layerNeuronCounts); this.network.initWithMatrixNetwork(nn, { vectorHandler: this.vectorHandler }); return this; } animateRunners(count = 5) { const inputLayer = this.network.inputLayer; for (let i = 0; i < count; i++) { const index = Math.floor(Math.random() * inputLayer.neurons.length); const n = inputLayer.neurons[index]; this.network.createRunner(n, null, 15); } setTimeout(() => { const newCount = Math.floor(Math.random() * 5) + 1; this.animateRunners(count); }, 750); } handleMouseMove(e) { const x = e.offsetX; const y = e.offsetY; const n = this.getNeuronAt(x, y); if (!!n) { const count = Math.floor(Math.random() * 8) + 2; for (let i = 0; i < count; i++) { const timing = Math.floor(Math.random() * 1500); setTimeout(() => { this.network.createRunner(n, null, 15); }, timing); } } } init(...args) { let layers = []; if (!!args[0] && args[0] instanceof MatrixNeuroApp) { const nn = args[0]; this.network.initWithMatrixNetwork(nn); } // If no layers were added, add default layers if (this.network.layers.length <= 1) { console.log("Setting up default layered network"); layers = [ new NeuronLayer(this.network, { name: "Input Layer", neuronCount: 3, biasCount: 1 }), new NeuronLayer(this.network, { name: "Hidden Layer 1", neuronCount: 5, biasCount: 1 }), new NeuronLayer(this.network, { name: "Hidden Layer 2", neuronCount: 7, biasCount: 1 }), new NeuronLayer(this.network, { name: "Hidden Layer 3", neuronCount: 5, biasCount: 1 }), new NeuronLayer(this.network, { name: "Output Layer", neuronCount: 1 }), ]; this.network.appendLayers(layers); this.network.connect(); } this.isSetup = true; // If the first arg is a function, use it as the getInputValues() method which is the mechanism for feeding input into the network if (args.length > 0 && typeof args[0] === "function") this.getInputValues = (sender) => args[0]; console.log("Neuro App setup: " + this.network.layerCount + " layers, " + this.network.neuronCount + " neurons"); } /** * Gets all the neurons in the network and returns them in a single array */ getAllNeurons() { const neurons = []; this.network.layers.map((layer) => { layer.neurons.map(n => neurons.push(n)); }); return neurons; } randomizeWeights() { this.network.randomizeWeights(); } layerCount() { return this.network.layerCount; } getNeuronAt(x, y) { let i = 0; const network = this.network; if (!network) return; const layerCount = network.layerCount; while (i < layerCount) { const neuron = network.layers[i].neurons.find(n => n.isAt(x, y)); if (neuron) return neuron; i++; } } clearSelectedNeurons() { this.selectedNeurons = []; this.network.layers.map((layer) => { layer.neurons.map(n => n.isSelected = false); }); } draw() { const network = this.network; if (!network) return; this.network.updatePositions(); super.refreshCanvas(); this.network.draw(); } static trainAndTestXor(matrixNet, epocs = 1000, testCount = 1, learningRate = 0.1) { // Setup let training_data = [ { inputs: [0, 0], outputs: [0] }, { inputs: [0, 1], outputs: [1] }, { inputs: [1, 0], outputs: [1] }, { inputs: [1, 1], outputs: [0] } ]; matrixNet.setLearningRate(learningRate); for (let tc = 0; tc < testCount; tc++) { // Train for (let i = 0; i < epocs; i++) { const randomIndex = Math.floor(Math.random() * training_data.length); const data = training_data[randomIndex]; matrixNet.train(data.inputs, data.outputs); } } return matrixNet; } } if (typeof module !== "undefined") module.exports = NeuroApp; else console.log("NeuroApp not exported. Running in browser.");