上一篇介绍了回归任务的常用损失函数,这一次介绍分类任务的常用损失函数
深度学习中的损失函数
一.分类任务
与回归任务不同,分类任务是指标签信息是一个离散值,其表示的是样本对应的类别,一般使用one-hot向量来表示类别,例如源数据中有两类,分别为猫和狗,此时可以使用数字1和数字2来表示猫和狗,但是更常用的方法是使用向量[0,1]表示猫,使用向量[1,0]表示狗。one-hot的中文释义为独热,热 的位置对应于向量中的1,所以容易理解独热的意思是指向量中只有一个位置为1,而其他位置都为0。那么使用独热编码表征类别相较于直接用标量进行表征有什么好处呢,从类别的区分性来说,两者都可以完成对不同类别的区分。但是从标量数字的性质来说,其在距离方面的诠释不如one-hot。例如现在有三个类别,分别为猫,狗和西瓜,若用标量表示可以表示为label猫=1,label狗=2,label西瓜=3,从距离上来说,以欧氏距离为例,dist(猫,狗)=1,dist(狗,西瓜)=1,dist(猫,西瓜)=2,这样会得出一个荒谬的结论,狗要比猫更像西瓜,因此用标量来区分类别是不明确的,若以独热编码表示类别,即label猫=[1,0,0],label狗=[0,1,0],label西瓜=[0,0,1],容易验证各类别之间距离都相同。
1.交叉熵损失
作为信息论基本概念之一,熵被用来衡量一个系统内信息的复杂度。一个时间包含的可能性越多,则这事件越复杂,其熵越大;若某个事件具有确定性的结果,则该事件不包含任何信息,其熵为0。
例如,假设天气状态只有下雨与晴天,明天下雨的概率是100%(P明天下雨=1),则H(明天下雨)=0,即 “明天下雨” 这件事的熵为0。对于明天下雨的概率是0%也表示同样的结论。那么什么时候明天下雨包含的信息最多,熵最大呢?我们有P(明天下雨)=0.5,则H(明天下雨)=a(a>0并且是该事件的最大熵),即完全不知道明天天气情况下,这件事包含的可能性最多,其对应的熵也是最大的。
交叉熵损失的代码如下:
代码语言:javascript复制def softmax_ce(label, pred, name):
with tf.variable_scope(name) as scope:
# 将预测值通过softmax变换为0~1概率值
pred = tf.nn.softmax(pred)
# 计算预测值的以2为底的对数值
pred = tf.math.log(pred) / tf.math.log(2.0)
# 计算预测值与真值对应位置的熵
output = -label * pred
# 对每个样本而言,将每个位置上求得的熵进行求和
# 得到的形状为[batch_size, 1]的张量
output = tf.reduce_sum(output, axis=-1)
# 计算整个batch上熵的均值
output = tf.reduce_mean(output)
2.铰链损失
Hinge loss最初在SVM中提出,通常用于最大化分类间隔,铰链损失专用于二分类问题,核心思想是着重关注尚未分类的样本,对于已经能正确分类的样本即预测标签已经是正负1的样本不做惩罚,其loss为0,对于介于-1~1的预测标签才计算损失。
代码语言:javascript复制loss=tf.losses.hinge_loss(label,pred)
3.KL散度
代码语言:javascript复制def kl_div(label, pred, name):
with tf.variable_scope(name) as scope:
# 计算真值的熵与真值和预测值的交叉熵
entro = label * tf.math.log(label 1e-10) / tf.math.log(2.0)
entro = tf.reduce_sum(entro, axis=-1)
entro = tf.reduce_mean(entro)
output = entro Loss.softmax_ce(label, pred, name='sm_ce')
return output
4.Js散度
代码语言:javascript复制def js_div(label, pred, name):
with tf.variable_scope(name) as scope:
return 0.5 * Loss.kl_div(label, (label pred) / 2, name='js1')
0.5 * Loss.kl_div(pred, (label pred) / 2, name='js2')
在实际应用中,交叉熵使用的最多。