共用方式為


教學課程:建立 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 20192017 的 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 - 協助程式常式裁剪和轉換影像格式。

Visual Studio solution explorer with project files

2.建置並執行專案

在 Visual Studio 工具列中,如果您的裝置為 64 位元,請將 [解決方案平台] 變更為 x64,以在本機電腦上執行專案,而如果是 32 位元,則變更為 x86。 (您可以簽入 Windows 設定 應用程式: 系統 > 關於 > 裝置規格 > 系統類型 。)

若要執行專案,按一下工具列上的 [開始偵錯] 按鈕,或按下 F5。 應用程式應該會顯示 InkCanvas(使用者可以在其中寫入數字)、[辨識] 按鈕以解釋數字 (所解釋的數字將顯示為文字的空白標籤欄位),以及 [清除數字] 按鈕以除 InkCanvas

Application screenshot

注意

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

注意

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

3.下載模型

接下來,取得機器學習模型以新增到我們的應用程式中。 在本教學課程中,我們會使用經由 Microsoft Cognitive Toolkit (CNTK) 訓練且匯出為 ONNX 格式的預先訓練 MNIST 模型。

MNIST 模型已包含在您的 Assets資料夾中,您需要將其視為現有項目新增到您的應用程式。 您也可以從 GitHub上的 ONNX 模型動物園 下載預先訓練模型。

4.新增模型

在 [方案總管] 中的 Assets 資料夾上按一下滑鼠右鍵,然後選取 [新增]>[現有項目]。 將檔案選擇器指向 ONNX 模型的位置,然後按一下 [新增]

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

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

Solution explorer with new files

在編譯應用程式時為了確保模型組建,請以滑鼠右鍵按一下 mnist.onnx 檔案,然後選取 [屬性]。 對於 [建置動作],選取 [內容]

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

  • mnistModel 會建立機器學習模型代表、在系統預設裝置上建立工作階段,將特定輸入和輸出繫結到模型,並以非同步方式評估模型。
  • mnistInput 會初始化模型預期的輸入類型。 在此案例中,輸入會預期 ImageFeatureValue
  • mnistOutput 會初始化模型將輸出的類型。 在此情況下,輸出會是名為 Plus214_Output_0 且類型為 TensorFloat 的清單。

現在我們將使用這些類別,以便在我們的專案中載入、繫結,以及評估模型。

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.儲存體]。下拉式功能表中的串流。

接下來,我們想要將我們的輸入與輸出繫結至模型。 產生的程式碼也包含 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 上繪製的數字。

complete application

這樣就完成了,您已經製作了您的第一個 Windows ML 應用程式! 如需示範如何使用 Windows ML 的更多範例,請參閱 GitHub 上的 Windows-Machine-Learning 存放庫。

注意

使用下列資源取得 Windows ML 的說明:

  • 如需詢問或回答有關 Windows ML 的技術問題,請使用 Stack Overflow 上的 windows-machine-learning 標籤。
  • 如需回報錯誤 (bug),請在 GitHub 上提出問題。