├── LICENSE
├── README.md
├── index.html
├── index.js
└── package.json
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Heather Arthur Organization
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | rnn-viewer
2 |
3 | #### A recurrent neural net utility for brain.js
4 | 
5 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | rnn-viewer
6 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Top View
30 | Side View
31 | Default View
32 |
33 |
34 |
35 |
36 |
37 |
115 |
116 |
117 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | function RNNViewer(settings) {
2 | Object.assign(this, RNNViewer.defaults, settings);
3 |
4 | this.net = settings.net;
5 | this.boundingGrid = null;
6 | this.values = [];
7 | this.grids = [];
8 | this.matrices = [];
9 | this.controls = null;
10 | this.scene = null;
11 | this.camera = null;
12 | this.light = null;
13 | this.renderer = null;
14 | this.stats = null;
15 |
16 | this.init();
17 |
18 | if (this.net) {
19 | var model = this.net.model;
20 | this.addMatrix(model.input);
21 | //this.addMatrix(model.inputConnector);
22 |
23 | model.hiddenLayers.forEach(this.addMatrix.bind(this));
24 |
25 | this.addMatrix(model.outputConnector);
26 | this.addMatrix(model.output);
27 | }
28 |
29 | this.animate();
30 | }
31 |
32 | RNNViewer.defaults = {
33 | net: null,
34 | container: null,
35 | height: window.innerHeight,
36 | width: window.innerWidth,
37 | depth: 400,
38 | hotColor: new THREE.Color(0xff55f9),
39 | coldColor: new THREE.Color(0x050638),
40 | squareWidth: 10,
41 | squareHeight: 10,
42 | devicePixelRatio: window.devicePixelRatio,
43 | includeStats: false
44 | };
45 |
46 | RNNViewer.prototype = {
47 | init: function() {
48 | //Set up camera
49 | var vFOVRadians = 2 * Math.atan(this.height / (2 * 1500)),
50 | fov = vFOVRadians * 180 / Math.PI,
51 | startPosition = this.startPosition = new THREE.Vector3(0, 0, 3000);
52 |
53 | var camera = this.camera = new THREE.PerspectiveCamera(fov, this.width / this.height, 1, 30000);
54 | camera.position.set(startPosition.x, startPosition.y, startPosition.z);
55 |
56 | var controls = this.controls = new THREE.OrbitControls(camera);
57 | controls.damping = 0.2;
58 | controls.addEventListener('change', this.render.bind(this));
59 |
60 | //Create scenes for webGL
61 | var scene = this.scene = new THREE.Scene();
62 | //Add a light source & create Canvas
63 | var light = this.light = new THREE.DirectionalLight( 0xffffff );
64 | light.position.set(0, 0, 1);
65 | scene.add(light);
66 |
67 | //set up webGL renderer
68 | var renderer = this.renderer = new THREE.WebGLRenderer();
69 | renderer.setPixelRatio(this.devicePixelRatio);
70 | renderer.setSize(this.width, this.height);
71 | this.container.appendChild(renderer.domElement);
72 |
73 | //stats
74 | if (this.includeStats) {
75 | var stats = this.stats = new Stats();
76 | stats.domElement.style.position = 'absolute';
77 | stats.domElement.style.bottom = '10px';
78 | stats.domElement.style.left = '10px';
79 | this.container.appendChild(stats.domElement);
80 | }
81 |
82 | var boundingGrid = this.boundingGrid = new THREE.Object3D();
83 | scene.add(boundingGrid);
84 | return this;
85 | },
86 | update: function() {
87 | var hotColor = this.settings.hotColor;
88 | var coldColor = this.settings.coldColor;
89 | return this;
90 | },
91 | render: function() {
92 | var depth = this.depth;
93 | this.grids.forEach(function(grid, i, grids) {
94 | grid.position.z = (grids.length - i) * depth;
95 | });
96 |
97 | this.camera.lookAt(this.scene.position);
98 | this.renderer.render(this.scene, this.camera);
99 | if (this.stats) this.stats.update();
100 | return this;
101 | },
102 | animate: function() {
103 | this.controls.update();
104 | window.requestAnimationFrame(this.animate.bind(this));
105 | return this;
106 | },
107 | addMatrix: function (matrix) {
108 | var grid = new THREE.Object3D(),
109 | depth = this.depth,
110 | rows = matrix.rows,
111 | columns = matrix.columns,
112 | xPixel = -(this.squareWidth * columns)/ 2,
113 | yPixel = -(this.squareHeight * rows) / 2,
114 | lowValue = 0,
115 | highValue = 0,
116 | index = 0;
117 |
118 | //height
119 | for (var row = 1; row <= rows; row++) {
120 | xPixel = -(this.squareWidth * columns) / 2;
121 | for (var column = 1; column <= columns; column++) {
122 | var color = this.coldColor.clone();
123 | var material = new THREE.MeshBasicMaterial({
124 | color: color,
125 | side: THREE.DoubleSide,
126 | vertexColors: THREE.FaceColors
127 | });
128 | var square = new THREE.Geometry();
129 | square.vertices.push(new THREE.Vector3(xPixel , yPixel , 0));
130 | square.vertices.push(new THREE.Vector3(xPixel , yPixel + this.squareHeight , 0));
131 | square.vertices.push(new THREE.Vector3(xPixel + this.squareWidth, yPixel + this.squareHeight , 0));
132 | square.vertices.push(new THREE.Vector3(xPixel + this.squareWidth, yPixel , 0));
133 |
134 | square.faces.push(new THREE.Face3(0, 1, 2));
135 | square.faces.push(new THREE.Face3(0, 3, 2));
136 | var mesh = new THREE.Mesh(square, material);
137 | grid.add(mesh);
138 |
139 | this.values.push({
140 | color: color,
141 | row: row - 1,
142 | column: column - 1,
143 | matrixIndex: this.grids.length,
144 | square: square,
145 | mesh: mesh,
146 | frontFace: mesh.geometry.faces[0],
147 | rearFace: mesh.geometry.faces[1],
148 | index: index,
149 | matrix: matrix,
150 | get value() {
151 | var value = this.matrix.weights[this.index];
152 | if (value > highValue) {
153 | highValue = value;
154 | }
155 | if (value < lowValue) {
156 | lowValue = value;
157 | }
158 | return value || 0;
159 | },
160 | get percentValue() {
161 | var value = this.value;
162 | var normalizedHigh = highValue - lowValue;
163 | var normalizedValue = value - lowValue;
164 | return (normalizedHigh - normalizedValue) / normalizedHigh;
165 | }
166 | });
167 |
168 | xPixel += this.squareWidth;
169 | index++;
170 | }
171 | yPixel += this.squareHeight;
172 | }
173 |
174 | this.grids.push(grid);
175 | this.matrices.push(matrix);
176 | this.boundingGrid.add(grid);
177 |
178 | return this;
179 | },
180 | viewTop: function() {
181 | this.controls.reset();
182 |
183 | var vFOVRadians = 2 * Math.atan(this.height / ( 2 * 35000 )),
184 | fov = vFOVRadians * 180 / Math.PI;
185 |
186 | this.camera.fov = fov;
187 | this.controls.rotateUp(90 * Math.PI / 180);
188 | this.camera.position.z = this.startPosition.z * 23;
189 | this.camera.position.y = this.startPosition.z * 55;
190 | this.camera.far = 1000000;
191 | this.camera.updateProjectionMatrix();
192 | return this.render();
193 | },
194 | viewSide: function() {
195 | this.controls.reset();
196 |
197 | var vFOVRadians = 2 * Math.atan(this.height / ( 2 * 35000 )),
198 | fov = vFOVRadians * 180 / Math.PI;
199 |
200 | this.camera.fov = fov;
201 | this.camera.position.z = this.startPosition.z * 58;
202 | this.camera.far = 1000000;
203 | this.camera.updateProjectionMatrix();
204 | return this.render();
205 | },
206 | viewDefault: function() {
207 | this.controls.reset();
208 |
209 | this.camera.fov = 30;
210 | this.camera.updateProjectionMatrix();
211 | return this.render();
212 | },
213 | setSize: function(width, height) {
214 | this.width = width;
215 | this.height = height;
216 | this.renderer.setSize(this.width, this.height);
217 | return this.render();
218 | },
219 | setValue: function(v) {
220 | var v = Math.random() * 2,
221 | r = (coldColor.r + hotColor.r) / v,
222 | g = (coldColor.g + hotColor.g) / v,
223 | b = (coldColor.b + hotColor.b) / v;
224 |
225 | value.frontFace.color.setRGB(
226 | r,
227 | g,
228 | b
229 | );
230 | value.rearFace.color.setRGB(
231 | r,
232 | g,
233 | b
234 | );
235 | value.square.colorsNeedUpdate = true;
236 | //value.mesh.geometry.elementsNeedUpdate = true;
237 | value.mesh.geometry.colorsNeedUpdate = true;
238 | }
239 | };
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rnn-viewer",
3 | "version": "1.0.0",
4 | "description": "a brain.js utility for viewing recurrent neural networks using three.js",
5 | "main": "index.js",
6 | "dependencies": {
7 | "three": "^0.81.2"
8 | },
9 | "devDependencies": {},
10 | "scripts": {
11 | "test": "echo \"Error: no test specified\" && exit 1"
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "git+https://github.com/harthur-org/rnn-viewer.git"
16 | },
17 | "author": "",
18 | "license": "ISC",
19 | "bugs": {
20 | "url": "https://github.com/harthur-org/rnn-viewer/issues"
21 | },
22 | "homepage": "https://github.com/harthur-org/rnn-viewer#readme"
23 | }
24 |
--------------------------------------------------------------------------------