HMM实现基于拼音的文本纠错

文章将从以下4个小节进行描述:

1.问题描述

2.思路

3.源码

4.应用

1.问题描述

对于歌曲的语音搜索实现方案之一如下。

使用百度语音进行用户语音识别,返回的字符串调用歌词搜索,而歌词搜索使用的是分词的方式进行的索引建立,因此字符串识别的准确率直接影响最后返回歌曲的正确性。

而百度语音是基于非特定样本进行的训练,其语言环境涵盖非常广,而对于歌曲语言搜索这个业务来说,我们的语料库只是特定的歌词文本集,那么如何解决这个纠正语言识别结果的问题便是这个模型的解决目标。

2.思路

语音识别返回的结果之所以与歌词库不匹配在于其上下文环境不符合歌词环境,但大部分文字是同音的,因此使用第三方java开源包将识别结果先转换为拼音形式,在使用HMM模型对拼音重新组合,从而得到符合歌词环境的字符串。

而在HMM模型中,几个比较重要的概念就是隐藏状态和可观测状态,以及隐藏状态到可观测状态的发射概率、隐藏状态间的转移概率。在这里,可观测状态明显就是拼音形式,而隐藏状态则是它背后的汉字形式,而在歌词环境中,汉字之间是有上下文联系的,也就是说汉字之间在歌词这个语料库中有其独特的转移概率,而每个汉字到其所有的发音都有一个发射概率,且和为1。但是在这里,由于使用的java包可以简单的认为每个字都是单音的,因此,对于每个字而言,它们都只有一个发音,而发射概率为1。

所以现在主要需要做的就是训练HMM模型,即计算字间的转移概率。

3.源码

以下是简要的代码demo

package HmmViterbi_Correction;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map.Entry;
import java.util.Stack;

public class HmmModel {
private static String CharSet = "UTF-8";

//拼音与字符对照表
private HashMap<String, HashSet<Character>> pinyinMap = new HashMap<String, HashSet<Character>>(); 
//字符与其条件概率对照表:<char1, <char2, pro(char1,char2|char1)>>
private HashMap<Character, HashMap<Character, Double>> transferMap = new HashMap<Character, HashMap<Character, Double>>();
//单字符统计表
private HashMap<Character, Integer> countMap = new HashMap<Character, Integer>();

public static void main(String[] args) {
HmmModel hmm=new HmmModel("data/pinyin.txt");
//hmm.showPinyinMap();
//hmm.showTransferMap();

String str="窝德爱移除酒香四年";
String output = hmm.predict(str);
System.out.println(output);
}

/**
* 预测
*/
public String predict(String str) {
String buffer = PinYin.simplify(str).trim();
int len=buffer.length();
String[] pinyins = new String[len];
for (int i = 0; i < len; i++) {
pinyins[i] = PinYin.toPY(buffer.charAt(i));
}

HashSet<Character> temp = pinyinMap.get(pinyins[0]); //首字符
HashSet<PathNode> chars1 = new HashSet<PathNode>();
for (char ch:temp) {
chars1.add(new PathNode(1, ch));
}

for (int i = 1; i < pinyins.length; i++) {
HashSet<Character> chars2 = pinyinMap.get(pinyins[i]);    //后一个字的候选集
HashSet<PathNode> chars3 = new HashSet<PathNode>();
for (char ch2:chars2) {
double maxValue=-1;
PathNode pNode=null;
for (PathNode node1:chars1) {
double value = node1.prob * checkProb(node1.ch,ch2); //p(ch2|ch1)
if (value>maxValue) { //如果超过了当前最大值
maxValue=value;
pNode=new PathNode(value, ch2);
pNode.preNode=node1;
}
}
chars3.add(pNode);
}
chars1=chars3;
}

PathNode targetNode=null;
double maxValue=-1;
for (PathNode node:chars1) {
if (node.prob>maxValue) {
maxValue=node.prob;
targetNode=node;
}
}

Stack<Character> charStack=new Stack<Character>();
PathNode path=targetNode;
while (path!=null) {
charStack.push(path.ch);
path=path.preNode;
}

StringBuilder stringBuilder=new StringBuilder();
while (!charStack.isEmpty()) {
stringBuilder.append(charStack.pop());
}
return stringBuilder.toString();
}

//需考虑null的情况
private double checkProb(char ch1, char ch2) { 
HashMap<Character, Double> proMap = transferMap.get(ch1);
if (proMap==null) {
return 0.01;
}
Double value = proMap.get(ch2);
if (value==null) {
return 0.01;
}
return value;
}

public HmmModel(String path) {
learnfromFile(path);
}

/**
* 训练
*/
private void learnfromFile(String path) {
BufferedReader br=null;
try {
br = new BufferedReader(new InputStreamReader(new FileInputStream(path), Charset.forName(CharSet)));
String line=null;
while ((line=br.readLine())!=null) {
line=line.trim();
if (line.equals("")) { //跳过空行
continue;
}
line = PinYin.simplify(line);  //繁体转简体
for (int i = 0; i < line.length(); i++) {
if (i>0) {
addProb(line.charAt(i-1), line.charAt(i));
}

char ch = line.charAt(i);
Integer count=countMap.get(ch);
if (count==null) {
countMap.put(ch, 1);
} else {
countMap.put(ch, ++count);
}

String py = PinYin.toPY(ch);
HashSet<Character> charSet=null;
if ((charSet = pinyinMap.get(py))==null) {
charSet=new HashSet<Character>();
charSet.add(ch);
pinyinMap.put(py, charSet);
} else {
charSet.add(ch);
}
}
}
for (Character ch : transferMap.keySet()) {
int dinominator=countMap.get(ch);
HashMap<Character, Double> proMap = transferMap.get(ch);
for (Character ch2 : proMap.keySet()) {
double newValue = proMap.get(ch2)/dinominator;
proMap.put(ch2, newValue);
}
}

} catch (IOException e) {
System.err.println("reader load failed");
e.printStackTrace();
} finally {
if (br!=null) {
try {
br.close();
} catch (IOException e) {
System.err.println("reader close failed");
e.printStackTrace();
}
}
}
}

private void addProb(char ch1, char ch2) { //顺序:ch1 ch2 ch3... p(ch2|ch1)=p(ch1,ch2)/p(ch1)
HashMap<Character, Double> proMap = transferMap.get(ch1);
if (proMap==null) {
proMap=new HashMap<Character, Double>();
transferMap.put(ch1, proMap);
}
Double value=proMap.get(ch2);
if (value==null) {
proMap.put(ch2, 1.0);
} else {
proMap.put(ch2, ++value);
}
}

public void showPinyinMap() {
System.out.println("pinyinMap:");
for (Entry<String, HashSet<Character>> entry : pinyinMap.entrySet()) {
System.out.print(entry.getKey()+"->[");
HashSet<Character> charSet=entry.getValue();
for (Character ch : charSet) {
System.out.print(ch+",");
}
System.out.println("]");
}
}

public void showTransferMap() {
for (Entry<Character, HashMap<Character, Double>> entry : transferMap.entrySet()) {
char ch1 = entry.getKey();
HashMap<Character, Double> probMap=entry.getValue();
for (Entry<Character, Double> entry2 : probMap.entrySet()) {
char ch2 = entry2.getKey();
double value = entry2.getValue();
System.out.print(ch2+"|"+ch1+"="+value+" ");
}
System.out.println();
}
}

}

class PathNode implements Comparable<PathNode> {
public PathNode preNode=null;
public char ch;
public double prob=0;

public PathNode(double probability, char ch) {
this.ch=ch;
prob = probability;
}

@Override
public int compareTo(PathNode o) {
if (this.prob > o.prob) {
return 1;

if (this.prob < o.prob) {
return -1;
}
return 0;
}

@Override
public String toString() {
StringBuilder stb=new StringBuilder();
stb.append("(").append(ch).append(",").append(prob).append(")");
return stb.toString();
}

}

4.应用

此算法基于HMM实现,适合用于语音识别等纠错场景,当然对于这种隐藏状态和可见状态并存的模型,这都是适用的。


使用HMM隐式马尔科夫链实现基于拼音的文本纠错相关推荐

  1. NLP 《隐式马尔科夫链》

    一:模型介绍和学习 隐式马尔科夫模型,是对马尔科夫链的扩展,是一个双重的随机过程,它包含一个隐藏链层S = {S1, S2, S3, ⋯ , SN}和一个可观测的链层W = {W1, W2, W3, ...

  2. HHM(Hidden Markov Model)-隐式马尔科夫模型

    HHM(Hidden Markov Model)-隐式马尔科夫模型 隐式马尔科夫模型是通过对观察序列的观测推导出隐藏状态.举例说明,由于本人是在十一小长假写下该篇文章,因此就拿小长假的出行计划介绍该算 ...

  3. 隐式马尔科夫模型(HMM)

    一.简介 1.隐马尔可夫模型(HiddenMarkovmodel/HMM)是一种结构最简单的动态贝叶斯网的生成模型,它也是一种著名的有向图模型.它是一种对数据序列(训练数据出现的次序对结果有影响)进行 ...

  4. 灰色马尔科夫链matlab,基于灰色-马尔科夫模型的电力功率预测

    利用1998-2009每年的用电量预测2010年的用电量 QQ图片20130515210109.jpg (20.32 KB, 下载次数: 18) 1998-2009每年用电量数据 2013-5-15 ...

  5. NLP 《马尔科夫链》

    定义:是一个离散的随机过程,状态的变化都是依赖于状态转移矩阵,用来描述状态空间中经过从一个状态到另一个状态的转换的随机过程,用图的形式表示如下,下图是截图别人的. 马尔科夫链是基于两个假设: 有限视野 ...

  6. MCMC(二)马尔科夫链

    在MCMC(一)蒙特卡罗方法中,我们讲到了如何用蒙特卡罗方法来随机模拟求解一些复杂的连续积分或者离散求和的方法,但是这个方法需要得到对应的概率分布的样本集,而想得到这样的样本集很困难.因此我们需要本篇 ...

  7. 马尔科夫链与MCMC方法

    马尔科夫链概述 基本思想: 过去所有的信息都已经被保存到了现在的状态,基于现在就可以预测未来. Example: 假如每天的天气是一个状态的话,那今天是不是晴天只依赖于昨天的天气,而和前天的天气没有任 ...

  8. MCMC学习笔记-马尔科夫链概述

    参考文章:MCMC(二)马尔科夫链 - 刘建平Pinard - 博客园 写给小白看的马尔科夫链(Markov Chain)最佳入门教程_许进进的博客-CSDN博客_markov链 目录 1.马尔科夫链 ...

  9. MCMC(一):蒙特卡罗方法和马尔科夫链

    作为一种随机采样方法,马尔科夫链蒙特卡罗(Markov Chain Monte Carlo,以下简称MCMC)在机器学习,深度学习以及自然语言处理等领域都有广泛的应用,是很多复杂算法求解的基础.比如分 ...

最新文章

  1. wxpython分割窗口_wxPython实现分隔窗口
  2. php性能提升5倍的秘诀,停机维护时长缩短5倍,全靠这3个秘诀
  3. 福州大学计算机学院董晨老师,福州大学代表队高分斩获第三届福建省高校网络空间安全大赛冠军...
  4. python每秒20个请求_使用Python每秒百万个请求
  5. java读取csv合适文件_解析-您可以推荐一个Java库来读取(并可能写入)CSV文件吗?...
  6. PHP 还有未来么,还是 25 岁就“寿终正寝”了?
  7. ipsec说明以及隧道案例
  8. C++ minidump类
  9. vue 后台系统引入pdf安装包
  10. Unity2019中文补丁下载
  11. houdini flowmap
  12. u盘重置后计算机不显示了,u盘在电脑上不显示了如何恢复
  13. apicloud访问php,支付宝 app应用 受权 php + APICloud
  14. linux temp文件夹在哪_linux基础知识笔记(第一天)
  15. 【Python学习】基于pytorch和pysimplegui实现中国人口预测算法部署
  16. 易车与汽车之家俩大巨头对决
  17. Spring Admin 入门
  18. IOS手机安装完fiddler证书后依然无法上网
  19. 1、Centos之常见目录作用介绍
  20. 关于网站漏洞的案例和解决思路

热门文章

  1. 小混混n多天不提编程,深刻反思
  2. 普通本科到清华大学研究生的真实人生蜕变,看了保证你考研至少增加 50 分!青春值得你去拼搏!!
  3. Gateway网关下载启动
  4. Pandas的常用操作(一)
  5. 河北大学计算机科学与技术考研,计算机专业考研经验贴(重)
  6. FDTD学习之偶极子光源的purcell值
  7. Netty的编解码器
  8. python 面向对象终极进阶之开发流程
  9. CSS3基础入门03
  10. java -苹果支付凭证校验