语音识别之HTK入门(十)——HTK解码工具HVite源码分析

article/2025/10/7 3:30:28

这一节讲的内容又是语音识别系统非常重要的一环——veterbi解码,前面我们经过了配置文件,处理音频数据,处理标注文本数据、通过Baum-Welch(前向-后向)算法评估模型参数等多个环节,目的都是为了在这一步通过已知的模型来把音频解码成对应的文字,实现对语音的识别功能。

这篇如何通俗地讲解 viterbi 算法讲的比较入门,一看就懂,viterbi的实质也的确如此。现在就是要看它在HTK中是如何应用的,因为实际系统中涉及到很多细节,比如语法、剪枝优化、词的边界处理等等,会增加理解的复杂度,但是细心加耐心肯定都能搞明白的。

其实,维特比解码算法涉及的关键步骤在前向算法中已经有所体现了。不同点在于,前向算法计算\alpha_{t}(i)的意义是,说在t时刻,状态为i情况下,观察向量为O_{1} O_{2} ... O_{t}的概率,它的实质是求和;那么,在veterbi解码算法中,类似的步骤\Phi_{t}(j)是求最大似然值。记\Phi_{t}(j) = \underset{i}{max}\left \{ \Phi_{t-1}(i)\alpha_{ij} \right \}b_{j}(O_{t}),,表示从t-1时刻各个状态到t时刻j状态下,概率最大的值,记录下那个对应的上一个状态i。当考虑连续语音识别时,要考虑的情况就比较多了,例如语法问题、多音字、以及模型的区分度等。

执行解码命令如下:

HVite -H  .\hmms\hmm7\macros  -H  .\hmms\hmm7\hmmdefs  -S  test.scp  -l  * -i recout_step7.mlf -w wdnet -p 0.0 -s 5.0 dict2 monophones1

 现在调试代码看看HVite是如何解码操作的。

根据-H指定HMM模型定义,这里包括两个一个是宏定义macros,里面floorvar1的模型参数,作为训练时模型的协方差的最小值;还有hmmdefs,里面定义了各子词(sub-word或phone)的模型参数,是解码操作的最重要的依据。-S test.scp包含了多个测试文件提取位置,test.scp里的每个文件都是以mfc作为扩展名。-i recout_step7.mlf,指定输出文件名recout_step7.mlf,且为mlf文件格式来存储识别结果。-w wdnet指明识别过程所依赖的词网络。-p -s设置语言模型的参数。dict2位发音字典,monophones1是音子模型列表。

现在进入HVite源码的main函数里,看看大体的思路:

int main(int argc, char *argv[])
{//函数声明、一系列初始化等等...if (!InfoPrinted() && NumArgs() == 0)ReportUsage();if (NumArgs() == 0) Exit(0);SetConfParms();CreateHeap(&modelHeap, "Model heap",  MSTAK, 1, 0.0, 100000, 800000 );CreateHMMSet(&hset,&modelHeap,TRUE); // 参数处理while (NextArg() == SWITCHARG) {s = GetSwtArg();if (strlen(s)!=1) HError(3219,"HVite: Bad switch %s; must be single letter",s);switch(s[0]){case 'a':loadLabels=TRUE; break;....// 数据处理if (wdNetFn==NULL)DoAlignment();     // 强制对齐elseDoRecognition();   // 识别的处理函数/* Free up and we are done */if (trace & T_MEM) {printf("Memory State on Completion\n");PrintAllHeapStats();}// 程序占有的资源释放DeleteVRecInfo(vri);ResetHeap(&netHeap);FreePSetInfo(psi);...Exit(0);return (0);           

main函数的开头和前面介绍的几个工具一样,声明变量和将用到的函数,然后就是初始化,例如内存、网络、模型等等准备工作,然后就是命令行参数的处理。核心方法就是 DoRecognition()。

// 通过识别网络来识别一个个文件
void DoRecognition(void)
{...if ( (nf = FOpen(wdNetFn,NetFilter,&isPipe)) == NULL)HError(3210,"DoRecognition: Cannot open Word Net file %s",wdNetFn);// wdNet为词级网络对象if((wdNet = ReadLattice(nf,&ansHeap,&vocab,TRUE,FALSE))==NULL)HError(3210,"DoAlignment: ReadLattice failed");// net为由词级网络扩展后的hmm模型网络net = ExpandWordNet(&netHeap,wdNet,&vocab,&hset);/* 如果没有输入待识别问句,就直接从音频输入设备读取语音数据 */if (NumArgs()==0) {      while(TRUE){printf("\nREADY[%d]>\n",++n); fflush(stdout);ProcessFile(NULL,net,n,genBeam, FALSE);if (update > 0 && n%update == 0) {...}}}else {              /* 识别指定的音频文件 */while (NumArgs()>0) {if (NextArg()!=STRINGARG)HError(3219,"DoRecognition: Data file name expected");datFN = GetStrArg();if (trace&T_TOP) {printf("File: %s\n",datFN); fflush(stdout);}....// 识别过程ProcessFile(datFN,net,n++,genBeam,FALSE);.....}}
}

而这里的ProcessFile是核心函数,参数有文件名,识别网络和束宽大小。看看这个函数里的代码结构。

Boolean ProcessFile(char *fn, Network *net, int utterNum, LogDouble currGenBeam, Boolean restartable)
{...// 初始化识别过程中一些数据结构,比如netStartRecognition(vri,net,lmScale,wordPen,prScale);// 设置剪枝参数SetPruningLevels(vri,maxActive,currGenBeam,wordBeam,nBeam,tmBeam);tact=0;nFrames=0;StartBuffer(pbuf);// 读取文件中的帧数据到obj中// 处理某一帧的语音特征向量,结果保存在vri相关的数据项中ProcessObservation(vri,&obs,-1,xfInfo.inXForm);      nFrames++;tact+=vri->nact;lat=CompleteRecognition(vri,pbinfo.tgtSampRate/10000000.0,&ansHeap);   lat->utterance=thisFN;lat->net=wdNetFn;lat->vocab=dictFn;/* accumulate stats for online unsupervised adaptation only if a token survived */if ((lat != NULL) &&  (!vri->noTokenSurvived) && ((update > 0) || (xfInfo.useOutXForm)))DoOnlineAdaptation(lat, pbuf, nFrames);...Dispose(&ansHeap,lat);CloseBuffer(pbuf);
}

函数ProcessObservation()才是核心中的核心。它真正实现了维特比算法,也就是token passing model algorithm。这个函数总共大概100行,下面就来详细了解它是如何一步步实现解码算法的,并以此为枢纽,连接多个数据结构。

涉及到的比较重要的结构体有,与识别网络有关的:Network、NetNode、NetNodeType、NetLink、NetInst;还有与网格有关的Lattice、LNode、LArc;与识别过程有关的:PRecInfo、VRecInfo、Token、Path、

 

 

 

 


http://chatgpt.dhexx.cn/article/bTsOfAQq.shtml

相关文章

如何下载并使用HTK工具包

HTK是用来进行自动语音识别研究的工具包,它由剑桥大学工程系的机器智能实验室开发的开源软件,全称叫做The HiddenMarkov Toolkit。官方网站:http://htk.eng.cam.ac.uk 这个工具包必须安装VS后才能使用。因为它是基于C进行开发的。HTK工具包…

HTK语音识别工具包的安装和编译

今天介绍一下HTK语音识别工具包的安装和编译,希望能够帮助到更多做语音相关工作的同仁们。 介绍: HTK是用来进行自动语音识别研究的工具包,它由剑桥大学工程系的机器智能实验室开发的开源软件,全称叫做HiddenMarkov Toolkit。 官…

语音识别之HTK入门(七)——HERest训练模型之Baum-Welch算法

上一个博客为B-W算法准备了基础,也就是前向算法和后向算法以及EM模型。 现在看看到底Baum-Welch算法是如何利用上述算法及模型来更新HMM的参数的。 之前也分析过多次了,在语音识别领域HMM模型之所以这么复杂,是因为观察向量对应的隐含状态不…

https tk6 us

https.tk6.us专题,为您展现优质的https.tk6.us各类信息,在这里您可以找到关于https.tk6.us的相关内容及最新的https.tk6.us贴子。 https.tk6.us服务器iP: 当前解析: 未查找到结果! 历史解析记录: 2022-09-29-----2023-05-024…

基于HTK的连续语音识别系统搭建学习笔记(一)

放假之前,就已经对HTK上完成连续语音识别的实验充满兴趣。于是找了很多资料,准备在放假的时候好好学习,仔细琢磨,HTK博大精深,光学习和完成孤立词识别肯定是不够。从今天开始,开始同步学习和记录基于HTK的连…

HTK在windows下的配置说明

本文档意在详细介绍在windows环境下如何配置编译HTK,是根据网上资料及自己实际操作步骤编写而成,一方面是为方便以后使用此工具的朋友们有个参考,另外一方面是给自己加深印象。 准备事项 安装Microsoft Visual Studio开发环境(以下简称VS),因为HTK代码需要通过VS来编译。…

HTK工具搭建识别器的总体框架

老早之前就学习了HTK工具,并用于搭建连续语音识别器,但是好久没有用对于一些东西又忘记了,现在由于做实验需要用到HTK,又重新看了一遍,所以把一些大致的东西记录下来,以后可以直接看这个。感觉用HTK搭建识别…

HTB-OpenKeyS

HTB-OpenKeyS 信息收集80端口立足于JenniferJennifer -> root 信息收集 80端口 对其进行简单的SQL注入测试和NoSQL注入测试后进行目录扫描。 auth.swp文件内容如下: 代码不是很完整,只能大致了解意思(请原谅我脑子抽了没注意是个swp交换…

HTK工具的安装

首先下载HMM 的开发包HTK,现在的版本是3.4.1.可以从CMU的官网进行下载。 http://htk.eng.cam.ac.uk/,下载后解压HTK工具包,我解压后的目录为:D:\htk\ 确保的环境变量Path包含路径:C:\Program Files\Microsoft Visual S…

HTK的使用方法

一,HTK目录结构 htk是一个开源的软件,解压之后的目录如下: [rootlocalhost htk]# ls AUTHORS config.status env HTK HTKTools Makefile.in ChangeLog config.sub FAQ HTKBook install-sh README co…

语音识别之HTK入门(一)HTK的下载配置

语音识别之HTK入门(一)HTK的下载配置 Linux环境配置VMware Tools安装必备环境 HTK下载HTK环境设置 跪拜大佬帖子: https://www.cnblogs.com/ansersion/p/4155828.html 基本按照大佬的帖子进行调试的,为表示敬意,全程跪…

HTK学习笔记(一)

HTK学习笔记(一) 一、HTK软件体系结构 HTK的软件体系结构 HTKTool各部分的功能: 所有的语音输入和输出都是通过HWAVE或HPARM HAudio:用于从音频设备输入波形 HWave:用于从文件中读取波形 HSLab:波形显示工具,可以用于采集语音…

基于htk工具包的语音识别

htk简介: HTK是一个构建隐藏马尔可夫模型(HMMs)的工具包。HMMs可以用于任何时间序列的建模建模,HTK的核心就是类似的通用目的。然而,HTK主要设计用于构建基于HMM的语音处理工具,特别是识别程序。因此,大部分HTK中的基础设施支持专门用于此任…

jQuery学习手册(15)

逐个设置 $(div).css(width, 100px)​ $(div).css(height, 100px)​ $(div).css(background, black)链式设置 注意:如果大于3步,建议分开 $(div).css(width, 100px).css(height, 100px).css(background, black)批量设置 $(div).css({ ​ …

第7章页面布局-ConstrainedBox限定宽高

防采集标记:亢少军老师的课程和资料 import package:flutter/material.dart; class LayoutDemo extends StatelessWidget {overrideWidget build(BuildContext context) {return new Scaffold(appBar: new AppBar(title: new Text(ConstrainedBox限定宽高示例),),b…

全网最详细的一篇Flutter 尺寸限制类容器总结

Flutter中尺寸限制类容器组件包括ConstrainedBox、UnconstrainedBox、SizedBox、AspectRatio、FractionallySizedBox、LimitedBox、Container。这些组件可以约束子组件的尺寸,下面一一介绍。 ConstrainedBox ConstrainedBox组件约束子组件的最大宽高和最小宽高&am…

android中各种height和width总结

1. getMeasuredWidth()和getWidth() 以这两个为例,高度与其相同。这两个是在自定义View中最常见到的,通过字面意思可以看出,前者是测量的宽度,后者是控件的实际宽度,下面看下官方文档对他们的描述: //Ret…

JavaFX布局(一)

说道GUI编程一定要谈到布局,JavaFX内置了大量的布局控件提供给我们使用。其实,JavaFX的布局控件和界面元素控件都是继承自javafx.scene.layout.Region类。我们这里只看布局控件类。布局控件我们在界面上一般是看不到的,它一个容器用于放置其它…

Android 桌面小组件 AppWidgetProvider

废话 桌面小组件,绝对是小程序中的小程序,说白了就是任何复杂一丁点的操作都不适合做成桌面小组件。 所以这里采用的演示的例子,就只有一个白色圆角背景,外加一个文本框,显示文字。 小组件的教程网上一搜一大堆&…

Android 约束布局 ConstrainLayout min max width

写一个自定义view package com.anguomob.guidelineimport android.content.Context import android.graphics.Canvas import android.graphics.Color import android.util.AttributeSet import android.view.Viewclass ZeroView constructor(context: Context?, attrs: Attri…