HMM, 隐Markov模型, 在人脸, 步态, 语音识别等领域有着广泛的用途.
通过以Javascript语言演示其使用方法, 读者可方便地理解其计算过程(其实,并不难).
理论就不讲解了,直接看计算过程:
?<html> <head> <meta charset="UTF-8"/> <meta author="alaclp@qq.com"/> <meta published="2014-11-28"/> <meta licence="public"/> <meta about="Hidden markov model"/> <title>让你真正理解隐Markov模型的计算示例</title> </head> <body> <h1>HMM Demo</h1> <hr/> <div id="info"> <h2>[0] HMM模型参数</h2> <b>状态S: {H, L}</b><br/> <b>初始状态I: {0.5, 0.5}</b><br/> <b>状态转移矩阵A:</b><br/> <table border="1px"> <tr> <td>a_ij</td><td>H</td><td>L</td> </tr> <tr> <td>H</td><td>0.5</td><td>0.5</td> </tr> <tr> <td>L</td><td>0.4</td><td>0.6</td> </tr> </table> <b>混淆矩阵B:</b><br/> <table border="1px"> <tr> <td>b_ik</td><td>A</td><td>C</td><td>T</td><td>G</td> </tr> <tr> <td>H</td><td>0.2</td><td>0.3</td><td>0.3</td><td>0.2</td> </tr> <tr> <td>L</td><td>0.3</td><td>0.2</td><td>0.2</td><td>0.3</td> </tr> </table> <br/> <h2>[1] 评估问题:使用上述模型,采用<font color='red'>Forward算法</font>计算发生GGCA观测结果的概率</h2> <h3>结果矩阵:</h3> <table border="1px"> <tr> <td>概率</td><td>初始</td> <td><div id="O1">G</div></td> <td><div id="O2">G</div></td> <td><div id="O3">C</div></td> <td><div id="O4">A</div></td> </tr> <tr> <td><div id="S0">H</div></td> <td>0.5</td> <td><div id="11"></div></td> <td><div id="12"></div></td> <td><div id="13"></div></td> <td><div id="14"></div></td> </tr> <tr> <td><div id="S1">L</div></td> <td>0.5</td> <td><div id="21"></div></td> <td><div id="22"></div></td> <td><div id="23"></div></td> <td><div id="24"></div></td> </tr> </table> <div id="prob"> </div> <br/> <div id="output"> <b>计算过程:</b><br/> </div> <hr/> <h2>[2] 解码问题: 给定观测序列GGCACTGAA,问产生该序列概率最大的状态路径是什么?</h2> <b>把HMM模型换算为以2为底的对数值,则有</b><br/> <b>状态S: {H, L}</b><br/> <b>初始状态I: {-1, -1}</b><br/> <b>状态转移矩阵A:</b><br/> <table border="1px"> <tr> <td>a_ij</td><td>H</td><td>L</td> </tr> <tr> <td>H</td><td>-1</td><td>-1</td> </tr> <tr> <td>L</td><td>-1.322</td><td>-0.737</td> </tr> </table> <b>混淆矩阵B:</b><br/> <table border="1px"> <tr> <td>b_ik</td><td>A</td><td>C</td><td>T</td><td>G</td> </tr> <tr> <td>H</td><td>-2.322</td><td>-1.737</td><td>-1.737</td><td>-2.322</td> </tr> <tr> <td>L</td><td>-1.737</td><td>-2.322</td><td>-2.322</td><td>-1.737</td> </tr> </table> <h3>结果矩阵:</h3> <table border="1px"> <tr> <td>概率</td><td>初始</td> <td><div id="D1">G</div></td> <td><div id="D2">G</div></td> <td><div id="D3">C</div></td> <td><div id="D4">A</div></td> <td><div id="D5">C</div></td> <td><div id="D6">T</div></td> <td><div id="D7">G</div></td> <td><div id="D8">A</div></td> <td><div id="D9">A</div></td> </tr> <tr> <td><div id="S0">H</div></td> <td>-1.0</td> <td><div id="V11"></div></td> <td><div id="V12"></div></td> <td><div id="V13"></div></td> <td><div id="V14"></div></td> <td><div id="V15"></div></td> <td><div id="V16"></div></td> <td><div id="V17"></div></td> <td><div id="V18"></div></td> <td><div id="V19"></div></td> </tr> <tr> <td><div id="S1">L</div></td> <td>-1.0</td> <td><div id="V21"></div></td> <td><div id="V22"></div></td> <td><div id="V23"></div></td> <td><div id="V24"></div></td> <td><div id="V25"></div></td> <td><div id="V26"></div></td> <td><div id="V27"></div></td> <td><div id="V28"></div></td> <td><div id="V29"></div></td> </tr> </table> <div id="result1"></div> 计算过程:<br/> <div id="output1"><div> <script type="text/javascript"> //状态集合 var S = ['H', 'L']; //观测集合 var O = ['A', 'C', 'T', 'G']; //初始状态发生H和L的概率矩阵 var imat = [0.5, 0.5]; //不同状态间转换的概率矩阵---状态转换矩阵 var amat = {'HH': 0.5, 'HL':0.5, 'LH':0.4, 'LL': 0.6}; //由状态产生特定观测的概率矩阵---混淆矩阵 var bmat = {'HA': 0.2, 'HC': 0.3, 'HG': 0.3, 'HT': 0.2, 'LA': 0.3, 'LC': 0.2, 'LG': 0.2, 'LT': 0.3}; //测试用的观测结果 var dest = 'GGCA'; //设置概率计算矩阵 var pmat = new Array(S.length); for(var i = 0; i < S.length; i++) { pmat[i] = new Array(); for(var j = 0; j < dest.length; j++) pmat[i].push(0); } var out = document.getElementById("output"); var tmp; //计算评估问题算法---前向算法 //分为两个部分计算 //计算结果矩阵pmat第1列---由初始状态矩阵及混淆矩阵所决定 for(var i = 0; i < S.length; i++) { pmat[i][0] = imat[i] * bmat[S[i] + dest[0]]; document.getElementById(String(i + 1) + "1").innerHTML = pmat[i][0]; } //计算后续列的概率---由前一状态概率 * 状态间转换概率amat * 状态到观测概率矩阵bmat所决定 for(var i = 1; i < dest.length; i++) { for(var rowA = 0; rowA < S.length; rowA++) { //输出 out.innerHTML += "<b>" + String(rowA + 1) + "行" + String(i + 1) + "列</b><br/>"; for(var rowB = 0; rowB < S.length; rowB++) { if (rowA == rowB) { tmp = pmat[rowA][i-1] * amat[S[rowA] + S[rowA]] * bmat[S[rowA] + dest[i]]; pmat[rowA][i] += tmp; //输出 out.innerHTML += S[rowA] + S[rowB] + dest[i] + ": " + String(pmat[rowA][i-1]) + "*" + String(amat[S[rowA] + S[rowA]]) + "*" + String(bmat[S[rowA] + dest[i]]) + "=" + String(tmp) + "<br/>"; } else { tmp = pmat[rowB][i-1] * amat[S[rowB] + S[rowA]] * bmat[S[rowA] + dest[i]]; pmat[rowA][i] += tmp; //输出 out.innerHTML += S[rowB] + S[rowA] + dest[i] + ": " + String(pmat[rowB][i-1]) + "*" + String(amat[S[rowB] + S[rowA]]) + "*" + String(bmat[S[rowB] + dest[i]]) + "=" + String(tmp) + "<br/>"; } } //输出 out.innerHTML += "和为: <b>" + String(pmat[rowA][i]) + "</b><br/>"; document.getElementById(String(rowA + 1) + String(i + 1)).innerHTML = pmat[rowA][i]; } } //输出状态S产生观测序列的概率 var sm = 0; for(var i = 0; i < S.length; i++) sm += pmat[i][dest.length-1]; document.getElementById("prob").innerHTML = "评估结果: HMM(S(H, L), O(A, T, C, G), imat, amat, bmat)产生观测结果" + dest + "的概率为: <font color='red'>" + String(sm) + "</font><br/>"; //------------------------ //取得最佳路径问题---解码问题 //测试用的观测结果 var dest = 'GGCACTGAA'; //把数值矩阵转换为对数 for(var i = 0; i < S.length; i++) imat[i] = Math.log(imat[i]) / Math.LN2; for(var i = 0; i < S.length; i++) for(var j = 0; j < S.length; j++) { amat[S[i] + S[j]] = Math.log(amat[S[i] + S[j]]) / Math.LN2; } for(var i = 0; i < S.length; i++) for(var j = 0; j < O.length; j++) { bmat[S[i] + O[j]] = Math.log(bmat[S[i] + O[j]]) / Math.LN2; console.log( S[i] + "->" + O[j] + "=" + bmat[S[i] + O[j]] ); } //初始化概率计算矩阵pmat var pmat = new Array(S.length); for(var i = 0; i < S.length; i++) { pmat[i] = new Array(); for(var j = 0; j < dest.length; j++) pmat[i].push(0); } var out = document.getElementById("output1"); //计算解码问题算法---Viterbi算法 //分为两个部分计算 //计算结果矩阵pmat第1列---由初始状态矩阵及混淆矩阵所决定 var link = new Array(); var maxval = -1e15, maxid = -1; for(var i = 0; i < S.length; i++) { pmat[i][0] = imat[i] + bmat[S[i] + dest[0]]; if (pmat[i][0] > maxval) { maxval = pmat[i][0]; maxid = i; } document.getElementById("V" + String(i + 1) + "1").innerHTML = pmat[i][0]; } //存储第1个最大概率点 link.push(S[maxid]); //计算后续列的概率---由前一状态最大概率 * 前一状态到其他状态的转换概率amat * 当前状态对观测值的发生概率 //记录当前可能产生观测结果的最大概率 for(var i = 1; i < dest.length; i++) { var thisO = dest[i]; //计算由上次状态lastS出发,发生状态转换到S[rowA]产生观测值dest[i]的最大概率 for(var rowA = 0; rowA < S.length; rowA++) { var thisS = S[rowA]; var maxval = -1e15; //由thisS产生thisO的概率 var pp = bmat[thisS + thisO]; for(var rowB = 0; rowB < S.length; rowB++) { var lastS = S[rowB]; //由lastS到thisS的转移概率 var tp = amat[lastS + thisS]; //上次的历史概率 var lp = pmat[rowB][i-1]; //总概率 var totalP = pp + tp + lp; if (totalP > maxval) { maxval = totalP; document.getElementById("V" + String(rowA + 1) + String(i + 1)).innerHTML = String(totalP); } out.innerHTML += "O" + String(i + 1) + ": " + lastS + "->" + thisS + "= " + String(pp) + "(" + thisS + "->" + thisO + ") +" + String(tp) + "(T: " + lastS + thisS + ") +" + String(lp) + "(" + lastS + ", " + String(i-1) + ") ==>" + String(totalP) + "<br/>"; } pmat[rowA][i] = maxval; } if (pmat[0][i] > pmat[1][i]) link.push(S[0]); else link.push(S[1]); out.innerHTML += "最佳: " + link[link.length - 1] + "<br/>"; } var out = document.getElementById("result1"); out.innerHTML = "最佳状态序列:"; for(var i = 0; i < link.length; i++) out.innerHTML += link[i]; </script> </body> </html>
a_ij | H | L |
H | 0.5 | 0.5 |
L | 0.4 | 0.6 |
b_ik | A | C | T | G |
H | 0.2 | 0.3 | 0.3 | 0.2 |
L | 0.3 | 0.2 | 0.2 | 0.3 |
概率 | 初始 |
G
|
G
|
C
|
A
|
H
|
0.5 |
0.15
|
0.0345
|
0.008415
|
0.0013767000000000002
|
L
|
0.5 |
0.1
|
0.027
|
0.00669
|
0.00246645
|
a_ij | H | L |
H | -1 | -1 |
L | -1.322 | -0.737 |
b_ik | A | C | T | G |
H | -2.322 | -1.737 | -1.737 | -2.322 |
L | -1.737 | -2.322 | -2.322 | -1.737 |
概率 | 初始 |
G
|
G
|
C
|
A
|
C
|
T
|
G
|
A
|
A
|
H
|
-1.0 |
-2.7369655941662066
|
-5.473931188332413
|
-8.210896782498619
|
-11.53282487738598
|
-14.006756065718395
|
-17.328684160605757
|
-19.539580943104376
|
-22.861509037991738
|
-25.65736832121151
|
L
|
-1.0 |
-3.321928094887362
|
-6.058893689053569
|
-8.795859283219775
|
-10.947862376664826
|
-14.006756065718395
|
-16.480687254050807
|
-19.539580943104376
|
-22.013512131436787
|
-24.4874433197692
|
让你真正理解HMM(Hidden Markov Model)的算法演示程序
原文地址:http://blog.csdn.net/miscclp/article/details/41569237