-
Notifications
You must be signed in to change notification settings - Fork 0
/
vol.js
executable file
·205 lines (180 loc) · 5.27 KB
/
vol.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
import { get_norm_weights } from 'weights_init.js';
import { zeros } from 'util/array.js';
class Vol {
constructor(sx, sy, depth, c) {
// this is how you check if a variable is an array. Oh, Javascript :)
if (Object.prototype.toString.call(sx) === '[object Array]') {
this.w = sx.slice(); // copy content
// we were given a list in sx, assume 1D volume and fill it up
sx = 1;
sy = 1;
depth = this.w.length;
}
// we were given dimensions of the vol
this.sx = sx;
this.sy = sy;
this.depth = depth;
this.shape = [this.depth, this.sy, this.sx];
this.size = this.sx * this.sy * this.depth;
if (typeof this.w === 'undefined') {
if (typeof c === 'undefined') {
this.w = get_norm_weights(this.size);
} else {
this.w = zeros(this.size).fill(c);
}
}
this.dw = this.zeros_like(); // -- save memory, allocmem at training?
this.length = this.size;
}
get ndim() { return this.shape.length };
axis(idx) {
return idx >= 0 ? this.shape[idx] : this.shape[this.ndim + idx];
}
get(x, y, d) {
let ix = ((this.sx * y) + x) * this.depth + d;
return this.w[ix];
}
set(x, y, d, v) {
let ix = ((this.sx * y) + x) * this.depth + d;
this.w[ix] = v;
}
add(x, y, d, v) {
var ix = ((this.sx * y) + x) * this.depth + d;
this.w[ix] += v;
}
get_grad(x, y, d) {
var ix = ((this.sx * y) + x) * this.depth + d;
return this.dw[ix];
}
set_grad(x, y, d, v) {
var ix = ((this.sx * y) + x) * this.depth + d;
this.dw[ix] = v;
}
add_grad(x, y, d, v) {
var ix = ((this.sx * y) + x) * this.depth + d;
this.dw[ix] += v;
}
toNumber() {
return this.w[0];
}
get max() {
let limit = this.size;
let amax = this.w[0];
let w = this.w;
for (let i = 1; i < limit; i++) {
if (w[i] > amax) amax = w[i];
}
return amax;
}
get softmax() {
let es = zeros(N);
this.softmax_a(es);
return es;
}
softmax_a(es) {
let w = this.w;
let N = this.size;
// compute max activation
let amax = this.max;
// compute exponentials (carefully to not blow up)
let esum = 0.0;
for (let i = 0; i < N; i++) {
let e = Math.exp(w[i] - amax);
esum += e;
es[i] = e;
}
// normalize and output to sum to one
for (let i = 0; i < N; i++) es[i] /= esum;
}
get max_index() {
let limit = this.size;
let amax = this.w[0];
let idx = 0;
for (let i = 1; i < limit; i++) {
if (this.w[i] > amax) {
idx = i;
amax = this.w[i];
}
}
return idx;
}
batchGrad(batch_size) {
for (let i = 0; i < this.size; i++) {
this.dw[i] /= batch_size;
}
}
cloneAndZero() { return new Vol(this.sx, this.sy, this.depth, 0.0); }
clone() {
var V = new Vol(this.sx, this.sy, this.depth, 0.0);
var n = this.w.length;
V.w = this.w.slice();
return V;
}
zeros_like() {
return zeros(this.size);
}
addFrom(V) { for (var k = 0; k < this.w.length; k++) { this.w[k] += V.w[k]; } }
addFromScaled(V, a) { for (var k = 0; k < this.w.length; k++) { this.w[k] += a * V.w[k]; } }
setConst(a) { this.w.fill(a); }
scale(f) {
for (let i = 0; i < w.length; i++) w[i] *= f;
}
toJSON() {
// todo: we may want to only save d most significant digits to save space
var json = {}
json.sx = this.sx;
json.sy = this.sy;
json.depth = this.depth;
json.w = this.w;
return json;
// we wont back up gradients to save space
}
fromJSON(json) {
this.sx = json.sx;
this.sy = json.sy;
this.depth = json.depth;
var n = this.sx * this.sy * this.depth;
this.w = zeros(n);
this.dw = zeros(n);
if (json.w instanceof Array) {
// copy over the elements.
this.w = json.w.slice();
} else {
this.w = zeros(json.w.length);
for (let i in json.w) {
this.w[i] = json.w[i];
}
}
this.shape = [this.sx, this.sy, this.depth];
this.size = this.sx * this.sy * this.depth;
this.length = this.size;
// for map function
return this;
}
}
class Constant extends Vol {
constructor(value) {
super(1, 1, 1, value);
}
}
class Vector extends Vol {
constructor(size, value = 0.) {
super(1, 1, size, value);
}
}
function createVector(depth, bias) {
// bias == undefined will cause initialize
return new Vol(1, 1, depth, bias);
}
function createMatrix(m, n) {
// m * n Matrix, m: output, n: input
let filters = [];
for (let i = 0; i < m; i++) {
filters.push(new Vol(1, 1, n));
}
return filters;
}
function getVolFromJSON(json) {
return new Vol(0, 0, 0, 0).fromJSON(json);
}
export { Vol, createVector, createMatrix, getVolFromJSON, Constant, Vector };