教學課程:建立 Windows 機器學習 UWP 應用程式 (C#)
在本教學課程中,我們會建置簡單的通用 Windows 平台應用程式,其使用經過訓練的機器學習模型來辨識使用者繪製的數字。 本教學課程主要著重於如何在 UWP 應用程式中載入和使用 Windows ML。
下列影片會逐步解說本教學課程所依據的範例。
如果您只想要查看已完成教學課程的程式碼,您可以在 WinML GitHub 存放庫中找到。 也可以在 C++/CX 中取得。
必要條件
- Windows 10 (版本 1809 或更高版本)
- Windows 10 SDK (組建 17763 或更高版本)
- Visual Studio 2019 (或 Visual Studio 2017,15.7.4 版或更新版本)
- 適用於 Visual Studio 2019 或 2017 的 Windows Machine Learning 程式碼產生器擴充功能
- 一些基本的 UWP 和 C# 知識
1.在 Visual Studio 中開啟專案
從 GitHub 下載專案之後,請啟動 Visual Studio 並開啟 MNIST_Demo.sln 檔案 (應位於<存放庫路徑>\Windows-Machine-Learning\Samples\MNIST\Tutorial\cs)。 如果解決方案顯示為無法使用,則需要以滑鼠右鍵按一下 [方案總管] 中的專案,然後選取 [重新載入專案]。
我們已提供搭配實作 XAML 控制項和事件的樣板,包括:
- InkCanvas 繪製數字。
- 按鈕 解釋數字並清除畫布。
- 協助程式常式,以將 InkCanvas 輸出轉換成 VideoFrame。
在 [方案總管] 中,該專案有三個主要的程式碼檔案:
- MainPage.xaml - 我們所有的 XAML 的程式碼,用於為 InkCanvas、按鈕及標籤建立 UI。
- MainPage.xaml.cs- 我們的應用程式程式碼所在之處。
- Helper.cs - 協助程式常式裁剪和轉換影像格式。
2.建置並執行專案
在 Visual Studio 工具列中,如果您的裝置為 64 位元,請將 [解決方案平台] 變更為 x64,以在本機電腦上執行專案,而如果是 32 位元,則變更為 x86。 (您可以簽入 Windows 設定 應用程式: 系統 > 關於 > 裝置規格 > 系統類型 。)
若要執行專案,按一下工具列上的 [開始偵錯] 按鈕,或按下 F5。 應用程式應該會顯示 InkCanvas(使用者可以在其中寫入數字)、[辨識] 按鈕以解釋數字 (所解釋的數字將顯示為文字的空白標籤欄位),以及 [清除數字] 按鈕以除 InkCanvas。
注意
如果不會建立專案,您可能需要變更專案的部署目標版本。 以滑鼠右鍵按一下 [方案總管] 中的專案,然後選取 [屬性]。 在 [應用程式] 索引標籤中,設定 [目標版本] 和 [最低版本] 以符合您的作業系統和 SDK。
注意
如果您收到應用程式已經安裝的警告,只要選取 [是] 即可繼續部署。 如果仍然無法運作,您可能需要關閉 Visual Studio,而後重新開啟。
3.下載模型
接下來,取得機器學習模型以新增到我們的應用程式中。 在本教學課程中,我們會使用經由 Microsoft Cognitive Toolkit (CNTK) 訓練且匯出為 ONNX 格式的預先訓練 MNIST 模型。
MNIST 模型已包含在您的 Assets資料夾中,您需要將其視為現有項目新增到您的應用程式。 您也可以從 GitHub上的 ONNX 模型動物園 下載預先訓練模型。
4.新增模型
在 [方案總管] 中的 Assets 資料夾上按一下滑鼠右鍵,然後選取 [新增]>[現有項目]。 將檔案選擇器指向 ONNX 模型的位置,然後按一下 [新增]。
該專案現在應該有兩個新的檔案:
- mnist. onnx - 您已定型的模型。
- mnist.cs - Windows ML 產生的程式碼。
在編譯應用程式時為了確保模型組建,請以滑鼠右鍵按一下 mnist.onnx 檔案,然後選取 [屬性]。 對於 [建置動作],選取 [內容]。
現在,我們來看看在 mnist.cs 檔案中新產生的程式碼。 我們有三個類別:
- mnistModel 會建立機器學習模型代表、在系統預設裝置上建立工作階段,將特定輸入和輸出繫結到模型,並以非同步方式評估模型。
- mnistInput 會初始化模型預期的輸入類型。 在此案例中,輸入會預期 ImageFeatureValue。
- mnistOutput 會初始化模型將輸出的類型。 在此情況下,輸出會是名為 Plus214_Output_0 且類型為 TensorFloat 的清單。
現在我們將使用這些類別,以便在我們的專案中載入、繫結,以及評估模型。
5.載入、系結及評估模型
針對 Windows ML 應用程式,我們想要遵循的模式是:載入 > 系結 > 評估。
- 載入機器學習模型。
- 將輸入和輸出繫結到模型。
- 評估模型和檢視結果。
我們將使用 mnist.cs 中產生的介面的程式碼,在我們的應用程式中載入、繫結,以及評估模型。
首先,在 MainPage.xaml.cs 中,讓我們初始化模型、輸入,以及輸出。 將下列成員變數新增到 MainPage類別:
private mnistModel ModelGen;
private mnistInput ModelInput = new mnistInput();
private mnistOutput ModelOutput;
然後,在 LoadModelAsync 中,我們將會載入模型。 在我們使用任何模型的方法之前 (也就是在 MainPage 的 Loaded 事件、OnNavigatedTo 覆寫,或在呼叫 recognizeButton_Click 前的任何位置),都應該呼叫這個方法。 mnistModel 類別代表 MNIST 模型,並在系統預設裝置上建立工作階段。 為了載入模型,我們會呼叫 CreateFromStreamAsync 方法,並傳入 ONNX 檔案作為參數。
private async Task LoadModelAsync()
{
// Load a machine learning model
StorageFile modelFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri($"ms-appx:///Assets/mnist.onnx"));
ModelGen = await mnistModel.CreateFromStreamAsync(modelFile as IRandomAccessStreamReference);
}
注意
如果您在 IRandomAccessStreamReference 之下取得紅色底線,就必須包含其命名空間。 將游標放在上方,按 Ctrl + , 然後選取 [使用 Windows.儲存體]。下拉式功能表中的串流。
接下來,我們想要將我們的輸入與輸出繫結至模型。 產生的程式碼也包含 mnistInput 和 mnistOutput 包裝函式類別。 mnistInput 類代表模型的預期輸入,mnistOutput 類別代表模型的預期輸出。
若要初始化模型的輸入物件,請呼叫 mnistInput 類別建構函式,傳遞應用程式的資料,並確保輸入資料符合您的模型所期望的輸入類型。 mnistInput 類別預期 ImageFeatureValue,所以我們使用協助程式方法來取得輸入的 ImageFeatureValue。
在 helper.cs 中使用我們隨附的協助程式函式,我們將會複製 InkCanvas 的內容,將其轉換成 ImageFeatureValue 類型,並將其繫結到我們的模型。
private async void recognizeButton_Click(object sender, RoutedEventArgs e)
{
// Bind model input with contents from InkCanvas
VideoFrame vf = await helper.GetHandWrittenImage(inkGrid);
ModelInput.Input3 = ImageFeatureValue.CreateFromVideoFrame(vf);
}
對於輸出,我們只需使用指定的輸入來呼叫 EvaluateAsync。 在您的輸入初始化後,呼叫模型的 EvaluateAsync 方法來評估輸入資料上的模型。 EvaluateAsync 將您的輸入和輸出繫結到模型物件,並在輸入上評估模型。
由於模型會傳回輸出張量,因此我們會先將其轉換成易記的資料類型,然後剖析所傳回的清單,以判斷哪個數字的機率最高並顯示該數字。
private async void recognizeButton_Click(object sender, RoutedEventArgs e)
{
// Bind model input with contents from InkCanvas
VideoFrame vf = await helper.GetHandWrittenImage(inkGrid);
ModelInput.Input3 = ImageFeatureValue.CreateFromVideoFrame(vf);
// Evaluate the model
ModelOutput = await ModelGen.EvaluateAsync(ModelInput);
// Convert output to datatype
IReadOnlyList<float> vectorImage = ModelOutput.Plus214_Output_0.GetAsVectorView();
IList<float> imageList = vectorImage.ToList();
// Query to check for highest probability digit
var maxIndex = imageList.IndexOf(imageList.Max());
// Display the results
numberLabel.Text = maxIndex.ToString();
}
最後,我們要清除 InkCanvas 以讓使用者繪製另一個數字。
private void clearButton_Click(object sender, RoutedEventArgs e)
{
inkCanvas.InkPresenter.StrokeContainer.Clear();
numberLabel.Text = "";
}
6.啟動應用程式
在我們建置並啟動應用程式 (按下 F5) 後,我們就能夠辨識 InkCanvas 上繪製的數字。
這樣就完成了,您已經製作了您的第一個 Windows ML 應用程式! 如需示範如何使用 Windows ML 的更多範例,請參閱 GitHub 上的 Windows-Machine-Learning 存放庫。
注意
使用下列資源取得 Windows ML 的說明:
- 如需詢問或回答有關 Windows ML 的技術問題,請使用 Stack Overflow 上的 windows-machine-learning 標籤。
- 如需回報錯誤 (bug),請在 GitHub 上提出問題。