如何手工计算分类交叉熵?

德里克斯

当我手动计算二元交叉熵时,我应用 sigmoid 来获得概率,然后使用交叉熵公式并表示结果:

logits = tf.constant([-1, -1, 0, 1, 2.])
labels = tf.constant([0, 0, 1, 1, 1.])

probs = tf.nn.sigmoid(logits)
loss = labels * (-tf.math.log(probs)) + (1 - labels) * (-tf.math.log(1 - probs))
print(tf.reduce_mean(loss).numpy()) # 0.35197204

cross_entropy = tf.keras.losses.BinaryCrossentropy(from_logits=True)
loss = cross_entropy(labels, logits)
print(loss.numpy()) # 0.35197204

如何计算范畴交叉熵的时候logitslabels有不同的大小?

logits = tf.constant([[-3.27133679, -22.6687183, -4.15501118, -5.14916372, -5.94609261,
                       -6.93373299, -5.72364092, -9.75725174, -3.15748906, -4.84012318],
                      [-11.7642536, -45.3370094, -3.17252636, 4.34527206, -17.7164974,
                      -0.595088899, -17.6322937, -2.36941719, -6.82157373, -3.47369862],
                      [-4.55468369, -1.07379043, -3.73261762, -7.08982277, -0.0288562477, 
                       -5.46847963, -0.979336262, -3.03667569, -3.29502845, -2.25880361]])
labels = tf.constant([2, 3, 4])

loss_object = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True,
                                                            reduction='none')
loss = loss_object(labels, logits)
print(loss.numpy()) # [2.0077195  0.00928135 0.6800677 ]
print(tf.reduce_mean(loss).numpy()) # 0.8990229

我的意思是如何[2.0077195 0.00928135 0.6800677 ]手动获得相同的结果 ( )?

@OverLordGoldDragon 答案是正确的。TF 2.0它看起来像这样:

loss_object = tf.keras.losses.SparseCategoricalCrossentropy(
    from_logits=True, reduction='none')
loss = loss_object(labels, logits)
print(f'{loss.numpy()}\n{tf.math.reduce_sum(loss).numpy()}')

one_hot_labels = tf.one_hot(labels, 10)

preds = tf.nn.softmax(logits)
preds /= tf.math.reduce_sum(preds, axis=-1, keepdims=True)
loss = tf.math.reduce_sum(tf.math.multiply(one_hot_labels, -tf.math.log(preds)), axis=-1)
print(f'{loss.numpy()}\n{tf.math.reduce_sum(loss).numpy()}')
# [2.0077195  0.00928135 0.6800677 ]
# 2.697068691253662
# [2.0077198  0.00928142 0.6800677 ]
# 2.697068929672241

对于语言模型:

vocab_size = 9
seq_len = 6
batch_size = 2

labels = tf.reshape(tf.range(batch_size*seq_len), (batch_size,seq_len)) # (2, 6)
logits = tf.random.normal((batch_size,seq_len,vocab_size)) # (2, 6, 9)

loss_object = tf.keras.losses.SparseCategoricalCrossentropy(
    from_logits=True, reduction='none')
loss = loss_object(labels, logits)
print(f'{loss.numpy()}\n{tf.math.reduce_sum(loss).numpy()}')

one_hot_labels = tf.one_hot(labels, vocab_size)

preds = tf.nn.softmax(logits)
preds /= tf.math.reduce_sum(preds, axis=-1, keepdims=True)
loss = tf.math.reduce_sum(tf.math.multiply(one_hot_labels, -tf.math.log(preds)), axis=-1)
print(f'{loss.numpy()}\n{tf.math.reduce_sum(loss).numpy()}')
# [[1.341706  3.2518263 2.6482694 3.039099  1.5835983 4.3498387]
#  [2.67237   3.3978183 2.8657475       nan       nan       nan]]
# nan
# [[1.341706  3.2518263 2.6482694 3.039099  1.5835984 4.3498387]
#  [2.67237   3.3978183 2.8657475 0.        0.        0.       ]]
# 25.1502742767334
霸王金龙

SparseCategoricalCrossentropyCategoricalCrossentropy采用整数标签而不是one-hot来自源代码的示例,以下两个是等效的:

scce = tf.keras.losses.SparseCategoricalCrossentropy()
cce = tf.keras.losses.CategoricalCrossentropy()

labels_scce = K.variable([[0, 1, 2]]) 
labels_cce  = K.variable([[1,    0,  0], [0,    1,  0], [0,   0,   1]])
preds       = K.variable([[.90,.05,.05], [.50,.89,.60], [.05,.01,.94]])

loss_cce  = cce(labels_cce,   preds, from_logits=False)
loss_scce = scce(labels_scce, preds, from_logits=False)
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    sess.run([loss_cce, loss_scce])

print(K.get_value(loss_cce))
print(K.get_value(loss_scce))
# [0.10536055  0.8046684  0.0618754]
# [0.10536055  0.8046684  0.0618754]

至于如何“手动”完成,我们可以参考Numpy 后端

np_labels = K.get_value(labels_cce)
np_preds  = K.get_value(preds)

losses = []
for label, pred in zip(np_labels, np_preds):
    pred /= pred.sum(axis=-1, keepdims=True)
    losses.append(np.sum(label * -np.log(pred), axis=-1, keepdims=False))
print(losses)
# [0.10536055  0.8046684  0.0618754]
  • from_logits = True:preds传入之前的模型输出softmax(所以我们将其传入 softmax)
  • from_logits = False:preds传入后的模型输出softmax(所以我们跳过这一步)

总而言之,手动计算:

  1. 将整数标签转换为单热标签
  2. 如果 preds 是softmax之前的模型输出,我们计算它们的 softmax
  3. pred /= ... 在计算日志之前规范化预测;这样,高概率。对零标签的预测会惩罚对单标签的正确预测。如果from_logits = False,则跳过此步骤,因为softmax进行归一化。看到这个片段进一步阅读
  4. 对于每个观察/样本,仅计算元素方面的负值log(基数 e),其中 label==1
  5. 取所有观测值的损失平均值

最后,分类交叉熵的数学公式是:

  • i迭代N观察
  • c迭代C
  • 1指示函数- 在这里,就像二元交叉熵一样,除了对长度C向量进行操作
  • p_model [y_i \in C_c]-i属于类的预测观察概率c

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何手工跟踪C ++程序?

来自分类Dev

手工问题

来自分类Dev

如何优化此函数计算两个 numpy 数组的分类交叉熵

来自分类Dev

如何从PyTorch中的概率计算交叉熵?

来自分类Dev

如何计算像素级预测的交叉熵

来自分类Dev

如何使用model.predict进行分类交叉熵?

来自分类Dev

如何正确使用交叉熵损失与Softmax进行分类?

来自分类Dev

分类交叉熵背后的直觉

来自分类Dev

与手工计算相比,R中的glht函数给出不同的结果

来自分类Dev

如何在PyTorch中计算自举交叉熵损失?

来自分类Dev

手工编写asm.js

来自分类Dev

matplotlib布局像手工绘制

来自分类Dev

OpenMP手工减少指令

来自分类Dev

Pytorch分类交叉熵损失函数行为

来自分类Dev

多重继承,如何通过复制和维护避免手工继承?

来自分类Dev

如何手工重新排列MIPS代码以最大程度地减少所需的NOP数量?

来自分类Dev

手工编译Android应用程序

来自分类Dev

带有实体框架6的手工POCO?

来自分类Dev

STL标头是完全手工编写的吗?

来自分类Dev

手工编码的汇编-实用的寄存器分配?

来自分类Dev

将手工系统移植到libcaf

来自分类Dev

使用Bookdown包引用“手工制作”表

来自分类Dev

scikit-learn:FeatureUnion包含手工制作的功能

来自分类Dev

了解手工MLE logit估计与优化

来自分类Dev

核心?手工SYN / ACK帧发送RST

来自分类Dev

手工编码的汇编-实用的寄存器分配?

来自分类Dev

手工编译Android应用程序

来自分类Dev

手工制作的Xavier Initializer:lrelu和relu的值

来自分类Dev

将“手工制作”的响应放入缓存中