TensorFlow 中的 Loss 函数介绍
前言
TensorFlow 提供了很多计算 Loss 的 API, 很多时候容易忘记这些 API 的输入和输出的 Shape. 这里对经常用到的 API 做个记录, 并配上 API 的使用实例, 加深体会.
广而告之
可以在微信中搜索 “珍妮的算法之路” 或者 “world4458” 关注我的微信公众号;另外可以看看知乎专栏 PoorMemory-机器学习, 以后文章也会发在知乎专栏中;
softmax_cross_entropy_with_logits
tf.nn.softmax_cross_entropy_with_logits
用于分类问题计算交叉熵, 输入分别是 labels
和 logits
(logits
是神经网络的输出结果, 但还未输入到 tf.nn.softmax
方法中; labels
一般是 OneHot 的形式, 可以使用 tf.one_hot
). 下面看个例子:
import os
import tensorflow as tf
os.environ['TF_CPP_MIN_LOG_LEVEL']='3'
os.environ['CUDA_VISIBLE_DEVICES'] = '-1'
logits = tf.constant([[1.0,2.0,3.0],
[1.0,2.0,3.0],
[1.0,2.0,3.0]])
y_ = tf.constant([[0.0,0.0,1.0],
[0.0,0.0,1.0],
[0.0,0.0,1.0]])
loss = tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=y_)
logits = tf.nn.softmax(logits)
manual_loss = tf.reduce_sum(-y_ * tf.log(tf.clip_by_value(logits, 1e-10, 1.)), axis=1)
with tf.Session() as sess:
loss_, logits_, manual_loss_ = sess.run([loss, logits, manual_loss])
print('loss: {}'.format(loss_))
print('logits_: {}'.format(logits_))
print('manual_loss_: {}'.format(manual_loss_))
### -----------------输出结果 --------------------------
loss_: [0.40760595 0.40760595 0.40760595]
logits_: [[0.09003057 0.24472848 0.66524094]
[0.09003057 0.24472848 0.66524094]
[0.09003057 0.24472848 0.66524094]]
manual_loss_: [0.407606 0.407606 0.40760598]
可以看到
loss_
和manual_loss_
的结果是一致的 (请忽略些许的误差).- 如果输入的
logits
的 Shape 为(B, T)
, 那么labels
变换成 OneHot 的形式, 大小也为(B, T)
. - 将
logits
和labels
输入到tf.nn.softmax_cross_entropy_with_logits
后, 得到的结果是(B,)
; 因此, 在实践中, 为了得到一个 Batch 的平均 loss, 需要使用:
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=y_))
manual_loss_
的计算方式: l o s s = ∑ j = 1 T y j ⋅ log ( y ^ j ) loss = \sum\limits_{j=1}^{T} y_j\cdot\log(\hat{y}_j) loss=j=1∑Tyj⋅log(y^j), 其中 y j ∈ { 0 , 1 } y_j\in\{0, 1\} yj∈{ 0,1}.
sparse_softmax_cross_entropy_with_logits
和 softmax_cross_entropy_with_logits
不同的是, labels
无需变换成 OneHot 的形式. 还是拿上面的作为例子, 代码只需要对 labels
做一定修改即可.
import os
import tensorflow as tf
os.environ['TF_CPP_MIN_LOG_LEVEL']='3'
os.environ['CUDA_VISIBLE_DEVICES'] = '-1'
logits = tf.constant([[1.0,2.0,3.0],
[1.0,2.0,3.0],
[1.0,2.0,3.0]])
y = tf.constant([2, 2, 2], dtype=tf.int32) # 和上一节的代码相比, 注意此处的改动
loss = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=y)
logits = tf.nn.softmax(logits)
y_ = tf.one_hot(y, depth=3) ## 注意此处的改动
manual_loss = tf.reduce_sum(-y_ * tf.log(tf.clip_by_value(logits, 1e-10, 1.)), axis=1)
with tf.Session() as sess:
loss_, logits_, manual_loss_ = sess.run([loss, logits, manual_loss])
print('loss_: {}'.format(loss_))
print('logits_: {}'.format(logits_))
print('manual_loss_: {}'.format(manual_loss_))
### -----------------输出结果 --------------------------
loss_: [0.40760595 0.40760595 0.40760595]
logits_: [[0.09003057 0.24472848 0.66524094]
[0.09003057 0.24472848 0.66524094]
[0.09003057 0.24472848 0.66524094]]
manual_loss_: [0.407606 0.407606 0.40760598]