diff --git a/.bowerrc b/.bowerrc new file mode 100644 index 00000000..9520cda3 --- /dev/null +++ b/.bowerrc @@ -0,0 +1,3 @@ +{ + "directory" : "demo/bower_components" +} \ No newline at end of file diff --git a/Gulpfile.js b/Gulpfile.js new file mode 100644 index 00000000..764bf843 --- /dev/null +++ b/Gulpfile.js @@ -0,0 +1,45 @@ +var gulp = require('gulp'); +var jshint = require('gulp-jshint'); +var browserSync = require('browser-sync'); +const reload = browserSync.reload; +gulp.task('copy', () => + gulp.src([ + 'build/**/*' + ], { + base: './' + }).pipe(gulp.dest('demo')) +); +// jshint files +gulp.task('jshint', function () { + //gulp.src(['test/**/*.js']) + // .pipe(jshint()) + // .pipe(jshint.reporter()); +}); +// start local http server for development +gulp.task('http-server', function () { + browserSync({ + notify: false, + // Customize the Browsersync console logging prefix + logPrefix: 'WSK', + // Allow scroll syncing across breakpoints + scrollElementMapping: ['main', '.mdl-layout'], + // Run as an https by uncommenting 'https: true' + // Note: this uses an unsigned certificate which on first access + // will present a certificate warning in the browser. + // https: true, + server: ['.tmp', 'demo'], + port: 3000 + }); + gulp.watch(['demo/**/*'], reload); +}); +// start local http server with watch and livereload set up +gulp.task('server', function () { + gulp.run('http-server'); +}); +gulp.task('default', function () { + gulp.run('jshint', 'copy', 'server'); +}); +gulp.task('serve', function () { + gulp.run('default'); +}); + diff --git a/bower.json b/bower.json index 6158a6d8..31b1ec52 100644 --- a/bower.json +++ b/bower.json @@ -27,5 +27,8 @@ "bower_components", "test", "tests" - ] + ], + "dependencies": { + "codemirror": "^5.15.2" + } } diff --git a/demo/index.html b/demo/index.html new file mode 100644 index 00000000..58bfdaea --- /dev/null +++ b/demo/index.html @@ -0,0 +1,29 @@ + + + + + + + +
+ + + + \ No newline at end of file diff --git a/demo/js/rldemo.js b/demo/js/rldemo.js index 5636c1f2..6b33b0e8 100644 --- a/demo/js/rldemo.js +++ b/demo/js/rldemo.js @@ -1,578 +1,551 @@ - var canvas, ctx; - - // A 2D vector utility - var Vec = function(x, y) { - this.x = x; - this.y = y; - } - Vec.prototype = { - - // utilities - dist_from: function(v) { return Math.sqrt(Math.pow(this.x-v.x,2) + Math.pow(this.y-v.y,2)); }, - length: function() { return Math.sqrt(Math.pow(this.x,2) + Math.pow(this.y,2)); }, - - // new vector returning operations - add: function(v) { return new Vec(this.x + v.x, this.y + v.y); }, - sub: function(v) { return new Vec(this.x - v.x, this.y - v.y); }, - rotate: function(a) { // CLOCKWISE +var canvas, ctx; +// A 2D vector utility +var Vec = function (x, y) { + this.x = x; + this.y = y; +} +Vec.prototype = { + // utilities + dist_from: function (v) { + return Math.sqrt(Math.pow(this.x - v.x, 2) + Math.pow(this.y - v.y, 2)); + }, + length: function () { + return Math.sqrt(Math.pow(this.x, 2) + Math.pow(this.y, 2)); + }, + // new vector returning operations + add: function (v) { + return new Vec(this.x + v.x, this.y + v.y); + }, + sub: function (v) { + return new Vec(this.x - v.x, this.y - v.y); + }, + rotate: function (a) { // CLOCKWISE return new Vec(this.x * Math.cos(a) + this.y * Math.sin(a), - -this.x * Math.sin(a) + this.y * Math.cos(a)); - }, - - // in place operations - scale: function(s) { this.x *= s; this.y *= s; }, - normalize: function() { var d = this.length(); this.scale(1.0/d); } + -this.x * Math.sin(a) + this.y * Math.cos(a)); + }, + // in place operations + scale: function (s) { + this.x *= s; + this.y *= s; + }, + normalize: function () { + var d = this.length(); + this.scale(1.0 / d); } - - // line intersection helper function: does line segment (p1,p2) intersect segment (p3,p4) ? - var line_intersect = function(p1,p2,p3,p4) { - var denom = (p4.y-p3.y)*(p2.x-p1.x)-(p4.x-p3.x)*(p2.y-p1.y); - if(denom===0.0) { return false; } // parallel lines - var ua = ((p4.x-p3.x)*(p1.y-p3.y)-(p4.y-p3.y)*(p1.x-p3.x))/denom; - var ub = ((p2.x-p1.x)*(p1.y-p3.y)-(p2.y-p1.y)*(p1.x-p3.x))/denom; - if(ua>0.0&&ua<1.0&&ub>0.0&&ub<1.0) { - var up = new Vec(p1.x+ua*(p2.x-p1.x), p1.y+ua*(p2.y-p1.y)); - return {ua:ua, ub:ub, up:up}; // up is intersection point - } - return false; +} +// line intersection helper function: does line segment (p1,p2) intersect segment (p3,p4) ? +var line_intersect = function (p1, p2, p3, p4) { + var denom = (p4.y - p3.y) * (p2.x - p1.x) - (p4.x - p3.x) * (p2.y - p1.y); + if (denom === 0.0) { + return false; + } // parallel lines + var ua = ((p4.x - p3.x) * (p1.y - p3.y) - (p4.y - p3.y) * (p1.x - p3.x)) / denom; + var ub = ((p2.x - p1.x) * (p1.y - p3.y) - (p2.y - p1.y) * (p1.x - p3.x)) / denom; + if (ua > 0.0 && ua < 1.0 && ub > 0.0 && ub < 1.0) { + var up = new Vec(p1.x + ua * (p2.x - p1.x), p1.y + ua * (p2.y - p1.y)); + return {ua: ua, ub: ub, up: up}; // up is intersection point } - - var line_point_intersect = function(p1,p2,p0,rad) { - var v = new Vec(p2.y-p1.y,-(p2.x-p1.x)); // perpendicular vector - var d = Math.abs((p2.x-p1.x)*(p1.y-p0.y)-(p1.x-p0.x)*(p2.y-p1.y)); - d = d / v.length(); - if(d > rad) { return false; } - - v.normalize(); - v.scale(d); - var up = p0.add(v); - if(Math.abs(p2.x-p1.x)>Math.abs(p2.y-p1.y)) { + return false; +} +var line_point_intersect = function (p1, p2, p0, rad) { + var v = new Vec(p2.y - p1.y, -(p2.x - p1.x)); // perpendicular vector + var d = Math.abs((p2.x - p1.x) * (p1.y - p0.y) - (p1.x - p0.x) * (p2.y - p1.y)); + d = d / v.length(); + if (d > rad) { + return false; + } + v.normalize(); + v.scale(d); + var up = p0.add(v); + if (Math.abs(p2.x - p1.x) > Math.abs(p2.y - p1.y)) { var ua = (up.x - p1.x) / (p2.x - p1.x); - } else { + } else { var ua = (up.y - p1.y) / (p2.y - p1.y); - } - if(ua>0.0&&ua<1.0) { - return {ua:ua, up:up}; - } - return false; } - - // Wall is made up of two points - var Wall = function(p1, p2) { - this.p1 = p1; - this.p2 = p2; + if (ua > 0.0 && ua < 1.0) { + return {ua: ua, up: up}; } - - // World object contains many agents and walls and food and stuff - var util_add_box = function(lst, x, y, w, h) { - lst.push(new Wall(new Vec(x,y), new Vec(x+w,y))); - lst.push(new Wall(new Vec(x+w,y), new Vec(x+w,y+h))); - lst.push(new Wall(new Vec(x+w,y+h), new Vec(x,y+h))); - lst.push(new Wall(new Vec(x,y+h), new Vec(x,y))); - } - - // item is circle thing on the floor that agent can interact with (see or eat, etc) - var Item = function(x, y, type) { - this.p = new Vec(x, y); // position - this.type = type; - this.rad = 10; // default radius - this.age = 0; - this.cleanup_ = false; - } - - var World = function() { - this.agents = []; - this.W = canvas.width; - this.H = canvas.height; - - this.clock = 0; - - // set up walls in the world - this.walls = []; - var pad = 10; - util_add_box(this.walls, pad, pad, this.W-pad*2, this.H-pad*2); - util_add_box(this.walls, 100, 100, 200, 300); // inner walls - this.walls.pop(); - util_add_box(this.walls, 400, 100, 200, 300); - this.walls.pop(); - - // set up food and poison - this.items = [] - for(var k=0;k<30;k++) { - var x = convnetjs.randf(20, this.W-20); - var y = convnetjs.randf(20, this.H-20); + return false; +} +// Wall is made up of two points +var Wall = function (p1, p2) { + this.p1 = p1; + this.p2 = p2; +} +// World object contains many agents and walls and food and stuff +var util_add_box = function (lst, x, y, w, h) { + lst.push(new Wall(new Vec(x, y), new Vec(x + w, y))); + lst.push(new Wall(new Vec(x + w, y), new Vec(x + w, y + h))); + lst.push(new Wall(new Vec(x + w, y + h), new Vec(x, y + h))); + lst.push(new Wall(new Vec(x, y + h), new Vec(x, y))); +} +// item is circle thing on the floor that agent can interact with (see or eat, etc) +var Item = function (x, y, type) { + this.p = new Vec(x, y); // position + this.type = type; + this.rad = 10; // default radius + this.age = 0; + this.cleanup_ = false; +} +var World = function () { + this.agents = []; + this.W = canvas.width; + this.H = canvas.height; + this.clock = 0; + // set up walls in the world + this.walls = []; + var pad = 10; + util_add_box(this.walls, pad, pad, this.W - pad * 2, this.H - pad * 2); + util_add_box(this.walls, 100, 100, 200, 300); // inner walls + this.walls.pop(); + util_add_box(this.walls, 400, 100, 200, 300); + this.walls.pop(); + // set up food and poison + this.items = [] + for (var k = 0; k < 30; k++) { + var x = convnetjs.randf(20, this.W - 20); + var y = convnetjs.randf(20, this.H - 20); var t = convnetjs.randi(1, 3); // food or poison (1 and 2) var it = new Item(x, y, t); this.items.push(it); - } } - - World.prototype = { - // helper function to get closest colliding walls/items - stuff_collide_: function(p1, p2, check_walls, check_items) { +} +World.prototype = { + // helper function to get closest colliding walls/items + stuff_collide_: function (p1, p2, check_walls, check_items) { var minres = false; - // collide with walls - if(check_walls) { - for(var i=0,n=this.walls.length;ieyep - var eyep = new Vec(a.p.x + e.max_range * Math.sin(a.angle + e.angle), - a.p.y + e.max_range * Math.cos(a.angle + e.angle)); - var res = this.stuff_collide_(a.p, eyep, true, true); - if(res) { - // eye collided with wall - e.sensed_proximity = res.up.dist_from(a.p); - e.sensed_type = res.type; - } else { - e.sensed_proximity = e.max_range; - e.sensed_type = -1; + for (var i = 0, n = this.agents.length; i < n; i++) { + var a = this.agents[i]; + for (var ei = 0, ne = a.eyes.length; ei < ne; ei++) { + var e = a.eyes[ei]; + // we have a line from p to p->eyep + var eyep = new Vec(a.p.x + e.max_range * Math.sin(a.angle + e.angle), + a.p.y + e.max_range * Math.cos(a.angle + e.angle)); + var res = this.stuff_collide_(a.p, eyep, true, true); + if (res) { + // eye collided with wall + e.sensed_proximity = res.up.dist_from(a.p); + e.sensed_type = res.type; + } else { + e.sensed_proximity = e.max_range; + e.sensed_type = -1; + } } - } } - // let the agents behave in the world based on their input - for(var i=0,n=this.agents.length;i2*Math.PI)a.angle-=2*Math.PI; - - // agent is trying to move from p to op. Check walls - var res = this.stuff_collide_(a.op, a.p, true, false); - if(res) { - // wall collision! reset position - a.p = a.op; - } - - // handle boundary conditions - if(a.p.x<0)a.p.x=0; - if(a.p.x>this.W)a.p.x=this.W; - if(a.p.y<0)a.p.y=0; - if(a.p.y>this.H)a.p.y=this.H; + for (var i = 0, n = this.agents.length; i < n; i++) { + var a = this.agents[i]; + a.op = a.p; // back up old position + a.oangle = a.angle; // and angle + // steer the agent according to outputs of wheel velocities + var v = new Vec(0, a.rad / 2.0); + v = v.rotate(a.angle + Math.PI / 2); + var w1p = a.p.add(v); // positions of wheel 1 and 2 + var w2p = a.p.sub(v); + var vv = a.p.sub(w2p); + vv = vv.rotate(-a.rot1); + var vv2 = a.p.sub(w1p); + vv2 = vv2.rotate(a.rot2); + var np = w2p.add(vv); + np.scale(0.5); + var np2 = w1p.add(vv2); + np2.scale(0.5); + a.p = np.add(np2); + a.angle -= a.rot1; + if (a.angle < 0)a.angle += 2 * Math.PI; + a.angle += a.rot2; + if (a.angle > 2 * Math.PI)a.angle -= 2 * Math.PI; + // agent is trying to move from p to op. Check walls + var res = this.stuff_collide_(a.op, a.p, true, false); + if (res) { + // wall collision! reset position + a.p = a.op; + } + // handle boundary conditions + if (a.p.x < 0)a.p.x = 0; + if (a.p.x > this.W)a.p.x = this.W; + if (a.p.y < 0)a.p.y = 0; + if (a.p.y > this.H)a.p.y = this.H; } - // tick all items var update_items = false; - for(var i=0,n=this.items.length;i 5000 && this.clock % 100 === 0 && convnetjs.randf(0, 1) < 0.1) { + it.cleanup_ = true; // replace this one, has been around too long update_items = true; - break; // break out of loop, item was consumed - } } - } - - if(it.age > 5000 && this.clock % 100 === 0 && convnetjs.randf(0,1)<0.1) { - it.cleanup_ = true; // replace this one, has been around too long - update_items = true; - } } - if(update_items) { - var nt = []; - for(var i=0,n=this.items.length;i 0.75) forward_reward = 0.1 * proximity_reward; - + if (this.actionix === 0 && proximity_reward > 0.75) forward_reward = 0.1 * proximity_reward; // agents like to eat good things var digestion_reward = this.digestion_signal; this.digestion_signal = 0.0; - var reward = proximity_reward + forward_reward + digestion_reward; - // pass to brain for learning this.brain.backward(reward); - } } - - function draw_net() { - if(simspeed <=1) { +} +function draw_net() { + if (simspeed <= 1) { // we will always draw at these speeds - } else { - if(w.clock % 50 !== 0) return; // do this sparingly - } - - var canvas = document.getElementById("net_canvas"); - var ctx = canvas.getContext("2d"); - var W = canvas.width; - var H = canvas.height; - ctx.clearRect(0, 0, canvas.width, canvas.height); - var L = w.agents[0].brain.value_net.layers; - var dx = (W - 50)/L.length; - var x = 10; - var y = 40; - ctx.font="12px Verdana"; - ctx.fillStyle = "rgb(0,0,0)"; - ctx.fillText("Value Function Approximating Neural Network:", 10, 14); - for(var k=0;k= 0) ctx.fillStyle = "rgb(0,0," + v + ")"; - if(v < 0) ctx.fillStyle = "rgb(" + (-v) + ",0,0)"; - ctx.fillRect(x,y,10,10); - y += 12; - if(y>H-25) { y = 40; x += 12}; + for (var q = 0; q < n; q++) { + var v = Math.floor(kw[q] * 100); + if (v >= 0) ctx.fillStyle = "rgb(0,0," + v + ")"; + if (v < 0) ctx.fillStyle = "rgb(" + (-v) + ",0,0)"; + ctx.fillRect(x, y, 10, 10); + y += 12; + if (y > H - 25) { + y = 40; + x += 12 + } + ; } x += 50; y = 40; - } } - - var reward_graph = new cnnvis.Graph(); - function draw_stats() { - var canvas = document.getElementById("vis_canvas"); - var ctx = canvas.getContext("2d"); - var W = canvas.width; - var H = canvas.height; - ctx.clearRect(0, 0, canvas.width, canvas.height); - var a = w.agents[0]; - var b = a.brain; - var netin = b.last_input_array; - ctx.strokeStyle = "rgb(0,0,0)"; - //ctx.font="12px Verdana"; - //ctx.fillText("Current state:",10,10); - ctx.lineWidth = 10; - ctx.beginPath(); - for(var k=0,n=netin.length;k255)r=255;if(r<0)r=0; - ctx.fillStyle = "rgb(" + r + ", 150, 150)"; - ctx.strokeStyle = "rgb(0,0,0)"; - for(var i=0,n=agents.length;i 255)r = 255; + if (r < 0)r = 0; + ctx.fillStyle = "rgb(" + r + ", 150, 150)"; + ctx.strokeStyle = "rgb(0,0,0)"; + for (var i = 0, n = agents.length; i < n; i++) { var a = agents[i]; - // draw agents body ctx.beginPath(); - ctx.arc(a.op.x, a.op.y, a.rad, 0, Math.PI*2, true); + ctx.arc(a.op.x, a.op.y, a.rad, 0, Math.PI * 2, true); ctx.fill(); ctx.stroke(); - // draw agents sight - for(var ei=0,ne=a.eyes.length;ei -ConvNetJS demo: Classify toy 2D data - - - - - - - - - - - + ConvNetJS demo: Classify toy 2D data + + + + + + + + + + +
-

ConvnetJS demo: toy 1d regression

+

ConvnetJS demo: toy 1d regression

-

The simulation below is a 1-dimensional regression where a neural network is trained to regress to y coordinates for every given point x through an L2 loss. That is, the minimized cost function computes the squared difference between the predicted y-coordinate and the "correct" y coordinate. Every 10th of a second, all points are fed to the network multiple times through the trainer class to train the network.

+

The simulation below is a 1-dimensional regression where a neural network is trained to regress to y coordinates + for every given point x through an L2 loss. That is, the minimized cost function computes the squared difference + between the predicted y-coordinate and the "correct" y coordinate. Every 10th of a second, all points are fed to + the network multiple times through the trainer class to train the network.

-

The simulation below will eval() whatever you have in the text area and reload. Feel free to explore and use ConvNetJS to instantiate your own network!

+

The simulation below will eval() whatever you have in the text area and reload. Feel free to explore and use + ConvNetJS to instantiate your own network!

-

Report questions/bugs/suggestions to @karpathy.

+

Report questions/bugs/suggestions to @karpathy.

-

- + +

+ -
-Number of points to generate: - -
+
+ Number of points to generate: + +
+ +
+ +

Add data points by clicking!

+
+ + Also draw outputs of a layer (click layer button below) in red. +
-
-

Add data points by clicking!

-
- -Also draw outputs of a layer (click layer button below) in red. -
+
-Browser not supported for Canvas. Get a real browser. + Browser not supported for Canvas. Get a real browser. -

Go back to ConvNetJS

+

Go back to ConvNetJS

diff --git a/demo/rldemo.html b/demo/rldemo.html index dac859f8..bbd9b968 100644 --- a/demo/rldemo.html +++ b/demo/rldemo.html @@ -54,37 +54,38 @@

Q-Learner full specification and options

@@ -145,5 +146,13 @@

I/O


+ + + +