Navigation

Visualisation of Artificial Neural Network with WebGL

BY MARKUS SPRUNCK

This WebGL experiment shows an Artificial Neural Network which learns to detect the frequency of the input signal independent from the phase. The implementation is based on Three.js (r56), Guava and Google Web Toolkit.

Here GWT helps to translate the Java code for the Artificial Neural Network into JavaScript, which is then executed in the browser. The experiment has been developed with GWT 2.5 and App Engine SDK 1.7.6. It runs best with Chrome Browser.

The class Neuron.java (lines 45-188) represents a single neuron of the artificial neural network. Neurons are grouped in Layers and connected with Links. A Neuron can be part of input-, output- or inner-layer. The neuron implements a non linear transfer function (line 85) and the first derivative (line 96) to train the network with back propagation algorithm. In this ANN implementation a so called Sigmoid Function has been used.

The class Network has all layers and can train and recall. In line 158 you will find the function which calculates the relative mean square error. In line 85 to 150 the Back Propagation training is implemented.

Implementation - WebGL User Interface

In Webgl_ann_sample.js (lines 37-284) the model is rendered as 3D. In this code the library three.js has been used. This helps to reduce the boilerplate code needed for native WebGL. You may read more about three.js here.

// Constants for drawing the networkvarCUBE_SIZE=40;varDISTANCE_CUBE=CUBE_SIZE*1.2;varDISTANCE_LAYER=CUBE_SIZE*4;varTEXT_LENGTH=190;varTEXT_HEIGHT=34;// Artificial neural network modelvarmodel;// Make initialization just oncevarinitReady=false;// Helps to draw the graphicvarmaxCols;varmaxRows;varsizeres;varhalfsizeres;vardeltaX=-50;vardeltaY=110;vardeltaZ=320;// WebGLvargrid=[];varscene,camera,renderer,geometry,projector,ray;// Draws the model and does the initialization if needed//functionrenderData(modelText){model=createObjects(modelText);if(initReady){update();}else{calulateModelDimensions()init();}}// Update the graphic with new values from model//functionupdate(){// Change size and color of all neuronsfor(varlayerId=0;layerId<model.layers.length;layerId++){varnumberOfNodes=model.layers[layerId].nodes.length;for(varnodeId=0;nodeId<numberOfNodes;nodeId++){varelementId=nodeId+layerId*maxRows;varcubeHeight=model.layers[layerId].nodes[nodeId].y*2;grid[elementId].scale.y=0.01+cubeHeight;varcolor=getColorHex(0.01+cubeHeight);grid[elementId].material.color.setHex(color);}}// Change size and color of expected output valuesvarlayerId=model.layers.length-1;varnumberOfNodes=model.layers[layerId].nodes.length;for(varnodeId=0;nodeId<numberOfNodes;nodeId++){varelementId=nodeId+(layerId+1)*maxRows;varcubeHeight=model.layers[layerId].nodes[nodeId].y_ex*2;grid[elementId].scale.y=0.01+cubeHeight;varcolor=getColorHex(0.01+cubeHeight);grid[elementId].material.color.setHex(color);}renderer.render(scene,camera);}// Initialization of the WebGL stuff//functioninit(){// Create cameracamera=newTHREE.PerspectiveCamera(50,window.innerWidth/window.innerHeight,1,2000);camera.position.x=halfsizeres+deltaX;camera.position.y=halfsizeres+deltaY;camera.position.z=sizeres*0.85+deltaZ;camera.lookAt(newTHREE.Vector3(halfsizeres+deltaX,halfsizeres/2+deltaY,halfsizeres+deltaZ));// Create scenescene=newTHREE.Scene();scene.add(camera);// Create rendererif(Detector.webgl){renderer=newTHREE.WebGLRenderer({antialias:true});}else{renderer=newTHREE.CanvasRenderer();varinfoLabel=document.getElementById('infoLabelContainer3');infoLabel.innerHTML="WebGL is not available (canvas renderer active)";}// Create light varlight=newTHREE.SpotLight(0xffffff,1.25);light.position.set(-500,900,1600);light.target.position.set(halfsizeres,0,halfsizeres);light.castShadow=true;scene.add(light);scene.add(newTHREE.AmbientLight(0xF0F0F0));// Create cubes (for each neuron)geometry=newTHREE.CubeGeometry(CUBE_SIZE,CUBE_SIZE,CUBE_SIZE);varmatrix=newTHREE.Matrix4();matrix.makeTranslation(0,CUBE_SIZE/2,0);geometry.applyMatrix(matrix);for(varlayerId=0;layerId<=maxCols;layerId++){for(varnodeId=0;nodeId<maxRows;nodeId++){varmaterial=newTHREE.MeshLambertMaterial({color:0xffffff,ambient:0x3f3f3f,reflectivity:0.75});cube=newTHREE.Mesh(geometry,material);cube.position.x=CUBE_SIZE+(nodeId*DISTANCE_CUBE);cube.position.z=CUBE_SIZE+(layerId*DISTANCE_LAYER);cube.receiveShadow=false;cube.scale.y=0.01;scene.add(cube);grid.push(cube);}}// Create labeling (for each layer)varz=DISTANCE_CUBE;scene.add(createText("Input",-TEXT_LENGTH/2,0,z));z=DISTANCE_CUBE+(maxCols-1)*DISTANCE_LAYER;scene.add(createText("Output",-TEXT_LENGTH/2,0,z));z=DISTANCE_CUBE+maxCols*DISTANCE_LAYER;scene.add(createText("Expected",-TEXT_LENGTH/2,0,z));for(varlayerId=1;layerId<maxCols-1;layerId++){z=DISTANCE_CUBE+layerId*DISTANCE_LAYER;scene.add(createText("Hidden",-TEXT_LENGTH/2,0,z));}varcontainer=document.getElementById('drawingArea');container.appendChild(renderer.domElement);// Support move with keyboardwindow.addEventListener("keydown",doKeyDown,true);// Support window resizevarresizeCallback=function(){varoffsetHeight=document.getElementById('header').clientHeight+90;vardevicePixelRatio=window.devicePixelRatio||1;varwidth=window.innerWidth*devicePixelRatio;varheight=(window.innerHeight-offsetHeight)*devicePixelRatio;renderer.setSize(width,height);renderer.domElement.style.width=window.innerWidth+'px';renderer.domElement.style.height=(window.innerHeight-offsetHeight)+'px';camera.updateProjectionMatrix();}window.addEventListener('resize',resizeCallback,false);resizeCallback();// Do all this just onceinitReady=true;}// Determines the maximal number of layers and nodes//functioncalulateModelDimensions(){maxCols=model.layers.length;maxRows=0;for(varlayerId=0;layerId<model.layers.length;layerId++){maxRows=Math.max(model.layers[layerId].nodes.length,maxRows);}sizeres=DISTANCE_CUBE*(Math.max(maxRows,maxCols));halfsizeres=sizeres/2;}// Helper for coloring the nodes (part 1)//functiongetColorHex(value){frequency=2.0;red=Math.sin(2-frequency*value)*127+128;green=Math.sin(1-frequency*value)*127+128;blue=Math.sin(4-frequency*value)*127+128;return'0x'+integerToHex(red)+integerToHex(green)+integerToHex(blue);}// Helper for coloring the nodes (part 2)//functionintegerToHex(n){n=Math.max(0,Math.min(parseInt(n,10),255));charFirst="0123456789ABCDEF".charAt((n-n%16)/16);charSecond="0123456789ABCDEF".charAt(n%16);returncharFirst+charSecond;}// Move the graphic and camera with arrow keys//functiondoKeyDown(e){delta=10;if(e.keyIdentifier=="Right"){deltaX-=delta;camera.position.x=camera.position.x-delta;}elseif(e.keyIdentifier=="Left"){deltaX+=delta;camera.position.x=camera.position.x+delta;}elseif(e.keyIdentifier=="Down"){deltaZ-=delta;camera.position.z=camera.position.z-delta;}elseif(e.keyIdentifier=="Up"){deltaZ+=delta;camera.position.z=camera.position.z+delta;}elseif(e.keyIdentifier=="PageDown"){deltaY+=delta;camera.position.y=camera.position.y+delta;}elseif(e.keyIdentifier=="PageUp"){deltaY-=delta;camera.position.y=camera.position.y-delta;}camera.lookAt(newTHREE.Vector3(halfsizeres+deltaX,halfsizeres/2+deltaY,halfsizeres+deltaZ));}// Helper for drawing the layer labeling // functioncreateText(text,x,y,z){vartextHolder=document.createElement('canvas');varctext=textHolder.getContext('2d');textHolder.width=TEXT_LENGTH;textHolder.height=TEXT_HEIGHT;ctext.fillStyle='white';ctext.font='28px Arial';ctext.textAlign='right';ctext.fillText(text,TEXT_LENGTH-2,TEXT_HEIGHT-6);vartex=newTHREE.Texture(textHolder);varmat=newTHREE.MeshBasicMaterial({map:tex,overdraw:true});mat.transparent=true;mat.map.needsUpdate=true;mat.depthTest=true;vartextBoard=newTHREE.Mesh(newTHREE.PlaneGeometry(textHolder.width,textHolder.height),mat);textBoard.position.x=x;textBoard.position.y=y;textBoard.position.z=z;textBoard.rotation.x=-Math.PI/4;textBoard.dynamic=true;textBoard.doubleSided=true;returntextBoard;}

<!doctype html><html><head><metahttp-equiv="content-type"content="text/html; charset=UTF-8"/><metaname="viewport"content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"/><style>a{color:#009de9;font-family:Helvetica;font-style:normal;font-size:10pt;text-align:left;}h1{color:#FFF;font-family:Helvetica;font-size:14pt;text-align:left;padding-left:5px;}.text{color:#FFF;font-family:Helvetica;font-size:10pt;text-align:left;padding-left:5px;padding-right:5px;}.warning{color:#F00;font-family:Helvetica;font-size:10pt;text-align:left;padding-left:5px;padding-right:5px;}.main{background:#252525;padding:0px;}.gwt-ProgressBar-shell{border:2pxsolid#faf9f7;border-right:2pxsolid#848280;border-bottom:2pxsolid#848280;background-color:#AAAAAA;height:14pt;width:50%;}.gwt-ProgressBar-shell.gwt-ProgressBar-bar{background-color:#67A7E3;}.gwt-ProgressBar-shell.gwt-ProgressBar-text{padding:0px;margin:0px;color:white;}</style><title>WebGL Experiment - ANN</title><script type="text/javascript"language="javascript"src="webgl_ann_sample/webgl_ann_sample.nocache.js"></script></head><bodyclass="main"><noscript><divstyle="width: 22em; position: absolute; left: 50%; margin-left: -11em; color: red; background-color: white; border: 1px solid red; padding: 4px; font-family: sans-serif">
Your web browser must have JavaScript enabled
in order for this application to display correctly.
</div></noscript><script type="text/javascript"src="Detector.js"></script> <script type="text/javascript"src="three.min.js"></script><script type="text/javascript"src="Jsonhelper.js"></script><script type="text/javascript"src="Webgl_ann_sample.js"></script><divid="header"> <h1class="title">Experimental Visualization of Artificial Neural Network with WebGL</h1> <tablealign="right"><tr><divclass="text"><ahref="https://plus.google.com/u/0/117292523089281814301?rel=author">by Markus Sprunck</a><p/>
This experiment shows an Artificial Neural Network which learns to detect the frequency of
the input signal independent from the phase. The implementation is based on Three.js (r56), Guava and
Google Web Toolkit. GWT helps to translate the Java code for the Artificial Neural Network
into JavaScript, which is then executed in the browser. The experiment has been developed with
GWT 2.5 and App Engine SDK 1.7.6. It runs best with Chrome Browser. You may read more and
get the source code
<ahref="http://www.sw-engineering-candies.com/blog-1/experimental-visualization-of-artificial-neural-network-with-webgl">here</a></div></tr></table></div><divid="drawingArea"></div> <divid="footer"><tablealign="right"width="100%"><td><divid="infoLabelContainer1"></div><divid="infoLabelContainer2"></div><divid="infoLabelContainer3"class="warning"></div></td><tdwidth="90px"id="resetButtonContainer"></td><tdwidth="90px"id="trainButtonContainer"></td></table></div></body></html>