Path: blob/master/site/ja/tutorials/keras/text_classification.ipynb
25118 views
Copyright 2019 The TensorFlow Authors.
映画レビューのテキスト分類
このチュートリアルでは、ディスクに保存されているプレーンテキストファイルを使用してテキストを分類する方法について説明します。IMDB データセットでセンチメント分析を実行するように、二項分類器をトレーニングします。ノートブックの最後には、Stack Overflow のプログラミングに関する質問のタグを予測するためのマルチクラス分類器をトレーニングする演習があります。
センチメント分析
このノートブックでは、映画レビューのテキストを使用して、それが肯定的であるか否定的であるかに分類するようにセンチメント分析モデルをトレーニングします。これは二項分類の例で、機械学習問題では重要な分類法として広く適用されます。
ここでは、Internet Movie Database から抽出した 50,000 件の映画レビューを含む、大規模なレビューデータセットを使います。レビューはトレーニング用とテスト用に 25,000 件ずつに分割されています。トレーニング用とテスト用のデータは均衡しています。言い換えると、それぞれが同数の肯定的及び否定的なレビューを含んでいます。
IMDB データセットをダウンロードして調べる
データセットをダウンロードして抽出してから、ディレクトリ構造を調べてみましょう。
aclImdb/train/pos
および aclImdb/train/neg
ディレクトリには多くのテキストファイルが含まれており、それぞれが 1 つの映画レビューです。それらの 1 つを見てみましょう。
データセットを読み込む
次に、データをディスクから読み込み、トレーニングに適した形式に準備します。これを行うには、便利な text_dataset_from_directory ユーティリティを使用します。このユーティリティは、次のようなディレクトリ構造を想定しています。
二項分類用のデータセットを準備するには、ディスクに class_a
および class_b
に対応する 2 つのフォルダが必要です。これらは、aclImdb/train/pos
および aclImdb/train/neg
にある肯定的および否定的な映画レビューになります。IMDB データセットには追加のフォルダーが含まれているため、このユーティリティを使用する前にそれらを削除します。
上記のように、トレーニングフォルダには 25,000 の例があり、そのうち 80% (20,000) をトレーニングに使用します。以下に示すとおり、データセットを model.fit
に直接渡すことで、モデルをトレーニングできます。tf.data
を初めて使用する場合は、データセットを繰り返し処理して、次のようにいくつかの例を出力することもできます。
レビューには生のテキストが含まれていることに注意してください(句読点や <br/>
などのような HTML タグが付いていることもあります)。次のセクションでは、これらの処理方法を示します。
ラベルは 0 または 1 です。これらのどれが肯定的および否定的な映画レビューに対応するかを確認するには、データセットの class_names
プロパティを確認できます。
次に、検証およびテスト用データセットを作成します。トレーニング用セットの残りの 5,000 件のレビューを検証に使用します。
注意: validation_split
および subset
引数を使用する場合は、必ずランダムシードを指定するか、shuffle=False
を渡して、検証とトレーニング分割に重複がないようにします。
トレーニング用データセットを準備する
次に、便利な tf.keras.layers.TextVectorization
レイヤーを使用して、データを標準化、トークン化、およびベクトル化します。
標準化とは、テキストを前処理することを指します。通常、句読点や HTML 要素を削除して、データセットを簡素化します。トークン化とは、文字列をトークンに分割することです (たとえば、空白で分割することにより、文を個々の単語に分割します)。ベクトル化とは、トークンを数値に変換して、ニューラルネットワークに入力できるようにすることです。これらのタスクはすべて、このレイヤーで実行できます。
前述のとおり、レビューには <br />
のようなさまざまな HTML タグが含まれています。これらのタグは、TextVectorization
レイヤーのデフォルトの標準化機能によって削除されません (テキストを小文字に変換し、デフォルトで句読点を削除しますが、HTML は削除されません)。HTML を削除するカスタム標準化関数を作成します。
注意: トレーニング/テストスキュー(トレーニング/サービングスキューとも呼ばれます)を防ぐには、トレーニング時とテスト時にデータを同じように前処理することが重要です。これを容易にするためには、このチュートリアルの後半で示すように、TextVectorization
レイヤーをモデル内に直接含めます。
次に、TextVectorization
レイヤーを作成します。このレイヤーを使用して、データを標準化、トークン化、およびベクトル化します。output_mode
を int
に設定して、トークンごとに一意の整数インデックスを作成します。
デフォルトの分割関数と、上記で定義したカスタム標準化関数を使用していることに注意してください。また、明示的な最大値 sequence_length
など、モデルの定数をいくつか定義します。これにより、レイヤーはシーケンスを正確に sequence_length
値にパディングまたは切り捨てます。
次に、adapt
を呼び出して、前処理レイヤーの状態をデータセットに適合させます。これにより、モデルは文字列から整数へのインデックスを作成します。
注意: Adapt を呼び出すときは、トレーニング用データのみを使用することが重要です(テスト用セットを使用すると情報が漏洩します)。
このレイヤーを使用して一部のデータを前処理した結果を確認する関数を作成します。
上記のように、各トークンは整数に置き換えられています。レイヤーで .get_vocabulary()
を呼び出すことにより、各整数が対応するトークン(文字列)を検索できます。
モデルをトレーニングする準備がほぼ整いました。最後の前処理ステップとして、トレーニング、検証、およびデータセットのテストのために前に作成した TextVectorization レイヤーを適用します。
データセットを構成してパフォーマンスを改善する
以下は、I/O がブロックされないようにするためにデータを読み込むときに使用する必要がある 2 つの重要な方法です。
.cache()
はデータをディスクから読み込んだ後、データをメモリに保持します。これにより、モデルのトレーニング中にデータセットがボトルネックになることを回避できます。データセットが大きすぎてメモリに収まらない場合は、この方法を使用して、パフォーマンスの高いオンディスクキャッシュを作成することもできます。これは、多くの小さなファイルを読み込むより効率的です。
.prefetch()
はトレーニング中にデータの前処理とモデルの実行をオーバーラップさせます。
以上の 2 つの方法とデータをディスクにキャッシュする方法についての詳細は、データパフォーマンスガイドを参照してください。
モデルを作成する
ニューラルネットワークを作成します。
これらのレイヤーは、分類器を構成するため一列に積み重ねられます。
最初のレイヤーは
Embedding
(埋め込み)レイヤーです。このレイヤーは、整数にエンコードされた語彙を受け取り、それぞれの単語インデックスに対応する埋め込みベクトルを検索します。埋め込みベクトルは、モデルのトレーニングの中で学習されます。ベクトル化のために、出力行列には次元が1つ追加されます。その結果、次元は、(batch, sequence, embedding)
となります。埋め込みの詳細については、単語埋め込みチュートリアルを参照してください。次は、
GlobalAveragePooling1D
(1次元のグローバル平均プーリング)レイヤーです。このレイヤーは、それぞれのサンプルについて、シーケンスの次元方向に平均値をもとめ、固定長のベクトルを返します。この結果、モデルは最も単純な形で、可変長の入力を扱うことができるようになります。最後のレイヤーは、単一の出力ノードと密に接続されています。
損失関数とオプティマイザ
モデルをトレーニングするには、損失関数とオプティマイザが必要です。これは二項分類問題であり、モデルは確率(シグモイドアクティベーションを持つ単一ユニットレイヤー)を出力するため、losses.BinaryCrossentropy
損失関数を使用します。
損失関数の候補はこれだけではありません。例えば、mean_squared_error
(平均二乗誤差)を使うこともできます。しかし、一般的には、確率を扱うにはbinary_crossentropy
の方が適しています。binary_crossentropy
は、確率分布の間の「距離」を測定する尺度です。今回の場合には、真の分布と予測値の分布の間の距離ということになります。
モデルをトレーニングする
dataset
オブジェクトを fit メソッドに渡すことにより、モデルをトレーニングします。
モデルを評価する
モデルがどのように実行するか見てみましょう。2 つの値が返されます。損失(誤差、値が低いほど良)と正確度です。
この、かなり素朴なアプローチでも 86% 前後の正解度を達成しました。
経時的な正解度と損失のグラフを作成する
model.fit()
は、トレーニング中に発生したすべての情報を詰まったディクショナリを含む History
オブジェクトを返します。
トレーニングと検証中に監視されている各メトリックに対して 1 つずつ、計 4 つのエントリがあります。このエントリを使用して、トレーニングと検証の損失とトレーニングと検証の正解度を比較したグラフを作成することができます。
このグラフでは、点はトレーニングの損失と正解度を表し、実線は検証の損失と正解度を表します。
トレーニングの損失がエポックごとに下降し、トレーニングの正解度がエポックごとに上昇していることに注目してください。これは、勾配下降最適化を使用しているときに見られる現象で、イテレーションごとに希望する量を最小化します。
これは検証の損失と精度には当てはまりません。これらはトレーニング精度の前にピークに達しているようです。これが過適合の例で、モデルが、遭遇したことのないデータよりもトレーニングデータで優れたパフォーマンスを発揮する現象です。この後、モデルは過度に最適化し、テストデータに一般化しないトレーニングデータ特有の表現を学習します。
この特定のケースでは、検証の正解度が向上しなくなったときにトレーニングを停止することにより、過適合を防ぐことができます。これを行うには、tf.keras.callbacks.EarlyStopping
コールバックを使用することができます。
モデルをエクスポートする
上記のコードでは、モデルにテキストをフィードする前に、TextVectorization
レイヤーをデータセットに適用しました。モデルで生の文字列を処理できるようにする場合 (たとえば、展開を簡素化するため)、モデル内に TextVectorization
レイヤーを含めることができます。これを行うには、トレーニングしたばかりの重みを使用して新しいモデルを作成します。
新しいデータの推論
新しい例の予測を取得するには、model.predict()
を呼び出します。
モデル内にテキスト前処理ロジックを含めると、モデルを本番環境にエクスポートして展開を簡素化し、トレーニング/テストスキューの可能性を減らすことができます。
TextVectorization レイヤーを適用する場所を選択する際に性能の違いに留意する必要があります。モデルの外部で使用すると、GPU でトレーニングするときに非同期 CPU 処理とデータのバッファリングを行うことができます。したがって、GPU でモデルをトレーニングしている場合は、モデルの開発中に最高のパフォーマンスを得るためにこのオプションを使用し、デプロイの準備ができたらモデル内に TextVectorization レイヤーを含めるように切り替えることをお勧めします。
モデルの保存の詳細については、このチュートリアルにアクセスしてください。
演習:StackOverflow の質問に対するマルチクラス分類
このチュートリアルでは、IMDB データセットで二項分類器を最初からトレーニングする方法を示しました。演習として、このノートブックを変更して、Stack Overflow のプログラミング質問のタグを予測するマルチクラス分類器をトレーニングできます。
Stack Overflow に投稿された数千のプログラミングに関する質問(たとえば、「Python でディクショナリを値で並べ替える方法」)の本文を含むデータセットが用意されています。それぞれ、1 つのタグ(Python、CSharp、JavaScript、または Java のいずれか)でラベル付けされています。この演習では、質問を入力として受け取り、適切なタグ(この場合は Python)を予測します。
使用するデータセットには、1,700 万件以上の投稿を含む BigQuery の大規模な StackOverflow パブリックデータセットから抽出された数千の質問が含まれています。
データセットをダウンロードすると、以前に使用した IMDB データセットと同様のディレクトリ構造になっていることがわかります。
注意: 分類問題の難易度を上げるために、プログラミングの質問での Python、CSharp、JavaScript、または Java という単語は、blank という単語に置き換えられました(多くの質問には、対象の言語が含まれているため)。
この演習を完了するには、、このノートブックを変更してStackOverflow データセットを操作する必要があります。次の変更を行います。
ノートブックの上部で、IMDB データセットをダウンロードするコードを、事前に準備されている Stack Overflow データセットをダウンロードするコードで更新します。Stack Overflow データセットは同様のディレクトリ構造を持っているため、多くの変更を加える必要はありません。
4 つの出力クラスがあるため、モデルの最後のレイヤーを
Dense(4)
に変更します。モデルをコンパイルするときは、損失を
tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
に変更します。これは、各クラスのラベルが整数である場合に、マルチクラス分類問題に使用する正しい損失関数です。(この場合、 0、1、2、または 3 のいずれかになります)。さらに、これはマルチクラス分類の問題であるため、メトリックをmetrics=['accuracy']
に変更します (tf.metrics.BinaryAccuracy
はバイナリ分類器にのみ使用されます)。経時的な精度をプロットする場合は、
binary_accuracy
およびval_binary_accuracy
をそれぞれaccuracy
およびval_accuracy
に変更します。これらの変更が完了すると、マルチクラス分類器をトレーニングできるようになります。
詳細
このチュートリアルでは、最初からテキスト分類を実行する方法を紹介しました。一般的なテキスト分類ワークフローの詳細については、Google Developers のテキスト分類ガイドをご覧ください。