我正在努力将分类模型从keras移植到pytorch。特别是交叉熵损失似乎返回完全不同的数字。
import numpy as np
import torch as t
import torch.nn as nn
import tensorflow.keras.backend as K
y_true = np.array([[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]])
y_pred = np.array([[0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 1, 0.41, 0.31, 0.21, 0.11]])
print("Keras", K.categorical_crossentropy(K.constant(y_true), K.constant(y_pred)))
print("PyTorch", nn.CrossEntropyLoss()(t.tensor(y_pred).argsort(dim=-1).float(), t.tensor(y_true).argmax(dim=-1)))```
打印:
Keras tf.Tensor([2.3369865],shape =(1,),dtype = float32)
PyTorch张量(1.4587)
因为我有一个自定义损失函数,交叉熵是其中的一部分,所以如果数字不同,我将需要获得相似的结果。
问题在于它们具有不同的实现。
如pytorch docs所说,nn.CrossEntropyLoss
将nn.LogSoftmax()
和nn.NLLLoss()
合并为一个类。但是,tensorflow docs指定默认情况下,除非您将keras.backend.categorical_crossentropy
设置为True,否则默认情况下from_logits
不应用Softmax。因此,除非事先使用softmax,否则不应该使用keras.backend.categorical_crossentropy
。除非您使用from_logits=True
。
如果您不想预先应用softmax,则应使用:
import numpy as np
import torch as t
import torch.nn as nn
import tensorflow.keras.backend as K
y_true = np.array([[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]])
y_pred = np.array([[0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 1, 0.41, 0.31, 0.21, 0.11]])
print("Keras", K.categorical_crossentropy(K.constant(y_true), K.constant(y_pred), from_logits=True))
# output: Keras tf.Tensor([2.408051], shape=(1,), dtype=float32)
print("PyTorch", nn.CrossEntropyLoss()(t.tensor(y_pred).float(), t.tensor(y_true).argmax(dim=-1)))
# output: PyTorch tensor(2.4081)
否则,您可以在计算categorical_crossentropy之前手动应用Softmax
import numpy as np
import torch as t
import torch.nn as nn
import tensorflow.keras.backend as K
y_true = np.array([[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0]])
y_pred = np.array([[0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 1, 0.41, 0.31, 0.21, 0.11]])
print("Keras", K.categorical_crossentropy(K.constant(y_true), K.softmax(K.constant(y_pred))))
# output: Keras tf.Tensor([2.408051], shape=(1,), dtype=float32)
print("PyTorch", nn.CrossEntropyLoss()(t.tensor(y_pred).float(), t.tensor(y_true).argmax(dim=-1)))
# output: PyTorch tensor(2.4081)
因此,您不应像在示例中那样将keras.backend.categorical_crossentropy
与from_logits=False
一起使用。
tf.keras.backend.categorical_crossentropy
target:与输出形状相同的张量。
output:由softmax产生的张量(除非from_logits为True,在这种情况下,预期输出为logits)。
from_logits:布尔值,是输出是softmax的结果还是logits的张量。