次の方法で共有


チュートリアル: ML.NET で事前トレーニング済みの TensorFlow モデルを使用して映画レビューのセンチメントを分析する

このチュートリアルでは、事前トレーニング済みの TensorFlow モデルを使用して、Web サイトのセンチメントを分類する方法について示します。 センチメントの 2 項分類子は、Visual Studio を使用して開発された C# コンソール アプリケーションです。

このチュートリアルで使用される TensorFlow モデルは、IMDB データベースの映画レビューを使用してトレーニングされました。 アプリケーションの開発が完了すると、映画レビューのテキストを入力できるようになり、レビューに肯定的または否定的なセンチメントが含まれるかどうかがアプリケーションによって通知されます。

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

  • 事前トレーニング済みの TensorFlow モデルを読み込む
  • Web サイトのコメント テキストをモデルに適したフィーチャーに変換する
  • モデルを使用して予測する

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

必須コンポーネント

  • .NET デスクトップ開発ワークロードがインストールされた Visual Studio 2022

セットアップ

アプリケーションを作成する

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

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

  3. データ セット ファイルを保存するために、プロジェクトに Data という名前のディレクトリを作成します。

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

    注意

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

    ソリューション エクスプローラーで、プロジェクトを右クリックし、 [NuGet パッケージの管理] を選択します。 パッケージ ソースとして "nuget.org" を選択してから、 [参照] タブを選択します。Microsoft.ML を検索し、目的のパッケージを選択して、 [インストール] ボタンを選択します。 選択したパッケージのライセンス条項に同意してインストールを続行します。 Microsoft.ML.TensorFlowMicrosoft.ML.SampleUtils、および SciSharp.TensorFlow.Redist に対して、これらの手順を繰り返します。

TensorFlow モデルをプロジェクトに追加する

Note

このチュートリアルのモデルは、dotnet/machinelearning-testdata GitHub リポジトリにあります。 このモデルは TensorFlow SavedModel 形式です。

  1. sentiment_model ZIP ファイルをダウンロードして解凍します。

    ZIP ファイルには次のものが含まれています。

    • saved_model.pb: TensorFlow モデルそのもの。 このモデルは、IMDB レビューの文字列内のテキストを表すフィーチャーの固定長 (サイズ 600) の整数配列を受け取り、合計が 1 になる 2 つの確率を出力します。これは、入力レビューに肯定的センチメントが含まれる確率と、入力レビューに否定的センチメントが含まれる確率です。
    • imdb_word_index.csv: 個々の単語から整数値へのマッピング。 マッピングは、TensorFlow モデル用に入力機能を作成するために使用されます。
  2. 最深部の sentiment_model ディレクトリの内容を TextClassificationTF プロジェクトの sentiment_model ディレクトリにコピーします。 次の画像に示すように、このディレクトリには、このチュートリアルに必要なモデルと追加のサポート ファイルが含まれています。

    sentiment_model ディレクトリ コンテンツ

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

using ステートメントとグローバル変数を追加する

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

    using Microsoft.ML;
    using Microsoft.ML.Data;
    using Microsoft.ML.Transforms;
    
  2. 保存されたモデルのファイル パスを保持するために、using ステートメントの直後にグローバル変数を作成します。

    string _modelPath = Path.Combine(Environment.CurrentDirectory, "sentiment_model");
    
    • _modelPath は、トレーニング済みモデルのファイル パスです。

データのモデル化

映画レビューは自由形式のテキストです。 アプリケーションでは、テキストがさまざまな個別のステージでモデルによって想定される入力形式に変換されます。

最初にテキストを別々の単語に分割し、指定されたマッピング ファイルを使用して各単語を整数のエンコードにマップします。 この変換の結果、文章内の単語数に応じた長さの可変長の整数配列になります。

プロパティ [値] 種類
ReviewText この映画は本当に良い string
VariableLengthFeatures 14、22、9、66、78、... int[]

可変長フィーチャーの配列は、固定長が 600 に変更されます。 これは、TensorFlow モデルで想定される長さです。

プロパティ [値] 種類
ReviewText この映画は本当に良い string
VariableLengthFeatures 14、22、9、66、78、... int[]
フィーチャー 14、22、9、66、78、... int[600]
  1. Program.cs ファイルの下部に入力データのクラスを作成します。

    /// <summary>
    /// Class to hold original sentiment data.
    /// </summary>
    public class MovieReview
    {
        public string? ReviewText { get; set; }
    }
    

    入力データ クラス (MovieReview) には、ユーザー コメント (ReviewText) 用の string があります。

  2. 次の MovieReview クラスの後に、可変長フィーチャー用のクラスを作成します。

    /// <summary>
    /// Class to hold the variable length feature vector. Used to define the
    /// column names used as input to the custom mapping action.
    /// </summary>
    public class VariableLength
    {
        /// <summary>
        /// This is a variable length vector designated by VectorType attribute.
        /// Variable length vectors are produced by applying operations such as 'TokenizeWords' on strings
        /// resulting in vectors of tokens of variable lengths.
        /// </summary>
        [VectorType]
        public int[]? VariableLengthFeatures { get; set; }
    }
    

    VariableLengthFeatures プロパティには、ベクターとして指定する VectorType 属性が含まれます。 ベクター要素はすべて同じ型である必要があります。 列が多いデータ セットでは、複数の列を 1 つのベクターとして読み込むことで、データ変換を適用するときのデータ パスの数が減少します。

    このクラスは、ResizeFeatures アクションで使用されます。 プロパティの名前 (この場合は 1 つのみ) を使用して、カスタム マッピング アクションへの入力として使用できる DataView 内の列を示します。

  3. 次の VariableLength クラスの後に、固定長フィーチャー用のクラスを作成します。

    /// <summary>
    /// Class to hold the fixed length feature vector. Used to define the
    /// column names used as output from the custom mapping action,
    /// </summary>
    public class FixedLength
    {
        /// <summary>
        /// This is a fixed length vector designated by VectorType attribute.
        /// </summary>
        [VectorType(Config.FeatureLength)]
        public int[]? Features { get; set; }
    }
    

    このクラスは、ResizeFeatures アクションで使用されます。 プロパティの名前 (この場合は 1 つのみ) を使用して、カスタム マッピング アクションへの出力として使用できる DataView 内の列を示します。

    プロパティ Features の名前は、TensorFlow モデルによって決定されることに注意してください。 このプロパティ名は変更できません。

  4. 次の FixedLength クラスの後に、予測用のクラスを作成します。

    /// <summary>
    /// Class to contain the output values from the transformation.
    /// </summary>
    public class MovieReviewSentimentPrediction
    {
        [VectorType(2)]
        public float[]? Prediction { get; set; }
    }
    

    MovieReviewSentimentPrediction はモデルのトレーニング後に使用される予測クラスです。 MovieReviewSentimentPrediction には、1 つの float 配列 (Prediction) と VectorType 属性が含まれます。

  5. 特徴ベクトルの長さなどの構成値を保持する別のクラスを作成します。

    static class Config
    {
        public const int FeatureLength = 600;
    }
    

MLContext、検索ディクショナリ、フィーチャーのサイズを変更するアクションを作成する

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

  1. Console.WriteLine("Hello World!") の行を、mlContext 変数を宣言して初期化する次のコードに置き換えます。

    MLContext mlContext = new MLContext();
    
  2. 次の表に示すように、LoadFromTextFile メソッドを使用して単語を整数としてエンコードするディクショナリを作成し、ファイルからマッピング データを読み込みます。

    単語 インデックス
    子供向け 362
    必要 181
    不適切 355
    効果 302
    感覚 547

    次のコードを追加して、検索マップを作成します。

    var lookupMap = mlContext.Data.LoadFromTextFile(Path.Combine(_modelPath, "imdb_word_index.csv"),
        columns: new[]
            {
                new TextLoader.Column("Words", DataKind.String, 0),
                new TextLoader.Column("Ids", DataKind.Int32, 1),
            },
        separatorChar: ','
        );
    
  3. Action を追加して、可変長単語の整数配列のサイズを固定サイズの整数配列に変更します。次のコード行を使用します。

    Action<VariableLength, FixedLength> ResizeFeaturesAction = (s, f) =>
    {
        var features = s.VariableLengthFeatures;
        Array.Resize(ref features, Config.FeatureLength);
        f.Features = features;
    };
    

事前トレーニング済みの TensorFlow モデルを読み込む

  1. TensorFlow モデルを読み込むためのコードを追加します。

    TensorFlowModel tensorFlowModel = mlContext.Model.LoadTensorFlowModel(_modelPath);
    

    モデルが読み込まれたら、その入力および出力スキーマを抽出できます。 スキーマは、参考および学習の目的のためにのみ表示されます。 最終的なアプリケーションを機能させるためには、このコードは必要ありません。

    DataViewSchema schema = tensorFlowModel.GetModelSchema();
    Console.WriteLine(" =============== TensorFlow Model Schema =============== ");
    var featuresType = (VectorDataViewType)schema["Features"].Type;
    Console.WriteLine($"Name: Features, Type: {featuresType.ItemType.RawType}, Size: ({featuresType.Dimensions[0]})");
    var predictionType = (VectorDataViewType)schema["Prediction/Softmax"].Type;
    Console.WriteLine($"Name: Prediction/Softmax, Type: {predictionType.ItemType.RawType}, Size: ({predictionType.Dimensions[0]})");
    
    

    入力スキーマは、整数でエンコードされた単語の固定長配列です。 出力スキーマは、レビューのセンチメントが否定的であるか、肯定的であるかを示す、確率の float 型配列です。 肯定的な確率は否定的なセンチメントの確率の補数であるため、これらの値の合計は 1 になります。

ML.NET パイプラインを作成する

  1. パイプラインを作成し、TokenizeIntoWords 変換を使用して入力テキストを単語に分割し、次のコード行としてテキストを単語に分割します。

    IEstimator<ITransformer> pipeline =
        // Split the text into individual words
        mlContext.Transforms.Text.TokenizeIntoWords("TokenizedWords", "ReviewText")
    

    TokenizeIntoWords 変換では、スペースを使用してテキストまたは文字列を単語に解析します。 これにより、新しい列が作成され、ユーザー定義の区切り記号に基づいて各入力文字列を部分文字列のベクターに分割します。

  2. 上記で宣言した参照テーブルを使用して、単語を整数エンコードにマップします。

    // Map each word to an integer value. The array of integer makes up the input features.
    .Append(mlContext.Transforms.Conversion.MapValue("VariableLengthFeatures", lookupMap,
        lookupMap.Schema["Words"], lookupMap.Schema["Ids"], "TokenizedWords"))
    
  3. 可変長の整数エンコーディングのサイズを、モデルで必要とされる固定長に変更します。

    // Resize variable length vector to fixed length vector.
    .Append(mlContext.Transforms.CustomMapping(ResizeFeaturesAction, "Resize"))
    
  4. 読み込まれた TensorFlow モデルで入力を分類します。

    // Passes the data to TensorFlow for scoring
    .Append(tensorFlowModel.ScoreTensorFlowModel("Prediction/Softmax", "Features"))
    

    TensorFlow モデルの出力は Prediction/Softmax と呼ばれます。 この名前 Prediction/Softmax は、TensorFlow モデルによって決定されることに注意してください。 この名前は変更できません。

  5. 出力予測用に新しい列を作成します。

    // Retrieves the 'Prediction' from TensorFlow and copies to a column
    .Append(mlContext.Transforms.CopyColumns("Prediction", "Prediction/Softmax"));
    

    Prediction/Softmax 列を C# クラス Prediction のプロパティとして使用できる名前を持つ列にコピーする必要があります。 / 文字は、C# プロパティ名では使用できません。

パイプラインから ML.NET モデルを作成する

  1. パイプラインからモデルを作成するためのコードを追加します。

    // Create an executable model from the estimator pipeline
    IDataView dataView = mlContext.Data.LoadFromEnumerable(new List<MovieReview>());
    ITransformer model = pipeline.Fit(dataView);
    

    ML.NET モデルは、Fit メソッドを呼び出すことによって、パイプラインのエスティメーターのチェーンから作成されます。 この場合、TensorFlow モデルは既に以前トレーニングされているため、モデルを作成するためのデータを調整することはありません。 Fit メソッドの要件を満たすために、空のデータ ビュー オブジェクトを提供します。

モデルを使用して予測する

  1. MovieReview クラスの上に PredictSentiment メソッドを追加します。

    void PredictSentiment(MLContext mlContext, ITransformer model)
    {
    
    }
    
  2. 次のコードを追加して、PredictionEnginePredictSentiment() メソッドの 1 行目として作成します。

    var engine = mlContext.Model.CreatePredictionEngine<MovieReview, MovieReviewSentimentPrediction>(model);
    

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

    注意

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

  3. コメントを追加して、Predict() メソッドでトレーニングされたモデルの予測をテストします。これには MovieReview のインスタンスを作成します。

    var review = new MovieReview()
    {
        ReviewText = "this film is really good"
    };
    
  4. PredictSentiment() メソッドに次のコード行を追加することで、テスト コメント データを Prediction Engine に渡します。

    var sentimentPrediction = engine.Predict(review);
    
  5. Predict() 関数では、データの単一行に対して予測を行います。

    プロパティ [値] 種類
    予測 [0.5459937, 0.454006255] float[]
  6. 次のコードを使用して、センチメント予測を表示します。

    Console.WriteLine($"Number of classes: {sentimentPrediction.Prediction?.Length}");
    Console.WriteLine($"Is sentiment/review positive? {(sentimentPrediction.Prediction?[1] > 0.5 ? "Yes." : "No.")}");
    
  7. Fit() メソッドを呼び出した後、PredictSentiment への呼び出しを追加します。

    PredictSentiment(mlContext, model);
    

結果

アプリケーションをビルドして実行します。

結果は以下のようになるはずです。 処理中にメッセージが表示されます。 警告または処理メッセージが表示されることがありますが、 わかりやすくするために、これらのメッセージは次の結果から削除してあります。

Number of classes: 2
Is sentiment/review positive ? Yes

おめでとうございます! これで、ML.NET で事前トレーニング済みの TensorFlow モデルを再利用することにより、メッセージのセンチメントを分類および予測するための機械学習モデルをビルドできました。

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

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

  • 事前トレーニング済みの TensorFlow モデルを読み込む
  • Web サイトのコメント テキストをモデルに適したフィーチャーに変換する
  • モデルを使用して予測する