2015-03-15 19:56:38 puqutogether 阅读数 7804
  • C++语音识别开篇

    本篇mark老师将教大家使用第三方库的调用来简单的实现语音识别。随着机器学习和人工智能的热闹,国内语音行业也可谓是百花齐放。 语音识别一个伟大的时代已在我们身边悄悄走来。

    5907 人正在学习 去看看 杨波

    

    从这一篇开始,陆续学习语音识别技术,由浅入深。


    这一篇是入门,主要学习的是语音识别技术的大致步骤,以及现在的几种主流方法。


    下图是语音识别技术的系统框图:


    主要包括这样几个步骤:

1)预处理。对输入语音信号进行预加重和分帧加窗等处理,过滤其中不重要信息及背景噪声,进行端点检测,以确定有效的语音段;

2)特征提取。常见的特征参数有基于时域的幅度、过零率、能量,以及基于频域的线性预测倒谱系数(LPCC)、Mel倒谱系数(MFCC)等;

3)模式匹配。


    目前已有几种主流的语音识别技术:

1)动态时间规整(DTW)技术。采用动态规整法,并结合时间变换关系,得到特征矢量之间的距离,是语音识别中的一种经典算法。DTW技术比较容易实现,但是不能充分利用语音信号的时序特性和动态特征,因此适合用于孤立词、小词汇等相对简单的汉语语音识别系统。


2)隐马尔可夫模型(HMM)技术。HMM用马尔科夫链中的状态表示语音的发音过程,在单字生成过程中,系统由一个状态转移到另一个状态,在每个状态下产生一个输出,直至该单字输出完毕。HMM用马尔科夫链来模拟信号的变化过程,在通过序列间接地描述这种变化,因此它是一个双重随机过程,因而能很好地描述语音信号的总体非平稳性和短时平稳性。

HMM需要对当前的状态序列分布作先验假设;对高层次声学音素建模能力弱,使声学上相似词容易混淆;HMM语音识别系统用硬件实现起来比较困难。


3)人工神经网络(ANN)技术。训练时间长。


    现有语音识别的难点:

1)识别性能依赖周围环境。当训练环境和测试环境不一样时,效果变差;

2)噪声问题。如何去噪;

3)语音信息的模糊性。读音相似的词语,同音不同意思的词语,如何识别。



参考:

《基于隐马尔可夫模型的额语音识别技术研究》



 

2016-10-07 21:18:45 sac761 阅读数 20549
  • C++语音识别开篇

    本篇mark老师将教大家使用第三方库的调用来简单的实现语音识别。随着机器学习和人工智能的热闹,国内语音行业也可谓是百花齐放。 语音识别一个伟大的时代已在我们身边悄悄走来。

    5907 人正在学习 去看看 杨波

本项目做出的产品是一个Windows下的增强现实系统,系统很庞大,产品功能已经基本完善,考虑到给用户带来更好的体验,故综合评估后采用讯飞语音识别方案进行嫁接。

项目介绍:

1)打开系统时启动语音识别,检测到用户说出关键词(如:上一步,下一步,结束等)时,系统自动进行相应的操作;

2)不需要按任何按键进行连续的语音识别控制,延迟为2秒左右;

3)可以识别词语,句子,中文,英文数字字母通吃,不限语速。并且语句结束判断机制很智能;

3)离线!离线!现在做一个基于windows的离线的语音识别系统在网络上还真没谁,讯飞自己也还没有推出这款SDK,我是在讯飞的离线命令词识别SDK开发包上开发出的介于两者之间功能的系统。

为什么用讯飞:

之前使用过语音识别开发版,用驻极体采集声音,通过串口传输信号来进行识别,只能讲开发版只适合用来做个课程设计啥的玩玩,做产品还是太LOW,识别率地下并且识别范围窄,貌似只能识别数字字母;之后调查过汉语语音识别库如Sphinx,Julius,百度语音等。去网上问,很多人推荐这些方案的,我没试过,不过一个SDK也只有自己正真开发过才知道好不好用强不强大,说的再牛逼也是在别人手上玩的转,到你这就不一定了。我用讯飞就是看上它的鲁棒,免费,毕竟是久经考验的平台,讯飞有一个开发者论坛,开发别人的SDK有个社区很重要,不然有问题没地方问。


项目开发经验与源码如下:

一、跑通讯飞离线命令词识别SDK

首先去讯飞官网下载相应SDK,要注册登录,绑定产品才能下载,下载后跑一跑给的demo,跑不通的话去讯飞的论坛找答案。

我用的demo是asr_record_demo,这个demo可以实现的功能是按下R键从mic中录制缓冲音频并按下S键后进行识别。

稍微看一看这个demo中的东西吧,把该删的东西删了,该修整的修整,玩转了demo才能进一步做移植。

二、文件分析与移植

把SDK包中的需要的.lib  .h  .c和所需要的其余文件拷贝到项目相应的文件夹去,最好是分个类,看起来比较清楚。它比较重要的几个文件有以下几个:

msc.lib   讯飞语音离线命令词识别所依赖的库(X64版本为msc_x64.lib)才15KB就能有如此强大的功能。

call.bnf    采用巴科斯范式语法规则的自定义语法库(call是根据自己需要命名的),用来编写语音识别过程中的语法规则,这个语法写的好语音识别更智能。

speech_recognizer.c  基于录音接口和MSC接口封装一个MIC录音识别的模块,SDK的主要文件

winrec.c  封装windows录音,Windows平台下SDK的主要文件


好了,既然demo已经知道怎么用了,把demo所依赖的所有文件和库照搬进自己的项目去,就可以在自己的项目中调用讯飞的函数了(注意头文件和库文件的路径问题)。

三、使用讲解

先看看我的语法文件

call.bnf:


巴科斯范式语法语法文件怎么写在讯飞的论坛里有很多资源自己去看吧,我写的比较简单,写得好的语法可以更加智能。


大致讲讲源码:

为了看起来简洁,我在speech_recognizer.h中做了一个类SR,把主文件中的一些函数定义和一些宏搬进去。

speech_recognizer.h:

class SR {
public:

	const char * ASR_RES_PATH = "fo|res/asr/common.jet";  //离线语法识别资源路径
#ifdef _WIN64
	const char * GRM_BUILD_PATH = "res/asr/GrmBuilld_x64";  //构建离线语法识别网络生成数据保存路径
#else
	const char * GRM_BUILD_PATH = "res/asr/GrmBuilld";  //构建离线语法识别网络生成数据保存路径
#endif
	const char * GRM_FILE = "call.bnf"; //构建离线识别语法网络所用的语法文件

	int build_grammar(UserData *udata);//构建语法
	int run_asr(UserData *udata);//启动引擎

};
speech_recognizer.c:

#pragma comment(lib,"../../lib/msc_x64.lib") //x64
#else
#pragma comment(lib,"XXXXXX/lib/msc.lib") //x86
#endif
这里的库目录要注意,用相对路径可能找不到文件,可以使用绝对路径

#ifdef _WIN64
<pre name="code" class="cpp">static int update_format_from_sessionparam(const char * session_para, WAVEFORMATEX *wavefmt)
{
	char *s;
	/*if ((s = strstr(session_para, "sample_rate"))) {
		if (s = strstr(s, "=")) {
			s = skip_space(s);
			if (s && *s) {
				wavefmt->nSamplesPerSec = atoi(s);
				wavefmt->nAvgBytesPerSec = wavefmt->nBlockAlign * wavefmt->nSamplesPerSec;
			}
		}
		else
			return -1;
	}
	else {
		return -1;
	}*/

	return 0;
}


如果加到讯飞提供的demo使用的是VS2010如果放到VS2015中就会出一些语法上的错,自己看着改一改,比如上面这个函数,是更新用户词典用的,我不需要但是又存在语法错误,就把它的内容直接注释掉得了。

我的项目的主文件中:

首先定义几个宏:

UserData asr_data;//语音识别用户配置
speech_rec asr;//麦克风输入存储结构体
SR sr;//语音识别实体
string SPEAKER="";//用于缓存语音识别内容
在程序初始化处配置如下:

openVoiceRecognizer = true;//语音识别开关
	if (openVoiceRecognizer)
	{
		const char *login_config = "appid = XXXXX"; //登录参数
		int ret = 0;


		ret = MSPLogin(NULL, NULL, login_config); //第一个参数为用户名,第二个参数为密码,传NULL即可,第三个参数是登录参数
		if (MSP_SUCCESS != ret) {
			printf("登录失败:%d\n", ret);
			openVoiceRecognizer = false;
		}


		memset(&asr_data, 0, sizeof(UserData));
		printf("构建离线识别语法网络...\n");
		ret = sr.build_grammar(&asr_data);  //第一次使用某语法进行识别,需要先构建语法网络,获取语法ID,之后使用此语法进行识别,无需再次构建
		if (MSP_SUCCESS != ret) {
			printf("构建语法调用失败!\n");
			openVoiceRecognizer = false;
		}


		while (1 != asr_data.build_fini)
			_sleep(300);
		if (MSP_SUCCESS != asr_data.errcode)
			_sleep(300);
		printf("离线识别语法网络构建完成,开始识别...\n");
		ret = sr.run_asr(&asr_data);//预启动语音识别引擎
	}
在初始化这里我修改了 sr.run_asr(&asr_data);这个函数,我把它调用的sr_start_listening(&asr);函数抽离出来,不让它启动识别引擎而只让它预启动,把所有结构体,变量先初始化待命。

void recognize_mic(const char* session_begin_params)  //根据自己项目需要写的语音识别预热函数
{
	int errcode;
	HANDLE helper_thread = NULL;

	struct speech_rec_notifier recnotifier = {
		on_result,
		on_speech_begin,
		on_speech_end
	};
	errcode = sr_init(&asr, session_begin_params, SR_MIC, DEFAULT_INPUT_DEVID, &recnotifier);
	if (errcode) {
		printf("speech recognizer init failed\n");
		return;
	}

	/*	while (1) {
			errcode = sr_start_listening(&asr);//我把它调用的sr_start_listening(&asr);函数抽离出来,不让它启动识别引擎而只让它预启动,把所有结构体,变量先初始化待命。
		}

	exit:
		sr_uninit(&asr);*/
}

int SR::run_asr(UserData *udata)
{
	char asr_params[MAX_PARAMS_LEN] = { NULL };
	const char *rec_rslt = NULL;
	const char *session_id = NULL;
	const char *asr_audiof = NULL;
	FILE *f_pcm = NULL;
	char *pcm_data = NULL;
	long pcm_count = 0;
	long pcm_size = 0;
	int last_audio = 0;
	int aud_stat = MSP_AUDIO_SAMPLE_CONTINUE;
	int ep_status = MSP_EP_LOOKING_FOR_SPEECH;
	int rec_status = MSP_REC_STATUS_INCOMPLETE;
	int rss_status = MSP_REC_STATUS_INCOMPLETE;
	int errcode = -1;
	int aud_src = 0;

	//离线语法识别参数设置
	_snprintf(asr_params, MAX_PARAMS_LEN - 1,         //<span style="font-family: Arial, Helvetica, sans-serif;">离线语法识别参数根据自己的需要进行更改</span>

		"engine_type = local, \
		asr_res_path = %s, sample_rate = %d, \
		grm_build_path = %s, local_grammar = %s, ",
		sr.ASR_RES_PATH,
		SAMPLE_RATE_16K,
		sr.GRM_BUILD_PATH,
		udata->grammar_id
		);

	recognize_mic(asr_params);
	return 0;
}
而后是三个语音识别的中间过程和结果处理的函数:

void on_result(const char *result, char is_last)   //根据自己的需要写结果处理
{
	char *p = "上一步";
	char *pq = "下一步";
	char *q = "扫频仪操作演示";
	char *end1 = "结束";
	char *end2 = "退出";
	if (strstr(result, p)) {
		SPEAKER = "上一步";	
	}
	else if (strstr(result, pq)) {
		SPEAKER = "下一步";
	}
	else if (strstr(result, q)) {
		SPEAKER = "扫频仪操作演示";
	}
	else if (strstr(result,end1)|| strstr(result, end2)) {
		SPEAKER = "退出";
	}
	cout << SPEAKER << endl;
}
void on_speech_begin()
{
	if (g_result)
	{
		free(g_result);
	}
	g_result = (char*)malloc(BUFFER_SIZE);
	g_buffersize = BUFFER_SIZE;
	memset(g_result, 0, g_buffersize);

	printf("Start Listening...\n");
}
void on_speech_end(int reason)
{
	if (reason == END_REASON_VAD_DETECT)
		printf("\nSpeaking done \n");
	else
		printf("\nRecognizer error %d\n", reason);
}
最后就是在自己项目哪里需要语音识别就在哪里抛出缓冲线程启动识别引擎:

if (openVoiceRecognizer) {
		
		sr_start_listening(&asr);//抛出缓冲线程进行语音识别

		if (SPEAKER=="下一步") {
			keyPressed(' ');
		}
		else if (SPEAKER == "上一步") {
			keyPressed('b');
		}
		else if (SPEAKER == "扫频仪操作演示") {
			keyPressed('1');
		}
		else if (SPEAKER=="退出") {
			std::exit(0);
		}
		SPEAKER = "";
	}

上面代码中的关键就是sr_start_listening(&asr);这个函数,前面也说了这是从run_asr()调用的方法中抽离出来的,抽离出来后run_asr()就变成了预热函数,只需在程序初始化的时候调用它后面的语音识别就不要重复调用了,节省资源。

必须要说说这个关键函数sr_start_listening(&asr);

这是讯飞这款SDK中不需要动的最后一个封装好的函数,里面的东西不要动,前面的东西配置好一调用它就可以进行语音识别了,这个函数中的东西是这款SDK的精华,实现过程很复杂不需要管,但是要记住它的几个特性:

1)一调用它就相当于抛出了一个带缓冲的新线程,这个线程独立进行语音的识别可以不干扰项目的主循环的进行。

2)这个线程寿命是自动的,程序一开始启动到这里调用这个函数后启动线程,当程序的主循环又回来这里不会重复启动这个线程,而是该线程识别完用户的语音判断语句结束机制触发后才待命,等待下一次循环的启动。这句话有些费解,用我的项目解释下:我的项目在update()函数中调用sr_start_listening(&asr); 我的update()函数每100毫秒循环一次,第一次循环启动这个函数,抛出线程进行语音识别,语音识别用了10秒结束,在这10秒过程中update()循环了100次,但是只启动该函数一次,第101次循环的时候就可以第二次启动该函数了,同时在上面代码片中我用SPEAKER转存的字符串的判断条件已经成立,就可以进行相应的操作了,在这里我触发了不同的按键来代替各种操作。

3)举个栗子,我在update()中可以在每一次循环时画一帧图片的方式实现一个视频的播放,而在这里面调用语音引擎sr_start_listening(&asr);,在引擎识别的过程中会不会中断视频的播放或者视频出现卡帧或迟滞呢?答案是不会,上面也解释了,这个函数抛出一个独立的线程,不影响主函数的循环。所以可以用这种方法实现用语音控制视频的播放:快进、后退、暂停、截屏、全屏、音量加大、切换到高清......是不是很酷!

上面的几个源码文件我打了个包,下载看可能更清楚:

http://download.csdn.net/detail/sac761/9647029

四、总结

我用这个方案实现了离线的语音控制系统,语音识别率达到百分之九十以上,而且词语句子中英文通吃,实时性强,系统鲁棒。

畅想一下用这个方法加方案开发这几个产品:

语音控制的媒体播放器,功能在上面也讲了,很酷的!

语音控制的PPT遥控器

语音控制的AR/VR系统

语音交互智能眼镜

.............





2019-11-02 11:44:35 caiji_is_studying 阅读数 117
  • C++语音识别开篇

    本篇mark老师将教大家使用第三方库的调用来简单的实现语音识别。随着机器学习和人工智能的热闹,国内语音行业也可谓是百花齐放。 语音识别一个伟大的时代已在我们身边悄悄走来。

    5907 人正在学习 去看看 杨波

前言

上篇文章中,讲述了语音识别技术中的DTW算法,DTW算法是用于模板匹配的。这篇文章我们将介绍人脸识别中的Gabor特征提取算法,Gabor算法是用在特征提取阶段。我们在这里对比一下语音识别的流程图和人脸识别技术的流程图,以便学习总结。

下图是基于DTW算法的语音识别技术的流程图:
基于DTW算法的语音识别技术
下图是基于Gabor特征提取算法和SVM分类器的人脸检测与识别流程图,其中包括测试过程与训练过程。

Gabor特征提取算法简介

为什么选择它

Gabor 特征提取算法可以在不同方向上描述局部人脸特征,对光照、遮挡以及表情变换等情况具有较强的鲁棒性,即Gabor算法在异常和危险情况下具有较强的系统生存的能力。

先介绍一些基本概念作为引入
一维Gabor核:

其由一个高斯核与一个复数波的乘积定义为如下公式:
在这里插入图片描述
其中w(t)是高斯函数,s(t)是复数波,两者的一维数学表达式定义如下:
在这里插入图片描述
我们将s(t)代入一维Gabor公式可得下式:
在这里插入图片描述

我们将上述一维情况推广到二维

二维复数波定义如下,其中(x,y)表示空间域坐标,(u0,v0)表示频率域坐标。
在这里插入图片描述
二维高斯函数定义如下,其中σx,σy 分别为在x,y两个方向上的尺度参数,用来控制高斯函数在两个方向上的“展布”形状。(x0,y0)为高斯函数的中心点。K为高斯核的幅度的比例。
在这里插入图片描述
但是由于高斯函数还有旋转的操作,所以我们对坐标进行如下的变换:
在这里插入图片描述
由此,我们得到了坐标变换后的高斯函数公式,其中θ表示高斯核顺时针旋转的角度。
在这里插入图片描述

二维Gabor核

类似一维 Gabor 核,我们将二维高斯函数与二维复数波相乘,就得到了二维的Gabor核:
在这里插入图片描述
一个Gabor核能获取到图像某个频率邻域的响应情况,这个响应结果可以看做是图像的一个特征。如果我们用多个不同频率的Gabor核去获取图像在不同频率邻域的响应情况,最后就能形成图像在各个频率段的特征,这个特征就可以描述图像的频率信息了。

下图展示了一系列具有不同频率的 Gabor 核,用这些核与图像卷积,我们就能得到图像上每个点和其附近区域的频率分布情况。
在这里插入图片描述
经过 Gabor 滤波获到的人脸图像信息包含实部和虚部两部分,分别代表不同局部的人脸特征信息,为了提取更加全面的人脸特征信息,一般会采用两种特征值相结合的方法,比如幅值和相位信息。但 Gabor 的相位信息会因为人脸空间位置发生改变而不太稳定。Gabor 幅值信息变化相对稳定,并且充分反映了人脸图像的能量谱。因此采取 Gabor 幅值特征。经过Gabor幅值特征处理,得到了人脸 Gabor 特征信息。5 个尺度,8 个方向的 Gabor 特征提取图如下所示:
在这里插入图片描述

2018-07-26 22:32:01 juwairen_yangfeng 阅读数 765
  • C++语音识别开篇

    本篇mark老师将教大家使用第三方库的调用来简单的实现语音识别。随着机器学习和人工智能的热闹,国内语音行业也可谓是百花齐放。 语音识别一个伟大的时代已在我们身边悄悄走来。

    5907 人正在学习 去看看 杨波

摘要:语音识别作为人工智能下很火爆的一门学科,是当下研究的一个重要领域。大多数的语音识别是基于市面上已有的语音识别模块,成本较高,本系统是孤立词语语音识别,考虑到成本以及可实现性,笔者选择了STM32F1系列MCU的最小系统,通过TFT彩屏实现人机交互,搭建音频采集模块,从而完成语音识别系统的硬件部分。软件设计采用A/D采样、预加重、加窗、端点检测、MFCC特征提取、特征匹配几个步骤,技术相对成熟,识别率较高。

主题词:孤立词语、音频采集模块、端点检测、MFCC特征提取、特征匹配

 

一、引言:语音识别的发展最早开始于上世纪50年代的贝尔实验室,Davis等科学家研究出可以识别出10个英文数字的实验装置。60年代的一系列数字信号处理方法推动了语音识别的发展,如FFT。同时,伴随着计算机技术的发展,语音识别逐渐从硬件工作转移到软件工作,这时的语音识别发展 很快,但人们很快就意识到语音识别的困难加深。此后,70年代日本学着提出的动态时间规整技术(DTW)解决不等长语音的对整匹配问题,以及80年代提出的隐马尔可夫模型法(HMM),都是现阶段语音识别的重要算法。

二、正文:

音频采集电路:首先是对于语音信号的采集,本系统使用电容式咪头采集音频,但MIC的输出电压只有几毫伏到十几毫伏,所以需要加放大电路,可采用三极管或者运放放大。本系统采用三极管阻容耦合二级放大电路,需要注意的是咪头需要一个工作电压,所以直接将VCC接到咪头的正极,然后第一级的耦合电容设置为10uf,这个对三极管基极充电时间有影响,它和集电极的电阻一同构成了RC充电电路,且10uf的电容会把音频信号耦合到基极上,咪头采集到的信号控制在3.3V以内。单片机是无法识别模拟电信号的,所以需要用到A/D采样;人说话的语音信号大多数有效信号集中在100HZ-3400HZ,所以根据香农采样定理,只要A/D采样频率大于等于6800HZ即可,这对于我们STM32F1系列单片机来说是完全可以实现的,接着考虑A/D精度,STM32F1ZET6拥有1~3个12 位逐次逼近型的模拟数字转换器,对于Vref=3.3v来说其最小误差为0.8mv,这是完全可以接受的,这就实现了语音模拟信号的采样量化。

高频补偿:经过研究,人的发生器官也相当于一个时变线性系统,在8000HZ以上频率时,会有大约6dB/倍频的频率衰减,所以为了平滑频率,需要对信号进行高频预加重,即 运用一个6dB/倍频的一阶数字滤波器。

语音信号的加窗处理:语音信号有一个很强的特性,那就是短时性,但从另一方面看,由于语音的形成过程是与发音器官的运动密切相关的,这种物理性的运动比起声音振动速度来说是缓慢的,所以在一个短时间范围内可以认为其变化很小,借此,我们对语音信号进行短时分析(分帧),一般语音信号在10ms-30ms之间保持稳定,我们去每帧长度为20ms,且为了使语音信号的连续性,每一帧之间混叠窗长的一半;窗函数的选择大致有矩形窗、汉宁窗、哈明窗等,而窗函数的选择要求一般包含两点:①尽量减少窗函数的旁瓣高度,使能量集中在主瓣②主瓣宽度尽量窄,以获得较陡的过渡带;介于以上条件,我们选择哈明窗。由于帧与帧连接处的信号因为加窗而弱化,如果没有帧移,这部分信息就丢失了。

端点检测:当系统接收到一段完整的语音信号时,去除语音段前后的噪声对于我们语音参数提取具有重要意义。经研究,当我们在发出语音时,清音和浊音会不断的出现,发现浊音的短时能量明显比环境噪声高,清音的短时平均过零率与环境噪声也有明显的区别,所以利用这个特性,设定短时能量和短时平均过零率的门限值,当某一帧的短时能量或短时平均过零率大于门限值,则可认为进入有效语音段,设定为语音起点,当某一帧的短时能量和短时平均过零率都小于门限值时,认为这是语音末点。

特征提取算法在语音识别系统中,模拟语音信号在完成 A/D 转换后成为数字信号。此时的语音信号为时域的信号,时域的信号难以进行分析和处理,而且数据量庞大。通常的做法是对时域信号进行变换,提取其中某种特定的参数,通过一些更加能反映语音本质特征的参数来进行语音识别。进过几十年的发展,语音特征提取算法大致有三类:

基于线性预测分析的提取方法 (LPCC)、基于频谱分析的提取方法(MFCC)、基于其它数字信号处理技术的特征分析方法,本系统采用基于频谱分析的提取方法,Mel频率倒谱频系数MFCC。

MFCC是Mel-Frequency Cepstral Coefficients的缩写,顾名思义MFCC特征提取包含两个关键步骤:转化到梅尔频率,然后进行倒谱分析。梅尔刻度是一种基于人耳对等距的音高(pitch)变化的感官判断而定的非线性频率刻度。和频率的赫兹的关系如下: M=2595log10(1+f/700)所以当在梅尔刻度上面上是均匀分度的话,对于的赫兹之间的距离将会越来越大。梅尔刻度的滤波器组在低频部分的分辨率高,高频部分分辨率低,这跟人耳的听觉特性是相符的。所以对于有效语音段,进行离散傅里叶变化(DFT),将频谱信号通过一组Mel尺度的三角形滤波器组,定义一个有M个滤波器的滤波器组,采用的滤波器为三角滤波器,中心频率为f(m),m=1,2,...,M。M通常取22-26。各f(m)之间在赫兹轴上的间隔随着m值的减小而缩小,随着m值的增大而增宽,但在梅尔刻度却是等距离。最后就是离散余弦变换,进行反傅里叶变换然后通过低通滤波器获得最后的低频信号,这样能量会集中在低频部分。每个三角滤波器会有一个输出,通过以上计算实现了每帧数据从N(FFT点数 )点到M点的降维,大大减小了计算量,减小了内存开销、缩减了运算时间。

特征匹配算法:现阶段,语音识别用到的模型匹配方法主要有动态时间规整(DTW)、隐马尔可夫模型(HMM)和人工神经网络。本系统用于孤立词识别,DTW 算法与 HMM 算法在相同的环境条件下,识别效果相差不大,但是 HMM 算法要复杂得多,这主要体现在HMM 算法在训练阶段需要提供大量的语音数据,通过反复计算才能得到模型参数,而 DTW 算法的训练中几乎不需要额外的计算。所以在孤立词语音识别中,DTW 算法得到更广泛的应用。笔者觉得,对于一个算法的理解,首先得从它的物理意义开始,在网上很多人的博客里都对这个算法有过通俗的解释,并配以实例,在这我就不多加说明了。主要步骤为初始化矩阵,计算每个数据之间的“距离”,计算累计匹配距离,匹配距离最小的特征模板与输入特征有最大的相似性。

单片机软件设计:首先,一段短时语音信号长度大约为2s以内,我们以8khz的ADC采用频率去采样得到的最大点数为16000,因为STM32F1为12位ADC,所以每个点的数据相当于两个字节,总的算来需要16000*2=32000字节,对于拥有64KB RAM的STM32F103ZET6来说在内存上是可以实现的。ST官方固件库提供的16位、1024点FFT用时2.138 ms,20ms为一帧,算下来总共有100帧,也就是100次1024点的FFT计算,总用时就是213.8ms,加上其他地方的指令、算法运算时间,识别一个指令应该在0.5s以内。至于每帧20ms,按照8khz的采样频率只能得到160个点,采用1024点FFT则需要在尾部补864个零,因为由公式(delta f)=fs/N 补零可以提高频率分辨率。且考虑到ADC采样次数比较多,所以采集到的数据采用DMA的方式传输到设定的数组,这样可以节省指令执行时间。从工程的初始化开始,代码如下……先是设定单片机运行频率(72MHZ),延时函数初始化(SysTick),ADC、DMA、按键函数部分以及需要用到的引脚的初始化,main()中的主要为一个按键函数来实现何时进行模板训练,何时进行语音识别。工程的主要部分为端点检测、MFCC语音特征提取、以及特征提算DTW的代码实现。想着重提出来说的是DTW算法,算法基于动态规划(DP)的思想,用于于长度不等的序列如何匹配。通俗理解也就是说怎么样的warping才是正确的?直观上理解,当然是warping一个序列后可以与另一个序列重合recover。这个时候两个序列中所有对应点的距离之和是最小的。所以从直观上理解,warping的正确性一般指“feature to feature”的对齐,我想这也是动态时间规整算法的核心。这个解释应该很宏观,理解了物理意义,这个算法也变的简单起来。

对于它的起源(DP)我们不去过多的诉说,而它广阔的应用前景,结合cpp面向对象的特性,我想我们可以把这个warping运用的很只能,就像对于人的情感、关系,将两个人综合特征的显现进行“匹配”,或是两代人之间的种种特征(貌似很像DNA检测,不过一个是唯物,一个是格物),这是对对象的一个小小改变。

2015-01-05 16:56:22 u012637501 阅读数 17956
  • C++语音识别开篇

    本篇mark老师将教大家使用第三方库的调用来简单的实现语音识别。随着机器学习和人工智能的热闹,国内语音行业也可谓是百花齐放。 语音识别一个伟大的时代已在我们身边悄悄走来。

    5907 人正在学习 去看看 杨波
一、语音识别技术
转载请表明出处:http://blog.csdn.net/u012637501(嵌入式_小J的天空)
    语音识别技术,广泛来说是指语意识别和声纹识别;从狭义上来说指语音语义的理解识别,也称为自动语音识别(ASR)。其关键技术包括选择识别单元、语音端点检测、特征参数提取、声学模型及语音模型的建立。语音识别技术目前在桌面系统、智能手机、导航设备等嵌入式领域均有一定程度的应用。其主要技术难题是识别系统的适应性较差、受背景噪声影响较大,未来的发展方向应是无限词汇量连续语音非特定人语音识别系统。
(1)信号处理及特征提取模块
    该模块的主要任务是从输入信号中提取特征,供声学模型处理。同时,它一般也包括了一些信号处理技术,以尽可能降低环境噪声、信道、说话人等因素对特征造成的影响。
(2)统计声学模型
    典型系统多采用基于一阶隐马尔科夫模型进行建模。
(3)发音词典
    发音词典包含系统所能处理的词汇集及其发音。发音词典实际提供了声学模型建模单元与语言模型建模单元间的映射。
(4)语言模型
    语言模型对系统所针对的语言进行建模。理论上,包括正则语言,上下文无关文法在内的各种语言模型都可以作为语言模型,但目前各种系统普遍采用的还是基于统计的N元文法及其变体。
(5)解码器
    解码器是语音识别系统的核心之一,其任务是对输入的信号,根据声学、语言模型及词典,寻找能够以最大概率输出该信号的词串,从数学角度可以更加清楚的了解上述模块之间的关系。
    当今语音识别技术的主流算法,主要有基于动态时间规整(DTW)算法、基于非参数模型的矢量量化(VQ)方法、基于参数模型的隐马尔可夫模型(HMM)的方法、基于人工神经网络(ANN)和支持向量机等语音识别方法.

二、非特定人、大词汇量、连续语音识别系统
       连续数字语音识别系统经过训练和识别两个部分。此训练可以看作是对 HMM 建立模型的过程。通过对参数重新评估,调整模型的各种参数,得到具有较好鲁棒性的模型。对基本模型进行改进和优化,可以有效提高精确度,获得更好的识别率。识别过程则可以认为是使用现有的 HMM 模型库、数据字典和语法控制组成识别网络,运用搜索算法寻找最佳匹配过程。 首先对等待识别的语音信号进行采样,然后通过转换变成电信号。预处理这 些电信号,也就是对信号进行增加预重、帧数分离、检测端点等操作。处理过后,对语音信号提炼生成特征的矢量数据。按识别模块中的 HMM 模型和词典要求组合,形成合词模型后完成识别,将结果和语言模型进行匹配,淘汰那些不符合语法限制的句子和词组,最后输出符合规范的识别的过程,就是语音识别的全过程。特征值、HMM 模 型、语法和数据字典都是影响识别率高低的重要因素。
    语音识别过程通常包括"前段"和"后端"两部分:“前端”模块 主要的作用是进行端点检测(去除多余的静音和非说话声)、降噪、 特征提取等;“后端”模块的作用是利用训练好的声学模型和语言模型对用户说话的特征向量进行统计模式识别(又称解码),得到其包含的文字信息,此外,后端模块还存在一个自适应的反馈模块,可以对用户的语音进行自学习,从而对声学模型和语音模型进行必要的校正,进一步提高识别的准确率。一个完整的非特定人大词汇量连续语音识别系统可大致分为三部分:语音信号预处理与特征提取、声学模型训练、语言模型训练、搜索算法与识别。
0.识别单元的选择

   选择识别单元是语音识别研究的第一步,分为单词、音节、音素。

(1)单词单元:广泛应用于中小词汇语音识别系统,但不适合大词汇系统,原因在于模型库太庞大,训练模型任务繁重、模型匹配算法复杂,难以满足实时性要求。

(2)音节单元:多见于汉语语音识别,主要因为汉语是单音节结构的语言,而英语是多音节。虽然汉语大约有1300个音节,但若不考了声调只有约408个无调音节。

(3)音素单元:目前广泛被应用到大词汇量语音识别系统中,原因是在于汉语音节仅有声明和韵母构成,并且声明和韵母的声学特性相差很大。

    总结,对大词汇量语音识别系统来说,通常识别单元越小,则计算量也越小,所需的模型存储量也小,要求的训练数量也少,但对应语音段的定位和分割较困难,因此识别模型规则也变得更复杂。

1、预处理模块

       对输入的原始语音信号进行处理(输入的语言信号首先要进行反混叠滤波 采样 A/D 转换 等过程进行数字化, 之后要进行预处理, 包括预加重 加窗和 分帧 端点检测等。),滤除掉其中的不重要的信息以及背景噪声,并进行语音信号的端点检测(找出语音信号的始末)、语音分帧(近似认为在10-30ms内是语音信号是短时平稳的,将语音信号分割为一段一段进行分析)以及预加重(提升高频部分)等处理。

目前主流的语音信号端点检测方法:

(1)短时能量En:反应语音振幅或能量随着事件缓慢变化的规律;

(2)短时平均过零率Zn:对于离散信号而言,是样本改变符号的次数,可以粗略分别清音和浊音;

(3)双门限端点检测:短时平均能量和过零率两者结合可以起到区分语音信号中的静音与语音信息的作 用,完成端点检测。一段完整的语音信号的可以分为三段:静音段、过渡段、语音段。 在静音段,过零率或能量越过了低门限,进入过渡段。在过渡段,过零率或能量都降低至低门限以下,则恢复到静音态;过零率或能量中的其中一个越过了高门限,则为进入了语音段。在低噪声情况下,双门限端点检测简单可靠。但在噪声较大的情况下,该方法失去判断能力,所以此方法的抗噪能力较差。 

2、声学特征提取

       语音信号是一种典型的时变信号,然而如果把音频的参考时间控制在几十毫 秒以内,则得到一段基本稳定的信号。去除语音信号中对于语音识别无用的冗余信息,保留能够反映语音本质特征的信息,并用一定的形式表示出来。也就是提取出反映语音信号特征的关键特征参数形成特征矢量序去掉那些相对无关的信息如背景噪声、信道失真等,以便用于后续处理目前的较常用的提取特征的方法还是比较多的,不过这些提取方法都是由频谱衍生出来的。

目前主流的语音信号特征提取方法:

(1)线性预测系数(LPCC):很好的模拟语音信号,语音信号是由声带振动发出的, 声带可以不振动也可以有周期的振动,分别对应清音(consonants)和浊音(vowels),每一段声管则对应一个 LPC 模型的极点。通常极点个数在 12-16 个左右,即可清晰地描述信号的特征了。

(2)Mel频率倒谱系数(MFCC)参数

   人的听觉系统却是一种特殊的非线性系 统,它对不同频率信号的响应灵敏度有较大区别。 MFCC参数比 LPC 参数更能够充分利用人耳的感知特性提高系统的识别性能因其良好的抗噪性和鲁棒性而应用广泛。MFCC的计算首先用FFT将时域信号转化成频域,之后对其对数能量谱用依照Mel刻度分布的三角滤波器组进行卷积,最后对各个滤波器的输出构成的向量进行离散余弦变换DCT,取前N个系数。在sphinx中也是用MFCC特征的,用帧frames去分割语音波形,每帧大概10ms,然后每帧提取可以代表该帧语音的39个数字,这39个数字也就是该帧语音的MFCC特征,用特征向量来表示

(3)小波分析

3、声学模型训练(模版匹配方法)

      声学模型的训练,即为建模过程。声学模型是识别系统的底层模型,是语音识别系统中最关键的部分。声学模型表示一种语言的发音声音,可以通过训练来识别某个特定用户的语音模式和发音环境的特征。根据训练语音库的特征参数训练出声学模型参数,在识别时可以将待识别的语音的特征参数同声学模型进行匹配与比较,得到最佳识别结果。

目前主流的声学模型训练方法

(1)动态时间规整(DTW):现实生活中语音信号的 随机性较强,就是同一人说的话,也不太可能说出一句一模一样的话来。就算字词都一样,发音的时间长短也可能不一样。因此,需要寻找一种变换关系来削除这种时间上的距离偏差,这种结合时间变换关系求特征序列之间距离的技术算法 称为动态时间规整算法(DTW:DynamicTimeWarping)。动态时间规整(DTW)算法 的算法的思想,就是将待识别的语音信号均匀的升长或缩短,使其与参考模板的长度一致。同时,使语音信号的时间轴进行不均匀的扭曲和弯折,最终达到与模板的特征对齐。DTW 是较早的一种模式匹配和模型训练技术, 它把整个单词作为识别单元,在训练阶段将词汇表中每个词的特征矢量序列作为模板存入模板库,在识别阶段将待识别语音的特征矢量序列依次与库中的每个模板进行相似度比较,将相似度最高者作为识别结果输出。DTW 应用动态规划方法成功解决了语音信号特征参数序列比较时时长不等的难题,在小词汇量、孤立词语音识别中获得了良好性能。但因其不适合连续语音大词汇量语音识别系统, 目前已逐渐被 HMM 和 ANN模型替代。
(2)矢量量化(VQ)技术
    矢量量化(VectorQuantization)是一种适用于小词汇量、孤立词的语音识别的 信号压缩方法 。矢量量化器的设计其核心思想是:为某一个特定的信源设计一 个优化的码书,那么来自同一个信息源所产生的信号与该码书的平均量化失真就应远远小于他与其他信息的信号与该码书的平均量化失真,也就是说编码器本身存在一定的区分能力。 
(3)隐马尔可夫模型HMM 

     HMM是对语音信号的时间序列结构建立统计模型,将其看作一个数学上的双重随机过程:一个是用具有有限状态数的Markov链来模拟语音信号统计特性变化的隐含(马尔可夫模型的内部状态外界不可见)的随机过程,另一个是与Markov链的每一个状态相关联的外界可见的观测序列(通常就是从各个帧计算而得的声学特征)的随机过程。

    HMM 模型是语音信号时变特征的有参表示法。它由相 互关联的两个随机过程共同描述信号的统计特性,其中一个 是隐蔽的 (不可观测的) 具有有限状态的 Markor 链, 另一个是 与 Markor 链的每一状态相关联的观察矢量的随机过程 (可观测的) 。HMM 很好的模拟了人得语言过程, 目前应用十分广泛。目前的主流语音识别系统多采用隐马尔可夫模型HMM进行声学模型建模。声学模型的建模单元,可以是音素,音节,词等各个层次。对于小词汇量的语音识别系统,可以直接采用音节进行建模。而对于词汇量偏大的识别系统,一般选取音素,即声母,韵母进行建模。识别规模越大,识别单元选取的越小。 

        人的言语过程实际上就是一个双重随机过程,语音信号本身是一个可观测的时变序列,是由大脑根据语法知识和言语需要(不可观测的状态)发出的音素的参数流(发出的声音)。HMM合理地模仿了这一过程,是较为理想的一种语音模型。用HMM刻画语音信号需作出两个假设,一是内部状态的转移只与上一状态有关,另一是输出值只与当前状态(或当前的状态转移)有关,这两个假设大大降低了模型的复杂度。所以 HMM 可以 非常精确地描述语音信号的产生过程。 

       语音识别中使用HMM通常是用从左向右单向、带自环、带跨越的拓扑结构来对识别基元建模,一个音素就是一个三至五状态的HMM,一个词就是构成词的多个音素的HMM串行起来构成的HMM,而连续语音识别的整个模型就是词和静音组合起来的HMM。总之 HMM 模型较为完整的表达了语音的声学模型,采用统计的训练方法将 上层的语言模型和底层的声学模型融入统一的语音识别搜索算法中,并获得更好 的效果。

(4)人工神经网络模型(ANN)

     神经网络是由许多被称为节点的简单非线性模拟处理要素密集互连配置而成的,是 一种模仿了生物神经元的系统模型。网络通过令每一个节点的输出与一些其他的节点输入连接形成,类似于真实神经元的突触连接。每个神经元表达了一种特定的输出函数,称为激励函数,每两个神经元之间的连接都包含一个连接强度,也就是作用于通过该连接的信号的加权值。经过训练之后的神经网络,具有信息特征抽取、知识概括和学习记忆的能力,而模型学习到的信息或知识则储存在每个单元节点之间的连接矩阵上。一个神经网络的表现是由节点定义,拓扑结构以及学习算法这三个特征组成的集体性质决定的。 

   ANN本质上是一个自适应非线性动力学系统,是由结点互连组成的计算网络, (优点)人工神经网络(ANN) 基本上能够模拟人类神经的活动原理,具有学习特性、容错性、并行性、自适应性和鲁棒性,是一个自适应非线性动力学系统,且具有较强的分类能力和输入输出映射能力。这些能力是 HMM 模型不具备的, 可用于处理一些环境信息十分复杂, 背景知识不清楚, 推理规则不明确的问题, 允许样品有较大的缺损、 畸变, 因此对于噪声环境下非特定人的语音识别问题来说是一种很好的解决方案。(缺点)由于语音训练和识别时间太长,实现和应用较难等不利因素,所以到目前为止该方法停留在实验阶段,目前大部分应用神经网络的语音识别系统都采用了 BP 网并取得了较好的识别效果.将 ANN 与 HMM 结合分别利用各自优点进行识别将是今后的一条研究途径。ANN 具有 较好的区分复杂分类边界的能力,显然它十分有助于模式识别。在这些研究中,大部分 

采用基于反向传播算法(BP 算法)的多层感知网络。 

a.BP神经网络:BP 神经网络在训练的时候,正向传播之后输出层没有得到期望输出,则采用反向传 播算法,提高网络系统对样本的似然度(Likelihood)。将样本的实际输出与期望输出之间的差值即误差信号,并在逐层反向传播的过程中由误差反馈不断调整网络的权值。网络学习效果的提升可以由增加隐藏层层数实现。 在诸多神经网络中,BP 是应用较多的一种,用于语音识别时也具有较好的效果,这 是由于 BP 神经网络具有许多独特的优点:(1)它可以联想模式对,将复杂的声学信号映射为不同级别的语音学和音韵学的表示;(2)可以通过插值进行归纳,因此相关特征 

可通过训练获取(3)对不同的类,他可以在超平面中形成不相交的区域,很适合捕捉细微的规律;(4)输入可以是二值或连续值,也可以是声学属性或语音特征的任意组合; (5)对数据的分布不做先验假设,对模型使用全局约束,因此能构造光滑的类边界, 识别精度好。虽然 BP 神经网络具有强大的计算能力,能够好的应用于语音识别,但随着对识别 性能要求的提高,网络本身仍有一些问题逐渐暴露出来,以下方面亟待改进: 

(1)局部极小值问题; 

(2)增加神经网络的可理解性。人们暂时仍然无法直接理解网络学习存储在连接矩阵上的知识; 

(3)加快神经网络学习速度。目前大部分神经网络算法都无法回避的一个部分就是迭代问题,为了获得好的学习效果,迭代需要大的计算开销。 

b.神经网络训练

    神经网络的学习也称为训练,是指通过神经网络所在环境的刺激作用,调整神经网 络的自由参数。能够从环境中学习和在学习中获得系统工作效果提升,是神经网络最有意义的性质。在神经网络中,一般有两类训练算法。 

(1)有监督学习算法。不但需要训练用的输入信号,同时需要与输入相对应的表示所需输出的目标信号。网络通过计算实际输出与每组输入对应的目标输出之间的差值来调整权值,做出正确反应。 

(2)无监督学习算法。不要求有目标输出,算法提供一个关于网络学习表示方法质量的测量尺度,根据尺度将自由参数最优化,当网络与输入数据统计规律性一致,就能形成内部表示方法记忆输入特征,由此进行类别识别。 

4、语言模型训练

       语音识别中的语言模型主要解决两个问题一是如何使用数学模型来描述语音中词的语音结构二是如何结合给定的语言结构和模式识别器形成识别算法。语言模型是用来计算一个句子出现概率的概率模型。它主要用于决定哪个词序列的可能性更大,或者在出现了几个词的情况下预测下一个即将出现的词语的内容。换一个说法说,语言模型是用来约束单词搜索的。它定义了哪些词能跟在上一个已经识别的词的后面(匹配是一个顺序的处理过程),这样就可以为匹配过程排除一些不可能的单词。语言模型一般指在匹配搜索时用于字词和路径约束的语言规 则,它包括由识别语音命令构成的语法网络或由统计方法构成的语言模型, 语言处理则可以进行语法、 语义分析.

       语言建模能够有效的结合汉语语法和语义的知识,描述词之间的内在关系,从而提高识别率,减少搜索范围。语言模型分为三个层次:字典知识,语法知识,句法知识。

         对训练文本数据库进行语法、语义分析,经过基于统计模型训练得到语言模型。

目前主流的语言建模方法

(1)基于规则模型
(2)基于统计模型

    统计语言模型是用概率统计的方法来揭示语言单位内在的统计规律,其中N-Gram模型简单有效,被广泛使用。它包含了单词序列的统计。N-Gram模型基于这样一种假设,第n个词的出现只与前面N-1个词相关,而与其它任何词都不相关,整句的概率就是各个词出现概率的乘积(即根据前面N-1个词汇的历史来决定下一个词可能出现的概率)。这些概率可以通过直接从语料中统计N个词同时出现的次数得到常用的是二元的Bi-Gram和三元的Tri-Gram。

         Sphinx中是采用二元语法和三元语法的统计语言概率模型,也就是通过前一个或两个单词来判定当前单词出现的概率P(w2| w1),P(w3| w2, w1)。

5、语音解码和搜索算法

       解码器:即指语音技术中的识别过程。针对输入的语音信号,根据己经训练好的HMM声学模型、语言模型及字典建立一个识别网络,根据搜索算法在该网络(识别网络)中寻找最佳的一条路径,这个路径就是能够以最大概率输出该语音信号的词串,这样就确定这个语音样本所包含的文字了。所以解码操作即指搜索算法是指在解码端通过搜索技术寻找最优词串的方法。连续语音识别中的搜索,就是寻找一个词模型序列以描述输入语音信号,从而得到词解码序列。搜索所依据的是对公式中的声学模型打分和语言模型打分。在实际使用中,往往要依据经验给语言模型加上一个高权重,并设置一个长词惩罚分数。当今的主流解码技术都是基于Viterbi搜索算法的,Sphinx也是。模型参数得到后可以用 Viterbi 算法来确定与观察序列对 应的最佳的状态序列。建好模型后,在识别阶段就是要计算每个模型产生观察符号序列的输出概率,输出概率最大的模型所表示的词就是我们的识别结果。

    基于动态规划的Viterbi算法在每个时间点上的各个状态,计算解码状态序列对观察序列的后验概率,保留概率最大的路径,并在每个节点记录下相应的状态信息以便最后反向获取词解码序列。Viterbi算法本质上是一种动态规划算法,该算法遍历HMM状态网络并保留每一帧语音在某个状态的最优路径得分。

    连续语音识别系统的识别结果是一个词序列。解码实际上是对词表的所有词反复搜索。词表中词的排列方式会影响搜索的速度,而词的排列方式就是字典的表示形式。Sphinx系统中采用音素作为声学训练单元,通常字典就用来记录每个单词由哪些个音素组成,也可以理解为对每个词的发音进行标注。

     N-best搜索和多遍搜索:为在搜索中利用各种知识源,通常要进行多遍搜索,第一遍使用代价低的知识源(如声学模型、语言模型和音标词典),产生一个候选列表或词候选网格,在此基础上进行使用代价高的知识源(如4阶或5阶的N-Gram、4阶或更高的上下文相关模型)的第二遍搜索得到最佳路径。



语音识别入门

阅读数 6893

没有更多推荐了,返回首页