先附上官方文档说明:https://pytorch.org/docs/stable/nn.functional.html
torch.nn.functional.kl_div(input, target, size_average=None, reduce=None, reduction='mean')
Parameters
input – Tensor of arbitrary shape
target – Tensor of the same shape as input
size_average (bool, optional) – Deprecated (see reduction). By default, the losses are averaged over each loss element in the batch. Note that for some losses, there multiple elements per sample. If the field size_average is set to False, the losses are instead summed for each minibatch. Ignored when reduce is False. Default: True
reduce (bool, optional) – Deprecated (see reduction). By default, the losses are averaged or summed over observations for each minibatch depending on size_average. When reduce is False, returns a loss per batch element instead and ignores size_average. Default: True
reduction (string, optional) – Specifies the reduction to apply to the output: 'none' | 'batchmean' | 'sum' | 'mean'. 'none': no reduction will be applied 'batchmean': the sum of the output will be divided by the batchsize 'sum': the output will be summed 'mean': the output will be divided by the number of elements in the output Default: 'mean'
然后看看怎么用:
第一个参数传入的是一个对数概率矩阵,第二个参数传入的是概率矩阵。这里很重要,不然求出来的kl散度可能是个负值。
比如现在我有两个矩阵X, Y。因为kl散度具有不对称性,存在一个指导和被指导的关系,因此这连个矩阵输入的顺序需要确定一下。
举个例子:
如果现在想用Y指导X,第一个参数要传X,第二个要传Y。就是被指导的放在前面,然后求相应的概率和对数概率就可以了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
import torch import torch.nn.functional as F # 定义两个矩阵 x = torch.randn(( 4 , 5 )) y = torch.randn(( 4 , 5 )) # 因为要用y指导x,所以求x的对数概率,y的概率 logp_x = F.log_softmax(x, dim = - 1 ) p_y = F.softmax(y, dim = - 1 ) kl_sum = F.kl_div(logp_x, p_y, reduction = 'sum' ) kl_mean = F.kl_div(logp_x, p_y, reduction = 'mean' ) print (kl_sum, kl_mean) >>> tensor( 3.4165 ) tensor( 0.1708 ) |
补充:pytorch中的kl散度,为什么kl散度是负数?
F.kl_div()或者nn.KLDivLoss()是pytroch中计算kl散度的函数,它的用法有很多需要注意的细节。
输入
第一个参数传入的是一个对数概率矩阵,第二个参数传入的是概率矩阵。并且因为kl散度具有不对称性,存在一个指导和被指导的关系,因此这连个矩阵输入的顺序需要确定一下。如果现在想用Y指导X,第一个参数要传X,第二个要传Y。就是被指导的放在前面,然后求相应的概率和对数概率就可以了。
所以,一随机初始化一个tensor为例,对于第一个输入,我们需要先对这个tensor进行softmax(确保各维度和为1),然后再取log;对于第二个输入,我们需要对这个tensor进行softmax。
1
2
3
4
5
6
7
8
9
10
11
|
import torch import torch.nn.functional as F a = torch.tensor([[ 0 , 0 , 1.1 , 2 , 0 , 10 , 0 ],[ 0 , 0 , 1 , 2 , 0 , 10 , 0 ]]) log_a = F.log_softmax(a) b = torch.tensor([[ 0 , 0 , 1.1 , 2 , 0 , 7 , 0 ],[ 0 , 0 , 1 , 2 , 0 , 10 , 0 ]]) softmax_b = F.softmax(b,dim = - 1 ) kl_mean = F.kl_div(log_a, softmax_b, reduction = 'mean' ) print (kl_mean) |
为什么KL散度计算出来为负数
先确保对第一个输入进行了softmax+log操作,对第二个参数进行了softmax操作。不进行softmax操作就可能为负。
然后查看自己的输入是否是小数点后有很多位,当小数点后很多位的时候,pytorch下的softmax会产生各维度和不为1的现象,导致kl散度为负,如下所示:
1
2
3
4
5
6
7
8
9
10
|
a = torch.tensor([[ 0. , 0 , 0.000001 , 0.0000002 , 0 , 0.0000007 , 0 ]]) log_a = F.log_softmax(a,dim = - 1 ) print ( "log_a:" ,log_a) b = torch.tensor([[ 0. , 0 , 0.000001 , 0.0000002 , 0 , 0.0000007 , 0 ]]) softmax_b = F.softmax(b,dim = - 1 ) print ( "softmax_b:" ,softmax_b) kl_mean = F.kl_div(log_a, softmax_b,reduction = 'mean' ) print ( "kl_mean:" ,kl_mean) |
输出如下,我们可以看到softmax_b的各维度和不为1:
以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/Answer3664/article/details/106265132