4.语音板使用snowboy唤醒引擎
0x00 snowboy唤醒引擎简介
snowboy 是一个开源的、轻量级语音唤醒引擎,通过它可以很轻松地创建属于自己的唤醒词。唤醒,是人机语音交互的起点。因为在将机器人唤醒前,人说话的声音是不进行处理的,只有在唤醒后,机器人才会将收听到的语音进行解析、处理、反馈。这里的唤醒动作,可以理解为机器人的名字。就跟现在市面上的“小爱同学”、“天猫精灵”一样,不过这些唤醒词都是经过商业化定制的,一般用户可没那么多钱进行定制商业化的唤醒词。这里的snowboy就提供了一种便捷的途径来帮我们做这件事,省去高昂的商业化唤醒词定制费,snowboy具备以下特点:
(1)高度可定制性:可自由、快速的训练属于自己的唤醒词
(2)始终倾听:无需联网,离线使用,保护隐私。精确度高,低延迟
(3)轻量可嵌入:硬件耗费资源非常低(树莓派CPU占用低于5%,内存消耗小)
(4)开源跨平台:开放源代码,支持多种操作系统和硬件平台,可多编程语言开发
0x01 下载snowboy代码
我们这款语音板现在就可以使用snowboy这个唤醒引擎,首先来下载snowboy的源码,然后我们就可以在本地进行测试了,下载snowboy的github仓库命令如下:
git clone https://github.com/Kitt-AI/snowboy.git
下载好代码后,就可以来安装下运行需要的软件了。后面我会把这些缺少的软件都提前安装好在下一版的ROS镜像中,把语音开发环境都配置好,这样后面的同学再使用语音板的时候,就不用这么麻烦来安装这些软件包了,直接就能用snowboy唤醒。这里的安装命令如下:
sudo apt-get install python-pyaudio python3-pyaudio swig
接下来就是安装python版本的PortAudio,安装命令如下:
pip install pyaudio
上述操作过程可以参考如下的截图:
在安装好这些软件后,接下来就可以来验证下是否可以正常录音了,只要语音板麦克风可以正常工作,可以录音了,我们才可以进行后面的操作。完整的测试录音命令如下:
rec test.wav
当在终端中输入完该命令后,就会自动开启录音,我们就可以对着麦克风说几句话。最终会保存到test.wav文件中,最后我们播放出来test.wav看看该文件是否正常,如果正常的话,那我们语音板就是进入正常工作状态了。要想播放一下wav文件,命令也很简单:
play test.wav
具体的测试过程,可以参考该视频:
0x02 编译唤醒引擎动态库
在这里我们在使用唤醒引擎前,需要编译对应编程语言版本所使用的动态库。由于snowboy的唤醒引擎可以在多种语言环境中使用,我们这里选择python版本,也就是python2.7的版本。当然也可以编译python3的版本,这里编译对应语言版本动态库用到的工具就是swig,这个swig是由Simple Wrapper and Interface Generator的首字母组成,根据这个英文也大概了解swig是干嘛的了。简单来说,swig就是为了将我们使用C/C++编写的代码封装起来,然后可以给其他语言使用的一个工具。这里的snowboy唤醒引擎是使用C/C++开发的,所以python要想使用就需要做下转换了。
这里编译python版本的引擎库也很简单,整个操作过程如下图所示:
当然,如果你想使用Python3版本的引擎库,这里就可以也可以编译,基本上编译过程是一样的,无非就是更换到Python3目录下执行编译命令。如下图所示:
0x03 测试唤醒python版本
当我们编译好python版本的唤醒引擎库以后,我们就可以来测试唤醒了,这次我们要切换到example目录下。我们可以直接使用下面的命令就可以来测试snowboy的唤醒了:
python demo.py ./resources/models/snowboy.umdl
当启动后,我们就可以对着语音板喊“snowboy”了,这个喊还是稍微有点技巧的,避免中文式英语发音就行了。实在不行,你就看视频我是怎么喊的,具体的测试视频如下:
这里需要注意,如果你打算使用Python3目录中的代码测试唤醒,启动命令要做一下修改,这里要是使用python3了:
python3 demo.py ./resources/models/snowboy.umdl
不过这里在执行的时候会提示一个小错误,我们需要修改一下才能继续运行,错误信息如下:
Traceback (most recent call last):
File "demo.py", line 1, in
import snowboydecoder
File "/home/corvin/snowboy/examples/Python3/snowboydecoder.py", line 5, in
from . import snowboydetect
ImportError: attempted relative import with no known parent package
这里的修改也很简单,我们就是要把snowboy/examples/Python3/snowboydecoder.py中第5行中的from . import snowboydetect修改为import snowboydetect就可以了。
0x04 自定义唤醒词
通过前面的视频我们可以得知,默认的唤醒词是“snowboy”,很多人可能发音也不标准导致体验不太好。那snowboy其实还提供一个可以自定义唤醒词的功能,这样我们就能很容易的来DIY自己专属的唤醒了。
这里制作自定义的唤醒词我们只需录制3个唤醒词的wav语音文件,然后将其通过post方式上传到snowboy的官网上训练即可,然后就可以立刻得到一个自己专属的唤醒引擎了。那接下来给大家介绍具体该如何操作,我们首先来录制3个包含有唤醒词的wav文件,完整的录制命令如下:
rec -r 16000 -c 1 -b 16 -e signed-integer 1.wav
在最后的1.wav就是最终生成的wav语音文件,我们可以将该命令依次运行三遍,这样我们就可以得到1.wav,2.wav,3.wav三个包含唤醒词的语音文件了。这里需要注意在录制wav文件的时候,这里录音过程不会自动结束,当我们说完唤醒词后,我们需要手动Ctrl+C来结束录制过程。
当录制好三个唤醒词语音文件后,我们就来看看上传到snowboy服务器的python代码,具体代码如下:
import sys
import base64
import requests
def get_wave(fname):
with open(fname) as infile:
return base64.b64encode(infile.read())
endpoint = "https://snowboy.kitt.ai/api/v1/train/"
############# MODIFY THE FOLLOWING #############
token = ""
hotword_name = "???"
language = "en"
age_group = "20_29"
gender = "M"
microphone = "macbook microphone"
############### END OF MODIFY ##################
if __name__ == "__main__":
try:
[_, wav1, wav2, wav3, out] = sys.argv
except ValueError:
print "Usage: %s wave_file1 wave_file2 wave_file3 out_model_name" % sys.argv[0]
sys.exit()
data = {
"name": hotword_name,
"language": language,
"age_group": age_group,
"gender": gender,
"microphone": microphone,
"token": token,
"voice_samples": [
{"wave": get_wave(wav1)},
{"wave": get_wave(wav2)},
{"wave": get_wave(wav3)}
]
}
response = requests.post(endpoint, json=data)
if response.ok:
with open(out, "w") as outfile:
outfile.write(response.content)
print "Saved model to '%s'." % out
else:
print "Request failed."
print response.text
这里代码的14-21行是需要我们修改的地方,我们需要修改的第一个参数就是token令牌,就是我们在snowboy官网注册的账户下的token。具体如下图所示:
第二个参数hotword_name="科文"就可以了,根据我们自己设置的唤醒词来。这里不在每个字段介绍了,其实这里各字段的意义官网上有介绍,我这里直接贴图给大家参考:
所以根据我个人的信息来设置的话,最终上述完整的代码如下,当然大家需要根据自己的个人信息来做相应修改。例如你要是女生的话,肯定gender要选择F了。
# -*- coding:utf-8 -*-
import sys
import base64
import requests
def get_wave(fname):
with open(fname) as infile:
return base64.b64encode(infile.read())
endpoint = "https://snowboy.kitt.ai/api/v1/train/"
############# MODIFY THE FOLLOWING #############
token = "41008e4bbb90d511506c73b7b0f1be311afff2a6"
hotword_name = "科文"
language = "zh"
age_group = "30_39"
gender = "M"
microphone = "rpi 2-MIC AI Board"
############### END OF MODIFY ##################
if __name__ == "__main__":
try:
[_, wav1, wav2, wav3, out] = sys.argv
except ValueError:
print "Usage: %s wave_file1 wave_file2 wave_file3 out_model_name" % sys.argv[0]
sys.exit()
data = {
"name": hotword_name,
"language": language,
"age_group": age_group,
"gender": gender,
"microphone": microphone,
"token": token,
"voice_samples": [
{"wave": get_wave(wav1)},
{"wave": get_wave(wav2)},
{"wave": get_wave(wav3)}
]
}
response = requests.post(endpoint, json=data)
if response.ok:
with open(out, "w") as outfile:
outfile.write(response.content)
print "Saved model to '%s'." % out
else:
print "Request failed."
print response.text
那接下来就可以执行该python代码来申请自定义的唤醒引擎了,我们将该源码文件命名为training.py,最后一个参数就是我们要生成的唤醒引擎文件,这里的文件是以pmdl文件结尾的,所以完整的命令如下:
python training.py 1.wav 2.wav 3.wav corvin.pmdl
当生成了该文件,我们就可以将得到的corvin.pmdl文件复制到我们snowboy下的resources/models目录中,这样我们就有自定义的唤醒引擎文件了。剩下的就是启动demo.py,然后加载我们自己生成的唤醒引擎文件来进行唤醒了。
那我们自定义的唤醒引擎的效果怎么样的?这里可以通过观看视频来感受:
完整看完上述视频的同学可能会发现,在刚开始的时候我喊“科文”唤醒基本上是正常的。但是当我喊相近的唤醒词,例如“科科”发现偶尔也是可以唤醒的。这就是因为我们唤醒引擎中设置的太敏感了,这样虽然能增加唤醒率,但是同时也会增加一定的误唤醒率。后面我将sensitivity从0.5改为0.4,发现再测试“科科”的时候,误唤醒就少多了,基本上没发现误唤醒了。当然这样可能也会影响一定程度上的正常唤醒,所以调整这个sensitivity值是个很难拿捏准的,不是说设置成0.4就对于所有唤醒词都是正确的。这个值一定要根据不同的唤醒和不同的唤醒词来做不同的调整,这样才能有最佳的唤醒效果。
detector = snowboydecoder.HotwordDetector(models, sensitivity=0.4)
0x05 参考资料
[1].树莓派使用snowboy配置语音唤醒. https://www.jianshu.com/p/a1c06020f5fd
[2].Snowboy官网. https://snowboy.kitt.ai/
[3].Snowboy github网址. https://github.com/Kitt-AI/snowboy
[4].Snowboy在线文档网址. http://docs.kitt.ai/snowboy/
[5].swig官网. http://www.swig.org/
0x06 问题反馈
大家在按照教程操作过程中有任何问题,可以直接在文章末尾给我留言,或者关注ROS小课堂的官方微信公众号,在公众号中给我发消息反馈问题也行。我基本上每天都会处理公众号中的留言!当然如果你要是顺便给ROS小课堂打个赏,我也会感激不尽的,打赏30块还会被邀请进ROS小课堂的微信群,与更多志同道合的小伙伴一起学习和交流!
[wshop_reward]