diff --git a/examples/meetup/nnet.ipynb b/examples/meetup/nnet.ipynb index d414382e..968483da 100644 --- a/examples/meetup/nnet.ipynb +++ b/examples/meetup/nnet.ipynb @@ -2,24 +2,13 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": { "collapsed": false }, - "outputs": [ - { - "data": { - "text/plain": [ - "plotgrid (generic function with 1 method)" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ - "using Plots; qwt()\n", + "using Plots; immerse()\n", "default(size=(500,300), leg=false)\n", "\n", "# creates x/y vectors which can define a grid in a zig-zag pattern\n", @@ -27,11 +16,6 @@ " xs = linspace(lim..., n)\n", " xypairs = vec([(x,y) for x in vcat(xs,reverse(xs)), y in xs])\n", " Plots.unzip(xypairs)\n", - "end\n", - "\n", - "# plot a grid from x/y vectors\n", - "function plotgrid(x, y)\n", - " plot([x y], [y x], c=:black)\n", "end" ] }, @@ -44,83 +28,18 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": { "collapsed": false }, - "outputs": [ - { - "data": { - "text/plain": [ - "f2 (generic function with 1 method)" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "# these are the functions we want to classify\n", - "f1(x) = 0.6sin(10x) + 0.1\n", + "scalar = 10 # larger is harder... start with 3\n", + "f1(x) = 0.6sin(scalar * x) + 0.1\n", "f2(x) = f1(x) - 0.2" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Build a neural net" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "INFO: Recompiling stale cache file /home/tom/.julia/lib/v0.4/OnlineStats.ji for module OnlineStats.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " 0.366577 seconds (2.08 M allocations: 156.080 MB, 3.22% gc time)\n", - "\n", - "\n", - "\n", - "maxabs(β - coef(o)) for\n", - "\n", - "glm: 0.005542500269197448\n", - "sgd: NaN\n", - "proxgrad: 0.004859362717011262\n", - "rda: 0.007882387662070361\n" - ] - } - ], - "source": [ - "using OnlineAI\n", - "\n", - "# first create a neural net to separate the functions\n", - "numInputs = 2\n", - "numOutputs = 1\n", - "hiddenLayerStructure = [3,3,2]\n", - "net = buildClassificationNet(numInputs, numOutputs, hiddenLayerStructure;\n", - " hiddenActivation = TanhActivation(),\n", - " finalActivation = TanhActivation(),\n", - "\n", - ")\n", - "\n", - "# show the network\n", - "viz = visualize(net);" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -138,30 +57,35 @@ "source": [ "# pick the plotting limits\n", "lim = (-1,1)\n", - "default(xlim = lim, ylim = lim)\n", - "\n", - "# show the grid\n", + "funcs = [f1, f2]\n", "n = 40\n", "gridx, gridy = gridxy(lim, n)\n", - "p = plotgrid(gridx, gridy)\n", + "default(xlim = lim, ylim = lim)\n", "\n", - "# show the funcs\n", - "funcs = [f1, f2]\n", - "plot!(funcs, lim..., w=3)\n", + "function initialize_plot(funcs, lim, gridx, gridy; kw...)\n", + " # show the grid\n", + " plot([gridx gridy], [gridy gridx], c=:black, kw...)\n", "\n", - "# kick off an animation... we can save frames whenever we want, lets save the start\n", - "anim = Animation()\n", - "frame(anim)\n", + " # show the funcs\n", + " plot!(funcs, lim..., l=(4,[:blue :red]))\n", + "end\n", "\n", - "# open a gui window\n", - "gui()" + "# kick off an animation... we can save frames whenever we want, lets save the starting frame\n", + "function initialize_animation()\n", + " anim = Animation()\n", + " frame(anim)\n", + " anim\n", + "end\n", + "\n", + "# lets see what we're dealing with...\n", + "p = initialize_plot(funcs, lim, gridx, gridy)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "# That looks tricky..." + "# That looks tricky... lets build a neural net!" ] }, { @@ -172,61 +96,35 @@ }, "outputs": [], "source": [ - "# function to sample from x's\n", - "xsample() = rand(Distributions.Uniform(lim...)) \n", - "\n", - "# pick one of the functions at random, sample from the x line, then update the\n", - "# neural net with [x, f(x)] as the inputs\n", - "function sampleAndUpdate()\n", - " f = sample(funcs)\n", - " x = xsample()\n", - " y = float(f == f1)\n", - " update!(net, Float64[x, f(x)], [y])\n", - "end\n", + "using OnlineAI\n", + "net = buildTanhClassificationNet(\n", + " 2, # number of inputs\n", + " 1, # number of outputs\n", + " [4,4,2], # hidden layers structure\n", + "# params = NetParams(gradientModel = SGDModel(η=1e-5))\n", + ")\n", "\n", "# take x matrix and convert to the first layer's activation\n", "function activateHidden(net, x)\n", - "# input = x\n", " @assert net.layers[end].nin == 2\n", - " proj = Array(nrows(x), 2)\n", + " proj = zeros(nrows(x), 2)\n", " for i in 1:nrows(x)\n", " data = row(x,i)\n", " for layer in net.layers[1:end-1]\n", - " #proj = Array(nrows(x), layer.nout)\n", - " OnlineAI.forward!(layer, row(proj,i), false)\n", + " OnlineAI.forward!(layer, data, false)\n", " data = layer.a\n", - "# row!(proj, i, layer.a)\n", " end\n", " row!(proj, i, data)\n", - "# input = proj\n", " end\n", " vec(proj[:,1]), vec(proj[:,2])\n", "end " ] }, { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], + "cell_type": "markdown", + "metadata": {}, "source": [ - "# update net with new samples\n", - "for i in 1:10000\n", - " sampleAndUpdate()\n", - "end\n", - "\n", - "# update the plot... project each series to the first hidden layer and reset the data\n", - "x = linspace(lim..., 100)\n", - "p[1] = activateHidden(net, hcat(gridx, gridy))\n", - "p[2] = activateHidden(net, hcat(gridy, gridx))\n", - "p[3] = activateHidden(net, hcat(x, map(f1,x)))\n", - "p[4] = activateHidden(net, hcat(x, map(f2,x)))\n", - "\n", - "# show/update the plot\n", - "gui(p)\n", - "frame(anim);" + "# Update our model and the visualization" ] }, { @@ -237,8 +135,100 @@ }, "outputs": [], "source": [ - "# build an animated gif\n", - "gif(anim, fps = 10)" + "p = initialize_plot(funcs, lim, gridx, gridy)\n", + "anim = initialize_animation()\n", + "gui()\n", + "\n", + "progressviz = track_progress(net)\n", + "gui(progressviz.subplt)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "iterations_per_frame = 2000\n", + "total_frames = 100\n", + "dist = Distributions.Uniform(lim...)\n", + "\n", + "for frm in 1:total_frames\n", + " # pick one of the functions at random, sample from the x line, then update the\n", + " # neural net with [x, f(x)] as the inputsn = 1000\n", + " for i in 1:iterations_per_frame\n", + " f = sample(funcs)\n", + " x = rand(dist)\n", + " y = f == f1 ? 1.0 : -1.0\n", + " update!(net, Float64[x, f(x)], [y])\n", + " end\n", + "\n", + " # update the plot... project each series to the first hidden layer and reset the data\n", + " # NOTE: this works because `getindex` and `setindex` are overloaded to get/set the underlying plot series data\n", + " x = linspace(lim..., 50)\n", + " p[1] = activateHidden(net, hcat(gridx, gridy))\n", + " p[2] = activateHidden(net, hcat(gridy, gridx))\n", + " p[3] = activateHidden(net, hcat(x, map(f1,x)))\n", + " p[4] = activateHidden(net, hcat(x, map(f2,x)))\n", + "\n", + " # show/update the plot\n", + " gui(p)\n", + " frame(anim)\n", + " \n", + " # update the progress visualization\n", + " update!(progressviz, true)\n", + "end" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Animate!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "gif(anim, fps = 20)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# show the network (uses Qwt, visualize isn't available unless you import it)\n", + "import Qwt\n", + "viz = visualize(net);" ] }, { @@ -296,7 +286,9 @@ "collapsed": true }, "outputs": [], - "source": [] + "source": [ + "gui(progressviz.subplt)" + ] }, { "cell_type": "code", @@ -385,6 +377,17 @@ "gui()" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "sp = progressviz.subplt.plts[1].o.widget[:minimumSizeHint]()" + ] + }, { "cell_type": "code", "execution_count": null, diff --git a/src/subplot.jl b/src/subplot.jl index e2ceb010..086b1f00 100644 --- a/src/subplot.jl +++ b/src/subplot.jl @@ -78,7 +78,7 @@ ncols(layout::GridLayout, row::Int) = layout.nc # get the plot index given row and column Base.getindex(layout::GridLayout, r::Int, c::Int) = (r-1) * layout.nc + c -Base.getindex(subplt::Subplot, args...) = subplt.layout[args...] +Base.getindex(subplt::Subplot, args...) = subplt.plts[subplt.layout[args...]] # handle "linking" the subplot axes together # each backend should implement the handleLinkInner and expandLimits! methods