机器学习:Kullback-Leibler Divergence(KL散度)以及R-dropout函数的通俗讲解

KL散度,最早是从信息论里演化而来的,信息熵的定义如下:
H = − ∑ i = 1 N p ( x i ) l o g ( p ( x i ) ) H = -\sum\limits_{i=1}^{N}p(x_{i})log(p(x_{i})) H=i=1Np(xi)log(p(xi))
其中 p ( x i ) p(x_{i}) p(xi)表示事件 x i x_{i} xi发生的概率,信息熵反映的就是要表示一个概率分布需要的平均信息量。
定义KL散度值
D K L ( p ∣ ∣ q ) = ∑ i = 1 N p ( x i ) ( l o g p ( x i ) − l o g q ( x i ) ) D_{KL}(p||q) = \sum\limits_{i=1}^{N}p(x_{i})(logp(x_{i})-logq(x_{i})) DKL(pq)=i=1Np(xi)(logp(xi)logq(xi))
或者表示成下面这种形式:
D K L ( p ∣ ∣ q ) D_{KL}(p||q) DKL(pq)表示的就是概率p与概率q之间的差异,散度越小,概率p与概率q之间越接近,那么估计的概率分布与真实的概率分布也就越接近。
理解了KL散度,它计算出来的是两者的概率差,也就是说KL散度可以作为一种损失,来计算两者的概率差异

R-dropout操作
在介绍R-dropout操作之前,首先需要介绍dropout操作
dropout是训练和预测使用方法不同的一个对应的网络层
在训练的时候dropout使用的是以p概率将对应的元素变为0,而剩下1-p的概率为1/(1-p)。
通俗的说,比如使用dropout的概率为0.2,则需要将现在的数据(占比0.8)除以0.8得到最后的结果,这样输出的期望才能够与原来的期望相同,否则输出的期望与实际的结果会有一定的差异。
但是在测试的时候,需要使用整个训练好的模型,因此不需要dropout的网络层操作。
dropout对应的神经网络图注意使用dropout的神经网络一般在神经元较多的神经网络之中,神经元较少的神经网络一般不需要使用dropout操作,因为神经元较多的层更容易让整个神经网络进行预测的结果产生过拟合。
理解了KL散度和dropout操作的内容,我们就能够理解R-dropout进行的操作
不同模型训练经过不同的dropout可能会产生较大的差异,而我们这里通过KL散度将这些差异缩小,从而能够达到预测较准的情况
也就是说新的损失函数内容为: L n e w = L s o f t m a x + α L K L L_{new} = L_{softmax}+\alpha L_{KL} Lnew=Lsoftmax+αLKL
这里放入R-dropout具体的代码进行讲解:

from tensorflow.keras.losses import kullback_leibler_divergence as kld
def categorical_crossentropy_with_rdrop(y_true, y_pred,alpha=1):
    """配合上述生成器的R-Drop Loss
    其实loss_kl的除以4,是为了在数量上对齐公式描述结果。
    """
    loss_ce = K.sparse_categorical_crossentropy(y_true, y_pred)  # 原来的loss
    #这里调用K.Sparse,一部分是常规的交叉熵
    loss_kl = kld(y_pred[::2], y_pred[1::2]) + kld(y_pred[1::2], y_pred[::2])
    #另一部分是两个模型的对称KL散度
    return K.mean(loss_ce) + K.mean(loss_kl) / 4 * alpha

这里首先调用的是交叉熵损失函数

loss_ce = K.sparse_categorical_crossentropy(y_true,y_pred)

获得对应的交叉熵损失的内容
接着调用对称KL散度的内容

loss_kl = kld(y_pred[::2],y_pred[1::2])+kld(y_pred[1::2],y_pred[::2])

这里的y_pred[::2]代表隔两个取出对应的数值,y_pred[1::2]代表从第一个位置开始隔两个取出对应的数值,也就是说这里的[0,2,4,6,8,…]为一组,[1,3,5,7,…]为一组,第一个KL散度让[0,2,4,6,8…]尽量往[1,3,5,7,…]去靠近,计算[0,2,4,6,8…]位置与[1,3,5,7…]位置的KL散度差,第二个KL散度让[1,3,5,7,…]尽量往[2,4,6,8,…]去靠近,计算[1,3,5,7…]到[2,4,6,8,…]位置的KL散度差,这个作为正则项进行调和两者的数值差,从而使得在收敛的时候不同的dropout算出来的结果尽量前去靠近。
另外一种配合交叉熵的写法

def crossentropy_with_rdrop(y_true, y_pred, alpha=4):
    """配合R-Drop的交叉熵损失
    """
    y_true = K.reshape(y_true, K.shape(y_pred)[:-1])
    y_true = K.cast(y_true, 'int32')
    loss1 = K.mean(K.sparse_categorical_crossentropy(y_true, y_pred))
    loss2 = kld(y_pred[::2], y_pred[1::2]) + kld(y_pred[1::2], y_pred[::2])
    return loss1 + K.mean(loss2) / 4 * alpha

单用交叉熵与交叉熵+R-dropout的区别
交叉熵的训练目标是:让目标类的得分大于非目标类的得分,这样模型就能正确地把目标类预测出来了,也就是说,如果只有交叉熵这一项,模型的训练结果顶多是:不同的Dropout下,目标类的得分都大于非目标类的得分
而不能做到:不同的Dropout下,每个类的得分一致。
假如目标类为第一个类别,那么预测结果是[0.5,0.2,0.3]或[0.5,0.3,0.2]对它来说都没有区别。但对于KL散度项每个类的得分都要参与计算,[0.5,0.2,0.3]或[0.5,0.3,0.2]是有非零损失的。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值