public override void Concat(Volume <double> right, Volume <double> result) { var batchSize = Math.Max(this.Shape.Dimensions[3], right.Shape.Dimensions[3]); if (this.Shape.TotalLength > 1 && right.Shape.TotalLength > 1) { var left = this.ReShape(new Shape(1, 1, -1, batchSize)); right = right.ReShape(new Shape(1, 1, -1, batchSize)); var elementPerBatch = result.Shape.TotalLength / batchSize; var threshold = left.Shape.Dimensions[2]; for (var n = 0; n < batchSize; n++) { for (var i = 0; i < elementPerBatch; i++) { result.Set(0, 0, i, n, i < threshold ? left.Get(0, 0, i, n) : right.Get(0, 0, i - threshold, n)); } } } else if (this.Shape.TotalLength == 1 && right.Shape.TotalLength > 1) { // Left volume is actually a scalar => broadcast its value right = right.ReShape(new Shape(1, 1, -1, batchSize)); var elementPerBatch = result.Shape.TotalLength / batchSize; const int threshold = 1; for (var n = 0; n < batchSize; n++) { for (var i = 0; i < elementPerBatch; i++) { result.Set(0, 0, i, n, i < threshold ? this.Get(0) : right.Get(0, 0, i - threshold, n)); } } } else { // Right volume is actually a scalar => broadcast its value var left = this.ReShape(new Shape(1, 1, -1, batchSize)); var elementPerBatch = result.Shape.TotalLength / batchSize; var threshold = left.Shape.Dimensions[2]; for (var n = 0; n < batchSize; n++) { for (var i = 0; i < elementPerBatch; i++) { result.Set(0, 0, i, n, i < threshold ? left.Get(0, 0, i, n) : right.Get(0)); } } } }
public override void DoSum(Volume <double> result) { var batchsize = this.Shape.GetDimension(3); var channel = this.Shape.GetDimension(2); var height = this.Shape.GetDimension(1); var width = this.Shape.GetDimension(0); var resultWIsOne = result.Shape.GetDimension(0) == 1; var resultHIsOne = result.Shape.GetDimension(1) == 1; var resultCIsOne = result.Shape.GetDimension(2) == 1; var resultNIsOne = result.Shape.GetDimension(3) == 1; for (int n = 0; n < batchsize; n++) { for (int c = 0; c < channel; c++) { for (int h = 0; h < height; h++) { for (int w = 0; w < width; w++) { var val = this.Get(w, h, c, n); var resultW = resultWIsOne ? 0 : w; var resultH = resultHIsOne ? 0 : h; var resultC = resultCIsOne ? 0 : c; var resultN = resultNIsOne ? 0 : n; var current = result.Get(resultW, resultH, resultC, resultN); result.Set(resultW, resultH, resultC, resultN, current + val); } } } } }
public override void Tile(Volume <double> reps, Volume <double> result) { var batchSize = this.Shape.Dimensions[3]; var channel = this.Shape.Dimensions[2]; var height = this.Shape.Dimensions[1]; var width = this.Shape.Dimensions[0]; var outputBatchSize = result.Shape.Dimensions[3]; var outputChannel = result.Shape.Dimensions[2]; var outputHeight = result.Shape.Dimensions[1]; var outputWidth = result.Shape.Dimensions[0]; for (var n = 0; n < outputBatchSize; n++) { for (var c = 0; c < outputChannel; c++) { for (var h = 0; h < outputHeight; h++) { for (var w = 0; w < outputWidth; w++) { result.Set(w, h, c, n, this.Get(w % width, h % height, c % channel, n % batchSize)); } } } } }
public override void Sum(Volume <double> result) { var batchSize = this.Shape.Dimensions[3]; var channel = this.Shape.Dimensions[2]; var height = this.Shape.Dimensions[1]; var width = this.Shape.Dimensions[0]; var resultWIsOne = result.Shape.Dimensions[0] == 1; var resultHIsOne = result.Shape.Dimensions[1] == 1; var resultCIsOne = result.Shape.Dimensions[2] == 1; var resultNIsOne = result.Shape.Dimensions[3] == 1; for (var n = 0; n < batchSize; n++) { for (var c = 0; c < channel; c++) { for (var h = 0; h < height; h++) { for (var w = 0; w < width; w++) { var val = this.Get(w, h, c, n); var resultW = resultWIsOne ? 0 : w; var resultH = resultHIsOne ? 0 : h; var resultC = resultCIsOne ? 0 : c; var resultN = resultNIsOne ? 0 : n; var current = result.Get(resultW, resultH, resultC, resultN); result.Set(resultW, resultH, resultC, resultN, current + val); } } } } }
public override void ConvolutionGradient(Volume <double> filters, Volume <double> outputGradients, Volume <double> filterGradient, int pad, int stride, Volume <double> inputGradient) { inputGradient.Clear(); // zero out gradient wrt bottom data, we're about to fill it var batchSize = this.Shape.Dimensions[3]; var inputWidth = this.Shape.Dimensions[0]; var inputHeight = this.Shape.Dimensions[1]; var outputWidth = outputGradients.Shape.Dimensions[0]; var outputHeight = outputGradients.Shape.Dimensions[1]; var outputDepth = outputGradients.Shape.Dimensions[2]; var filterWidth = filters.Shape.Dimensions[0]; var filterHeight = filters.Shape.Dimensions[1]; var filterDepth = filters.Shape.Dimensions[2]; for (var n = 0; n < batchSize; n++) { for (var depth = 0; depth < outputDepth; depth++) { var y = -pad; for (var ay = 0; ay < outputHeight; y += stride, ay++) { var x = -pad; for (var ax = 0; ax < outputWidth; x += stride, ax++) { // convolve centered at this particular location var chainGradient = outputGradients.Get(ax, ay, depth, n); // gradient from above, from chain rule for (var fy = 0; fy < filterHeight; fy++) { var oy = y + fy; // coordinates in the original input array coordinates for (var fx = 0; fx < filterWidth; fx++) { var ox = x + fx; if (oy >= 0 && oy < inputHeight && ox >= 0 && ox < inputWidth) { for (var fd = 0; fd < filterDepth; fd++) { filterGradient.Set(fx, fy, fd, depth, filterGradient.Get(fx, fy, fd, depth) + Get(ox, oy, fd, n) * chainGradient); inputGradient.Set(ox, oy, fd, n, inputGradient.Get(ox, oy, fd, n) + filters.Get(fx, fy, fd, depth) * chainGradient); } } } } } } } } }
public override void DoNorm1(Volume <double> result) { var batchSize = this.Shape.DimensionCount > 1 ? this.Shape.GetDimension(-1) : 1; var reshape = ReShape(-1, batchSize); var n = reshape.Shape.GetDimension(0); for (var i = 0; i < batchSize; i++) { var sum = 0.0; for (var j = 0; j < n; j++) { var d = reshape.Get(j, i); sum += Math.Abs(d); } result.Set(new[] { i }, sum); } }
public override void Transpose(Volume <double> result) { var expectedShape = new Shape(this.Shape.Dimensions[1], this.Shape.Dimensions[0], 1, this.Shape.Dimensions[3]); if (!result.Shape.Equals(expectedShape)) { throw new ArgumentException($"Result shape should be {expectedShape}"); } for (var n = 0; n < this.Shape.Dimensions[3]; n++) { for (var j = 0; j < this.Shape.Dimensions[1]; j++) { for (var i = 0; i < this.Shape.Dimensions[0]; i++) { result.Set(j, i, 0, n, this.Get(i, j, 0, n)); } } } }
public override Volume <double> Random(Shape shape, double mu = 0, double std = 1.0) { var vol = new Volume(new NcwhVolumeStorage <double>(shape)); for (var n = 0; n < shape.Dimensions[3]; n++) { for (var c = 0; c < shape.Dimensions[2]; c++) { for (var y = 0; y < shape.Dimensions[1]; y++) { for (var x = 0; x < shape.Dimensions[0]; x++) { vol.Set(x, y, c, n, RandomUtilities.Randn(mu, std)); } } } } return(vol); }
public override void DoSum(Volume <double> result) { var batchSize = this.Shape.DimensionCount > 1 ? this.Shape.GetDimension(-1) : 1; var inputReshape = ReShape(-1, batchSize); var n = inputReshape.Shape.GetDimension(0); if (batchSize > 1 && result.Shape.DimensionCount > 1 && result.Shape.GetDimension(3) == 1) { var resultReshape = result.ReShape(-1, 1); for (var j = 0; j < n; j++) { var sum = 0.0; // Sum over batch for (var i = 0; i < batchSize; i++) { var d = inputReshape.Get(j, i); sum += d; } resultReshape.Set(j, 0, sum); } } else { for (var i = 0; i < batchSize; i++) { var sum = 0.0; for (var j = 0; j < n; j++) { var d = inputReshape.Get(j, i); sum += d; } result.Set(new[] { i }, sum); } } }
public override Volume <double> Random(Shape shape, double mu = 0, double std = 1.0) { //RandomUtilities.RandomDoubleArray(shape.TotalLength, mu, std), shape) var vol = new Volume(new NcwhVolumeStorage <double>(shape)); for (int n = 0; n < shape.GetDimension(3); n++) { for (int c = 0; c < shape.GetDimension(2); c++) { for (int y = 0; y < shape.GetDimension(1); y++) { for (int x = 0; x < shape.GetDimension(0); x++) { vol.Set(x, y, c, n, RandomUtilities.Randn(mu, std)); } } } } return(vol); }
public override void Extract(int length, int offset, Volume <double> result) { var input = this.ReShape(1, 1, Shape.None, Shape.Keep); if (input.Shape.TotalLength == 1) { var v = input.Get(0); this.Storage.Map(x => v, result.Storage); } else { var batchSize = this.Shape.Dimensions[3]; for (var n = 0; n < batchSize; n++) { for (var i = 0; i < length; i++) { result.Set(0, 0, i, n, input.Get(0, 0, i + offset, n)); } } } }
public override void MatMultiply(Volume <double> right, Volume <double> result) { if (this.Shape.Dimensions[2] != 1 || right.Shape.Dimensions[2] != 1) { throw new ArgumentException($"Left and right volumes should be [w, h, 1, b]. left = {this.Shape} right = {right.Shape}"); } var broadCastLeft = this.Shape.Dimensions[3] == 1; var broadCastRight = right.Shape.Dimensions[3] == 1; if (this.Shape.Dimensions[3] != right.Shape.Dimensions[3] && !(broadCastLeft || broadCastRight)) { throw new ArgumentException($"Left and right volumes should have the same batch size. left = {this.Shape.Dimensions[3]} right = {right.Shape.Dimensions[3]}"); } var expectedShape = ComputeMatMultiplyShape(this.Shape, right.Shape); if (!result.Shape.Equals(expectedShape)) { throw new ArgumentException($"Result shape should be {expectedShape} but is {result.Shape}"); } for (var n = 0; n < this.Shape.Dimensions[3]; n++) { for (var i = 0; i < expectedShape.Dimensions[0]; i++) { for (var j = 0; j < expectedShape.Dimensions[1]; j++) { var cell = 0.0; for (var k = 0; k < this.Shape.Dimensions[0]; k++) { cell += this.Get(k, j, 0, broadCastLeft ? 0 : n) * right.Get(i, k, 0, broadCastRight ? 0 : n); } result.Set(i, j, 0, n, cell); } } } }
public override void DoMin(Volume <double> result) { var batchSize = this.Shape.DimensionCount > 1 ? this.Shape.GetDimension(-1) : 1; var reshape = ReShape(-1, batchSize); var n = reshape.Shape.GetDimension(0); for (var i = 0; i < batchSize; i++) { var min = double.MaxValue; for (var j = 0; j < n; j++) { var d = reshape.Get(j, i); if (d < min) { min = d; } } result.Set(new[] { i }, min); } }
public override void Max(Volume <double> result) { var batchSize = this.Shape.Dimensions[3]; var reshape = this.ReShape(-1, batchSize); var n = reshape.Shape.Dimensions[0]; for (var i = 0; i < batchSize; i++) { var max = double.MinValue; for (var j = 0; j < n; j++) { var d = reshape.Get(j, i); if (d > max) { max = d; } } result.Set(new[] { i }, max); } }