目录

信息量

信息熵

交叉熵

TensorFlow实现


信息量

        信息是个很抽象的概念。人们常常说信息很多,或者信息较少,但却很难说清楚信息到底有多少。比如一本五十万字的中文书到底有多少信息量。直到1948年,香农提出了“信息熵”的概念,才解决了对信息的量化度量问题。信息熵这个词是Shannon(香农)从热力学中借用过来的。热力学中的热熵是表示分子状态混乱程度的物理量,分子状态越混乱,熵值越高,分子状态越稳定,熵值越低。香农用信息熵的概念来描述信源的不确定度。

        通常,一个信源发送出什么符号是不确定的,衡量它可以根据其出现的概率来度量。概率大,出现机会多,不确定性小;反之不确定性就大。比如在星期一的时候,小明告诉你明天星期二,你会觉得他脑残,因为明天是星期二是一个确定的事实,发生的概率p=1,不存在不确定性,也就是说不确定性为0,从小明的这句话中你获取不到任何信息量,也就是信息量为0;又比如小明告诉你明天是星期三,你还是会觉的他脑残,因为明天不可能是星期三,发生的概率p=0,同样也不存在不确定性,从这句话中也获取不到任何信息。但是有一天,在你买了彩票以后,小明得知你中奖的消息,然后告诉你中了1000万,你肯定会吃惊,如果扛不住可能会晕过去,说明小明的这句话信息量太大了,因为中奖的概率极低,几乎为0。上面这些例子说明的一个事实:某个事实含有的信息量和这个事实发生的概率有关,而且发生的概率越小,信息量越大,反之信息量越小,也就是信息量和发生的概率成反比。而且我们又发现两个不同的事实的信息量是可以叠加的,两个事实含有的信息量I=I(第一个事实)+I(第2个事实),I表示信息量。所以可以在数学证明,这个信息量的度量就是如下公式:

从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow

我们来用这个公式验证下上面的例子:

(1)当p=1时,从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_02

(2)当p=0时,从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_03,这条说明,当概率为0的事情发生了,它的信息量是无穷大的,这复合实际,因为概率为0的事件不可能发生,发生了,信息量当然达到没有边界。

(3)假设有两个独立事件A和B,发生的概率分别为从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_04,那么它们各自的信息量为:

从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_05从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_06

两个事件同时发生的概率为从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_07,信息量为

从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_08

满足可加性。

 

信息熵

         现在有一个不均匀的硬币,抛硬币,出现正面朝上的概率从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_09,反面朝下的概率为从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_10,假设我们抛一次硬币,结果是正面朝上,那给我们的信息量就是:

从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_11

假设刚才抛的结果是反面朝上,那此时给我的信息量是:

从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_12

因为从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_13,显然从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_14。那我们就想,抛一次硬币,平均可以给我们多少信息量呢?一个简单的想法是对这两个信息量求平均值:

从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_15

,但是你会发现,这和事实不符,因为正面朝上的概率从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_09,所以正面朝上更容易发生,如果那你抛了n次后,信息量从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_17出现的会多一些,也就是平均的信息更接近于从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_17。通过这个分析我们如下公式度量平均不确定性

从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_19

这样就合理。

这就是信息熵(Entropy),它度量了平均信息量。一般表述如下:

假设某个事件可能会出现n个结果,而概率分别为:从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_20。那么信息熵如下:

从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_21

很多时候我们对信息熵的最大值比较感兴趣。直观地,信息熵度量了系统的平均不确定性,也就是系统越不确定,信息熵越大,什么时候系统最不确定呢,当然是所有可能发生的结果的概率一样,也就是不知道发生什么样的结果。数学上可以证明

从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_22时,从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_23达到最大值从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_24

信息熵是对各种可能的信息量的概率加权,如下:

从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_25

从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_26

 

交叉熵

     前面信息熵其实度量一个概率分布的平均不确定性,交叉熵,顾名思义,考虑了两个概率分布,一个是真实的概率分布,概率分别为从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_20,另一个是非真实的概率分布   从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_28。那么交叉熵定义如下:

从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_29

事实上,使用了非真实概率分布下的信息量从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_30。下面以多分类问题解释下。

假设现在有N个样本,从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_31,它们可能属于的类别从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_32。为了方便,不妨假设样本从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_33属于类别从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_34。通过建立的模型可以预测出从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_33属于各个类别的概率为:

从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_36

它就是非真实的概率分布,是通过我们建立的模型计算出来的,而从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_33是属于类别从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_34的,概率分布为:

从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_39

这个就是真实概率分布,因为属于类别从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_34,所以第一个分量为1,其余为0,其他样本也是如此,都是有一个分量为1(所属类别对应的分量),其他分量为0。

根据交叉熵定义,对于样本从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_33的交叉熵如下:

从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_42

按照这个可以分别计算出其他样本的交叉熵

从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_43

总体样本的交叉熵如下:

从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_44

总体样本的平均交叉熵如下:

从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_45

我们在求解模型时,如果损失函数选择的是交叉熵,是做最小化交叉熵。那这是为什么呢?我们还是来看样本从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_33,它的真实类别是从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_34,而通过模型计算它属于类别从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_34的概率是从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_49,那显然,我们希望从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_49越大越好,最好是等于1,这样通过模型计算的结果就是正确的了。而样本从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_33的交叉熵如下:

从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_42

从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_49越大,对应着从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_54越小,其他样本类似,所以我们是最小化交叉熵。

 

TensorFlow实现

        有了上面的基础。现在我们来看TesorFlow的实现,它有很多形式的实现。我们选择tensorfllow 1.0.0版本中的

sequence_loss方法,他在tensorflow.contrib.seq2seq中。方法源码如下:
def sequence_loss(logits, targets, weights,
                  average_across_timesteps=True, average_across_batch=True,
                  softmax_loss_function=None, name=None):

logits就对应我们上面说的非真实分布(严格说是非真实分布的前几步,后面会详细说明),targets就是真实分布,可以理解成真实的类别,下面举例说明。

# [batch_size x sequence_length x num_decoder_symbols]
# 3,2,4
logits = tf.constant([[[1.0, 2.0, 3.0, 4.0], [5.0, 2.0, 2.0, 2.0]],
                      [[3.0, 3.0, 3.0, 3.0], [4.0, 4.0, 4.0, 4.0]],
                      [[5.0, 5.0, 5.0, 5.0], [6.0, 6.0, 6.0, 6.0]]])
# [batch_size x sequence_length]
# 3,2
targets = tf.constant([[0, 1],
                       [2, 1],
                       [3, 0]])
# [batch_size x sequence_length]
# 3,2
weights = tf.constant([[1.0, 1.0],
                       [1.0, 1.0],
                       [1.0, 1.0]])

logits:是一个三维张量,batch_size x sequence_length x num_decoder_symbols

第一个维度是批次数,对应上面说的样本数,第二个维度是序列长度,第三个维度是类别数,我们给的代码中分别是

 3,2,4

也就是3个样本,每个样本长度为2,每个样本可能所属的类别有4个(分别为0,1,2,3)

targets: 是一个2维张量,[batch_size x sequence_length]

第一个维数是批次数,第二个维度是序列长度,代码中分别是

3,2

也就是三个样本,每个样本序列长度为2,它表示的含义如下,比如第一个元素0:表示第一个样本的第一个序列所属的类别是0.

weights:它是各个样本的权重,这里我们不考虑,所以设置成了相同的权重1,实际是从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_55

下面来看下计算过程。logits还不是真正的非真实概率,在sequence_loss方法内部,首先进行softmax操作,将其转换为概率:

比如对于第一个样本[1.0,2.0,3.0,4.0],经过softmax函数计算后结果如下:

从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_56

其中从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_57

它才是对应上面的非真实概率。下面就可以计算交叉熵了,从上面的交叉熵定义来看,只需要计算对应类别的信息量即可,

比如对于targets的第一个样本的第一个序列0来说,它属于类别0,而该样本属于类别0的概率为

从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_58

交叉熵为:

从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_59

targets的第一个样本的第二个序列是1,它的非真实分布如下:

可以通过logits的第一个样本的第二个序列[5.0, 2.0, 2.0, 2.0]就算得到:

从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_60

从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_61

属于类别1的非真实概率为

从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_62

交叉熵为:

从信息量到信息熵再到交叉熵(Cross Entropy)及TensorFlow实现细节_tensorflow_63

其他样本类似计算。最后可以得到总体样本交叉熵,我们将上面的过程整理如下:

(1)对logits计算softmax

[[0.0320586  0.08714432 0.23688284 0.6439143 ]
 [0.8700486  0.04331717 0.04331717 0.04331717]
 [0.25       0.25       0.25       0.25      ]
 [0.25       0.25       0.25       0.25      ]
 [0.25       0.25       0.25       0.25      ]
 [0.25       0.25       0.25       0.25      ]]

(2)计算单个样本的交叉熵(对上面的结果计算log)

[[-3.4401896  -2.4401896  -1.4401896  -0.44018966]
 [-0.13920623 -3.1392064  -3.1392064  -3.1392064 ]
 [-1.3862944  -1.3862944  -1.3862944  -1.3862944 ]
 [-1.3862944  -1.3862944  -1.3862944  -1.3862944 ]
 [-1.3862944  -1.3862944  -1.3862944  -1.3862944 ]
 [-1.3862944  -1.3862944  -1.3862944  -1.3862944 ]]

(3)根据targets的真实分类,对每个样本选择交叉熵

[3.4401896 3.1392062 1.3862944 1.3862944 1.3862944 1.3862944]

(4)计算总体平均交叉熵

2.0207622

测试代码如下:

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

from tensorflow.python.framework import ops
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import nn_ops
from tensorflow.python.ops import math_ops
import tensorflow.contrib.seq2seq as seq2seq
import tensorflow as tf

# [batch_size x sequence_length x num_decoder_symbols]
# 3,2,4
logits = tf.constant([[[1.0, 2.0, 3.0, 4.0], [5.0, 2.0, 2.0, 2.0]],
                      [[3.0, 3.0, 3.0, 3.0], [4.0, 4.0, 4.0, 4.0]],
                      [[5.0, 5.0, 5.0, 5.0], [6.0, 6.0, 6.0, 6.0]]])
# [batch_size x sequence_length]
# 3,2
targets = tf.constant([[0, 1],
                       [2, 1],
                       [3, 0]])
# [batch_size x sequence_length]
# 3,2
weights = tf.constant([[1.0, 1.0],
                       [1.0, 1.0],
                       [1.0, 1.0]])
with tf.Session() as sess:
    # 2.0207622
    loss = sess.run(seq2seq.sequence_loss(logits=logits, targets=targets, weights=weights))
    print('final-loss=', loss)
    # 4
    num_classes = sess.run(array_ops.shape(logits)[2])
    # print('num_classes=', num_classes)
    # 0维元素4个,其他维度拉平
    probs_flat = sess.run(array_ops.reshape(logits, [-1, num_classes]))
    print('probs_flat=', probs_flat)
    # targets= [0 1 2 1 3 0]
    targets = sess.run(array_ops.reshape(targets, [-1]))
    # print('targets=', targets)
    crossent = sess.run(nn_ops.sparse_softmax_cross_entropy_with_logits(labels=targets, logits=probs_flat))
    print(sess.run(tf.nn.softmax(probs_flat)))
    print(sess.run(tf.log(tf.nn.softmax(probs_flat))))
    print('crossent=', crossent)
    crossent = sess.run(crossent * array_ops.reshape(weights, [-1]))
    print('weights-crossent=', crossent)
    crossent = sess.run(math_ops.reduce_sum(crossent))
    print('reduce_sum-crossent=', crossent)
    total_size = sess.run(math_ops.reduce_sum(weights))
    total_size += 1e-12  # to avoid division by 0 for all-0 weights
    crossent /= total_size
    print('final-crossent=', crossent)

 

 

更多文章请关注《万象专栏》