Path: blob/master/site/ja/guide/keras/train_and_evaluate.ipynb
25118 views
Copyright 2020 The TensorFlow Authors.
組み込みメソッドを使用したトレーニングと評価
セットアップ
はじめに
このガイドでは、トレーニングと検証に組み込みAPI(model.fit()
、model.evaluate()
、model.predict()
など)を使用する場合のトレーニング、評価、予測(推論)モデルについて説明します。
独自のトレーニングステップ関数を指定しながら fit()
を利用する場合は、「fit()
の処理をカスタマイズする」ガイドをご覧ください。
独自のトレーニングと評価ループを新規に作成する場合は、「トレーニングループの新規作成」をご覧ください。
一般的にモデルのトレーニングと評価は、組み込みループを使用するか独自のループを作成するかに関係なく、すべての Keras モデル(Sequential モデル、Functional API を使用して構築されたモデル、モデルのサブクラス化により新規作成されたモデル)で同じように機能します。
このガイドは、分散型トレーニングについては説明されていません。この説明はマルチ GPU と分散型トレーニングに関するガイドをご覧ください。
API の概要:最初のエンドツーエンドの例
モデルの組み込みトレーニングループにデータを渡すときは、NumPy 配列(データが小さく、メモリに収まる場合)または tf.data Dataset
オブジェクトを使用する必要があります。 以下の例では、オプティマイザ、損失、およびメトリクスの使用方法を示すために、MNIST データセットを NumPy 配列として使用します。
次のモデルを見てみましょう(ここでは、Functional API を使用して構築していますが、Sequential モデルまたはサブクラス化モデルも使用可能です)。
一般的なエンドツーエンドのワークフローは以下のとおりです。
トレーニング
元のトレーニングデータから生成されたホールドアウトセットの検証
テストデータの評価
この例では MNIST データを使用します。
トレーニングの構成(オプティマイザ、損失、メトリクス)を指定します。
fit()
を呼び出します。これは、データを batch_size
サイズの「バッチ」にスライスし、指定された数の epochs
間にデータセット全体を繰り返しイテレートすることでモデルをトレーニングします。
返された history
オブジェクトは、トレーニング間の損失値とメトリクス値の記録を保持します。
evaluate()
を介してテストデータでモデルを評価します。
では、このワークフローの各部分を詳しく見ていきましょう。
compile()
メソッド: 損失、メトリクス、およびオプティマイザを指定する
fit()
を使用してモデルをトレーニングするには、損失関数、オプティマイザ、および必要に応じて監視するメトリクスを指定する必要があります。
これらを compile()
メソッドの引数としてモデルに渡します。
metrics
引数はリストである必要があります。モデルは任意の数のメトリクスを持つことができます。
モデルに複数の出力がある場合、出力ごとに異なる損失とメトリクスを指定でき、モデルの総損失に対する各出力の貢献を修正できます。詳細については、「 データを多入力多出力モデルに渡す」セクションをご覧ください。
デフォルト設定に満足している場合、多くの場合、オプティマイザ、損失、およびメトリクスは、ショートカットとして文字列識別子を介して指定できます。
後で再利用できるよう、モデルの定義とコンパイルの手順を関数に入れましょう。このガイドでは、さまざまな例でこの関数を何度か呼び出しています。
提供されている多数の組み込みオプティマイザ、損失、およびメトリクス
一般的に、Keras API には必要とされているものが含まれているため、一般的に、独自の損失、メトリクス、またはオプティマイザを新規作成する必要はありません。
オプティマイザ:
SGD()
(モメンタムの有無に関係なく)RMSprop()
Adam()
など
損失:
MeanSquaredError()
KLDivergence()
CosineSimilarity()
など
メトリクス:
AUC()
Precision()
Recall()
など
カスタム損失
カスタム損失を作成する必要がある場合、Keras には作成する方法が 2 つあります。
最初の方法は、入力 y_true
と y_pred
を受け入れる関数を作成する方法です。次の例は、実データと予測の間の平均二乗誤差を計算する損失関数を示しています。
y_true
およびy_pred
以外のパラメータを取る損失関数が必要な場合は、tf.keras.losses.Loss
クラスをサブクラス化して、次の 2 つのメソッドを実装できます。
__init__(self)
: 損失関数の呼び出し中に渡すパラメータを受け入れるcall(self, y_true, y_pred)
: ターゲット(y_true)とモデル予測(y_pred)を使用してモデルの損失を計算する
平均二乗誤差を使用する際に、0.5 より離れた予測値にペナルティを与えるとします(カテゴリターゲットはワンホットエンコードされ、0 と 1 の間の値を取ると想定します)。これにより、モデルの信頼性が調整され、過剰適合を防ぐのに役立ちます(ただし、実際に試してみるまで、その効果はわかりません!)。
以下のように記述します。
カスタムメトリック
API に含まれていないメトリックが必要な場合は、tf.keras.metrics.Metric
クラスをサブクラス化することにより、カスタムメトリックを簡単に作成できます。
__init__(self)
- メトリックの状態変数を作成します。update_state(self, y_true, y_pred, sample_weight=None)
- ターゲット (y_true) とモデル予測 (y_pred) を使用し状態変数を更新します。result(self)
- 状態変数を使用して最終結果を計算します。reset_state(self)
- メトリックの状態を再初期化します。
多くの場合、結果の計算に非常に負荷がかかり、定期的にしか実行されないため、状態の更新(update_state()
)と結果の計算(result()
)は別々に保持されます。
以下は、CategoricalTruePositives
メトリックを実装する方法を示す簡単な例です。これは、特定のクラスに属するものとして正しく分類されたサンプル数を数えます。
標準のシグネチャに適合しない損失と測定基準の処理
大多数の損失とメトリクスは、y_true
およびy_pred
から計算できます。この場合、y_pred
はモデルの出力です。例外として、正則化損失ではレイヤーのアクティブ化のみが必要で(この場合はターゲットはありません)、このアクティブ化はモデルの出力ではない場合があります。
このような場合は、カスタムレイヤーの呼び出しメソッド内から self.add_loss(loss_value)
を呼び出すことができます。この方法で追加された損失は、トレーニング時に「メイン」の損失(compile()
に渡されたもの)に追加されます。以下は、アクティビティの正規化を追加する簡単な例です(アクティビティの正規化はすべての Keras レイヤーに組み込まれています。このレイヤーは具体的な例を示すためのものです)。
add_metric()
を使用して、メトリクス値のロギングに対して同じく実行できます。
Functional API では、model.add_loss(loss_tensor)
または model.add_metric(metric_tensor, name, aggregation)
を呼び出せます。
簡単な例を下記に示します。
add_loss()
を介して損失を渡すと、モデルにはすでに最小化する損失があるため、損失関数なしで compile()
を呼び出すことが可能になります。
次の LogisticEndpoint
レイヤーでは、入力としてターゲットとロジットを取り、add_loss()
を介してクロスエントロピー損失を追跡します。また、add_metric()
を介して分類の精度を追跡します。
次のように、loss
引数なしでコンパイルされた 2 つの入力(入力データとターゲット)を持つモデルで使用できます。
多入力モデルのトレーニングの詳細については、「多入力多出力モデルにデータを渡す」をご覧ください。
自動的にホールドアウトセットを別にする
最初に紹介したエンドツーエンドの例では、各エポックの終わりに検証損失と検証メトリクスを評価するために、NumPy 配列のタプル (x_val, y_val)
をモデルに渡すために validation_data
引数を使用しました。
もう一つのオプションとして、validation_split
引数を使うと、検証用に自動的にトレーニングデータの一部を予約しておくことができます。 引数値は検証用に予約されるデータの割合を表すため、0 より高く 1 より低い数字に設定する必要があります。たとえば、validation_split=0.2
は「検証用にデータの 20% を使用する」ことを意味し、validation_split=0.6
は「検証用にデータの 60% を使用する」ことを意味します。
シャッフルの前に、fit()
の呼び出しが受け取った配列の最後の x% サンプルを取って検証が計算されます。
NumPy データでトレーニングする場合は、validation_split
のみを使用できることに注意してください。
tf.data データセットからのトレーニングと評価
前の段落では、損失、メトリクスおよびオプティマイザをどのように扱うかを見ました。そしてデータが Numpy 配列として渡されるとき、fit()
で validation_data
と validation_split
引数をどのように使用するかを見ました。
次に、データが tf.data.Dataset
オブジェクトの形式で渡される場合を見てみましょう。
tf.data
API は高速でスケーラブルな方法でデータを読み込んで前処理するための TensorFlow 2.0 の一連のユティリティです。
Datasets
の作成についての詳細は、tf.data ドキュメントをご覧ください。
Dataset
のインスタンスは、fit()
、evaluate()
、predict()
メソッドに直接的に渡すことができます。
データセットは各エポックの最後にリセットされるため、次のエポックで再利用できます。
このデータセットから特定の数のバッチでのみトレーニングを実行する場合は、steps_per_epoch
引数を渡します。これは、次のエポックに進む前に、このデータセットを使用してモデルが実行するトレーニングステップの数を指定します。
この場合、データセットは各エポックの終わりにリセットされず、次のバッチを取得し続けます。最終的にデータセットのデータは使い果たされます(無限ループのデータセットでない限り)。
検証データセットを使用する
Dataset
インスタンスを fit()
の validation_data
引数として渡すことができます。
各エポックの終わりに、モデルは検証データセットを反復処理し、検証損失と検証メトリクスを計算します。
このデータセットから特定の数のバッチでのみ検証を実行する場合は、validation_steps
引数を渡すことができます。これは、検証を中断して次のエポックに進む前に、モデルが検証データセットで実行する必要がある検証ステップの数を指定します。
検証データセットは使用するたびにリセットされることに注意してください(エポックごとに常に同じサンプルが評価されます)。
validation_split
引数(トレーニングデータからホールドアウトセットを生成)は、Dataset
オブジェクトからトレーニングする場合はサポートされません。この機能には、データセットのサンプルにインデックスを付ける機能が必要ですが、一般的に Dataset
API では不可能です。
サポートされるほかの入力形式
NumPy 配列、eager tensors、TensorFlow Datasets
のほか、Pandas データフレームやデータとラベルのバッチを生成する Python ジェネレータを使用して Keras モデルをトレーニングできます。
特に、keras.utils.Sequence
クラスは、Python データジェネレータを構築するためのシンプルなインターフェースを提供します。 これらはマルチプロセッシングに対応し、シャッフルすることができます。
一般的に、以下を使用することをお勧めします。
NumPy 入力データ - データが小さく、メモリに収まる場合
Dataset
オブジェクト - 大規模なデータセットがあり、分散トレーニングを行う必要がある場合Sequence
オブジェクト - 大規模なデータセットがあり、TensorFlow では実行できない多くのカスタム Python 側の処理を行う必要がある場合(たとえば、データの読み込みや前処理が外部ライブラリに依存している場合)。
keras.utils.Sequence
オブジェクトを入力として使用する
keras.utils.Sequence
は、以下の 2 つの重要な特性を持つ Python ジェネレータを取得するためにサブクラス化できるユーティリティです。
マルチプロセッシングでうまく機能する
シャッフル可能(
shuffle=True
をfit()
に渡す場合など)
Sequence
は以下の 2 つのメソッドを実装する必要があります。
__getitem__
__len__
__getitem__
メソッドは完全なバッチを返します。エポック間でデータセットを変更する場合は、on_epoch_end
を実装できます。
簡単な例を次に示します。
サンプルの重み付けとクラスの重み付けを使用する
デフォルト設定ではサンプルの重みはデータセット内の頻度によって決定されますが、サンプルの頻度に関係なくデータに重みを付けるには、以下の 2 つの方法があります。
クラスの重み
サンプルの重み
クラスの重み
クラスに対する重みは、ディクショナリを class_weight
引数に渡し、Model.fit()
に渡すことで設定されます。このディクショナリは、クラスインデックスを、このクラスに属するサンプルに使用する重みにマッピングします。
これは、リサンプリングせずにクラスのバランスを取るために使用できます。または、特定のクラスをより重要視するモデルをトレーニングするために使用できます。
たとえば、クラス「0」がデータでクラス「1」として表されるものの半分である場合、Model.fit(..., class_weight={0: 1., 1: 0.5})
とすることができます。
以下は NumPy の例です。クラス#5(MNIST データセットの数字「5」)の正しい分類をより重要視するために、クラスの重みまたはサンプルの重みを使用しています。
サンプルの重み
細かく制御する場合、または分類子を構築しない場合は、「サンプルの重み」を使用できます。
NumPy データからトレーニングする場合:
sample_weight
引数をModel.fit()
に渡します。tf.data
またはその他のイテレータからトレーニングする場合:(input_batch, label_batch, sample_weight_batch)
タプルを介します。
「サンプルの重み」配列は、バッチ内の各サンプルが総損失を計算する際に必要な重みを指定する数値の配列です。 これは、不均衡な分類の問題(頻繁に使用されないクラスにより大きな重みを与えるため)でよく使用されます。
使用される重みが 1 と 0 の場合、配列は損失関数のマスクとして使用できます(損失全体に対する特定のサンプルの貢献を完全に破棄します)。
以下は、一致する Dataset
の例です。
多入力多出力モデルにデータを渡す
前の例では、1つの入力(テンソルの形状 (764,)
)と1つの出力(形状の予測テンソル (10,)
)を持つモデルを見ました。では、複数の入力や出力を持つモデルではどうでしょう。
次のモデルを考えてみましょう。形状 (32, 32, 3)
の画像入力(<code data-md-type="codespan">(height, width, channels)
)、形状 (None, 10)
の時系列入力((timesteps, features)
)があります。モデルは、これらの入力の組み合わせから 2 つの出力(「スコア」(形状(1,)
)および 5 つのクラスにわたる確率分布(形状(5,)
)を計算します。
ここで何が行われているか明確に分かるようにこのモデルをプロットしてみましょう(プロットに表示される形状は、サンプルごとの形状ではなく、バッチの形状であることに注意してください)。
コンパイル時に損失関数をリストとして渡すことにより出力ごとに異なる損失を指定できます。
モデルに単一の損失関数のみを渡した場合、同じ損失関数がすべての出力に適用されます(ここでは適切ではありません)。
メトリクスの場合も同様です。
出力レイヤーに名前を付けたので、dict を介して出力ごとの損失とメトリクスを指定することもできます。
3 つ以上の出力がある場合は、明示的な名前とディクショナリを使用することをお勧めします。
loss_weights
引数を使用すると、異なる出力固有の損失に異なる重みを与えることができます(この例でクラス損失の 2 倍の重要性を与えることにより、「スコア」損失を優先する場合など)。
これらの出力が予測に使用するもので、トレーニングには使用されない場合、特定の出力の損失を計算しないことを選択することもできます。
fit()
で多入力または多出力モデルにデータを渡すと、コンパイルで損失関数を指定するのと同じように機能します。NumPy 配列のリスト(損失関数を受け取った出力に 1:1 でマッピング)または出力の名前を NumPy 配列にマッピングする dict を渡すことができます。
以下は Dataset
のユースケースです。NumPy 配列と同様に、Dataset
は dicts のタプルを返します。
コールバックを使用する
Keras のコールバックは、トレーニング中の異なる時点(エポックの始め、バッチの終わり、エポックの終わりなど)で呼び出されるオブジェクトで、以下のような動作を実装するために使用できます。
トレーニング中に(組み込みのエポックごとの検証だけでなく)さまざまな時点で検証を行う
定期的に、または特定の精度しきい値を超えたときにモデルにチェックポイントを設定する
学習が停滞したときにモデルの学習率を変更する
学習が停滞したときにトップレイヤーをファインチューニングする
トレーニング終了時、または特定のパフォーマンスしきい値を超えたときにメールまたはインスタントメッセージ通知を送信する
など
コールバックは、リストとして fit()
の呼び出しに渡すことができます。
利用できる多数の組み込みコールバック
Keras には、次のような組み込みコールバックが多数用意されています。
ModelCheckpoint
: モデルを定期的に保存するEarlyStopping
: トレーニングによって検証指標が改善されなくなったら、トレーニングを停止するTensorBoard
: TensorBoard で視覚化できるモデルログを定期的に記述する(詳細については、「視覚化」セクションを参照)。CSVLogger
: 損失およびメトリクスデータを CSV ファイルにストリーミングするなど
完全なリストについてはコールバックのドキュメントをご覧ください。
コールバックを記述する
ベースクラス keras.callbacks.Callback
を拡張することにより、カスタムコールバックを作成できます。コールバックは、クラスプロパティ self.model
を通じて関連するモデルにアクセスできます。
詳細については、カスタムコールバックの作成に関する完全ガイドを参照してください。
以下は、トレーニング時にバッチごとの損失値のリストを保存する簡単な例です。
モデルにチェックポイントを設定する
比較的大きなデータセットでモデルをトレーニングする場合、モデルのチェックポイントを頻繁に保存することが重要です。
これを達成するには ModelCheckpoint
コールバックを使用するのが最も簡単です。
ModelCheckpoint
コールバックを使用するとフォールトトレランスを実装できます。フォールトトレランスはトレーニングがランダムに中断された場合に、モデルの最後に保存された状態からトレーニングを再開する機能です。 以下は基本的な例です。
また、モデルを保存および復元するための独自のコールバックを記述することもできます。
シリアル化と保存の完全なガイドについては、モデルの保存とシリアル化に関するガイドをご覧ください。
学習率スケジュールを使用する
ディープラーニングモデルをトレーニングする際は、一般的に、トレーニングが進むにつれて徐々に学習進度が減少するパターンが見られます。これは一般に「学習率の減衰」として知られています。
学習減衰スケジュールは、静的(その時点のエポックまたはその時点のバッチインデックスの関数として事前に指定)または動的(モデルの現在の動作、特に検証損失に対応)にすることができます。
オプティマイザにスケジュールを渡す
オプティマイザの learning_rate
引数としてスケジュールオブジェクトを渡すことで、静的学習率の減衰スケジュールを簡単に使用できます。
組み込みスケジュールには、ExponentialDecay
、PiecewiseConstantDecay
、PolynomialDecay
、および InverseTimeDecay
を利用できます。
コールバックを使用して動的学習率スケジュールを実装する
オプティマイザは検証メトリクスにアクセスできないため、これらのスケジュールオブジェクトでは動的学習率のスケジュール(検証の損失が改善されなくなったときに学習率を下げるなど)を実現できません。
ただし、コールバックは、検証メトリクスを含むすべてのメトリクスにアクセスできます。このパターンでは、コールバックを使用してオプティマイザのその時点の学習率を変更します。これはReduceLROnPlateau
コールバックとして組み込まれています。
トレーニング時の損失とメトリクスを視覚化する
トレーニング時にモデルを監視する場合、TensorBoard を使用するのが最善の方法です。これは、ローカルで実行できるブラウザベースのアプリケーションで、以下の機能を提供します。
トレーニングと評価のための損失とメトリクスのライブプロット
レイヤーアクティベーションのヒストグラムの視覚化(オプション)
Embedding
レイヤーが学習した埋め込みスペースの 3D 視覚化(オプション)
TensorFlow を pip でインストールした場合は、コマンドラインから TensorBoard を起動できます。
TensorBoard コールバックを使用する
Keras モデルと fit()
メソッドで TensorBoard を使用するには、TensorBoard
コールバックを使用するのが最も簡単です。
最も単純なケースでは、コールバックがログを書き込む場所を指定するだけで完了します。
詳細については、TensorBoard
コールバックのドキュメントを参照してください。