Пример #1
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);
                        }
                    }
                }
            }
        }
Пример #2
0
        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);
                        }
                    }
                }
            }
        }
Пример #3
0
        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);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Пример #4
0
        public override void PoolGradient(Volume <double> input, Volume <double> outputGradient,
                                          int windowWidth, int windowHeight,
                                          int horizontalPad, int verticalPad, int horizontalStride, int verticalStride,
                                          Volume <double> inputGradient)
        {
            var inputWidth  = input.Shape.Dimensions[0];
            var inputHeight = input.Shape.Dimensions[1];

            var outputWidth  = outputGradient.Shape.Dimensions[0];
            var outputHeight = outputGradient.Shape.Dimensions[1];
            var outputDepth  = outputGradient.Shape.Dimensions[2];
            var batchSize    = outputGradient.Shape.Dimensions[3];

            for (var n = 0; n < batchSize; n++)
            {
                for (var depth = 0; depth < outputDepth; depth++)
                {
                    var x = -horizontalPad;
                    for (var ax = 0; ax < outputWidth; x += verticalStride, ax++)
                    {
                        var y = -verticalPad;
                        for (var ay = 0; ay < outputHeight; y += horizontalStride, ay++)
                        {
                            var a = double.MinValue;
                            int winx = -1, winy = -1;

                            for (var fx = 0; fx < windowWidth; fx++)
                            {
                                for (var fy = 0; fy < windowHeight; fy++)
                                {
                                    var oy = y + fy;
                                    var ox = x + fx;
                                    if (oy < 0 || oy >= inputHeight || ox < 0 || ox >= inputWidth)
                                    {
                                        continue;
                                    }

                                    var v = input.Get(ox, oy, depth, n);
                                    // 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;
                                    }
                                }
                            }

                            var chainGradient = outputGradient.Get(ax, ay, depth, n);
                            inputGradient.Storage.Set(winx, winy, depth, n, chainGradient);
                        }
                    }
                }
            }
        }
Пример #5
0
        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));
                    }
                }
            }
        }
Пример #6
0
        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);
                    }
                }
            }
        }