算法介绍见博客:http://www.cnblogs.com/tornadomeet/archive/2012/03/24/2415889.html,实现结果与他一样,下面是我的实现细节:
分为loadmodel、viterbi搜索、print输出结果三个部分。主体程序如下:
#include "Viterbi.h"
#include
#include
int main()
{
Viterbi viterbi_1;
viterbi_1.loadModel();
viterbi_1.viterbi();
viterbi_1.print();
return 0;
}
头文件中主要用来确定需要用那些函数和数据,这里面使用什么样的数据结构尤其需要考虑,我的实现中
二维数组: vector < vector
观测序列与发射矩阵中第二维的对应: 用map容器;
最后的结果反向遍历得到,然后又正向输出结果: 用stack容器适配器;
具体代码如下:
/*
* File: Viterbi.h
* Author: junan
*
* Created on December 3, 2014, 4:16 PM
*/
#include
#include
#include
#include
避免代码的重复书写,比如定义了open_file函数,具体代码如下:
#include
#include
#include
#include
#include "Viterbi.h"
using namespace std;
//void Viterbi::loadModel(string initProF, string transF, string emitF){
void Viterbi::loadModel(){
// 载入初始矩阵
open_file(fin, initProbF);
while (fin >> tmp)
initProb_vec.push_back(tmp);
N = initProb_vec.size(); // 状态数
// 载入状态转移矩阵
open_file(fin, transF);
trans_mat.resize(N);
for (int i=0; i> tmp)
trans_mat[i].push_back(tmp);
}
// 载入发射矩阵
open_file(fin, emitF);
while (!fin.eof()) {
for (int i = 0; i> tmp)
tmp_vec.push_back(tmp);
}
emit_mat.push_back(tmp_vec);
tmp_vec.clear();
}
// 载入观测序列
open_file(fin, observF);
char ch;
while (fin >> ch)
obser_vec.push_back(ch);
len = obser_vec.size();
// 载入观测字符与序号之间的对应
open_file(fin, char2orderF);
int order;
while (fin >> ch) {
fin >> order;
char2order_map[ch] = order;
}
// 初始化概率矩阵
state2observ();
}
fstream& Viterbi::open_file(fstream& filein, string& filename) {
filein.close();
filein.clear();
filein.open(filename.c_str(), ios::in);
if (!filein)
cerr << "fail to open file!" << flush;
return filein;
}
/* 对状态矩阵进行初始化
* 1 由字符找到序号
* 2 根据序号返回字符在该状态下的发射概率
* 3 得到整个矩阵
*/
void Viterbi::state2observ(){
Prob_mat.resize(len);
vector::const_iterator iter = obser_vec.begin();
for (; iter!=obser_vec.end(); ++iter) {
fra = iter - obser_vec.begin();
ord = char2order_map[*iter];
for (int i=0; imax_pro) {
max_pro = tmp;
forward_path = i;
}
}
backPath[fra].push_back(forward_path);
Prob_mat[fra][j] = max_pro * Prob_mat[fra][j];
}
}
}
// 所有帧计算完毕,找最大概率,然后找最优路径
max_pro = Prob_mat[fra][0];
int last_state(0);
for (int i=0; imax_pro) {
max_pro = Prob_mat[fra][i];
last_state = i;
}
}
state_stack.push(last_state);
len = obser_vec.size();
for (fra=len-1; fra>0; --fra) {
last_state = backPath[fra][last_state];
state_stack.push(last_state);
}
}
void Viterbi::print() {
cout << "最佳状态序列是:" << endl;
while (!state_stack.empty()) {
cout << state_stack.top() << " " << nounitbuf; // 刷新所有输出
state_stack.pop();
}
cout << endl;
cout << "最佳状态序列对应的概率为: " << max_pro << endl;
}
还有些改进的地方,比如将矩阵归一化等,需待后续完善。