隐马尔科夫模型(HMM)的应用

HMM简介

隐马尔可夫模型(Hidden Markov Model,HMM)
如果你也是第一次接触的话,可以看这篇文章,讲得很好。
看了这篇之后我就去看代码了,下面的代码是 ASRT_v0.6.1 的 Language Model 部分,再次感谢作者——AI柠檬

代码分析

这部分代码的功能是把拼音转成汉字,比如,把 [‘ni3’, ‘hao3’, ‘zhong1’, 'guo2] 转成 ‘你好中国’ 。
首先要准备你的模型,如下:
在这里插入图片描述
所有拼音对应汉字,用如下代码搞成字典:

def GetSymbolDict(self, dictfilename):
	'''
	读取拼音汉字的字典文件
	返回读取后的字典
	'''
	txt_obj = open(dictfilename, 'r', encoding='UTF-8') # 打开文件并读入
	txt_text = txt_obj.read()
	txt_obj.close()
	txt_lines = txt_text.split('\n') # 文本分割
	
	dic_symbol = {} # 初始化符号字典
	for i in txt_lines:
		list_symbol=[] # 初始化符号列表
		if(i!=''):
			txt_l=i.split('\t')
			pinyin = txt_l[0]
			for word in txt_l[1]:
				list_symbol.append(word)
		dic_symbol[pinyin] = list_symbol
	
	return dic_symbol

字典就是这个样子:
在这里插入图片描述
还有下面两份 txt 文件,如法炮制:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
第一行的数字是总频数,每个字或词后面的数字是词频,用户可以根据自己的场景创建或找适合自己的语料库,然后通过“滑窗”,去统计词频。
下面就是核心函数了:

def SpeechToText(self, list_syllable):
	'''
	语音识别专用的处理函数

	实现从语音拼音符号到最终文本的转换

	使用恐慌模式处理一次解码失败的情况
	'''
	length = len(list_syllable)
	if(length == 0): # 传入的参数没有包含任何拼音时
		return ''
	
	lst_syllable_remain = [] # 存储剩余的拼音序列
	str_result = ''

	# 存储临时输入拼音序列
	tmp_list_syllable = list_syllable

	while(len(tmp_list_syllable) > 0):
		# 进行拼音转汉字解码,存储临时结果
		tmp_lst_result = self.decode(tmp_list_syllable, 0.0)

		if(len(tmp_lst_result) > 0): # 有结果,不用恐慌
			str_result = str_result + tmp_lst_result[0][0]
			
		while(len(tmp_lst_result) == 0): # 没结果,开始恐慌
			# 插入最后一个拼音
			lst_syllable_remain.insert(0, tmp_list_syllable[-1])
			# 删除最后一个拼音
			tmp_list_syllable = tmp_list_syllable[:-1]
			# 再次进行拼音转汉字解码
			tmp_lst_result = self.decode(tmp_list_syllable, 0.0)
			if(len(tmp_lst_result) > 0):
				# 将得到的结果加入进来
				str_result = str_result + tmp_lst_result[0][0]
			
		# 将剩余的结果补回来
		tmp_list_syllable = lst_syllable_remain
		lst_syllable_remain = [] # 清空

	
	return str_result

def decode(self,list_syllable, yuzhi = 0.0001):
	'''
	实现拼音向文本的转换
	基于马尔可夫链
	'''
	#assert self.dic_pinyin == null or self.model1 == null or self.model2 == null
	list_words = []
	
	num_pinyin = len(list_syllable)
	#print('======')
	#print('decode function: list_syllable\n',list_syllable)
	#print(num_pinyin)
	# 开始语音解码
	for i in range(num_pinyin):
		#print(i)
		ls = ''
		if(list_syllable[i] in self.dict_pinyin): # 如果这个拼音在汉语拼音字典里的话
			# 获取拼音下属的字的列表,ls包含了该拼音对应的所有的字
			ls = self.dict_pinyin[list_syllable[i]]
		else:
			break
		
		
		if(i == 0):
			# 第一个字做初始处理
			num_ls = len(ls)
			for j in range(num_ls):
				tuple_word = ['',0.0]
				# 设置马尔科夫模型初始状态值
				# 设置初始概率,置为1.0
				tuple_word = [ls[j], 1.0]
				#print(tuple_word)
				# 添加到可能的句子列表
				list_words.append(tuple_word)

			
			# print(list_words)
			continue
		else:
			# 开始处理紧跟在第一个字后面的字
			list_words_2 = []
			num_ls_word = len(list_words)
			#print('ls_wd: ',list_words)

			for j in range(0, num_ls_word):
				
				num_ls = len(ls)
				for k in range(0, num_ls):
					tuple_word = ['',0.0]
					tuple_word = list(list_words[j]) # 把现有的每一条短语取出来
					#print('tw1: ',tuple_word)
					tuple_word[0] = tuple_word[0] + ls[k]  # 尝试按照下一个音可能对应的全部的字进行组合
					#print('ls[k]  ',ls[k])
					
					tmp_words = tuple_word[0][-2:] # 取出用于计算的最后两个字
					#print('tmp_words: ',tmp_words,tmp_words in self.model2)
					if(tmp_words in self.model2): # 判断它们是不是再状态转移表里
						#print(tmp_words,tmp_words in self.model2)
						tuple_word[1] = tuple_word[1] * float(self.model2[tmp_words]) / float(self.model1[tmp_words[-2]])
						# 核心!在当前概率上乘转移概率,公式化简后为第n-1和n个字出现的次数除以第n-1个字出现的次数
						#print(self.model2[tmp_words],self.model1[tmp_words[-2]])
					else:
						tuple_word[1] = 0.0
						continue
					#print('tw2: ',tuple_word)
					#print(tuple_word[1] >= pow(yuzhi, i))
					if(tuple_word[1] >= pow(yuzhi, i)):
						# 大于阈值之后保留,否则丢弃
						list_words_2.append(tuple_word)
					
			list_words = list_words_2
			#print(list_words,'\n')

	for i in range(0, len(list_words)):
		for j in range(i + 1, len(list_words)):
			if(list_words[i][1] < list_words[j][1]):
				tmp = list_words[i]
				list_words[i] = list_words[j]
				list_words[j] = tmp
	
	return list_words
	pass

下面是我的伪代码:

def SpeechToText(拼音序列):
    '''
    语音识别专用的处理函数
    实现从语音拼音符号到最终文本的转换
    使用恐慌模式处理一次解码失败的情况
    '''
    if 拼音序列长度为 0:
        返回空字符串

    lst_syllable_remain = [] # 存储剩余的拼音序列
    str_result = ''

    tmp_list_syllable = 拼音序列 # 存储临时输入拼音序列

    while tmp_list_syllable 的长度大于零的时候:
        tmp_lst_result = self.decode(tmp_list_syllable, 0.0)  # 进行拼音转汉字解码,存储临时结果

        if tmp_lst_result 的长度大于零: # 有结果,不用恐慌
            把结果放到 str_result 里面

        while tmp_lst_result 的长度等于零时:  # 没结果,开始恐慌
            把 tmp_list_syllable 的最后一个拼音删了,放到 lst_syllable_remain 里面
            tmp_lst_result = self.decode(tmp_list_syllable, 0.0) # 再次进行拼音转汉字解码
            if tmp_lst_result 的长度大于零:
                把结果放到 str_result 里面

        # 将剩余的结果补回来
		tmp_list_syllable = lst_syllable_remain
		清空 lst_syllable_remain

	return str_result

def decode(拼音序列, 阈值=0.0001):
    '''
	实现拼音向文本的转换
	基于马尔可夫链
	'''
    list_words = []

    for 遍历拼音序列中的每一个拼音:

        if 这个拼音在 dict_pinyin 这个字典里的话:
            ls = 这个拼音对应的所有字
        else:
             否则跳出循环

        if 现在是第一个拼音:
            for 遍历第一个拼音下的所有字:
                tuple_word = [字, 1.0]  # 把每个字的初始概率设为 1
                list_words.append(tuple_word) # 添加到可能的句子列表
        else:
            开始处理紧跟在第一个字后面的字
            list_words_2 = []
            for list_words 中有多少个字就循环多少次:
                for 遍历 ls: # 比如说是第二次,ls 就是第二个拼音下的所有字
                    tuple_word = list(list_words中的字) # 这里相当于deepcopy
                    tuple_word[0] = tuple_word[0] + ls里的字 # 尝试按照下一个音可能对应的全部的字进行组合
                    tmp_words = tuple_word[0][-2:] # 取出用于计算的最后两个字
                    if tmp_words 在 model2 里面:
                        # 核心!在当前概率上乘转移概率,公式化简后为第n-1和n个字出现的次数除以第n-1个字出现的次数
                        tuple_word[1] = tuple_word[1] * float(self.model2[tmp_words]) / float(self.model1[tmp_words[-2]])
                    else:
                        tuple_word[1] = 0.0
						continue
					if tuple_word[1] >= 阈值的 i 次方: # i 是最外层循环的索引
					    list_words_2.append(tuple_word) # 大于阈值之后保留,否则丢弃
			list_words = list_words_2

    冒泡排序,list_words[i][1] 大的在前

    return list_words

逐行翻译,将就看,哈哈。
That’s it !

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值