TensorFlow : Tutorials : Keras : overfitting と underfitting を調査する (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 08/27/2018
* TensorFlow 1.10 で更に改訂されています。
* TensorFlow 1.9 でドキュメント構成が変更され、数篇が新規に追加されましたので再翻訳しました。
* 本ページは、TensorFlow の本家サイトの Tutorials – Learn and use ML – Explore overfitting and underfitting を翻訳した上で適宜、補足説明したものです:
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
いつものように、このサンプルのコードは tf.keras API を使用します。
前の例の両者 — 映画レビューの分類、そして住居価格の予測 — では、検証データ上のモデルの精度が幾つかのエポックの訓練後にピークになり、それから減少を開始することを見ました。
換言すれば、モデルは訓練データに overfit しています。overfitting にどのように対処するかを学ぶことは重要です。訓練セット上で高い精度を獲得することはしばしば可能ですが、本当に望むことはテストデータ (あるいは前にまだ見ていないデータ) に上手く一般化されたモデルを開発することです。
overfitting の反対は underfitting です。underfitting は テストデータ上でまだ改善の余地があるときに発生します。これは多くの理由で起こります : モデルが十分にパワフルでない場合、過剰に正則化されている、あるいは単に十分に長く訓練されていない場合。これはネットワークが訓練データ内の関連するパターンを学習していないことを意味しています。
けれども長すぎる訓練をする場合、モデルは overfit し始めて訓練データからテストデータに一般化されないパターンを学習するでしょう。上手くバランスを取る必要があります。どのように適切な数のエポックの間訓練するかを理解することは下で探究するように有用なスキルです。
overfitting を回避するためには、最善の解法はより多くの訓練データを使用することです。より多くのデータ上で訓練されたモデルは自然により良く一般化されます。それが最早可能ではないとき、次善の解法は正則化のようなテクニックを使用することです。これらはモデルがストアできる情報の量とタイプに制約を課します。ネットワークがパターンの小さい数を記憶するだけの余裕がある場合、最適化プロセスはそれに最も目立つパターンに注目するように強制します、これは上手く一般化するより良い可能性を持ちます。
このノートブックでは、2 つの一般的な正則化テクニックを探究します — 重み正則化と dropout です — そしてそれらを使用して IMDB 映画レビュー分類ノートブックを改良します。
import tensorflow as tf from tensorflow import keras import numpy as np import matplotlib.pyplot as plt print(tf.__version__)
1.9.0
IMDB データセットをダウンロードする
前のノートブックのように埋め込みを使用するのではなく、ここではセンテンスを multi-hot エンコードします。このモデルは訓練セットに迅速に overfit します。それは overfitting が発生したとき、それとどのように戦うかを示すために使用されます。
リストの multi-hot エンコーディングはそれらを 0 と 1 のベクトルに変えることを意味します。具体的には、これは例えばシークエンス [3, 5] を (1 となる) インデックス 3 と 5 を除いて総て 0 の 10,000 次元ベクトルに変えることを意味します。
NUM_WORDS = 10000 (train_data, train_labels), (test_data, test_labels) = keras.datasets.imdb.load_data(num_words=NUM_WORDS) def multi_hot_sequences(sequences, dimension): # Create an all-zero matrix of shape (len(sequences), dimension) results = np.zeros((len(sequences), dimension)) for i, word_indices in enumerate(sequences): results[i, word_indices] = 1.0 # set specific indices of results[i] to 1s return results train_data = multi_hot_sequences(train_data, dimension=NUM_WORDS) test_data = multi_hot_sequences(test_data, dimension=NUM_WORDS)
Downloading data from https://s3.amazonaws.com/text-datasets/imdb.npz 17465344/17464789 [==============================] - 2s 0us/step
結果としての multi-hot ベクトルの一つを見てみましょう。単語インデックスは頻度でソートされますので、プロットで見て取れるように、インデックス 0 の近くにはより多くの 1-値があることが予想されます :
plt.plot(train_data[0])
[]
overfitting を示す
overfitting を回避する最も単純な方法はモデルのサイズ, i.e. モデルの学習可能なパラメータの数 (これは層数と層毎のユニット数により決定されます) を減じることです。深層学習では、モデルの学習可能なパラメータ数はしばしばモデルの “capacity” として参照されます。直感的には、より多くのパラメータを持つモデルはより多くの “記憶 capacity” を持ちそしてそれ故に訓練サンプルとターゲットの間の完全な辞書ライクなマッピング、どのような一般化パワーもないマッピングを簡単に学習可能です、しかしこれは以前に見ていないデータ上で予測を行なうときに役に立ちません。
これを常に念頭に置いてください : 深層学習モデルは訓練データに fit するには良い傾向がありますが、実際の挑戦は一般化であり、fitting ではありません。
その一方で、ネットワークが制限された記憶リソースを持つ場合には、マッピングを簡単には学習することができないでしょう。損失を最小化するためには、より予測力を持つ圧縮された (= compressed) 表現を学習しなければなりません。同時に、モデルを小さくし過ぎれば、それは訓練データに fit することが困難になるでしょう。これは “too much capacity” と “not enough capacity” の間のバランスです。
不幸なことに、モデルの正しいサイズやアーキテクチャ (層の数の視点から、あるいは各層のための正しいサイズが何か) を決定するための魔法の公式はありません。異なるアーキテクチャのシリーズを使用して実験しなければなりません。
適切なモデルサイズを見つけるためには、比較的少ない層とパラメータで始めて、それから検証損失上の戻しが減衰し始めるまで層のサイズを増やしたり新しい層を追加します。これを映画レビュー分類ネットワークで試してみましょう。
ベースラインとして Dense 層だけを使用する単純なモデルを作成します、それからより小さいものと大きいバージョンを作成し、それらを比較してみます。
ベースライン・モデルを作成する
baseline_model = keras.Sequential([ # `input_shape` is only required here so that `.summary` works. keras.layers.Dense(16, activation=tf.nn.relu, input_shape=(NUM_WORDS,)), keras.layers.Dense(16, activation=tf.nn.relu), keras.layers.Dense(1, activation=tf.nn.sigmoid) ]) baseline_model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy', 'binary_crossentropy']) baseline_model.summary()
_________________________________________________________________ Layer (type) Output Shape Param # ================================================================= dense (Dense) (None, 16) 160016 _________________________________________________________________ dense_1 (Dense) (None, 16) 272 _________________________________________________________________ dense_2 (Dense) (None, 1) 17 ================================================================= Total params: 160,305 Trainable params: 160,305 Non-trainable params: 0 _________________________________________________________________
baseline_history = baseline_model.fit(train_data, train_labels, epochs=20, batch_size=512, validation_data=(test_data, test_labels), verbose=2)
Train on 25000 samples, validate on 25000 samples Epoch 1/20 - 4s - loss: 0.4830 - acc: 0.8082 - binary_crossentropy: 0.4830 - val_loss: 0.3383 - val_acc: 0.8758 - val_binary_crossentropy: 0.3383 Epoch 2/20 - 4s - loss: 0.2494 - acc: 0.9114 - binary_crossentropy: 0.2494 - val_loss: 0.2851 - val_acc: 0.8862 - val_binary_crossentropy: 0.2851 Epoch 3/20 - 4s - loss: 0.1816 - acc: 0.9372 - binary_crossentropy: 0.1816 - val_loss: 0.2894 - val_acc: 0.8850 - val_binary_crossentropy: 0.2894 Epoch 4/20 - 4s - loss: 0.1444 - acc: 0.9516 - binary_crossentropy: 0.1444 - val_loss: 0.3147 - val_acc: 0.8790 - val_binary_crossentropy: 0.3147 Epoch 5/20 - 4s - loss: 0.1184 - acc: 0.9613 - binary_crossentropy: 0.1184 - val_loss: 0.3409 - val_acc: 0.8747 - val_binary_crossentropy: 0.3409 Epoch 6/20 - 4s - loss: 0.0960 - acc: 0.9704 - binary_crossentropy: 0.0960 - val_loss: 0.3744 - val_acc: 0.8702 - val_binary_crossentropy: 0.3744 Epoch 7/20 - 4s - loss: 0.0766 - acc: 0.9788 - binary_crossentropy: 0.0766 - val_loss: 0.4213 - val_acc: 0.8624 - val_binary_crossentropy: 0.4213 Epoch 8/20 - 4s - loss: 0.0610 - acc: 0.9843 - binary_crossentropy: 0.0610 - val_loss: 0.4507 - val_acc: 0.8634 - val_binary_crossentropy: 0.4507 Epoch 9/20 - 4s - loss: 0.0472 - acc: 0.9901 - binary_crossentropy: 0.0472 - val_loss: 0.4909 - val_acc: 0.8617 - val_binary_crossentropy: 0.4909 Epoch 10/20 - 4s - loss: 0.0355 - acc: 0.9942 - binary_crossentropy: 0.0355 - val_loss: 0.5343 - val_acc: 0.8570 - val_binary_crossentropy: 0.5343 Epoch 11/20 - 4s - loss: 0.0270 - acc: 0.9963 - binary_crossentropy: 0.0270 - val_loss: 0.5752 - val_acc: 0.8584 - val_binary_crossentropy: 0.5752 Epoch 12/20 - 4s - loss: 0.0202 - acc: 0.9979 - binary_crossentropy: 0.0202 - val_loss: 0.6161 - val_acc: 0.8565 - val_binary_crossentropy: 0.6161 Epoch 13/20 - 4s - loss: 0.0148 - acc: 0.9989 - binary_crossentropy: 0.0148 - val_loss: 0.6524 - val_acc: 0.8562 - val_binary_crossentropy: 0.6524 Epoch 14/20 - 4s - loss: 0.0111 - acc: 0.9995 - binary_crossentropy: 0.0111 - val_loss: 0.6874 - val_acc: 0.8538 - val_binary_crossentropy: 0.6874 Epoch 15/20 - 4s - loss: 0.0084 - acc: 0.9998 - binary_crossentropy: 0.0084 - val_loss: 0.7186 - val_acc: 0.8536 - val_binary_crossentropy: 0.7186 Epoch 16/20 - 4s - loss: 0.0067 - acc: 0.9999 - binary_crossentropy: 0.0067 - val_loss: 0.7471 - val_acc: 0.8535 - val_binary_crossentropy: 0.7471 Epoch 17/20 - 4s - loss: 0.0053 - acc: 1.0000 - binary_crossentropy: 0.0053 - val_loss: 0.7722 - val_acc: 0.8536 - val_binary_crossentropy: 0.7722 Epoch 18/20 - 4s - loss: 0.0044 - acc: 1.0000 - binary_crossentropy: 0.0044 - val_loss: 0.7973 - val_acc: 0.8522 - val_binary_crossentropy: 0.7973 Epoch 19/20 - 4s - loss: 0.0037 - acc: 1.0000 - binary_crossentropy: 0.0037 - val_loss: 0.8185 - val_acc: 0.8536 - val_binary_crossentropy: 0.8185 Epoch 20/20 - 4s - loss: 0.0031 - acc: 1.0000 - binary_crossentropy: 0.0031 - val_loss: 0.8396 - val_acc: 0.8522 - val_binary_crossentropy: 0.8396
より小さいモデルを作成する
作成したばかりのベースライン・モデルに対して比較するためにより少ない隠れユニットを持つモデルを作成しましょう :
smaller_model = keras.Sequential([ keras.layers.Dense(4, activation=tf.nn.relu, input_shape=(NUM_WORDS,)), keras.layers.Dense(4, activation=tf.nn.relu), keras.layers.Dense(1, activation=tf.nn.sigmoid) ]) smaller_model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy', 'binary_crossentropy']) smaller_model.summary()
_________________________________________________________________ Layer (type) Output Shape Param # ================================================================= dense_3 (Dense) (None, 4) 40004 _________________________________________________________________ dense_4 (Dense) (None, 4) 20 _________________________________________________________________ dense_5 (Dense) (None, 1) 5 ================================================================= Total params: 40,029 Trainable params: 40,029 Non-trainable params: 0 _________________________________________________________________
そして同じデータを使用してモデルを訓練します :
smaller_history = smaller_model.fit(train_data, train_labels, epochs=20, batch_size=512, validation_data=(test_data, test_labels), verbose=2)
Train on 25000 samples, validate on 25000 samples Epoch 1/20 - 4s - loss: 0.5875 - acc: 0.7590 - binary_crossentropy: 0.5875 - val_loss: 0.4841 - val_acc: 0.8534 - val_binary_crossentropy: 0.4841 Epoch 2/20 - 4s - loss: 0.3949 - acc: 0.8851 - binary_crossentropy: 0.3949 - val_loss: 0.3738 - val_acc: 0.8733 - val_binary_crossentropy: 0.3738 Epoch 3/20 - 4s - loss: 0.3001 - acc: 0.9069 - binary_crossentropy: 0.3001 - val_loss: 0.3222 - val_acc: 0.8838 - val_binary_crossentropy: 0.3222 Epoch 4/20 - 4s - loss: 0.2469 - acc: 0.9221 - binary_crossentropy: 0.2469 - val_loss: 0.2992 - val_acc: 0.8860 - val_binary_crossentropy: 0.2992 Epoch 5/20 - 4s - loss: 0.2129 - acc: 0.9320 - binary_crossentropy: 0.2129 - val_loss: 0.2901 - val_acc: 0.8862 - val_binary_crossentropy: 0.2901 Epoch 6/20 - 4s - loss: 0.1881 - acc: 0.9386 - binary_crossentropy: 0.1881 - val_loss: 0.2850 - val_acc: 0.8878 - val_binary_crossentropy: 0.2850 Epoch 7/20 - 4s - loss: 0.1689 - acc: 0.9461 - binary_crossentropy: 0.1689 - val_loss: 0.2862 - val_acc: 0.8854 - val_binary_crossentropy: 0.2862 Epoch 8/20 - 4s - loss: 0.1534 - acc: 0.9506 - binary_crossentropy: 0.1534 - val_loss: 0.2903 - val_acc: 0.8847 - val_binary_crossentropy: 0.2903 Epoch 9/20 - 4s - loss: 0.1412 - acc: 0.9550 - binary_crossentropy: 0.1412 - val_loss: 0.2964 - val_acc: 0.8828 - val_binary_crossentropy: 0.2964 Epoch 10/20 - 4s - loss: 0.1291 - acc: 0.9600 - binary_crossentropy: 0.1291 - val_loss: 0.3066 - val_acc: 0.8791 - val_binary_crossentropy: 0.3066 Epoch 11/20 - 4s - loss: 0.1193 - acc: 0.9646 - binary_crossentropy: 0.1193 - val_loss: 0.3139 - val_acc: 0.8790 - val_binary_crossentropy: 0.3139 Epoch 12/20 - 4s - loss: 0.1103 - acc: 0.9680 - binary_crossentropy: 0.1103 - val_loss: 0.3267 - val_acc: 0.8759 - val_binary_crossentropy: 0.3267 Epoch 13/20 - 4s - loss: 0.1022 - acc: 0.9712 - binary_crossentropy: 0.1022 - val_loss: 0.3347 - val_acc: 0.8755 - val_binary_crossentropy: 0.3347 Epoch 14/20 - 4s - loss: 0.0953 - acc: 0.9735 - binary_crossentropy: 0.0953 - val_loss: 0.3465 - val_acc: 0.8731 - val_binary_crossentropy: 0.3465 Epoch 15/20 - 4s - loss: 0.0883 - acc: 0.9762 - binary_crossentropy: 0.0883 - val_loss: 0.3589 - val_acc: 0.8712 - val_binary_crossentropy: 0.3589 Epoch 16/20 - 4s - loss: 0.0822 - acc: 0.9783 - binary_crossentropy: 0.0822 - val_loss: 0.3717 - val_acc: 0.8704 - val_binary_crossentropy: 0.3717 Epoch 17/20 - 4s - loss: 0.0767 - acc: 0.9811 - binary_crossentropy: 0.0767 - val_loss: 0.3864 - val_acc: 0.8688 - val_binary_crossentropy: 0.3864 Epoch 18/20 - 4s - loss: 0.0712 - acc: 0.9833 - binary_crossentropy: 0.0712 - val_loss: 0.4017 - val_acc: 0.8668 - val_binary_crossentropy: 0.4017 Epoch 19/20 - 4s - loss: 0.0659 - acc: 0.9857 - binary_crossentropy: 0.0659 - val_loss: 0.4142 - val_acc: 0.8666 - val_binary_crossentropy: 0.4142 Epoch 20/20 - 4s - loss: 0.0606 - acc: 0.9877 - binary_crossentropy: 0.0606 - val_loss: 0.4292 - val_acc: 0.8656 - val_binary_crossentropy: 0.4292
より大きいモデルを作成する
エクササイズとして、より大きいモデルさえも作成して、それがどのように素早く overfitting し始めるかを見ることができます。次に、このベンチマークに、問題が必要とするよりも遥かにより大きい capacity を持つネットワークを追加しましょう :
bigger_model = keras.models.Sequential([ keras.layers.Dense(512, activation=tf.nn.relu, input_shape=(NUM_WORDS,)), keras.layers.Dense(512, activation=tf.nn.relu), keras.layers.Dense(1, activation=tf.nn.sigmoid) ]) bigger_model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy','binary_crossentropy']) bigger_model.summary()
_________________________________________________________________ Layer (type) Output Shape Param # ================================================================= dense_6 (Dense) (None, 512) 5120512 _________________________________________________________________ dense_7 (Dense) (None, 512) 262656 _________________________________________________________________ dense_8 (Dense) (None, 1) 513 ================================================================= Total params: 5,383,681 Trainable params: 5,383,681 Non-trainable params: 0 _________________________________________________________________
そして、再度、同じデータを使用してモデルを訓練します :
bigger_history = bigger_model.fit(train_data, train_labels, epochs=20, batch_size=512, validation_data=(test_data, test_labels), verbose=2)
Train on 25000 samples, validate on 25000 samples Epoch 1/20 - 8s - loss: 0.3478 - acc: 0.8486 - binary_crossentropy: 0.3478 - val_loss: 0.2999 - val_acc: 0.8788 - val_binary_crossentropy: 0.2999 Epoch 2/20 - 8s - loss: 0.1424 - acc: 0.9483 - binary_crossentropy: 0.1424 - val_loss: 0.3631 - val_acc: 0.8639 - val_binary_crossentropy: 0.3631 Epoch 3/20 - 8s - loss: 0.0515 - acc: 0.9854 - binary_crossentropy: 0.0515 - val_loss: 0.4228 - val_acc: 0.8700 - val_binary_crossentropy: 0.4228 Epoch 4/20 - 8s - loss: 0.0081 - acc: 0.9989 - binary_crossentropy: 0.0081 - val_loss: 0.5690 - val_acc: 0.8706 - val_binary_crossentropy: 0.5690 Epoch 5/20 - 8s - loss: 0.0013 - acc: 0.9999 - binary_crossentropy: 0.0013 - val_loss: 0.6585 - val_acc: 0.8719 - val_binary_crossentropy: 0.6585 Epoch 6/20 - 8s - loss: 8.3323e-04 - acc: 1.0000 - binary_crossentropy: 8.3323e-04 - val_loss: 0.6917 - val_acc: 0.8710 - val_binary_crossentropy: 0.6917 Epoch 7/20 - 8s - loss: 1.8393e-04 - acc: 1.0000 - binary_crossentropy: 1.8393e-04 - val_loss: 0.7174 - val_acc: 0.8717 - val_binary_crossentropy: 0.7174 Epoch 8/20 - 7s - loss: 1.2353e-04 - acc: 1.0000 - binary_crossentropy: 1.2353e-04 - val_loss: 0.7397 - val_acc: 0.8720 - val_binary_crossentropy: 0.7397 Epoch 9/20 - 8s - loss: 9.1524e-05 - acc: 1.0000 - binary_crossentropy: 9.1524e-05 - val_loss: 0.7577 - val_acc: 0.8720 - val_binary_crossentropy: 0.7577 Epoch 10/20 - 8s - loss: 7.1093e-05 - acc: 1.0000 - binary_crossentropy: 7.1093e-05 - val_loss: 0.7716 - val_acc: 0.8721 - val_binary_crossentropy: 0.7716 Epoch 11/20 - 8s - loss: 5.7032e-05 - acc: 1.0000 - binary_crossentropy: 5.7032e-05 - val_loss: 0.7852 - val_acc: 0.8719 - val_binary_crossentropy: 0.7852 Epoch 12/20 - 8s - loss: 4.6592e-05 - acc: 1.0000 - binary_crossentropy: 4.6592e-05 - val_loss: 0.7972 - val_acc: 0.8719 - val_binary_crossentropy: 0.7972 Epoch 13/20 - 8s - loss: 3.8803e-05 - acc: 1.0000 - binary_crossentropy: 3.8803e-05 - val_loss: 0.8071 - val_acc: 0.8722 - val_binary_crossentropy: 0.8071 Epoch 14/20 - 8s - loss: 3.2781e-05 - acc: 1.0000 - binary_crossentropy: 3.2781e-05 - val_loss: 0.8176 - val_acc: 0.8722 - val_binary_crossentropy: 0.8176 Epoch 15/20 - 8s - loss: 2.7967e-05 - acc: 1.0000 - binary_crossentropy: 2.7967e-05 - val_loss: 0.8265 - val_acc: 0.8723 - val_binary_crossentropy: 0.8265 Epoch 16/20 - 7s - loss: 2.4134e-05 - acc: 1.0000 - binary_crossentropy: 2.4134e-05 - val_loss: 0.8344 - val_acc: 0.8722 - val_binary_crossentropy: 0.8344 Epoch 17/20 - 7s - loss: 2.0978e-05 - acc: 1.0000 - binary_crossentropy: 2.0978e-05 - val_loss: 0.8435 - val_acc: 0.8723 - val_binary_crossentropy: 0.8435 Epoch 18/20 - 8s - loss: 1.8398e-05 - acc: 1.0000 - binary_crossentropy: 1.8398e-05 - val_loss: 0.8501 - val_acc: 0.8722 - val_binary_crossentropy: 0.8501 Epoch 19/20 - 8s - loss: 1.6204e-05 - acc: 1.0000 - binary_crossentropy: 1.6204e-05 - val_loss: 0.8572 - val_acc: 0.8722 - val_binary_crossentropy: 0.8572 Epoch 20/20 - 8s - loss: 1.4384e-05 - acc: 1.0000 - binary_crossentropy: 1.4384e-05 - val_loss: 0.8645 - val_acc: 0.8723 - val_binary_crossentropy: 0.8645
訓練検証損失をプロットする
実践は訓練損失を示し、破線は検証損失を示します (remember: より低い検証損失はより良いモデルを示します)。ここで、より小さいネットワークはベースラインモデルよりも後で overfitting し始めて (4 ではなくて 6 エポック後) そしてそのパフーマンスはひとたび overfitting し始めれば遥かによりゆっくりと低下します。
def plot_history(histories, key='binary_crossentropy'): plt.figure(figsize=(16,10)) for name, history in histories: val = plt.plot(history.epoch, history.history['val_'+key], '--', label=name.title()+' Val') plt.plot(history.epoch, history.history[key], color=val[0].get_color(), label=name.title()+' Train') plt.xlabel('Epochs') plt.ylabel(key.replace('_',' ').title()) plt.legend() plt.xlim([0,max(history.epoch)]) plot_history([('baseline', baseline_history), ('smaller', smaller_history), ('bigger', bigger_history)])
より大きいネットワークは殆ど直ちに、丁度 1 エポック後に overfitting し始めます、そして遥かにより厳しく overfit することに気がつくでしょう。ネットワークがより多くの capacity を持つほど、より迅速に訓練データをモデリングすることが可能です (低い訓練損失という結果になります) が、それはより overfitting しやすいです (訓練と検証損失間の巨大な差異という結果になります) 。
ストラテジー
重み正則化を追加する
貴方はオッカムの剃刀の原理を知っているかもしれません: 何かについて 2 つの説明が与えられたとき、最も正しい可能性がある説明は「単純な」もの、最小量の仮定をするものです。これはまたニューラルネットワークにより学習されたモデルにも適用されます : ある訓練データとネットワーク・アーキテクチャが与えられたとき、データを説明できる重み値の複数のセット (複数のモデル) があり、そしてより単純なモデルは複雑なものよりも overfit する可能性が低いです。
このコンテキストでの「単純なモデル」はそこではパラメータ値の分布がより少ないエントロピーを持ちます (あるいはまとめてより少ないパラメータを持つモデルです、上のセクションで見たような)。そのため overfitting を軽減する一般的な方法はその (ネットワークの) 重みを小さい値だけを取るように強制してネットワークの複雑さに制約を置くことです、それは重み値の分布をより「正則 (= regular)」にします。これは「重み正則化」と呼ばれ、それはネットワークの損失関数に巨大な重みを持つことに関連するコストを追加することによって成されます。このコストは 2 つのフレーバーに分けられます :
- L1 正則化, ここでは追加されるコストは重み係数への (i.e. 重みの「L1 ノルム」と呼称されるものへの) 絶対値への比例項です。
- L2 正則化, ここでは追加されるコストは重み係数の値の二乗への (i.e. 重みの「L2 ノルム」と呼称されるものへの) 比例項です。L2 正則化はまたニューラルネットワークのコンテキストでは重み減衰とも呼称されます。異なる名前に混乱してはいけません。重み減衰は数学的には L2 正則化と正確時同じです。
tf.keras では、重み正則化は層にキーワード引数として重み regularizer インスタンスを渡すことにより追加されます。今 L2 重み正則化を追加しましょう。
l2_model = keras.models.Sequential([ keras.layers.Dense(16, kernel_regularizer=keras.regularizers.l2(0.001), activation=tf.nn.relu, input_shape=(NUM_WORDS,)), keras.layers.Dense(16, kernel_regularizer=keras.regularizers.l2(0.001), activation=tf.nn.relu), keras.layers.Dense(1, activation=tf.nn.sigmoid) ]) l2_model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy', 'binary_crossentropy']) l2_model_history = l2_model.fit(train_data, train_labels, epochs=20, batch_size=512, validation_data=(test_data, test_labels), verbose=2)
Train on 25000 samples, validate on 25000 samples Epoch 1/20 - 4s - loss: 0.5401 - acc: 0.7926 - binary_crossentropy: 0.5019 - val_loss: 0.3785 - val_acc: 0.8760 - val_binary_crossentropy: 0.3386 Epoch 2/20 - 4s - loss: 0.2991 - acc: 0.9103 - binary_crossentropy: 0.2543 - val_loss: 0.3339 - val_acc: 0.8870 - val_binary_crossentropy: 0.2856 Epoch 3/20 - 4s - loss: 0.2479 - acc: 0.9311 - binary_crossentropy: 0.1970 - val_loss: 0.3392 - val_acc: 0.8854 - val_binary_crossentropy: 0.2863 Epoch 4/20 - 4s - loss: 0.2230 - acc: 0.9424 - binary_crossentropy: 0.1684 - val_loss: 0.3551 - val_acc: 0.8804 - val_binary_crossentropy: 0.2994 Epoch 5/20 - 4s - loss: 0.2109 - acc: 0.9484 - binary_crossentropy: 0.1535 - val_loss: 0.3678 - val_acc: 0.8781 - val_binary_crossentropy: 0.3093 Epoch 6/20 - 4s - loss: 0.1980 - acc: 0.9528 - binary_crossentropy: 0.1389 - val_loss: 0.3845 - val_acc: 0.8745 - val_binary_crossentropy: 0.3249 Epoch 7/20 - 4s - loss: 0.1915 - acc: 0.9560 - binary_crossentropy: 0.1307 - val_loss: 0.3987 - val_acc: 0.8718 - val_binary_crossentropy: 0.3371 Epoch 8/20 - 4s - loss: 0.1841 - acc: 0.9600 - binary_crossentropy: 0.1217 - val_loss: 0.4122 - val_acc: 0.8698 - val_binary_crossentropy: 0.3495 Epoch 9/20 - 4s - loss: 0.1791 - acc: 0.9607 - binary_crossentropy: 0.1158 - val_loss: 0.4294 - val_acc: 0.8684 - val_binary_crossentropy: 0.3656 Epoch 10/20 - 4s - loss: 0.1775 - acc: 0.9620 - binary_crossentropy: 0.1130 - val_loss: 0.4455 - val_acc: 0.8642 - val_binary_crossentropy: 0.3804 Epoch 11/20 - 4s - loss: 0.1726 - acc: 0.9639 - binary_crossentropy: 0.1071 - val_loss: 0.4527 - val_acc: 0.8648 - val_binary_crossentropy: 0.3867 Epoch 12/20 - 4s - loss: 0.1690 - acc: 0.9653 - binary_crossentropy: 0.1029 - val_loss: 0.4718 - val_acc: 0.8604 - val_binary_crossentropy: 0.4054 Epoch 13/20 - 4s - loss: 0.1682 - acc: 0.9660 - binary_crossentropy: 0.1011 - val_loss: 0.4770 - val_acc: 0.8628 - val_binary_crossentropy: 0.4095 Epoch 14/20 - 4s - loss: 0.1597 - acc: 0.9693 - binary_crossentropy: 0.0922 - val_loss: 0.4842 - val_acc: 0.8592 - val_binary_crossentropy: 0.4170 Epoch 15/20 - 4s - loss: 0.1542 - acc: 0.9729 - binary_crossentropy: 0.0871 - val_loss: 0.4987 - val_acc: 0.8596 - val_binary_crossentropy: 0.4315 Epoch 16/20 - 4s - loss: 0.1525 - acc: 0.9733 - binary_crossentropy: 0.0851 - val_loss: 0.5099 - val_acc: 0.8566 - val_binary_crossentropy: 0.4423 Epoch 17/20 - 4s - loss: 0.1500 - acc: 0.9742 - binary_crossentropy: 0.0824 - val_loss: 0.5175 - val_acc: 0.8567 - val_binary_crossentropy: 0.4495 Epoch 18/20 - 4s - loss: 0.1487 - acc: 0.9741 - binary_crossentropy: 0.0805 - val_loss: 0.5354 - val_acc: 0.8552 - val_binary_crossentropy: 0.4668 Epoch 19/20 - 4s - loss: 0.1466 - acc: 0.9748 - binary_crossentropy: 0.0778 - val_loss: 0.5389 - val_acc: 0.8589 - val_binary_crossentropy: 0.4700 Epoch 20/20 - 4s - loss: 0.1451 - acc: 0.9755 - binary_crossentropy: 0.0757 - val_loss: 0.5499 - val_acc: 0.8557 - val_binary_crossentropy: 0.4800
l2(0.001) は層の重み行列の総ての係数が 0.001 * weight_coefficient_value をネットワークの総計損失に追加することを意味します。このペナルティは訓練時のみに追加されますので、このネットワークに対する損失はテスト時よりも訓練時に遥かに高くなります。
L2 正則化ペナルティのインパクトがここにあります :
見て取れるように、両者のモデルが同じパラメータ数を持つ場合でさえも、L2 正則化されたモデルはベースライン・モデルよりも overfitting に大して遥かにより耐性があります。
dropout を追加する
Dropout は最も効果的で最も一般に使用されるニューラルネットワークのための正則化テクニックの一つで、University of Toronto の Hinton とその学生により開発されました。Dropout は層に適用され、訓練の間層の出力特徴の数をランダムに “dropping out” (i.e. ゼロに設定) することから成ります。訓練の間に与えられた入力サンプルに対して与えられた層は通常はベクトル [0.2, 0.5, 1.3, 0.8, 1.1] を返したと仮定します ; dropout を適用した後、このベクトルはランダムに分布する幾つかのゼロ要素を持つでしょう、e.g. [0, 0.5, 1.3, 0, 1.1] です。”dropout 率” はゼロにされる特徴の割合です ; それは通常は 0.2 と 0.5 の間に設定されます。テスト時には、ユニットは drop out されず、代わりに層の出力値は dropout 率に等しい係数でスケールダウンされます、これは訓練時よりもより多いユニットが有効であるという事実のためにバランスを取るためです。
tf.keras では Dropout 層を通してネットワークに dropout を導入できます、それはすぐ前の層の出力に適用されます。
IMDB ネットワークに 2 つの Dropout 層をそれらがどのように上手く overfitting を減じるかを見るために追加しましょう :
dpt_model = keras.models.Sequential([ keras.layers.Dense(16, activation=tf.nn.relu, input_shape=(NUM_WORDS,)), keras.layers.Dropout(0.5), keras.layers.Dense(16, activation=tf.nn.relu), keras.layers.Dropout(0.5), keras.layers.Dense(1, activation=tf.nn.sigmoid) ]) dpt_model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy','binary_crossentropy']) dpt_model_history = dpt_model.fit(train_data, train_labels, epochs=20, batch_size=512, validation_data=(test_data, test_labels), verbose=2)
Train on 25000 samples, validate on 25000 samples Epoch 1/20 - 4s - loss: 0.6363 - acc: 0.6294 - binary_crossentropy: 0.6363 - val_loss: 0.5156 - val_acc: 0.8526 - val_binary_crossentropy: 0.5156 Epoch 2/20 - 4s - loss: 0.4776 - acc: 0.7993 - binary_crossentropy: 0.4776 - val_loss: 0.3629 - val_acc: 0.8782 - val_binary_crossentropy: 0.3629 Epoch 3/20 - 4s - loss: 0.3731 - acc: 0.8549 - binary_crossentropy: 0.3731 - val_loss: 0.2976 - val_acc: 0.8864 - val_binary_crossentropy: 0.2976 Epoch 4/20 - 4s - loss: 0.3065 - acc: 0.8850 - binary_crossentropy: 0.3065 - val_loss: 0.2748 - val_acc: 0.8896 - val_binary_crossentropy: 0.2748 Epoch 5/20 - 4s - loss: 0.2610 - acc: 0.9066 - binary_crossentropy: 0.2610 - val_loss: 0.2751 - val_acc: 0.8882 - val_binary_crossentropy: 0.2751 Epoch 6/20 - 4s - loss: 0.2245 - acc: 0.9192 - binary_crossentropy: 0.2245 - val_loss: 0.2844 - val_acc: 0.8870 - val_binary_crossentropy: 0.2844 Epoch 7/20 - 4s - loss: 0.1968 - acc: 0.9266 - binary_crossentropy: 0.1968 - val_loss: 0.2999 - val_acc: 0.8873 - val_binary_crossentropy: 0.2999 Epoch 8/20 - 4s - loss: 0.1759 - acc: 0.9362 - binary_crossentropy: 0.1759 - val_loss: 0.3136 - val_acc: 0.8859 - val_binary_crossentropy: 0.3136 Epoch 9/20 - 4s - loss: 0.1596 - acc: 0.9438 - binary_crossentropy: 0.1596 - val_loss: 0.3242 - val_acc: 0.8826 - val_binary_crossentropy: 0.3242 Epoch 10/20 - 4s - loss: 0.1412 - acc: 0.9498 - binary_crossentropy: 0.1412 - val_loss: 0.3551 - val_acc: 0.8823 - val_binary_crossentropy: 0.3551 Epoch 11/20 - 4s - loss: 0.1292 - acc: 0.9539 - binary_crossentropy: 0.1292 - val_loss: 0.3745 - val_acc: 0.8792 - val_binary_crossentropy: 0.3745 Epoch 12/20 - 4s - loss: 0.1176 - acc: 0.9568 - binary_crossentropy: 0.1176 - val_loss: 0.3983 - val_acc: 0.8800 - val_binary_crossentropy: 0.3983 Epoch 13/20 - 4s - loss: 0.1115 - acc: 0.9582 - binary_crossentropy: 0.1115 - val_loss: 0.4218 - val_acc: 0.8791 - val_binary_crossentropy: 0.4218 Epoch 14/20 - 4s - loss: 0.1035 - acc: 0.9612 - binary_crossentropy: 0.1035 - val_loss: 0.4368 - val_acc: 0.8780 - val_binary_crossentropy: 0.4368 Epoch 15/20 - 4s - loss: 0.0949 - acc: 0.9626 - binary_crossentropy: 0.0949 - val_loss: 0.4608 - val_acc: 0.8773 - val_binary_crossentropy: 0.4608 Epoch 16/20 - 4s - loss: 0.0909 - acc: 0.9626 - binary_crossentropy: 0.0909 - val_loss: 0.4573 - val_acc: 0.8776 - val_binary_crossentropy: 0.4573 Epoch 17/20 - 4s - loss: 0.0860 - acc: 0.9642 - binary_crossentropy: 0.0860 - val_loss: 0.4963 - val_acc: 0.8770 - val_binary_crossentropy: 0.4963 Epoch 18/20 - 4s - loss: 0.0832 - acc: 0.9655 - binary_crossentropy: 0.0832 - val_loss: 0.4879 - val_acc: 0.8762 - val_binary_crossentropy: 0.4879 Epoch 19/20 - 4s - loss: 0.0752 - acc: 0.9698 - binary_crossentropy: 0.0752 - val_loss: 0.5262 - val_acc: 0.8760 - val_binary_crossentropy: 0.5262 Epoch 20/20 - 4s - loss: 0.0768 - acc: 0.9666 - binary_crossentropy: 0.0768 - val_loss: 0.5360 - val_acc: 0.8754 - val_binary_crossentropy: 0.5360
plot_history([('baseline', baseline_history), ('dropout', dpt_model_history)])
dropout の追加はベースライン・モデルを超える明確な改善です。
復習のために: こちらはニューラルネットワークで overfitting を回避するための最も一般的な方法です :
- より多くの訓練データを得る。
- ネットワークの capcity を減じる。
- 重み正則を追加する。
- dropout を追加する。
そしてこのガイドでカバーされていない 2 つの重要なアプローチはデータ増強とバッチ正規化です。
以上