TensorFlow 2.0 Beta : Beginner Tutorials : ML 基本 :- overfitting と underfitting を調査する (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 06/23/2019
* 本ページは、TensorFlow の本家サイトの TF 2.0 Beta – Beginner Tutorials – ML basics の以下のページを翻訳した上で
適宜、補足説明したものです:
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
ML 基本 :- overfitting と underfitting を調査する
いつものように、このサンプルのコードは tf.keras API を使用します、これについては TensorFlow Keras guide で更に学習できます。
前の例の両者 — 映画レビューの分類と燃費効率の予測 — では、検証データ上のモデルの精度が幾つかのエポックの訓練後に最大になり、それから減少し始めることを見ました。
換言すれば、モデルは訓練データに overfit しています。overfitting にどのように対処するかを学ぶことは重要です。訓練セット上で高い精度を獲得することはしばしば可能ですが、本当に望むことはテストデータ (あるいは前にまだ見ていないデータ) に上手く一般化されたモデルを開発することです。
overfitting の反対は underfitting です。underfitting は テストデータ上でまだ改善の余地があるときに発生します。これは幾つかの理由で起こります : モデルが十分にパワフルでない場合、過剰に正則化されている、あるいは単に十分に長く訓練されていない場合。これはネットワークが訓練データ内の関連するパターンを学習していないことを意味しています。
けれども長すぎる訓練をする場合、モデルは overfit し始めて訓練データからテストデータに一般化されないパターンを学習するでしょう。上手くバランスを取る必要があります。どのように適切な数のエポックの間訓練するかを理解することは下で探究するように有用なスキルです。
overfitting を回避するためには、最善の解法はより多くの訓練データを使用することです。より多くのデータ上で訓練されたモデルは自然により良く一般化されます。それが最早可能ではないとき、次善の解法は正則化のようなテクニックを使用することです。これらはモデルがストアできる情報の量とタイプに制約を課します。ネットワークが小さい数のパターンを記憶するだけの余裕がある場合、最適化プロセスはそれに最も目立つパターンに注目するように強制します、これは上手く一般化するより良い可能性を持ちます。
このノートブックでは、2 つの一般的な正則化テクニックを探究します — 重み正則化と dropout です — そしてそれらを使用して IMDB 映画レビュー分類ノートブックを改良します。
from __future__ import absolute_import, division, print_function, unicode_literals !pip install -q tensorflow==2.0.0-beta1 import tensorflow as tf from tensorflow import keras import numpy as np import matplotlib.pyplot as plt print(tf.__version__)
2.0.0-beta1
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)
結果としての 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='relu', input_shape=(NUM_WORDS,)), keras.layers.Dense(16, activation='relu'), keras.layers.Dense(1, activation='sigmoid') ]) baseline_model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy', 'binary_crossentropy']) baseline_model.summary()
Model: "sequential" _________________________________________________________________ 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)
WARNING: Logging before flag parsing goes to stderr. W0614 17:36:34.386701 139673406682880 deprecation.py:323] From /tmpfs/src/tf_docs_env/lib/python3.5/site-packages/tensorflow/python/ops/math_grad.py:1250: add_dispatch_support.<locals>.wrapper (from tensorflow.python.ops.array_ops) is deprecated and will be removed in a future version. Instructions for updating: Use tf.where in 2.0, which has the same broadcast rule as np.where Train on 25000 samples, validate on 25000 samples Epoch 1/20 25000/25000 - 5s - loss: 0.5435 - accuracy: 0.7573 - binary_crossentropy: 0.5435 - val_loss: 0.3906 - val_accuracy: 0.8675 - val_binary_crossentropy: 0.3906 Epoch 2/20 25000/25000 - 4s - loss: 0.2790 - accuracy: 0.9034 - binary_crossentropy: 0.2790 - val_loss: 0.2889 - val_accuracy: 0.8872 - val_binary_crossentropy: 0.2889 Epoch 3/20 25000/25000 - 4s - loss: 0.1947 - accuracy: 0.9311 - binary_crossentropy: 0.1947 - val_loss: 0.2861 - val_accuracy: 0.8861 - val_binary_crossentropy: 0.2861 Epoch 4/20 25000/25000 - 4s - loss: 0.1572 - accuracy: 0.9461 - binary_crossentropy: 0.1572 - val_loss: 0.3030 - val_accuracy: 0.8798 - val_binary_crossentropy: 0.3030 Epoch 5/20 25000/25000 - 4s - loss: 0.1297 - accuracy: 0.9570 - binary_crossentropy: 0.1297 - val_loss: 0.3207 - val_accuracy: 0.8769 - val_binary_crossentropy: 0.3207 Epoch 6/20 25000/25000 - 3s - loss: 0.1091 - accuracy: 0.9660 - binary_crossentropy: 0.1091 - val_loss: 0.3461 - val_accuracy: 0.8739 - val_binary_crossentropy: 0.3461 Epoch 7/20 25000/25000 - 4s - loss: 0.0923 - accuracy: 0.9724 - binary_crossentropy: 0.0923 - val_loss: 0.3743 - val_accuracy: 0.8699 - val_binary_crossentropy: 0.3743 Epoch 8/20 25000/25000 - 3s - loss: 0.0791 - accuracy: 0.9773 - binary_crossentropy: 0.0791 - val_loss: 0.4051 - val_accuracy: 0.8671 - val_binary_crossentropy: 0.4051 Epoch 9/20 25000/25000 - 4s - loss: 0.0656 - accuracy: 0.9833 - binary_crossentropy: 0.0656 - val_loss: 0.4379 - val_accuracy: 0.8652 - val_binary_crossentropy: 0.4379 Epoch 10/20 25000/25000 - 4s - loss: 0.0557 - accuracy: 0.9866 - binary_crossentropy: 0.0557 - val_loss: 0.4746 - val_accuracy: 0.8624 - val_binary_crossentropy: 0.4746 Epoch 11/20 25000/25000 - 4s - loss: 0.0435 - accuracy: 0.9910 - binary_crossentropy: 0.0435 - val_loss: 0.5135 - val_accuracy: 0.8601 - val_binary_crossentropy: 0.5135 Epoch 12/20 25000/25000 - 3s - loss: 0.0333 - accuracy: 0.9940 - binary_crossentropy: 0.0333 - val_loss: 0.5561 - val_accuracy: 0.8591 - val_binary_crossentropy: 0.5561 Epoch 13/20 25000/25000 - 4s - loss: 0.0250 - accuracy: 0.9965 - binary_crossentropy: 0.0250 - val_loss: 0.5952 - val_accuracy: 0.8569 - val_binary_crossentropy: 0.5952 Epoch 14/20 25000/25000 - 3s - loss: 0.0180 - accuracy: 0.9978 - binary_crossentropy: 0.0180 - val_loss: 0.6357 - val_accuracy: 0.8549 - val_binary_crossentropy: 0.6357 Epoch 15/20 25000/25000 - 4s - loss: 0.0133 - accuracy: 0.9988 - binary_crossentropy: 0.0133 - val_loss: 0.6691 - val_accuracy: 0.8562 - val_binary_crossentropy: 0.6691 Epoch 16/20 25000/25000 - 3s - loss: 0.0099 - accuracy: 0.9994 - binary_crossentropy: 0.0099 - val_loss: 0.7028 - val_accuracy: 0.8535 - val_binary_crossentropy: 0.7028 Epoch 17/20 25000/25000 - 4s - loss: 0.0073 - accuracy: 0.9997 - binary_crossentropy: 0.0073 - val_loss: 0.7265 - val_accuracy: 0.8543 - val_binary_crossentropy: 0.7265 Epoch 18/20 25000/25000 - 4s - loss: 0.0055 - accuracy: 0.9998 - binary_crossentropy: 0.0055 - val_loss: 0.7547 - val_accuracy: 0.8536 - val_binary_crossentropy: 0.7547 Epoch 19/20 25000/25000 - 4s - loss: 0.0042 - accuracy: 0.9998 - binary_crossentropy: 0.0042 - val_loss: 0.7752 - val_accuracy: 0.8539 - val_binary_crossentropy: 0.7752 Epoch 20/20 25000/25000 - 3s - loss: 0.0033 - accuracy: 0.9999 - binary_crossentropy: 0.0033 - val_loss: 0.7939 - val_accuracy: 0.8542 - val_binary_crossentropy: 0.7939
より小さいモデルを作成する
作成したばかりのベースライン・モデルに対して比較するためにより少ない隠れユニットを持つモデルを作成しましょう :
smaller_model = keras.Sequential([ keras.layers.Dense(4, activation='relu', input_shape=(NUM_WORDS,)), keras.layers.Dense(4, activation='relu'), keras.layers.Dense(1, activation='sigmoid') ]) smaller_model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy', 'binary_crossentropy']) smaller_model.summary()
Model: "sequential_1" _________________________________________________________________ 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 25000/25000 - 4s - loss: 0.5741 - accuracy: 0.7644 - binary_crossentropy: 0.5741 - val_loss: 0.4683 - val_accuracy: 0.8536 - val_binary_crossentropy: 0.4683 Epoch 2/20 25000/25000 - 4s - loss: 0.3749 - accuracy: 0.8862 - binary_crossentropy: 0.3749 - val_loss: 0.3575 - val_accuracy: 0.8753 - val_binary_crossentropy: 0.3575 Epoch 3/20 25000/25000 - 4s - loss: 0.2826 - accuracy: 0.9096 - binary_crossentropy: 0.2826 - val_loss: 0.3133 - val_accuracy: 0.8838 - val_binary_crossentropy: 0.3133 Epoch 4/20 25000/25000 - 3s - loss: 0.2330 - accuracy: 0.9237 - binary_crossentropy: 0.2330 - val_loss: 0.2931 - val_accuracy: 0.8872 - val_binary_crossentropy: 0.2931 Epoch 5/20 25000/25000 - 4s - loss: 0.2007 - accuracy: 0.9344 - binary_crossentropy: 0.2007 - val_loss: 0.2855 - val_accuracy: 0.8878 - val_binary_crossentropy: 0.2855 Epoch 6/20 25000/25000 - 3s - loss: 0.1780 - accuracy: 0.9420 - binary_crossentropy: 0.1780 - val_loss: 0.2842 - val_accuracy: 0.8873 - val_binary_crossentropy: 0.2842 Epoch 7/20 25000/25000 - 4s - loss: 0.1594 - accuracy: 0.9486 - binary_crossentropy: 0.1594 - val_loss: 0.2882 - val_accuracy: 0.8856 - val_binary_crossentropy: 0.2882 Epoch 8/20 25000/25000 - 4s - loss: 0.1444 - accuracy: 0.9541 - binary_crossentropy: 0.1444 - val_loss: 0.2947 - val_accuracy: 0.8839 - val_binary_crossentropy: 0.2947 Epoch 9/20 25000/25000 - 4s - loss: 0.1317 - accuracy: 0.9586 - binary_crossentropy: 0.1317 - val_loss: 0.3093 - val_accuracy: 0.8786 - val_binary_crossentropy: 0.3093 Epoch 10/20 25000/25000 - 3s - loss: 0.1212 - accuracy: 0.9626 - binary_crossentropy: 0.1212 - val_loss: 0.3155 - val_accuracy: 0.8781 - val_binary_crossentropy: 0.3155 Epoch 11/20 25000/25000 - 4s - loss: 0.1111 - accuracy: 0.9669 - binary_crossentropy: 0.1111 - val_loss: 0.3260 - val_accuracy: 0.8763 - val_binary_crossentropy: 0.3260 Epoch 12/20 25000/25000 - 4s - loss: 0.1025 - accuracy: 0.9699 - binary_crossentropy: 0.1025 - val_loss: 0.3407 - val_accuracy: 0.8740 - val_binary_crossentropy: 0.3407 Epoch 13/20 25000/25000 - 4s - loss: 0.0944 - accuracy: 0.9736 - binary_crossentropy: 0.0944 - val_loss: 0.3518 - val_accuracy: 0.8733 - val_binary_crossentropy: 0.3518 Epoch 14/20 25000/25000 - 3s - loss: 0.0873 - accuracy: 0.9755 - binary_crossentropy: 0.0873 - val_loss: 0.3662 - val_accuracy: 0.8708 - val_binary_crossentropy: 0.3662 Epoch 15/20 25000/25000 - 4s - loss: 0.0809 - accuracy: 0.9783 - binary_crossentropy: 0.0809 - val_loss: 0.3801 - val_accuracy: 0.8690 - val_binary_crossentropy: 0.3801 Epoch 16/20 25000/25000 - 3s - loss: 0.0753 - accuracy: 0.9806 - binary_crossentropy: 0.0753 - val_loss: 0.3954 - val_accuracy: 0.8673 - val_binary_crossentropy: 0.3954 Epoch 17/20 25000/25000 - 4s - loss: 0.0685 - accuracy: 0.9835 - binary_crossentropy: 0.0685 - val_loss: 0.4096 - val_accuracy: 0.8662 - val_binary_crossentropy: 0.4096 Epoch 18/20 25000/25000 - 3s - loss: 0.0632 - accuracy: 0.9862 - binary_crossentropy: 0.0632 - val_loss: 0.4284 - val_accuracy: 0.8642 - val_binary_crossentropy: 0.4284 Epoch 19/20 25000/25000 - 4s - loss: 0.0584 - accuracy: 0.9874 - binary_crossentropy: 0.0584 - val_loss: 0.4417 - val_accuracy: 0.8636 - val_binary_crossentropy: 0.4417 Epoch 20/20 25000/25000 - 3s - loss: 0.0538 - accuracy: 0.9894 - binary_crossentropy: 0.0538 - val_loss: 0.4590 - val_accuracy: 0.8624 - val_binary_crossentropy: 0.4590
より大きいモデルを作成する
エクササイズとして、より大きいモデルさえも作成して、それがどのように素早く overfitting し始めるかを見ることができます。次に、このベンチマークに、問題が必要とするよりも遥かにより大きい capacity を持つネットワークを追加しましょう :
bigger_model = keras.models.Sequential([ keras.layers.Dense(512, activation='relu', input_shape=(NUM_WORDS,)), keras.layers.Dense(512, activation='relu'), keras.layers.Dense(1, activation='sigmoid') ]) bigger_model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy','binary_crossentropy']) bigger_model.summary()
Model: "sequential_2" _________________________________________________________________ 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 25000/25000 - 7s - loss: 0.3504 - accuracy: 0.8484 - binary_crossentropy: 0.3504 - val_loss: 0.3066 - val_accuracy: 0.8734 - val_binary_crossentropy: 0.3066 Epoch 2/20 25000/25000 - 7s - loss: 0.1451 - accuracy: 0.9473 - binary_crossentropy: 0.1451 - val_loss: 0.3286 - val_accuracy: 0.8747 - val_binary_crossentropy: 0.3286 Epoch 3/20 25000/25000 - 7s - loss: 0.0478 - accuracy: 0.9859 - binary_crossentropy: 0.0478 - val_loss: 0.4457 - val_accuracy: 0.8685 - val_binary_crossentropy: 0.4457 Epoch 4/20 25000/25000 - 7s - loss: 0.0072 - accuracy: 0.9991 - binary_crossentropy: 0.0072 - val_loss: 0.5815 - val_accuracy: 0.8684 - val_binary_crossentropy: 0.5815 Epoch 5/20 25000/25000 - 7s - loss: 8.4594e-04 - accuracy: 1.0000 - binary_crossentropy: 8.4594e-04 - val_loss: 0.6755 - val_accuracy: 0.8712 - val_binary_crossentropy: 0.6755 Epoch 6/20 25000/25000 - 7s - loss: 2.2323e-04 - accuracy: 1.0000 - binary_crossentropy: 2.2323e-04 - val_loss: 0.7145 - val_accuracy: 0.8712 - val_binary_crossentropy: 0.7145 Epoch 7/20 25000/25000 - 7s - loss: 1.3682e-04 - accuracy: 1.0000 - binary_crossentropy: 1.3682e-04 - val_loss: 0.7393 - val_accuracy: 0.8713 - val_binary_crossentropy: 0.7393 Epoch 8/20 25000/25000 - 7s - loss: 9.8825e-05 - accuracy: 1.0000 - binary_crossentropy: 9.8825e-05 - val_loss: 0.7579 - val_accuracy: 0.8710 - val_binary_crossentropy: 0.7579 Epoch 9/20 25000/25000 - 7s - loss: 7.5939e-05 - accuracy: 1.0000 - binary_crossentropy: 7.5939e-05 - val_loss: 0.7727 - val_accuracy: 0.8711 - val_binary_crossentropy: 0.7727 Epoch 10/20 25000/25000 - 7s - loss: 6.0573e-05 - accuracy: 1.0000 - binary_crossentropy: 6.0573e-05 - val_loss: 0.7846 - val_accuracy: 0.8720 - val_binary_crossentropy: 0.7846 Epoch 11/20 25000/25000 - 7s - loss: 4.9462e-05 - accuracy: 1.0000 - binary_crossentropy: 4.9462e-05 - val_loss: 0.7961 - val_accuracy: 0.8712 - val_binary_crossentropy: 0.7961 Epoch 12/20 25000/25000 - 7s - loss: 4.1340e-05 - accuracy: 1.0000 - binary_crossentropy: 4.1340e-05 - val_loss: 0.8059 - val_accuracy: 0.8716 - val_binary_crossentropy: 0.8059 Epoch 13/20 25000/25000 - 7s - loss: 3.4927e-05 - accuracy: 1.0000 - binary_crossentropy: 3.4927e-05 - val_loss: 0.8144 - val_accuracy: 0.8719 - val_binary_crossentropy: 0.8144 Epoch 14/20 25000/25000 - 7s - loss: 3.0028e-05 - accuracy: 1.0000 - binary_crossentropy: 3.0028e-05 - val_loss: 0.8225 - val_accuracy: 0.8717 - val_binary_crossentropy: 0.8225 Epoch 15/20 25000/25000 - 7s - loss: 2.6054e-05 - accuracy: 1.0000 - binary_crossentropy: 2.6054e-05 - val_loss: 0.8295 - val_accuracy: 0.8717 - val_binary_crossentropy: 0.8295 Epoch 16/20 25000/25000 - 7s - loss: 2.2880e-05 - accuracy: 1.0000 - binary_crossentropy: 2.2880e-05 - val_loss: 0.8366 - val_accuracy: 0.8718 - val_binary_crossentropy: 0.8366 Epoch 17/20 25000/25000 - 7s - loss: 2.0204e-05 - accuracy: 1.0000 - binary_crossentropy: 2.0204e-05 - val_loss: 0.8429 - val_accuracy: 0.8719 - val_binary_crossentropy: 0.8429 Epoch 18/20 25000/25000 - 7s - loss: 1.7972e-05 - accuracy: 1.0000 - binary_crossentropy: 1.7972e-05 - val_loss: 0.8487 - val_accuracy: 0.8718 - val_binary_crossentropy: 0.8487 Epoch 19/20 25000/25000 - 7s - loss: 1.6091e-05 - accuracy: 1.0000 - binary_crossentropy: 1.6091e-05 - val_loss: 0.8541 - val_accuracy: 0.8719 - val_binary_crossentropy: 0.8541 Epoch 20/20 25000/25000 - 7s - loss: 1.4484e-05 - accuracy: 1.0000 - binary_crossentropy: 1.4484e-05 - val_loss: 0.8593 - val_accuracy: 0.8720 - val_binary_crossentropy: 0.8593
訓練と検証損失をプロットする
実線は訓練損失を示し、破線は検証損失を表示します (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 しやすいです (訓練と検証損失間の巨大な差異という結果になります) 。
overfitting を回避するためのストラテジー
重み正則化を追加する
貴方はオッカムの剃刀の原理を知っているかもしれません: 何かについて 2 つの説明が与えられたとき、最も正しい可能性がある説明は「単純な」もの、最小量の仮定をするものです。これはまたニューラルネットワークにより学習されたモデルにも適用されます : ある訓練データとネットワーク・アーキテクチャが与えられたとき、データを説明できる重み値の複数のセット (複数のモデル) があり、そしてより単純なモデルは複雑なものよりも overfit する可能性が低いです。
このコンテキストでの「単純なモデル」はそこではパラメータ値の分布がより少ないエントロピーを持ちます (あるいはまとめてより少ないパラメータを持つモデルです、上のセクションで見たように)。そのため overfitting を軽減する一般的な方法はその (ネットワークの) 重みを小さい値だけを取るように強制してネットワークの複雑さに制約を置くことです、それは重み値の分布をより「正則 (= regular)」にします。これは「重み正則化」と呼ばれ、それはネットワークの損失関数に巨大な重みを持つことに関するコストを追加することによって成されます。このコストは 2 つのフレーバーに分けられます :
- L1 正則化, そこでは追加されるコストは重み係数の絶対値に (i.e. 重みの「L1 ノルム」と呼称されるものに) 比例します。
- L2 正則化, そこでは追加されるコストは重み係数の値の二乗に (i.e. 重みの「L2 ノルム」と呼称されるものに) 比例します。L2 正則化はまたニューラルネットワークのコンテキストでは重み減衰とも呼称されます。異なる名前に混乱してはいけません。重み減衰は数学的には L2 正則化と正確に同じです。
L1 正則化は重みパラメータの幾つかをゼロにするために疎性を導入します。L2 正則化は重みパラメータにそれらを疎にすることなくペナルティを課します – L2 がより一般的である一つの理由です。
tf.keras では、重み正則化は層にキーワード引数として重み regularizer インスタンスを渡すことにより追加されます。今は L2 重み正則化を追加しましょう。
l2_model = keras.models.Sequential([ keras.layers.Dense(16, kernel_regularizer=keras.regularizers.l2(0.001), activation='relu', input_shape=(NUM_WORDS,)), keras.layers.Dense(16, kernel_regularizer=keras.regularizers.l2(0.001), activation='relu'), keras.layers.Dense(1, activation='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 25000/25000 - 5s - loss: 0.5295 - accuracy: 0.8148 - binary_crossentropy: 0.4887 - val_loss: 0.3801 - val_accuracy: 0.8801 - val_binary_crossentropy: 0.3360 Epoch 2/20 25000/25000 - 4s - loss: 0.3049 - accuracy: 0.9076 - binary_crossentropy: 0.2554 - val_loss: 0.3387 - val_accuracy: 0.8876 - val_binary_crossentropy: 0.2855 Epoch 3/20 25000/25000 - 4s - loss: 0.2536 - accuracy: 0.9302 - binary_crossentropy: 0.1978 - val_loss: 0.3437 - val_accuracy: 0.8851 - val_binary_crossentropy: 0.2863 Epoch 4/20 25000/25000 - 4s - loss: 0.2330 - accuracy: 0.9393 - binary_crossentropy: 0.1738 - val_loss: 0.3631 - val_accuracy: 0.8781 - val_binary_crossentropy: 0.3027 Epoch 5/20 25000/25000 - 4s - loss: 0.2176 - accuracy: 0.9470 - binary_crossentropy: 0.1562 - val_loss: 0.3712 - val_accuracy: 0.8769 - val_binary_crossentropy: 0.3091 Epoch 6/20 25000/25000 - 4s - loss: 0.2059 - accuracy: 0.9526 - binary_crossentropy: 0.1428 - val_loss: 0.3836 - val_accuracy: 0.8749 - val_binary_crossentropy: 0.3201 Epoch 7/20 25000/25000 - 4s - loss: 0.1990 - accuracy: 0.9542 - binary_crossentropy: 0.1348 - val_loss: 0.4034 - val_accuracy: 0.8713 - val_binary_crossentropy: 0.3387 Epoch 8/20 25000/25000 - 4s - loss: 0.1929 - accuracy: 0.9567 - binary_crossentropy: 0.1276 - val_loss: 0.4146 - val_accuracy: 0.8696 - val_binary_crossentropy: 0.3490 Epoch 9/20 25000/25000 - 5s - loss: 0.1878 - accuracy: 0.9585 - binary_crossentropy: 0.1214 - val_loss: 0.4298 - val_accuracy: 0.8656 - val_binary_crossentropy: 0.3630 Epoch 10/20 25000/25000 - 5s - loss: 0.1829 - accuracy: 0.9607 - binary_crossentropy: 0.1157 - val_loss: 0.4405 - val_accuracy: 0.8670 - val_binary_crossentropy: 0.3730 Epoch 11/20 25000/25000 - 4s - loss: 0.1779 - accuracy: 0.9635 - binary_crossentropy: 0.1101 - val_loss: 0.4512 - val_accuracy: 0.8653 - val_binary_crossentropy: 0.3830 Epoch 12/20 25000/25000 - 5s - loss: 0.1747 - accuracy: 0.9628 - binary_crossentropy: 0.1060 - val_loss: 0.4647 - val_accuracy: 0.8634 - val_binary_crossentropy: 0.3958 Epoch 13/20 25000/25000 - 5s - loss: 0.1703 - accuracy: 0.9672 - binary_crossentropy: 0.1012 - val_loss: 0.4761 - val_accuracy: 0.8625 - val_binary_crossentropy: 0.4067 Epoch 14/20 25000/25000 - 4s - loss: 0.1683 - accuracy: 0.9660 - binary_crossentropy: 0.0986 - val_loss: 0.4919 - val_accuracy: 0.8589 - val_binary_crossentropy: 0.4218 Epoch 15/20 25000/25000 - 4s - loss: 0.1678 - accuracy: 0.9674 - binary_crossentropy: 0.0976 - val_loss: 0.5063 - val_accuracy: 0.8605 - val_binary_crossentropy: 0.4356 Epoch 16/20 25000/25000 - 4s - loss: 0.1642 - accuracy: 0.9682 - binary_crossentropy: 0.0928 - val_loss: 0.5094 - val_accuracy: 0.8572 - val_binary_crossentropy: 0.4380 Epoch 17/20 25000/25000 - 4s - loss: 0.1613 - accuracy: 0.9689 - binary_crossentropy: 0.0901 - val_loss: 0.5202 - val_accuracy: 0.8590 - val_binary_crossentropy: 0.4488 Epoch 18/20 25000/25000 - 4s - loss: 0.1623 - accuracy: 0.9689 - binary_crossentropy: 0.0902 - val_loss: 0.5563 - val_accuracy: 0.8546 - val_binary_crossentropy: 0.4838 Epoch 19/20 25000/25000 - 4s - loss: 0.1610 - accuracy: 0.9682 - binary_crossentropy: 0.0883 - val_loss: 0.5347 - val_accuracy: 0.8559 - val_binary_crossentropy: 0.4617 Epoch 20/20 25000/25000 - 5s - loss: 0.1520 - accuracy: 0.9752 - binary_crossentropy: 0.0793 - val_loss: 0.5456 - val_accuracy: 0.8568 - val_binary_crossentropy: 0.4734
l2(0.001) は層の重み行列の総ての係数が 0.001 * weight_coefficient_value**2 をネットワークの総計損失に追加することを意味します。このペナルティは訓練時のみに追加されますので、このネットワークに対する損失はテスト時よりも訓練時に遥かに高くなることに注意してください。
L2 正則化ペナルティのインパクトがここにあります :
plot_history([('baseline', baseline_history), ('l2', l2_model_history)])
見て取れるように、両者のモデルが同じパラメータ数を持つ場合でさえも、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='relu', input_shape=(NUM_WORDS,)), keras.layers.Dropout(0.5), keras.layers.Dense(16, activation='relu'), keras.layers.Dropout(0.5), keras.layers.Dense(1, activation='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 25000/25000 - 5s - loss: 0.6143 - accuracy: 0.6682 - binary_crossentropy: 0.6143 - val_loss: 0.4819 - val_accuracy: 0.8586 - val_binary_crossentropy: 0.4819 Epoch 2/20 25000/25000 - 4s - loss: 0.4486 - accuracy: 0.8210 - binary_crossentropy: 0.4486 - val_loss: 0.3502 - val_accuracy: 0.8823 - val_binary_crossentropy: 0.3502 Epoch 3/20 25000/25000 - 4s - loss: 0.3543 - accuracy: 0.8742 - binary_crossentropy: 0.3543 - val_loss: 0.3037 - val_accuracy: 0.8895 - val_binary_crossentropy: 0.3037 Epoch 4/20 25000/25000 - 4s - loss: 0.2968 - accuracy: 0.9008 - binary_crossentropy: 0.2968 - val_loss: 0.2826 - val_accuracy: 0.8897 - val_binary_crossentropy: 0.2826 Epoch 5/20 25000/25000 - 4s - loss: 0.2510 - accuracy: 0.9173 - binary_crossentropy: 0.2510 - val_loss: 0.2767 - val_accuracy: 0.8884 - val_binary_crossentropy: 0.2767 Epoch 6/20 25000/25000 - 4s - loss: 0.2200 - accuracy: 0.9300 - binary_crossentropy: 0.2200 - val_loss: 0.2909 - val_accuracy: 0.8857 - val_binary_crossentropy: 0.2909 Epoch 7/20 25000/25000 - 4s - loss: 0.1907 - accuracy: 0.9376 - binary_crossentropy: 0.1907 - val_loss: 0.2935 - val_accuracy: 0.8847 - val_binary_crossentropy: 0.2935 Epoch 8/20 25000/25000 - 4s - loss: 0.1705 - accuracy: 0.9476 - binary_crossentropy: 0.1705 - val_loss: 0.3140 - val_accuracy: 0.8850 - val_binary_crossentropy: 0.3140 Epoch 9/20 25000/25000 - 4s - loss: 0.1468 - accuracy: 0.9536 - binary_crossentropy: 0.1468 - val_loss: 0.3418 - val_accuracy: 0.8811 - val_binary_crossentropy: 0.3418 Epoch 10/20 25000/25000 - 5s - loss: 0.1313 - accuracy: 0.9598 - binary_crossentropy: 0.1313 - val_loss: 0.3731 - val_accuracy: 0.8803 - val_binary_crossentropy: 0.3731 Epoch 11/20 25000/25000 - 4s - loss: 0.1218 - accuracy: 0.9629 - binary_crossentropy: 0.1218 - val_loss: 0.3755 - val_accuracy: 0.8796 - val_binary_crossentropy: 0.3755 Epoch 12/20 25000/25000 - 4s - loss: 0.1102 - accuracy: 0.9656 - binary_crossentropy: 0.1102 - val_loss: 0.3962 - val_accuracy: 0.8792 - val_binary_crossentropy: 0.3962 Epoch 13/20 25000/25000 - 4s - loss: 0.1022 - accuracy: 0.9681 - binary_crossentropy: 0.1022 - val_loss: 0.4369 - val_accuracy: 0.8790 - val_binary_crossentropy: 0.4369 Epoch 14/20 25000/25000 - 5s - loss: 0.0931 - accuracy: 0.9702 - binary_crossentropy: 0.0931 - val_loss: 0.4528 - val_accuracy: 0.8778 - val_binary_crossentropy: 0.4528 Epoch 15/20 25000/25000 - 4s - loss: 0.0886 - accuracy: 0.9726 - binary_crossentropy: 0.0886 - val_loss: 0.4817 - val_accuracy: 0.8754 - val_binary_crossentropy: 0.4817 Epoch 16/20 25000/25000 - 4s - loss: 0.0808 - accuracy: 0.9745 - binary_crossentropy: 0.0808 - val_loss: 0.4971 - val_accuracy: 0.8745 - val_binary_crossentropy: 0.4971 Epoch 17/20 25000/25000 - 4s - loss: 0.0758 - accuracy: 0.9745 - binary_crossentropy: 0.0758 - val_loss: 0.4992 - val_accuracy: 0.8746 - val_binary_crossentropy: 0.4992 Epoch 18/20 25000/25000 - 4s - loss: 0.0720 - accuracy: 0.9762 - binary_crossentropy: 0.0720 - val_loss: 0.5373 - val_accuracy: 0.8756 - val_binary_crossentropy: 0.5373 Epoch 19/20 25000/25000 - 4s - loss: 0.0709 - accuracy: 0.9768 - binary_crossentropy: 0.0709 - val_loss: 0.5491 - val_accuracy: 0.8744 - val_binary_crossentropy: 0.5491 Epoch 20/20 25000/25000 - 4s - loss: 0.0663 - accuracy: 0.9783 - binary_crossentropy: 0.0663 - val_loss: 0.5506 - val_accuracy: 0.8740 - val_binary_crossentropy: 0.5506
plot_history([('baseline', baseline_history), ('dropout', dpt_model_history)])
dropout の追加はベースライン・モデルを超える明確な改良です。
復習のために: ここにニューラルネットワークで overfitting を回避するための最も一般的な方法があります :
- より多くの訓練データを得る。
- ネットワークの capcity を減じる。
- 重み正則を追加する。
- dropout を追加する。
そしてこのガイドでカバーされていない 2 つの重要なアプローチはデータ増強とバッチ正規化です。
以上