1. 程式人生 > >機器學習框架ML.NET學習筆記【8】目標檢測(採用YOLO2模型)

機器學習框架ML.NET學習筆記【8】目標檢測(採用YOLO2模型)

一、概述

本篇文章介紹通過YOLO模型進行目標識別的應用,原始程式碼來源於:https://github.com/dotnet/machinelearning-samples

實現的功能是輸入一張圖片,對圖片中的目標進行識別,輸出結果在圖片中通過紅色框線標記出來。如下:

 YOLO簡介

 YOLO(You Only Look Once)是一種最先進的實時目標檢測系統。官方網站:https://pjreddie.com/darknet/yolo/

 本文采用的是TinyYolo2模型,可以識別的目標型別包括:"aeroplane", "bicycle", "bird", "boat", "bottle","bus", "car", "cat", "chair", "cow","diningtable", "dog", "horse", "motorbike", "person","pottedplant", "sheep", "sofa", "train", "tvmonitor" 。 

ONNX簡介

ONNX 即Open Neural Network Exchange(開放神經網路交換格式),是一個用於表示深度學習模型的通用標準,可使模型在不同框架之間進行互相訪問,其規範及程式碼主要由微軟,亞馬遜 ,Facebook 和 IBM 等公司共同制定與開發。有了ONNX標準,我們就可以在ML.NET程式碼中使用通過其他機器學習框架訓練並儲存的模型。

 

二、程式碼分析

 1、Main方法

        static void Main(string[] args)
        {
            TrainAndSave();
            LoadAndPredict();

            Console.WriteLine("Press any key to exit!");
            Console.ReadKey();
        }

 第一次執行時需要執行TrainAndSave方法,生成本地模型後,可以直接執行生產程式碼。

 

2、訓練並儲存模型

     static readonly string tagsTsv = Path.Combine(trainImagesFolder,  "tags.tsv");       
     private static void TrainAndSave() { var mlContext = new MLContext(); var trainData = mlContext.Data.LoadFromTextFile<ImageNetData>(tagsTsv); var pipeline = mlContext.Transforms.LoadImages(outputColumnName: "image", imageFolder: trainImagesFolder, inputColumnName: nameof(ImageNetData.ImagePath)) .Append(mlContext.Transforms.ResizeImages(outputColumnName: "image", imageWidth: ImageNetSettings.imageWidth, imageHeight: ImageNetSettings.imageHeight, inputColumnName: "image")) .Append(mlContext.Transforms.ExtractPixels(outputColumnName: "image")) .Append(mlContext.Transforms.ApplyOnnxModel(modelFile: YOLO_ModelFilePath, outputColumnNames: new[] { TinyYoloModelSettings.ModelOutput }, inputColumnNames: new[] { TinyYoloModelSettings.ModelInput })); var model = pipeline.Fit(trainData); using (var file = File.OpenWrite(ObjectDetectionModelFilePath)) mlContext.Model.Save(model, trainData.Schema, file); Console.WriteLine("Save Model success!"); }

  ImageNetData類定義如下:

    public class ImageNetData
    {
        [LoadColumn(0)]
        public string ImagePath;

        [LoadColumn(1)]
        public string Label;
    }

tags.tsv檔案中僅包含一條樣本資料,因為模型已經訓練好,不存在再次訓練的意義。這裡只要放一張圖片樣本即可,通過Fit方法建立資料處理通道模型。

ApplyOnnxModel方法載入第三方ONNX模型,

    public struct TinyYoloModelSettings
    {
        // input tensor name
        public const string ModelInput = "image";

        // output tensor name
        public const string ModelOutput = "grid";
    }

 其中,輸入、輸出的列名稱是指定的。可以通過安裝Netron這樣的工具來查詢ONNX檔案的詳細資訊,可以看到輸入輸出的資料列名稱。


3、應用
        private static void LoadAndPredict()
        {
            var mlContext = new MLContext();

            ITransformer trainedModel;
            using (var stream = File.OpenRead(ObjectDetectionModelFilePath))
            {
                trainedModel = mlContext.Model.Load(stream, out var modelInputSchema);               
            }
            var predictionEngine = mlContext.Model.CreatePredictionEngine<ImageNetData, ImageNetPrediction>(trainedModel);

            DirectoryInfo testdir = new DirectoryInfo(testimagesFolder);
            foreach (var jpgfile in testdir.GetFiles("*.jpg"))
            {  
                ImageNetData image = new ImageNetData
                {
                    ImagePath = jpgfile.FullName
                };               
var Predicted = predictionEngine.Predict(image); PredictImage(image.ImagePath, Predicted); } }
程式碼遍歷一個資料夾下面的JPG檔案。對每一個檔案進行轉換,獲得預測結果。
ImageNetPrediction類定義如下:
    public class ImageNetPrediction
    {
        [ColumnName(TinyYoloModelSettings.ModelOutput)]
        public float[] PredictedLabels;       
    }

 輸出的“grid”列資料是一個float陣列,不能直接理解其含義,所以需要通過程式碼將其資料轉換為便於理解的格式。

     YoloWinMlParser _parser = new YoloWinMlParser();
     IList<YoloBoundingBox> boundingBoxes = _parser.ParseOutputs(Predicted.PredictedLabels, 0.4f);            

YoloWinMlParser.ParseOutputs方法將float陣列轉為YoloBoundingBox物件的列表,第二個引數是可信度闕值,只輸出大於該可信度的資料。

YoloBoundingBox類定義如下:

    class YoloBoundingBox
    {    
        public string Label { get; set; }
        public float Confidence { get; set; }

        public float X { get; set; }
        public float Y { get; set; }
        public float Height { get; set; }
        public float Width { get; set; }
        public RectangleF Rect
        {
            get { return new RectangleF(X, Y, Width, Height); }
        }
    }

 其中:Label為目標型別,Confidence為可行程度。

由於YOLO的特點導致對同一個目標會輸出多個同樣的檢測結果,所以還需要對檢測結果進行過濾,去掉那些高度重合的結果。

     YoloWinMlParser _parser = new YoloWinMlParser();
     IList<YoloBoundingBox> boundingBoxes = _parser.ParseOutputs(Predicted.PredictedLabels, 0.4f); 
     var filteredBoxes = _parser.NonMaxSuppress(boundingBoxes, 5, 0.6F);

 YoloWinMlParser.NonMaxSuppress第二個引數表示最多保留多少個結果,第三個引數表示重合率闕值,將去掉重合率大於該值的記錄。

 

四、資源獲取 

原始碼下載地址:https://github.com/seabluescn/Study_ML.NET

工程名稱:YOLO_ObjectDetection

資源獲取:https://gitee.com/seabluescn/ML_Assets (ObjectDetection)

點選檢視機器學習框架ML.NET學習筆記系列文章