在搭建神经网络模型时,都会计算模型的loss,再进行反向传播优化参数。而在TensorFlow中计算loss的函数有很多,其中使用比较多的是:
- tf.losses.sparse_softmax_cross_entropy()
- tf.nn.sparse_softmax_cross_entropy_with_logits()
- tf.nn.softmax_cross_entropy_with_logits()
这三种求loss的函数,看似没有区别,但是,在使用的过程中稍不注意就会出错。
首先来说说第一个求loss的函数与后面两者的区别。区别主要有两个:
第一、tf.losses.sparse_softmax_cross_entropy()能自动将labels转化为One-Hot编码后再与经过softmax的logits计算交叉熵,而后面两个函数的labels的维度如果是[None],那么就需要做一个
维度变换(tf.reshape(labels, [-1]))再与经过softmax的logits计算交叉熵;
第二、tf.losses.sparse_softmax_cross_entropy()得到的loss是平均损失,而后面两个函数的loss
却并不是。可以通过下面这个例子证明。
y = tf.constant([2,0])
x = tf.constant([[2.0, -1.0, 3.0], [1.0, 0.0, -0.5]])
# 首先使用tf.losses.sparse_softmax_cross_entropy函数
loss = tf.losses.sparse_softmax_cross_entropy(y, x)
sess = tf.Session()
sess.run(loss)
0.39546573
# 再使用tf.nn.sparse_softmax_cross_entropy_with_logits函数
loss_1 = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=y, logits=x)
loss_2 = tf.reduce_mean(loss_1)
sess = tf.Session()
sess.run(loss_1, loss_2)
array([0.32656264, 0.4643688 ], dtype=float32)
0.39546573
然后再说tf.nn.sparse_softmax_cross_entropy_with_logits和tf.nn.softmax_cross_entropy_with_logits两者的区别。它们的区别主要是labels的形式,tf.nn.softmax_cross_entropy_with_logits函数要求labels必须是概率分布的形式。比如上面例子中,如果是:
loss_3 = tf.nn.softmax_cross_entropy_with_logits(labels=y, logits=x)
sess = tf.Session()
sess.run(loss_3)
则会报错,因为y并不是概率形式,所以要修改y的形式:
y_ = tf.constant([[0.0, 0.0, 1.0], [1.0, 0.0, 0.0]])
loss_3 = tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=x)
sess = tf.Session()
sess.run(loss_3)
array([0.32656264, 0.4643688 ], dtype=float32)
这样得到的值就是正确的了。同时,为了保证在优化参数和loss的时候,梯度不会发生爆炸,可以如下处理:
# 设置一个最大梯度值
max_grad_norm = 5
trainable_variables = tf.trainable_variables()
grads, _ = tf.clip_by_global_norm(tf.gradients(loss, trainable_variables), max_grad_norm)
optimizer = tf.train.GradientDescentOptimizer(learning_rate=1.0)
train_op = optimizer.apply_gradients(zip(grads, trainable_variables))