ML-NET 示例:圖像分類模型訓練 - 首選 API(基於原生 TensorFlow 遷移學習)

eXzjaF

問題

在這個示例應用程序中,您可以創建自己的自定義圖像分類器模型,方法是使用自己的圖像從 ML.NET API 本機訓練 TensorFlow 模型。

圖像分類器場景–使用 ML.NET 訓練您自己的定製深度學習模型

數據集(圖像集)

圖像集許可證

此示例的數據集基於 Tensorflow 提供的 “flower_photosimageset”,下載地址。此存檔中的所有圖像均獲得 Creative Commons By Attribution 許可證的許可,網址爲:https://creativecommons.org/licenses/by/2.0/

完整的許可證信息在 license.txt 文件中提供,該文件包含在作爲. zip 文件下載的同一圖像集中。

默認情況下,示例下載的 imageset 有 200 個圖像,平均分佈在 5 個 flower 類中:

Images --> flower_photos_small_set -->
           |
           daisy
           |
           dandelion
           |
           roses
           |
           sunflowers
           |
           tulips

機器學習任務 - 圖像分類

1. 將項目配置爲使用 GPU 或 CPU

默認情況下,此解決方案使用 CPU 進行訓練和評分。但是,如果您的機器有一個兼容的 GPU 可用(基本上大多數 NVIDIA GPU 顯卡),您可以配置該項目使用 GPU。

: 警告:請確保使用下面列出的 NuGet 包的正確版本。其他版本可能與 Nvidia CUDA v10.0 不兼容

使用 CPU 進行訓練或推斷 / 評分

當使用 CPU 時,您的項目必須引用以下 redist 庫:

使用 CPU 的訓練項目中的示例參考屏幕截圖:

使用 GPU 進行訓練或推斷 / 評分

使用 GPU 時,項目必須引用以下 redist 庫(並刪除 CPU 版本引用):

使用 GPU 的訓練項目中的示例參考屏幕截圖:

2. 構建模型

構建模型包括以下步驟:

定義數據架構,並在從 files 文件夾加載圖像時引用該類型。

public class ImageData
{
    public ImageData(string imagePath, string label)
    {
        ImagePath = imagePath;
        Label = label;
    }

    public readonly string ImagePath;
    public readonly string Label;
}

由於 API 使用內存圖像,因此稍後您可以使用內存圖像對模型進行評分,因此需要定義一個包含 “byte[]image” 類型中圖像位的類,如下所示:

public class InMemoryImageData
{
    public InMemoryImageData(byte[] image, string label, string imageFileName)
    {
        Image = image;
        Label = label;
        ImageFileName = imageFileName;
    }

    public readonly byte[] Image;
    public readonly string Label;
    public readonly string ImageFileName;
}

使用 LoadImagesFromDirectory()和 LoadFromEnumerable()下載 imageset 並加載其信息。

// 1. Download the image set and unzip
string finalImagesFolderName = DownloadImageSet(imagesDownloadFolderPath);
string fullImagesetFolderPath = Path.Combine(imagesDownloadFolderPath, finalImagesFolderName);

var mlContext = new MLContext(seed: 1);

// 2. Load the initial full image-set into an IDataView and shuffle so it'll be better balanced
IEnumerable<ImageData> images = LoadImagesFromDirectory(folder: fullImagesetFolderPath, useFolderNameAsLabel: true);
IDataView fullImagesDataset = mlContext.Data.LoadFromEnumerable(images);
IDataView shuffledFullImageFilePathsDataset = mlContext.Data.ShuffleRows(fullImagesDataset);

將數據加載到 IDataView 後,將對這些行進行混洗,以便在拆分爲訓練 / 測試數據集之前更好地平衡數據集。。

下一步非常重要。因爲我們希望 ML 模型能夠處理內存中的圖像,所以我們需要將圖像加載到數據集中,並通過調用 fit() 和 ttransform() 來實現。需要在初始且分離的管道中執行此步驟,以便在訓練時,管道和模型不會使用文件路徑來創建。

// 3. Load Images with in-memory type within the IDataView and Transform Labels to Keys (Categorical)
IDataView shuffledFullImagesDataset = mlContext.Transforms.Conversion.
        MapValueToKey(outputColumnName: "LabelAsKey", inputColumnName: "Label", keyOrdinality: KeyOrdinality.ByValue)
    .Append(mlContext.Transforms.LoadRawImageBytes(
                                    outputColumnName: "Image",
                                    imageFolder: fullImagesetFolderPath,
                                    inputColumnName: "ImagePath"))
    .Fit(shuffledFullImageFilePathsDataset)
    .Transform(shuffledFullImageFilePathsDataset);

此外,在分割數據集之前,我們還將標籤轉換爲鍵(分類)。如果您不想在第二個管道(訓練管道)中轉換標籤時處理 / 匹配 KeyOrdinality,那麼在拆分之前執行此操作也很重要。

現在,讓我們將數據集分成兩個數據集,一個用於訓練,另一個用於測試 / 驗證模型的質量。

// 4. Split the data 80:20 into train and test sets, train and evaluate.
var trainTestData = mlContext.Data.TrainTestSplit(shuffledFullImagesDataset, testFraction: 0.2);
IDataView trainDataView = trainTestData.TrainSet;
IDataView testDataView = trainTestData.TestSet;

作爲最重要的步驟,您可以定義模型的訓練管道,在這裏您可以看到如何輕鬆地訓練一個新的 TensorFlow 模型,該模型基於默認體系結構(預先訓練的模型)的遷移學習,例如 Resnet V2 500

// 5. Define the model's training pipeline using DNN default values
//
var pipeline = mlContext.MulticlassClassification.Trainers
        .ImageClassification(featureColumnName: "Image",
                                labelColumnName: "LabelAsKey",
                                validationSet: testDataView)
    .Append(mlContext.Transforms.Conversion.MapKeyToValue(outputColumnName: "PredictedLabel",
                                                          inputColumnName: "PredictedLabel"));

上面代碼中的重要一行是使用mlContext.MulticlassClassification.Trainers.ImageClassification分類訓練器的行,正如您所看到的,這是一個高級 API,您只需要提供哪個列包含圖像,帶有標籤的列(要預測的列)和用於在訓練時計算質量度量的驗證數據集,以便模型在訓練時可以自我調整(更改內部超參數)。

在本質上,此模型訓練基於從默認體系結構(預先訓練的模型)學習的本地 TensorFlow DNN 遷移,例如 Resnet V2 50。還可以通過配置可選的超參數來選擇要從中派生的超參數。

就這麼簡單,您甚至不需要進行圖像變換(調整大小、規格化等)。根據所使用的 DNN 架構,該框架在幕後進行所需的圖像轉換,因此您只需使用單個 API 即可。

可選使用高級超參數

高級用戶還有另一種重載方法,您還可以指定可選的超參數,例如 epoch,batchSize,learningRate,特定的 DNN 架構,例如 Inception v3 或者 Resnet v2101 和其他典型的 DNN 參數,但大多數用戶都可以從簡化的 API 開始。

以下是如何使用高級 DNN 參數:

// 5.1 (OPTIONAL) Define the model's training pipeline by using explicit hyper-parameters

var options = new ImageClassificationTrainer.Options()
{
    FeatureColumnName = "Image",
    LabelColumnName = "LabelAsKey",
    // Just by changing/selecting InceptionV3/MobilenetV2/ResnetV250
    // you can try a different DNN architecture (TensorFlow pre-trained model).
    Arch = ImageClassificationTrainer.Architecture.MobilenetV2,
    Epoch = 50,       //100
    BatchSize = 10,
    LearningRate = 0.01f,
    MetricsCallback = (metrics) => Console.WriteLine(metrics),
    ValidationSet = testDataView
};

var pipeline = mlContext.MulticlassClassification.Trainers.ImageClassification(options)
        .Append(mlContext.Transforms.Conversion.MapKeyToValue(
            outputColumnName: "PredictedLabel",
            inputColumnName: "PredictedLabel"));

3. 訓練模型

爲了開始訓練過程,您需要在構建的管道上運行Fit

// 4. Train/create the ML model
ITransformer trainedModel = pipeline.Fit(trainDataView);

4. 評估模型

訓練完成後,利用測試數據集對模型進行質量評價。

Evaluate函數需要一個IDataView,其中包含通過調用 Transform() 從測試數據集生成的預測。

// 5. Get the quality metrics (accuracy, etc.)
IDataView predictionsDataView = trainedModel.Transform(testDataset);

var metrics = mlContext.MulticlassClassification.Evaluate(predictionsDataView, labelColumnName:"LabelAsKey", predictedLabelColumnName: "PredictedLabel");
ConsoleHelper.PrintMultiClassClassificationMetrics("TensorFlow DNN Transfer Learning", metrics);

最後,保存模型:

// Save the model to assets/outputs (You get ML.NET .zip model file and TensorFlow .pb model file)
mlContext.Model.Save(trainedModel, trainDataView.Schema, outputMlNetModelFilePath);

運行項目來訓練模型

您應該按照以下步驟來訓練您的模型:

  1. 在 Visual Studio 中將ImageClassification.Train設置爲啓動項目

  2. 在 Visual Studio 中按 F5。幾秒鐘後,該過程將完成並保存一個新的 ML.NET 模型到文件assets/outputs/imageClassifier.zip

5. “終端用戶” 應用中的使用模型

GPU 與 CPU 對模型的使用 / 評分對比

在使用 / 評分模型時,您也可以在 CPU/GPU 之間進行選擇,但是,如果使用 GPU,您還需要確保運行模型的計算機 / 服務器支持 GPU。

設置評分 / 使用項目以使用 GPU 的方法與本 readme.md 開頭所述的方法相同,只需使用一個或另一個 redist 庫。

用於評分的示例控制檯應用程序

在示例的解決方案中,還有第二個項目名爲 ImageClassifcation.Predict。這個控制檯應用程序只需加載您定製的 ML.NET 模型,並以假設的最終用戶應用程序的方式執行一些樣本預測。

首先要做的是將生成的assets/outputs/imageClassifier.zip文件複製 / 粘貼到使用項目的 inputs/MLNETModel 文件夾中。

關於代碼,您首先需要加載在模型訓練應用執行期間創建的模型。

MLContext mlContext = new MLContext(seed: 1);
ITransformer loadedModel = mlContext.Model.Load(imageClassifierModelZipFilePath, out var modelInputSchema);

然後,您可以創建一個預測器引擎對象,並最終使用文件夾assets/inputs/images-for-predictions的第一個圖像進行一些樣本預測,其中只有一些圖像在訓練模型時沒有使用。

請注意,在評分時,只需要具有內存圖像的InMemoryImageData類型。

該圖像也可以通過任何其他通道傳輸,而不是從文件中加載。例如,這個解決方案中的ImageClassification.WebApp通過 HTTP 獲取將要用於預測的圖像。

var predictionEngine = mlContext.Model.CreatePredictionEngine<InMemoryImageData, ImagePrediction>(loadedModel);

//Predict the first image in the folder
IEnumerable<InMemoryImageData> imagesToPredict = LoadInMemoryImagesFromDirectory(
                                                        imagesFolderPathForPredictions, false);

InMemoryImageData imageToPredict = new InMemoryImageData
{
    Image = imagesToPredict.First().Image,
    ImageFileName = imagesToPredict.First().ImageFileName
};

var prediction = predictionEngine.Predict(imageToPredict);

// Get the highest score and its index
float maxScore = prediction.Score.Max();

Console.WriteLine($"Image Filename : [{imageToPredict.ImageFileName}], " +
                    $"Predicted Label : [{prediction.PredictedLabel}], " +
                    $"Probability : [{maxScore}] "
                    );

預測引擎接收InMemoryImageData類型的對象作爲參數(包含 2 個屬性:ImageImageFileName)。該模型不使用 ImageFileName。您只需將它放在這裏,以便在顯示預測時可以將文件名打印出來。預測僅使用byte[] Image字段中的圖像位。

然後,模型返回類型爲ImagePrediction的對象,該對象包含所有圖像類 / 類型的PredictedLabel和所有Scores

由於PredictedLabel已經是一個字符串,因此它將顯示在控制檯中。關於預測標籤的分數,我們只需要取最高的分數,即預測標籤的概率。

運行 “最終用戶應用程序” 項目以嘗試預測

您應該按照以下步驟來使用您的模型:

  1. 在 Visual Studio 中將 “ImageClassification.Predict” 設置爲啓動項目

  2. 在 Visual Studio 中按 F5。幾秒鐘後,該過程將通過加載並使用自定義的imageClassifier.zip 模型來顯示預測。

用於評分 / 推斷的 ASP.NET Core web 應用示例

在示例的解決方案中,還有另一個名爲 ImageClassification.WebApp 的項目,它是一個 ASP.NET Core web 應用程序,允許用戶通過 HTTP 提交圖像,並使用內存中的圖像進行評分 / 預測。

此示例還使用了PredictionEnginePool,建議用於多線程和可擴展的應用程序。

您可以在下面看到該應用的屏幕截圖:

TensorFlow DNN 遷移學習背景信息

與此相反,本例在本地基於遷移學習方法對新的 TensorFlow 模型進行重新訓練,再從指定的預訓練模型(Inception V3 或 ResNet)派生的新 TensorFlow 模型進行了訓練。

重要的區別在於,這種方法使用 TensorFlowAPI 進行內部再訓練,並創建一個新的 TensorFlow 模型(.pb)。然後,您使用的 ML.NET.zip 文件模型就像是新的重新訓練的 TensorFlow 模型的包裝器。這就是爲什麼您還可以看到訓練後生成的新. pb 文件的原因:

在下面的屏幕截圖中,您可以看到如何在 Netron 中看到重新訓練的 TensorFlow 模型(custom_retrained_model_based_on_InceptionV3.meta.pb),因爲它是本機 TensorFlow 模型:

好處:

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/DPfO96YF0gyXuWLBvvRTAw