张春成
2022/10/13阅读:41主题:默认主题
信息论中的各种熵
信息论中的各种熵
信息论中有各种熵的定义,本文用一组例子说明熵的计算方式。以及通过熵对信号进行排序,我们可能会得到怎样的结果。
Shannon Entropy
这是最基本的熵,它从概率的方式定义了一个符号可能提供的“信息量”
信息量的期望就是信息熵,也以它的提出者 Shannon 命名
当我们有了两个变量,这两个变量就有了联合概率
对于联合概率,我们同样可以依定义求它的信息熵,称为联合熵
这两个变量同样可以有条件概率
从条件概率求得的信息熵称为条件熵
由于它显得过于复杂,我们引入所谓的互信息的概念
这里不加证明地给出结论
不难发现,互信息是一个变量提供的熵,减去它在已知另一个变量的值时,它还能够提供的熵。前者永远大于后者,二者有包含关系如下

KL Divergence
由于熵的计算方式可知,它是对信息量的度量。但机器学习问题往往是这样的问题
已知某个变量的分布,它能否用于预测另外的变量
在这种情况下,如果仅仅用条件熵或互信息来约束的话,会遇到一些困难,比如不方便计算梯度,再比如不方便获取条件概率等等。
另外,在真实场景中,我们也往往并不关心模型在整个空间上表现,而只关心它在特定范围内的表现。因此交叉熵应运而生
不难发现,它的上限是信号 p 的 Shannon Entropy。因此将它们的差值定义为 KL 散度,散度越小代表两个分布越接近。
熵的比较
下面我将提供一段可用的代码,用于直观说明熵的意义和计算方式。
首先,用 Perlin 噪声生成一组随机信号,波形图以及任意两个信号的联合概率密度函数如下图所示。可以看到,联合概率密度函数很少能够覆盖整个空间,因为你不能指望 2n 个点覆盖 n平方的范围。
.png)
.png)
之后,计算它们的各种熵,其中熵最大和最小的信号以及它们的数值分布如下图所示,熵越大,代表数值越难以预测。
.png)
.png)
接下来,选择熵最高的信号,将它他其他信号画在一起,为了方便展示,分别用热度图和空间曲线分别展示这些信号,从而直观地观察这些信号之间的差异。
信号排序原则分别是联合熵、互信息和交叉熵。不难发现,通过交叉熵排序找到的交叉熵更高的信号,它们之间的“相似性”也更高。
.png)

.png)

.png)

计算三种熵的代码如下,值得说明的是,计算概率和联合概率的方法是网格法,它的精度受限于 bins 的选择,本文的数值是 100。
另外,为了避免信号差异过大,将信号的范围限制在 0 和 1 之间。
# Compute probability
pdata = []
for d in tqdm(data, 'Prob.'):
a, b = np.histogram(d, bins=bins)
a = a.astype(np.float32) / len(d)
pdata.append(a)
pdata = np.array(pdata)
px.imshow(pdata, title='Prob.').show()
# Compute joint probability
p2data = []
for j in tqdm(range(repeat), 'Prob.2'):
p2data.append([e for e in range(repeat)])
for k in range(repeat):
a, b, c = np.histogram2d(data[j], data[k], bins=bins)
a /= np.sum(a)
p2data[j][k] = a
p2data = np.array(p2data)
px.imshow(p2data[0][1], title='Prob.2', x=bins[:-1], y=bins[:-1], color_continuous_scale='dense').show()
p2data.shape
# Compute entropy
entropy = []
for p in tqdm(pdata, 'Entropy'):
a, b = np.histogram(p, bins=bins)
e = scipy.stats.entropy(a)
entropy.append(e)
px.scatter(entropy, title='Entropy').show()
# Compute joint entropy
joint_entropy = np.zeros((repeat, repeat))
for j in tqdm(range(repeat), 'Joint Entropy'):
for k in range(repeat):
p = p2data[j][k].flatten()
e = scipy.stats.entropy(p)
joint_entropy[j][k] = e
pass
px.imshow(joint_entropy, title='Joint Entropy').show()
# Compute mutual information
mutual_information = np.zeros((repeat, repeat))
for j in tqdm(range(repeat), 'Mutual Information'):
for k in range(repeat):
p1 = pdata[j][:, np.newaxis]
p2 = pdata[k][np.newaxis, :]
pxy = np.matmul(p1, p2)
pp = p2data[j, k]
m = pp != 0
pxy = pxy[m]
pp = pp[m]
s = pp * np.log(pxy / pp)
mutual_information[j][k] = -np.sum(s)
px.imshow(mutual_information, title='Mutual Information').show()
# Compute cross entropy
cross_entropy = np.zeros((repeat, repeat))
for j in tqdm(range(repeat), 'Cross Entropy'):
for k in range(repeat):
p1 = pdata[j]
p2 = pdata[k]
m = p2 != 0
p1 = p1[m]
p2 = p2[m]
s = p1 * np.log(p2)
cross_entropy[j][k] = -np.sum(s)
px.imshow(cross_entropy, title='Cross Entropy').show()
作者介绍