短縮版:
2つのテンソルがありy_hat
、各クラスの計算されたスコアが含まれ(たとえば、y = W * x + bから)、y_true
ワンホットエンコードされた真のラベルが含まれているとします。
y_hat = ... # Predicted label, e.g. y = tf.matmul(X, W) + b
y_true = ... # True label, one-hot encoded
のスコアy_hat
を正規化されていない対数確率として解釈する場合、それらはロジットです。
さらに、この方法で計算されたクロスエントロピー損失の合計:
y_hat_softmax = tf.nn.softmax(y_hat)
total_loss = tf.reduce_mean(-tf.reduce_sum(y_true * tf.log(y_hat_softmax), [1]))
基本的に、関数で計算されたクロスエントロピー損失の合計と同等ですsoftmax_cross_entropy_with_logits()
。
total_loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(y_hat, y_true))
ロングバージョン:
ニューラルネットワークの出力層では、計算などから、各トレーニングインスタンスのクラススコアを含む配列を計算しy_hat = W*x + b
ます。例として、以下を作成しy_hat
ました。2x 3の配列として作成しました。行はトレーニングインスタンスに対応し、列はクラスに対応しています。したがって、ここには2つのトレーニングインスタンスと3つのクラスがあります。
import tensorflow as tf
import numpy as np
sess = tf.Session()
# Create example y_hat.
y_hat = tf.convert_to_tensor(np.array([[0.5, 1.5, 0.1],[2.2, 1.3, 1.7]]))
sess.run(y_hat)
# array([[ 0.5, 1.5, 0.1],
# [ 2.2, 1.3, 1.7]])
値は正規化されていないことに注意してください(つまり、行の合計が1になりません)。それらを正規化するために、入力を非正規化対数確率(別名logits)として解釈し、正規化線形確率を出力するsoftmax関数を適用できます。
y_hat_softmax = tf.nn.softmax(y_hat)
sess.run(y_hat_softmax)
# array([[ 0.227863 , 0.61939586, 0.15274114],
# [ 0.49674623, 0.20196195, 0.30129182]])
softmax出力の意味を完全に理解することが重要です。以下に、上記の出力をより明確に表す表を示しました。たとえば、インスタンス1のトレーニングが「クラス2」である確率は0.619であることがわかります。各トレーニングインスタンスのクラス確率は正規化されているため、各行の合計は1.0です。
Pr(Class 1) Pr(Class 2) Pr(Class 3)
,--------------------------------------
Training instance 1 | 0.227863 | 0.61939586 | 0.15274114
Training instance 2 | 0.49674623 | 0.20196195 | 0.30129182
これで、各トレーニングインスタンスのクラス確率が得られました。各行のargmax()を取得して、最終的な分類を生成できます。上記から、トレーニングインスタンス1は「クラス2」に属し、トレーニングインスタンス2は「クラス1」に属していることが生成されます。
これらの分類は正しいですか?トレーニングセットの真のラベルに対して測定する必要があります。y_true
行がトレーニングインスタンスで、列がクラスである、ワンホットエンコードされた配列が必要になります。以下にy_true
、トレーニングインスタンス1の真のラベルが「クラス2」であり、トレーニングインスタンス2の真のラベルが「クラス3」である、ワンホット配列の例を作成しました。
y_true = tf.convert_to_tensor(np.array([[0.0, 1.0, 0.0],[0.0, 0.0, 1.0]]))
sess.run(y_true)
# array([[ 0., 1., 0.],
# [ 0., 0., 1.]])
確率分布はの確率分布にy_hat_softmax
近いy_true
ですか?クロスエントロピー損失を使用してエラーを測定できます。
行単位でクロスエントロピー損失を計算し、結果を確認できます。以下では、トレーニングインスタンス1の損失が0.479であるのに対し、トレーニングインスタンス2の損失は1.200と大きくなっています。上記の例でy_hat_softmax
は、トレーニングインスタンス1の最も高い確率は "クラス2"であり、これはのトレーニングインスタンス1と一致するため、この結果は理にかなっていy_true
ます。ただし、トレーニングインスタンス2の予測では、「クラス1」の確率が最も高く、真のクラス「クラス3」とは一致しません。
loss_per_instance_1 = -tf.reduce_sum(y_true * tf.log(y_hat_softmax), reduction_indices=[1])
sess.run(loss_per_instance_1)
# array([ 0.4790107 , 1.19967598])
私たちが本当に望んでいるのは、すべてのトレーニングインスタンスの合計損失です。したがって、以下を計算できます。
total_loss_1 = tf.reduce_mean(-tf.reduce_sum(y_true * tf.log(y_hat_softmax), reduction_indices=[1]))
sess.run(total_loss_1)
# 0.83934333897877944
softmax_cross_entropy_with_logits()の使用
代わりにtf.nn.softmax_cross_entropy_with_logits()
、以下に示すように、関数を使用して合計クロスエントロピー損失を計算できます。
loss_per_instance_2 = tf.nn.softmax_cross_entropy_with_logits(y_hat, y_true)
sess.run(loss_per_instance_2)
# array([ 0.4790107 , 1.19967598])
total_loss_2 = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(y_hat, y_true))
sess.run(total_loss_2)
# 0.83934333897877922
とtotal_loss_1
、total_loss_2
最後の桁に若干の違いがある基本的に同等の結果を生成することに注意してください。ただし、2番目の方法を使用することもできます。softmaxはの内部で行われるため、コードの行数が1つ減り、蓄積される数値エラーが少なくなりますsoftmax_cross_entropy_with_logits()
。
cross_entropy = tf.nn.softmax_cross_entropy_with_logits(tf.nn.softmax(tf.add(tf.matmul(x,W),b)),y) cost=tf.reduce_mean(cross_entropy)
。しかし、私が別の方法を使用するとpred=tf.nn.softmax(tf.add(tf.matmul(x,W),b)) cost =tf.reduce_mean(-tf.reduce_sum(y*tf.log(pred),reduction_indices=1))
、結果は安定していてより良いです。