基于动态时间规整的声控指令识别
来源:互联网 发布:阿里专有云asp csp 编辑:程序博客网 时间:2024/04/27 15:47
识别过程:
1 用户通过麦克风输入语音指令
2 软件返回所识别的指令文本内容
训练过程:
3 用户按照软件窗口提示信息,通过麦克风输入指定的语音内容,完成训练数据的录入
4 软件提取语音参数模板,形成特征辞典库
指令格式:
支持固定长度的短语、数字或两者的混合。
芝麻开门
3721
芝麻开门3721
3721芝麻开门
如何计算语段样本之间的距离
一种识别问题,在数学上总是可以等价为某种距离的计算。DTW(Dynamic Time Wrapping)是比较两个时间序列之间距离(即相似度)的简单而有效的工具。语音信号,很显然就是一种时间序列。下面我们来设想一下如何比较两个语音波形之间的距离,也就是相似度。
设想一个周期性的谐波,我们最容易想到的就是3至4个周期的正弦波。将其增加一万倍,设想一万个周期的波形。这样的数据量就和一句语句的尺度相当,而且实际的语音波形幅度是一个随机变量。我们可以看到,比较两个语音波形之间的相似程度,直接计算是非常困难的。通常,我们要将其变换到频域中来。
对这样的时域波形,进行谐波分解,将其频率分量提取出来,形成MFCC(镁尔倒谱参数)。上述时域波形的数据量,大约会减小100倍。此时,我们仍然面对着一个时间序列,序列中的每个成员,都是一个13维的MFCC参数向量,代表该时刻的频域特征。频域特征自然是随时间变化的,对应了不同的语音中的音节。
现在我们可以回到两个时间序列之间的距离的计算上来了。已经得到了MFCC特征序列,数据量已经降下来了,但是这两个序列的长度是不相等的(两句同样内容的语音,时间长度不相等)。因此,在比较两个序列之间的相似度时,需要进行“对齐”。
在对齐的过程中,我们可以将序列部分的“拉长”和“压缩”,在拉长和压缩的过程中,对数据点即进行插值或删除。总之,合理的对齐方式有很多种可能性,将这些可能性全部枚举(遍历)一遍,找到最佳的方式,使得两个时间序列之间的匹配度最高(距离最小),即是一个优化搜索的问题。这个优化问题,可以通过动态规划,“分段”进行优化求解,称为DTW(Dynamic Time Wrapping)。
如何设计识别模板
有了计算时间序列之间距离的工具,我们就可以来进行语音识别和声纹匹配。在进行语音识别时,就是对比两条语音数据的相似程度,识别出用户说的是哪条口令。在进行声纹匹配时,就是对比某条口令由不同的人发音时,声纹图的相似程度,MFCC特征是反映这种相似程度的较好特征。
我们进一步考虑,如何对比两条语音的相似程度。有三种设计方式。
第一种是将语句作为一个整体,输入到DTW模块中。这样做的好处是语句内部可以连读、停顿,可以有噪声。这些干扰因素都会在动态规划算法中,通过序列的压缩和拉伸消除掉。
第二种是将整条语句切分成“字”的级别,这样做对切分的精度要求较高,切分模块稍有偏差,就会导致错误向后传播,影响整个后续的识别系统。但是这种方法的优点是可以不完全约束用户口令的文本内容,用户可以说“春暖花开 1 2 3 4”,而其中的数字,可以是任意的,只要其在注册过的“字典”中。这个时候,我们对比的不是整个语句之间的相似度,而是相应位置的字的相似度。可以推出:“春暖花开 开 开 花 花”也是可以被识别的。
第三种方法,是组合前两种方法,对词语部分进行整句识别,支持连读,对数字部分进行切分到字级别的识别。这种方式下,切分模块的功能变复杂,精度可能下降。但优点是既能支持连读,又能任意修改部分文本的内容。
其实到这里,我们已经在使用“模板”这个概念了,上面将整个语句作为识别对象,就是以某条语句为模板,将字作为识别的最小级别,就是将某个字作为模板。模板当然会有很多个,模板越多,模板构成的字典越大,能识别的词汇量越大
动态时间规整代码实现:
/*------------------------------欧氏距离 for MFCC-----------------------------*/double DistFrame(double* p1, double* p2){ double sum = 0; int order = ORDER; int i; for (i = 0; i < order; i++) { sum = sum + (*(p1 + i) - * (p2 + i)) * (*(p1 + i) - * (p2 + i)); } sum = sum / order; sum = sqrt (sum); /* a ^ 2 + b^ 2 + ... */ return sum;}/*--------------------------------DTW-----------------------------------------*/double MatchingDTW(double* p1, double* p2, int len1, int len2){ /* 基本算法, 有约束 */ int n, m; n = len1; m = len2; /* check n>0 m>0 */ if ((n < 2) || (m < 2)) { printf(">>>>>>>> unaccepted DTW input (Error in Segment Length) : n, m: %d, %d\n", n, m); return 100000; } /*int mfccOrder = ORDER;*/ double* dtw; dtw = (double*)malloc(sizeof(double) * n * m); /* * ------------------------- * - i - * 1 ... n * | m * j .. * | 1 * ------------------------- */ /* 注意要归一化 两帧mfcc 之间的距离 远小于102400 */ double nInf = n * m * 10240; /* 注意不要超过 c++ 的最大数, 初始化 dtw */ for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { *(dtw + i * m + j) = nInf; } } *(dtw) = 0; /* Window, 可调节的 local constrain */ int w = (int)(0.2 * (n + m) / 2); /* 动态规划 */ double cost; /* why we have n-1 and m-1: room for 13 mfcc values */ n = n - 1; m = m - 1; /* printf("start DTW on distance space: \n"); */ for (int i = 1 ; i < n; i++) { for (int j = max(1, i * m / n - w) ; j < min(m, i * m / n + w) ; j++) { cost = DistFrame(p1 + i * ORDER, p2 + j * ORDER); if (cost > 10) { printf("Unusual cost value in DTW function: %f, @frame %d, %d\n", cost, i, j); } /* printf("mfcc距离 = %d; ", cost); */ double minimum = 0; minimum = *(dtw + (i - 1) * m + j ); if ( *(dtw + i * m + j - 1) < minimum ) { minimum = *(dtw + i * m + j - 1); } if ( *(dtw + (i - 1)*m + j - 1) < minimum ) { minimum = *(dtw + (i - 1) * m + j - 1); } /* printf("dtw最小距离 = %d;", minimum); */ *(dtw + i * m + j) = cost + minimum; /* printf("dtw路径距离 = %d;", *(dtw + i * m + j)); */ } } /* printf("\n"); */ double dist = *(dtw + n * m - 1); if (dist > 100) { printf("Unusual dist valule in DTW function: %f\n", dist); } free(dtw); return dist;}
效果和改进
- 基于动态时间规整的声控指令识别
- 动态时间规整算法
- DTW 动态时间规整
- 动态时间规整DTW
- 动态时间规整DTW简述
- 动态时间规整DTW简述
- 动态规划-时间规整算法
- 动态时间规整(DTW)
- DTW(动态时间规整算法)
- 动态时间规整(DTW)
- 动态时间规整算法(dynamic time warping)
- 动态时间规整简介及入门
- 动态规划时间规整简介入门
- Dynamic Time Warping 动态时间规整算法
- 算法笔记-DTW动态时间规整
- Dynamic Time Warping 动态时间规整算法
- Dynamic Time Warping 动态时间规整算法
- Dynamic Time Warping 动态时间规整算法
- Python模块paramiko安装
- boost之program_options库,解析命令行参数、读取配置文件
- 解决Linux环境下Tomcat日志乱码的问题
- 将服务器安装的Windchill迁移到本地分区以便用于开发和测试
- Tomcat 解决中文路径的图片不能显示问题
- 基于动态时间规整的声控指令识别
- 169 Majority Element
- java学习练习(每个程序员1小时内必须解决的5个编程问题)
- 理解class.forName()
- 行星序列(AHOI2009)(线段树)
- Web - 发布网址更改方法
- Android 调用电话和短信
- .net 调用delphi 的DLL
- objdump && readelf