小白给小白详解维特比算法(一)


  • 小白给小白详解维特比算法一

    • 篱笆网络Lattice的最短路径问题

      • 这个问题长什么样子
      • 这个问题难在哪里
      • 简化成这个模样你总能回答了吧
      • 下一步我们该干什么
    • 别倒立了我们再从头想一下这个问题
      • 我们是怎么走过来的
      • 来我们从A开始走
      • 这次我们需要算的次数大约是多少呢
    • We are almost there

初见HMM求解状态序列用到的维特比算法时,其实内心真的是崩溃的:数不尽的假设和公式,让人头昏脑涨的同时也击溃了自信心。但是仔细研究一下会发现其实问题蛮简单的,本文就致力于尝试用更通俗的方式解释一下维特比算法和它是如何运用在HMM求解状态序列中的,因为我也是刚看个差不多……所以如果有不对的地方请各位直接喷别留情!
(以下部分内容参考了吴军《数学之美》26.1,感谢吴军博士通俗易懂的讲解)

篱笆网络(Lattice)的最短路径问题

这个问题长什么样子?

尝试着回答一下这个问题(就算没办法回答也请先别关闭这个窗口!):
已知下图的篱笆网络,每个节点之间的数字表示相邻节点之间的距离,举个例子来说,如果我走A→B1→C2→D1→EA→B1→C2→D1→EA\rightarrow B_1 \rightarrow C_2 \rightarrow D_1 \rightarrow E,这个距离是6+6+5+4=216+6+5+4=216+6+5+4=21。那么如果让你从A走到E,最短路径是哪一条呢?


图1

这个问题难在哪里?

好啦不用尝试啦!显然大家都知道,通过穷举的方法是很容易得到最短路径,可是问题就在于如果穷举的话,需要的加法次数不用算你也知道实在是太多啦(每条路径需要计算444次加法,一共3×3×3=27" role="presentation" style="position: relative;">3×3×3=273×3×3=273\times 3 \times 3=27条路径共108108108次计算)!像这种没几层的篱笆网络也就罢了,如果每层13个节点,一共12层(然而这个规模对于标注问题来说也依然根本不算什么),可想而知那个线有多乱,如果仅仅穷举的话,这个计算量(大致是每条121212次计算,一共1312131213^{12}条路径共大约12×1312≈2×101512×1312≈2×101512\times 13^{12}\approx 2\times 10^{15}次计算)怕是超级计算机也吃不消。

为了不直接给公式让大家关掉窗口,我们尝试着一点一点来解决这个问题

简化成这个模样,你总能回答了吧?

如下图,如果我想让你找到A→EA→EA\rightarrow E的最短路径,就很简单了吧?

图2

显然图2上只有三条路径,我们分别计算之后得到最短路径应该是A→D3→EA→D3→EA \rightarrow D_3 \rightarrow E这一条,路程是17。

这个时候请把这个问题和上一个问题做一个对比,同时从相反的方向考虑一下上一个问题:如果我最终想要到达E这个节点,其实无论如何都是要经过D这一层的,那么要是我知道从A到D的每一个节点的最短路径长度(在刚才的图上,我们事实上假设了他们分别是15、14和12),再加上从D的各节点到E的路程就得到了最终路径的长度。

当然我们还需要再多想一点:如果想要真的按照A到E的最短路径来走的话,我们其实不会选择D1D1D_1和D2D2D_2这两个节点,因为哪怕(以)A→D2A→D2A\rightarrow D_2(为例)路径更短(就算是10),但是加上D2→ED2→ED_2\rightarrow E的距离之后就变得更长了(这时候也是18)。相应的我们也就明白这样一个道理:虽然我们最后没有选择D1D1D_1和D2D2D_2这两个节点,但我们是否真的就不需要得到A到他们的最短路径了呢?答案当然是否定的:从刚才的例子我们很容易理解,站在D层的角度来看的话,最终的长度是由“历史”(A到每一个D的长度)和“未来”(每一个D到E的长度)同时决定的,只有同时掌握了“历史”和“未来”,世界才能在我们手中(旁白:你说什么呢)!

当然刚才我们从A到D层的路径是假设出来的,事实上如果我们真的要解决最开始那个问题,我们需要求解这个问题:

图3

我们就可以知道,最终的最短路径到底走的是哪个D。

下一步我们该干什么?

我们已经明白了,为了确定从哪个D到E才是最短的,我们就必须确定A到每一个D的最短路径。诶?这个问题是不是从哪里见过?

其实这就是所谓的“动态规划”的核心了:子问题几乎是完全一样的,我们只要一个一个解决了子问题(的子问题),最终的问题就迎刃而解了。

为了确定这个问题,我们就需要一个D一个D地去考虑(旁白:???),比如在考虑D1D1D_1的时候不考虑D2、D3、ED2、D3、ED_2 、D_3、E等等。把问题简化成这个样子:

图4

这个图是不是和图1 非常相似?

然后根据图3的思想,我们把它简化成这个样子:

图5

这个图是不是和图3非常相似?

问题相应就变成了从A到每一个C的最短路径是多少?

解决了这个问题的话,我们就可以知道,最终如果走了比如D1D1D_1,前面路过的到底是哪个C

再进一步递推:为了确定到某一个C的最短路径,我们需要确定的就是这个问题:

图6

不不不!聪明的你(O__O”…)一定发现了,这根本算不得什么问题,因为其实它是这样的:

图7

因为我们已经推到最后一步了!从A到每一个B的路径事实上都是已知的,我们只需要把他们加在一起去比较大小就可以了!

别忘了我们的目标是什么:我们事实上是要确认如果最终路过了C1C1C_1,前面路过的是哪一个B。

从动态规划的角度考虑,假设我们最终的路径能路过C1C1C_1而我们已经走到了C1C1C_1,那么可以肯定地说,我们来到C1C1C_1的路径一定是所有来到C1C1C_1路径里面最短的那一条(在这个图上看应该是B3B3B_3)。因为如果我们没有走最短的那一条(比如我们错走成了B1B1B_1),那么我们只要用更短的那一条(B3B3B_3)去替换也一样可以走到C1C1C_1。

别倒立了,我们再从头想一下这个问题!

我们刚才是从最终的E节点倒推考虑的这个问题,这一次我们从A真正的走一遍。

我们是怎么走过来的

我们在每一层MMM都仅仅需要考虑这样一个问题:

为了到下一个层的某一个确定的节点Ni" role="presentation" style="position: relative;">NiNiN_i,我们到底应该从哪一个MiMiM_i出发呢?

一旦确定了从哪一个MiMiM_i出发,其他的MjMjM_j就不在我考虑范围内了。
就像我们刚才说的,只要我能找到去C1C1C_1应该从B3B3B_3走,我就不需要考虑其他的到C1C1C_1的路径了。这样就大大的减少了路径总数。

来,我们从A开始走

  1. A→BA→BA\rightarrow B
    这个没啥说的:6,7,5

    我们顺利走到了B层

  2. A→B→CA→B→CA \rightarrow B \rightarrow C
    我们确定到每一个C的节点,应该路过哪一个B:

    • C1C1C_1:6+5=11, 7+4=11, 5+4=9,最终选择A→B3→C1A→B3→C1A\rightarrow B_3 \rightarrow C_1,抛弃其他到C1C1C_1的路径,长度9
    • C2C2C_2:12 ,10 ,11, 最终选择A→B2→C2A→B2→C2A\rightarrow B_2 \rightarrow C_2,抛弃其他到C2C2C_2的路径,长度10
    • C3C3C_3:15,14,11,最终选择A→B3→C3A→B3→C3A\rightarrow B_3 \rightarrow C_3,抛弃其他到C3C3C_3的路径,长度11

    我们顺利走到了C层,同时得到了到每一个C的最短路程

  3. A(→B)→C→DA(→B)→C→DA (\rightarrow B) \rightarrow C \rightarrow D
    我们确定到每一个D的节点,应该路过哪一个C

    • D_1:9+7=16,10+5=15,11+5=16,最终选择A→B2→C2→D1A→B2→C2→D1A\rightarrow B_2 \rightarrow C_2 \rightarrow D_1,抛弃其他到D1D1D_1的路径,长度15
    • D_2:17,14,18,最终选择A→B2→C2→D2A→B2→C2→D2A\rightarrow B_2 \rightarrow C_2 \rightarrow D_2,抛弃其他到D2D2D_2的路径,长度14
    • D_3:12,13,17,最终选择A→B3→C1→D3A→B3→C1→D3A\rightarrow B_3 \rightarrow C_1 \rightarrow D_3,抛弃其他到D3D3D_3的路径,长度12

    我们顺利走到了D层,同时得到了到每一个D的最短路程

  4. A(→B→C)→D→EA(→B→C)→D→EA (\rightarrow B \rightarrow C) \rightarrow D \rightarrow E
    我们确定每一个D到最终节点E的路程

    显然最后应该选择D3D3D_3,完整路径为
    A→B3→C1→D3→EA→B3→C1→D3→EA\rightarrow B_3 \rightarrow C_1 \rightarrow D_3 \rightarrow E
    路程为17。抛弃其他所有路径。

这次我们需要算的次数大约是多少呢?

简单来说,从A到B有3条路径,每一条我们需要算到每一个C的最短距离,所以是2(路径加法数)×3(A→B)×3(B→C)2(路径加法数)×3(A→B)×3(B→C)2(路径加法数)\times 3(A\rightarrow B)\times 3(B\rightarrow C),只要我们确定了每一个到C的最短距离剩下的事情就可以从C开始考虑了:每一个C需要确定到每一个D的最短距离,最终再加上D到E的距离就搞定了(2(路径加法数)×3(C个数)×3(D个数)2(路径加法数)×3(C个数)×3(D个数)2(路径加法数)\times 3(C个数)\times 3(D个数))。
如果换成是12层,每层最多13节点的话,每推一步的计算量最大规模在13213213^2(为了确定从哪一个B来到C,需要对每一个B到每一个C进行一次计算,上述计算每步是32=932=93^2=9次),而因为子问题都是一样的,所以增长是与网络长度成正比的:推进12次也仅仅乘以12而已。当然计算的方式不可能像这样简单乘一乘就搞定,但是可以看得出要比穷举要简单得多了。

We are almost there!

这几乎就是维特比算法了。至于维特比算法更公式化的描述和在隐含马尔科夫过程中的应用,我们下一文再说!

小白给小白详解维特比算法(一)相关推荐

  1. 小白给小白详解维特比算法(二)

    https://blog.csdn.net/athemeroy/article/details/79342048 本文致力于解释隐含马尔科夫模型和上一篇我们提到的篱笆网络的最短路径问题的相同点和不同点 ...

  2. python 快速排序_小白入门知识详解:Python实现快速排序的方法(含实例代码)...

    前言: 今天为大家带来的内容是:小白入门知识详解:Python实现快速排序的方法(含实例代码)希望通过本文的内容能够对各位有所帮助,喜欢的话记得点赞转发收藏不迷路哦!!! 提示: 这篇文章主要介绍了P ...

  3. 史上最小白之BM25详解与实现

    史上最小白之BM25详解与实现 原理 BM25算法是一种计算句子与文档相关性的算法,它的原理十分简单:将输入的句子sentence进行分词,然后分别计算句子中每个词word与文档doc的相关度,然后进 ...

  4. 史上最小白之Transformer详解

    1.前言 博客分为上下两篇,您现在阅读的是下篇史上最小白之Transformer详解,在阅读该篇博客之前最好你能够先明白Encoder-Decoder,Attention机制,self-Attenti ...

  5. MySQL安装详细教程(小白式安装详解)

    MySQL安装详细教程(小白式安装详解) 1.下载地址 1.1地址 https://dev.mysql.com/downloads/mysql/ 下载链接 1.2下载版本 2.安装配置 2.1路径(路 ...

  6. 【算法知识】详解希尔排序算法

    前言 已发布: [算法知识]详解选择冒泡算法 [算法知识]详解选择排序算法 [算法知识]详解插入排序算法 当待插入元素是一个很小(当需求是从小到大排序时,从大到小排序时此处为很大)直接插入排序需要移动 ...

  7. 【算法知识】详解直接插入排序算法

    前言 已发布: [算法知识]详解选择冒泡算法 [算法知识]详解选择排序算法 在玩扑克牌的时候,我们抽到一张牌的时候,都是将它插入到当前手中牌的合适位置的. 如下图: (上图来自算法导论) 直接插入排序 ...

  8. 算法详解_常用算法详解——打印杨辉三角形

    杨辉三角,是二项式系数在三角形中的一种几何排列.在中国南宋数学家杨辉1261年所著的<详解九章算法>一书中出现.在欧洲,这个表叫做帕斯卡三角形.帕斯卡(1623----1662)是在165 ...

  9. 最形象的卷积神经网络详解:从算法思想到编程实现(转载)

    mark一下,感谢作者分享! 原标题:最形象的卷积神经网络详解:从算法思想到编程实现 1 新智元推荐 查看全文 http://www.taodudu.cc/news/show-4611564.html ...

最新文章

  1. Windows Server云服务器配置深度学习环境WS
  2. JAVA实现链表面试题
  3. 利用DB Link两步搞定Oracle两个数据库间的表同步
  4. python高效编程15个利器_15个Python库,让你学习编程更轻松!
  5. LeetCode刷题(50)--Word Search
  6. 9个元素换6次达到排序序列_全面讲解十大经典排序算法(Python实现)
  7. 一文说透WordPress的自定义文章类型
  8. mysql5.7.10安装时密码_Windows10中MySQL5.7安装及修改root密码的详细方法
  9. 环回测试能够提供什么信息_X射线无损检测能够提供BGA焊点的重要信息
  10. Easyui清除tree的选中
  11. 古代皇帝的某祖某宗,有什么讲究
  12. 实用的CSS3属性和使用技巧
  13. 电信光猫改桥接还在苦苦破解超级密码吗?
  14. python读取pdf内容转word_Python 实现加密过的PDF文件转WORD格式
  15. r型聚类典型指标_SPSS聚类分析经典案例分享
  16. 如何写一篇给天使投资人看的《商业计划书》?
  17. 5.1劳动节|致敬每一位数字安全劳动者
  18. 大道至简——RISC-V架构之魂(中)
  19. 个人微信协议接口开发
  20. 软件工程--沃尔沃物流信息系统tp5实现源码

热门文章

  1. 关于女神SQLite的疑惑(2)
  2. R语言计算方差分析的F值和P值
  3. “公域流量”与“私域流量”
  4. 网页中QQ在线客服进行聊天的一些坑和解决方案
  5. Excle条件格式与公式
  6. Bootstrap系列之导航
  7. ASEMI高效恢复二极管型号之US1G
  8. java编程按规律输出数字图案
  9. 根据模板及表元数据生成Controll控制层类
  10. 易迅,生的霸气,死的窝囊