AI應用開發實戰 - 定製化視覺服務的使用

AI應用開發實戰 - 定製化視覺服務的使用

本篇教程的目標是學會使用定製化視覺服務,並能在UWP應用中集成定製化視覺服務模型。html

前一篇:AI應用開發實戰 - 手寫識別應用入門git

建議和反饋,請發送到
https://github.com/Microsoft/vs-tools-for-ai/issues程序員

聯繫咱們
OpenmindChina@microsoft.comgithub

零、定製化視覺服務簡介

有的時候,在構建應用的過程當中,在缺乏強大計算資源與高性能算法的狀況下,咱們不必定須要本身從零開始訓練模型。咱們須要用的一些輪子,已經有人給咱們造好了。算法

就好比:c#

微軟提供的定製化視覺服務。windows

在機器學習應用中,任何狀況下都須要一個或大或小的模型。而怎麼獲得這個模型是其中最複雜的部分。定製化視覺服務至關於在雲端提供了一個生成模型的方法,把模型相關的複雜的算法都簡化了。同時,它不只可以讓用戶本身管理訓練數據,定義本身的分類問題,並且支持一鍵訓練,一鍵導出模型;不只能導出適配全部主流框架的模型,並且能夠生成REST接口,讓程序經過接口獲取圖片分類的結果。這樣給用戶提供了多種集成模型的方法和選擇,儘量知足用戶的各類需求,這也正是定製化視覺服務的強大之處。同時,經過定製化服務來生成模型,須要的數據量能夠很是少,訓練過程相對來講也很快。使用上也是很是的方便。數組

本篇教程,就教你們如何使用定製化視覺服務。服務器

定製化視覺服務官方地址 :https://customvision.ai/網絡

1、準備微軟帳號

使用該服務須要準備微軟帳號,能夠直接在定製化視覺服務官方地址上建立。

2、建立定製化視覺服務

截圖 操做
進入官方網站,點擊SIGN IN,目前定製化視覺服務提供了免費試用版,能夠體驗定製化視覺服務。
登陸後,而後界面會提示要求贊成一些條約。
條約的大體內容就是,我的必須在微軟要求的規則下使用微軟提供的這項服務。請勾選agree
此時,界面會提示註冊Azure,由於定製化視覺服務其實是Azure提供的一項雲服務,正式使用這項服務須要有Azure訂閱。
不過咱們如今只是免費試用,因此選擇Continue With trial,若是在根據這篇博客流程作完了一個小應用以後,你以爲確實須要使用這項服務,那麼你能夠去註冊Azure帳號,獲取Azure訂閱。

3、建立定製化視覺服務項目

點擊New Project,填寫項目信息。

這裏不妨以一個熊的分類模型做爲例子來實踐吧。

填寫好NameDescription,這裏Name不妨填寫爲BearClassification

隨後選擇ClassificationGeneral(compact),點擊Create

截圖 操做
Project Type一欄,定製化視覺服務提供了識別和分類兩種服務,另外提供了多種識別場景,其中末尾帶有(compact),也即壓縮字樣的三種。
壓縮模型,顧名思義,模型佔用的空間更少,運行更快,甚至能夠放到手機這種移動設備裏。
固然,會有一個小問題就是精確度會受影響。導出模型後,模型文件的使用是沒有任何限制的,而其他的幾種場景只能經過調用API來進行預測,因爲當前屬於免費試用,所以這種方式有10000次調用上限。
因爲分類服務須要準備用來訓練的數據集,請自行準備幾種不一樣的熊的照片,將同種的熊放在以這種熊的名字命名的文件夾裏,最後再將這些文件夾放在一個data文件夾中。而後點擊Add images
選擇一種熊的所有照片,而後建立對應的標籤,點擊Up load xxx files
在添加了全部的數據集和標籤以後,點擊網頁上方的Train,開始訓練模型。
一小會以後,點擊網頁上方的performance,就能夠看到此次訓練的結果了。
這裏簡單解釋一下Precision和Recall,這是兩個評估模型好壞的主要指標。
簡單來講,兩個數都是越大越好。在這個項目中,以Brown Bear爲例:
Precision就是識別出來的結果的準確率,即在全部被識別爲棕熊的圖片中真正有棕熊的圖片所佔的比例;而Recall則是測試結果中正確識別爲棕熊的圖片佔測試集中全部棕熊圖片的比例。
這時再點擊界面右上角的齒輪,能夠看到免費用戶每一個項目可以使用的服務額度:
一共能夠上傳5000張圖片,建立50個不一樣標籤,保存10次迭代的結果。
這十次迭代有什麼用呢?當須要增刪標籤、給標籤添加或刪除訓練圖片時,此次再訓練,就會花費掉一次迭代。
這些都是當前項目的總數而不是累計值。對於通常的免費用戶,這基本上就至關於你能夠隨意使用這項服務了,若是有大量的訓練數據,那麼建議您仍是訂閱Azure雲服務,Azure秉持着使用多少,收費多少的原則,即便收費,也仍然良心。
而後選擇剛剛訓練好的此次迭代,點擊Export
視覺認知服務一共提供了適用於四種平臺的模型導出,對三大操做系統都能支持。
選擇ONNX,這個格式由微軟、臉書、亞馬遜等大廠鼎力支持,點擊Export,等待服務器把模型導出,而後點擊Download,便可下載模型。最後獲得了一個.onnx文件,而後就可使用它來構建應用了。

若是須要上傳大量的圖片數據,那麼點擊鼠標的方式確定不夠方便,微軟同時提供了代碼的支持,詳見官方文檔:

https://docs.microsoft.com/en-us/azure/cognitive-services/custom-vision-service/home

4、使用Windows ML構建應用

此次不寫Winform程序,而是搭建一個識別熊的UWP的AI應用,經過這個應用來教你們如何使用Windows ML導入模型。

這部分的代碼已經完成了,請使用git克隆samples-for-ai到本地,UWP項目的代碼在/samples-for-ai/projects/BearClassificationUWPDemo中。

在運行代碼以前,請先安裝開發UWP所需的工做負載,流程以下:

  1. 打開Visual Studio Installer
  2. 在工做負載中勾選Universal Windows Platform development
  3. 在單個組件一欄中下拉到最下方,確認Windows 10 SDK(10.0.17134.0)已被勾選上,這是使用Windows ML開發的核心組件




另外,請將您的操做系統更新到1803版本,不然本程序將不能安裝。

若是您將進行相似的開發,請將UWP項目設置成最低運行目標版本爲17134,不然對於版本低於17134的用戶,在運行時會出現:

"Requested Windows Runtime type 'Windows.AI.MachineLearning.Preview.LearningModelPreview' is not registered."

詳見:https://github.com/MicrosoftDocs/windows-uwp/issues/575

安裝須要的時間比較長,能夠先看看UWP的視頻教程,作一作頭腦預熱: https://www.bilibili.com/video/av7997007

Visual Studio 和 Windows 更新完畢後,咱們打開CustomVisionApp.sln,運行這個程序。

你能夠從必應上查找一些熊的圖片,複製圖片的URL,粘貼到輸入框內,而後點擊識別按鈕;或者,點擊瀏覽按鈕,選擇一張本地圖片,點擊肯定,你就能夠看到識別結果了:




如今來看看這個程序是怎麼實現的。

咱們來梳理一下這個應用的邏輯,這個應用的邏輯與上一篇博客中的手寫數字識別大致上是同樣的:

  1. 導入模型
  2. 按下按鈕後,經過某種方式獲取要用來識別的圖片
  3. 將圖片交給模型識別
  4. 將圖片與識別結果展現在界面上

1. 文件結構:

文件結構見下圖:

  • Assets文件夾存放了這個項目的資產文件,好比程序圖標等等,在本示例程序中,.onnx文件也存放在其中。
  • Strings文件夾存放了用於本地化與全球化資源文件,這樣能夠支持不一樣的語言。
  • ViewModel文件夾中則存放了本項目的關鍵代碼,整個程序運行的邏輯都在ResultViewModel.cs中
  • BearClassification.cs則是系統自動生成的模型包裝文件
  • MainPage.xaml是程序的UI佈局文件

2. 核心代碼一:BearClassification.cs

這部分的代碼是自動生成的,教程詳見連接:https://docs.microsoft.com/zh-cn/windows/uwp/machine-learning/

  1. 將.onnx文件添加到UWP項目的Assets文件夾中,隨後將自動生成一個對應的包裝.cs文件,在本例中爲BearClassification.cs
  2. 因爲目前存在的一些BUG,生成的類名會有亂碼,須要將亂碼替換爲別的字符串。
  3. 修改BearClassification.onnx屬性->生成操做,將其改成內容,確保在生成時,可以調用到這個模型。

生成的文件共有三個類:

  • BearClassificationModelInput:定義了該模型的輸入格式是VideoFrame
  • BearClassificationModelOutput:定義了該模型的輸出爲一個list和一個dict,list存儲了全部標籤按照probability降序排列,dict則存儲了標籤與機率的鍵值對
  • BearClassificationModel:定義了該模型的初始化函數與推理函數
// 模型的輸入格式爲VideoFrame
public sealed class BearClassificationModelInput
{
    public VideoFrame data { get; set; }
}

// 模型的輸出格式,其中包含了一個列表:classLabel和一個字典:loss
// 列表中包含每種熊的標籤,按照機率降序排列
// 字典中則包含了每種熊的標籤和其機率,按照用戶在建立模型時的添加順序排列
public sealed class BearClassificationModelOutput
{
    public IList<string> classLabel { get; set; }
    public IDictionary<string, float> loss { get; set; }
    public BearClassificationModelOutput()
    {
        this.classLabel = new List<string>();
        this.loss = new Dictionary<string, float>(){...}
    }
}

// 模型的包裝類,提供了兩個函數
// CreateBearClassificationModel:從.onnx文件中建立模型
// EvaluateAsync:對輸入對象進行評估,並返回結果
public sealed class BearClassificationModel
{
    private LearningModelPreview learningModel;
    public static async Task<BearClassificationModel> CreateBearClassificationModel(StorageFile file)
    {
        ...
    }

    public async Task<BearClassificationModelOutput> EvaluateAsync(BearClassificationModelInput input)
    {
        ...
    }
}

3. 核心代碼二:ResultViewModel.cs

經過以前的運行能夠發現:每次識別圖片,UI中的內容須要進行頻繁地更新,爲了簡化更新控件內容的代碼邏輯,這個程序使用UWP開發中經常使用的MVVM(model-view-viewmodel)這一組合模式開發,使用「綁定」的方式,將UI控件與數據綁定起來,讓數據與界面自動地同步更新,簡化了代碼邏輯,保證了ResultViewModel職責單一。

綁定源(ResultViewMode.cs) 綁定目標(MainPage.xaml)
string BearUrl TextBox InputUriBox
ObservableCollection Results ListView ResultArea
BitmapImage BearImage Image DisplayArea
string Description TextBox DescribeArea
ICommand RecognizeCommand Button RecognizeButton
ICommand BrowseCommand Button BrowseButton

綁定好以後,程序還須要一系列邏輯才能運行,這裏就包括:

導入與初始化模型:

在程序一開始,須要調用LoadModel進行模型初始化工做。

private async void LoadModel()
{
    //導入模型文件,實例化模型對象
    StorageFile modelFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/BearClassification.onnx"));
    model = await BearClassificationModel.CreateBearClassificationModel(modelFile);
}

圖片推理:

本程序提供了兩種方式訪問圖片資源:

  1. 經過URL訪問網絡圖片
  2. 經過文件選取器訪問本地圖片
private async void EvaluateNetPicAsync()
{
    try
    {
        ...
        //BearClassification要求的輸入格式爲VideoFrame
        //程序須要以stream的形式從URL中讀取數據,生成VideoFrame
        var response = await new HttpClient().GetAsync(BearUrl);
        var stream = await response.Content.ReadAsStreamAsync();
        BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream.AsRandomAccessStream());
        VideoFrame imageFrame = VideoFrame.CreateWithSoftwareBitmap(await decoder.GetSoftwareBitmapAsync());

        //將videoframe交給函數進行識別
        EvaluateAsync(imageFrame);
    }
    catch (Exception ex){ ... }
}


private async void EvaluateLocalPicAsync()
{
    try
    {
        ...
        // 從文件選取器中得到文件
        StorageFile file = await openPicker.PickSingleFileAsync();
        var stream = await file.OpenReadAsync();
        ...
        // 生成videoframe
        BitmapDecoder decoder = await BitmapDecoder.CreateAsync(stream);
        VideoFrame imageFrame = VideoFrame.CreateWithSoftwareBitmap(await decoder.GetSoftwareBitmapAsync());

        // 將videoframe交給函數進行識別
        EvaluateAsync(imageFrame);
    }
    catch (Exception ex){ ... }
}

private async void EvaluateAsync(VideoFrame imageFrame)
{
    //將VideoFrame包裝進BearClassificationModelInput中,交給模型識別
    //模型的輸出格式爲BearClassificationModelOutput
    //其中包含一個列表,存儲了每種熊的標籤名稱,按照probability降序排列
    //和一個字典,存儲了每種熊的標籤,和對應的probability
    //這裏取出輸出中的字典,並對其進行降序排列
    var result = await model.EvaluateAsync(new BearClassificationModelInput() { data = imageFrame });
    var resultDescend = result.loss.OrderByDescending(p => p.Value).ToDictionary(p => p.Key, o => o.Value).ToList();

    //根據結果生成圖片描述
    Description = DescribResult(resultDescend.First().Key, resultDescend.First().Value);

    Results.Clear();
    foreach (KeyValuePair<string, float> kvp in resultDescend)
    {
        Results.Add(resourceLoader.GetString(kvp.Key) + " : " + kvp.Value.ToString("0.000"));
    }
}

5、使用其餘方法構建應用

一樣,用以前使用Visual Studio Tools for AI提供的推理類庫生成器也可以構建類似的應用。想看視頻教程的請移步:

【教程】普通程序員一小時入門AI應用——看圖識熊(不含公式,包會)

該教程講解了如何使用模型瀏覽工具Netron

想看圖文教程請繼續往下看:

1. 界面設計

建立Windows窗體應用(.NET Framework)項目,這裏給項目起名ClassifyBear。

注意,項目路徑不要包含中文。

在解決方案資源管理器中找到Form1.cs,雙擊,打開界面設計器。從工具箱中向Form中依次拖入控件並調整,最終效果以下圖所示:

左側從上下到依次是:

  • Label控件,將內容改成「輸入要識別的圖片地址:」
  • TextBox控件,能夠將控件拉長一些,方便輸入URL
  • Button控件,將內容改成「識別」
  • Lable控件,將label的內容清空,用來顯示識別後的結果。由於label也沒有邊框,因此在界面看不出來。能夠將此控件的字體調大一些,能更清楚的顯示推理結果。

右側的控件是一個PictureBox,用來預覽輸入的圖片,同時,咱們也從這個控件中取出對應的圖片數據,傳給咱們的模型推理類庫去推理。建議將控件屬性的SizeMode更改成StretchImage,並將控件長和寬設置爲一樣的值,保持一個正方形的形狀,這樣能夠方便咱們直觀的瞭解模型的輸入,由於在前面查看模型信息的時候也看到了,該模型的輸入圖片應是正方形。

2. 查看模型信息

在將模型集成到應用以前,咱們先來看一看模型的基本信息,好比模型須要什麼樣的輸入和輸出。打開Visual Studio中的AI工具菜單,選擇模型工具下的查看模型,會啓動Netron模型查看工具。該工具默認不隨Tools for AI擴展一塊兒安裝,第一次使用時能夠按照提示去下載並安裝。

Netron打開後,點擊Open model選擇打開以前下載的BearModel.onnx文件。而後點擊左上角的漢堡菜單顯示模型的輸入輸出。

上圖中能夠看到該模型須要的輸入data是一個float數組,數組中要求依次放置227*227圖片的全部藍色份量、綠色份量和紅色份量,後面程序中調用時要對輸入圖片作相應的處理。

上圖中還能夠看到輸出有兩個值,第一個值loss包含全部分類的得分,第二個值classLabel是肯定的分類的標籤,這裏只需用到第二個輸出便可。

3. 封裝模型推理類庫

因爲目前模型推理用到的庫只支持x64,因此這裏須要將解決方案平臺設置爲x64。打開解決方案資源管理器,在解決方案上點右鍵,選擇配置管理器。

在配置管理器對話框中,點開活動解決方案平臺下拉框,選擇新建

在新建解決方案平臺對話框中,輸入新平臺名x64,點擊肯定便可

下面添加模型推理類庫,再次打開解決方案資源管理器,在解決方案上點右鍵,選擇添加,而後選擇新建項目。

添加新項目對話框中,將左側目錄樹切換到AI Tools下的Inference,右側選擇模型推理類庫,下方填入項目名稱,這裏用Model做爲名稱。

肯定之後會出現檢查環境的進度條,耐心等待一會就能夠出現模型推理類庫建立嚮導對話框。

點擊模型路徑後面的瀏覽按鈕,選擇前面下載的BearModel.onnx模型文件。

注意,這裏會出現幾處錯誤提示,咱們須要手動修復一下。首先會看到「發現不支持的張量的數據類型」提示,能夠直接點肯定。

肯定後若是彈出「正在建立項目…」的進度條,一直不消失,這裏只須要在類名後面的輸入框內點一下,切換下焦點便可。

而後,咱們來手動配置一下模型的相關信息。類名輸入框中填入模型推理類的名字,這裏用Bear。而後點擊推理接口右側的添加按鈕,在彈出的編輯接口對話框中,隨便起個方法名,這裏用Infer。輸入節點的變量名和張量名填入data,輸出節點的變量名和張量名填入classLabel,字母拼寫要和以前查看模型時看到的拼寫如出一轍。而後一路肯定,再耐心等待一會,就能夠在解決方案資源管理器看到新建的模型推理類庫了。

還有一處錯誤須要手動修復一下,切換到解決方案資源管理器,在Model項目的Bear目錄下找到Bear.cs雙擊打開,將函數Infer的最後一行

return r0;

替換爲

List<List<string>> results = new List<List<string>>();
results.Add(r0);
return results;

至此,模型推理類庫封裝完成。相信Tools for AI未來的版本中會修復這些問題,直接選擇模型文件建立模型推理類庫就能夠了。

4. 使用模型推理類庫

首先添加對模型推理類庫的引用,切換到解決方案資源管理器,在ClassifyBear項目的引用上點右鍵,選擇添加引用。

在彈出的引用管理器對話框中,選擇項目、解決方案,右側能夠看到剛剛建立的模型推理類庫,勾選該項目,點擊肯定便可。

在Form1.cs上點右鍵,選擇查看代碼,打開Form1.cs的代碼編輯窗口。

添加兩個成員變量

// 使用Netron查看模型,獲得模型的輸入應爲227*227大小的圖片
private const int imageSize = 227;

// 模型推理類
private Model.Bear model;

回到Form1的設計界面,雙擊Form的標題欄,會自動跳轉到代碼頁面並添加了Form1_Load方法,在其中初始化模型推理對象

private void Form1_Load(object sender, EventArgs e)
{
    // 初始化模型推理對象
    model = new Model.Bear();
}

回到Form1的設計界面,雙擊識別按鈕,會自動跳轉到代碼頁面並添加了button1_Click方法,在其中添加如下代碼:

首先,每次點擊識別按鈕時都先將界面上顯示的上一次的結果清除

// 識別以前先重置界面顯示的內容
label1.Text = string.Empty;
pictureBox1.Image = null;
pictureBox1.Refresh();

而後,讓圖片控件加載圖片

bool isSuccess = false;
try
{
    pictureBox1.Load(textBox1.Text);
    isSuccess = true;
}
catch (Exception ex)
{
    MessageBox.Show($"讀取圖片時出現錯誤:{ex.Message}");
    throw;
}

若是加載成功,將圖片數據傳給模型推理類庫來推理。

if (isSuccess)
{
    // 圖片加載成功後,從圖片控件中取出227*227的位圖對象
    Bitmap bitmap = new Bitmap(pictureBox1.Image, imageSize, imageSize);

    float[] imageArray = new float[imageSize * imageSize * 3];

    // 按照先行後列的方式依次取出圖片的每一個像素值
    for (int y = 0; y < imageSize; y++)
    {
        for (int x = 0; x < imageSize; x++)
        {
            var color = bitmap.GetPixel(x, y);

            // 使用Netron查看模型的輸入發現
            // 須要依次放置227 *227的藍色份量、227*227的綠色份量、227*227的紅色份量
            imageArray[y * imageSize + x] = color.B;
            imageArray[y * imageSize + x + 1* imageSize * imageSize] = color.G;
            imageArray[y * imageSize + x + 2* imageSize * imageSize] = color.R;
        }
    }

    // 模型推理類庫支持一次推理多張圖片,這裏只使用一張圖片
    var inputImages = new List<float[]>();
    inputImages.Add(imageArray);

    // 推理結果的第一個First()是取第一張圖片的結果
    // 以前定義的輸出只有classLabel,因此第二個First()就是分類的名字
    label1.Text = model.Infer(inputImages).First().First();
}

注意,這裏的數據轉換必定要按照前面查看的模型的信息來轉換,圖片大小須要長寬都是227像素,而且要依次放置全部的藍色份量、全部的綠色份量、全部的紅色份量,若是順序不正確,不能達到最佳的推理結果。

5. 測試

編譯運行,而後在網上找一張熊的圖片,把地址填到輸入框內,而後點擊識別按鈕,就能夠看到識別的結果了。注意,這個URL應該是圖片的URL,而不是包含該圖片的網頁的URL。

6、下一步?

本篇博客咱們學會了使用定製化視覺服務與在UWP應用中集成定製化視覺服務模型。這裏我提兩個課後習題:(想不到吧)

  1. 當訓練含有多個標籤、大量圖片數據時,如何作到一鍵上傳圖片並訓練?

  2. 如何經過調用REST接口的方式完成對圖片的推理?

提示:請看看定製化視覺服務給咱們提供的API,這一題確定是要寫代碼作的
https://docs.microsoft.com/en-us/azure/cognitive-services/custom-vision-service/home

加油!

7、內容預告

接下來咱們將會陸續推出:

  1. 微軟認知服務使用教程
  2. 模型訓練及推理的一般流程及原理
  3. 模型轉換工具的使用
  4. 開放AI平臺-大規模計算資源調度系統

請在下方留言,告知咱們您最想閱讀哪一個教程,咱們將優先考慮。

若是您有別的想要了解的內容,也能夠在評論區留言。

相關文章
相關標籤/搜索