.net Framwork4.7.2 & VB.net でML.NETを試してみた(3)- モデルのトレーニングと画像認識

ML.NETの転移学習のチュートリアルを参照して、VB.NETで実装してみます。

docs.microsoft.com

 

データの準備

前回の続き、プロジェクトの直下にフォルダ「assets」、「workspace」を作成し、以下のサイトからダウンロードしたデータを解凍し、「CD」、「UD」フォルダを「assets」にコピーする。

「assets」:トレーニングデータ

「workspace」:トレーニングモデルのデータなど

digitalcommons.usu.edu

f:id:sesnail:20200925183820p:plain

training Data Download

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の転移学習のチュートリアルを参照して、より詳しい解説が載っています。

f:id:sesnail:20200925174952p:plain

Form画像

 

早速実行して見ると、ビルドできませんでした。

これはCPUターゲットを間違えたためです。x64のCPUターゲットを作成し、もう一回実行する。

f:id:sesnail:20200925185306p:plain

CPUターゲットを変更

f:id:sesnail:20200925185350p:plain

64bit CPUターゲットを作成

問題なく動いています。

出力のところに結構スレッド何とか終了しましたなどがあるが、それはトレーニングを加速するためにマルチスレッドを使っていると思います。

 

モデルを訓練するため、2、3分ぐらいかかります。

予測は時々NG

レーニング時間が足らないかもしれません。また調べてみます。

 

レーニングモデルができたみたいですが、毎回のトレーニングすると大変です。

次回、モデルの保存、読み込むなどをやってみます。

 

f:id:sesnail:20200925185033p:plain

実行中

f:id:sesnail:20200925190707p:plain

間違えた予測結果

 

f:id:sesnail:20200925191100p:plain

レーニングした後の「workspace」フォルダ



 

 

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

*1:Path.GetExtension(thefile) <> ".jpg") And (Path.GetExtension(thefile) <> ".png"