kerasでlabel_smoothingを試そうと思って調べたらtf.keras.losses.categorical_crossentropy(y_true, y_pred, label_smoothing=0)と引数に用意されていて、簡単に実装できるようになってました。
この場合自作関数で渡すのですが、「実際のところこれってどう動作してるんだ」とちょっと確かめてみたところ、Tensorで出力されて普段kerasしか使わない身としてはどう値を確認すればいいかすぐにはわからなかったのでその時のメモです。
自作損失関数について
自作の損失関数は(y_true, y_pred)を受け取って値を返す処理を作ればいいだけです。
import tensorflow as tf
#普通の'categorical_crossentropy'はこの動作
def normal_cross_entropy(y_true, y_pred):
loss = tf.keras.losses.categorical_crossentropy(y_true, y_pred, label_smoothing=0)
return loss
#smooth labeling、0/1じゃなくて正解以外の分類にもわずかに確率を与えるようにする。
def smooth_label(y_true, y_pred):
loss = tf.keras.losses.categorical_crossentropy(y_true, y_pred, label_smoothing=0.1)
return loss
こんな感じです。そんな難しくないでしょう。
出力を確認する
これに単純に結果を入れても
true = [[0, 0, 0, 1], [0, 0, 0, 1]]
ans = [[0, 0.01, 0, 0.99], [0, 0.1, 0, 0.9]]
print(smooth_label(tt, ans))
# Tensor("Neg_1:0", shape=(3,), dtype=float32)
# 値がわからない!
となって値を確認したくてもできません。なのでtensorflowで値をSessionする必要があります。
tt = [[0, 0, 0, 1], [0, 0, 0, 1]]
ans = [[0, 0.01, 0, 0.99], [0.04, 0.03, 0.03, 0.9]]
with tf.Session() as sess:
print(sess.run(normal_cross_entropy(tt, ans)))
print(sess.run(smooth_label(tt, ans)))
# [0.01005033 0.10536055]
# [0.93033063 0.3532583 ]
こんな感じですね。sess.runが必要なだけでわりかし単純。
0.99と当てるより0.9と当ててほかは平均的にしたほうがlossは低くなります。
これが学習の上でホントにいいかというのはまた別の話。
まとめ
まあ普通にSessionでrunすればいいということだけですが、基本kerasしか使わない身としてはtensorflowはハードル高くて気後れします。
ちなみにmixup,cutmixみたいな教師データを0,1以外にするとどうなんだろうと試したらちょっと不思議な結果でした。normalの方でもぴったり当ててるのにそんなにlossが小さくない・・・何でだ?
tt = [[0, 0.2, 0, 0.8], [0, 0.2, 0, 0.8], [0, 0.2, 0, 0.8]]
ans = [[0, 0.3, 0, 0.7], [0, 0.2, 0, 0.8], [0, 0.1, 0, 0.9]]
with tf.Session() as sess:
print(sess.run(normal_cross_entropy(tt, ans)))
print(sess.run(smooth_label(tt, ans)))
#[0.52613455 0.5004024 0.54480547]
#[1.3184421 1.3020815 1.3564284]
softmax_cross_entropy_with_logits_v2_helperあたりまでは辿ったけどよくわからなかったので、ちょっと保留。