/// <summary> /// Intended for use with data augmentation /// </summary> /// <param name="volume">Input volume</param> /// <param name="crop">Size of output</param> /// <param name="dx">Offset wrt incoming volume, of the shift</param> /// <param name="dy">Offset wrt incoming volume, of the shift</param> /// <param name="flipLeftRight">flip left/right</param> /// <returns></returns> public static Volume Augment(this Volume volume, int crop, int dx = -1, int dy = -1, bool flipLeftRight = false) { if (dx == -1) { dx = Random.Next(volume.Width - crop); } if (dy == -1) { dy = Random.Next(volume.Height - crop); } // randomly sample a crop in the input volume Volume w; if (crop != volume.Width || dx != 0 || dy != 0) { w = new Volume(crop, crop, volume.Depth, 0.0); for (var x = 0; x < crop; x++) { for (var y = 0; y < crop; y++) { if (x + dx < 0 || x + dx >= volume.Width || y + dy < 0 || y + dy >= volume.Width) { continue; // oob } for (var depth = 0; depth < volume.Depth; depth++) { w.Set(x, y, depth, volume.Get(x + dx, y + dy, depth)); // copy data over } } } } else { w = volume; } if (flipLeftRight) { // flip volume horziontally var w2 = w.CloneAndZero(); for (var x = 0; x < w.Width; x++) { for (var y = 0; y < w.Height; y++) { for (var depth = 0; depth < w.Depth; depth++) { w2.Set(x, y, depth, w.Get(w.Width - x - 1, y, depth)); // copy data over } } } w = w2; //swap } return(w); }
public override Volume Forward(Volume input, bool isTraining = false) { this.InputActivation = input; var outputActivation = new Volume(this.OutputWidth, this.OutputHeight, this.OutputDepth, 0.0); #if PARALLEL Parallel.For(0, this.OutputDepth, depth => #else for (var depth = 0; depth < this.OutputDepth; depth++) #endif { var n = depth * this.OutputWidth * this.OutputHeight; // a counter for switches var x = -this.Pad; var y = -this.Pad; for (var ax = 0; ax < this.OutputWidth; x += this.Stride, ax++) { y = -this.Pad; for (var ay = 0; ay < this.OutputHeight; y += this.Stride, ay++) { // convolve centered at this particular location var a = double.MinValue; int winx = -1, winy = -1; for (var fx = 0; fx < this.Width; fx++) { for (var fy = 0; fy < this.Height; fy++) { var oy = y + fy; var ox = x + fx; if (oy >= 0 && oy < input.Height && ox >= 0 && ox < input.Width) { var v = input.Get(ox, oy, depth); // 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++; outputActivation.Set(ax, ay, depth, a); } } }
/// <summary> /// Intended for use with data augmentation /// </summary> /// <param name="volume">Input volume</param> /// <param name="crop">Size of output</param> /// <param name="dx">Offset wrt incoming volume, of the shift</param> /// <param name="dy">Offset wrt incoming volume, of the shift</param> /// <param name="flipLeftRight">flip left/right</param> /// <returns></returns> public static IVolume Augment(this Volume volume, int crop, int dx = -1, int dy = -1, bool flipLeftRight = false) { if (dx == -1) { dx = Random.Next(volume.Width - crop); } if (dy == -1) { dy = Random.Next(volume.Height - crop); } // randomly sample a crop in the input volume Volume w; if (crop != volume.Width || dx != 0 || dy != 0) { w = new Volume(crop, crop, volume.Depth, 0.0); for (var x = 0; x < crop; x++) { for (var y = 0; y < crop; y++) { if (x + dx < 0 || x + dx >= volume.Width || y + dy < 0 || y + dy >= volume.Width) { continue; // oob } for (var depth = 0; depth < volume.Depth; depth++) { w.Set(x, y, depth, volume.Get(x + dx, y + dy, depth)); // copy data over } } } } else { w = volume; } IVolume result = w; if (flipLeftRight) { result = w.Flip(FlipMode.LeftRight); } return(result); }
public static Volume Flip(this Volume volume, FlipMode mode) { Volume result = volume; if (mode == FlipMode.LeftRight || mode == FlipMode.Both) { // flip volume horziontally var w = volume.CloneAndZero(); for (var x = 0; x < volume.Width; x++) { for (var y = 0; y < volume.Height; y++) { for (var depth = 0; depth < volume.Depth; depth++) { w.Set(x, y, depth, volume.Get(volume.Width - x - 1, y, depth)); // copy data over } } } result = w; //swap } if (mode == FlipMode.UpDown || mode == FlipMode.Both) { // flip volume horziontally var w = volume.CloneAndZero(); for (var x = 0; x < volume.Width; x++) { for (var y = 0; y < volume.Height; y++) { for (var depth = 0; depth < volume.Depth; depth++) { w.Set(x, y, depth, result.Get(x, volume.Height - y - 1, depth)); // copy data over } } } result = w; //swap } return(result); }
public override Volume Forward(Volume input, bool isTraining = false) { this.InputActivation = input; var outputActivation = new Volume(this.OutputWidth, this.OutputHeight, this.OutputDepth, 0.0); #if PARALLEL Parallel.For(0, this.OutputDepth, depth => #else for (var depth = 0; depth < this.OutputDepth; depth++) #endif { var n = depth * this.OutputWidth * this.OutputHeight; // a counter for switches var x = -this.Pad; var y = -this.Pad; for (var ax = 0; ax < this.OutputWidth; x += this.Stride, ax++) { y = -this.Pad; for (var ay = 0; ay < this.OutputHeight; y += this.Stride, ay++) { // convolve centered at this particular location var a = double.MinValue; int winx = -1, winy = -1; for (var fx = 0; fx < this.Width; fx++) { for (var fy = 0; fy < this.Height; fy++) { var oy = y + fy; var ox = x + fx; if (oy >= 0 && oy < input.Height && ox >= 0 && ox < input.Width) { var v = input.Get(ox, oy, depth); // 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++; outputActivation.Set(ax, ay, depth, a); } } } #if PARALLEL ); #endif this.OutputActivation = outputActivation; return this.OutputActivation; }
public override Volume Forward(Volume input, bool isTraining = false) { this.InputActivation = input; var depth = this.OutputDepth; var outputActivation = new Volume(this.OutputWidth, this.OutputHeight, this.OutputDepth, 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.OutputWidth == 1 && this.OutputHeight == 1) { for (var i = 0; i < depth; i++) { var ix = i * this.GroupSize; // base index offset var a = input.Weights[ix]; var ai = 0; for (var j = 1; j < this.GroupSize; j++) { var a2 = input.Weights[ix + j]; if (a2 > a) { a = a2; ai = j; } } outputActivation.Weights[i] = a; this.switches[i] = ix + ai; } } else { var n = 0; // counter for switches for (var x = 0; x < input.Width; x++) { for (var y = 0; y < input.Height; y++) { for (var i = 0; i < depth; i++) { var ix = i * this.GroupSize; var a = input.Get(x, y, ix); var ai = 0; for (var j = 1; j < this.GroupSize; j++) { var a2 = input.Get(x, y, ix + j); if (a2 > a) { a = a2; ai = j; } } outputActivation.Set(x, y, i, a); this.switches[n] = ix + ai; n++; } } } } this.OutputActivation = outputActivation; return(this.OutputActivation); }
public override Volume Forward(Volume input, bool isTraining = false) { this.InputActivation = input; var depth = this.OutputDepth; var outputActivation = new Volume(this.OutputWidth, this.OutputHeight, this.OutputDepth, 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.OutputWidth == 1 && this.OutputHeight == 1) { for (var i = 0; i < depth; i++) { var ix = i * this.GroupSize; // base index offset var a = input.Weights[ix]; var ai = 0; for (var j = 1; j < this.GroupSize; j++) { var a2 = input.Weights[ix + j]; if (a2 > a) { a = a2; ai = j; } } outputActivation.Weights[i] = a; this.switches[i] = ix + ai; } } else { var n = 0; // counter for switches for (var x = 0; x < input.Width; x++) { for (var y = 0; y < input.Height; y++) { for (var i = 0; i < depth; i++) { var ix = i * this.GroupSize; var a = input.Get(x, y, ix); var ai = 0; for (var j = 1; j < this.GroupSize; j++) { var a2 = input.Get(x, y, ix + j); if (a2 > a) { a = a2; ai = j; } } outputActivation.Set(x, y, i, a); this.switches[n] = ix + ai; n++; } } } } this.OutputActivation = outputActivation; return this.OutputActivation; }