数据的压缩编码

现在我们要开始讨论熵的意义。讨论的核心就是数据的压缩编码。

首先我们要严格地定义编码。在这里,我们默认用二进制进行编码。事实上,我们将要证明的所有结论对于一般的DD进制而言都是成立的。(我们的证明并不是依赖于熵中对数的底数的。在信息论中底数并不重要。)我们定义对随机变量XX的编码就是X{0,1}X{0,1}的映射CCXX的每个取值对应着一个有限01串。进一步,如果CC是一个单射,也即如果任意不同的取值对应不同的01串,我们就称CC是一个nonsingular(非奇异的)的编码方式。对于nonsingular的编码方式,只需要在相邻字符间加上逗号或其它分隔符,就能够通过编码后的串唯一解码出原始的字符串。但在实际应用中,使用分隔符并不是一种高效的做法。如果一种编码方式无需分隔符就可以唯一解码,那么我们称这种编码方式是自带标点(Self-punctuating)的或唯一可解(Uniquely Decodable)的。

Kraft Inequality

前缀码(Prefix Code)

一种常见的唯一可解码称为前缀码(Prefix Code)或即时码(Instantaneous Code),其中所有编码后的字符不存在其中一个串是另一个串的前缀的情况,那么我们无需分隔符就可以唯一的解码——前缀码是唯一可解码。

当我们要求编码方式必须是前缀码时,我们就不能总是采用最短的可用字符串了。例如如果同时采用0011作为编码,那就不可能使用任何其它串了。也就是说,对于|X|=n|X|=n,如果把需要编码的字符编码后的长度排成一列1,2,,n1,2,,n,这些长度肯定要满足某些约束。例如当|X|=3|X|=3时,{1,1,2}{1,1,2}肯定不是一个可行的前缀码编码方式,而{1,2,2}{1,2,2}却是可行的。

思考编码问题的一个常见方法是把编码放到前缀树上去思考。在二进制下,编码的前缀树是一棵二叉树。记maxmax是编码最长的字符,那么这一定是一棵深度不超过maxmax的树。对于前缀树而言,只有叶节点能够作为编码的终点。前缀树可以看作去除了某些子树后的满二叉树。一棵深度为maxmax的满二叉树,那么第kk层恰好有2k2k个节点,在第maxmax层有2max2max个节点。对于长度为ii的编码,由于它一定没有后代,所以相较于满二叉树在第maxmax层会损失共2maxi2maxi个节点。而每个ii的后代都是互不重叠的,因此在最后一层上总的损失节点数就是ni=12maxini=12maxi,它一定不超过2max2max。这样我们就得到了不等式ni=12i1ni=12i1。这称为Kraft Inequality。

而一旦我们得到了一个满足Kraft Inequality的序列1,,n1,,n,那么我们可以直接在01前缀树上构造出一个合法的前缀编码。把1,,n1,,n从小到大排序,从满二叉树出发,依次找到字典序最小的深度为ii的节点,移除它的后代,不断重复如上操作即可。这说明Kraft Inequality是紧的!它恰好刻画了前缀码长度需要满足的充要条件。

另一种理解Kraft Inequality的方法是二进制小数。假设第ii个二进制编码记为y1y2yiy1y2yi,我们可以把它与二进制小数0.y1y2yi0.y1y2yi对应。由于不存在与它有相同前缀的编码,我们可以视为这个小数独占了区间[0.y1y2yi,0.y1y2yi+2i)[0.y1y2yi,0.y1y2yi+2i)。这恰好是一个长度为2i2i的区间。由于所有编码对应的区间互不重叠,一定有ni=12i1ni=12i1。这样我们就再一次得到了Kraft Inequality。而在这种证明中,即便编码数量是无穷(但是可数)的,这个不等式依然成立。因此,我们得到了更广义的在可数意义下的Kraft Inequality。

一般情形的唯一可解码

事实上,我们即将证明Kraft Inequality对于任何唯一可解码都是成立的。并且显然,任何前缀码都是唯一可解的,所以我们得到了以下基于Kraft Inequality的定理:任何唯一可解码的编码长度序列1,,n1,,n都要满足ni=12i1ni=12i1,并且只要满足就能被构造出来。

对这个定理的证明需要用到巧妙的技巧。要证ni=12i1ni=12i1,我们任取一个正整数kk,对左式做kk次方,得到(ni=12i)k(ni=12i)k,展开后逐项相乘得到x1XxkX2(x1)2(xk)=x1XxkX2kj=1(xj)x1XxkX2(x1)2(xk)=x1XxkX2kj=1(xj)。这等价于,我们对kk个随机变量XX可能形成的随机串xkxk编码,每个xkxk对应着长度(xk)=lj=1(xj)(xk)=lj=1(xj),也即xkXk2(xk)xkXk2(xk)。设1,,n1,,n中最大值为maxmax,显然最长的随机串的长度也不超过kmkm。按长度枚举所有的随机串,设长度为mm的随机串共有a(m)a(m)个,因为所有这些随机串都是唯一可解的,因此a(m)2ma(m)2m。则xkXk2(xk)=kmaxm=1a(m)2mxkXk2(xk)=kmaxm=1a(m)2mkmaxm=12m2m=kmaxkmaxm=12m2m=kmax。于是我们得到了ni=12i(kmax)1kni=12i(kmax)1k。这对于任何正整数kk都成立,因此在k+k+时也成立,而limk(kmax)1k=limkk1klimk1kmax=11=1limk(kmax)1k=limkk1klimk1kmax=11=1,证毕。

如果我们允许XX的大小是可数无穷的,那么我们的证明在最后一步就出错了,因为我们假设了maxmax是有限的。但是我们只需直接利用有限的结论与紧性,就能证明Kraft Inequality对于无限样本空间的随机变量也是依然成立的:假设|X|=|X|=,那么XX的每个有限子集XnXn都应当满足Kraft Inequality(紧性),那么取一列数列an=xXn2ian=xXn2i,则an1an1恒成立。于是limnan=xX2i1limnan=xX2i1也成立。

既然唯一可解码和前缀码一样也必须服从Kraft Inequality,所有能够成为唯一可解码的长度序列都可以作为前缀码的长度序列。由此可见把条件从前缀码放松到唯一可解码并没有给我们带来什么便利,或者我们说这两者差不多就是一回事。我们可以认为唯一可解码几乎就是指前缀码。

最优编码问题

在编码时,我们不仅要保证解码不能有歧义,还要使得编码的长度尽可能短。这里的长度指的是在统计词频后期望意义下的最短。例如在英文中e出现的概率最高,我们就希望e被编码得尽量短;q出现的概率低,我们就可以让q有相对较长的编码。设字母表的概率分布函数为pp,第ii个字符的出现概率为pipi,被编码长度为ii。则我们要选取合适的ii的分布,最小化L=ni=1piiL=ni=1pii

由于ii的分布必须满足Kraft Inequality,而一旦满足了Kraft Inequality就是一个可行的编码。因此这其实就是一个不等式约束下的凸优化问题:在约束ni=12i1ni=12i1下最小化L=ni=1piiL=ni=1pii。对于这个问题,可以根据KKT条件直接求解。但方便起见我们先用Lagrange条件在等式取紧ni=12i=1ni=12i=1时求出LL的最小值,再证明任何编码都不可能比这个最小值更小。

根据Lagrange乘数法,L(,λ)=ni=1pii+λ(ni=12i1)L(,λ)=ni=1pii+λ(ni=12i1)。于是Li=piλ2iln2=0Li=piλ2iln2=0。因此2i=piλln22i=piλln2是个定值。代入ni=12i=1ni=12i=1,得到piλln2=1piλln2=1,也即λ=1ln2λ=1ln2。由此解得2i=pi2i=pi,也就是说第ii个字符应当被编码成长度为i=log21pii=log21pi的串。这恰好是熵的定义中出现的项。如果我们重新写出期望的编码长度的式子,恰好得到L=ni=1pilog21piL=ni=1pilog21pi。这就是H(X)H(X)的定义!我们还要进一步验证任何编码方式得到的LL都不可能比H(X)H(X)更小。LH(X)=ni=1pii+ni=1pilogpiLH(X)=ni=1pii+ni=1pilogpi=ni=1pilog(pi2i)=ni=1pilog(pi2i)。记c=nj=12ic=nj=12iri=2icri=2ic,则riri构成了某个概率分布qqLH(X)=ni=1pilog(pi2icc)=ni=1pilog(pi2i/c1c)LH(X)=ni=1pilog(pi2icc)=ni=1pilog(pi2i/c1c)=ni=1pilogpirilogc=ni=1pilogpirilogc=D(p||r)logc=D(p||r)logc。根据Kraft Inequality,c1c1,因此logc0logc0。而根据信息不等式,相对熵D(p||r)0D(p||r)0也成立。综上,LH(X)LH(X)始终成立。

所以我们看到,熵的含义就是最优编码的期望编码长度。当然,i=logpii=logpi不一定是整数。这个等号只有在XX的所有分布密度都是22的幂次时才能取到。一个自然的问题时,既然对于一般的分布等号总是无法取到,我们能否给出一个LL的上界?(在AEP一节中我们已经给出H(X)+ϵH(X)+ϵ作为上界,但当时并没有要求编成前缀码)下面我们证明,只需向上取整取i=logpii=logpi就能得到上界LH(X)+1LH(X)+1。首先,将所有长度都变大一定仍然满足Kraft Inequality,因此这一定是一种合法的唯一可解码编码方式。(这种编码方式称为Shannon编码。)根据logpiilogpi+1logpiilogpi+1,两边同时乘以pipi得到pilogpipiilogpi+pipilogpipiilogpi+pi。累加得到ni=1pilogpi=ni=1pilogpi=H(X)H(X)ni=1pii=Lni=1pii=Lni=1pilogpi+ni=1pini=1pilogpi+ni=1pi=H(X)+1=H(X)+1

于是我们看到我们的理论给出的最优编码的bound H(X)LH(X)+1H(X)LH(X)+1指出它最多只会比熵多1个bit。但进一步发现,如果连续给nn个字符编码而考虑总的长度,那么nn个随机变量可以看作合并看作单个随机变量,上述分析依然成立。那么H(X1,,Xn)LnH(X1,,Xn)+1H(X1,,Xn)LnH(X1,,Xn)+1,而XiXi是i.i.d.的,因此得到nH(X)LnnH(X)+1nH(X)LnnH(X)+1,于是平均意义下单个字符的编码长度满足H(X)LnnH(X)+1nH(X)LnnH(X)+1n,在nn1n01n0,上下界都夹逼到了同一极限H(X)H(X)。如果XiXi不是i.i.d.的而是一个随机过程,那么H(X1,,Xn)nLnnH(X1,,Xn)n+1nH(X1,,Xn)nLnnH(X1,,Xn)n+1n,当nn时,平均编码长度收敛于熵率limnH(X1,,Xn)n=H(X)limnH(X1,,Xn)n=H(X)。由此我们看到了熵和熵率的重要意义:熵描述单个随机变量做最优编码所需要的期望位数;熵率描述给随机过程做最优编码时平均每个随机变量所需要的期望位数。

根据最优编码,我们还可以给出相对熵D(p||q)D(p||q)的直观意义。如果随机变量XX的分布为p(x)p(x),却被按照分布q(x)q(x)来编码得到i=logqii=logqi,此时编码长度E[(X)]=xXp(x)logqi<E[(X)]=xXp(x)logqi<xXp(x)(logqi+1)xXp(x)(logqi+1)=xXp(x)log(piqi1pi)+xXp(x)=xXp(x)log(piqi1pi)+xXp(x)=xXp(x)logpiqi+xXp(x)log1pi+1=xXp(x)logpiqi+xXp(x)log1pi+1=D(p||q)+H(X)+1=D(p||q)+H(X)+1。可见如果我们按照一个错误的分布qq来编码分布为pp的随机变量,平均长度会增长一个误差D(p||q)D(p||q)。这正是我们之前所说的相对熵描述两个分布之间熵的“相对距离”的一个具体体现。

哈夫曼编码(Huffman Code)

我们已经能够构造满足Kraft Inequality的编码了,但这不一定是最优编码。Shannon编码i=logpii=logpi满足LH(X)+1LH(X)+1,但也不一定是最优的。现在我们要来实际构造一个唯一可解的最优编码,称为“哈夫曼编码”,并证明任何其它编码方式都不可能在期望长度上做到比它更优。

我们在前缀树上思考这个问题。我们现在要构造一棵nn个叶节点的二叉树,期望编码长度就等于每个叶节点的权值(概率)乘以该叶节点的深度求和,我们要让这个和尽量小。这样一棵二叉树有什么性质呢?首先我们观察到,深度最大的节点一定不止一个,不然我们可以删除这个节点用它的父节点代替它,结果一定会更优。同时,深度最大的节点的兄弟节点必然存在,不然我们也可以删掉它用父节点顶替。我们还发现,深度更大的叶节点的概率权值一定更小,因为如果存在一对违反这一性质的节点,仅仅通过交换这两个叶节点的权值我们就能让总和更小了。既然这样,那么我们总是能让概率最小的那个叶节点的兄弟是概率第二小的,如果不是,我们可以把它的兄弟节点和概率第二小的交换一下而不影响结果,因为概率第二小的一定和第一小的有相同的深度。

现在我们归纳地构造哈夫曼编码。如果样本空间为2,那么直接编码为0和1即可,我们有了最简单的一棵二叉树。现在假设我们已经能够构造样本空间为m1m1的哈夫曼编码了,那么对于概率分布p=(p1,p2,,pm)p=(p1,p2,,pm),不失一般性假设p1p2pmp1p2pm。现在把概率最小的两个pm1pm1pmpm合并为pm1+pmpm1+pm,得到了一个m1m1元的分布p=(p1,p2,,pm1+pm)p=(p1,p2,,pm1+pm)(并不保证按顺序排列),构造这个分布的哈夫曼树,并在pm1+pmpm1+pm对应的叶节点下增添两个儿子,分别对应pmpm1对应的叶节点,我们证明这样我们就得到了m元的哈夫曼树了!在增添了这两个叶节点后,总和增大了pm1+pm。设m1元时哈夫曼编码的总和为L0,那么现在的总和为L0+pm1+pm。假设现在的不是最优编码,那么最优编码长度L满足L<L0+pm1+pm,它对应的哈夫曼树上pmpm1恰好是深度最深的并且互为兄弟节点,只需把它们删除而用它们的父亲以权值pm+pm1顶替,我们就得到了一棵总和为Lpm1pmm1元哈夫曼树,而Lpm1pm<L0,矛盾。综上,我们的构造一定是最优的。

构造哈夫曼编码的算法本质上是贪心算法,因为我们直观上就想让概率小的有较长的编码,概率大的有较短的编码:我们每次选择概率最小的两个,将它们合并(也即令它们在二叉树上互为兄弟),然后以这两个节点合并的身份继续在剩下的n1个里面选最小的两个,这样我们就得到了一棵二叉树,这就是哈夫曼树。

需要指出,这个算法对于任何D进制编码都是成立的。当D>2时,我们每次选出最小的D个合并构造D叉树,并能证明这就是最优编码。(一个要注意的细节是,我们要求哈夫曼树的每个节点的儿子个数都是满的。因此总的待编码的样本大小必须是1+(D1)k,如果样本大小恰好不满足这个形式,我们可以加入一些概率为0的样本,让它们获得最长的编码而不是让那些概率不为0的样本被编码成更长的。)

Shannon–Fano–Elias编码

哈夫曼编码是需要依据概率分布的排序的,在编码过程中我们需要一个支持给出最小值和合并(插入、删除)的数据结构,这样的数据结构(堆、平衡树等)是O(nlogn)的。下面我们给出一种基于累积分布函数的编码方式,称为Shannon–Fano–Elias编码,由于累积分布函数的计算是O(n)的,我们能够在线性时间内完成编码。

不失一般性,设样本空间为X={1,,n}。于是有累积分布函数F(x)=ixp(i)。由于在所有样本点iF的值都互不相同,且这个值一定是一个[0,1]间的小数,我们可以用这个小数来做编码。但由于这个小数可能是无限的,我们必须对其进行truncate。假设我们规定了第i个样本的编码长度i,那么我们就截取F(i)二进制小数点后的前i位作为我们的编码。在这里,我们就取类似Shannon编码中的i=logpi+1(显然符合Kraft Inequality)。我们要保证我们的编码是前缀码,为此我们要用[0,1]上小数区间覆盖的方式证明所有编码对应的区间是互不重叠的。对于样本点i,由于它被截断到i位,它会占据长度位2i的区间。而2i=2(logpi+1)2logpi2=p(i)2。为了使区间互不重叠,我们需要做一些调整,在F的每个样本点i处减掉p(i)的一半,对新的函数ˉF(x)=p(x)2+i<xp(i)进行上述编码。这样得到的所有区间确实是互不重叠的了。这就是Shannon–Fano–Elias编码。

Shannon–Fano–Elias编码的期望长度L=ni=1pi(logpi+1)=1+ni=1pilogpi,而ni=1pilogpi就是Shannon编码的期望长度,我们证明过它有上界H(X)+1。因此Shannon–Fano–Elias编码的期望长度有上界H(X)+2

Competitive Optimality

到目前位置,当我们讨论编码的最优性时,我们讨论的是编码的期望意义下的长度。现在我们想要从别的角度来看这个问题。一种比较编码最优性的方式称为竞争最优性(Competitive Optimality),每次我们随机从样本空间中抽取一个样本,然后分别用两种方式编码,编码较短的一方获胜。通过获胜的概率来衡量编码的优劣。与哈夫曼编码相比,Shannon编码或Shannon–Fano–Elias编码的一个优势在于它对于编码长度有显式的表达式i=logpii=logpi+1,这对于我们分析算法的最优性提供了很大的数学上的便利。接下来我们就讨论Shannon编码的竞争最优性。

设对于字符x,Shannon编码的长度为l(x)。我们任意选定另一种唯一可解的编码方式,记它对x的编码长度为l(x)。下面我们来计算Shannon编码战败的概率,更精确的,计算Shannon编码比给定编码方式长c位的概率Pr[l(X)l(X)+c],其中c是正整数。代入l(X)=log1p(X),由于l(X)log1p(X)+1Pr[l(X)l(X)+c]Pr[log1p(X)l(X)+c1]=Pr[1p(X)2l(X)+c1]=p(x)2(l(x)+c1)p(x)p(x)2(l(x)+c1)2(l(x)+c1)xX2(l(x)+c1)=12c1xX2l(x)。而l(x)满足Kraft Inequality,因此12c1xX2l(x)12c1。综上,我们得到Pr[l(X)l(X)+c]12c1。可见Shannon编码比其它编码在单个字符上长2位的概率小于1/2,长3位的概率小于1/4……别的编码方式只有很小概率能战胜Shannon编码。

上述不等式在c=1时并没有良好的刻画。我们想进一步讨论Pr[l(X)>l(X)]。为此,我们假设l(X)都是2的幂次(也即l(x)=logp(x)),来证明Pr[l(X)>l(X)]12。这等价于证明Pr[l(X)<l(X)]Pr[l(X)>l(X)]Pr[l(X)>l(X)]Pr[l(X)<l(X)]=x:l(x)>l(x)p(x)x:l(x)<l(x)p(x)=xp(x)sgn(l(x)l(x))。由于当tN时总是成立sgn(t)2t1xp(x)sgn(l(x)l(x))xp(x)(2l(x)l(x)1)=x2l(x)(2l(x)l(x)1)=x2l(x)x2l(x)=x2l(x)xp(x)=x2l(x)1,根据Kraft Inequality,x2l(x)10。综上,Pr[l(X)>l(X)]Pr[l(X)<l(X)]0。特别地,我们来观察取等条件。这要求l(x)l(x)只能等于0或1,也即ll在每一个字符都要更短,并且最后的Kraft Inequality取紧,而l也要满足Kraft Inequality,说明只能l(x)=l(x)处处成立。

在我们的证明中,依赖于l(X)都是2的幂次得到了一个简洁的结论。如果这个条件不满足,我们需要在p(x)的放缩中加一个1,最终用类似的方法证明xp(x)sgn(l(x)l(x)1)0。在上述过程中,我们选择了2t1这个函数来放缩sgn(t)。选取任意别的更小的函数f都可以完成证明,也即E[f(l(x)l(x)1)]0

随机变量的生成

假如我们已经知道了一个概率分布,怎么根据这个分布来生成一个随机变量呢?抛硬币是最简单的生成随机变量的方法,只需进行一次抛硬币的动作我们就能得到一个0-1的二项分布的结果。能不能通过多次抛硬币,来得到一个复杂的概率分布的随机变量呢?如果要做到这样,我们就要把每个抛硬币的结果序列对应到随机变量的一个取值上,每个长度为k的结果序列都对应着概率2k。我们可以进行一些适当的拼凑,使得这些概率之和恰好凑成了对应的概率密度,这样我们就最终实现了用抛硬币来生成任意随机变量的目标。

在如上的生成随机变量的过程中,我们当然关心能否让期望的抛硬币的次数尽量小。我们将发现,这再次与随机变量的熵联系在了一起。假如我们要生成的随机变量的概率分布的每个密度本身就都是2的幂次,那么我们直接用这个分布对应的哈夫曼树就得到了一个二进制序列与分布的一一对应。容易发现,此时抛硬币次数的期望就是该随机变量哈夫曼编码的期望长度,也就是熵。假如概率分布不是2的幂次呢?如果继续采用哈夫曼编码,我们就要把每个概率密度按照二进制小数的方式拆分成细小的2的幂次的分布之和(这可能是无穷的,因为存在无限小数)。下面我们证明,用这些拆分后的2的幂次直接生成哈夫曼树来生成随机变量,期望的抛硬币次数在H(X)H(X)+2之间。

X的概率密度p(i)拆成二进制小数以后写作0.p(i)(1)p(i)(2)p(i)(n),也即p(i)=j:p(i)(j)>02j。设所有的拆分后的概率组成一个新的更细小的分布YY对应的哈夫曼树的期望深度就是期望的抛硬币次数。所以我们就是要bound H(Y)。容易看到XY的函数,因此H(X)H(Y)。而H(Y)=ni=1j:p(i)(j)>02jlog(2j)=ni=1j:p(i)(j)>0j2j。对于p(i),假设它在小数部分恰好有ni个前导0,那么2ni+1>p(i)2ni,那么令Ti=j:p(i)(j)>0j2j=jn:p(i)(j)>0j2j。要证H(Y)=ni=1TiH(X)+2=ni=1p(i)(logp(i)+2),只需证i,Ti<p(i)logp(i)+2p(i):根据logp(i)ni+1,有Ti+p(i)logp(i)2p(i)Ti(ni+1)p(i)=jn:p(i)(j)>0j2j(n+1)jn:p(i)(j)>02j=jn:p(i)(j)>0(jn1)2j,单独取出j=nj=n+1两项,得到2n+jn+2:p(i)(j)>0(jn1)2j,换元令k=jn12n+k1:p(i)(k+n+1)>0k2kn12n+2n1k1k2k=2n+2n12=0。得证。

posted @   行而上  阅读(240)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
点击右上角即可分享
微信分享提示