You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyTorch中KL散度为何出现负值?

解决PyTorch中KL散度计算出现负值的问题

你的问题核心是误用了正态分布的采样值作为KL散度的输入,而非使用分布的概率密度/对数概率,这直接导致计算结果不符合KL散度非负的理论特性。

错误原因分析

你代码中torch.empty(10).normal_(...)生成的是正态分布的随机样本点,不是分布的概率密度值:

  • 这些样本可能出现负值,不满足概率分布非负的要求;
  • 样本没有经过归一化,不满足概率分布求和/积分等于1的条件;
  • 直接对样本取对数后传入F.kl_div,完全不符合函数对输入的定义。

修正后的代码

推荐使用PyTorch内置的torch.distributions模块来直接计算KL散度,既简洁又避免手动实现的错误:

import torch 
from torch.distributions import Normal

x_axis_kl_div_values = []
for epoch in range(200):
    # 随机生成两个正态分布的均值
    mu1 = torch.randint(1, 50, (1,)).item()
    mu2 = torch.randint(1, 50, (1,)).item()
    
    # 定义正态分布对象
    dist1 = Normal(mu1, 0.5)
    dist2 = Normal(mu2, 0.5)
    
    # 直接计算两个分布的KL散度 D_KL(dist1 || dist2)
    kl_divergence = torch.distributions.kl.kl_divergence(dist1, dist2)
    
    x_axis_kl_div_values.append(kl_divergence.item())

print(x_axis_kl_div_values)

手动计算的替代方案(可选)

如果你需要手动实现数值积分的方式计算KL散度,需确保输入是合法的概率密度:

import torch 
from torch.distributions import Normal

x_axis_kl_div_values = []
for epoch in range(200):
    mu1 = torch.randint(1, 50, (1,)).item()
    mu2 = torch.randint(1, 50, (1,)).item()
    dist1 = Normal(mu1, 0.5)
    dist2 = Normal(mu2, 0.5)
    
    # 取足够多的采样点覆盖分布范围,保证积分精度
    samples = torch.linspace(min(mu1, mu2)-3, max(mu1, mu2)+3, 1000)
    log_p = dist1.log_prob(samples)
    p = log_p.exp()  # 获取dist1的概率密度
    log_q = dist2.log_prob(samples)
    
    # 数值积分计算KL散度:D_KL(p||q) = ∫p(x)log(p(x)/q(x))dx
    kl_divergence = (p * (log_p - log_q)).sum() * (samples[1] - samples[0])
    
    x_axis_kl_div_values.append(kl_divergence.item())

print(x_axis_kl_div_values)

关键注意点

  • F.kl_div的输入要求:第一个参数是对数概率,第二个参数是概率,两者都必须是合法的分布(非负、归一化);
  • 对于连续分布,KL散度需要通过积分计算,不能直接用随机样本代替概率密度;
  • 使用torch.distributions模块是处理概率分布相关计算的最优方式,它内置了多种分布的KL散度实现,计算准确且高效。

内容的提问来源于stack exchange,提问作者Penguin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 20:05:27