diff options
| author | schneefux <schneefux+commit@schneefux.xyz> | 2016-03-28 20:06:49 +0200 |
|---|---|---|
| committer | schneefux <schneefux+commit@schneefux.xyz> | 2016-03-28 20:06:49 +0200 |
| commit | 016989874c9be3d61080a6fd1396e11fa5feeee1 (patch) | |
| tree | 575cd01c265ba4ee829da0c06455862d3ca63a46 /index.js | |
| parent | 6556c88426c5ca3686a6e0aaee79706b41ed52d3 (diff) | |
| download | vortrag-knn-016989874c9be3d61080a6fd1396e11fa5feeee1.tar.gz vortrag-knn-016989874c9be3d61080a6fd1396e11fa5feeee1.zip | |
first working version
Diffstat (limited to 'index.js')
| -rw-r--r-- | index.js | 177 |
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); +} |
