public override void DoConvolution(Volume <float> filters, int pad, int stride, Volume <float> result) { var batchSize = this.Shape.GetDimension(3); var inputWidth = this.Shape.GetDimension(0); var inputHeight = this.Shape.GetDimension(1); var outputWidth = result.Shape.GetDimension(0); var outputHeight = result.Shape.GetDimension(1); var outputDepth = result.Shape.GetDimension(2); var filterWidth = filters.Shape.GetDimension(0); var filterHeight = filters.Shape.GetDimension(1); var filterDepth = filters.Shape.GetDimension(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 a = 0.0f; 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++) { a += filters.Storage.Get(fx, fy, fd, depth) * this.Storage.Get(ox, oy, fd, n); } } } } result.Storage.Set(ax, ay, depth, n, a); } } } } }
protected override void DoConvolutionGradient(Volume <float> filters, Volume <float> outputGradients, Volume <float> inputGradient, Volume <float> filterGradient, int pad, int stride) { inputGradient.Clear(); // zero out gradient wrt bottom data, we're about to fill it var batchSize = this.Shape.GetDimension(3); var inputWidth = this.Shape.GetDimension(0); var inputHeight = this.Shape.GetDimension(1); var outputWidth = outputGradients.Shape.GetDimension(0); var outputHeight = outputGradients.Shape.GetDimension(1); var outputDepth = outputGradients.Shape.GetDimension(2); var filterWidth = filters.Shape.GetDimension(0); var filterHeight = filters.Shape.GetDimension(1); var filterDepth = filters.Shape.GetDimension(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++) { // xyStride var x = -pad; for (var ax = 0; ax < outputWidth; x += stride, ax++) { // xyStride // 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.Storage.Set(fx, fy, fd, depth, filterGradient.Get(fx, fy, fd, depth) + Get(ox, oy, fd, n) * chainGradient); inputGradient.Storage.Set(ox, oy, fd, n, inputGradient.Storage.Get(ox, oy, fd, n) + filters.Get(fx, fy, fd, depth) * chainGradient); } } } } } } } } }
public override void DoSigmoid(Volume <float> volume) { this.Storage.Map(x => (float)(1.0 / (1.0 + Math.Exp(-x))), volume.Storage); }
public override void DoTanhGradient(Volume <float> input, Volume <float> outputGradient, Volume <float> inputGradient) { this.Storage.Map((output, outGradient) => (1.0f - output * output) * outGradient, outputGradient.Storage, inputGradient.Storage); }
public override void DoSoftMaxGradient(Volume <float> outputGradient, Volume <float> inputGradient) { this.Storage.Map((input, outputG) => (outputG - 1) * input + input, outputGradient.Storage, inputGradient.Storage); }
public override void DoTanh(Volume <float> volume) { this.Storage.Map(x => (float)Math.Tanh(x), volume.Storage); }
public override void DoReluGradient(Volume <float> input, Volume <float> output, Volume <float> outputGradient) { this.Storage.Map((x, y) => x > 0 ? y : 0, output.Storage, outputGradient.Storage); }
public override void DoRelu(Volume <float> volume) { this.Storage.Map(x => x <= 0 ? 0 : x, volume.Storage); }
protected override void DoNegate(Volume <float> volume) { DoMultiply(volume, -1.0f); }
protected override void DoMultiply(Volume <float> result, float factor) { this.Storage.Map(x => x * factor, result.Storage); }
public override void DoAdd(Volume <float> other, Volume <float> result) { this.Storage.MapEx((x, y) => x + y, other.Storage, result.Storage); }