共用方式為


教學課程:建立 Windows Machine Learning UWP 應用程式 (C#)

在本教學課程中,我們將建置簡單的通用 Windows 平台應用程式,以使用定型的機器學習模型來辨識用戶繪製的數值數位。 本教學課程主要著重於如何在UWP應用程式中載入和使用Windows ML。

下列影片會逐步解說本教學課程所依據的範例。


如果您想要只查看已完成教學課程的程式代碼,您可以在 WinML GitHub 存放庫中找到它。 它也可在 C++/CX 中使用。

先決條件

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 - 協助程式例程裁剪和轉換影像格式。

Visual Studio 方案總管與項目檔

2.建置並執行專案

在 Visual Studio 工具列中,如果您的裝置是 64 位,請將 [方案平臺 ] 變更為 x64 ,以在本機電腦上執行專案,如果它是 32 位,則為 x86 。 (您可以在 Windows 設定中查看: 系統 > 關於 > 裝置規格 > 系統類型

若要執行專案,請按下工具列上的 [ 開始偵錯] 按鈕,或按 F5。 應用程式應該會顯示 InkCanvas,讓使用者可以寫入數位、可解譯數位的 [辨識] 按鈕、將解譯數字顯示為文字的空白卷標字段,以及清除 InkCanvas[清除數位] 按鈕。

應用程式螢幕快照

備註

如果專案不會建置,您可能需要變更專案的部署目標版本。 以滑鼠右鍵按兩下 方案 總管中的項目,然後選取 [ 屬性]。 在 [ 應用程式] 索引標籤中,設定 [目標版本 ] 和 [ 最小版本 ] 以符合您的 OS 和 SDK。

備註

如果您收到已安裝應用程式的警告,只要選取 [ ] 繼續部署即可。 如果 Visual Studio 仍然無法運作,您可能需要關閉 Visual Studio 並重新開啟。

3.下載模型

接下來,讓我們取得要新增至應用程式的機器學習模型。 在本教學課程中,我們將使用預先定型的 MNIST 模型,該模型是以 Microsoft 認知工具組 (CNTK) 定型,並 導出至 ONNX 格式

MNIST 模型已包含在 [資產 ] 資料夾中,您必須將它新增至您的應用程式做為現有專案。 您也可以從 GitHub 上的 ONNX 模型動物園 下載預先定型的模型。

4.新增模型

以滑鼠右鍵按兩下 [方案總管] 中的 [資產] 資料夾,然後選取 [新增>現有專案]。 將檔案選擇器指向 ONNX 模型的位置,然後按兩下 [ 新增]。

項目現在應該有兩個新的檔案:

  • mnist.onnx - 已定型的模型。
  • mnist.cs - Windows ML 產生的程式代碼。

包含新檔案的方案總管

若要確定模型會在編譯應用程式時建置,請以滑鼠右鍵按兩下 mnist.onnx 檔案,然後選取 [ 屬性]。 針對建置動作,選取內容

現在,讓我們看看 mnist.cs 檔案中新產生的程序代碼。 我們有三個類別:

  • mnistModel 會建立機器學習模型表示法、在系統預設裝置上建立會話、將特定輸入和輸出系結至模型,並以異步方式評估模型。
  • mnistInput 會初始化模型預期的輸入類型。 在此情況下,輸入需要 ImageFeatureValue
  • mnistOutput 會初始化模型將輸出的類型。 在此情況下,輸出會是名為 Plus214_Output_0TensorFloat 類型清單。

我們現在會使用這些類別來載入、系結和評估專案中的模型。

5.載入、系結及評估模型

針對 Windows ML 應用程式,我們想要遵循的模式是:載入 > 系結 > 評估。

  1. 載入機器學習模型。
  2. 將輸入和輸出系結至模型。
  3. 評估模型並檢視結果。

我們將使用 mnist.cs 中產生的介面程式代碼來載入、系結及評估應用程式中的模型。

首先,在 MainPage.xaml.cs中,讓我們具現化模型、輸入和輸出。 將下列成員變數新增至 MainPage 類別:

private mnistModel ModelGen;
private mnistInput ModelInput = new mnistInput();
private mnistOutput ModelOutput;

然後,在 LoadModelAsync 中,我們將載入模型。 在使用模型的任何方法之前,應該先呼叫這個方法,也就是可以在MainPageLoaded事件中,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.Storage.Streams ]。

接下來,我們想要將輸入和輸出系結至模型。 產生的程式代碼也包含 mnistInputmnistOutput 包裝函式類別。 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 上提出問題。