ML-NET 示例:對象檢測 - ASP-NET Core Web 和 WPF 桌面示例
問題
對象檢測是計算機視覺中的經典問題之一:識別給定圖像中包含哪些對象以及它們在圖像中的位置。對於這些情況,您可以使用預先訓練的模型,也可以訓練自己的模型對自定義域特定的圖像進行分類。默認情況下,此示例使用預先訓練的模型,但是您也可以添加從 Custom Vision 導出的模型。
示例的工作原理
此示例由兩個獨立的應用程序組成:
-
一個 WPF Core 桌面應用程序呈現攝像頭的實時流,使用 ML.NET 通過對象檢測模型運行視頻幀,並用標籤繪製邊界框,指示實時檢測到的對象。
-
一個允許用戶上載或選擇圖像的 ASP.NET Core Web 應用。Web 應用程序使用 ML.NET 通過一個對象檢測模型運行圖像,並用指示檢測到的對象的標籤繪製邊界框。
Web 應用程序顯示右側列出的圖像,可以選擇每個圖像進行處理。一旦圖像被處理,它將被繪製在屏幕的中間,每個檢測到的對象周圍都有標記的邊界框,如下所示。
或者,您可以嘗試上傳自己的圖片,如下所示。
ONNX
開放式神經網絡交換即 ONNX 是一種表示深度學習模型的開放格式。使用 ONNX,開發人員可以在最先進的工具之間移動模型,並選擇最適合他們的組合。ONNX 是由包括微軟在內的衆多合作伙伴共同開發和支持的。
預訓練模型
有多個預先訓練的模型用於識別圖像中的多個對象。WPF app 和 Web app 都默認使用從 ONNX Model Zoo 下載的預先訓練好的模型 Tiny YOLOv2; 一組經過預先訓練的、最先進的 ONNX 格式模型。Tiny YOLOv2 是一種用於目標檢測的實時神經網絡,用於檢測 20 個不同的類,並在 Pascal VOC 數據集上進行訓練。它由 9 個卷積層和 6 個最大池層組成,是更復雜的完整的 YOLOv2 網絡的較小版本。
Custom Vision 模型
此示例默認使用上述預先訓練的 Tiny YOLOv2 模型。不過,它也支持從微軟 Custom Vision 導出的 ONNX 模型。
要使用自己的模型,請使用以下步驟
-
使用 Custom Vision 創建和訓練物體探測器。要導出模型,請確保選擇一個緊湊域,例如常規(緊湊)。要導出現有的對象檢測器,請通過選擇右上角的齒輪圖標將域轉換爲緊湊型。在_ **設置** _中,選擇一個緊湊的模型,保存並訓練您的項目。
-
轉到_**性能**選項卡導出模型。選擇一個用緊湊域訓練的迭代,將出現一個 “導出” 按鈕。選擇_導出、ONNX、ONNX1.2,然後選擇導出。文件準備好後,選擇 “下載” 按鈕。
-
導出的是一個包含多個文件的 zip 文件,包括一些示例代碼、標籤列表和 ONNX 模型。將. zip 文件放到 OnnxObjectDetection 項目中的 OnnxModels 文件夾中。
-
在解決方案資源管理器中,右鍵單擊 OnnxModels 文件夾,然後選擇_添加現有項_。選擇剛添加的. zip 文件。
-
在解決方案資源管理器中,從 OnnxModels 文件夾中選擇. zip 文件。更改文件的以下屬性:
-
生成操作 -> 內容
-
複製到輸出目錄 -> 如果較新則複製
現在,當你生成和運行應用程序時,它將使用你的模型而不是 Tiny YOLOv2 模型。
模型輸入和輸出
爲了解析 ONNL 模型的預測輸出,我們需要了解輸入和輸出張量的格式(或形狀)。爲此,我們將首先使用 Netron,一個用於神經網絡和機器學習模型的 GUI 可視化工具,用於檢查模型。
下面是一個例子,我們將看到使用 Netron 打開這個示例的 Tiny YOLOv2 模型:
從上面的輸出中,我們可以看到 Tiny YOLOv2 模型具有以下輸入 / 輸出格式:
輸入: 'image' 3x416x416
首先要注意的是,輸入張量的名稱是 'image'。稍後在定義評估管道的** input** 參數時,我們將需要這個名稱。
我們還可以看到,輸入張量的形狀是 3x416x416。這說明傳入模型的位圖圖像應該是 416 高 x 416 寬。“3”表示圖像應爲 BGR 格式;前 3 個 “通道” 分別是藍色、綠色和紅色。
輸出: 'data' 125x13x13
與輸入張量一樣,我們可以看到輸出名稱是 'data'。同樣,在定義評估管道的** output** 參數時,我們會注意到這一點。
我們還可以看到, 輸出張量的形狀是 125x13x13。
125x13x13 的 “13x13” 部分意味着圖像被分成一個 13x13 的 “單元格” 網格(13 列 x 13 行)。因爲我們知道輸入圖像是 416x416,所以我們可以推斷出每個 “單元” 都是 32 高 x 32 寬(416/13=32)
├──────────────── 416 ─────────────────┤
┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐ ┬ 416/13=32
├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ │ ┌──┐
├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ │ └──┘
├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ │ 32x32
├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ │
├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ │
13 ├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ │
├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ 416
├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ │
├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ │
├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ │
├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ │
├──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┼──┤ │
└──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘ ┴
13
那 125 呢?“125” 告訴我們,對於每個網格單元,模型返回 125 個 “通道”(或數據)作爲該單個單元的預測輸出。
要了解爲什麼有 125 個通道,我們首先需要了解該模型不能預測對象的任意邊界框。相反,每個單元格負責預測 5 個預定的邊界框。這 5 個框是根據以下每個anchor
框的偏移量計算得出的:
┌───────────────────┐
│ ┌───┐ │
│ ┌─────┼───┼─────┐ │
│ │ ┌──┼───┼──┐ │ │
│ │ │ │┌─┐│ │ │ │
│ │ │ │└─┘│ │ │ │
│ │ └──┼───┼──┘ │ │
│ └─────┼───┼─────┘ │
│ └───┘ │
└───────────────────┘
因此,對於每個單獨的單元格,該模型返回 5 個預測(每個錨定一個,由上面的框形表示),每個預測包括以下 25 個參數:
-
4 個參數指示邊界框的位置(x,y,寬度,高度)
-
1 個參數指示盒子的置信度得分(或客觀性)
-
20 個類別的概率(每個類別一個概率分數,表明該對象是該類別的可能性)
5 個盒子 x 25 個參數 = 125 個'通道'
注意,如果對模型進行訓練以檢測不同數量的類,則該值將不同。例如,僅能檢測 3 個不同類的模型的輸出格式爲 40x13x13:
-
(x,y,寬度,高度,客觀性)+ 3 個類別概率 = 8 個參數
-
5 個盒子 x 8 個參數 = 40 個'通道'
解決方案
此解決方案中的項目使用. NET Core 3.0。爲了運行此示例,您必須安裝. NET Core SDK 3.0。爲此,請執行以下任一操作:
-
通過轉到. NET Core 3.0 下載頁面手動安裝 SDK,並在 “SDK” 列中下載最新的“.NET Core 安裝程序”。
-
或者,如果您使用的是 Visual Studio 2019,請轉至: 工具 > 選項 > 環境 > 預覽功能 ,然後選中以下複選框: 使用. NET Core SDK 的預覽
解決方案包含三個項目
-
OnnxObjectDetection 是 WPF 應用程序和 Web 應用程序都使用的. NET Standard 庫。它包含用於通過模型運行圖像並解析結果預測的大多數邏輯。該項目還包含 ONNX 模型文件。除了在圖像 / 屏幕上繪製標籤邊界框之外,此項目包含下面的所有代碼段。
-
OnnxObjectDetectionWeb 包含一個 ASP.NET Core Web App,其中包含 Razor UI 頁面和 API controller 以處理和呈現圖像。
-
OnnxObjectDetectionApp 包含一個. NET CORE WPF 桌面應用程序,該應用程序使用 OpenCvSharp 從設備的網絡攝像頭捕獲視頻。
代碼演練
該示例與 getting-started object detection sample 不同,在這裏我們加載 / 處理在內存中的圖像 ,而入門示例從文件**中加載圖像。
創建一個類,該類定義將數據加載到 IDataView 中時要使用的數據模式。ML.NET 支持圖像的Bitmap
類型,因此我們將指定以ImageTypeAttribute
修飾的Bitmap
屬性,並傳入通過 [檢查模型]](#model-input-and-output) 得到的高度和寬度尺寸,如下所示。
public struct ImageSettings
{
public const int imageHeight = 416;
public const int imageWidth = 416;
}
public class ImageInputData
{
[ImageType(ImageSettings.imageHeight, ImageSettings.imageWidth)]
public Bitmap Image { get; set; }
}
ML.NET: 配置模型
第一步是創建一個空的DataView
,以獲取配置模型時要使用的數據架構。
var dataView = _mlContext.Data.LoadFromEnumerable(new List<ImageInputData>());
第二步是定義評估器管道。通常在處理深度神經網絡時,必須使圖像適應網絡所期望的格式。因此,下面的代碼將調整圖像的大小並對其進行變換(所有 R、G、B 通道的像素值都已標準化)。
var pipeline = mlContext.Transforms.ResizeImages(resizing: ImageResizingEstimator.ResizingKind.Fill, outputColumnName: onnxModel.ModelInput, imageWidth: ImageSettings.imageWidth, imageHeight: ImageSettings.imageHeight, inputColumnName: nameof(ImageInputData.Image))
.Append(mlContext.Transforms.ExtractPixels(outputColumnName: onnxModel.ModelInput))
.Append(mlContext.Transforms.ApplyOnnxModel(modelFile: onnxModel.ModelPath, outputColumnName: onnxModel.ModelOutput, inputColumnName: onnxModel.ModelInput));
接下來,我們將使用通過檢查模型 得到的輸入和輸出張量名稱來定義 Tiny YOLOv2 Onnx 模型的 input 和 output 參數。
public struct TinyYoloModelSettings
{
public const string ModelInput = "image";
public const string ModelOutput = "grid";
}
最後,通過擬合 “DataView” 來創建模型。
var model = pipeline.Fit(dataView);
加載模型並創建 PredictionEngine
配置模型後,我們需要保存模型,加載保存的模型,創建一個PredictionEngine
,然後將圖像傳遞給引擎以使用模型檢測對象。這是一個 Web 應用程序和 WPF 應用程序略有不同的地方。
Web 應用程序使用一個PredictionEnginePool
來高效地管理服務,併爲服務提供一個PredictionEngine
來進行預測。在內部,它進行了優化,以便在創建這些對象時,以最小的開銷在 Http 請求之間緩存和共享對象依賴關係。
public ObjectDetectionService(PredictionEnginePool<ImageInputData, TinyYoloPrediction> predictionEngine)
{
this.predictionEngine = predictionEngine;
}
而 WPF 桌面應用程序創建一個PredictionEngine
,並在本地緩存以用於每個幀預測。需要澄清的關鍵點是,實例化PredictionEngine
的調用代碼負責處理緩存(與PredictionEnginePool
相比)。
public PredictionEngine<ImageInputData, TinyYoloPrediction> GetMlNetPredictionEngine()
{
return mlModel.Model.CreatePredictionEngine<ImageInputData, TinyYoloPrediction>(mlModel);
}
檢測圖像中的對象
獲取預測時,我們在PredictedLabels
屬性中得到一個大小爲 21125 的 float
數組。這是前面討論過的模型的 125x13x13 輸出。然後,我們使用OnnxOutputParser
類解釋並返回每個圖像的多個邊界框。同樣,這些框被過濾,因此我們只檢索到 5 個具有高置信度的框。
var labels = tinyYoloPredictionEngine?.Predict(imageInputData).PredictedLabels;
var boundingBoxes = outputParser.ParseOutputs(labels);
var filteredBoxes = outputParser.FilterBoundingBoxes(boundingBoxes, 5, 0.5f);
在圖像中檢測到的對象周圍繪製邊界框
最後一步是在對象周圍繪製邊界框。
Web 應用程序使用 Paint API 將框直接繪製到圖像上,並返回圖像以在瀏覽器中顯示。
var img = _objectDetectionService.DrawBoundingBox(imageFilePath);
using (MemoryStream m = new MemoryStream())
{
img.Save(m, img.RawFormat);
byte[] imageBytes = m.ToArray();
// Convert byte[] to Base64 String
base64String = Convert.ToBase64String(imageBytes);
var result = new Result { imageString = base64String };
return result;
}
另外,WPF 應用程序在與流式視頻播放重疊的Canvas
元素上繪製邊界框。
DrawOverlays(filteredBoxes, WebCamImage.ActualHeight, WebCamImage.ActualWidth);
WebCamCanvas.Children.Clear();
foreach (var box in filteredBoxes)
{
var objBox = new Rectangle {/* ... */ };
var objDescription = new TextBlock {/* ... */ };
var objDescriptionBackground = new Rectangle {/* ... */ };
WebCamCanvas.Children.Add(objDescriptionBackground);
WebCamCanvas.Children.Add(objDescription);
WebCamCanvas.Children.Add(objBox);
}
關於準確性的說明
Tiny YOLOv2 的精確度明顯低於完整的 YOLOv2 模型,但是對於這個示例應用程序來說,Tiny 版本已經足夠了。
疑難解答(Web 應用程序)
通過應用程序服務在 Azure 上部署此應用程序時,您可能會遇到一些常見問題。
- 應用程序返回 5xx 代碼
-
要在 Azure 門戶中添加. NET Core 3.0 支持,請選擇相應應用程序服務的開發工具 > 擴展部分中的添加按鈕。
-
然後,從擴展列表中選擇選擇擴展並選擇 ASP.NET Core 3.0(x64)Runtime 並接受法律條款,繼續將擴展添加到應用程序服務。
-
部署應用程序後,您可能會得到 5xx 代碼的一個原因是平臺。web 應用程序僅在 64 位體系結構上運行。在 Azure 中,更改設置 > 配置 > 常規設置菜單中相應應用程序服務中的平臺設置。
-
部署應用程序後使用 5xx 代碼的另一個原因是 web 應用程序的目標框架是. NET Core 3.0,它目前正在預覽中。您可以將應用程序和引用的項目還原爲. NET Core 2.x 或嚮應用程序服務添加擴展。
-
相對路徑
在本地和 Azure 上工作時,路徑的工作方式略有不同。如果成功地部署了應用程序,但單擊其中一個預加載的映像或上載自己的映像不起作用,請嘗試更改相對路徑。爲此,在 Controllers/ObjectDetectionController.cs 文件中,更改構造函數中的
_imagesTmpFolder
的值。_imagesTmpFolder = CommonHelpers.GetAbsolutePath(@"ImagesTemp");
對
Get
操作中的imageFileRelativePath
執行相同的操作。string imageFileRelativePath = @"assets" + url;
或者,您可以根據環境(dev / prod)設置條件,是使用路徑的本地版本還是 Azure 首選的版本。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/JqvYIWhRTjuCzuh3pZXTHQ