チュートリアル: ML.NET 分類モデルをトレーニングして画像を分類する

画像処理のために事前トレーニングされた TensorFlow モデルを使用して、画像を分類するために分類モデルをトレーニングする方法について説明します。

TensorFlow モデルは、画像を 1,000 個のカテゴリに分類するためにトレーニングされました。 TensorFlow モデルを使用すれば画像内のパターンを認識する方法がわかっているため、その一部を ML.NET モデルのパイプライン内で利用して未加工の画像を特徴や入力に変換し、分類モデルをトレーニングすることができます。

このチュートリアルでは、次の作業を行う方法について説明します。

  • 問題を把握する
  • 事前トレーニング済みの TensorFlow モデルを ML.NET パイプラインに組み込む
  • ML.NET モデルのトレーニングと評価
  • テスト画像を分類する

このチュートリアルのソース コードは dotnet/samples リポジトリで確認できます。 既定では、このチュートリアルの .NET プロジェクトの構成は .NET Core 2.2 を対象としています。

必須コンポーネント

適切な機械学習タスクを選択する

ディープ ラーニング

ディープ ラーニングは、コンピューター ビジョンや音声認識などの分野に革命を起こしている、機械学習のサブセットです。

ディープ ラーニング モデルは、複数の学習レイヤーを含む多数のラベル付きデータニューラル ネットワークを使用してトレーニングされます。 ディープ ラーニング:

  • コンピューター ビジョンなどの一部のタスクでより効果的に機能します。
  • 大量のトレーニング データが必要です。

画像分類は、画像を次のようなカテゴリに自動的に分類することができる、特定の機械学習タスクです。

  • 画像から人の顔を検出するかどうか。
  • 猫と犬の検出。

または、次の画像のように、画像が食品、おもちゃ、または電化製品のいずれであるかを判断する場合。

ピザ画像テディベア画像トースター画像

注意

上の画像は Wikimedia Commons に属し、次のように属性が付けられています。

画像分類モデルを最初からトレーニングするには、数百万のパラメーター、大量のラベル付きトレーニング データ、膨大な量の計算リソース (数百時間の GPU) を設定する必要があります。 最初からカスタム モデルをトレーニングするほど効果的ではありませんが、事前トレーニング済みのモデルを使用すると、何千もの画像と何百万ものラベル付き画像を使用し、カスタマイズされたモデルを短時間 (GPU が搭載されていないマシンで 1 時間以内) で構築できます。 このチュートリアルでは、1 ダースのトレーニング画像のみを使用して、そのプロセスをさらにスケールダウンします。

Inception model は、画像を 1,000 個のカテゴリに分類するようにトレーニングされていますが、このチュートリアルでは、画像をより小さなカテゴリ セットにのみ分類する必要があります。 Inception model の、画像を認識してカスタム画像分類器の新しい限られたカテゴリに分類する能力を使用することができます。

  • 食品
  • おもちゃ
  • アプライアンス

このチュートリアルでは、TensorFlow の Inception ディープ ラーニング モデルを使用します。これは、ImageNet データセットに対してトレーニングされた、よく使われる画像認識モデルです。 TensorFlow モデルでは、画像全体を "傘"、"ジャージー"、"食器洗い機" などの 1,000 個のクラスに分類します。

Inception model は何千種類もの画像に対して事前にトレーニングされているため、画像の識別に必要な画像の特徴が内部に含まれています。 モデルでこれらの内部画像機能を利用して、はるかに少数のクラスで新しいモデルをトレーニングすることができます。

次の図に示すように、.NET Core または .NET Framework アプリケーションに ML.NET NuGet パッケージへの参照を追加します。 内部的には、既存のトレーニング済み TensorFlow モデル ファイルを読み込むコードを作成できるネイティブ TensorFlow ライブラリが ML.NET には含まれ、参照されています。

TensorFlow 変換 ML.NET Arch 図

多クラス分類

TensorFlow Inception モデルを使用して、従来の機械学習アルゴリズムの入力に適した特徴を抽出したら、ML.NET の多クラス分類器を追加します。

この場合に使用される特定のトレーナーは、多項ロジスティック回帰アルゴリズムです。

このトレーナーに実装されているアルゴリズムは、多数の特徴を持つ問題 (画像データに対して機能するディープ ラーニング モデルのケース) に適しています。

詳細については、ディープ ラーニングと機械学習の違いに関するページを参照してください。

データ

データ ソースは 2 つあります。.tsv ファイルと画像ファイルです。 tags.tsv ファイルには 2 つの列があります。最初の列は ImagePath と定義され、2 番目の列は画像に対応する Label です。 次のファイル例にはヘッダー行がなく、次のような内容です。

broccoli.jpg	food
pizza.jpg	food
pizza2.jpg	food
teddy2.jpg	toy
teddy3.jpg	toy
teddy4.jpg	toy
toaster.jpg	appliance
toaster2.png	appliance

トレーニングとテストの画像は、zip ファイルでダウンロードする資産フォルダー内にあります。 これらの画像は Wikimedia Commons に属します。

Wikimedia Commons、無料メディア リポジトリ。 2018 年 10 月 17 日 10:48 に以下から取得: https://commons.wikimedia.org/wiki/Pizzahttps://commons.wikimedia.org/wiki/Toasterhttps://commons.wikimedia.org/wiki/Teddy_bear

セットアップ

プロジェクトを作成する

  1. "TransferLearningTF" という C# コンソール アプリケーションを作成します。 [次へ] をクリックします。

  2. 使用するフレームワークとして [.NET 6] を選択します。 [作成] ボタンをクリックします。

  3. Microsoft.ML NuGet パッケージをインストールします。

    注意

    このサンプルでは、特に明記されていない限り、記載されている最新の安定バージョンの NuGet パッケージを使用します。

    • ソリューション エクスプローラーで、プロジェクトを右クリックし、 [NuGet パッケージの管理] を選択します。
    • [パッケージ ソース] として "nuget.org" を選択し、[参照] タブを選択し、"Microsoft.ML" を検索します。
    • [インストール] ボタンを選択します。
    • [変更のプレビュー] ダイアログで [OK] ボタンを選択します。
    • 一覧表示されているパッケージのライセンス条項に同意する場合は、 [ライセンスへの同意] ダイアログで [同意する] ボタンを選択します。
    • Microsoft.ML.ImageAnalyticsSciSharp.TensorFlow.Redist、および Microsoft.ML.TensorFlow に対して、これらの手順を繰り返します。

資産をダウンロードする

  1. プロジェクト資産ディレクトリの zip ファイルをダウンロードし、展開します。

  2. assets ディレクトリを TransferLearningTF プロジェクト ディレクトリにコピーします。 このディレクトリとそのサブディレクトリには、このチュートリアルに必要なデータ ファイルとサポート ファイル (次の手順でダウンロードして追加する Inception モデルを除く) が含まれています。

  3. Inception モデルをダウンロードして展開します。

  4. inception5h ディレクトリの内容をコピーし、TransferLearningTF プロジェクトの assets/inception ディレクトリに展開します。 次の画像に示すように、このディレクトリには、このチュートリアルに必要なモデルと追加のサポート ファイルが含まれています。

    Inception ディレクトリの内容

  5. ソリューション エクスプローラーで、資産ディレクトリとサブディレクトリ内の各ファイルを右クリックし、 [プロパティ] を選択します。 [詳細設定] で、 [出力ディレクトリにコピー] の値を [新しい場合はコピーする] に変更します。

クラスを作成してパスを定義する

  1. 次に示す追加の using ステートメントを Program.cs ファイルの先頭に追加します。

    using Microsoft.ML;
    using Microsoft.ML.Data;
    
  2. using ステートメントのすぐ下の行に次のコードを追加して、資産パスを指定します。

    string _assetsPath = Path.Combine(Environment.CurrentDirectory, "assets");
    string _imagesFolder = Path.Combine(_assetsPath, "images");
    string _trainTagsTsv = Path.Combine(_imagesFolder, "tags.tsv");
    string _testTagsTsv = Path.Combine(_imagesFolder, "test-tags.tsv");
    string _predictSingleImage = Path.Combine(_imagesFolder, "toaster3.jpg");
    string _inceptionTensorFlowModel = Path.Combine(_assetsPath, "inception", "tensorflow_inception_graph.pb");
    
  3. 入力データと予測のためにクラスを作成します。

    public class ImageData
    {
        [LoadColumn(0)]
        public string? ImagePath;
    
        [LoadColumn(1)]
        public string? Label;
    }
    

    ImageData は、入力画像データ クラスであり、次の String フィールドがあります。

    • ImagePath には、画像ファイル名が含まれます。
    • Label には、画像ラベルの値が含まれます。
  4. ImagePrediction のプロジェクトに新しいクラスを追加します。

    public class ImagePrediction : ImageData
    {
        public float[]? Score;
    
        public string? PredictedLabelValue;
    }
    

    ImagePrediction は、画像予測クラスであり、次のフィールドがあります。

    • Score には、指定した画像分類の信頼度が含まれています。
    • PredictedLabelValue には、予測された画像分類ラベルの値が含まれています。

    ImagePrediction は、モデルがトレーニングされた後に、予測に使用されるクラスです。 これには画像パスの string (ImagePath) が含まれます。 Label はモデルの再利用とトレーニングに使用されます。 PredictedLabelValue は予測と評価の際に使用されます。 評価では、トレーニング データを含む入力、予測された値、およびモデルが使用されます。

変数の初期化

  1. 新しいインスタンスの MLContext を使用して mlContext 変数を初期化します。 Console.WriteLine("Hello World!") の行を次のコードに置き換えます。

    MLContext mlContext = new MLContext();
    

    MLContext クラスは、すべての ML.NET 操作の開始点であり、mlContext を初期化することで、モデル作成ワークフローのオブジェクト間で共有できる新しい ML.NET 環境が作成されます。 これは Entity Framework における DBContext と概念的には同じです。

Inception モデル パラメーターの構造体を作成する

  1. Inception モデルには、渡す必要があるパラメーターがいくつかあります。 次のコードを使用して、mlContext 変数の初期化の直後に、パラメーター値をフレンドリ名にマップする構造体を作成します。

    struct InceptionSettings
    {
        public const int ImageHeight = 224;
        public const int ImageWidth = 224;
        public const float Mean = 117;
        public const float Scale = 1;
        public const bool ChannelsLast = true;
    }
    

表示ユーティリティ メソッドを作成する

画像データとそれに関連する予測を複数回表示するので、画像と予測結果の表示を処理する表示ユーティリティ メソッドを作成します。

  1. InceptionSettings 構造体の直後に、次のコードを使用して DisplayResults() メソッドを作成します。

    void DisplayResults(IEnumerable<ImagePrediction> imagePredictionData)
    {
    
    }
    
  2. DisplayResults メソッドの本体を入力します。

    foreach (ImagePrediction prediction in imagePredictionData)
    {
        Console.WriteLine($"Image: {Path.GetFileName(prediction.ImagePath)} predicted as: {prediction.PredictedLabelValue} with score: {prediction.Score?.Max()} ");
    }
    

予測を行うメソッドを作成する

  1. DisplayResults() メソッドの直前に、次のコードを使用して ClassifySingleImage() メソッドを作成します。

    void ClassifySingleImage(MLContext mlContext, ITransformer model)
    {
    
    }
    
  2. 1 つの ImagePath の完全修飾パスと画像ファイル名を含む ImageData オブジェクトを作成します。 ClassifySingleImage() メソッドの次の行として、次のコードを追加します。

    var imageData = new ImageData()
    {
        ImagePath = _predictSingleImage
    };
    
  3. 次のコードを ClassifySingleImage メソッドの次の行として追加して、1 つの予測を作成します。

    // Make prediction function (input = ImageData, output = ImagePrediction)
    var predictor = mlContext.Model.CreatePredictionEngine<ImageData, ImagePrediction>(model);
    var prediction = predictor.Predict(imageData);
    

    予測を取得するには、Predict() メソッドを使用します。 PredictionEngine は、データの 1 つのインスタンスに対して予測を実行できる便利な API です。 PredictionEngine はスレッド セーフではありません。 シングル スレッド環境またはプロトタイプ環境で使用できます。 運用環境でパフォーマンスとスレッド セーフを向上させるには、PredictionEnginePool サービスを使用します。これにより、アプリケーション全体で使用するできる PredictionEngine オブジェクトの ObjectPool が作成されます。 ASP.NET Core Web API で PredictionEnginePool を使用する方法については、こちらのガイドを参照してください。

    注意

    PredictionEnginePool サービスの拡張機能は、現在プレビュー段階です。

  4. ClassifySingleImage() メソッドの次のコード行として予測結果を表示します。

    Console.WriteLine($"Image: {Path.GetFileName(imageData.ImagePath)} predicted as: {prediction.PredictedLabelValue} with score: {prediction.Score?.Max()} ");
    

ML.NET モデルのパイプラインを構築する

ML.NET モデルのパイプラインは推定器のチェーンです。 パイプラインの構築中に実行は発生しません。 推定器オブジェクトは作成されますが、実行されません。

  1. モデルを生成するメソッドを追加する

    このメソッドは、このチュートリアルの中核となるものです。 モデルのパイプラインを作成し、パイプラインをトレーニングして ML.NET モデルを生成します。 また、未認識のテスト データに対してモデルを評価します。

    InceptionSettings 構造体の直後、かつ DisplayResults() メソッドの直前に、次のコードを使用して GenerateModel() メソッドを作成します。

    ITransformer GenerateModel(MLContext mlContext)
    {
    
    }
    
  2. 画像データを読み込み、サイズを変更し、ピクセルを抽出する推定器を追加します。

    IEstimator<ITransformer> pipeline = mlContext.Transforms.LoadImages(outputColumnName: "input", imageFolder: _imagesFolder, inputColumnName: nameof(ImageData.ImagePath))
                    // The image transforms transform the images into the model's expected format.
                    .Append(mlContext.Transforms.ResizeImages(outputColumnName: "input", imageWidth: InceptionSettings.ImageWidth, imageHeight: InceptionSettings.ImageHeight, inputColumnName: "input"))
                    .Append(mlContext.Transforms.ExtractPixels(outputColumnName: "input", interleavePixelColors: InceptionSettings.ChannelsLast, offsetImage: InceptionSettings.Mean))
    

    画像データは、TensorFlow モデルで想定されている形式に処理する必要があります。 この場合、画像はメモリに読み込まれ、サイズが一貫したサイズに変更され、ピクセルが数値ベクターに抽出されます。

  3. TensorFlow モデルを読み込み、評価する推定器を追加します。

    .Append(mlContext.Model.LoadTensorFlowModel(_inceptionTensorFlowModel).
        ScoreTensorFlowModel(outputColumnNames: new[] { "softmax2_pre_activation" }, inputColumnNames: new[] { "input" }, addBatchDimensionInput: true))
    

    パイプラインのこのステージでは、TensorFlow モデルをメモリに読み込み、次に TensorFlow モデル ネットワークを介してピクセル値のベクターを処理します。 ディープ ラーニング モデルに入力を適用し、モデルを使用して出力を生成することは、スコアリングと呼ばれます。 モデル全体を使用する場合、スコアリングによって推論または予測が行われます。

    この場合、最後のレイヤー (推論を行うレイヤー) を除き、すべての TensorFlow モデルを使用します。 最後から 2 番目のレイヤーの出力には、softmax_2_preactivation というラベルが付けられます。 このレイヤーの出力は、実質的に、元の入力画像を特徴付ける特徴のベクターです。

    TensorFlow モデルによって生成されるこの特徴ベクターは、ML.NET トレーニング アルゴリズムへの入力として使用されます。

  4. トレーニング データの文字列ラベルを整数キー値にマップする推定器を追加します。

    .Append(mlContext.Transforms.Conversion.MapValueToKey(outputColumnName: "LabelKey", inputColumnName: "Label"))
    

    次に追加される ML.NET トレーナーでは、ラベルが任意の文字列ではなく key 形式である必要があります。 キーは、文字列値への 1 対 1 のマッピングを持つ数値です。

  5. ML.NET トレーニング アルゴリズムを追加します。

    .Append(mlContext.MulticlassClassification.Trainers.LbfgsMaximumEntropy(labelColumnName: "LabelKey", featureColumnName: "softmax2_pre_activation"))
    
  6. 予測されたキー値を元の文字列にマップする推定器を追加します。

    .Append(mlContext.Transforms.Conversion.MapKeyToValue("PredictedLabelValue", "PredictedLabel"))
    .AppendCacheCheckpoint(mlContext);
    

モデルをトレーニングする

  1. LoadFromTextFile ラッパーを使用してトレーニング データを読み込みます。 GenerateModel() メソッドに次のコード行を追加します。

    IDataView trainingData = mlContext.Data.LoadFromTextFile<ImageData>(path:  _trainTagsTsv, hasHeader: false);
    

    ML.NET 内のデータは、IDataView インターフェイスとして表されます。 IDataView は、表形式のデータ (数値とテキスト) を表すための柔軟で効率的な方法です。 データはテキスト ファイルから、またはリアルタイムで (SQL データベースやログ ファイルなど) IDataView オブジェクトに読み込むことができます。

  2. 前の手順で読み込まれたデータを使用してモデルをトレーニングします。

    ITransformer model = pipeline.Fit(trainingData);
    

    Fit() メソッドで、トレーニング データセットをパイプラインに適用してモデルをトレーニングします。

モデルの精度を評価する

  1. GenerateModel メソッドの次の行に次のコードを追加して、テスト データを読み込んで変換します。

    IDataView testData = mlContext.Data.LoadFromTextFile<ImageData>(path: _testTagsTsv, hasHeader: false);
    IDataView predictions = model.Transform(testData);
    
    // Create an IEnumerable for the predictions for displaying results
    IEnumerable<ImagePrediction> imagePredictionData = mlContext.Data.CreateEnumerable<ImagePrediction>(predictions, true);
    DisplayResults(imagePredictionData);
    

    モデルの評価に使用できるサンプル画像がいくつかあります。 トレーニング データと同様に、モデルで変換できるように、これらを IDataView に読み込む必要があります。

  2. GenerateModel() メソッドに次のコードを追加して、モデルを評価します。

    MulticlassClassificationMetrics metrics =
        mlContext.MulticlassClassification.Evaluate(predictions,
            labelColumnName: "LabelKey",
            predictedLabelColumnName: "PredictedLabel");
    

    予測セットを作成したら、Evaluate() メソッドを呼び出します。

    • モデルを評価します (予測値とテスト データセット labels を比較します)。
    • モデルのパフォーマンス メトリックを返します。
  3. モデルの精度のメトリックを表示する

    次のコードを使用してメトリックを表示し、結果を共有し、それに対してアクションを実行します。

    Console.WriteLine($"LogLoss is: {metrics.LogLoss}");
    Console.WriteLine($"PerClassLogLoss is: {String.Join(" , ", metrics.PerClassLogLoss.Select(c => c.ToString()))}");
    

    画像分類では、次のメトリックが評価されます。

    • Log-loss - 「対数損失」を参照してください。 対数損失は可能な限り 1 に近づけます。
    • Per class Log-loss. クラスごとの対数損失は可能な限り 1 に近づけます。
  4. 次の行としてトレーニング済みモデルを返すように次のコードを追加します。

    return model;
    

アプリケーションを実行します。

  1. MLContext クラスを作成した後、GenerateModel の呼び出しを追加します。

    ITransformer model = GenerateModel(mlContext);
    
  2. GenerateModel() メソッドへの呼び出しの後に、ClassifySingleImage() メソッドへの呼び出しを追加します。

    ClassifySingleImage(mlContext, model);
    
  3. コンソール アプリを実行します (Ctrl + F5 キー)。 結果は以下の出力のようになるはずです。 (警告やメッセージの処理が表示される場合がありますが、わかりやすくするために、これらのメッセージは次の結果から削除されています。

    =============== Training classification model ===============
    Image: broccoli2.jpg predicted as: food with score: 0.8955513
    Image: pizza3.jpg predicted as: food with score: 0.9667718
    Image: teddy6.jpg predicted as: toy with score: 0.9797683
    =============== Classification metrics ===============
    LogLoss is: 0.0653774699265059
    PerClassLogLoss is: 0.110315812569315 , 0.0204391272836966 , 0
    =============== Making single image classification ===============
    Image: toaster3.jpg predicted as: appliance with score: 0.9646884
    

おめでとうございます! これで、画像処理用に事前トレーニング済みの TensorFlow を使用して、画像を分類するための分類モデルが ML.NET で正常に作成されました。

このチュートリアルのソース コードは dotnet/samples リポジトリで確認できます。

このチュートリアルでは、次の作業を行う方法を学びました。

  • 問題を把握する
  • 事前トレーニング済みの TensorFlow モデルを ML.NET パイプラインに組み込む
  • ML.NET モデルのトレーニングと評価
  • テスト画像を分類する

Machine Learning サンプルの GitHub リポジトリを確認し、拡張された画像分類サンプルを探索してください。