viterbi算法linux下C++实现
来源:互联网 发布:铁塔倾斜度的算法 编辑:程序博客网 时间:2024/06/11 02:56
算法介绍见博客:http://www.cnblogs.com/tornadomeet/archive/2012/03/24/2415889.html,实现结果与他一样,下面是我的实现细节:
一 程序整体布局
分为loadmodel、viterbi搜索、print输出结果三个部分。主体程序如下:
#include "Viterbi.h"#include <fstream>#include <string>int main(){ Viterbi viterbi_1; viterbi_1.loadModel(); viterbi_1.viterbi(); viterbi_1.print(); return 0;}
二 头文件的定义
头文件中主要用来确定需要用那些函数和数据,这里面使用什么样的数据结构尤其需要考虑,我的实现中
二维数组: vector < vector<type> > , 第一维表示帧等,第二维表示状态数;
观测序列与发射矩阵中第二维的对应: 用map容器;
最后的结果反向遍历得到,然后又正向输出结果: 用stack容器适配器;
具体代码如下:
/* * File: Viterbi.h * Author: junan * * Created on December 3, 2014, 4:16 PM */#include <iostream>#include <vector>#include <fstream>#include <map>#include <stack>#define DBL_MIN 2.2250738585072014e-308#ifndef VITERBI_H#defineVITERBI_H#endif/* VITERBI_H */using namespace std;class Viterbi{public: // default construct function Viterbi(): max_pro(0), forward_path(0){ initProbF = "/home/junan/Documents/C++/viterbi/ArrayIniprob_3.txt"; transF = "/home/junan/Documents/C++/viterbi/ArrayTranmat_3.txt"; emitF = "/home/junan/Documents/C++/viterbi/ArrayRadmat_3.txt"; observF = "/home/junan/Documents/C++/viterbi/ArrayObseque.txt"; char2orderF = "/home/junan/Documents/C++/viterbi/ArrayChar2order_3.txt"; }; fstream& open_file(fstream&, string&); // loadModel: 将模型从文件读入缓存 void loadModel(); // state2observ: 求状态观测序列 void state2observ(); // 开始viterbi搜索 void viterbi(); // 输出结果 void print(); typedef vector< vector<double> >::iterator iter_mat; private: int N, len, forward_path; // N:存储状态数, len: 存储帧数, forward_path: 前向路径 int ord, fra; // ord: 字符对应的序列,f: 第f帧 double tmp, max_pro; vector<double> tmp_vec; // 下面的string用来存储文件的绝对路径 string initProbF, transF, emitF, observF, char2orderF; /* * initProb_vec[i]: 存储状态先验概率, i表示第i个状态的先验概率 * trans_mat[i][j]: 从状态i转移到状态j的转移概率 * emit_mat[i][c]: 用状态i产生字符c的发射概率 * observ_vec[f]: 存储状态序列, f表示第f帧 * backPath[i][f]: 表示第f帧的第i个状态的前一个状态 */ vector<double> initProb_vec; vector< vector<double> > trans_mat; vector< vector<double> > emit_mat; vector<char> obser_vec; vector< vector<int> > backPath; // ifstream: 定义文件流 fstream fin; // 定义关联容器,使观测字符到序列对应 map<char, int> char2order_map; // 定义每个字符在所有状态下产生概率的矩阵 vector< vector<double> > Prob_mat; // 存储最佳状态序列 stack<int> state_stack; };
三 函数的定义
避免代码的重复书写,比如定义了open_file函数,具体代码如下:
#include <fstream>#include <vector>#include <stack>#include <iostream>#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<N; ++i) for (int j=0; j<N; ++j){ if (fin >> tmp) trans_mat[i].push_back(tmp); } // 载入发射矩阵 open_file(fin, emitF); while (!fin.eof()) { for (int i = 0; i<N; ++i) { if (fin >> 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<char>::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; i<N; ++i) // N是状态数 Prob_mat[fra].push_back(emit_mat[ord][i]); }}void Viterbi::viterbi() { backPath.resize(len); iter_mat iter = Prob_mat.begin(); for (; iter!=Prob_mat.end(); ++iter) { fra = iter - Prob_mat.begin(); // 计算第一帧 if (fra==0){ for (int j=0; j<N; ++j){ Prob_mat[fra][j] = Prob_mat[fra][j] * initProb_vec[j]; backPath[fra].push_back(0); // 第一帧前面没有状态了,先设为0 } } // 计算其他帧 else { for (int j=0; j<N; ++j) { max_pro = 0; forward_path = 0; // 使用之前记得重置! for (int i=0; i<N; ++i){ tmp = Prob_mat[fra-1][i] * trans_mat[i][j]; if (tmp>max_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; i<N; ++i) { if (Prob_mat[fra][i]>max_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;}
还有些改进的地方,比如将矩阵归一化等,需待后续完善。
0 0
- viterbi算法linux下C++实现
- viterbi算法实现
- Viterbi 算法应用实现
- R语言实现viterbi算法
- viterbi 算法
- Viterbi 算法
- viterbi算法
- viterbi算法
- Viterbi算法
- HMM的Viterbi算法C#实现
- hmm------java代码实现的viterbi算法
- 隐马尔可夫模型中的Viterbi算法的C++实现
- 隐马尔可夫模型中的Viterbi算法的C++实现
- 维特比算法viterbi的简单实现 python版
- viterbi译码算法简介
- viterbi算法 python版
- Viterbi算法(转)
- 论Viterbi算法
- 软件工程 - 2、项目管理
- 用JS或者jQuery监听 浏览器窗口大小的变化事件
- 剑指offer源码-旋转数组的最小数字
- 广告牌安放问题
- [Python]Invalid mode ('w') or filename: 'd:\x0bideo'
- viterbi算法linux下C++实现
- 未经处理的异常:0xC0000005:读取/写入位置冲突——从去掉字符串所有空格说起
- 表变量与临时表的优缺点?
- oracle 行转列
- Android 颜色渲染(九) PorterDuff及Xfermode详解
- 软件工程 - 3、项目开发
- SEO工作时都会用哪些辅助工具
- 第三章
- 仿网易彩票思路