public override Vol forward(Vol V, bool is_training) { this.in_act = V; var N = this.out_depth; var V2 = new Vol(this.out_sx, this.out_sy, this.out_depth, 0.0); // optimization branch. If we're operating on 1D arrays we dont have // to worry about keeping track of x,y,d coordinates inside // input volumes. In convnets we do :( if (this.out_sx == 1 && this.out_sy == 1) { for (var i = 0; i < N; i++) { var ix = i * this.group_size; // base index offset var a = V.w[ix]; var ai = 0; for (var j = 1; j < this.group_size; j++) { var a2 = V.w[ix + j]; if (a2 > a) { a = a2; ai = j; } } V2.w[i] = a; this.switches[i] = ix + ai; } } else { var n = 0; // counter for switches for (var x = 0; x < V.sx; x++) { for (var y = 0; y < V.sy; y++) { for (var i = 0; i < N; i++) { var ix = i * this.group_size; var a = V.get(x, y, ix); var ai = 0; for (var j = 1; j < this.group_size; j++) { var a2 = V.get(x, y, ix + j); if (a2 > a) { a = a2; ai = j; } } V2.set(x, y, i, a); this.switches[n] = ix + ai; n++; } } } } this.out_act = V2; return(this.out_act); }
public static Vol img_to_vol(Bitmap img, bool convert_grayscale) { ImageConverter converter = new ImageConverter(); var p = (byte[])converter.ConvertTo(img, typeof(byte[])); var W = img.Width; var H = img.Height; Stack <double> pv = new Stack <double>(); for (var i = 0; i < p.Length; i++) { pv.Push(p[i] / 255.0 - 0.5); // normalize image pixels to [-0.5, 0.5] } var x = new Vol(W, H, 4, 0.0); //input volume (image) x.w = pv.ToArray(); if (convert_grayscale) { // flatten into depth=1 array var x1 = new Vol(W, H, 1, 0.0); for (var i = 0; i < W; i++) { for (var j = 0; j < H; j++) { x1.set(i, j, 0, x.get(i, j, 0)); } } x = x1; } return(x); }
public override Vol forward(Vol V, bool is_training) { this.in_act = V; var A = new Vol(this.out_sx, this.out_sy, this.out_depth, 0.0); var n = 0; // a counter for switches for (var d = 0; d < this.out_depth; d++) { var x = -this.pad; var y = -this.pad; for (var ax = 0; ax < this.out_sx; x += this.stride, ax++) { y = -this.pad; for (var ay = 0; ay < this.out_sy; y += this.stride, ay++) { // convolve centered at this particular location double a = -99999; // hopefully small enough ;\ int winx = -1, winy = -1; for (var fx = 0; fx < this.sx; fx++) { for (var fy = 0; fy < this.sy; fy++) { var oy = y + fy; var ox = x + fx; if (oy >= 0 && oy < V.sy && ox >= 0 && ox < V.sx) { var v = V.get(ox, oy, d); // perform max pooling and store pointers to where // the max came from. This will speed up backprop // and can help make nice visualizations in future if (v > a) { a = v; winx = ox; winy = oy; } } } } this.switchx[n] = winx; this.switchy[n] = winy; n++; A.set(ax, ay, d, a); } } } this.out_act = A; return(this.out_act); }
public override Vol forward(Vol V, bool is_training) { // optimized code by @mdda that achieves 2x speedup over previous version this.in_act = V; var A = new Vol(this.out_sx | 0, this.out_sy | 0, this.out_depth | 0, 0.0); var V_sx = V.sx | 0; var V_sy = V.sy | 0; var xy_stride = this.stride | 0; for (var d = 0; d < this.out_depth; d++) { var f = this.filters[d]; var x = -this.pad | 0; var y = -this.pad | 0; for (var ay = 0; ay < this.out_sy; y += xy_stride, ay++) // xy_stride { x = -this.pad | 0; for (var ax = 0; ax < this.out_sx; x += xy_stride, ax++) // xy_stride // convolve centered at this particular location { var a = 0.0; for (var fy = 0; fy < f.sy; fy++) { var oy = y + fy; // coordinates in the original input array coordinates for (var fx = 0; fx < f.sx; fx++) { var ox = x + fx; if (oy >= 0 && oy < V_sy && ox >= 0 && ox < V_sx) { for (var fd = 0; fd < f.depth; fd++) { // avoid function call overhead (x2) for efficiency, compromise modularity :( a += f.w[((f.sx * fy) + fx) * f.depth + fd] * V.w[((V_sx * oy) + ox) * V.depth + fd]; } } } } a += this.biases.w[d]; A.set(ax, ay, d, a); } } } this.out_act = A; return(this.out_act); }