ML.NET 示例:图像分类模型训练-首选API(基于原生TensorFlow迁移学习)
| Microsoft.ML 1.5.0 | 動態API | 最新 | 控制臺應用程序和Web應用程序 | 圖片文件 | 圖像分類 | 基于遷移學習的TensorFlow模型再訓練進行圖像分類 | DNN架構:ResNet、InceptionV3、MobileNet等 |
問題
圖像分類是深度學習學科中的一個常見問題。此示例演示如何通過基于遷移學習方法訓練模型來創建您自己的自定義圖像分類器,該方法基本上是重新訓練預先訓練的模型(如InceptionV3或ResNet架構),這樣您就可以在自己的圖像上訓練自定義模型。
在這個示例應用程序中,您可以創建自己的自定義圖像分類器模型,方法是使用自己的圖像從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每個子文件夾的名稱很重要,因為它將是模型用于分類圖像的每個類/標簽的名稱。
機器學習任務-圖像分類
為了解決這個問題,我們首先要建立一個ML模型。然后我們將在現有數據上訓練模型,評估它有多好,最后我們將使用模型對新圖像進行分類。
1. 將項目配置為使用GPU或CPU
默認情況下,此解決方案使用CPU進行訓練和評分。但是,如果您的機器有一個兼容的GPU可用(基本上大多數NVIDIA GPU顯卡),您可以配置該項目使用GPU。
:警告:請確保使用下面列出的NuGet包的正確版本。其他版本可能與Nvidia CUDA v10.0不兼容
使用CPU進行訓練或推斷/評分
當使用CPU時,您的項目必須引用以下redist庫:
SciSharp.TensorFlow.Redist (1.15.0)?(CPU training)
使用CPU的訓練項目中的示例參考屏幕截圖:
使用GPU進行訓練或推斷/評分
使用GPU時,項目必須引用以下redist庫(并刪除CPU版本引用):
SciSharp.TensorFlow.Redist-Windows-GPU (1.14.0)?(GPU training on Windows)
SciSharp.TensorFlow.Redist-Linux-GPU (1.14.0)?(GPU training on Linux)
使用GPU的訓練項目中的示例參考屏幕截圖:
2. 構建模型
構建模型包括以下步驟:
將圖像文件(本例中為文件路徑)加載到IDataView中
使用ImageClassification評估器進行圖像分類(高級API)
定義數據架構,并在從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-parametersvar?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,???????//100BatchSize?=?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);運行項目來訓練模型
您應該按照以下步驟來訓練您的模型:
在Visual Studio中將ImageClassification.Train設置為啟動項目
在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個屬性:Image和ImageFileName)。該模型不使用ImageFileName。您只需將它放在這里,以便在顯示預測時可以將文件名打印出來。預測僅使用byte[] Image字段中的圖像位。
然后,模型返回類型為ImagePrediction的對象,該對象包含所有圖像類/類型的PredictedLabel和所有Scores。
由于PredictedLabel已經是一個字符串,因此它將顯示在控制臺中。關于預測標簽的分數,我們只需要取最高的分數,即預測標簽的概率。
運行“最終用戶應用程序”項目以嘗試預測
您應該按照以下步驟來使用您的模型:
在Visual Studio中將“ImageClassification.Predict”設置為啟動項目
在Visual Studio中按F5。幾秒鐘后,該過程將通過加載并使用自定義的imageClassifier.zip?模型來顯示預測。
用于評分/推斷的ASP.NET Core web應用示例
在示例的解決方案中,還有另一個名為ImageClassification.WebApp的項目,它是一個ASP.NET Core web應用程序,允許用戶通過HTTP提交圖像,并使用內存中的圖像進行評分/預測。
此示例還使用了PredictionEnginePool,建議用于多線程和可擴展的應用程序。
您可以在下面看到該應用的屏幕截圖:
TensorFlow DNN遷移學習背景信息
這個示例應用程序正在重新訓練用于圖像分類的TensorFlow模型。您可能認為它與另一個示例非常相似 Image classifier using the TensorFlow Estimator featurizer。不過,內部的實現方式卻有很大的不同。在上述示例中,它使用的是“模型合成方法”,其中初始TensorFlow模型(即InceptionV3或ResNet)僅用于對圖像進行特征化,并生成每個圖像的二進制信息,以供添加在頂部的另一個ML.NET分類器訓練器使用(例如LbfgsMaximumEntropy)。因此,即使該示例使用的是TensorFlow模型,您也只能使用ML.NET trainer進行訓練,您不會重新訓練新的TensorFlow模型,而是訓練ML.NET模型。這就是為什么該示例的輸出只是一個ML.NET模型(.zip文件)。
與此相反,本例在本地基于遷移學習方法對新的TensorFlow模型進行重新訓練,再從指定的預訓練模型(Inception V3或ResNet)派生的新TensorFlow模型進行了訓練。
重要的區別在于,這種方法使用TensorFlowAPI進行內部再訓練,并創建一個新的TensorFlow模型(.pb)。然后,您使用的ML.NET.zip文件模型就像是新的重新訓練的TensorFlow模型的包裝器。這就是為什么您還可以看到訓練后生成的新.pb文件的原因:
在下面的屏幕截圖中,您可以看到如何在Netron中看到重新訓練的TensorFlow模型(custom_retrained_model_based_on_InceptionV3.meta.pb),因為它是本機TensorFlow模型:
好處:
使用GPU進行訓練和推斷:當使用基于TensorFlow的本機DNN方法時,您可以使用CPU或GPU(如果可用)來獲得更好的性能(減少訓練和評分所需的時間)。
跨多個框架和平臺重用:由于您本機訓練了Tensorflow模型,除了能夠使用ML.NET 'wrapper'模型(.zip文件)運行/使用該模型之外,您還可以使用.pb Tensorflow凍結模型并在任何其他框架(如Python/Keras/Tensorflow)上運行它,或者Java/Android應用程序或任何支持TensorFlow的框架。
靈活性和性能:由于ML.NET是在Tensorflow層上進行內部再訓練的,因此ML.NET團隊將能夠進一步優化并采取多種方法,如在最后一層上進行訓練或跨Tensorflow模型在多個層上進行訓練,并獲得更好的質量水平。
總結
以上是生活随笔為你收集整理的ML.NET 示例:图像分类模型训练-首选API(基于原生TensorFlow迁移学习)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《权力》读书笔记
- 下一篇: ASP.NET Core 单元测试:如何