KL散度,全称Kullback-Leibler散度,也被称为相对熵(Relative Entropy)。它是信息论和概率论中的一个非对称测度,用于度量两个概率分布之间的差异。
对于离散概率分布P和Q,KL散度定义如下:
D
K
L
(
P
∣
∣
Q
)
=
Σ
P
(
i
)
l
o
g
(
P
(
i
)
/
Q
(
i
)
)
D_{KL}(P||Q) = Σ P(i) log(P(i) / Q(i))
DKL(P∣∣Q)=ΣP(i)log(P(i)/Q(i))
对于连续概率分布P和Q,KL散度定义如下:
D
K
L
(
P
∣
∣
Q
)
=
∫
P
(
x
)
l
o
g
(
P
(
x
)
/
Q
(
x
)
)
d
x
D_{KL}(P||Q) = ∫ P(x) log(P(x) / Q(x)) dx
DKL(P∣∣Q)=∫P(x)log(P(x)/Q(x))dx
在这两个公式中,Σ表示对所有可能的事件求和,∫表示对所有可能的事件求积分。
KL散度的值总是大于或等于零。当两个分布完全相同时,KL散度为零。KL散度越大,表示两个概率分布之间的差异越大。
需要注意的是,KL散度是不对称的,也就是说, D K L ( P ∣ ∣ Q ) D_{KL}(P||Q) DKL(P∣∣Q)不等于 D K L ( Q ∣ ∣ P ) D_{KL}(Q||P) DKL(Q∣∣P)。这是因为在计算过程中,我们使用的是P的概率分布来对事件进行加权。
在机器学习中,KL散度通常用于度量模型预测的概率分布与真实概率分布之间的差异。例如,在自然语言处理中,可以用KL散度来衡量语言模型生成的文本与人类写作的文本在语言风格上的差异。
def compute_kl_loss(p, q, pad_mask=None):
p_loss = F.kl_div(F.log_softmax(p, dim=-1), F.softmax(q, dim=-1), reduction='none')
q_loss = F.kl_div(F.log_softmax(q, dim=-1), F.softmax(p, dim=-1), reduction='none')
# pad_mask is for seq-level tasks
if pad_mask is not None:
p_loss.masked_fill_(pad_mask, 0.)
q_loss.masked_fill_(pad_mask, 0.)
# You can choose whether to use function "sum" and "mean" depending on your task
p_loss = p_loss.sum()
q_loss = q_loss.sum()
loss = (p_loss + q_loss) / 2
return loss
这段代码定义了一个函数compute_kl_loss,它计算了两个概率分布p和q之间的KL散度的均值。KL散度是一种度量两个概率分布之间差异的方法。以下是函数中每行代码的解释:
p_loss = F.kl_div(F.log_softmax(p, dim=-1), F.softmax(q, dim=-1), reduction=‘none’):计算从p到q的KL散度。F.log_softmax(p, dim=-1)将p中的元素进行log softmax操作,使得p中的元素可以表示概率。F.softmax(q, dim=-1)同样是将q中的元素转换成概率。F.kl_div计算两个概率分布之间的KL散度。参数reduction='none’表示不对结果进行降维,即保持原有的维度。
Gamma公式展示
Γ
(
n
)
=
(
n
−
1
)
!
∀
n
∈
N
\Gamma(n) = (n-1)!\quad\forall n\in\mathbb N
Γ(n)=(n−1)!∀n∈N 是通过 Euler integral
Γ
(
z
)
=
∫
0
∞
t
z
−
1
e
−
t
d
t
.
\Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,.
Γ(z)=∫0∞tz−1e−tdt.
q_loss = F.kl_div(F.log_softmax(q, dim=-1), F.softmax(p, dim=-1), reduction=‘none’):计算从q到p的KL散度。这一步的操作和上一步类似,只是将p和q交换了位置。这是因为KL散度是不对称的,即
D
K
L
(
P
∣
∣
Q
)
不等于
D
K
L
(
Q
∣
∣
P
)
。
D_{KL}(P||Q)不等于D_{KL}(Q||P)。
DKL(P∣∣Q)不等于DKL(Q∣∣P)。
if pad_mask is not None: p_loss.masked_fill_(pad_mask, 0.); q_loss.masked_fill_(pad_mask, 0.):如果提供了pad_mask,则将p_loss和q_loss中对应pad_mask位置的元素值替换为0。这是在处理序列任务时,忽略padding位置的损失。
p_loss = p_loss.sum(); q_loss = q_loss.sum():将p_loss和q_loss中所有元素的值加起来,得到总的损失。
loss = (p_loss + q_loss) / 2:计算p_loss和q_loss的均值。
return loss:返回计算得到的损失。
这个函数可以用于训练过程中,比如在自编码器或者生成模型中,使用KL散度作为损失函数进行优化。