首页 > 解决方案 > 如何在 C# 中创建 TensorProto,方法与 Python 相同

问题描述

我得到了以下 python 片段,用于调用 Tensorflow 模型

# Create prediction request object
request = predict_pb2.PredictRequest()

# Specify model name (must be the same as when the TensorFlow serving serving was started)
request.model_spec.name = FLAGS.model_name

# Specify signature name (should be the same as specified when exporting model)
request.model_spec.signature_name = FLAGS.signature_name



data={}

image=cv2.imread(FLAGS.input_image)
image=np.expand_dims(image, axis=0)
request.inputs['inputs'].CopyFrom(tf.contrib.util.make_tensor_proto(image))
start=time.time()
# Call the prediction server
result = stub.Predict(request, 10)  # 10 secs timeout

我正在尝试将此调用合并到我的 asp.net core 3.1 应用程序中。我已经使用 openCV 成功创建了一个 docker 图像,并且可以将我的图像加载到 Mat 中。我无法弄清楚如何复制以下方法。

图像=np.expand_dims(图像,轴=0)

tf.contrib.util.make_tensor_proto(图像)

到目前为止,这是我的代码

    public Task GetSignatures(IEnumerable<string> filenames)
    {
        Channel channel = new Channel("172.17.0.4:8500", ChannelCredentials.Insecure);
        var client = new ModelService.ModelServiceClient(channel);
        var request = new GetModelStatusRequest
        {
            ModelSpec = new ModelSpec
            {
                Name = "model"
            }
        };
        var reply = client.GetModelStatus(request);

        var pClient = new PredictionService.PredictionServiceClient(channel);

        foreach (string filename in filenames)
        {
            TensorProto tensor = GetTensorProto(filename);
            PredictRequest pRequest = new PredictRequest();
            pRequest.ModelSpec = new ModelSpec() { Name = "model" };
            pRequest.Inputs.Add("inputs", tensor);
            DateTime deadline = DateTime.UtcNow.AddSeconds(2000);
            PredictResponse response = pClient.Predict(pRequest, new CallOptions(deadline: deadline));
        }


    }

    private TensorProto GetTensorProto(string filename)
    {
        using Mat mat = new Mat(filename);
        byte[] bytes = mat.ToBytes();
        ByteString imageData = ByteString.CopyFrom(bytes);

        TensorProto tensorProto = new TensorProto();

        Dim dimBatch = new Dim() { Name = "batch", Size = 1 };
        Dim dimData = new Dim() { Name = "data", Size = 1 };

        TensorShapeProto tensorShape = new TensorShapeProto();
        tensorShape.Dim.Add(dimBatch);
        tensorShape.Dim.Add(dimData);

        tensorProto.TensorShape = tensorShape;

        tensorProto.Dtype = DataType.DtUint8;
        tensorProto.StringVal.Add(imageData);

        return tensorProto;
    }

我收到以下错误

 rpc.Core.RpcException: Status(StatusCode=InvalidArgument, Detail="slice index 1 of dimension 0 out of bounds.
 [[{{node Preprocessor/map/while/ResizeToRange/strided_slice_1}}]]")

标签: c#pythontensorflowasp.net-core

解决方案


这篇文章有点晚了,但我遇到了类似的问题并努力寻找任何资源。我对这种机器学习的东西还很陌生,但我想我知道了其中的一部分。

在 python 中,如果您运行以下命令,您可以找到有关矩阵的更多信息:

# tell us it's a numpy.ndarray
print(type(image))
# tells us the dimensions of the array -4 dimensions 
print(image.ndim) 
# tells us the shape - (1, height of image, width of image, RGB)
print(image.shape) 

然后在 C# 中,我能够像这样将这些维度添加到我的张量原型中:

var imageFeatureShape = new TensorShapeProto();

// define our matrix dimensions that we will populate with data. [1, Img.Height, Img.Width, RGB] 
imageFeatureShape.Dim.Add(new TensorShapeProto.Types.Dim() { Size = 1 }); // first dimension in our matrix
imageFeatureShape.Dim.Add(new TensorShapeProto.Types.Dim() { Size = imageHeight }); //second dimension in our matrix 
imageFeatureShape.Dim.Add(new TensorShapeProto.Types.Dim() { Size = imageWidth }); //third dimension in our matrix
imageFeatureShape.Dim.Add(new TensorShapeProto.Types.Dim() { Size = 3 }); // fourth dimension - RGB values

这是我在 C# 中从文件名转换为张量原型的整个帮助文件。希望这可以帮助某人。

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using Tensorflow;

namespace TRANS_AI_BASE.DATA.Services
{
    public class ImageToTensorProto: IImageToTensorProto
    {

        /// <summary>
        ///  Exposed helper function that creates our TensorProto object from our fileInput
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        public TensorProto GetTensorProto(string filename)
        {
            // create bitmap from file
            Bitmap image = new Bitmap(filename);
            // convert bitmap to RGB Array/Matrix where values are the individual RGB values from 0-255
            var imageDimArray = ConvertImageStreamToDimArraysColor(image);
            // take the RGB value array and convert it into a 4 dimensional matrix tensor protoe
            var imageTensor = CreateTensorFromImage(imageDimArray, image.Width, image.Height);

            return imageTensor;

        }







        /// <summary>
        /// Function to return dim Array, Calls two sub functions to do actual work. 
        /// </summary>
        /// <param name="bitmap"></param>
        /// <returns></returns>
        private static (int, int, int)[][] ConvertImageStreamToDimArraysColor(Bitmap bitmap)
        {
            // Convert Bitmap to Byte Array
            var bitmapArray = BitmapToByteArrayColor(bitmap);
            using (var memoryStream = new MemoryStream(bitmapArray))
            {
                memoryStream.Position = 0;
                // Take byte array and convert it to RGB Matrix format(maybe the same as a tuple array in C#?)
                return ConvertImageDataToDimArraysColor(bitmap.Height, bitmap.Width, memoryStream);
            }
        }

        /// <summary>
        /// Convert Bitmap to a byte array
        /// </summary>
        /// <param name="bitmap"></param>
        /// <returns></returns>
        private static byte[] BitmapToByteArrayColor(Bitmap bitmap)
        {
            BitmapData bmpdata = null;

            try
            {
                bmpdata = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
                int numbytes = bmpdata.Stride * bitmap.Height;
                var bytedata = new byte[numbytes];
                var ptr = bmpdata.Scan0;
                Marshal.Copy(ptr, bytedata, 0, numbytes);
                return bytedata;
            }
            finally
            {
                if (bmpdata != null)
                    bitmap.UnlockBits(bmpdata);
            }
        }


        /// <summary>
        /// Convert Byte Array to Dim Array (RGB matrix) format for tensorflow
        /// </summary>
        /// <param name="numRows"></param>
        /// <param name="numCols"></param>
        /// <param name="stream"></param>
        /// <returns></returns>
        private static (int, int, int)[][] ConvertImageDataToDimArraysColor(int numRows, int numCols, MemoryStream stream)
        {
            var imageMatrix = new (int, int, int)[numRows][];
            for (int row = 0; row < numRows; row++)
            {
                imageMatrix[row] = new (int, int, int)[numCols];
                for (int col = 0; col < numCols; ++col)
                {
                    imageMatrix[row][col] = (stream.ReadByte(), stream.ReadByte(), stream.ReadByte());
                }
            }
            return imageMatrix;
        }



        /// <summary>
        /// Create our Tensor Proto. Basemodel expect a matrix of [1, Img.Width, Img.Height, RGB]
        /// </summary>
        /// <param name="imageData"></param>
        /// <returns></returns>
        private static TensorProto CreateTensorFromImage((int b, int g, int r)[][] imageData, int imageWidth, int imageHeight)
        {
            var imageFeatureShape = new TensorShapeProto();

            // define our matrix dimensions that we will populate with data. [1, Img.Width, Img.Height, RGB] 
            imageFeatureShape.Dim.Add(new TensorShapeProto.Types.Dim() { Size = 1 }); // first dimension in our matrix
            imageFeatureShape.Dim.Add(new TensorShapeProto.Types.Dim() { Size = imageHeight }); //second dimension in our matrix 
            imageFeatureShape.Dim.Add(new TensorShapeProto.Types.Dim() { Size = imageWidth }); //third dimension in our matrix
            imageFeatureShape.Dim.Add(new TensorShapeProto.Types.Dim() { Size = 3 }); // fourth dimension - RGB values - the values we really care about most

            // create a TensorProto and add our tensor shape and datatype values to it
            var imageTensorBuilder = new TensorProto();
            imageTensorBuilder.Dtype = DataType.DtUint8; // Basemodel (Faster rcnn/resnet 101) expects values of Uint8, AKA byte in C#
            imageTensorBuilder.TensorShape = imageFeatureShape;


            // loop through essentially the image height or rows of the matrix
            for (int i = 0; i < imageData.Length; ++i)
            {
                //  loop through each rows columns or image width
                for (int j = 0; j < imageData[i].Length; ++j)
                {
                    // it's hard to find documentation on this stuff. It's by Google, not Microsoft
                    // developers.google.com/protocol-buffers/docs/reference/csharp
                    // add the current pixle RGB values to the imageTensorBuilder (tensorProto), but in B.G.R. order
                    imageTensorBuilder.IntVal.Add(imageData[i][j].b);
                    imageTensorBuilder.IntVal.Add(imageData[i][j].g);
                    imageTensorBuilder.IntVal.Add(imageData[i][j].r);
                }
               
               
            }

            // useful to compare the count here to the numpy array in python
            //var a = imageTensorBuilder.IntVal.Count;

            return imageTensorBuilder;
        }

    }
}

留下我在下面使用的来源:


推荐阅读