summaryrefslogtreecommitdiff
path: root/index.js
diff options
context:
space:
mode:
authorschneefux <schneefux+commit@schneefux.xyz>2016-03-28 20:06:49 +0200
committerschneefux <schneefux+commit@schneefux.xyz>2016-03-28 20:06:49 +0200
commit016989874c9be3d61080a6fd1396e11fa5feeee1 (patch)
tree575cd01c265ba4ee829da0c06455862d3ca63a46 /index.js
parent6556c88426c5ca3686a6e0aaee79706b41ed52d3 (diff)
downloadvortrag-knn-016989874c9be3d61080a6fd1396e11fa5feeee1.tar.gz
vortrag-knn-016989874c9be3d61080a6fd1396e11fa5feeee1.zip
first working version
Diffstat (limited to 'index.js')
-rw-r--r--index.js177
1 files changed, 177 insertions, 0 deletions
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..8c6f14e
--- /dev/null
+++ b/index.js
@@ -0,0 +1,177 @@
+function drawNodes(nodes, netSpec, designSpec, env) {
+ var cnt = 0;
+ var biasLayers = 0;
+ for (layer=0; layer<designSpec.length; layer++) {
+ if (designSpec[layer] == "bias") biasLayers++;
+ }
+ for (layer=0; layer<netSpec.length; layer++) {
+ for (node=0; node<netSpec[layer]; node++) {
+ // dynamic ("responsive") attributes for all window sizes
+ if (designSpec[layer] == "bias") {
+ nodes[cnt].x = (layer - biasLayers + 1.25) * (env.width / (netSpec.length - biasLayers));
+ nodes[cnt].y = (node + 0.25) * (env.height / netSpec[layer]);
+ nodes[cnt].r = d3.min([env.width, env.height]) / d3.max(netSpec.concat(netSpec.length)) * 0.2;
+ } else {
+ nodes[cnt].x = (layer - biasLayers + 0.5) * (env.width / (netSpec.length - biasLayers));
+ nodes[cnt].y = (node + 0.5) * (env.height / netSpec[layer]);
+ nodes[cnt].r = d3.min([env.width, env.height]) / d3.max(netSpec.concat(netSpec.length)) * 0.3;
+ }
+ cnt++;
+ }
+ }
+ return nodes;
+}
+
+function drawLinks(links, weights) {
+ var cnt = 0;
+ for (layer=0; layer<weights.length; layer++) {
+ for (layer2=0; layer2<weights[layer].length; layer2++) {
+ for (node=0; node<weights[layer][layer2].length; node++) {
+ links[cnt++].weight = weights[layer][layer2][node];
+ }
+ }
+ }
+ return links;
+}
+
+function createNet(netSpec, designSpec) {
+ // create layers
+ var nodes = [];
+ for (layer=0; layer<netSpec.length; layer++) {
+ for (node=0; node<netSpec[layer]; node++) {
+ nodes.push({
+ id: layer.toString() + "_" + node.toString(),
+ fixed: true
+ });
+ }
+ }
+ var nodesMap = d3.map();
+ nodes.forEach(function (n) {
+ return nodesMap.set(n.id, n);
+ });
+ // create links
+ var links = [];
+ for (layer=0; layer<netSpec.length-1; layer++) {
+ for (src=0; src<netSpec[layer]; src++) {
+ if (designSpec[layer] == "bias") {
+ links.push({
+ source: nodesMap.get(layer.toString() + "_" + src.toString()),
+ target: nodesMap.get((layer + 1).toString() + "_" + src.toString()),
+ weight: 1
+ });
+ } else {
+ for (tar=0; tar<netSpec[layer+1]; tar++) {
+ links.push({
+ source: nodesMap.get(layer.toString() + "_" + src.toString()),
+ target: nodesMap.get((layer + 1).toString() + "_" + tar.toString()),
+ weight: 1
+ });
+ }
+ }
+ }
+ }
+
+ return {
+ "nodes": nodes,
+ "links": links
+ };
+}
+
+// create empty elements and determine the visualisation"s size
+var svg = d3.select("#visContainer").append("svg")
+ .attr("width", "100%")
+ .attr("height", "100%");
+
+// create network and links
+var netSpec = [13, 13, 11, 1],
+ designSpec = ["bias", "standard", "standard", "standard"];
+var net = createNet(netSpec, designSpec);
+
+
+// create visualisation
+function envRedraw(weights, duration) {
+ // "cache" the values for pure resize events
+ if (!duration) {
+ duration = 0;
+ }
+ if (!weights) {
+ weights = this._weigths;
+ } else {
+ this._weigths = weights;
+ }
+ var width = parseInt(svg.style("width")) || 800,
+ height = parseInt(svg.style("height")) || 600;
+ net.nodes = drawNodes(net.nodes, netSpec, designSpec, {"width": width, "height": height});
+ net.links = drawLinks(net.links, weights);
+
+ node = svg.selectAll(".node");
+ node
+ .transition()
+ .duration(duration)
+ .attr("cx", function(d) { return d.x; })
+ .attr("cy", function(d) { return d.y; })
+ .attr("r", function(d) { return d.r; });
+ link = svg.selectAll(".link");
+ link
+ .transition()
+ .duration(duration)
+ .style("stroke-width", function(d) { return d.weight * 4; })
+ .attr("x1", function(d) { return d.source.x; })
+ .attr("y1", function(d) { return d.source.y; })
+ .attr("x2", function(d) { return d.target.x; })
+ .attr("y2", function(d) { return d.target.y; });
+}
+window.addEventListener("resize", envRedraw, true);
+
+var link = svg.selectAll(".link")
+ .data(net.links)
+ .enter().append("line")
+ .attr("class", "link")
+ .style("stroke", "grey")
+ .style("stroke-width", function(d) { return d.weight * 4; })
+ .attr("x1", function(d) { return d.source.x; })
+ .attr("y1", function(d) { return d.source.y; })
+ .attr("x2", function(d) { return d.target.x; })
+ .attr("y2", function(d) { return d.target.y; });
+var node = svg.selectAll(".node")
+ .data(net.nodes)
+ .enter().append("circle")
+ .attr("class", "node")
+ .attr("cx", function(d) { return d.x; })
+ .attr("cy", function(d) { return d.y; })
+ .attr("r", function(d) { return d.r; });
+
+
+// now we're getting to the grips
+function preload(callback) {
+ d3.json("data/log.json")
+ .get(function(e, json) {
+ if (e) console.log(e);
+ callback(json);
+ });
+}
+
+var cache = {};
+preload(function (json) {
+ cache = json;
+ animate();
+});
+
+var maxBatch = 8, maxEpoch = 300;
+var epochStep = 50;
+var numLayers = 3;
+var currBatch = 0, currEpoch = 0;
+function animate() {
+ frameDuration = 20000 / (maxBatch * maxEpoch / epochStep);
+ envRedraw(cache[currBatch][currEpoch], frameDuration);
+ currEpoch += epochStep;
+ if (currEpoch >= maxEpoch) {
+ currEpoch = 0;
+ console.log("batch " + currBatch.toString());
+ if (++currBatch >= maxBatch) {
+ currBatch = 0;
+ return; // stop
+ }
+ }
+ setTimeout(animate, frameDuration);
+}