编写自己的语音识别代码


17

问题描述

我想将语音识别用作硬件项目的一部分,我想完全将其包含在内(我使用的是低功耗,低速的小型设备,例如Arduino和Raspberry Pi,Kinects等,而不能运行具有涉及到一个操作系统(因此是一个封闭/自包含的项目)。

语音识别可能非常复杂,具体取决于您所需的复杂程度。我有一套相对简单的要求。我只想识别自己的声音,并且有一个小词典,我想识别20个左右的单词。因此,我不需要复杂的语音到文本和语音识别库,也不需要通过互联网搜索引擎找到的任何出色的第三方软件(不乏这些!)。我认为我的要求“足够简单”(在一定程度上),我可以编写自己的解决方案。我想知道是否有人编写了这样的自己的流程,我的方法是否存在严重缺陷?有没有更好的方法可以做到这一点,而无需高水平的数学知识或不必编写复杂的算法? 这就是我尝试在下面考虑的解决方案。

解决方案说明

我将使用C语言编写此文档,但我希望讨论语言不可知的过程,重点是其自身的过程。因此,如果可以的话,让我们忽略它。

1。我将预先录制我的单词词典,以使其与口语相匹配。我们可以想象我有20个录音,记录了20个不同的单词,或者说是短短语或两个或三个单词的句子。我相信,这比实际将音频转换为文本并比较两个字符串要容易,比较两个录音文件的过程更容易。

2。麦克风已连接到运行我的代码的硬件设备。[1]。该代码连续获取固定长度的样本(例如长度为10毫秒),并以循环记录方式存储例如10个连续的样本。[2]。(我是在脑海中发明这些数字的,因此它们只是描述过程的示例)。

[1]这很可能通过带通滤波器和运算放大器进行连接,就像进行字典录音一样,以保持较小的存储和收集的音频样本。

[2]我不确定要如何采样,我需要制定一种方法,尽管我会产生一个表示10毫秒采样音频(也许是CRC值)的数字(整数/浮点/双精度)或音频样本的MD5和等)或数字流(可能是频率的音频读数流)。最终,“样本”将是一个或多个数字。这部分将涉及更多的硬件,因此这里不作讨论。

3。该代码查看它存储的10个连续样本,并寻找增加的音量以指示正在说一个单词或短语(从沉默中休息),然后增加连续样本的收集量,例如说500个样本。这意味着它将在10毫秒的样本中捕获5秒的音频。

这些样本或“片段”在存储的声音和捕获的声音之间进行比较。如果捕获的样本中有足够高的百分比与存储的等效样本匹配,则代码将采用相同的词。

The start of a store recording of the world "hello" for example,
stored words are split into 10 msec samples also

Stored Sample No           | 1| 2| 3| 4| 5| 6| 7|  8|
Stored Sample Value        |27|38|41|16|59|77|200|78|

Incoming audio (me saying "hello") with some "blank" samples
at the start to symbolise silence

Incoming Sample No         | 1| 2| 3| 4| 5| 6| 7| 8| 9|10| 11|12|
Incoming Sample Value      |  |  |  |20|27|38|46|16|59|77|200|78|

4。一旦代码收集了完整的样本流,便会在开始时砍掉空白样本,以产生以下音频记录。它还可以将样本集前后移动一些位置,以更好地与存储的样本对齐。

这将产生如下所示的样本集:

Stored Sample No           | 1| 2| 3| 4| 5| 6|  7| 8|
Stored Sample Value        |27|38|41|16|59|77|200|78|

Incoming Sample No      |-1| 1| 2| 3| 4| 5| 6|  7| 8|
Incoming Sample Value   |20|27|38|46|16|59|81|201|78|

5。我相信,通过为每个样本必须达到的接近程度设定一个百分比值,因此样本7的差值为1(小于%1),而样本总数的百分比值必须在其样本匹配百分比之内,代码的准确度很容易调整。

我以前从未用音频做过类似的事情,这可能是很多工作。这就是为什么我问这个问题的原因,如果您也许已经知道这个问题的答案很明显(无论答案是什么)。我希望这不会是一个计算量大的任务,因为我将要使用的某些硬件将是低速的东西。在数百兆赫兹中(也许使用超频的Rasp Pi达到1Ghz)。因此,这是使用较低的计算能力来匹配音频样本的一种相当粗糙的方法。我的目标不是立竿见影,但不到30秒就能获得不错的概念证明。

PS 我没有代表用新标签标记此,例如“音频”,“音频识别”,“语音”,“语音识别”等。


17
虚拟现实非常复杂,我怀疑没有该领域知识的人是否会在没有大量阅读的情况下取得很大进展。关于您的算法,令我着迷的第一件事是它无法处理说出单词速度的差异。甚至简单的VR都需要花费数年的时间才能正确实现。

4
确实。除非您介意多年的开发,否则您可能希望研究可以编译为目标的库。我确定它们存在。
钻机

6
我建议采取另一步骤-对每个样本进行傅立叶变换。这样可以使您随时间推移每个音频的强度,而不必直接处理样本。通常您可以检测到的元音的基本频率会保持合理一致,您需要查看语音的特定特征,而不仅仅是音频。正如其他人所说,这是一项艰巨的任务。
Paul Anderson

1
我建议您尝试使用一些语音识别库,即使您不能将它们用于最终产品。它们对于创建概念证明很有用。
2013年

Answers:


3

好吧,我不相信Arduino有能力做到这一点。它以16Mhz的速度运行Arduino具有大约32K的内存。尽管只有自己的声音,但即使以Mp3(小于wav)采样的20个单词也无法放入其中。

rasberi pi可以解决这个问题,其运行速度为700Mhz,具体取决于它可能具有512MB内存的版本。那仍然不是很多。

您可能需要付里叶(http://www.drdobbs.com/cpp/a-simple-and-efficiency-fft-implementatio/199500857

或者,如果您打算使用体积,请对以前的样本进行一些平均,例如
x =(x + x [n-1] + x [n-2] + x [n-3])/ 4 //那很简单需要更多

接下来需要做的是我想是否要绘制这些X值,那么就需要对该直线进行某种斜率检测,因为基于体积的检测命令在很大程度上取决于距离,而您希望检测到的模式话

然后,这取决于如何记录斜率,以使图案适合其他时间。我的意思是说的不是计算机可以匹配的准确速度,而且坡度可能更陡一些。最后,我认为这些线的陡峭程度及其y轴的长度应该在一定的平均值内


1
  1. Arduino和Raspberry Pi正在制作带有少量芯片的原型板。您应该首先关注芯片。使用DSP(数字信号处理)工具箱查找某些东西,也许您已经有了DSP工具箱,却不知道。DSP工具箱具有待调用的算法,例如fft(快速傅立叶变换)和ifft(逆fft),用于快速频域分析。

  2. 关注您的程序风格:您的样本是在堆栈中还是在队列中?您将需要此类数据的队列。队列如下所示:

    Position NO --|1|2|3|4|5|6|7|8|
    Sample Value  |5|7|9|1|2|2|9|8|
    

    下一次迭代:

    Position NO --|1|2|3|4|5|6|7|8|
    Sample Value  |0|5|7|9|1|2|2|9|
    ->  First in First out (FIFO)
    

    注意到事情如何向“正确”方向转变?我认为您描述了一种“圆形”算法。只需用第二个最旧的样本覆盖最旧的样本,然后用第三个最旧的样本覆盖第二个最旧的样本,一直到插入最新数据的队列的开始。

  3. “代码连续获取固定长度的样本,例如10毫秒” <- 不正确地 思考:代码以每秒10000个样本的采样率离散地获取量化的(高度)样本,这使每个样本相距0.1毫秒。

    您的采样频率是多少?您的量化器的比特率是多少?较小的数字将帮助您释放内存。我建议使用较低的采样率,例如每秒6600个采样(奈奎斯特)。我怀疑4位(16个级别)足以识别。这样一来,每秒记录3300字节。现在执行fft并删除3300 Hz以上的所有内容(电话滤波器)。现在您有1650个字节用于一秒钟的声音。这些DSP技巧将节省大量内存。

    我不知道谁认为512 MB小。有了以上信息,记录了300,000+秒……超过3天的时间。

  4. 我认为您会发现频域(通过使用fft)是执行语音识别的更好环境。

我希望我不会让你更困惑:)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.