.net Framwork4.7.2 & VB.net でML.NETを試してみた(3)- モデルのトレーニングと画像認識
ML.NETの転移学習のチュートリアルを参照して、VB.NETで実装してみます。
データの準備
前回の続き、プロジェクトの直下にフォルダ「assets」、「workspace」を作成し、以下のサイトからダウンロードしたデータを解凍し、「CD」、「UD」フォルダを「assets」にコピーする。
「assets」:トレーニングデータ
「workspace」:トレーニングモデルのデータなど
SDNET2018 is an image dataset that contains annotations for cracked and non-cracked concrete structures (bridge decks, walls, and pavement).
The data is organized in three subdirectories:
- D contains bridge deck images
- P contains pavement images
- W contains wall images
Each of these subdirectories contains two additional prefixed subdirectories:
- C is the prefix used for cracked surfaces
- U is the prefix used for uncracked surfaces
In this sample, only bridge deck images are used.
ダブルクリックコピペ
Formをダブルクリック、記事最後に載っているコードを作成しました。詳細はML.NETの転移学習のチュートリアルを参照して、より詳しい解説が載っています。
早速実行して見ると、ビルドできませんでした。
これはCPUターゲットを間違えたためです。x64のCPUターゲットを作成し、もう一回実行する。
問題なく動いています。
出力のところに結構スレッド何とか終了しましたなどがあるが、それはトレーニングを加速するためにマルチスレッドを使っていると思います。
モデルを訓練するため、2、3分ぐらいかかります。
予測は時々NG
トレーニング時間が足らないかもしれません。また調べてみます。
トレーニングモデルができたみたいですが、毎回のトレーニングすると大変です。
次回、モデルの保存、読み込むなどをやってみます。
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.IO
Imports Microsoft.ML
Imports Microsoft.ML.Data
Imports Microsoft.ML.DataOperationsCatalog
Imports Microsoft.ML.Vision
Imports Microsoft.ML.Transforms
Imports Tensorflow.Data
Public Class Form1
#Region "Machine Learning"
'画像データクラス
Class ImageData
Public ImagePath As String
Public Label As String
End Class
'入力データクラス
Class ModelInput
Public Image() As Byte
Public LabelAsKey As UInt32
Public ImagePath As String
Public Label As String
'Public score As Double
End Class
'出力データクラス
Class ModelOutput
Public ImagePath As String
Public Label As String
Public PredictedLabel As String
End Class
'ワークスペース ディレクトリを作成する
Dim projectDirectory As String = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "../../../"))
Dim workspaceRelativePath As String = Path.Combine(projectDirectory, "workspace")
Public assetsRelativePath As String = Path.Combine(projectDirectory, "assets")
Dim theMLContext As MLContext = New MLContext()
Dim judgePicture As String
Dim testSet As IDataView
Dim images As IEnumerable(Of ImageData)
Dim theimageData As IDataView
Dim trainedModel As ITransformer
Dim predictionEngine As PredictionEngine(Of ModelInput, ModelOutput)
Dim modelSchema As DataViewSchema = Nothing
'データ読み込みユーティリティ メソッドを作成する
Public Iterator Function LoadImagesFromDirectory(ByVal folder As String, ByVal Optional useFolderNameAsLabel As Boolean = True) As IEnumerable(Of ImageData)
Dim files = Directory.GetFiles(folder, "*", SearchOption.AllDirectories)
For Each thefile In files
If *1 Then
Continue For
Else
Dim theLabel = Path.GetFileName(thefile)
If useFolderNameAsLabel Then
theLabel = Directory.GetParent(thefile).Name
Else
For index = 0 To theLabel.Length
If (Not Char.IsLetter(theLabel(index))) Then
theLabel = theLabel.Substring(0, index)
Exit For
End If
Next
End If
Yield New ImageData With {.ImagePath = thefile, .Label = theLabel}
End If
Next
End Function
'モデルを使用する
Private Sub OutputPrediction(ByVal prediction As ModelOutput)
Dim imageName As String = Path.GetFileName(prediction.ImagePath)
Console.WriteLine($"Image: {imageName} | Actual Value: {prediction.Label} | Predicted Value: {prediction.PredictedLabel}")
Debug.WriteLine($"Image: {imageName} | Actual Value: {prediction.Label} | Predicted Value: {prediction.PredictedLabel}")
End Sub
'1 枚の画像を分類する
Public Sub ClassifySingleImage(ByVal themlContext As MLContext, ByVal data As IDataView, ByVal trainModel As ITransformer)
Dim predictionEngine As PredictionEngine(Of ModelInput, ModelOutput) = themlContext.Model.CreatePredictionEngine(Of ModelInput, ModelOutput)(trainedModel)
Dim image As ModelInput = themlContext.Data.CreateEnumerable(Of ModelInput)(data, True).First()
Dim prediction As ModelOutput = predictionEngine.Predict(image)
Console.WriteLine("Classifying single image")
OutputPrediction(prediction)
End Sub
#End Region
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'データを準備する
images = LoadImagesFromDirectory(assetsRelativePath, True)
theimageData = theMLContext.Data.LoadFromEnumerable(images)
Dim shuffledData As IDataView = theMLContext.Data.ShuffleRows(theimageData)
Dim preprocessingPipeline As EstimatorChain(Of ImageLoadingTransformer) =
theMLContext.Transforms.Conversion.MapValueToKey("LabelAsKey", "Label").Append(
theMLContext.Transforms.LoadRawImageBytes("Image", assetsRelativePath, "ImagePath"))
Dim preProcessedData As IDataView = preprocessingPipeline.Fit(shuffledData).Transform(shuffledData)
Dim trainSplit As TrainTestData = theMLContext.Data.TrainTestSplit(preProcessedData, 0.3)
Dim validationTestSplit As TrainTestData = theMLContext.Data.TrainTestSplit(trainSplit.TestSet)
Dim trainSet As IDataView = trainSplit.TrainSet
Dim validationSet As IDataView = validationTestSplit.TrainSet
testSet = validationTestSplit.TestSet
'トレーニング パイプラインを定義する
Dim classifierOptions As ImageClassificationTrainer.Options = New ImageClassificationTrainer.Options With {
.FeatureColumnName = "Image",
.LabelColumnName = "LabelAsKey",
.ValidationSet = validationSet,
.Arch = ImageClassificationTrainer.Architecture.ResnetV2101,
.TestOnTrainSet = False,
.ReuseTrainSetBottleneckCachedValues = True,
.ReuseValidationSetBottleneckCachedValues = True,
.WorkspacePath = workspaceRelativePath
}
Dim trainingPipeline As EstimatorChain(Of KeyToValueMappingTransformer) = theMLContext.MulticlassClassification.Trainers.ImageClassification(classifierOptions).Append(theMLContext.Transforms.Conversion.MapKeyToValue("PredictedLabel"))
trainedModel = trainingPipeline.Fit(trainSet)
'画像のテスト セットを利用して ClassifySingleImage を呼び出します
ClassifySingleImage(theMLContext, testSet, trainedModel)
End Sub
End Class