隐马尔科夫模型C#语言算法实现

开发工具:

Visual Studio v2010

.NET Framework 4 Client Profile

版本历史:

V1.1 2011年06月09日

  • 修正UMDHMM在Baum-Welch算法中存在的模型参数调整错误。

 

V1.0 2011年06月08日

  • 将C语言实现的隐马尔科夫模型算法(UMDHMM)改为C#语言实现。

功能描述:

  • 前向算法(forward algorithm):给定HMM求一个观察序列的概率(评估)
  • 后向算法(backward algorithm):给定HMM求一个观察序列的概率(评估)
  • 前向-后向算法(forward-backward algorithm):根据观察序列生成隐马尔科夫模型(学习)
  • 维特比算法(Viterbi algorithm):搜索最有可能生成一个观察序列的隐藏状态序列(解码)

下载地址:

隐马尔科夫模型.zip

源代码:

HMM.cs(类构造函数)

[c-sharp] view plaincopyprint?
  1. /* ---------------------------------------------------------- 
  2. 文件名称:HMM.cs 
  3.  
  4. 作者:秦建辉 
  5.  
  6. MSN:splashcn@msn.com 
  7. QQ:36748897 
  8.  
  9. 版本历史: 
  10.     V1.1    2011年06月09日 
  11.             修正UMDHMM在Baum-Welch算法中存在的模型参数调整错误。 
  12.  
  13.     V1.0    2011年06月08日 
  14.             将C语言实现的隐马尔科夫模型算法(UMDHMM)改为C#语言实现。 
  15.  
  16. 功能描述: 
  17.     1.前向算法(forward algorithm):给定HMM求一个观察序列的概率(评估) 
  18.     2.后向算法(backward algorithm):给定HMM求一个观察序列的概率(评估) 
  19.     3.前向-后向算法(forward-backward algorithm):根据观察序列生成隐马尔科夫模型(学习) 
  20.     4.维特比算法(Viterbi algorithm):搜索最有可能生成一个观察序列的隐藏状态序列(解码) 
  21.  
  22. 参考资料: 
  23.     C代码:http://www.kanungo.com/software/umdhmm-v1.02.zip 
  24.     学习资料:http://www.52nlp.cn/category/hidden-markov-model 
  25.  ------------------------------------------------------------ */  
  26. using System;  
  27.   
  28. namespace Splash  
  29. {  
  30.     public partial class HMM  
  31.     {  
  32.         /// <summary>   
  33.         /// 隐藏状态数目 N   
  34.         /// </summary>   
  35.         public readonly Int32 N;  
  36.   
  37.         /// <summary>   
  38.         /// 观察符号数目 M   
  39.         /// </summary>   
  40.         public readonly Int32 M;   
  41.   
  42.         /// <summary>   
  43.         /// 状态转移矩阵 A   
  44.         /// </summary>   
  45.         public Double[,]  A;  
  46.   
  47.         /// <summary>   
  48.         /// 混淆矩阵(confusion matrix)B   
  49.         /// </summary>   
  50.         public Double[,]  B;  
  51.   
  52.         /// <summary>   
  53.         /// 初始概率向量 PI   
  54.         /// </summary>   
  55.         public Double[]   PI;  
  56.   
  57.         /// <summary>   
  58.         /// 构造函数   
  59.         /// </summary>   
  60.         /// <param name="StatesNum">隐藏状态数目</param>   
  61.         /// <param name="ObservationSymbolsNum">观察符号数目</param>   
  62.         public HMM(Int32 StatesNum, Int32 ObservationSymbolsNum)  
  63.         {  
  64.             N = StatesNum;              // 隐藏状态数目   
  65.             M = ObservationSymbolsNum;  // 观察符号数目   
  66.   
  67.             A = new Double[N, N];   // 状态转移矩阵   
  68.             B = new Double[N, M];   // 混淆矩阵    
  69.             PI = new Double[N];     // 初始概率向量   
  70.         }          
  71.     }  
  72. }  

Viterbi.cs(维特比算法)

[c-sharp] view plaincopyprint?
  1. using System;  
  2.   
  3. namespace Splash  
  4. {  
  5.     partial class HMM  
  6.     {  
  7.         /// <summary>   
  8.         /// 维特比算法:通过给定的观察序列,推算出可能性最大的隐藏状态序列   
  9.         /// Viterbi Algorithm: Finding most probable sequence of hidden states   
  10.         /// </summary>   
  11.         /// <param name="OB">已知的观察序列</param>   
  12.         /// <param name="Probability">可能性最大的隐藏状态序列的概率</param>   
  13.         /// <returns>可能性最大的隐藏状态序列</returns>   
  14.         /// <remarks>使用双精度运算,不输出中间结果</remarks>   
  15.         public Int32[] Viterbi(Int32[] OB, out Double Probability)  
  16.         {  
  17.             Double[,] DELTA;  
  18.             Int32[,] PSI;  
  19.   
  20.             return Viterbi(OB, out DELTA, out PSI, out Probability);  
  21.         }  
  22.   
  23.         /// <summary>   
  24.         /// 维特比算法:通过给定的观察序列,推算出可能性最大的隐藏状态序列   
  25.         /// </summary>   
  26.         /// <param name="OB">已知的观察序列</param>   
  27.         /// <param name="DELTA">输出中间结果:局部最大概率</param>   
  28.         /// <param name="PSI">输出中间结果:反向指针指示最可能路径</param>   
  29.         /// <param name="Probability">可能性最大的隐藏状态序列的概率</param>   
  30.         /// <returns>可能性最大的隐藏状态序列</returns>    
  31.         /// <remarks>使用双精度运算,且输出中间结果</remarks>   
  32.         public Int32[] Viterbi(Int32[] OB, out Double[,] DELTA, out Int32[,] PSI, out Double Probability)  
  33.         {              
  34.             DELTA = new Double[OB.Length, N];   // 局部概率   
  35.             PSI = new Int32[OB.Length, N];      // 反向指针   
  36.   
  37.             // 1. 初始化   
  38.             for (Int32 j = 0; j < N; j++)  
  39.             {  
  40.                 DELTA[0, j] = PI[j] * B[j, OB[0]];  
  41.             }  
  42.   
  43.             // 2. 递归   
  44.             for (Int32 t = 1; t < OB.Length; t++)  
  45.             {  
  46.                 for (Int32 j = 0; j < N; j++)  
  47.                 {  
  48.                     Double MaxValue = DELTA[t - 1, 0] * A[0, j];  
  49.                     Int32 MaxValueIndex = 0;  
  50.                     for (Int32 i = 1; i < N; i++)  
  51.                     {  
  52.                         Double Value = DELTA[t - 1, i] * A[i, j];  
  53.                         if (Value > MaxValue)  
  54.                         {  
  55.                             MaxValue = Value;  
  56.                             MaxValueIndex = i;  
  57.                         }  
  58.                     }  
  59.   
  60.                     DELTA[t, j] = MaxValue * B[j, OB[t]];  
  61.                     PSI[t, j] = MaxValueIndex; // 记录下最有可能到达此状态的上一个状态   
  62.                 }  
  63.             }  
  64.   
  65.             // 3. 终止   
  66.             Int32[] Q = new Int32[OB.Length];   // 定义最佳路径   
  67.             Probability = DELTA[OB.Length - 1, 0];  
  68.             Q[OB.Length - 1] = 0;  
  69.             for (Int32 i = 1; i < N; i++)  
  70.             {  
  71.                 if (DELTA[OB.Length - 1, i] > Probability)  
  72.                 {  
  73.                     Probability = DELTA[OB.Length - 1, i];  
  74.                     Q[OB.Length - 1] = i;  
  75.                 }  
  76.             }  
  77.   
  78.             // 4. 路径回溯   
  79.             for (Int32 t = OB.Length - 2; t >= 0; t--)  
  80.             {  
  81.                 Q[t] = PSI[t + 1, Q[t + 1]];  
  82.             }  
  83.   
  84.             return Q;  
  85.         }  
  86.   
  87.         /// <summary>   
  88.         /// 维特比算法:通过给定的观察序列,推算出可能性最大的隐藏状态序列   
  89.         /// </summary>   
  90.         /// <param name="OB">已知的观察序列</param>   
  91.         /// <param name="Probability">可能性最大的隐藏状态序列的概率</param>   
  92.         /// <returns>可能性最大的隐藏状态序列</returns>   
  93.         /// <remarks>使用对数运算,不输出中间结果</remarks>   
  94.         public Int32[] ViterbiLog(Int32[] OB, out Double Probability)  
  95.         {  
  96.             Double[,] DELTA;  
  97.             Int32[,] PSI;    
  98.   
  99.             return ViterbiLog(OB, out DELTA, out PSI, out Probability);  
  100.         }  
  101.   
  102.         /// <summary>   
  103.         /// 维特比算法:通过给定的观察序列,推算出可能性最大的隐藏状态序列   
  104.         /// </summary>   
  105.         /// <param name="OB">已知的观察序列</param>   
  106.         /// <param name="DELTA">输出中间结果:局部最大概率。结果为自然对数值</param>   
  107.         /// <param name="PSI">输出中间结果:反向指针指示最可能路径</param>   
  108.         /// <param name="Probability">可能性最大的隐藏状态序列的概率</param>   
  109.         /// <returns>可能性最大的隐藏状态序列</returns>    
  110.         /// <remarks>使用对数运算,且输出中间结果</remarks>   
  111.         public Int32[] ViterbiLog(Int32[] OB, out Double[,] DELTA, out Int32[,] PSI, out Double Probability)  
  112.         {              
  113.             DELTA = new Double[OB.Length, N];   // 局部概率   
  114.             PSI = new Int32[OB.Length, N];      // 反向指针   
  115.   
  116.             // 0. 预处理   
  117.             Double[,] LogA = new Double[N, N];  
  118.             for (Int32 i = 0; i < N; i++)  
  119.             {  
  120.                 for (Int32 j = 0; j < N; j++)  
  121.                 {  
  122.                     LogA[i, j] = Math.Log(A[i, j]);  
  123.                 }  
  124.             }  
  125.   
  126.             Double[,] LogBIOT = new Double[N, OB.Length];  
  127.             for (Int32 i = 0; i < N; i++)  
  128.             {  
  129.                 for (Int32 t = 0; t < OB.Length; t++)  
  130.                 {  
  131.                     LogBIOT[i, t] = Math.Log(B[i, OB[t]]);  
  132.                 }  
  133.             }  
  134.   
  135.             Double[] LogPI = new Double[N];  
  136.             for (Int32 i = 0; i < N; i++)  
  137.             {  
  138.                 LogPI[i] = Math.Log(PI[i]);  
  139.             }  
  140.   
  141.             // 1. 初始化   
  142.             for (Int32 j = 0; j < N; j++)  
  143.             {  
  144.                 DELTA[0, j] = LogPI[j] + LogBIOT[j, 0];  
  145.             }  
  146.   
  147.             // 2. 递归   
  148.             for (Int32 t = 1; t < OB.Length; t++)  
  149.             {  
  150.                 for (Int32 j = 0; j < N; j++)  
  151.                 {  
  152.                     Double MaxValue = DELTA[t - 1, 0] + LogA[0, j];  
  153.                     Int32 MaxValueIndex = 0;  
  154.                     for (Int32 i = 1; i < N; i++)  
  155.                     {  
  156.                         Double Value = DELTA[t - 1, i] + LogA[i, j];  
  157.                         if (Value > MaxValue)  
  158.                         {  
  159.                             MaxValue = Value;  
  160.                             MaxValueIndex = i;  
  161.                         }  
  162.                     }  
  163.   
  164.                     DELTA[t, j] = MaxValue + LogBIOT[j, t];  
  165.                     PSI[t, j] = MaxValueIndex; // 记录下最有可能到达此状态的上一个状态   
  166.                 }  
  167.             }  
  168.   
  169.             // 3. 终止   
  170.             Int32[] Q = new Int32[OB.Length];   // 定义最佳路径   
  171.             Probability = DELTA[OB.Length - 1, 0];  
  172.             Q[OB.Length - 1] = 0;  
  173.             for (Int32 i = 1; i < N; i++)  
  174.             {  
  175.                 if (DELTA[OB.Length - 1, i] > Probability)  
  176.                 {  
  177.                     Probability = DELTA[OB.Length - 1, i];  
  178.                     Q[OB.Length - 1] = i;  
  179.                 }  
  180.             }  
  181.   
  182.             // 4. 路径回溯   
  183.             Probability = Math.Exp(Probability);  
  184.             for (Int32 t = OB.Length - 2; t >= 0; t--)  
  185.             {  
  186.                 Q[t] = PSI[t + 1, Q[t + 1]];  
  187.             }  
  188.   
  189.             return Q;  
  190.         }  
  191.     }  
  192. }  

Forward.cs(前向算法)

[c-sharp] view plaincopyprint?
  1. using System;  
  2.   
  3. namespace Splash  
  4. {  
  5.     partial class HMM  
  6.     {  
  7.         /// <summary>   
  8.         /// 前向算法:计算观察序列的概率   
  9.         /// Forward Algorithm: Finding the probability of an observed sequence   
  10.         /// </summary>   
  11.         /// <param name="OB">已知的观察序列</param>   
  12.         /// <returns>观察序列的概率</returns>   
  13.         /// <remarks>使用双精度运算,不输出中间结果</remarks>   
  14.         public Double Forward(Int32[] OB)  
  15.         {  
  16.             Double[,] ALPHA;    // 只声明,不定义   
  17.   
  18.             return Forward(OB, out ALPHA);  
  19.         }  
  20.   
  21.         /// <summary>   
  22.         /// 前向算法:计算观察序列的概率   
  23.         /// </summary>   
  24.         /// <param name="OB">已知的观察序列</param>   
  25.         /// <param name="ALPHA">输出中间结果:局部概率</param>   
  26.         /// <returns>观察序列的概率</returns>   
  27.         /// <remarks>使用双精度运算,输出中间结果</remarks>   
  28.         public Double Forward(Int32[] OB, out Double[,] ALPHA)  
  29.         {              
  30.             ALPHA = new Double[OB.Length, N];   // 局部概率   
  31.   
  32.             // 1. 初始化:计算初始时刻所有状态的局部概率   
  33.             for (Int32 j = 0; j < N; j++)  
  34.             {  
  35.                 ALPHA[0, j] = PI[j] * B[j, OB[0]];  
  36.             }  
  37.   
  38.             // 2. 归纳:递归计算每个时间点的局部概率   
  39.             for (Int32 t = 1; t < OB.Length; t++)  
  40.             {  
  41.                 for (Int32 j = 0; j < N; j++)  
  42.                 {  
  43.                     Double Sum = 0;  
  44.                     for (Int32 i = 0; i < N; i++)  
  45.                     {  
  46.                         Sum += ALPHA[t - 1, i] * A[i, j];  
  47.                     }  
  48.   
  49.                     ALPHA[t, j] = Sum * B[j, OB[t]];  
  50.                 }  
  51.             }  
  52.   
  53.             // 3. 终止:观察序列的概率等于最终时刻所有局部概率之和   
  54.             Double Probability = 0;  
  55.             for (Int32 i = 0; i < N; i++)  
  56.             {  
  57.                 Probability += ALPHA[OB.Length - 1, i];  
  58.             }  
  59.   
  60.             return Probability;  
  61.         }  
  62.   
  63.         /// <summary>   
  64.         /// 带比例因子修正的前向算法:计算观察序列的概率   
  65.         /// </summary>   
  66.         /// <param name="OB">已知的观察序列</param>   
  67.         /// <param name="ALPHA">中间结果:局部概率</param>   
  68.         /// <param name="SCALE">中间结果:比例因子</param>   
  69.         /// <returns>观察序列的概率(自然对数值)</returns>   
  70.         private Double ForwardWithScale(Int32[] OB, ref Double[,] ALPHA, ref Double[] SCALE)  
  71.         {  
  72.             if(ALPHA == null) ALPHA = new Double[OB.Length, N];  
  73.             if(SCALE == null) SCALE = new Double[OB.Length];  
  74.   
  75.             // 1. 初始化   
  76.             SCALE[0] = 0;  
  77.             for (Int32 j = 0; j < N; j++)  
  78.             {  
  79.                 ALPHA[0, j] = PI[j] * B[j, OB[0]];  
  80.                 SCALE[0] += ALPHA[0, j];  
  81.             }  
  82.   
  83.             for (Int32 j = 0; j < N; j++)  
  84.             {  
  85.                 ALPHA[0, j] /= SCALE[0];  
  86.             }  
  87.   
  88.             // 2. 归纳   
  89.             for (Int32 t = 1; t < OB.Length; t++)  
  90.             {  
  91.                 SCALE[t] = 0;  
  92.                 for (Int32 j = 0; j < N; j++)  
  93.                 {  
  94.                     Double Sum = 0;  
  95.                     for (Int32 i = 0; i < N; i++)  
  96.                     {  
  97.                         Sum += ALPHA[t - 1, i] * A[i, j];  
  98.                     }  
  99.   
  100.                     ALPHA[t, j] = Sum * B[j, OB[t]];  
  101.                     SCALE[t] += ALPHA[t, j];  
  102.                 }  
  103.   
  104.                 for (Int32 j = 0; j < N; j++)  
  105.                 {  
  106.                     ALPHA[t, j] /= SCALE[t];  
  107.                 }  
  108.             }              
  109.   
  110.             // 3. 终止   
  111.             Double Probability = 0;  
  112.             for (Int32 t = 0; t < OB.Length; t++)  
  113.             {  
  114.                 Probability += Math.Log(SCALE[t]);  
  115.             }  
  116.   
  117.             return Probability;     // 自然对数值   
  118.         }  
  119.     }  
  120. }  

Backward.cs(后向算法)

[c-sharp] view plaincopyprint?
  1. using System;  
  2.   
  3. namespace Splash  
  4. {  
  5.     partial class HMM  
  6.     {  
  7.         /// <summary>   
  8.         /// 后向算法:计算观察序列的概率   
  9.         /// </summary>   
  10.         /// <param name="OB">已知的观察序列</param>   
  11.         /// <returns>观察序列的概率</returns>   
  12.         public Double Backward(Int32[] OB)  
  13.         {  
  14.             Double[,] BETA;     // 只声明,不定义   
  15.   
  16.             return Backward(OB, out BETA);  
  17.         }  
  18.   
  19.         /// <summary>   
  20.         /// 后向算法:计算观察序列的概率   
  21.         /// </summary>   
  22.         /// <param name="OB">已知的观察序列</param>   
  23.         /// <param name="BETA">中间结果</param>   
  24.         /// <returns>观察序列的概率</returns>   
  25.         public Double Backward(Int32[] OB, out Double[,] BETA)  
  26.         {              
  27.             BETA = new Double[OB.Length, N];  
  28.   
  29.             // 初始化   
  30.             for (Int32 j = 0; j < N; j++)  
  31.             {  
  32.                 BETA[OB.Length - 1, j] = 1.0;  
  33.             }  
  34.   
  35.             // 归纳   
  36.             for (Int32 t = OB.Length - 2; t >= 0; t--)  
  37.             {  
  38.                 for (Int32 j = 0; j < N; j++)  
  39.                 {  
  40.                     Double Sum = 0;  
  41.                     for (Int32 i = 0; i < N; i++)  
  42.                     {  
  43.                         Sum += A[j, i] * B[i, OB[t + 1]] * BETA[t + 1, i];  
  44.                     }  
  45.   
  46.                     BETA[t, j] = Sum;  
  47.                 }  
  48.             }  
  49.   
  50.             // 终止   
  51.             Double Probability = 0;  
  52.             for (Int32 i = 0; i < N; i++)  
  53.             {  
  54.                 Probability += BETA[0, i];  
  55.             }  
  56.   
  57.             return Probability;  
  58.         }  
  59.   
  60.         /// <summary>   
  61.         /// 带比例因子修正的后向算法   
  62.         /// </summary>   
  63.         /// <param name="OB">已知的观察序列</param>   
  64.         /// <param name="SCALE">用于修正的比例因子</param>   
  65.         /// <param name="BETA">中间结果:局部概率</param>   
  66.         private void BackwardWithScale(Int32[] OB, Double[] SCALE, ref Double[,] BETA)  
  67.         {  
  68.             if(BETA == null) BETA = new Double[OB.Length, N];  
  69.   
  70.             // 初始化   
  71.             for (Int32 j = 0; j < N; j++)  
  72.             {  
  73.                 BETA[OB.Length - 1, j] = 1.0 / SCALE[OB.Length - 1];  
  74.             }  
  75.   
  76.             // 归纳   
  77.             for (Int32 t = OB.Length - 2; t >= 0; t--)  
  78.             {  
  79.                 for (Int32 j = 0; j < N; j++)  
  80.                 {  
  81.                     Double Sum = 0;  
  82.                     for (Int32 i = 0; i < N; i++)  
  83.                     {  
  84.                         Sum += A[j, i] * B[i, OB[t + 1]] * BETA[t + 1, i];  
  85.                     }  
  86.   
  87.                     BETA[t, j] = Sum / SCALE[t];  
  88.                 }  
  89.             }  
  90.         }  
  91.     }  
  92. }  

BaumWelch.cs(前向-后向算法)

[c-sharp] view plaincopyprint?
  1. using System;  
  2.   
  3. namespace Splash  
  4. {  
  5.     partial class HMM  
  6.     {  
  7.         /// <summary>   
  8.         /// 前向-后向算法,用于参数学习   
  9.         /// Forward-backward algorithm: Generating a HMM from a sequence of obersvations   
  10.         /// </summary>   
  11.         /// <param name="OB">已知的观察序列</param>           
  12.         /// <param name="LogProbInit">初始自然对数概率</param>   
  13.         /// <param name="LogProbFinal">最终自然对数概率</param>   
  14.         /// <param name="ExitError">迭代中允许的自然对数概率误差,缺省0.001</param>   
  15.         /// <param name="MSP">状态概率最小值,缺省0.001</param>   
  16.         /// <param name="MOP">观察概率最小值,缺省0.001</param>   
  17.         /// <returns>迭代次数</returns>   
  18.         /// <remarks>修正UMDHMM在模型参数调整中的错误</remarks>           
  19.         public Int32 BaumWelch(Int32[] OB, out Double LogProbInit, out Double LogProbFinal,   
  20.             Double ExitError = 0.001, Double MSP = 0.001, Double MOP = 0.001)  
  21.         {  
  22.             Double[,] ALPHA = null;  
  23.             Double[,] BETA = null;              
  24.             Double[] SCALE = null;  
  25.             Double[,] GAMMA = null;  
  26.             Double[, ,] XI = null;  
  27.   
  28.             Double LogProbForward = LogProbInit = ForwardWithScale(OB, ref ALPHA, ref SCALE); // 前向算法   
  29.             BackwardWithScale(OB, SCALE, ref BETA); // 后向算法   
  30.             ComputeGamma(ALPHA, BETA, ref GAMMA);   // 求解各时刻位于各隐藏状态的概率矩阵   
  31.             ComputeXI(OB, ALPHA, BETA, ref XI);     // 求解各时刻位于各隐藏状态及下一时刻位于各隐藏状态的关联概率矩阵   
  32.               
  33.             Int32 Iterations;  
  34.             Double LogProbPrev = LogProbForward;  
  35.             for(Iterations = 1; ; Iterations++)  
  36.             {   // 重新估计初始概率向量   
  37.                 for (Int32 i = 0; i < N; i++)  
  38.                 {   // 注意:此处修正UMDHMM错误,以保证概率总和为1   
  39.                     PI[i] = MSP + (1 - MSP * N) * GAMMA[0, i];  
  40.                 }  
  41.   
  42.                 for(Int32 i = 0; i < N; i++)  
  43.                 {   // 重新估计状态转移矩阵   
  44.                     Double DenominatorA = 0;  
  45.                     for(Int32 t = 0; t < OB.Length - 1; t++)  
  46.                         DenominatorA += GAMMA[t, i];  
  47.                       
  48.                     for(Int32 j = 0; j < N; j++)  
  49.                     {  
  50.                         Double NumeratorA = 0;  
  51.                         for(Int32 t = 0; t < OB.Length - 1; t++)  
  52.                             NumeratorA += XI[t,i,j];  
  53.   
  54.                         // 注意:此处修正UMDHMM错误,以保证概率总和为1   
  55.                         A[i, j] = MSP + (1 - MSP * N) * NumeratorA / DenominatorA;  
  56.                     }  
  57.   
  58.                     // 重新估计混淆矩阵   
  59.                     Double DenominatorB = DenominatorA + GAMMA[OB.Length - 1, i];  
  60.                     for(Int32 k = 0; k < M; k++)  
  61.                     {  
  62.                         Double NumeratorB = 0;  
  63.                         for(Int32 t = 0; t < OB.Length; t++)  
  64.                         {  
  65.                             if(OB[t] == k) NumeratorB += GAMMA[t,i];  
  66.                         }  
  67.   
  68.                         // 注意:此处修正UMDHMM错误,以保证概率总和为1   
  69.                         B[i, k] = MOP + (1 - MOP * M) * NumeratorB / DenominatorB;  
  70.                     }                     
  71.                 } // End for i   
  72.   
  73.                 // 计算概率差,决定是否停止迭代   
  74.                 LogProbForward = ForwardWithScale(OB, ref ALPHA, ref SCALE);  
  75.                 if (LogProbForward - LogProbPrev <= ExitError) break;  
  76.   
  77.                 BackwardWithScale(OB, SCALE, ref BETA);  
  78.                 ComputeGamma(ALPHA, BETA, ref GAMMA);  
  79.                 ComputeXI(OB, ALPHA, BETA, ref XI);  
  80.                 LogProbPrev = LogProbForward;  
  81.             } // End for Iterations   
  82.   
  83.             LogProbFinal = LogProbForward;  // 最终概率   
  84.   
  85.             // 返回迭代次数   
  86.             return Iterations;  
  87.         }  
  88.   
  89.         /// <summary>   
  90.         /// 求解t时刻位于隐藏状态Si的概率矩阵   
  91.         /// </summary>   
  92.         /// <param name="ALPHA">前向算法局部概率</param>   
  93.         /// <param name="BETA">后向算法局部概率</param>   
  94.         /// <param name="GAMMA">输出:各时刻位于各隐藏状态的概率矩阵</param>   
  95.         private void ComputeGamma(Double[,] ALPHA, Double[,] BETA, ref Double[,] GAMMA)  
  96.         {  
  97.             Int32 T = ALPHA.GetLength(0);  
  98.             if (GAMMA == null) GAMMA = new Double[T, N];  
  99.   
  100.             for (Int32 t = 0; t < T; t++)  
  101.             {  
  102.                 Double Denominator = 0;  
  103.                 for (Int32 i = 0; i < N; i++)  
  104.                 {  
  105.                     GAMMA[t, i] = ALPHA[t, i] * BETA[t, i];  
  106.                     Denominator += GAMMA[t, i];  
  107.                 }  
  108.   
  109.                 for (Int32 i = 0; i < N; i++)  
  110.                 {  
  111.                     GAMMA[t, i] /= Denominator; // 保证各时刻的概率总和等于1   
  112.                 }  
  113.             }  
  114.         }  
  115.   
  116.         /// <summary>   
  117.         /// 求解t时刻位于隐藏状态Si及t+1时刻位于隐藏状态Sj的概率矩阵   
  118.         /// </summary>   
  119.         /// <param name="OB">观察序列</param>   
  120.         /// <param name="ALPHA">前向算法局部概率</param>   
  121.         /// <param name="BETA">后向算法局部概率</param>   
  122.         /// <param name="XI">输出:求解各时刻位于各隐藏状态及下一时刻位于各隐藏状态的关联概率矩阵</param>   
  123.         private void ComputeXI(Int32[] OB, Double[,] ALPHA, Double[,] BETA, ref Double[,,] XI)  
  124.         {  
  125.             Int32 T = OB.Length;  
  126.             if (XI == null) XI = new Double[T, N, N];  
  127.   
  128.             for (Int32 t = 0; t < T - 1; t++)  
  129.             {  
  130.                 Double Sum = 0;  
  131.                 for (Int32 i = 0; i < N; i++)  
  132.                 {  
  133.                     for (Int32 j = 0; j < N; j++)  
  134.                     {  
  135.                         XI[t, i, j] = ALPHA[t, i] * A[i, j] * B[j, OB[t + 1]] * BETA[t + 1, j];  
  136.                         Sum += XI[t, i, j];  
  137.                     }  
  138.                 }  
  139.   
  140.                 // 保证各时刻的概率总和等于1   
  141.                 for (Int32 i = 0; i < N; i++)  
  142.                     for (Int32 j = 0; j < N; j++)  
  143.                         XI[t, i, j] /= Sum;   
  144.             }  
  145.         }  
  146.     }  
  147. }  
转载:http://blog.csdn.net/jhqin/article/details/6534916

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/352628.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

绘制条形图python_小白学Python(13)——pyecharts 绘制 柱状图/条形图 Bar

Bar-基本示例 1 from example.commons importFaker2 from pyecharts importoptions as opts3 from pyecharts.charts importBar4 5 bar(6 Bar()7 .add_xaxis(Faker.choose())8 .add_yaxis("商家A", Faker.values())9 .add_yaxis("商家B", Faker.values())1…

初进JAVA职场面试小技巧:一个老学长的吐血之作!

看着一批批小白的遭遇&#xff0c;有些无奈&#xff0c;又跟我年轻时有些类似。今天正好有点时间&#xff0c;给你几个建议。 1、在结业之前一定要把自己参与过的项目仔细审视一下&#xff0c;一点要特别熟悉项目的流程功能&#xff0c;另外也要重视自己做过的模块&#xff0c;…

阿里云飞天系统的技术架构(转)

阿里云有以下五大优势&#xff1a;中国万网&#xff0c;提供虚拟主机托管的服务&#xff0c;而且还提供域名等服务&#xff0c;其客户群非常庞大。淘宝、阿里巴巴&#xff08;内部称&#xff1a;B2B&#xff09;、支付宝等其他子公司&#xff1a;有大量的数据分析业务&#xff…

Jenkins 流水线 获取git 分支列表_基于Jenkins的DevOps流水线实践

讲师介绍课程寄语我认为Jenkins是对我这些年运维经验的总结&#xff0c;起初我们运维同学都是编写脚本完成一些自动化的操作。而有了Jenkins我们可以将我们的运维经验与Jenkins设计理念融合完成自动化运维平台。全程最佳实践&#xff0c;Pipeline as Code&#xff0c;打通DevOp…

Java微服务:蛋糕是骗人的,但您不能忽略它

构建微服务实际上意味着什么&#xff1f; 通过微服务框架的眼光回答 忽略微服务的趋势已变得不可能。 有些人会说这只是另一个难以忍受的流行语&#xff0c;而另一些人会背诵打破巨石的优势或采取逆势方法并关注负面因素。 在本文中&#xff0c;我们将深入了解我们拥有的框架…

隐马尔科夫模型C#类库调用示例

[c-sharp] view plaincopyprint?using System; using Splash; namespace SplashCheck { class TestHMMCS { enum Weather { Sunny, Cloudy, Rainy }; // 隐藏状态&#xff08;天气&#xff09; enum Seaweed { Dry, Dryish, Damp, Soggy }…

芯片,开源,数学,计算机

近代数学好像没什么数学定理是中国人命名的&#xff0c;有也是凤毛麟角是广泛意义上的华人命名的。开源Linux内核好像也没有几行代码是中国人贡献的&#xff0c;通用CPU芯片美帝的&#xff0c;计算机美帝发明的&#xff0c;内存/硬盘/显示器&#xff0c;三星台湾造。20年前我大…

C#之继承

本文意在巩固基础知识&#xff0c;并不是对其进行深入剖析&#xff0c;如若对各位高手没有什么作用&#xff0c;请绕过。本文为原创文&#xff0c;所有示例均是博主测试过的&#xff0c;欢迎大家批评指正&#xff0c;如有转载请标明出处&#xff0c;谢谢。继承、封装和多态是面…

python的requests模块功能_python中requests模块的使用方法

本文实例讲述了python中requests模块的使用方法。分享给大家供大家参考。具体分析如下&#xff1a; 在HTTP相关处理中使用python是不必要的麻烦&#xff0c;这包括urllib2模块以巨大的复杂性代价获取综合性的功能。相比于urllib2,Kenneth Reitz的Requests模块更能简约的支持完整…

ODPS技术架构及应用实践

《程序员》杂志2014年10月刊《凌云》云计算大数据阿里云ODPShadoop摘要&#xff1a;ODPS是分布式的海量数据处理平台&#xff0c;提供了丰富的数据处理功能和灵活的编程框架。本文从ODPS面临的挑战、技术架构、Hadoop迁移到ODPS、应用实践注意点等方面带领我们初步了解了ODPS的…

ssh,scp带密码操作

1、远程执行&#xff0c;带密码参数 sshpass 安装命令&#xff1a; yum install sshpass 执行命令&#xff1a; sshpass -p "mima" ssh rootlocalhost --------参数小写p&#xff0c;密码mima 2、非22端口 ssh -p 9062 111.111.111…

junit 测试 dao_JUnit测试Spring Service和DAO(带有内存数据库)

junit 测试 dao这篇文章描述了如何为Spring Web Application的Services和DAO实现JUnit测试。 它建立在Spring MVC-Service-DAO-Persistence Architecture Example的基础上 。 从Github的Spring-Web-JPA-Testing目录中可以找到该示例。 提醒 测试装置 –固定状态&#xff0c;用…

C++判断文件夹是否存在

判断文件夹是否存在一、判断文件夹是否存在&#xff1a; 1.用CreateDirectory(".//FileManege",NULL);如果文件夹FileManege不存在&#xff0c;则创建。 2.或者if(_access(".//FileManege",0)-1)&#xff0c;表示FileManege不存在。 3.或者…

ODPS MR开发 WordCount

参考&#xff1a; ODPS初始篇--客户端配置和使用&#xff1a;http://blog.itpub.net/26613085/viewspace-1327313/ odps dship客户端使用&#xff1a;http://blog.itpub.net/26613085/viewspace-1328434/ 有了上面两篇文章&#xff0c;就可以使用ODPS的客户端&#xff1b;使用O…

跨域设置

# 参考&#xff1a; https://blog.csdn.net/linzi1994/article/details/82724429 https://www.cnblogs.com/ShaunChen/p/5998800.html# 配置详解&#xff1a; # 跨域设置 CORS_ORIGIN_ALLOW_ALL True # 允许所有域名 CORS_ALLOW_CREDENTIALS True # 允许获取cookie CORS_UR…

kdb q介绍

Q起源Kx systems公司的创始人之一Arthur Whitney在2003年研发了列式数据库KDB和它的操作语言q。q也可以写成Q。设计之初&#xff0c;q语言要做到简洁&#xff0c;高效和富表达性。 q的起源受到多种语言的启示。包括APL、LISP和函数式编程。 APL是一个向量语言&#xff0c;所以…

mysql多大_洞悉MySQL底层架构:游走在缓冲与磁盘之间

提起MySQL&#xff0c;其实网上已经有一大把教程了&#xff0c;为什么我还要写这篇文章呢&#xff0c;大概是因为网上很多网站都是比较零散&#xff0c;而且描述不够直观&#xff0c;不能系统对MySQL相关知识有一个系统的学习&#xff0c;导致不能形成知识体系。为此我撰写了这…

odps新手上路之安装Eclipse开发环境

只看楼主更多操作楼主 发表于: 2014-11-07—本帖被 亮伟 执行取消精华操作(2014-11-27)—准备工作&#xff1a;登录阿里云官网&#xff0c;开通odps服务。创建一个odps的project。安装odps的客户端&#xff0c;具体的方法见 传送门下载Eclipse并解压缩。建议到官网上下载。作…

mfc对话框在不同计算机上显示不全

出现&#xff2d;&#xff26;&#xff23;对话框在不同计算机上显示不全的或者显示大小不一样的活可以调整电脑的分辨率也可以在创建对话框时根据分辨率来调整控件。

c++二进制转十进制_二进制,八进制,十进制,十六进制转换详解~

点 击 上 方 蓝 字 关 注 我 们 哦 ^-^本文思维导图&#xff1a;1.数制&#xff1a;用一组固定的数字和一套统一的规则来表示数目的方法称为数制。进位计数制的要素&#xff1a;①、数码&#xff1a;用来表示进制数的元素。二进制&#xff1a;0,1。八进制&#xff1a;0,1,2,3,4…