深層学習ニューラル ネットワークをトレーニングする際の損失関数の選択方法
深層学習ニューラル ネットワークは、確率的勾配降下最適化アルゴリズムを使用してトレーニングされます。
最適化アルゴリズムの一部として、モデルの現在の状態の誤差を繰り返し推定する必要があります。これには、 次の評価で損失を減らすために重みを更新できるように、モデルの損失を推定するために使用できる誤差関数 ( 従来は損失関数 と呼ばれています) を選択する必要があります。
ニューラル ネットワーク モデルは、例からの入力から出力へのマッピングを学習し、損失関数の選択は、分類や回帰などの特定の予測モデリング問題の枠組みと一致する必要があります。さらに、出力層の構成も、選択した損失関数に適切でなければなりません。
このチュートリアルでは、特定の予測モデリング問題に対して深層学習ニューラル ネットワークの損失関数を選択する方法を学びます。
このチュートリアルを完了すると、次のことがわかります。
- 平均二乗誤差のモデルと回帰問題のバリアントを構成する方法。
- 二項分類用のクロスエントロピーおよびヒンジ損失関数のモデルを構成する方法。
- マルチクラス分類用のクロスエントロピーおよび KL 発散損失関数のモデルを構成する方法。
すべての例のステップバイステップのチュートリアルとPython ソース コードファイルを含む、私の新しい本『Better Deep Learning』 でプロジェクトを開始してください。 。
始めましょう。
- 2019 年 10 月更新: Keras 2.3 および TensorFlow 2.0 用に更新されました。
- 2020 年 1 月更新: scikit-learn v0.22 API の変更点を更新しました。
チュートリアルの概要
このチュートリアルは 3 つの部分に分かれています。彼らです:
回帰損失関数
- 平均二乗誤差損失
- 平均二乗対数誤差損失
- 平均絶対誤差損失
二項分類損失関数
- バイナリクロスエントロピー
マルチクラス分類損失関数
- マルチクラスのクロスエントロピー損失
さまざまな損失関数を選択して実装する方法に焦点を当てます。
損失関数の理論の詳細については、次の投稿を参照してください。
- 深層学習ニューラル ネットワークをトレーニングするための損失関数と損失関数
回帰損失関数
回帰予測モデリング問題には、実数値の量の予測が含まれます。
このセクションでは、回帰予測モデリング問題に適した損失関数を調査します。
この調査のコンテキストとして、make_regression() 関数の scikit-learn ライブラリによって提供される標準の回帰問題ジェネレーターを使用します。この関数は、指定された数の入力変数、統計ノイズ、およびその他のプロパティを使用した単純な回帰問題から例を生成します。
この関数を使用して、20 個の入力特徴がある問題を定義します。機能のうち 10 個は意味があり、10 個は関連性がありません。合計 1,000 個の例がランダムに生成されます。疑似乱数ジェネレーターは、コードが実行されるたびに同じ 1,000 個の例が確実に取得されるように修正されます。
# generate regression dataset
X, y = make_regression(n_samples=1000, n_features=20, noise=0.1, random_state=1)
一般に、ニューラル ネットワークは、実数値の入力変数と出力変数が適切な範囲にスケーリングされる場合にパフォーマンスが向上します。この問題では、入力変数とターゲット変数のそれぞれにガウス分布があります。したがって、この場合はデータを標準化することが望ましいです。
これは、scikit-learn ライブラリの StandardScaler トランスフォーマー クラスを使用して実現できます。実際の問題では、トレーニング データセットでスケーラーを準備し、それをトレーニング セットとテスト セットに適用しますが、簡単にするために、トレーニング セットとテスト セットに分割する前にすべてのデータをまとめてスケーリングします。
# standardize dataset
X = StandardScaler().fit_transform(X)
y = StandardScaler().fit_transform(y.reshape(len(y),1))[:,0]
スケーリングが完了すると、データはトレーニング セットとテスト セットに均等に分割されます。
# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
この問題に対処し、さまざまな損失関数を探索するための基礎を提供するために、小規模な多層パーセプトロン (MLP) モデルが定義されます。
モデルは、問題で定義されているように、入力として 20 個の特徴を想定します。モデルには 25 ノードを持つ 1 つの隠れ層があり、修正線形活性化関数 (ReLU) を使用します。出力層には 1 つのノードがあり、予測される 1 つの実数値が与えられ、線形活性化関数が使用されます。
# define model
model = Sequential()
model.add(Dense(25, input_dim=20, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(1, activation='linear'))
モデルは、学習率 0.01 と運動量 0.9 (どちらも適切なデフォルト値) の確率的勾配降下法で適合されます。
トレーニングは 100 エポックにわたって実行され、実行の終了時に学習曲線をプロットできるように、各エポックの終了時にテスト セットが評価されます。
opt = SGD(lr=0.01, momentum=0.9)
model.compile(loss='...', optimizer=opt)
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=100, verbose=0)
問題とモデルの基礎ができたので、回帰予測モデリング問題に適した 3 つの一般的な損失関数を評価してみましょう。
これらの例では MLP が使用されていますが、回帰用に CNN モデルと RNN モデルをトレーニングするときに同じ損失関数を使用できます。
平均二乗誤差損失
平均二乗誤差 (MSE) 損失は、回帰問題に使用するデフォルトの損失です。
数学的には、ターゲット変数の分布がガウス分布である場合、これは最尤推論フレームワークの下で好ましい損失関数です。これは損失関数であり、最初に評価され、正当な理由がある場合にのみ変更されます。
平均二乗誤差は、予測値と実際の値の間の二乗差の平均として計算されます。結果は、予測値と実際の値の符号に関係なく常に正であり、完全な値は 0.0 です。二乗は、大きな間違いが小さな間違いよりも多くのエラーを引き起こすことを意味し、モデルが大きな間違いを犯した場合に罰せられることを意味します。
平均二乗誤差損失関数は、モデルのコンパイル時に損失関数として ‘mse’ または ‘mean_squared_error’ を指定することで Keras で使用できます。
model.compile(loss='mean_squared_error')
出力層にはターゲット変数に対して 1 つのノードがあり、線形活性化関数が使用されることが推奨されます。
model.add(Dense(1, activation='linear'))
説明した回帰問題に関する MLP を実証する完全な例を以下に示します。
# mlp for regression with mse loss function
from sklearn.datasets import make_regression
from sklearn.preprocessing import StandardScaler
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import SGD
from matplotlib import pyplot
# generate regression dataset
X, y = make_regression(n_samples=1000, n_features=20, noise=0.1, random_state=1)
# standardize dataset
X = StandardScaler().fit_transform(X)
y = StandardScaler().fit_transform(y.reshape(len(y),1))[:,0]
# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# define model
model = Sequential()
model.add(Dense(25, input_dim=20, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(1, activation='linear'))
opt = SGD(lr=0.01, momentum=0.9)
model.compile(loss='mean_squared_error', optimizer=opt)
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=100, verbose=0)
# evaluate the model
train_mse = model.evaluate(trainX, trainy, verbose=0)
test_mse = model.evaluate(testX, testy, verbose=0)
print('Train: %.3f, Test: %.3f' % (train_mse, test_mse))
# plot loss during training
pyplot.title('Loss / Mean Squared Error')
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='test')
pyplot.legend()
pyplot.show()
この例を実行すると、まずトレーニング データセットとテスト データセット上のモデルの平均二乗誤差が出力されます。
注: アルゴリズムや評価手順の確率的性質、または数値精度の違いにより、結果が異なる場合があります。例を数回実行して、平均結果を比較することを検討してください。
この場合、モデルが問題を学習して、少なくとも小数点以下 3 桁まで誤差ゼロを達成していることがわかります。
Train: 0.000, Test: 0.001
トレーニング (青) セットとテスト (オレンジ) セットの両方のトレーニング エポックにわたる平均二乗誤差損失を示す折れ線プロットも作成されます。
モデルがかなり早く収束し、トレーニングとテストの両方のパフォーマンスが同等のままであることがわかります。モデルのパフォーマンスと収束動作は、平均二乗誤差がこの問題を学習するニューラル ネットワークに適していることを示唆しています。
平均二乗対数誤差損失
ターゲット値に値の広がりがある回帰問題が発生する可能性があり、大きな値を予測する場合は、平均二乗誤差ほどモデルを厳しく罰したくない場合があります。
代わりに、まず各予測値の自然対数を計算し、次に平均二乗誤差を計算します。これは、平均二乗対数誤差損失 (略して MSLE) と呼ばれます。
大きな予測値の差が大きい場合の罰則を緩和する効果があります。
損失の尺度としては、モデルがスケーリングされていない量を直接予測する場合に適している可能性があります。それにもかかわらず、単純な回帰問題を使用してこの損失関数を実証することができます。
モデルを更新して、「mean_squared_logarithmic_error」損失関数を使用し、出力層に対して同じ構成を維持することができます。また、モデルをフィッティングするときに平均二乗誤差を指標として追跡し、それをパフォーマンスの尺度として使用し、学習曲線をプロットできるようにします。
model.compile(loss='mean_squared_logarithmic_error', optimizer=opt, metrics=['mse'])
MSLE 損失関数の完全な使用例を以下に示します。
# mlp for regression with msle loss function
from sklearn.datasets import make_regression
from sklearn.preprocessing import StandardScaler
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import SGD
from matplotlib import pyplot
# generate regression dataset
X, y = make_regression(n_samples=1000, n_features=20, noise=0.1, random_state=1)
# standardize dataset
X = StandardScaler().fit_transform(X)
y = StandardScaler().fit_transform(y.reshape(len(y),1))[:,0]
# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# define model
model = Sequential()
model.add(Dense(25, input_dim=20, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(1, activation='linear'))
opt = SGD(lr=0.01, momentum=0.9)
model.compile(loss='mean_squared_logarithmic_error', optimizer=opt, metrics=['mse'])
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=100, verbose=0)
# evaluate the model
_, train_mse = model.evaluate(trainX, trainy, verbose=0)
_, test_mse = model.evaluate(testX, testy, verbose=0)
print('Train: %.3f, Test: %.3f' % (train_mse, test_mse))
# plot loss during training
pyplot.subplot(211)
pyplot.title('Loss')
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='test')
pyplot.legend()
# plot mse during training
pyplot.subplot(212)
pyplot.title('Mean Squared Error')
pyplot.plot(history.history['mean_squared_error'], label='train')
pyplot.plot(history.history['val_mean_squared_error'], label='test')
pyplot.legend()
pyplot.show()
この例を実行すると、まずトレーニングおよびテスト データセット上のモデルの平均二乗誤差が出力されます。
注: アルゴリズムや評価手順の確率的性質、または数値精度の違いにより、結果が異なる場合があります。例を数回実行して、平均結果を比較することを検討してください。
この場合、モデルの結果、トレーニング データセットとテスト データセットの両方で MSE がわずかに悪化したことがわかります。ターゲット変数の分布は標準ガウス分布であるため、この問題には適切ではない可能性があります。
Train: 0.165, Test: 0.184
また、トレーニング (青) セットとテスト (オレンジ) セットの両方のトレーニング エポックにわたる平均二乗対数誤差損失を示す折れ線プロット (上) と、平均二乗誤差の同様のプロット (下) も作成されます。
MSLE が 100 エポック アルゴリズムを超えて収束したことがわかります。 MSE は問題の過剰適合の兆候を示している可能性があり、急速に低下し、エポック 20 以降上昇し始めているようです。
平均絶対誤差損失
一部の回帰問題では、ターゲット変数の分布はほとんどがガウス分布ですが、外れ値が含まれる場合があります。平均値からかけ離れた大きな値または小さな値。
平均絶対誤差 (MAE) 損失は、外れ値に対してより堅牢であるため、この場合に適切な損失関数です。これは、実際の値と予測値の間の絶対差の平均として計算されます。
モデルは、「mean_absolute_error」損失関数を使用し、出力層に対して同じ構成を維持するように更新できます。
model.compile(loss='mean_absolute_error', optimizer=opt, metrics=['mse'])
回帰テスト問題の損失関数として平均絶対誤差を使用する完全な例を以下に示します。
# mlp for regression with mae loss function
from sklearn.datasets import make_regression
from sklearn.preprocessing import StandardScaler
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import SGD
from matplotlib import pyplot
# generate regression dataset
X, y = make_regression(n_samples=1000, n_features=20, noise=0.1, random_state=1)
# standardize dataset
X = StandardScaler().fit_transform(X)
y = StandardScaler().fit_transform(y.reshape(len(y),1))[:,0]
# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# define model
model = Sequential()
model.add(Dense(25, input_dim=20, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(1, activation='linear'))
opt = SGD(lr=0.01, momentum=0.9)
model.compile(loss='mean_absolute_error', optimizer=opt, metrics=['mse'])
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=100, verbose=0)
# evaluate the model
_, train_mse = model.evaluate(trainX, trainy, verbose=0)
_, test_mse = model.evaluate(testX, testy, verbose=0)
print('Train: %.3f, Test: %.3f' % (train_mse, test_mse))
# plot loss during training
pyplot.subplot(211)
pyplot.title('Loss')
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='test')
pyplot.legend()
# plot mse during training
pyplot.subplot(212)
pyplot.title('Mean Squared Error')
pyplot.plot(history.history['mean_squared_error'], label='train')
pyplot.plot(history.history['val_mean_squared_error'], label='test')
pyplot.legend()
pyplot.show()
この例を実行すると、まずトレーニングおよびテスト データセット上のモデルの平均二乗誤差が出力されます。
注: アルゴリズムや評価手順の確率的性質、または数値精度の違いにより、結果が異なる場合があります。例を数回実行して、平均結果を比較することを検討してください。
この場合、モデルが問題を学習し、少なくとも小数点以下 3 桁までほぼゼロの誤差を達成したことがわかります。
Train: 0.002, Test: 0.002
また、トレーニング (青) セットとテスト (オレンジ) セットの両方のトレーニング エポックにわたる平均絶対誤差損失 (上) と、平均二乗誤差の同様のプロット (下) を示す折れ線プロットも作成されます。
この場合、MSE のダイナミクスは大きな影響を受けていないように見えますが、MAE は収束しますが、でこぼこしたコースを示していることがわかります。ターゲット変数は大きな外れ値のない標準ガウスであることがわかっているため、この場合 MAE は適切ではありません。
最初にターゲット変数をスケーリングしなかった方が、この問題に対してより適切になる可能性があります。
二項分類損失関数
二項分類は、例に 2 つのラベルのいずれかが割り当てられる予測モデリング問題です。
この問題は、多くの場合、最初または 2 番目のクラスの値 0 または 1 を予測するものとして組み立てられ、例がクラス値 1 に属する確率を予測するものとして実装されます。
このセクションでは、二項分類予測モデリング問題に適した損失関数を調査します。
この調査の基礎として、scikit-learn のサークル テスト問題からサンプルを生成します。円の問題には、2 次元平面上の 2 つの同心円から抽出されたサンプルが含まれます。外側の円の点はクラス 0 に属し、内側の円の点はクラス 1 に属します。統計ノイズがサンプルに追加されて、曖昧さが追加され、この問題は学ぶのがより困難です。
1,000 個の例を生成し、10% の統計ノイズを追加します。疑似乱数ジェネレーターには同じ値がシードされ、常に同じ 1,000 個の例が得られるようにします。
# generate circles
X, y = make_circles(n_samples=1000, noise=0.1, random_state=1)
データセットの散布図を作成して、モデル化している問題を把握することができます。完全な例を以下に示します。
# scatter plot of the circles dataset with points colored by class
from sklearn.datasets import make_circles
from numpy import where
from matplotlib import pyplot
# generate circles
X, y = make_circles(n_samples=1000, noise=0.1, random_state=1)
# select indices of points with each class label
for i in range(2):
samples_ix = where(y == i)
pyplot.scatter(X[samples_ix, 0], X[samples_ix, 1], label=str(i))
pyplot.legend()
pyplot.show()
例を実行すると、例の散布図が作成されます。ここで、入力変数は点の位置を定義し、クラス値は色を定義します (クラス 0 は青、クラス 1 はオレンジ)。
ポイントはすでに 0 付近でほぼ [-1,1] の範囲内で適切にスケールされています。この場合、それらを再スケーリングしません。
データセットは、トレーニング セットとテスト セットに均等に分割されます。
# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
この問題に対処するために、データセット内の 2 つの特徴に対する 2 つの入力、50 ノードの隠れ層、修正された線形活性化関数、および損失の選択用に構成する必要がある出力層を期待する単純な MLP モデルを定義できます。関数。
# define model
model = Sequential()
model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(1, activation='...'))
モデルは、確率的勾配降下法を使用し、実用的なデフォルト学習率 0.01 と運動量 0.9 で適合されます。
opt = SGD(lr=0.01, momentum=0.9)
model.compile(loss='...', optimizer=opt, metrics=['accuracy'])
学習曲線をプロットできるように、モデルを 200 のトレーニング エポックに適合させ、各エポックの終了時に損失と精度に対してモデルのパフォーマンスを評価します。
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=200, verbose=0)
問題とモデルの基礎ができたので、バイナリ分類予測モデリング問題に適した 3 つの一般的な損失関数を評価してみましょう。
これらの例では MLP が使用されていますが、二項分類用に CNN モデルと RNN モデルをトレーニングするときに同じ損失関数を使用できます。
バイナリクロスエントロピー損失
クロスエントロピーは、バイナリ分類問題に使用するデフォルトの損失関数です。
これは、ターゲット値がセット {0, 1} に含まれるバイナリ分類で使用することを目的としています。
数学的には、これは最尤の推論フレームワークの下で好ましい損失関数です。これは損失関数であり、最初に評価され、正当な理由がある場合にのみ変更されます。
クロス エントロピーは、クラス 1 を予測するための実際の確率分布と予測された確率分布の間の平均差を要約するスコアを計算します。スコアは最小化され、完全なクロス エントロピー値は 0 になります。
クロスエントロピーは、モデルのコンパイル時に ‘binary_crossentropy’ を指定することで、Keras の損失関数として指定できます。
model.compile(loss='binary_crossentropy', optimizer=opt, metrics=['accuracy'])
この関数では、クラス 1 の確率を予測するために、出力層が単一ノードと「シグモイド」アクティベーションで構成されている必要があります。
model.add(Dense(1, activation='sigmoid'))
2 つの円のバイナリ分類問題に対するクロス エントロピー損失を伴う MLP の完全な例を以下に示します。
# mlp for the circles problem with cross entropy loss
from sklearn.datasets import make_circles
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import SGD
from matplotlib import pyplot
# generate 2d classification dataset
X, y = make_circles(n_samples=1000, noise=0.1, random_state=1)
# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# define model
model = Sequential()
model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(1, activation='sigmoid'))
opt = SGD(lr=0.01, momentum=0.9)
model.compile(loss='binary_crossentropy', optimizer=opt, metrics=['accuracy'])
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=200, verbose=0)
# evaluate the model
_, train_acc = model.evaluate(trainX, trainy, verbose=0)
_, test_acc = model.evaluate(testX, testy, verbose=0)
print('Train: %.3f, Test: %.3f' % (train_acc, test_acc))
# plot loss during training
pyplot.subplot(211)
pyplot.title('Loss')
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='test')
pyplot.legend()
# plot accuracy during training
pyplot.subplot(212)
pyplot.title('Accuracy')
pyplot.plot(history.history['accuracy'], label='train')
pyplot.plot(history.history['val_accuracy'], label='test')
pyplot.legend()
pyplot.show()
この例を実行すると、まずトレーニングおよびテスト データセット上のモデルの分類精度が出力されます。
注: アルゴリズムや評価手順の確率的性質、または数値精度の違いにより、結果が異なる場合があります。例を数回実行して、平均結果を比較することを検討してください。
この場合、モデルが問題をかなりうまく学習し、トレーニング データセットで約 83%、テスト データセットで約 85% の精度を達成したことがわかります。スコアはかなり近いので、モデルがおそらく過大または過小適合ではないことを示唆しています。
Train: 0.836, Test: 0.852
また、2 つの折れ線プロットを示す図も作成されます。上のプロットはトレーニング (青) とテスト (オレンジ) データセットのエポックにわたるクロスエントロピー損失を示し、下のプロットはエポックにわたる分類精度を示します。
プロットは、トレーニング プロセスが適切に収束したことを示しています。損失のプロットは、確率分布間の誤差が連続的な性質を持っているため滑らかですが、精度の線プロットは凹凸を示しています。トレーニングおよびテスト セット内の例が与えられた場合、最終的には正しいか間違っているかを予測することしかできず、粒度の低いフィードバックが提供されます。パフォーマンスについて。
ヒンジの損失
バイナリ分類問題に対するクロス エントロピーの代替手段は、主にサポート ベクター マシン (SVM) モデルで使用するために開発されたヒンジ損失関数です。
これは、ターゲット値がセット {-1, 1} に含まれるバイナリ分類で使用することを目的としています。
ヒンジ損失関数は、サンプルが正しい符号を持つように促し、実際のクラス値と予測されたクラス値の間で符号に違いがある場合には、より多くの誤差を割り当てます。
ヒンジ損失によるパフォーマンスのレポートはまちまちであり、バイナリ分類問題ではクロス エントロピーよりも優れたパフォーマンスが得られる場合があります。
まず、セット {-1, 1} 内の値を持つようにターゲット変数を変更する必要があります。
# change y from {0,1} to {-1,1}
y[where(y == 0)] = -1
ヒンジ損失関数は、コンパイル関数で ‘hinge’ として指定できます。
model.compile(loss='hinge', optimizer=opt, metrics=['accuracy'])
最後に、ネットワークの出力層は、範囲 [-1, 1] の単一値を出力できる双曲線正接活性化関数を備えた単一ノードを持つように構成する必要があります。
model.add(Dense(1, activation='tanh'))
2 つの円の二値分類問題に対するヒンジ損失関数を備えた MLP の完全な例を以下に示します。
# mlp for the circles problem with hinge loss
from sklearn.datasets import make_circles
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import SGD
from matplotlib import pyplot
from numpy import where
# generate 2d classification dataset
X, y = make_circles(n_samples=1000, noise=0.1, random_state=1)
# change y from {0,1} to {-1,1}
y[where(y == 0)] = -1
# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# define model
model = Sequential()
model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(1, activation='tanh'))
opt = SGD(lr=0.01, momentum=0.9)
model.compile(loss='hinge', optimizer=opt, metrics=['accuracy'])
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=200, verbose=0)
# evaluate the model
_, train_acc = model.evaluate(trainX, trainy, verbose=0)
_, test_acc = model.evaluate(testX, testy, verbose=0)
print('Train: %.3f, Test: %.3f' % (train_acc, test_acc))
# plot loss during training
pyplot.subplot(211)
pyplot.title('Loss')
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='test')
pyplot.legend()
# plot accuracy during training
pyplot.subplot(212)
pyplot.title('Accuracy')
pyplot.plot(history.history['accuracy'], label='train')
pyplot.plot(history.history['val_accuracy'], label='test')
pyplot.legend()
pyplot.show()
この例を実行すると、まずトレーニングおよびテスト データセット上のモデルの分類精度が出力されます。
注: アルゴリズムや評価手順の確率的性質、または数値精度の違いにより、結果が異なる場合があります。例を数回実行して、平均結果を比較することを検討してください。
この場合、トレーニング セットとテスト セットでの精度が 80% 未満の選択されたモデル構成では、クロス エントロピーを使用した場合よりもわずかにパフォーマンスが低下することがわかります。
Train: 0.792, Test: 0.740
また、2 つの折れ線プロットを示す図も作成されます。上のプロットはトレイン (青) とテスト (オレンジ) データセットのエポックにわたるヒンジ損失を示し、下のプロットはエポックにわたる分類精度を示します。
ヒンジ損失のプロットは、モデルが収束し、両方のデータセットで妥当な損失があることを示しています。分類精度のプロットも、この問題に関して望ましいレベルよりも低いスキルレベルではあるものの、収束の兆候を示しています。
方形ヒンジ損失
ヒンジ損失関数には多くの拡張機能があり、多くの場合、SVM モデルでの調査の対象になります。
一般的な拡張機能は、スコア ヒンジ損失の 2 乗を単純に計算する 2 乗ヒンジ損失と呼ばれます。これには、誤差関数の表面を滑らかにし、数値的に扱いやすくする効果があります。
ヒンジ損失を使用すると、特定のバイナリ分類問題でパフォーマンスが向上する場合は、二乗ヒンジ損失が適切である可能性があります。
ヒンジ損失関数を使用する場合と同様に、セット {-1, 1} 内の値を持つようにターゲット変数を変更する必要があります。
# change y from {0,1} to {-1,1}
y[where(y == 0)] = -1
2 乗ヒンジ損失は、モデルを定義するときに compile() 関数で ‘squared_hinge’ として指定できます。
model.compile(loss='squared_hinge', optimizer=opt, metrics=['accuracy'])
最後に、出力層は、範囲 [-1, 1] の連続値を出力できる双曲線正接活性化関数を持つ単一ノードを使用する必要があります。
model.add(Dense(1, activation='tanh'))
2 つの円の二項分類問題に対する二乗ヒンジ損失関数を使用した MLP の完全な例を以下に示します。
# mlp for the circles problem with squared hinge loss
from sklearn.datasets import make_circles
from keras.models import Sequential
from keras.layers import Dense
from keras.optimizers import SGD
from matplotlib import pyplot
from numpy import where
# generate 2d classification dataset
X, y = make_circles(n_samples=1000, noise=0.1, random_state=1)
# change y from {0,1} to {-1,1}
y[where(y == 0)] = -1
# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# define model
model = Sequential()
model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(1, activation='tanh'))
opt = SGD(lr=0.01, momentum=0.9)
model.compile(loss='squared_hinge', optimizer=opt, metrics=['accuracy'])
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=200, verbose=0)
# evaluate the model
_, train_acc = model.evaluate(trainX, trainy, verbose=0)
_, test_acc = model.evaluate(testX, testy, verbose=0)
print('Train: %.3f, Test: %.3f' % (train_acc, test_acc))
# plot loss during training
pyplot.subplot(211)
pyplot.title('Loss')
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='test')
pyplot.legend()
# plot accuracy during training
pyplot.subplot(212)
pyplot.title('Accuracy')
pyplot.plot(history.history['accuracy'], label='train')
pyplot.plot(history.history['val_accuracy'], label='test')
pyplot.legend()
pyplot.show()
この例を実行すると、まずトレーニング データセットおよびテスト データセット上のモデルの分類精度が出力されます。
注: アルゴリズムや評価手順の確率的性質、または数値精度の違いにより、結果が異なる場合があります。例を数回実行して、平均結果を比較することを検討してください。
この場合、この問題と選択したモデル構成では、ヒンジ二乗損失が適切ではない可能性があり、その結果、トレーニング セットとテスト セットの分類精度が 70% 未満になることがわかります。
Train: 0.682, Test: 0.646
また、2 つの折れ線プロットを示す図も作成されます。上のプロットはトレイン (青) とテスト (オレンジ) データセットのエポックにわたる二乗ヒンジ損失を示し、下のプロットはエポックにわたる分類精度を示します。
損失のプロットは、確かにモデルが収束していることを示していますが、誤差曲面の形状は、重みの小さな変化が損失に大きな変化を引き起こす他の損失関数ほど滑らかではありません。
マルチクラス分類損失関数
マルチクラス分類は、サンプルが 3 つ以上のクラスの 1 つに割り当てられる予測モデリング問題です。
この問題は整数値の予測として組み立てられることが多く、各クラスには 0 から (num_classes – 1) までの一意の整数値が割り当てられます。この問題は、既知の各クラスに属する例の確率を予測することとして実装されることがよくあります。
このセクションでは、マルチクラス分類予測モデリング問題に適した損失関数を調査します。
ブロブ問題を調査の基礎として使用します。 scikit-learn によって提供される make_blobs() 関数は、指定された数のクラスと入力特徴を指定してサンプルを生成する方法を提供します。この関数を使用して、2 つの入力変数を持つ 3 クラス分類問題の 1,000 個の例を生成します。疑似乱数ジェネレーターは一貫してシードされるため、コードが実行されるたびに同じ 1,000 個の例が生成されます。
# generate dataset
X, y = make_blobs(n_samples=1000, centers=3, n_features=2, cluster_std=2, random_state=2)
2 つの入力変数は、2 次元平面上の点のx 座標とy 座標として取得できます。
以下の例では、クラス メンバーシップ別にポイントを色分けしたデータセット全体の散布図を作成します。
# scatter plot of blobs dataset
from sklearn.datasets import make_blobs
from numpy import where
from matplotlib import pyplot
# generate dataset
X, y = make_blobs(n_samples=1000, centers=3, n_features=2, cluster_std=2, random_state=2)
# select indices of points with each class label
for i in range(3):
samples_ix = where(y == i)
pyplot.scatter(X[samples_ix, 0], X[samples_ix, 1])
pyplot.show()
この例を実行すると、データセット内の 1,000 個の例を示す散布図が作成されます。この例では、それぞれ青、オレンジ、緑のクラス 0、1、2 に属する例が示されています。
入力特徴はガウス分布であり、標準化の恩恵を受ける可能性があります。ただし、簡潔にするために、この例では値をスケーリングしないままにします。
データセットはトレーニング セットとテスト セットに均等に分割されます。
# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
小規模な MLP モデルは、損失関数を探索するための基礎として使用されます。
このモデルは 2 つの入力変数を想定しており、隠れ層と修正線形活性化関数に 50 個のノードがあり、損失関数の選択に基づいてカスタマイズする必要がある出力層があります。
# define model
model = Sequential()
model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(..., activation='...'))
このモデルは、確率的勾配降下法を使用して、適切なデフォルト学習率 0.01 と運動量 0.9 でフィッティングされます。
# compile model
opt = SGD(lr=0.01, momentum=0.9)
model.compile(loss='...', optimizer=opt, metrics=['accuracy'])
モデルはトレーニング データセット上で 100 エポックに適合し、テスト データセットは検証データセットとして使用されます。これにより、各トレーニング エポックの終了時にトレーニング セットとテスト セットの損失と分類精度の両方を評価し、学習曲線を描くことができます。 。
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=100, verbose=0)
問題とモデルの基礎ができたので、マルチクラス分類予測モデリング問題に適した 3 つの一般的な損失関数を評価してみましょう。
これらの例では MLP が使用されていますが、マルチクラス分類用に CNN モデルと RNN モデルをトレーニングするときに同じ損失関数を使用できます。
マルチクラスのクロスエントロピー損失
クロスエントロピーは、マルチクラス分類問題に使用するデフォルトの損失関数です。
この場合、ターゲット値がセット {0, 1, 3, …, n} 内にあり、各クラスに一意の整数値が割り当てられるマルチクラス分類で使用することを目的としています。
数学的には、これは最尤の推論フレームワークの下で好ましい損失関数です。これは損失関数であり、最初に評価され、正当な理由がある場合にのみ変更されます。
クロスエントロピーは、問題内のすべてのクラスの実際の確率分布と予測された確率分布の間の平均差を要約するスコアを計算します。スコアは最小化され、完全なクロスエントロピー値は 0 になります。
クロスエントロピーは、モデルのコンパイル時に ‘categorical_crossentropy’ を指定することで、Keras の損失関数として指定できます。
model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy'])
この関数では、出力層が n 個のノード (クラスごとに 1 つ) (この場合は 3 つのノード)、および予測するために 'ソフトマックス' アクティブ化で構成されている必要があります。各クラスの確率。
model.add(Dense(3, activation='softmax'))
これは、ターゲット変数が 1 つのホット エンコードである必要があることを意味します。
これは、各例の実際のクラス値の期待確率が 1.0 であり、他のすべてのクラス値の期待確率が 0.0 であることを保証するためです。これは、to_categorical() Keras 関数を使用して実現できます。
# one hot encode output variable
y = to_categorical(y)
マルチクラス BLOB 分類問題に対するクロスエントロピー損失を伴う MLP の完全な例を以下に示します。
# mlp for the blobs multi-class classification problem with cross-entropy loss
from sklearn.datasets import make_blobs
from keras.layers import Dense
from keras.models import Sequential
from keras.optimizers import SGD
from keras.utils import to_categorical
from matplotlib import pyplot
# generate 2d classification dataset
X, y = make_blobs(n_samples=1000, centers=3, n_features=2, cluster_std=2, random_state=2)
# one hot encode output variable
y = to_categorical(y)
# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# define model
model = Sequential()
model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(3, activation='softmax'))
# compile model
opt = SGD(lr=0.01, momentum=0.9)
model.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy'])
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=100, verbose=0)
# evaluate the model
_, train_acc = model.evaluate(trainX, trainy, verbose=0)
_, test_acc = model.evaluate(testX, testy, verbose=0)
print('Train: %.3f, Test: %.3f' % (train_acc, test_acc))
# plot loss during training
pyplot.subplot(211)
pyplot.title('Loss')
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='test')
pyplot.legend()
# plot accuracy during training
pyplot.subplot(212)
pyplot.title('Accuracy')
pyplot.plot(history.history['accuracy'], label='train')
pyplot.plot(history.history['val_accuracy'], label='test')
pyplot.legend()
pyplot.show()
この例を実行すると、まずトレーニングおよびテスト データセット上のモデルの分類精度が出力されます。
注: アルゴリズムや評価手順の確率的性質、または数値精度の違いにより、結果が異なる場合があります。例を数回実行して、平均結果を比較することを検討してください。
この場合、モデルが良好に機能し、トレーニング データセットで約 84%、テスト データセットで約 82% の分類精度を達成していることがわかります。
Train: 0.840, Test: 0.822
また、2 つの折れ線プロットを示す図も作成されます。上のプロットはトレーニング (青) とテスト (オレンジ) データセットのエポックにわたるクロスエントロピー損失を示し、下のプロットはエポックにわたる分類精度を示します。
この場合、プロットはモデルが収束しているように見えることを示しています。クロスエントロピーと精度の両方の折れ線グラフは、多少でこぼこはしていますが、良好な収束動作を示しています。過剰または過少のフィッティングの兆候がない場合、モデルは適切に構成されている可能性があります。この場合、学習率またはバッチ サイズを調整して、収束の滑らかさを均一にすることができます。
スパースマルチクラスクロスエントロピー損失
多数のラベルを伴う分類問題でクロス エントロピーを使用する場合にフラストレーションが生じる原因として、ワン ホット エンコーディング プロセスが考えられます。
たとえば、語彙内の単語の予測には、ラベルごとに 1 つずつ、数万または数十万のカテゴリが存在する場合があります。これは、各トレーニング サンプルのターゲット要素が、数万または数十万のゼロ値を持つワンホット エンコードされたベクトルを必要とし、大量のメモリを必要とする可能性があることを意味する可能性があります。
スパース クロス エントロピーは、トレーニング前にターゲット変数を 1 ホット エンコードする必要なく、誤差の同じクロス エントロピー計算を実行することでこの問題に対処します。
スパースクロスエントロピーは、compile() 関数を呼び出すときに ‘sparse_categorical_crossentropy’ を使用することで、keras でマルチクラス分類に使用できます。
model.compile(loss='sparse_categorical_crossentropy', optimizer=opt, metrics=['accuracy'])
この関数では、出力層が n 個のノード (クラスごとに 1 つ) (この場合は 3 つのノード)、および予測するために 'ソフトマックス' アクティブ化で構成されている必要があります。各クラスの確率。
model.add(Dense(3, activation='softmax'))
この損失関数の利点は、ターゲット変数の 1 つのホット エンコーディングが必要ないことです。
BLOB のマルチクラス分類問題でスパースクロスエントロピーを使用して MLP をトレーニングする完全な例を以下に示します。
# mlp for the blobs multi-class classification problem with sparse cross-entropy loss
from sklearn.datasets import make_blobs
from keras.layers import Dense
from keras.models import Sequential
from keras.optimizers import SGD
from matplotlib import pyplot
# generate 2d classification dataset
X, y = make_blobs(n_samples=1000, centers=3, n_features=2, cluster_std=2, random_state=2)
# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# define model
model = Sequential()
model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(3, activation='softmax'))
# compile model
opt = SGD(lr=0.01, momentum=0.9)
model.compile(loss='sparse_categorical_crossentropy', optimizer=opt, metrics=['accuracy'])
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=100, verbose=0)
# evaluate the model
_, train_acc = model.evaluate(trainX, trainy, verbose=0)
_, test_acc = model.evaluate(testX, testy, verbose=0)
print('Train: %.3f, Test: %.3f' % (train_acc, test_acc))
# plot loss during training
pyplot.subplot(211)
pyplot.title('Loss')
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='test')
pyplot.legend()
# plot accuracy during training
pyplot.subplot(212)
pyplot.title('Accuracy')
pyplot.plot(history.history['accuracy'], label='train')
pyplot.plot(history.history['val_accuracy'], label='test')
pyplot.legend()
pyplot.show()
この例を実行すると、まずトレーニングおよびテスト データセット上のモデルの分類精度が出力されます。
注: アルゴリズムや評価手順の確率的性質、または数値精度の違いにより、結果が異なる場合があります。例を数回実行して、平均結果を比較することを検討してください。
この場合、モデルが問題に対して良好なパフォーマンスを達成していることがわかります。実際、実験を何度も繰り返すと、スパースクロスエントロピーと非スパースクロスエントロピーの平均パフォーマンスは同等になるはずです。
Train: 0.832, Test: 0.818
また、2 つの折れ線プロットを示す図も作成されます。上のプロットは、トレーニング (青) とテスト (オレンジ) データセットのエポックにわたるスパースのクロスエントロピー損失を示し、下のプロットは、エポックにわたる分類精度を示します。
この場合、プロットは、損失と分類精度に関してトレーニング全体でモデルが良好に収束していることを示しています。
カルバック ライブラー ダイバージェンス損失
カルバック ライブラー ダイバージェンス (略して KL ダイバージェンス) は、ある確率分布がベースライン分布とどのように異なるかを示す尺度です。
KL 発散損失が 0 の場合は、分布が同一であることを示します。実際には、KL Divergence の動作はクロスエントロピーに非常に似ています。予測された確率分布を使用して目的のターゲット確率分布を近似した場合に、どれだけの情報が失われるか (ビット単位で) を計算します。
そのため、KL 発散損失関数は、単に多クラス分類よりも複雑な関数を近似することを学習するモデルを使用する場合によく使用されます。たとえば、必要なモデルの下で密な特徴表現を学習するために使用されるオートエンコーダーの場合です。元の入力を再構築します。この場合、KL 発散損失が優先されます。それにもかかわらず、これはマルチクラス分類に使用でき、その場合、機能的にはマルチクラス クロス エントロピーと同等になります。
KL 発散損失は、compile() 関数で ‘kullback_leibler_divergence’ を指定することで Keras で使用できます。
model.compile(loss='kullback_leibler_divergence', optimizer=opt, metrics=['accuracy'])
クロスエントロピーと同様に、出力層はn 個のノード (クラスごとに 1 つ) (この場合は 3 つのノード)、および 'ソフトマックス' アクティベーションで順番に構成されます。各クラスの確率を予測します。
また、カテゴリカルクロスエントロピーと同様に、クラス値の期待確率が 1.0、他のすべてのクラス値の期待確率が 0.0 になるように、ターゲット変数をホット エンコードする必要があります。
# one hot encode output variable
y = to_categorical(y)
BLOB マルチクラス分類問題に対する KL 発散損失を使用して MLP をトレーニングする完全な例を以下に示します。
# mlp for the blobs multi-class classification problem with kl divergence loss
from sklearn.datasets import make_blobs
from keras.layers import Dense
from keras.models import Sequential
from keras.optimizers import SGD
from keras.utils import to_categorical
from matplotlib import pyplot
# generate 2d classification dataset
X, y = make_blobs(n_samples=1000, centers=3, n_features=2, cluster_std=2, random_state=2)
# one hot encode output variable
y = to_categorical(y)
# split into train and test
n_train = 500
trainX, testX = X[:n_train, :], X[n_train:, :]
trainy, testy = y[:n_train], y[n_train:]
# define model
model = Sequential()
model.add(Dense(50, input_dim=2, activation='relu', kernel_initializer='he_uniform'))
model.add(Dense(3, activation='softmax'))
# compile model
opt = SGD(lr=0.01, momentum=0.9)
model.compile(loss='kullback_leibler_divergence', optimizer=opt, metrics=['accuracy'])
# fit model
history = model.fit(trainX, trainy, validation_data=(testX, testy), epochs=100, verbose=0)
# evaluate the model
_, train_acc = model.evaluate(trainX, trainy, verbose=0)
_, test_acc = model.evaluate(testX, testy, verbose=0)
print('Train: %.3f, Test: %.3f' % (train_acc, test_acc))
# plot loss during training
pyplot.subplot(211)
pyplot.title('Loss')
pyplot.plot(history.history['loss'], label='train')
pyplot.plot(history.history['val_loss'], label='test')
pyplot.legend()
# plot accuracy during training
pyplot.subplot(212)
pyplot.title('Accuracy')
pyplot.plot(history.history['accuracy'], label='train')
pyplot.plot(history.history['val_accuracy'], label='test')
pyplot.legend()
pyplot.show()
この例を実行すると、まずトレーニングおよびテスト データセット上のモデルの分類精度が出力されます。
注: アルゴリズムや評価手順の確率的性質、または数値精度の違いにより、結果が異なる場合があります。例を数回実行して、平均結果を比較することを検討してください。
この場合、クロスエントロピー損失で見られた結果と同様のパフォーマンスが見られます。この場合、トレーニング データセットとテスト データセットでの精度は約 82% です。
Train: 0.822, Test: 0.822
また、2 つの折れ線プロットを示す図も作成されます。上のプロットはトレーニング (青) とテスト (オレンジ) データセットのエポックにわたる KL 発散損失を示し、下のプロットはエポックにわたる分類精度を示します。
この場合、プロットは損失と分類精度の両方に関して良好な収束動作を示しています。クロスエントロピーの評価では、測定値の類似性を考慮すると、ほぼ同一の動作が得られる可能性が非常に高くなります。
さらに読む
さらに詳しく知りたい場合は、このセクションでこのトピックに関するさらなるリソースを提供します。
投稿
- 深層学習ニューラル ネットワークをトレーニングするための損失関数と損失関数
論文
- 分類におけるディープ ニューラル ネットワークの損失関数について、2017 年。
API
- Keras 損失関数 API
- Keras アクティベーション関数 API
- sklearn.preprocessing.StandardScaler API
- sklearn.datasets.make_regression API
- sklearn.datasets.make_circles API
- sklearn.datasets.make_blobs API
記事
- 平均二乗誤差、ウィキペディア。
- 平均絶対誤差、ウィキペディア。
- クロスエントロピー、ウィキペディア。
- ヒンジの損失、ウィキペディア。
- カルバックとライブラーの発散、ウィキペディア。
- ニューラル ネットワークの損失関数、2017 年。
まとめ
このチュートリアルでは、特定の予測モデリング問題に対して深層学習ニューラル ネットワークの損失関数を選択する方法を学びました。
具体的には、次のことを学びました。
- 平均二乗誤差のモデルと回帰問題のバリアントを構成する方法。
- 二項分類用のクロスエントロピーおよびヒンジ損失関数のモデルを構成する方法。
- マルチクラス分類用のクロスエントロピーおよび KL 発散損失関数のモデルを構成する方法。
ご質問はありますか?
以下のコメント欄にご質問ください。できる限りお答えいたします。