统计自然语言处理——n元语法(马尔可夫模型)小结

来源:互联网 发布:亿网备案域名 编辑:程序博客网 时间:2024/05/19 16:49

统计自然语言处理——n元语法(马尔可夫模型)小结

标签: 自然语言处理signal算法floatsystemqt
 3156人阅读 评论(0) 收藏 举报
 分类:
终于把书看到传说中重要的第六章了。。。

看完第六章开始后悔之前花那么多时间看前四章内容了。。看了也忘掉了。。什么困惑度啊什么的一堆概念还是要翻一翻。。之前总怕不仔细看后面的看不懂。。结果重要的第五章第六章反而看的比前面愉快了许多~主要还是概率的知识,几乎都是条件概率,条件概率公式、全概率公式和贝叶斯公式用的挺多,当然还有独立性。。下面不废话了。。具体说一下。。


【心得及问题】

1、N元语法的n体现了该词间的独立性,n越小独立性越强。则可根据不同语料的独立性特点选择不同的模型了。通常n=3。直观上讲,第i位置的词与前面多少个词的相关性并不一定,另外,“词”是一个笼统的概念(可以代表字、词短语等),它的选取也不确定,而一个模型直接赋予n一个确定的值,这本身是一种近似。所以说,模型不可能精确表达,根据这种局限性,一个好的模型的重要性就可想而知了。模型提出后也要检验,至少要满足已知定理,比如n元语法模型就加上了<BOS> 和<EOS>,以使i-1有意义并满足概率的归一性。
2、P75:刚开始没看懂计算P(Wi|Wi-1)的公式。是因为求和符号下面的Wi理解为施加给i了,思维定势,而Wi-1是不变的。其实就是条件概率公式P(A|B) = P(AB)/P(B)约掉了样本空间里元素的个数而已。
3、P77:之前看平滑方法的时候想比较一下,看看优缺点,但是一堆公式看起来很费劲。计算了一下,发现使用加法平滑算法时,概率的变大还是变小取决于(b-a|V|)的正负(a为原来概率的分子,b为原来概率的分母)。感觉词汇表的容量|V|通常应该很大,即使a比b小也有可能大多数情况该值为负,即概率变小,那么概率的归一性怎么保证?这点没有想明白。另外关于平滑还有一个问题,说平滑的基本思想是“劫富济贫”,不明白为什么。不让概率为零的实际意义书上有解释,而为什么要让概率分布均匀就不晓得了,没百度出来。。后面的平滑方法看不懂也看不下去了,想着将来用到再看,毕竟我发现纯理论的东西看了跟没看一样,知道有这么回事就行了。况且最后有人做过实验比较,具有指导意义。
4、P95:P(q1,q2,……,qt)的第二个等式刚开始感觉应该用约等。后来想想,感觉它的意思应该是基于马尔可夫模型吧,模型已经是近似了,而在该模型中就是假定该模型是准确的吧,然后与前面其他的状态无关,所以就写等号了。
5、隐马尔可夫模型不过是一个双重的随机过程,书上小球的例子举得很直观,理解没有困难,将马尔可夫模型的应用范围扩大到潜在事件随即生成表面时间的情况。
6、前向、后向(这个还要实现以下,之后附上代码。。)包括维特比算法,个人认为关键是动态规划的思想,所以总结在下面。之前连动态规划是什么都不知道。。汗颜。。这也体现了算法的重要性啊!


【思想小结】

1、动态规划:就是为了避免重复计算浪费时间,通常把计算过的量给保留起来,下次则直接查找,无需计算。就是一种空间换时间的感觉。。当然计算量要是很小就不必要这样啦。。那个维特比算法让我想起来Dijkstra的单源最短路径那个算法,有点像呢。而且都是设了一个变量来进行路径的记录。(而路径记录要是我刚开始肯定会想到链表或者数组。。效率啊。。人家一个变量就解决了,最后递归输出一个逆序就行了~)所以说,算法有很多,也有很多是相通的,算法思想才是最重要的。

2、模型思想:呵呵,刚才正好说到算法思想,模型思想也是如此,感觉这是一种抽象的能力。这世界上万事万物那么多,谁有时间和精力都去研究一遍呢,况且研究难度也很大。而模型的思想就是一种抽象思想,把一个问题抽象成一类问题,一个好的模型就能解决一系列问题了,也是一种对一系列问题的归类和总结,是透过现象看本质的能力。咦。。扯到哲学了。。言归正传,这同时也是理论与实际的完美结合。一个模型建立的时候,你不能不考虑理论因素,比如不能与公理定理等客观真理相违背(感受第一点加<EOS>就是这样)。而建立之后,又要经得起检验,不能与人的基本常识(当然是可证明的客观常识)或者实际经验和需求等相违背(比如平滑方法的提出,概率为零导致语音识别错误)。所以提出和提出之后都要经过检验和优化,提出新的方法甚至新的模型,这便是研究一个模型的价值吧。


附前向算法(注意代码风格呀!!那个*写成+让我Debug了一天啊有木有!!):

[cpp] view plaincopy
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3.   
  4. int main()  
  5. {  
  6.     int i, n, j;  
  7.     int array[100]= {0};  
  8.     double result=0;  
  9.     float init[5] = {0.1,0.3,0.2,0.2,0.2};  
  10.     float state[5][5] = { {0,0.2,0.4,0.1,0.3}, {0.2,0.8,0,0,0}, {0.5,0.1,0.1,0.2,0.1}, \  
  11.         {0.2,0.3,0.1,0.3,0.1}, {0,0.1,0.2,0.4,0.3}  
  12.     };  
  13.     double forward[100][5];  
  14.     float signal[5][3] = { {0.5,0.3,0.2}, {0.1,0.1,0.8}, {0,0,1}, {0.4,0.5,0.1}, {0.7,0,0.3}};  
  15.     printf("请输入观察序列的长度:\n");  
  16.     scanf("%d", &n);  
  17.     for(i=0; i<n; i++)  
  18.     {  
  19.         printf("请输入第%d个观察到的颜色序号并按回车结束\n", i+1);  
  20.         scanf("%d", &array[i]);  
  21.         if(array[i]<1 || array[i]>3)  
  22.         {  
  23.             printf("颜色只有1、2、3!请重新输入!\n\n");  
  24.             i--;  
  25.         }  
  26.     }  
  27.     system("cls");  
  28.     printf("您输入的序列为:\n");  
  29.     for(i=0; i<n; i++)  
  30.     {  
  31.         printf("%d  ", array[i]);  
  32.     }  
  33.     for(i=0; i<5; i++)  
  34.     {  
  35.         forward[0][i] = init[i]*signal[i][array[0]-1];  
  36.         printf("forward[0][%d]: %lf  ", i, forward[0][i]);  
  37.     }  
  38.     for(i=1; i<n; i++)  
  39.     {  
  40.         for(j=0; j<5; j++)  
  41.         {  
  42.             forward[i][j] = (forward[i-1][0]*state[0][j]+forward[i-1][1]*state[1][j]+ \  
  43.                              forward[i-1][2]*state[2][j]+forward[i-1][3]*state[3][j]+ \  
  44.                              forward[i-1][4]|*state[4][j])*signal[j][array[i]-1];  
  45. //            printf("\nforward[%d][%d]: %lf\n", i, j, forward[i][j]);  
  46.         }  
  47.     }  
  48.     for(i=0; i<5; i++)  
  49.     {  
  50. //        printf("%lf  ", forward[n-1][i]);  
  51.         result += forward[n-1][i];  
  52.     }  
  53.     printf("\n该观察序列的概率为:%lf\n", result);  
  54.     return 0;  
  55. }  

后向算法(感觉书上算法第三步写错了。。害我苦思冥想到底和第一个状态有什么关系想了好久。。。):

[cpp] view plaincopy
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3.   
  4. int main()  
  5. {  
  6.     int i, j, n;  
  7.     int array[100] = {0};  
  8.     double result=0;  
  9.     float init[5] = {0.1,0.3,0.2,0.2,0.2};  
  10.     float state[5][5] = { {0,0.2,0.4,0.1,0.3}, {0.2,0.8,0,0,0}, {0.5,0.1,0.1,0.2,0.1}, \  
  11.         {0.2,0.3,0.1,0.3,0.1}, {0,0.1,0.2,0.4,0.3}  
  12.     };  
  13.     double back[100][5];  
  14.     float signal[5][3] = { {0.5,0.3,0.2}, {0.1,0.1,0.8}, {0,0,1}, {0.4,0.5,0.1}, {0.7,0,0.3}};  
  15.     printf("请输入观察序列的长度:\n");  
  16.     scanf("%d", &n);  
  17.     for(i=0; i<n; i++)  
  18.     {  
  19.         printf("请输入第%d个观察到的颜色序号并按回车结束\n", i+1);  
  20.         scanf("%d", &array[i]);  
  21.         if(array[i]<1 || array[i]>3)  
  22.         {  
  23.             printf("颜色只有1、2、3!请重新输入!\n\n");  
  24.             i--;  
  25.         }  
  26.     }  
  27.     system("cls");  
  28.     printf("您输入的序列为:\n");  
  29.     for(i=0; i<n; i++)  
  30.     {  
  31.         printf("%d  ", array[i]);  
  32.     }  
  33.     for(i=0; i<5; i++)  
  34.     {  
  35.         back[n][i] = 1;  
  36.     }  
  37.     for(i=n-1; i>0; i--)  
  38.     {  
  39.         for(j=0; j<5; j++)  
  40.         {  
  41.             back[i][j] = state[j][0]*signal[0][array[i]-1]*back[i+1][0] + \  
  42.             state[j][1]*signal[1][array[i]-1]*back[i+1][1] + \  
  43.             state[j][2]*signal[2][array[i]-1]*back[i+1][2] + \  
  44.             state[j][3]*signal[3][array[i]-1]*back[i+1][3] + \  
  45.             state[j][4]*signal[4][array[i]-1]*back[i+1][4];  
  46.         }  
  47.     }  
  48.     for(i=0; i<5; i++)  
  49.     {  
  50.         result += back[1][i]*init[i]*signal[i][array[0]-1];  
  51.     }  
  52.         printf("\n该观察序列的概率为:%lf\n", result);  
  53.     return 0;  
  54. }  
0 0
原创粉丝点击