孤立词语音识别算法和复杂度

1. 摘要

非特定人孤立词识别时间复杂度需求最高的部分是短时傅立叶变换。其次是说话人特征平滑(非特定人连续语音识别则相反,复杂度最高的是模式识别部分)。识别基本原理为,将信号通过短时傅立叶变换为话语频谱图,然后提取特征用于对比预设模版或对其做分类/序列标记。

话语识别模型并不是随时都在工作,通常情况会在前级设置信号能量检测,只有在信号能量持续高于门限才会进入话语识别处理流程。在语言识别期间一般会忽略麦克风信号(原因是处理器资源被全部用于特征计算)。当然,如处理器性能足够,也可以不忽略识别期新接收到的信号。

2. 话语信号特性

人类语言的频率范围大约在50Hz – 3.5kHz之间,并且被认为是非平稳信号(其幅度和频率随着时间改变),但是在很短的时间范围(20ms-40ms)内,其信号改变不明显,可以认为是平稳信号,语音识别正是以这个时间片为基本语素识别单位。

另外, 人耳对不同频段的音频信号分辨率不同,在低频分辨率比较高,而高频段信号分辨率比较低。

中文为单音节字符,英文可以具有多音节字符,但单音节很容易被算法误判(人耳也是如此)。因此语音识别算法更适用于三到四个音节以上连续发音。

不同的说话人其频谱范围不同,所以要做到非特定人高识别率,需要用到多人多词汇语料训练模式识别模型,以达到消除说话人差异的目的, 反之也可以突出说话人特征,识别说话人。

3. 算法流程和复杂度计算

基本流程:

模拟低通滤波去除高于4khz的信号 -> ADC -> 信号检测 -> FIR -> 分桢 -> 加窗 -> 短时傅立叶变换并取模 -> mel三角滤波器 -> 倒谱 -> 模式识别(神经网络/深度学习/图模型/模版比对等,孤立词识别最简单的方法是DTW(动态时间规整)做模版对比,但缺陷是只能做到特定人(模版录制人)高识别率)。

3.1 预设参数

ADC采样率 8Khz, 位宽16bit(据说12bit效果也可行)。
每桢时间宽度25ms, 前后桢重叠15ms(桢位移步进10ms)。
mel滤波器通道数40个。倒谱变换(频谱包络分离)只取前面12个点成分。
在语音信号前后预留200ms-300ms左右空白低幅度信号以避免词汇遗漏。
假设使用DTW对比预设模版实现词汇识别。

3.2 算法流程和复杂度

时间复杂度 \( T(n) \):
常数项约为一个乘法和加法。记为 \( c_t \)

空间复杂度 \( S(m) \):
常数项为一个bit16或bit32的数值空间。 记为 \( c_s \)

以下按算法顺序说明并计算对应复杂度:

3.3.1 短时平均能量和短时平均过零率

识别算法平时并未被执行,长驻系统执行的是信号能量检测,目的是检测当前麦克风是否存在音频信号,只有持续超过特定门限的信号片断才会被保存并传递到识别算法模块。 识别信号算法有两种,需要配合执行,只有当两个信号指标均多次超过门限才能认为麦克风有信号。 对于信号门限判断基本为线性判别式。根据实际硬件性能和样本条件选择判别式窗口,信号检测算法是需要跟随音频输入持续运行的,所以这实际上也是硬件计算速度的最低需求,原因是性能太低可能会因为性能不足而错过部分音频信号。

3.3.1.1 短时平均能量/幅度

\[ E_n = \sum^{+\infty}_{m=-\infty} [x(m)w(n-m)]^2 \]

在n时刻的能量等于n时刻前后m区间的加权平方和。在工程中,m区间宽度是25ms(前面已经预设)。这里考虑简单平均,那么实际上每桢的短时平均能量就是:

\[ E = \frac{1}{M} \sum^{M}_{m=1} x(m)^2 \]

分桢是矩形窗,于是这里每桢时间复杂度为(实际操作中,可以改平方为取绝对值(幅度),这并不影响信号门限度量,但降低了性能需求):

\[ T(短时平均能量(桢长=0.025秒)) = c_t M = c_t 8kHz * 0.025 = c_t 200 \]

3.3.1.2 短时平均过零率

只检测平均能量误触率比较高,所以再结合短时平均过零率检测.

\[ Z_n = \sum^{+\infty}_{m=-\infty} |sign[x(m)] – sign[x(m-1)]| w(n-m) \]

这里其实就是检测每桢的采样点中有多少个点在一阶差分上是过了零点的。和上面一样,实际窗口等于桢长的矩形窗,计算简单平均。时间复杂度:

\[ T(短时平均过零率(桢长=0.025秒)) = c_t M = c_t 8kHz * 0.025 = c_t 200 \]

结合上面的短时平均能量,那么实际上每个采样点都要计算两次。其时间复杂度为:

\[ T(n=采样率) = 2 * c_t * n \]

注意: \( c_t \)代表单个乘加计算时长。

3.3.1.3 信号门限的线性判别式

一般情况下连续多桢平均能量和平均过率超过门限才认为信号到来。那么这里使用如下判别式:

\[ g(n=桢编号) > c = a_n * E_n + b_n * Z_n + a_{n-1} * E_{n-1} + b_{n-1} * Z_{n-1} \cdots > c \]

其中 \(a,b,c\)是预先计算好的系数和门限,其数量取决判断桢数,一般需要判断5-10桢。高于门限表示有语音信号,低于门限表示语音信号结束。

信号门限检测的时间和空间复杂度总计:
结合以上计算, 去掉低次项(线性判别复杂度相对平均能量和过零率计算非常小)的时间复杂度为 \( O(2n) \) , n为采样率(8kHz)。也就是说,单片机必须每秒计算至少16K个乘法和加法才能满足语音识别最低需求。
忽略低次项的空间复杂度为 \( S(f(t)) = O((t+1) * 8000) \)。 t为需识别的音频信号序列总时间长度,单位秒, 采样率8khz, 之所以要多保留1秒,是因为考虑话语单词停顿和话语信号前后预留空白,以免说话人发言还没有结束就错误的开始进行语音识别。常数项为 bit16(每个采样点两个字节)。注意: 这并不是语音识别最低内存需求,因为后续离线计算还需占用大量内存。

3.3.2 特征处理和模式识别

经过前面的音频片断拾取后得到待识别音频数据,接下来把音频数据根据需求转换为文本(或类别)。这个转换的过程中一般会暂停新音频拾取,也就是说此时麦克风任何信号都会被忽略。虽然单片机每秒最低处理16kHz就可实现语音识别,但特征处理和模式识别时间过长,会极大降低用户体验,想像一下,说话人发出命令后等待数秒系统才给出识别结果。 接下来分析识别算法每个步骤。

为方便描述,我们约定:
待识别音频信号长度用秒为基本单位,使用符号 \( t \) 标识。
采样率:8kHz

3.3.2.1 一阶FIR高通滤波器

高频信号一般幅度比较低,需要增强高频信号以突显特征。这里使用一阶FIR实现高频预加重。

\[ x(n) = a x(n) – b x(n-1) \]

在采样率为8khz下,a,b分别为 1.0和0.97。 很显然:

时间复杂度: \( O( 8000 t ) \)
空间复杂度: \( O( 16000 t) \) (保存计算前和计算后的数据, 实际工程中可以分段计算,减少存储占用。)

3.3.2.2 分桢

将信号序列分为宽度25ms,重叠区域15ms的连续交叉桢。最终得到的桢数(不足整数桢的补0)为:

\[ \begin{align}
frame count = \frac{8000 t}{8000 * 0.01} = \lceil 100 t \rceil
frame lengtg = 8000 * 0.025 = 200
\end{align} \]

时间复杂度: \( O(8000t) \)
空间复杂度: \( O( 200 \lceil 100 t \rceil ) \)

3.3.2.3 加窗

这里加hamming窗的目的减小傅立叶变换的旁瓣,毕竟没法对信号做等周期分桢(天知道周期是啥,随时在变)。
hamming窗就是对每桢信号做乘法。因此时间和空间复杂度都是:

\[ O(f(t)) = O(200 \lceil 100 t \rceil) \]

3.3.2.4 短时傅立叶变换

对每桢信号做FFT变换,并且对变换结果取模和和对数,转换为声压。取对数还有个因素是突显低幅值频率成份.
fft变换的时间复杂度为 \( n \log n \), 底数是2。实际操作中以256为起始点(最低识别频率31Hz)。而在语音识别这里,n就是桢长度: 200, 考虑到只取正频率部分,那么整个信号长度的时间复杂度为:

\[ O(f(t)) = O(\lceil 100 t \rceil( 200 \log 200 + 100 )) \]

3.3.2.5 mel三角滤波

40个滤波通道,这里也就是 100维的fft结果向量到40维的mel向量转换。突出人耳敏感频率区域。在频域的滤波器实际上就是乘法。时间复杂度等同加hamming窗.

如果是连续语音识别或后续接深度学习网络,那么特征处理到此为止。但如模式识别算法精度不高,那么还需要进一步处理。

3.3.2.6 倒谱(提取共震峰)

这里的处理就两步,先把前面的滤波结果取对数,接着做cos变换(类似dft)。在不考虑算法优化情况下,只取12个点,那么计算复杂度为, (dct之前有40个点,cos函数靠查表实现)

\[ O(f(t)) = O( 480 \lceil 100 t \rceil ) \]

3.3.2.7 最简易的DTW模版比对孤立词识别.

使用欧式距离对比模版和待识别特征距离,距离最近的为识别结果。

\[
O(DTW(t)) = O(\sum^{p=模版数}_{i=1} 12 freamecount(p) \lceil 100 t \rceil ) \\
result = \arg\min_p dtw(p, test)
\]

假设有10个模版,平均每个模版时长1秒(即桢数100), 待识别语音长度也是1秒, 那么dtw复杂度
O(f(t)) = 12 * 100 * 100 * 10 = 1200000

3.3.3 时间复杂度和空间复杂度总结

假设10个模版,平均模板时长1秒。累计之前计算的所有项。

语音识别部分时间复杂度: O(1468800t)
大约等效为每秒信号识别需要计算147万个单精度(在fft时双精度效果更好)乘加法。不同的处理器架构指令周期不同,以arm为例,官方给的为 1.25MIPS/Mhz
也就是说每1M的时钟可以执行1.25M指令,但是实际计算中,每个时间步骤一个指令完成不了,大概需要3-10个指令。也就是说. 假设1秒的语音信号需要在1秒内识别完毕,我们需要大约50M-100M的时钟,并且需要硬件级别的乘法器(软件模拟乘法速度慢上千倍)。如果能用硬件实现消耗最大的fft计算和向量乘加运算,并且在几个指令周期完成一个fft,或可以使用向量指令在单指令周期完成计算。那么单片机时钟需求可以降低数倍。

语音识别部分空间复杂度: O(35200t), 约等于每秒语音信号需占用70kb RAM(如考虑模版数量则乘模版倍数)。

如果可能,在硬件中实现单指令多数据向量计算,常见的对数,指数,三角函数。点乘,叉乘,矩阵乘法,加法等。那么可以明显提高性能。这样就不用每个变量循环计算。在语音识别中,每桢就是一个向量,而针对每个向量的计算完全相同。是可以作为向量指令实现的。

3.4 提升识别精度和性能.

如果是孤立词,但是非特定人:
mfcc做时间序列网络,压缩为向量后对比模版向量,做距离或余玄角度,复杂度 lstm gru算法. 需试验确定.

如果是连续非特定人(不适合单片机)
mfcc或mel滤波后,做高斯混合,后接hmm(或许也可以考虑最大墒或crf), 得到声学模型后,再乘语言模型概率矩阵。得到最终识别结果.

如果是深度学习(不适合单片机)
mfcc,后接双向lstm+ctc,再乘语言模型概率矩阵。

Leave a Reply

Your email address will not be published.

Time limit is exhausted. Please reload the CAPTCHA.

Proudly powered by WordPress   Premium Style Theme by www.gopiplus.com
渝公网安渝公网安备 50010702500270号 渝ICP备09056628号-7