Beispiel #1
0
        internal static Tensor Permute(Tensor inTensor, int[] permutations) // TODO: unify Permute() arguments
        {
            // See: https://stackoverflow.com/a/32034565

            Profiler.BeginSample("ONNXTensor.Permute");
            var outTensor = new Tensor(ONNXLayout.Permute(inTensor.shape.ToArray(), permutations));

            Debug.Assert(outTensor.length == inTensor.length);

            // {0, 2, 3, 1} => {0, 3, 1, 2}
            // {2, 3, 1, 0} => {3, 2, 0, 1}
            //              => {find_index(0), find_index(1), find_index(2), find_index(3)}
            var reversePermute = new int[permutations.Length];

            for (var i = 0; i < permutations.Length; ++i)
            {
                reversePermute[i] = Array.IndexOf(permutations, i);
            }

            // outTensor strides
            var outStrideC   = outTensor.channels;
            var outStrideWC  = outStrideC * outTensor.width;
            var outStrideHWC = outStrideWC * outTensor.height;

            var outStride = new int[reversePermute.Length];

            for (var i = 0; i < reversePermute.Length; ++i)
            {
                outStride[i] = new[] { 0, outStrideHWC, outStrideWC, outStrideC, 1 }
            }
Beispiel #2
0
        public ONNXTensor Permute(int[] permutations)
        {
            // transpose both data & shape
            var transposedData  = Permute(m_Data, permutations);
            var transposedShape = ONNXLayout.Permute(m_Shape, permutations);

            return(new ONNXTensor(transposedData, transposedShape));
        }
        // Complex attribute helpers
        private int[] GetPads()
        {
            var noPadding = new[] { 0, 0, 0, 0 };

            if (SupportsAutoPad)
            {
                // known_paddings = {
                //     'VALID' : [0,0,0,0],
                //     'SAME_UPPER'  : [-1],
                //     'SAME_LOWER'  : [-2],
                // }
                var autoPad = GetOptionalString("auto_pad", "NOTSET");
                if (autoPad == "VALID")
                {
                    return(noPadding);
                }
                else if (autoPad == "SAME_UPPER")
                {
                    return new[] { -1 }
                }
                ;
                else if (autoPad == "SAME_LOWER")
                {
                    return new[] { -2 }
                }
                ;
                else
                {
                }       // TODO: Assert NOTSET
            }

            // NOTE: ONNX has pad layout of [z, y, x ...] while Barracuda is opposite [x, y, z ...]
            var pads = GetOptionalIntArray("pads", noPadding);

            if (SupportsSpatialOnlyPads)
            {
                // See: https://github.com/onnx/onnx/blob/master/docs/Operators.md#AveragePool
                // Padding for the beginning and ending along each spatial axis, it can take any value greater than or equal to 0.
                // The value represent the number of pixels added to the beginning and end part of the corresponding axis.
                // `pads` format should be as follow [x1_begin, x2_begin...x1_end, x2_end,...],
                // where xi_begin the number of pixels added at the beginning of axis `i` and xi_end,
                // the number of pixels added at the end of axis `i`.

                switch (pads.Length)
                {
                case 2: return(new [] { pads[0], 0, pads[1], 0 });             // 1D WW => W_W_

                case 4: return(new [] { pads[1], pads[0], pads[3], pads[2] }); // 2D HWHW => WHWH

                case 6: Warn("3D pads are not supported yet!");
                    return(new [] { pads[2], pads[1], pads[0], pads[3], pads[4], pads[5] });    // TODO: 3D DHWDHW => WHDWHD

                default:
                    throw new OnnxLayerImportException(
                              $"Attribute pads of unsupported length {pads.Length} in {Name} ot fype {OperatorType}.");
                }
            }

            // See: https://github.com/onnx/onnx/blob/master/docs/Operators.md#Pad
            // `pads` should be a 1D tensor of shape [2 * input_rank].
            // `pads` format should be: [x1_begin, x2_begin,...,x1_end, x2_end,...],
            // where xi_begin is the number of pad values added at the beginning of axis `i` and xi_end,
            // the number of pad values added at the end of axis `i

            Debug.Assert(pads.Length % 2 == 0);
            long[] onnxStarts = new long[pads.Length / 2];//TODO make the semantic diff between Permute(int[] and Permute(long[] more clear.
            long[] onnxEnds   = new long[pads.Length / 2];
            for (int i = 0; i < onnxStarts.Length; ++i)
            {
                onnxStarts[i] = (long)pads[i];
                onnxEnds[i]   = (long)pads[i + onnxStarts.Length];
            }
            var starts = ONNXLayout.Permute(onnxStarts, "NCHW");
            var ends   = ONNXLayout.Permute(onnxEnds, "NCHW");

            if ((starts[0] != 0) || (starts[3] != 0) || (ends[0] != 0) || (ends[3] != 0))
            {
                Warn($"Unsupported padding, only H and W padding are supported. Value will be ignored and defaulted to 0.");
            }

            return(new int[] { starts[2], starts[1], ends[2], ends[1] });
        }