微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

无法从 Customvision 的 ONNX 模型中获得正确的预测

如何解决无法从 Customvision 的 ONNX 模型中获得正确的预测

我正在评估 customvision.ai 以训练图像分类模型,然后将该模型下载为 onnx 文件,该文件将在 .Net Windows 表单应用程序中使用。

我创建了一个新项目,上传了几张图片标记了它们,并且能够从 Customvision.ai 中的模型中获取预测。模型的准确性是可以接受的。 CustomVision 允许您将模型下载为 ONNX 文件,该文件可以部署在跨平台应用程序中。就我而言,我计划在 Windows 表单应用程序中部署和使用该模型。

当我将模型下载为 onnx 时,我会收到一个包含 .onnx 文件和其他一些文件的 zip 文件

其中一个文件Metadata_properties.json,内容如下:

{
    "CustomVision.Metadata.AdditionalModelInfo": "","CustomVision.Metadata.Version": "1.2","CustomVision.Postprocess.Method": "ClassificationMultiClass","CustomVision.Postprocess.Yolo.Biases": "[]","CustomVision.Postprocess.Yolo.NmsThreshold": "0.0","CustomVision.Preprocess.CropHeight": "0","CustomVision.Preprocess.CropMethod": "FullImageShorterSide","CustomVision.Preprocess.CropWidth": "0","CustomVision.Preprocess.MaxDimension": "0","CustomVision.Preprocess.MaxScale": "0.0","CustomVision.Preprocess.MinDimension": "0","CustomVision.Preprocess.MinScale": "0.0","CustomVision.Preprocess.normalizeMean": "[0.0,0.0,0.0]","CustomVision.Preprocess.normalizeStd": "[1.0,1.0,1.0]","CustomVision.Preprocess.ResizeMethod": "Stretch","CustomVision.Preprocess.TargetHeight": "300","CustomVision.Preprocess.TargetWidth": "300","Image.BitmapPixelFormat": "Rgb8","Image.ColorSpaceGamma": "SRGB","Image.NominalPixelRange": "normalized_0_1"
}

我从这个文件中了解到,提供给模型进行推理的最终张量需要拉伸调整为 300x300,在 0 和 1 之间标准化,均值设置为零,stdev 设置为 1。为了为了在我的代码中使用此模型,以下是我从各种在线资源中汇总的内容

using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
//using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using microsoft.ml.OnnxRuntime.Tensors;
using microsoft.ml.OnnxRuntime;
using System.IO;

namespace TestONNXRunner
{
   

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            RunModel();
        }

        public void RunModel()
        {
            // Read paths
            string modelFilePath = @"C:\ImageMLProjects\MarbleImagesDataset\OnnxModel\onnxdataset\model.onnx";
            var LabelsDict = GetLabelMap(@"C:\ImageMLProjects\MarbleImagesDataset\OnnxModel\onnxdataset\labels.txt");


            string imageFilePath = @"";
            OpenFileDialog openFileDialog1 = new OpenFileDialog
            {
                InitialDirectory = @"C:\",Title = "browse Image Files",CheckFileExists = true,CheckPathExists = true,FilterIndex = 2,RestoreDirectory = true,ReadOnlyChecked = true,ShowReadOnly = true
            };

            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                imageFilePath = openFileDialog1.FileName;

                // Read image
                using Image<Rgb24> image = Image.Load<Rgb24>(imageFilePath);

                // Resize image
                image.Mutate(x =>
                {
                    x.Resize(new ResizeOptions
                    {
                        Size = new SixLabors.ImageSharp.Size(300,300),Mode = ResizeMode.Stretch
                    });
                });

                // Preprocess image
                Tensor<float> input = new DenseTensor<float>(new[] { 1,3,image.Height,image.Width });
                var mean = new[] { 0f,0f,0f };
                var stddev = new[] { 1f,1f,1f };
                for (int y = 0; y < image.Height; y++)
                {
                    Span<Rgb24> pixelSpan = image.GetPixelRowSpan(y);
                    for (int x = 0; x < image.Width; x++)
                    {
                        input[0,x,y] = ((pixelSpan[x].R / 255f) - mean[0]) / stddev[0];
                        input[0,1,y] = ((pixelSpan[x].G / 255f) - mean[1]) / stddev[1];
                        input[0,2,y] = ((pixelSpan[x].B / 255f) - mean[2]) / stddev[2];
                    }
                }

                // Setup inputs
                var inputs = new List<NamedOnnxValue>
                {
                    NamedOnnxValue.CreateFromTensor("data",input)
                };

                // Run inference
                //int gpudeviceid = 0; // The GPU device ID to execute on
                //var session = new InferenceSession("model.onnx",Sessionoptions.MakeSessionoptionWithCudaProvider(gpudeviceid));
                using var session = new InferenceSession(modelFilePath);
                using IdisposableReadOnlyCollection<disposableNamedOnnxValue> results = session.Run(inputs);

                // Postprocess to get softmax vector
                IEnumerable<float> output = results.First().AsEnumerable<float>();
                float sum = output.Sum(x => (float)Math.Exp(x));
                IEnumerable<float> softmax = output.Select(x => (float)Math.Exp(x) / sum);

                // Extract top 10 predicted classes
                IEnumerable<Prediction> top10 = softmax.Select((x,i) => new Prediction { Label = LabelsDict[i],Confidence = x })
                                   .OrderByDescending(x => x.Confidence)
                                   .Take(10);

                // Print results to console
                Console.WriteLine("Top 10 predictions for resnet50 v2...");
                Console.WriteLine("--------------------------------------------------------------");
                foreach (var t in top10)
                {
                    Console.WriteLine($"Label: {t.Label},Confidence: {t.Confidence}");
                }
            }
        }


        public Dictionary<int,string> GetLabelMap(string LabelMapFile)
        {
            Dictionary<int,string> labelsDict = new Dictionary<int,string>();
            if(File.Exists(LabelMapFile))
            {
                string data = File.ReadAllText(LabelMapFile);

                string[] labels = data.Split('\n');
                int i = 0;
                foreach (var label in labels)
                {
                    labelsDict.Add(i,label);
                    i++;
                }
            }
            return labelsDict;
        }
        internal class Prediction
        {
            public string Label { get; set; }
            public float Confidence { get; set; }
        }


      
    }
}

现在有什么问题?

我没有看到任何错误,无论我使用什么图像进行推理,我都得到相同的结果。

问题

  1. 我应该以不同的方式构造张量吗?我不确定这是否与 Tensor 的结构方式有关。
  2. Github 上对 Customvision 页面的最后一次更新是在几年前,是否建议在 2021 年将 CustomVision 用于生产用途?我应该寻找其他东西吗?我们的想法是能够使用低/零代码方法构建/训练高质量图像分类模型,然后将该模型部署到本地计算机上以用于低延迟应用。

在这方面的任何帮助将不胜感激

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?