整体代码
import torch
import torch.nn as nn
import numpy as np
'''
手动实现交叉熵的计算
'''
#使用torch计算交叉熵
ce_loss = nn.CrossEntropyLoss()
#假设有3个样本,每个都在做3分类
pred = torch.FloatTensor([[0.3, 2.1, 0.3],
[0.19, 1.2, 0.9],
[0.5, 0.4, 0.2]]) #n*class_num
'''
pred经过softmax函数的输出:
tensor([[0.1242, 0.7515, 0.1242],
[0.1730, 0.4751, 0.3519],
[0.3780, 0.3420, 0.2800]])
'''
#正确的类别分别为1,2,0
target = torch.LongTensor([1,2,0]) #n
'''
也可以写成这种形式:
torch.LongTensor([
[0,1,0],
[0,0,1],
[1,0,0],
])
交叉熵计算方式:
-(0 * log(0.1242) + 1 * log(0.7515) + 0 * log(0.1242)) = -log(0.7515)
-(0 * log(0.1730) + 0 * log(0.4751) + 1 * log(0.3519)) = -log(0.3519)
-(1 * log(0.3780) + 0 * log(0.3420) + 0 * log(0.2800)) = -log(0.3780)
如果模型对真实类别预测概率接近1 → log值接近0 → 损失小
如果模型对真实类别预测概率接近0 → log值很大 → 损失大
'''
loss = ce_loss(pred, target)
print(loss, "torch输出交叉熵")
#实现softmax函数
def softmax(matrix):
return np.exp(matrix) / np.sum(np.exp(matrix), axis=1, keepdims=True)
#验证softmax函数
print(torch.softmax(pred, dim=1))
print(softmax(pred.numpy()))
#将输入转化为onehot矩阵
def to_one_hot(target, shape):
one_hot_target = np.zeros(shape)
for i, t in enumerate(target):
one_hot_target[i][t] = 1
return one_hot_target
#手动实现交叉熵
def cross_entropy(pred, target):
batch_size, class_num = pred.shape
pred = softmax(pred)
target = to_one_hot(target, pred.shape)
entropy = - np.sum(target * np.log(pred), axis=1)
return sum(entropy) / batch_size
print(cross_entropy(pred.numpy(), target.numpy()), "手动实现交叉熵")
# print(np.log(2.7))
执行代码后打印结果如下
tensor(0.7677) torch输出交叉熵
tensor([[0.1242, 0.7515, 0.1242],
[0.1730, 0.4751, 0.3519],
[0.3780, 0.3420, 0.2800]])
[[0.1242 0.7515 0.1242]
[0.1730 0.4751 0.3519]
[0.3780 0.3420 0.2800]]
0.7677 手动实现交叉熵
关键点说明(PyTorch内置的CrossEntropyLoss VS 手动实现交叉熵)
两种方法结果一致:PyTorch内置的CrossEntropyLoss和手动实现的结果都是 0.7677
CrossEntropyLoss内部包含Softmax:所以不需要对pred先做softmax
手动实现的步骤:
(1)先对pred做softmax
(2)将target转为one-hot
(3)计算交叉熵
数值差异:由于浮点数精度,可能会有微小的差异(比如0.767649 vs 0.7677),但基本一致。
常见值的log对照表
| 概率p | ln( p ) | -ln ( p )(损失) |
|---|---|---|
| 1.0 | 0 | 0(完美预测) |
| 0.9 | -0.105 | 0.105 |
| 0.5 | -0.693 | 0.693 |
| 0.1 | -2.303 | 2.303 |
| 0.01 | -4.605 | 4.605 |
| 0.001 | -6.908 | 6.908 |
规律总结
概率越小 → 负对数值越大 → 损失越大
这就是为什么:
- 预测对(概率接近1)→ 损失小
- 预测错(概率接近0)→ 损失大
核心规律
交叉熵只关注真实类别的预测概率:
one-hot的0 消除了所有其他类别的贡献
one-hot的1 只保留真实类别的log值
最终公式简化为:-log(真实类别的预测概率)
本文详细对比PyTorch内置CrossEntropyLoss与手动实现交叉熵的计算过程,阐明其等价性:内置函数隐含Softmax,而手动实现需显式执行Softmax、target转one-hot及-log(p_true)计算。强调交叉熵仅依赖真实类别预测概率,揭示损失随预测概率减小而增大的核心规律,并指出浮点精度导致的微小数值差异。

175

被折叠的 条评论
为什么被折叠?



