python - 香农熵的导数是什么?
问题描述
我有以下简单的 python 函数,它根据香农的信息理论计算单个输入 X 的熵:
import numpy as np
def entropy(X:'numpy array'):
_, frequencies = np.unique(X, return_counts=True)
probabilities = frequencies/X.shape[0]
return -np.sum(probabilities*np.log2(probabilities))
a = np.array([1., 1., 1., 3., 3., 2.])
b = np.array([1., 1., 1., 3., 3., 3.])
c = np.array([1., 1., 1., 1., 1., 1.])
print(f"entropy(a): {entropy(a)}")
print(f"entropy(b): {entropy(b)}")
print(f"entropy(c): {entropy(c)}")
输出如下:
entropy(a): 1.4591479170272446
entropy(b): 1.0
entropy(c): -0.0
但是,我还需要计算导数dx
:
d熵/dx
这不是一件容易的事,因为主要公式
-np.sum(概率*np.log2(概率))
接受probabilities
,而不是x
值,因此不清楚如何区分dx
。
有谁知道如何做到这一点?
解决方案
解决这个问题的一种方法是使用有限差分来数值计算导数。
在这种情况下,我们可以定义一个小常数来帮助我们计算数值导数。此函数采用单参数函数并计算其对 input 的导数x
:
ε = 1e-12
def derivative(f, x):
return (f(x + ε) - f(x)) / ε
为了使我们的工作更容易,让我们定义一个计算熵的最内层运算的函数:
def inner(x):
return x * np.log2(x)
回想一下,和的导数是导数的和。因此,真正的导数计算发生在inner
我们刚刚定义的函数中。
因此,熵的数值导数为:
def numerical_dentropy(X):
_, frequencies = np.unique(X, return_counts=True)
probabilities = frequencies / X.shape[0]
return -np.sum([derivative(inner, p) for p in probabilities])
我们能做得更好吗?我们当然可以!这里的关键见解是产品规则:(f g)' = fg' + gf'
、 wheref=x
和g=np.log2(x)
。(另请注意d[log_a(x)]/dx = 1/(x ln(a))
。)
因此,分析熵可以计算为:
import math
def dentropy(X):
_, frequencies = np.unique(X, return_counts=True)
probabilities = frequencies / X.shape[0]
return -np.sum([(1/math.log(2, math.e) + np.log2(p)) for p in probabilities])
使用样本向量进行测试,我们有:
a = np.array([1., 1., 1., 3., 3., 2.])
b = np.array([1., 1., 1., 3., 3., 3.])
c = np.array([1., 1., 1., 1., 1., 1.])
print(f"numerical d[entropy(a)]: {numerical_dentropy(a)}")
print(f"numerical d[entropy(b)]: {numerical_dentropy(b)}")
print(f"numerical d[entropy(c)]: {numerical_dentropy(c)}")
print(f"analytical d[entropy(a)]: {dentropy(a)}")
print(f"analytical d[entropy(b)]: {dentropy(b)}")
print(f"analytical d[entropy(c)]: {dentropy(c)}")
执行时,它给了我们:
numerical d[entropy(a)]: 0.8417710972707937
numerical d[entropy(b)]: -0.8854028621385623
numerical d[entropy(c)]: -1.4428232973189605
analytical d[entropy(a)]: 0.8418398787754222
analytical d[entropy(b)]: -0.8853900817779268
analytical d[entropy(c)]: -1.4426950408889634
作为奖励,我们可以使用自动微分库测试这是否正确:
import torch
a, b, c = torch.from_numpy(a), torch.from_numpy(b), torch.from_numpy(c)
def torch_entropy(X):
_, frequencies = torch.unique(X, return_counts=True)
frequencies = frequencies.type(torch.float32)
probabilities = frequencies / X.shape[0]
probabilities.requires_grad_(True)
return -(probabilities * torch.log2(probabilities)).sum(), probabilities
for v in a, b, c:
h, p = torch_entropy(v)
print(f'torch entropy: {h}')
h.backward()
print(f'torch derivative: {p.grad.sum()}')
这给了我们:
torch entropy: 1.4591479301452637
torch derivative: 0.8418397903442383
torch entropy: 1.0
torch derivative: -0.885390043258667
torch entropy: -0.0
torch derivative: -1.4426950216293335
推荐阅读
- javascript - 为多个下拉选择呈现标签
- typescript - 创建对象时如何为键编写类型?
- react-native - expo-image-picker 不处理网络浏览器中的取消事件?
- python - 无法正确处理 dict
- node.js - 如何修复“无法编译 Node.js 应用程序”?
- angular - PKCE 的 OAuth 授权代码流不会触发 /token API 来获取令牌
- openshift - 在 RedHat OpenShift 4.6 中将 SCC 添加到组时,组没有得到更新
- java - 如何使用具有多个相同字符的字符拆分字符串?
- php - Codeigniter 3 不支持 allowed_types tud
- javascript - 想要删除以前附加的表