[[333587]] 重み制約は、ディープラーニング ニューラル ネットワーク モデルのトレーニング データへの過剰適合を減らし、新しいデータ (テスト セットなど) に対するモデルのパフォーマンスを向上させる方法を提供します。重み制約には、最大値や単位ベクトルノルムなどさまざまな種類があり、ハイパーパラメータを設定する必要があるものもあります。 このチュートリアルでは、オーバーフィッティングを減らすためにディープラーニング ニューラル ネットワーク モデルに重み制約を追加するための Keras API について説明します。 このチュートリアルを完了すると、次のことが分かります。 - Keras API を使用してベクトルノルム制約を作成する方法。
- Keras API を使用して MLP、CNN、および RNN レイヤーに重み制約を追加する方法。
- 既存のモデルに重み制約を追加して過剰適合を減らす方法。
チュートリアルの概要 このチュートリアルは、次の 3 つの部分に分かれています。 - Keras における重量制約
- レイヤーの重量制限
- 重量制限のケーススタディ
Keras における重量制約 Keras API は重量制限をサポートしています。制約はレイヤーごとに指定されますが、レイヤー内のノードごとに適用および強制されます。 制約を使用するには、通常、入力重みのレイヤーに kernel_constraint パラメータを設定し、バイアス重みのbias_constraint を設定する必要があります。 通常、重み制約はバイアス重みには使用されません。さまざまなベクトルノルムのセットを制約として使用でき、keras.constraints モジュールのクラスとして提供されます。彼らです: - 最大ノルム (max_norm)。重みを指定された制限値以下になるように強制するために使用されます。
- 非負ノルム (non_neg) は、重みに正の値を強制します。
- 単位ノルム (unit_norm) は、重みを 1.0 に強制します。
- 最小最大ノルム (min_max_norm) は、重みを一定の範囲内に強制するために使用されます。
たとえば、単純な制約は次のように導入してインスタンス化できます。 - # インポート基準
- keras.constraintsからmax_normをインポートする
- # 規範をインスタンス化する
- ノルム=最大ノルム(3.0)
- # インポート基準
- keras.constraintsからmax_normをインポートする
- # 規範をインスタンス化する
- ノルム=最大ノルム(3.0)
レイヤーの重量制限 重みノルムは、Keras のほとんどのレイヤーで使用できます。このセクションでは、いくつかの一般的な例を見ていきます。 MLP 重み付け制約 次の例では、密な完全接続層に最大ノルム重み制約を設定します。 - # 密な層における最大ノルムの例
- keras.layersからDenseをインポート
- keras.constraintsからmax_normをインポートする
- ...
- モデルを追加します(密度(32、カーネル制約= max_norm (3)、バイアス制約== max_norm(3)))
- ...
- # 密な層における最大ノルムの例
- keras.layersからDenseをインポート
- keras.constraintsからmax_normをインポートする
- ...
- モデルを追加します(密度(32、カーネル制約= max_norm (3)、バイアス制約== max_norm(3)))
- ...
CNN 重み付け制約 次の例では、畳み込み層に最大ノルム重み制約を設定します。 - # CNN レイヤーの最大ノルムの例
- keras.layersからConv2Dをインポートする
- keras.constraintsからmax_normをインポートする
- ...
- モデルを追加します(Conv2D(32, (3,3), kernel_constraint = max_norm (3), bias_constraint == max_norm(3)))
- ...
RNN 重み制約 他のレイヤー タイプとは異なり、再帰型ニューラル ネットワークでは、再帰型入力重みだけでなく、入力重みとバイアスにも重み制約を設定できます。繰り返される重みの制約は、レイヤーの recurrent_constraint パラメータによって設定されます。次の例では、LSTM レイヤーに最大ノルム重み制約を設定します。 - # lstm レイヤーの最大ノルムの例
- keras.layersからLSTMをインポートする
- keras.constraintsからmax_normをインポートする
- ...
- モデルを追加します(LSTM(32、カーネル制約= max_norm (3)、リカレント制約= max_norm (3)、バイアス制約== max_norm(3)))
- ...
- # lstm レイヤーの最大ノルムの例
- keras.layersからLSTMをインポートする
- keras.constraintsからmax_normをインポートする
- ...
- モデルを追加します(LSTM(32、カーネル制約= max_norm (3)、リカレント制約= max_norm (3)、バイアス制約== max_norm(3)))
- ...
重量制約 API の使い方がわかったので、実際の例を見てみましょう。 重み付け制約のケーススタディ このセクションでは、重み制約を使用して、単純なバイナリ分類問題に対する MLP の過剰適合を減らす方法を説明します。この例では、分類および回帰問題のために独自のニューラル ネットワークに重み制約を適用するためのテンプレートを提供します。 バイナリ分類問題 標準的なバイナリ分類問題を使用して、各クラスに 1 つずつ、半円のデータセットを 2 つ定義します。各観測には、等しいスケールと 0 または 1 のクラス出力値を持つ 2 つの入力変数があります。このデータセットは、プロットされたときに各クラスの観測の形状から、「月」データセットと呼ばれます。 make_moons() 関数を使用して、この問題から観測結果を生成できます。コードを実行するたびに同じサンプルが生成されるように、データにノイズを追加し、乱数ジェネレーターをシードします。 - # 2D分類データセットを生成する
- X, y = make_moons ( n_samples = 100 、ノイズ= 0.2 、ランダム状態= 1 )
2 つの変数を x 座標と y 座標としてグラフ上のデータセットとしてプロットし、クラス値を観測値の色としてプロットできます。データセットを生成してプロットする完全な例を以下に示します。 - # 2つの月のデータセットを生成する
- sklearn.datasets から make_moons をインポートします
- matplotlibからpyplotをインポートする
- pandasからDataFrameをインポートする
- # 2D分類データセットを生成する
- X, y = make_moons ( n_samples = 100 、ノイズ= 0.2 、ランダム状態= 1 )
- # 散布図、クラス値によって色分けされた点
- df = DataFrame (dict( x = X [:,0], y = X [:,1],ラベル= y ))
- 色= {0:'赤', 1:'青'}
- 図、 ax = pyplot.subplots ()
- グループ化= df .groupby('label')
- キーの場合、グループ化されたグループ:
- group.plot( ax ax =ax、 kind = 'scatter' 、 x = 'x' 、 y = 'y' 、 label = key 、 color = colors [key])
- pyplot.show()
- # 2つの月のデータセットを生成する
- sklearn.datasets から make_moons をインポートします
- matplotlibからpyplotをインポートする
- pandasからDataFrameをインポートする
- # 2D分類データセットを生成する
- X, y = make_moons ( n_samples = 100 、ノイズ= 0.2 、ランダム状態= 1 )
- # 散布図、クラス値によって色分けされた点
- df = DataFrame (dict( x = X [:,0], y = X [:,1],ラベル= y ))
- 色= {0:'赤', 1:'青'}
- 図、 ax = pyplot.subplots ()
- グループ化= df .groupby('label')
- キーの場合、グループ化されたグループ:
- group.plot( ax ax =ax、 kind = 'scatter' 、 x = 'x' 、 y = 'y' 、 label = key 、 color = colors [key])
- pyplot.show()
例を実行すると、各クラスの観測値の半円または月形を示す散布図が作成されます。点の散乱によるノイズにより衛星が見えにくくなっていることがわかります。 これは、クラスを 1 本の線で分離できない (つまり線形に分離できない) ため、解決するにはニューラル ネットワークなどの非線形手法が必要となるため、優れたテスト問題です。生成したサンプルは 100 個だけで、これはニューラル ネットワークとしては小さいため、トレーニング データセットに過剰適合し、テスト データセットでエラーが高くなる可能性があります。これは、正規化を使用する良い例です。さらに、サンプルにはノイズが含まれているため、モデルは矛盾したサンプルの側面を学習する機会が得られます。 多層パーセプトロンの重ね合わせ このバイナリ分類問題を解決するために MLP モデルを開発できます。モデルには、問題を解決するために必要以上のノードを持つ隠し層が含まれるため、過剰適合が発生する可能性があります。また、モデルの堅牢性を確保するために、必要以上に長くモデルをトレーニングします。モデルを定義する前に、データセットをトレーニング セットとテスト セットに分割し、30 個の例を使用してモデルをトレーニングし、70 個の例を使用して適合モデルのパフォーマンスを評価します。 - X, y = make_moons ( n_samples = 100 、ノイズ= 0.2 、ランダム状態= 1 )
- # トレーニングとテストに分割
- n_train = 30
- 訓練X、テストX = X[:n_train、:]、X[n_train:、:]
- 訓練された、テストされた= y[:n_train]、y[n_train:]
次に、モデルを定義します。隠し層では、隠し層内の 500 個のノードと正規化された線形活性化関数を使用します。出力層ではシグモイド活性化関数を使用して、クラス値 0 または 1 を予測します。このモデルは、バイナリ分類問題に適したバイナリクロスエントロピー損失関数と効率的な Adam バージョンの勾配降下法を使用して最適化されています。 - # モデルを定義する
- モデル=シーケンシャル()
- model.add(Dense(500, input_dim = 2 , activation = 'relu' ))を追加
- model.add(Dense(1, activation = 'sigmoid' ))
- model.compile(損失= 'binary_crossentropy' 、オプティマイザー= 'adam' 、メトリック= ['accuracy'])
定義されたモデルは、デフォルトのバッチ サイズ 32 で 4,000 個のトレーニング データ ポイントに適合されます。テスト データセットを検証データセットとしても使用します。 - # 適合モデル
- history = model .fit(trainX, trainy, validation_data =(testX, testy),エポック= 4000 , verbose = 0 )
テスト データセットでモデルのパフォーマンスを評価し、結果を報告できます。 - # モデルを評価する
- _, train_acc =モデル.evaluate(trainX, trainy, verbose = 0 )
- _, test_acc =モデル.evaluate(testX, testy, verbose = 0 )
- print('トレーニング: %.3f、テスト: %.3f' % (train_acc, test_acc))
最後に、各エポックでのトレーニング セットとテスト セットのモデルのパフォーマンスをプロットします。モデルが実際にトレーニング データセットに過剰適合している場合、モデルがトレーニング データセット内の統計的ノイズを学習するにつれて、トレーニング セットの精度の折れ線グラフは増加し続け、テスト セットは上昇してから再び低下することが予想されます。 - # プロット履歴
- pyplot.plot(history.history['acc'],ラベル= 'train' )
- pyplot.plot(history.history['val_acc'],ラベル= 'test' )
- pyplot.凡例()
- pyplot.show()
これらすべてを組み合わせると、完全な例が下記に示されます。 - # 月データセットの MLP オーバーフィット
- sklearn.datasets から make_moons をインポートします
- keras.layersからDenseをインポート
- keras.modelsからSequentialをインポートする
- matplotlibからpyplotをインポートする
- # 2D分類データセットを生成する
- X, y = make_moons ( n_samples = 100 、ノイズ= 0.2 、ランダム状態= 1 )
- # トレーニングとテストに分割
- n_train = 30
- 訓練X、テストX = X[:n_train、:]、X[n_train:、:]
- 訓練された、テストされた= y[:n_train]、y[n_train:]
- # モデルを定義する
- モデル=シーケンシャル()
- model.add(Dense(500, input_dim = 2 , activation = 'relu' ))を追加
- model.add(Dense(1, activation = 'sigmoid' ))
- model.compile(損失= 'binary_crossentropy' 、オプティマイザー= 'adam' 、メトリック= ['accuracy'])
- # 適合モデル
- history = model .fit(trainX, trainy, validation_data =(testX, testy),エポック= 4000 , verbose = 0 )
- # モデルを評価する
- _, train_acc =モデル.evaluate(trainX, trainy, verbose = 0 )
- _, test_acc =モデル.evaluate(testX, testy, verbose = 0 )
- print('トレーニング: %.3f、テスト: %.3f' % (train_acc, test_acc))
- # プロット履歴
- pyplot.plot(history.history['acc'],ラベル= 'train' )
- pyplot.plot(history.history['val_acc'],ラベル= 'test' )
- pyplot.凡例()
- pyplot.show()
例を実行すると、トレーニング データセットとテスト データセットでのモデルのパフォーマンスが報告されます。モデルはテスト データセットよりもトレーニング データセットで優れたパフォーマンスを発揮することがわかります。これは、過剰適合の兆候である可能性があります。ニューラル ネットワークとトレーニング アルゴリズムの確率的な性質を考慮すると、結果は異なる場合があります。モデルは過剰適合されているため、通常、同じデータセットでモデルを繰り返し実行しても、精度に大きな違いが出ることはほとんど予想されません。 - トレーニング: 1.000、テスト: 0.914
トレーニング セットとテスト セットのモデル精度のグラフを示すプロットを作成します。過剰適合モデルの予想される形状を確認できます。テスト精度は、ある時点まで増加し、その後再び減少し始めます。 重み付け制約によるオーバーフィット MLP 重量制約を使用するように例を更新できます。さまざまな加重制限から選択できます。このモデルの優れた単純な制約は、ノルムが 1.0 になるように重みを単純に正規化することです。この制約は、すべての入力重みを強制的に小さくする効果があります。 Keras の unit_norm を使用することでこれを実行できます。この制約は、次のように最初の隠し層に追加できます。 - model.add(Dense(500, input_dim = 2 , activation = 'relu' , kernel_constraint = unit_norm ()))
min_max_norm を使用して、最小値と最大値を 1.0 に設定することでも同じ結果を得ることができます。次に例を示します。 - model.add(Dense(500, input_dim = 2 , activation = 'relu' , kernel_constraint = min_max_norm ( min_value = 1.0 , max_value = 1.0 )))
最大ノルム制約では、ノルムが指定された制限以下になることが許可されるため、同じ結果を達成することはできません。例: - model.add(Dense(500, input_dim = 2 , activation = 'relu' , kernel_constraint = max_norm (1.0)))
ユニット指定制約を含む完全な更新例を以下に示します。 - # 単位ノルム制約による月データセットの MLP オーバーフィット
- sklearn.datasets から make_moons をインポートします
- keras.layersからDenseをインポート
- keras.modelsからSequentialをインポートする
- keras.constraintsからunit_normをインポートする
- matplotlibからpyplotをインポートする
- # 2D分類データセットを生成する
- X, y = make_moons ( n_samples = 100 、ノイズ= 0.2 、ランダム状態= 1 )
- # トレーニングとテストに分割
- n_train = 30
- 訓練X、テストX = X[:n_train、:]、X[n_train:、:]
- 訓練された、テストされた= y[:n_train]、y[n_train:]
- # モデルを定義する
- モデル=シーケンシャル()
- model.add(Dense(500, input_dim = 2 , activation = 'relu' , kernel_constraint = unit_norm ()))
- model.add(Dense(1, activation = 'sigmoid' ))
- model.compile(損失= 'binary_crossentropy' 、オプティマイザー= 'adam' 、メトリック= ['accuracy'])
- # 適合モデル
- history = model .fit(trainX, trainy, validation_data =(testX, testy),エポック= 4000 , verbose = 0 )
- # モデルを評価する
- _, train_acc =モデル.evaluate(trainX, trainy, verbose = 0 )
- _, test_acc =モデル.evaluate(testX, testy, verbose = 0 )
- print('トレーニング: %.3f、テスト: %.3f' % (train_acc, test_acc))
- # プロット履歴
- pyplot.plot(history.history['acc'],ラベル= 'train' )
- pyplot.plot(history.history['val_acc'],ラベル= 'test' )
- pyplot.凡例()
- pyplot.show()
例を実行すると、トレーニング データセットとテスト データセットでのモデルのパフォーマンスが報告されます。重みのサイズに厳しい制限を設けることで、トレーニング セットのパフォーマンスに影響を与えることなく、テスト セットでのモデルのパフォーマンスが向上することがわかります。 - トレーニング: 1.000、テスト: 0.943
トレーニング セットとテスト精度の曲線を振り返ってみると、モデルがトレーニング データセットに過剰適合していることがわかります。トレーニング セットとテスト セットの両方のモデル精度は、安定するまで向上し続けています。 拡張機能 このセクションでは、チュートリアルを拡張するためのアイデアをいくつか紹介します。 - 重み付け基準を報告します。例を更新してネットワークの重みの大きさを計算し、制約によって実際に大きさが小さくなることを示します。
- 出力レイヤーを制約します。例を更新してモデルの出力層に制約を追加し、結果を比較します。
- 制約の逸脱。例を更新してバイアス重みに制約を追加し、結果を比較します。
- 繰り返し評価します。例を更新してモデルを複数回適合および評価し、モデルのパフォーマンスの平均と標準偏差を報告します。
|