次の方法で共有


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

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

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

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

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

このチュートリアルのソース コードは、dotnet/samples リポジトリにあります。

前提 条件

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

セットアップ

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

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

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

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

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

    手記

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

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

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

手記

このチュートリアルのモデルは、gitHub リポジトリ dotnet/machinelearning-testdata から取得したものです。 モデルは 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. ソリューション エクスプローラーで、 ディレクトリとサブディレクトリ内の各ファイルを右クリックし、[プロパティ]選択します。 [上級]で、[出力ディレクトリへのコピー] の値を [コピー(新しい場合のみ)]に変更します。

using ディレクティブとグローバル変数を追加する

  1. Program.cs ファイルの先頭に、次の追加の using ディレクティブを追加します。

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

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

データをモデル化する

映画のレビューは自由形式のテキストです。 アプリケーションは、複数の不連続ステージでモデルで想定される入力形式にテキストを変換します。

1 つ目は、テキストを個別の単語に分割し、指定されたマッピング ファイルを使用して各単語を整数エンコードにマップすることです。 この変換の結果は、文内の単語数に対応する長さを持つ可変長整数配列です。

財産 価値 種類
レビュー内容 この映画は本当に良いです
VariableLengthFeatures 14,22,9,66,78,... int[]

その後、可変長機能配列のサイズが固定長の 600 に変更されます。 これは、TensorFlow モデルが期待する長さです。

財産 価値 種類
ReviewText この映画は本当に良いです
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 メソッドを使用してファイルからマッピング データを読み込み、単語を整数としてエンコードするディクショナリを作成します。

    Word インデックス
    キッズ 362
    want 181
    間違っている 355
    effects 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. 次のコードを追加して、PredictSentiment() メソッドの最初の行として PredictionEngine を作成します。

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

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

    手記

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

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

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

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

    財産 価値 種類
    予測 [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 サイトのコメント テキストをモデルに適した機能に変換する
  • モデルを使用して予測を行う