@TOC
如果想直接看CrossEntropyLoss的作用可以直接看第三节
1. torch.nn.LogSoftmax
torch.nn.LogSoftmax(dim=None)
此函数计算输入向量的Softmax并取对数
%7D%7B%5Csum_%7Bj%7Dexp(x_%7Bj%7D)%7D)%0A)
- 输入:输入向量或者矩阵
- 输出:与输入维度相同,返回值范围

- dim:决定哪一维的向量被计算
举例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| batch_size = 2 class_num = 3 inputs = torch.randn(batch_size, class_num) for i in range(batch_size): for j in range(class_num): inputs[i][j] = (i + 1) * (j + 1) print("inputs:", inputs) ''' inputs: tensor([[1., 2., 3.], [2., 4., 6.]]) '''
softmax = nn.Softmax(dim=1) probs = softmax(inputs) print("probs:\n", probs) ''' 取第一个值进行验证 print(exp(1)/(exp(1)+exp(2)+exp(3))):0.09003057317038046 probs: tensor([[0.0900, 0.2447, 0.6652], [0.0159, 0.1173, 0.8668]]) '''
LogSoftmax = nn.LogSoftmax(dim=1) log_probs = LogSoftmax(inputs) print("log_probs:\n", log_probs) ''' log_probs: tensor([[-2.4076, -1.4076, -0.4076], [-4.1429, -2.1429, -0.1429]]) '''
print(torch.log(probs)) ''' tensor([[-2.4076, -1.4076, -0.4076], [-4.1429, -2.1429, -0.1429]]) '''
|
nn.Softmax()函数和nn.LogSoftmax()函数的唯一区别是nn.LogSoftmax函数在求出Sofmax值之后会取自然对数e
2. torch.nn.NLLLOSS
torch.nn.NLLLOSS(reduction='mean')
直接举例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| batch_size = 2 class_num = 3 inputs = torch.randn(batch_size, class_num) for i in range(batch_size): for j in range(class_num): inputs[i][j] = (i + 1) * (j + 1) print("inputs:", inputs) ''' inputs: tensor([[1., 2., 3.], [2., 4., 6.]]) '''
nlloss = nn.NLLLoss() target = torch.empty(2, dtype=torch.long).random_(3) output = nlloss(inputs, target) print(target) print(output) ''' tensor([2, 2]) tensor(-4.5000) '''
|
NLLLOSS取了对应target的数值,然后相加求平均取负,比如上述例子,target分别为2和2,所以tensor的第一行和第二行分别取3和6,然后相加取平均最后加负号就是最终结果-4.5
3. torch.nn.CrossEntropyLoss
torch.nn.CrossEntropyLoss(reduction='mean')
明白上述两个函数LogSoftmax以及NLLLoss之后,CrossEntropyLoss其实就是将上述两个函数进行了结合
首先讲解交叉熵的原理
在分类问题中,假设我们有两个样本,这两个样本有三个类别可以分。比如我们有两只小动物,现在有猫狗猪三个类别,经过网络计算结果如下
| predict |
real |
|
| (0.1, 0.2, 0.7) |
(0, 0, 1) |
正确 |
| (0.5, 0.2, 0.3) |
(0, 1, 0) |
错误 |
使用交叉熵损失公式来计算我们的结果
二元分类:
log(1-p_%7Bi%7D)%5D%0A)
多元分类:

上述损失:
%2B1%5Ctimes%20log(0.7)%5D%20%3D%200.36%20%5C%5C%0A%26%20sample~2%3Aloss%20%3D%20-%5B0%5Ctimes%20log(0.5)%2B1%5Ctimes%20log(0.2)%2B0%5Ctimes%20log(0.3)%5D%20%3D%201.61%20%5C%5C%0A%26%20loss_%7Bave%7D%20%3D%20%5Cfrac%7B0.36%2B1.61%7D%7B2%7D%20%3D%200.96%0A%5Cend%7Baligned%7D%0A)
代码解释
明白原理之后我们来看一下具体的代码公式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| batch_size = 2 class_num = 3 input = torch.randn(batch_size, class_num) for i in range(batch_size): for j in range(class_num): input[i][j] = (i + 1) * (j + 1) print("inputs:", input) target = torch.empty(2, dtype=torch.long).random_(3) print("targets:", target) ''' inputs: tensor([[1., 2., 3.], [2., 4., 6.]]) targets: tensor([2, 1]) '''
loss = nn.CrossEntropyLoss() output = loss(input, target) print(output) ''' tensor(1.2753) '''
|
下面我们用LogSoftmax以及NLLLoss拆分来看看CrossEntropyLoss具体作了什么
LogSoftmax函数
1 2 3 4 5 6 7 8
| LogSoftmax = nn.LogSoftmax(dim=1) log_probs = LogSoftmax(input) print("log_probs:\n", log_probs) ''' log_probs: tensor([[-2.4076, -1.4076, -0.4076], [-4.1429, -2.1429, -0.1429]]) '''
|
这一步主要进行了两个操作,一个是取Softmax,然后进行log
- softmax将得分score调整到0-1之间
- log作用:暂时不知道
求解之后和上述LogSoftmax函数结果一致
1 2 3 4 5 6 7
| Softmax = nn.Softmax(dim=1) probs = Softmax(input) print(torch.log(probs)) ''' tensor([[-2.4076, -1.4076, -0.4076], [-4.1429, -2.1429, -0.1429]]) '''
|
NLLLoss函数
此函数在第二节介绍过,这里我们在第一步LogSoftmax函数的基础上直接用此函数
1 2 3 4 5 6
| nllloss = nn.NLLLoss() output2 = nllloss(log_probs, target) print(output2) ''' tensor(1.2753) '''
|
发现这两步合起来的结果和只用CrossEntropyLoss的结果一致,我们看上述结果,1.2753是怎么的出来的呢?注意看
1 2 3 4 5
| tensor([[-2.4076, -1.4076, -0.4076], [-4.1429, -2.1429, -0.1429]])
targets: tensor([2, 1])
|
由于正确样本target为1,错误的为0,因此只需要计算正确的损失即可
即
%5D%0A)