internal static Tensor Permute(Tensor inTensor, int[] permutations) // TODO: unify Permute() arguments
        {
            var padPermutationsToBarracudaRank = TensorShape.MaxRank - permutations.Length;

            if (padPermutationsToBarracudaRank > 0)
            {
                permutations = permutations.Concat(Enumerable.Range(permutations.Length, padPermutationsToBarracudaRank)).ToArray();
            }
            Debug.Assert(permutations.Length == TensorShape.MaxRank);

            // 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 tempOutStrides = new int[TensorShape.MaxRank + 1];

            tempOutStrides[8] = 1;
            for (int i = 7; i >= 0; --i)
            {
                tempOutStrides[i] = tempOutStrides[i + 1] * outTensor.shape[i];
            }

            var outStride = new int[reversePermute.Length];

            for (var i = 0; i < reversePermute.Length; ++i)
            {
                outStride[i] = tempOutStrides[reversePermute[i] + 1];
            }

            // inTensor strides
            var inStrides = new int[TensorShape.MaxRank];

            inStrides[7] = 1;
            for (int i = 6; i >= 0; --i)
            {
                inStrides[i] = inStrides[i + 1] * inTensor.shape[i + 1];
            }

            for (var it = new TensorIterator(inTensor.shape); it.IsValid(); ++it)
            {
                outTensor[it.d0 * outStride[0] + it.d1 * outStride[1] + it.d2 * outStride[2] + it.d3 * outStride[3] + it.d4 * outStride[4] + it.d5 * outStride[5] + it.d6 * outStride[6] + it.d7 * outStride[7]] = inTensor[
                    it.d0 * inStrides[0] + it.d1 * inStrides[1] + it.d2 * inStrides[2] + it.d3 * inStrides[3] + it.d4 * inStrides[4] + it.d5 * inStrides[5] + it.d6 * inStrides[6] + it.d7 * inStrides[7]];
            }

            Profiler.EndSample();
            return(outTensor);
        }
예제 #2
0
        public ONNXTensor NonZero()
        {
            //https://github.com/onnx/onnx/blob/master/docs/Operators.md#NonZero
            //https://numpy.org/doc/stable/reference/generated/numpy.nonzero.html
            //Return the indices of the elements that are non-zero. Iterating row major c style.

            // pad with 1s to visit all elements at least once in the loop.
            int[] paddedONNXShape = new int[] { 1, 1, 1, 1, 1, 1, 1, 1 };
            for (int d = 0; d < rank; ++d)
            {
                paddedONNXShape[d] = shape[d];
            }

            // collect all non zero item
            List <int[]> nonZeroIndices = new List <int[]>();

            for (var it = new TensorIterator(m_Data.shape); it.IsValid(); it.Next())
            {
                if (Math.Abs(m_Data[it.index]) > Single.Epsilon)
                {
                    nonZeroIndices.Add(new int[] { it.d0, it.d1, it.d2, it.d3, it.d4, it.d5, it.d6, it.d7 });
                }
            }

            // store indices in dest tensor
            Tensor result = new Tensor(new TensorShape(rank, nonZeroIndices.Count));

            for (int i = 0; i < nonZeroIndices.Count; ++i)
            {
                for (int d = 0; d < rank; ++d)
                {
                    result[d, i] = nonZeroIndices[i][d];
                }
            }

            return(new ONNXTensor(result, new int[] { rank, nonZeroIndices.Count }));
        }