對DenseTensor進行Transpose

ML.NET 是微軟推出的爲. NET 平臺設計的深度學習庫,通過這個東西(ModelBuilder)可以自己構建模型,並用於後來的推理與數據處理。雖然設計是很好的,但是由於現在的 AI 發展基本上都以 python 實現作爲基礎,未來這個東西的發展不好說,特別是模型構建部分。我個人認爲,它提供的最有價值的場景是:算法組的同學進行模型構建,然後導出 onnx 格式模型,由 ML.NET 加載並應用於生產環境中。這個流程可以進行持續集成與持續部署,性能也不錯。此外,後端人員不需要太多 AI 相關知識,只需要瞭解怎麼處理結果就可以了,這樣降低了部署的門檻。

按照這個思路,最近使用 ML. NET 加載 pytorch 導出的 onnx 模型進行推理時,由於模型的輸出的行順序做了調整,我在利用之前需要進行一個 transpose 操作。

請分清楚 reshape 與 transpose 操作的區別,兩者有本質不同。

但是 ML.NET 自帶的數據功能太少了,後來找了一圈,發現 ML. NET 的 ONNXRUNTIME 設計之初就沒有考慮過對其的後續數據處理,他們認爲後續處理應當是屬於另外過程的問題,需要使用其他的手段來處理數據變換等操作。

不得不說貌似非常有道理,我理解還是太膚淺了,最後使用了很多方法,甚至自己去實現了一個,但是感覺好像有點問題,不能白寫,貼在這裏了。

//用法
TransposeHelper.TransposeDimensions(w, new int[] { 1, 3, 80, 80, 57 }, new int[] { 1, 3, 57, 80, 80 }, new int[] { 0, 1, 4, 2, 3 })


	//貌似還是有點問題
    internal class TransposeHelper
    {
        public static float[] TransposeDimensions(float[] data, int[] inputShape, int[] outputShape, int[] permutation)
        {
            var rank = inputShape.Length;
            var indices = Enumerable.Range(0, rank).ToArray();
            var transposedIndices = permutation ?? indices.Reverse().ToArray();

            if (inputShape.Length != transposedIndices.Length || inputShape.Length != outputShape.Length)
            {
                throw new ArgumentException("Invalid input shape, output shape or permutation.");
            }

            var transposedData = new float[data.Length];
            var index = new int[rank];

            for (var i = 0; i < data.Length; i++)
            {
                index = GetIndex(i, index, inputShape);
                var transposedIndex = GetTransposedIndex(index, transposedIndices);
                var transposedOffset = GetOffset(transposedIndex, outputShape);
                transposedData[transposedOffset] = data[i];
            }

            return transposedData;
        }

        private static int[] GetIndex(int i, int[] index, int[] shape)
        {
            for (var j = shape.Length - 1; j >= 0; j--)
            {
                var div = 1;

                for (var k = j - 1; k >= 0; k--)
                {
                    div *= shape[k];
                }

                index[j] = i / div % shape[j];
            }

            return index;
        }

        private static int[] GetTransposedIndex(int[] index, int[] transposedIndices)
        {
            var transposedIndex = new int[index.Length];

            for (var i = 0; i < index.Length; i++)
            {
                transposedIndex[i] = index[transposedIndices[i]];
            }

            return transposedIndex;
        }

        private static int GetOffset(int[] index, int[] shape)
        {
            var offset = 0;
            var stride = 1;

            for (var i = shape.Length - 1; i >= 0; i--)
            {
                offset += index[i] * stride;
                stride *= shape[i];
            }

            return offset;
        }

    }

活不能不幹,總得想想辦法,經過查找,發現 NumSharp 支持 numpy 的 transpose 功能,實現起來和在 numpy 上一樣簡單:

NumSharp 實現在 C# 上用 numpy 的語法實現其功能,以下代碼使用 RoslynPad 運行並測試。

#r "nuget: NumSharp, 0.30.0"  
#r "nuget: System.Numerics.Tensors, 0.1.0"  
  
using System.Numerics.Tensors;  
using NumSharp.Utilities;  
using NumSharp;  
  
var tensor = new DenseTensor<float>(new float[] { 1, 2, 3, 4, 5, 6 }, new[] { 2, 3 });  
//tensor.Dump();  
tensor.Reshape(new int[]{ 3, 2}).Dump();  
NDArray nDArray = new NDArray(tensor.ToArray(), new Shape(new []{ 2, 3}));  
//nDArray.Dump();  
nDArray = nDArray.transpose(new int[]{1,0});  
nDArray.Dump();
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章