TensorFlow文本分类示例中为何需设置from_logits=True?
问题:BinaryCrossentropy设置
from_logits=True的原因及训练准确率无变化的问题 我在运行TensorFlow基础文本分类示例时产生疑问:为什么使用BinaryCrossentropy损失函数时需要设置from_logits=True?当我移除该参数,同时给最后一层Dense添加activation="sigmoid"后,训练过程中的binary_accuracy完全没有变化。
修改后的代码
model = tf.keras.Sequential([ layers.Embedding(max_features + 1, embedding_dim), layers.Dropout(0.2), layers.GlobalAveragePooling1D(), layers.Dropout(0.2), layers.Dense(1, activation="sigmoid")]) # <-- 此处添加sigmoid激活 model.compile(loss=losses.BinaryCrossentropy(), # <-- 此处移除from_logits=True optimizer='adam', metrics=tf.metrics.BinaryAccuracy(threshold=0.0)) epochs = 10 history = model.fit( train_ds, validation_data=val_ds, epochs=epochs)
训练输出
Epoch 1/10 625/625 [==============================] - 4s 4ms/step - loss: 0.6635 - binary_accuracy: 0.4981 - val_loss: 0.6149 - val_binary_accuracy: 0.5076 Epoch 2/10 625/625 [==============================] - 2s 4ms/step - loss: 0.5492 - binary_accuracy: 0.4981 - val_loss: 0.4990 - val_binary_accuracy: 0.5076 Epoch 3/10 625/625 [==============================] - 2s 4ms/step - loss: 0.4453 - binary_accuracy: 0.4981 - val_loss: 0.4208 - val_binary_accuracy: 0.5076 Epoch 4/10 625/625 [==============================] - 2s 4ms/step - loss: 0.3792 - binary_accuracy: 0.4981 - val_loss: 0.3741 - val_binary_accuracy: 0.5076 Epoch 5/10 625/625 [==============================] - 3s 4ms/step - loss: 0.3360 - binary_accuracy: 0.4981 - val_loss: 0.3454 - val_binary_accuracy: 0.5076 Epoch 6/10 625/625 [==============================] - 3s 4ms/step - loss: 0.3054 - binary_accuracy: 0.4981 - val_loss: 0.3262 - val_binary_accuracy: 0.5076 Epoch 7/10 625/625 [==============================] - 3s 4ms/step - loss: 0.2813 - binary_accuracy: 0.4981 - val_loss: 0.3126 - val_binary_accuracy: 0.5076 Epoch 8/10 625/625 [==============================] - 3s 4ms/step - loss: 0.2616 - binary_accuracy: 0.4981 - val_loss: 0.3033 - val_binary_accuracy: 0.5076 Epoch 9/10 625/625 [==============================] - 3s 4ms/step - loss: 0.2456 - binary_accuracy: 0.4981 - val_loss: 0.2967 - val_binary_accuracy: 0.5076 Epoch 10/10 625/625 [==============================] - 2s 4ms/step - loss: 0.2306 - binary_accuracy: 0.4981 - val_loss: 0.2920 - val_binary_accuracy: 0.5076
解答
1. from_logits=True的作用
核心是为了数值稳定性:
- 当模型最后一层没有激活函数时,输出的是原始logits(无范围限制的实数),设置
from_logits=True会让损失函数内部自动完成sigmoid转换,同时避免直接计算sigmoid可能引发的梯度消失问题——当logits绝对值很大时,sigmoid的梯度会趋近于0,导致模型训练停滞。 - 如果最后一层加了
sigmoid激活,输出已经是0-1之间的概率值,此时from_logits应该设为False(默认值),损失函数会直接用概率值计算交叉熵。
2. 准确率无变化的原因
问题出在BinaryAccuracy(threshold=0.0)上:
- 加了
sigmoid后,模型输出是0-1的概率值,而threshold=0.0会把所有大于0的输出都判定为类别1。你的数据集正负样本比例接近1:1(初始准确率约0.5),模型输出几乎全大于0,相当于把所有样本归为一类,准确率自然固定在样本占比高的那一类数值上,不会随训练更新。
解决方法
把BinaryAccuracy的阈值改成默认的0.5即可,这样输出大于0.5判定为类别1,小于等于0.5判定为类别0,准确率会随训练正常变化:
model.compile(loss=losses.BinaryCrossentropy(), optimizer='adam', metrics=tf.metrics.BinaryAccuracy()) # 去掉threshold=0.0,使用默认0.5
内容的提问来源于stack exchange,提问作者Yaiba
相关产品推荐
相关产品推荐

