词性标注维特比算法介绍
对求解词性标注过程中使用的维特比算法进行介绍。
篱笆网络(Lattice)的最短路径问题
已知下图的篱笆网络,每个节点间的数字表示相邻节点间的距离,求从A走到E的最短路径是那一条。
针对上述篱笆网络(Lattic),如何求出A到E的最短路径?
一般情况下,我们可以通过穷举法,一条一条路径进行计算,然后通过比较获取最短的路径,基于上述的图我们知道需要 \(4*3*3*3\)次计算,其中4为每一条路径的计算次数,也就是从A到E需要计算4次加法获取路径距离,3个3是B、C、D三层每层是3个节点,每次每层取一个节点组成一条路径。这种方法适合于很少层数以及每层很少节点的篱笆网络,若是一个篱笆网络有12层,每层13个节点,使用穷举法则需要\(12*13^{13}\)次计算,这么大的计算量即是是超级计算机也需要很久才能计算出来。
那么针对上述篱笆网络的计算是否有很好的计算方式呢?我们采用动态规划的思想将问题进行拆分看。思路分析如下:
- 第一步,我们反向思考此问题,如果我想要从A到E节点,则必须经过D[D1、D2、D3]层的节点,那么要是我知道从A到D层每个节点的最短路径,再加上D层各节点到E节点的距离,则可以计算出从A到E的最短路径;
- 确定了从D到E的最短路径后,我们则面临新的问题,就是从A到D的最短路径的计算问题,撇开最后一个E节点不考虑,将D认为是最后一层的节点,考虑D1的最短路径,此时是不是将该问题同样定位到我们第一步的问题,类似的采用此方法计算即可;
- 依次类推,求C层节点的最短路径;而后求B层最短路径,到了B层我们知道已经是最后一步的计算了,因为从A到B我们已经知道了距离,直接计算即可;
- 基于上述步骤,我们反向即可计算最短路径问题了。
我们基于上述的步骤,我们在每一层M都仅需要考虑这样一个问题:
为了到下一层的某个确定的点Nj,我们需要从当前层哪一个Mi出发?
一旦确定了从哪一个Mi出发,其他的节点则不在后续计算的考虑范围内了。就比如我们找到了到C1需要从B3走,那就不考虑其他到C1的路径了,这样就大大减少了需要计算的路径总数。
经过上述分析,我们从新考虑其计算复杂度。我们上述计算过程知道,每一步计算的复杂度都和相邻两个状态的节点数目有关,比如C层有3个节点(状态),B层有3个节点,从B层到C层计算最短路径需要3*3次,也就是各个状态节点数的乘积,如果整个篱笆网络的某个状态的最大节点数为N,则每一步计算的最大复杂度为N*N次,总共有多少层则需要在乘以层数得到最终的计算复杂度。
维特比(vertibe)算法
基于上述篱笆网络的说明,给出维特比算法:
- 从点S出发,对于第一个状态 \(x_1\)的各个节点,不妨假设有\(n_1\)个,计算出S到它们的距离\(d(S,x_{1i})\),其中\(x_{1i}\)代表任意状态1的节点。因为只有一步,所以这些距离都是S到它们各自的最短距离;
- 对于第二个状态 \(x_2\)的各个节点,要计算S到它们的最短路径。我们知道,对于特定的节点\(x_{2i}\),从S到它的路径可以经过状态1的\(n_1\)中任何一个节点\(x_{1i}\),当然,对应的路径长度就是\(d(S,x_{2i})=d(S,x_{1j})+d(x_{1j}, x_{2i})\),由于\(j\)有\(n_1\)中可能性,我们要一一计算,然后找到最小值,即是\(d(S,x_{2i})=min_{j=1,n_1}d(S,x_{1j})+d(x_{1j}, x_{2i})\)。这样对于第二个状态的每个节点,需要\(n_1\)次乘法计算,假定这个状态有\(n_2\)个节点,把从S到这些节点的距离都计算一遍,就有\(O(n_1*n_2)\)次计算。
- 接下来,类似的按照上述方法从第二个状态走到第三个状态,一直走到最后一个状态,记得到了整个网络从头到尾的最短路径。每一步计算的复杂度都和两个状态 \(s_i\)和\(s_{i+1}\)各自的节点数目\(n_1\)、\(n_2\)的乘积成正比,即\(O(n_1*n_2)\)。如果假设在这个隐含马尔科夫链中节点最多的状态有D个节点,也就是说整个篱笆网络的宽度为D,那么任何一步的复杂度不超过\(O(D^2)\),由于网络长度为N,所以整个维特比算法的复杂度为\(O(N*D^2)\)
上述即是对维特比算法的相关介绍,文章参考了吴军博士的《数学之美》维特比算法介绍章节,及小白给小白详解维特比算法(一)。