Softmax函数与交叉熵函数
简介
本节主要讲解二分类问题和多分类问题之间的区别,以及每种问题下的交叉熵损失的定义方法. 由于多分类问题的输出为属于每个类别的概率,要求概率和为1. 因此, 我们还介绍了如何利用Softmax函数,处理神经网络的输出, 使其满足损失函数的格式要求
知识点:
- 二分类和多分类
- 交叉熵损失
- PyTorch中的Softmax和交叉熵
二分类问题和多分类问题
二分类问题: 表示分类任务只有两个类别. 比如我们想要识别一幅图是否是猫, 我们一般会训练处一个分类器, 输入一副图像,输出该图像是猫的概率p. 我们可以用对p进行四舍五入,则输出结果为0或者1,这就是一个二分类问题
多分类问题: 表示分类任务有多个类别. 比如我们需要建立一个分类器,拥有分辨一堆水果图片中,哪些是橘子,哪些是苹果,哪些是香蕉.
在二分类问题中, 我们可以用max函数(if a > b return a else b) 来判断结果, 就是非黑即白. 但是在多分类的问题中, 我们就不能这样做. 我们需要引入Softmax的概念.
Softmax
在机器学习尤其是深度学习中,Softmax是个非常常用的函数, 尤其在多分类的场景中使用广泛. 他把输入映射为0-1之间的实数, 并且通过归一化保证和为1
在多分类问题中,我们需要分类器输出每种分类的概率,且为了能够比较概率之间的大小,我们还希望概率之和能够为1. 因此,我们就需要使用Softmax函数.特别是在利用神经网络解决多分类问题时, 我们一般都会将输出的最后一层,加上Softmax函数,用于数据的归一化输出
import numpy as np
def softmax(x):
return np.exp(x)/np.sum(np.exp(x))
x = np.array([2.0,1.0,0.1])
outputs = softmax(x)
print("numpy版softmax的输入:",x)
print("numpy版softmax的输出:",outputs)
print("numpy版softmax的输出之和:",outputs.sum())
当然, 我们也可以使用PyTorch中自带的Softmax函数,,完成数据的处理:
import torch
x = torch.tensor([2.0,1.0,0.1])
outputs = torch.softmax(x,dim=0)
print("torch版 softmax的输入:",x)
print("torch版 softmax的输出:",outputs)
print("torch版 softmax的输出之和:",outputs.sum())
损失函数
损失函数反映的是预测结果和实际结果之间的差距,即从预测结果到实际结果要走的距离,也就是所需要消耗的成本,故称之为损失函数.
这里让我们介绍一种常用的损失函数: 交叉熵损失.
葡萄酒的种类预测
我们希望通过葡萄酒的酒精浓度, 苹果酸浓度, 灰分浓度等独立特征, 来预测该葡萄酒的源产地. 假设数据集中有三种源产地: 英国,法国,美国.
假设这里我们建立了两个模型用以预测葡萄酒的种类. 每个模型都会输出三个值, 即某个葡萄酒来源于英国,法国和美国的概率
模型1:
序号 | 预测结果 | 预测标签 | 是否正确 |
---|---|---|---|
1 | 0.3 0.3 0.4 | 0 0 1 (美国) | 正确 |
2 | 0.3 0.4 0.3 | 0 1 0 (法国) | 正确 |
3 | 0.1 0.2 0.7 | 1 0 0 (英国) | 错误 |
从结果可以看出,模型1对于样本1样本2以非常微弱的优势判断正确. 对于样本3的判断则彻底错误
模型2:
序号 | 预测结果 | 预测标签 | 是否正确 |
---|---|---|---|
1 | 0.1 0.2 0.7 | 0 0 1 (美国) | 正确 |
2 | 0.1 0.7 0.2 | 0 1 0 (法国) | 正确 |
3 | 0.3 0.4 0.3 | 1 0 0 (英国) | 错误 |
模型2对于样本1和样本2的判断非常准确,概率比其它的结果高很多
模型2对于样本3判断错误,但是相对来说没有错得太离谱,概率只比其它结果高0.1
有了模型之后,我们需要通过损失函数判断模型在样本上的表现,那么我可以定义哪些损失函数呢?
如果使用简单的分类错误率作为损失函数,那么两个模型的分类错误率都为1/3
从结果可以看出,如果使用分类错误率来衡量两个模型的好坏,那么这两个模型的好坏程度相同.
我们从上面的结果可以看出,虽然模型1和模型2都预测错了1个,但是相对来说,模型2的预测效果更好,损失函数照理来说应该更小.因此, 我们使用分类错误率不能很好的描述模型的优劣.
为此, 我们引入了交叉熵函数用以描述模型的优劣
交叉熵损失函数
交叉熵损失函数有两种: 二分类(nn.BCELoss()) 和多分类( nn.CrossEntropyLoss()
)
loss = nn.BCELoss()
# 假设两个模型最后的预测结果相同,但是概率不同
model1_pred = torch.tensor([0.6, 0.4])
model2_pred = torch.tensor([0.9, 0.1])
# 真实结果
label = torch.tensor([1., 0.])
# 计算两种模型的损失
l1 = loss(model1_pred, label)
l2 = loss(model2_pred, label)
print(l1,l2)
结果可以看出,模型1和模型2都预测对了一条数据,预测错了一条数据.但是,由于模型1在概率差距很大的情况跟下,预测正确的.因此模型1的预测效果比模型2好,即模型1的损失应该比模型2的损失小.
在多分类任务中,我们使用nn.CrossEntropyLoss()
.
下面我们利用交叉熵来评估一下上面建立的两个葡萄酒预测模型的好坏:
loss = torch.nn.CrossEntropyLoss()
Y = torch.tensor([2,1,0])
model1_pred = torch.tensor(
[[0.3, 0.3, 0.4], # predict class 2
[0.3, 0.4, 0.3], # predict class 1
[0.1, 0.2, 0.7]]
)
model2_pred = torch.tensor(
[[0.1, 0.2, 0.7], # predict class 2
[0.1, 0.7, 0.2], # predict class 1
[0.3, 0.4, 0.3]])
l1 = loss(model1_pred,Y)
l2 = loss(model2_pred,Y)
l1,l2
从上面的损失大小可以看出, 通过交叉熵损失对模型进行评估的话,模型2的效果要优于模型1的效果, 这是复合我们的客观想法的.
综上, 这就是我们为什么使用交叉熵损失的原因.交叉熵损失函数除了考虑模型准确率之外,还将模型的鲁棒性等因素考虑了进去,能更好的评估模型的好坏, 使训练出来的模型具有更加稳定的预测准确率.
从上面的输入可以看出,交叉熵损失需要的输入是每条数据所属种类的概率,且这些概率之和为1. 说道这里, 大家应该想到之前学的Softmax函数了
实际上,我们一般无法严格的将神经网络的输出控制在0-1之间,更无法使这些值之和等于1. 因此我们一般会在神经网络的最后一层加上softmax函数.得到每种种类的概率值.然后将概率值放入交叉熵损失函数中,得到预测结果和真实结果之间的距离.
小结
本节我们以葡萄酒的分类为例,以一种简单的方式,理解交叉熵损失与其他损失的不同,以及引入交叉熵损失的原因.从模型训练的角度,引入交叉熵损失函数也是为了能够加快模型的收敛速度.