Browse Source

Bugfix: Fix client-side Brain.js crashes

master
Starbeamrainbowlabs 2 years ago
parent
commit
dea7940b2e
  1. 12
      build
  2. 6
      client_src/js/LayerAI.mjs
  3. 1
      client_src/js/Worker/AI.worker.mjs
  4. 33
      client_src/js/Worker/AIWrapper.mjs
  5. 43
      package-lock.json
  6. 1
      package.json
  7. 12
      rollup.main.config.js
  8. 14
      rollup.plugins.config.js
  9. 12
      rollup.worker.config.js
  10. 28
      server/train-ai/AITrainer.mjs

12
build

@ -139,7 +139,8 @@ task_server-ttn() {
# ██████ ███████ ██ ███████ ██ ████ ██
task_client() {
task_begin "Packaging Javascript";
execute node_modules/rollup/bin/rollup --sourcemap --config rollup.config.js;
execute node_modules/rollup/bin/rollup --sourcemap --config rollup.main.config.js;
execute node_modules/rollup/bin/rollup --sourcemap --config rollup.worker.config.js;
task_end $? "Error: rollup packing failed!";
task_begin "Copying html";
@ -150,17 +151,22 @@ task_client() {
task_client-watch() {
set_title "Client Watcher";
execute node_modules/rollup/bin/rollup --watch --sourcemap --config rollup.config.js &
# execute node_modules/rollup/bin/rollup --watch --sourcemap --config rollup.config.js &
echo -e "Watching for changes.";
while :; do # : = infinite loop
# Wait for an update
# inotifywait's non-0 exit code forces an exit for some reason :-/
inotifywait -qr --event modify --format '%:e %f' client_src rollup.config.js;
inotifywait -qr --event modify --format '%:e %f' client_src rollup.*.config.js;
task_begin "Copying html";
execute cp client_src/index.html "app/";
task_end $?;
stage_begin "Rebuilding client code";
set +e; tasks_run client; set -e;
stage_end $?;
done
}

6
client_src/js/LayerAI.mjs

@ -1,5 +1,7 @@
"use strict";
import path from 'path';
import L from 'leaflet';
import chroma from 'chroma-js';
@ -65,6 +67,10 @@ class LayerAI {
);
console.log(this.index);
for(let gateway of this.index.index) {
gateway.frozen_net = JSON.parse(await GetFromUrl(`${window.location.href}/${path.dirname(Config.ai_index_file)}/${gateway.filename}`))
}
// Figure out the bounds of the map we're going to generate
this.map_bounds = this.gateway_bounds;
this.map_bounds.north += Config.border.lat;

1
client_src/js/Worker/AI.worker.mjs

@ -32,5 +32,6 @@ async function handle_message(event) {
self.addEventListener("message", (event) => {
handle_message(event).catch((error) => {
console.error(error);
throw error;
});
});

33
client_src/js/Worker/AIWrapper.mjs

@ -1,6 +1,5 @@
"use strict";
import path from 'path';
import brain from 'brain.js';
import haversine from 'haversine-distance';
@ -13,7 +12,6 @@ import {
unnormalise_rssi
} from '../../../common/Normalisers.mjs';
import GetFromUrl from '../Helpers/GetFromUrl.mjs';
class AIWrapper {
constructor() {
@ -36,15 +34,14 @@ class AIWrapper {
// WebGL isn't available inside WebWorkers yet :-(
for(let gateway of this.index.index) {
let net = new brain.NeuralNetwork();
let net = new brain.NeuralNetwork(/*gateway.net_settings*/);
net.fromJSON(
// TODO: Move this to the UI thread & do it only once?
await GetFromUrl(`${path.dirname(self.location.href)}/${path.dirname(this.Config.ai_index_file)}/${gateway.filename}`)
gateway.frozen_net
);
this.gateways.set(
gateway.id,
net
{ ai: net, latitude: gateway.latitude, longitude: gateway.longitude }
);
}
console.log("Model setup complete.");
@ -64,21 +61,27 @@ class AIWrapper {
for(let lng = this.map_bounds.west; lng < this.map_bounds.east; lng += this.Config.step.lng) {
let max_predicted_rssi = -Infinity;
for(let [gateway_id, ai] of this.gateways) {
for(let [gateway_id, gateway] of this.gateways) {
let distance_from_gateway = haversine(
{ latitude: lat, longitude: lng },
this.gateways.get(gateway_id)
gateway
);
let next_value = gateway.ai.run({
latitude: normalise_lat(lat),
longitude: normalise_lng(lng),
distance: normalise_gateway_distance(
distance_from_gateway
),
});
if(isNaN(next_value[0])) {
console.log(next_value);
throw new Error("Error: Neural Network returned NaN");
}
// console.log(next_value);
max_predicted_rssi = Math.max(
max_predicted_rssi,
ai.run({
latitude: normalise_lat(lat),
longitude: normalise_lng(lng),
distance: normalise_gateway_distance(
distance_from_gateway
),
})[0]
next_value[0]
);
}

43
package-lock.json

@ -3712,6 +3712,43 @@
"rollup-pluginutils": "^2.8.1"
}
},
"rollup-plugin-node-globals": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/rollup-plugin-node-globals/-/rollup-plugin-node-globals-1.4.0.tgz",
"integrity": "sha512-xRkB+W/m1KLIzPUmG0ofvR+CPNcvuCuNdjVBVS7ALKSxr3EDhnzNceGkGi1m8MToSli13AzKFYH4ie9w3I5L3g==",
"dev": true,
"requires": {
"acorn": "^5.7.3",
"buffer-es6": "^4.9.3",
"estree-walker": "^0.5.2",
"magic-string": "^0.22.5",
"process-es6": "^0.11.6",
"rollup-pluginutils": "^2.3.1"
},
"dependencies": {
"acorn": {
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
"integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==",
"dev": true
},
"estree-walker": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.5.2.tgz",
"integrity": "sha512-XpCnW/AE10ws/kDAs37cngSkvgIR8aN3G0MS85m7dUpuK2EREo9VJ00uvw6Dg/hXEpfsE1I1TvJOJr+Z+TL+ig==",
"dev": true
},
"magic-string": {
"version": "0.22.5",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.5.tgz",
"integrity": "sha512-oreip9rJZkzvA8Qzk9HFs8fZGF/u7H/gtrE8EN6RjKJ9kh2HlC+yQ2QezifqTZfGyiuAV0dRv5a+y/8gBb1m9w==",
"dev": true,
"requires": {
"vlq": "^0.2.2"
}
}
}
},
"rollup-plugin-node-resolve": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz",
@ -4444,6 +4481,12 @@
"integrity": "sha512-fOi47nsJP5Wqefa43kyWSg80qF+Q3XA6MUkgi7Hp1HQaKDQW4cQrK2D0P7mmbFtsV1N89am55Yru/nyEwRubcw==",
"dev": true
},
"vlq": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz",
"integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==",
"dev": true
},
"websocket-stream": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/websocket-stream/-/websocket-stream-5.5.0.tgz",

1
package.json

@ -41,6 +41,7 @@
"@types/leaflet": "^1.4.6",
"rollup": "^1.17.0",
"rollup-plugin-commonjs": "^10.0.1",
"rollup-plugin-node-globals": "^1.4.0",
"rollup-plugin-node-resolve": "^5.2.0",
"rollup-plugin-postcss": "^2.0.3",
"rollup-plugin-replace": "^2.2.0",

12
rollup.main.config.js

@ -0,0 +1,12 @@
import plugins from './rollup.plugins.config.js';
export default {
input: {
"app": 'client_src/js/index.mjs',
},
output: {
dir: 'app/',
format: 'esm'
},
plugins
};

14
rollup.config.js → rollup.plugins.config.js

@ -8,6 +8,7 @@ import postcss from 'rollup-plugin-postcss';
import { terser } from "rollup-plugin-terser";
import replace from 'rollup-plugin-replace';
import builtins from '@joseph184/rollup-plugin-node-builtins';
import globals from 'rollup-plugin-node-globals';
// import json from 'rollup-plugin-json';
import postcss_import from 'postcss-import';
@ -15,6 +16,7 @@ import postcss_copy from 'postcss-copy';
let plugins = [
builtins(),
globals(),
resolve({
mainFields: [
@ -87,14 +89,4 @@ if(process.env.NODE_ENV == "production") {
}));
}
export default {
input: {
"app": 'client_src/js/index.mjs',
"worker": 'client_src/js/Worker/AI.worker.mjs'
},
output: {
dir: 'app/',
format: 'esm'
},
plugins
};
export default plugins;

12
rollup.worker.config.js

@ -0,0 +1,12 @@
import plugins from './rollup.plugins.config.js';
export default {
input: {
"worker": 'client_src/js/Worker/AI.worker.mjs'
},
output: {
dir: 'app/',
format: 'esm'
},
plugins
};

28
server/train-ai/AITrainer.mjs

@ -15,16 +15,6 @@ class AITrainer {
this.repo_gateway = GatewayRepo;
}
generate_neural_net() {
let net = new brain.NeuralNetwork({
hiddenLayers: this.settings.ai.network_arch,
activation: "sigmoid"
});
return net;
}
async train_all() {
let index = [];
for(let gateway of this.repo_gateway.iterate()) {
@ -34,7 +24,8 @@ class AITrainer {
if(!fs.existsSync(path.dirname(filepath)))
await fs.promises.mkdir(path.dirname(filepath), { recursive: true });
if(!await this.train_gateway(gateway.id, filepath)) {
let result = await this.train_gateway(gateway.id, filepath);
if(!result || result.success === false) {
this.l.warn(`Warning: Failed to train AI for ${gateway.id}.`);
continue;
}
@ -43,7 +34,8 @@ class AITrainer {
id: gateway.id,
filename: path.basename(filepath),
latitude: gateway.latitude,
longitude: gateway.longitude
longitude: gateway.longitude,
net_settings: result.net_settings
});
}
@ -71,7 +63,12 @@ class AITrainer {
*/
async train_gateway(gateway_id, destination_filename) {
this.l.log(`${this.a.fgreen}${this.a.hicol}Training AI for gateway ${gateway_id}${this.a.reset}`);
let net = this.generate_neural_net();
let net_settings = {
hiddenLayers: this.settings.ai.network_arch,
activation: "sigmoid"
};
let net = new brain.NeuralNetwork(net_settings);
let dataset = this.dataset_fetcher.fetch_all(gateway_id);
@ -91,7 +88,10 @@ class AITrainer {
await fs.promises.writeFile(destination_filename, JSON.stringify(net.toJSON()));
// console.log(result);
return true;
return {
success: true,
net_settings
};
}
}

Loading…
Cancel
Save