随着深度学习的不断发展,生活中各种随处可见的问题都可以利用很多网络来解决。一个训练好的神经网络作为一个黑箱,直接输入原始数据就能够得到对应的结果,在很多直接通过传统算法不好解决的问题中,利用网络却往往较为简单。但是大部分网络都是在x86的平台上进行训练和部署,且其资源占用也比较大,较难以直接搬到资源紧张的嵌入式平台上。这其中就包括关键词识别问题,该问题如果利用传统算法实现起来较为困难,但是通过神经网络却能够很好的解决。
TencentOS Tiny AIoT开发套件:
由于板载咪头出厂时存在问题,自己修改并换过多个咪头后仍旧无法获取音频信号,故通过MAX9814模块+ADC直接采集音频信号:
通过语音信号对关键词进行识别的主要原理是通过获取音频信号的梅尔频率倒谱系数(Mel-Frequency Cepstral Coefficients, MFCC),并利用神经网络将MFCC特征视为图像进行分类即可。如下图所示即为某一音频的MFCC特征图:
在本项目中,所使用的音频数据以及采集的信号格式均为16bit,16kHz,单通道。MFCC特征的窗口大小为31.25ms,在本项目中的音频数据格式下,对应的数据长度为512点。对应的窗口重叠区域为50%,即16.125ms。
本项目所选用的网络为Keyword Spotting Through Image Recognition,其主要由Conv2D组成,对应的网络框架如下所示:
而板子上实际的网络模型是通过上述修改后的,减去了一层CNN,其结构如下:
本项目在MCU端的主要功能主要由以下三个命令实现:
其中:
而主要的推理线程kws的流程图如下所示:
而PC端主要通过TensorFlow来搭建和训练模型,其中数据集主要采用的Google speech command dataset。其中主要包括以下的语音数据:
'backward', 'bed', 'bird', 'cat', 'dog', 'down', 'eight', 'five', 'follow', 'forward',
'four','go','happy','house','learn','left','marvin','nine','no','off','on','one','right',
'seven','sheila','six','stop','three','tree','two','up','visual','yes','zero'
针对上述kws线程的核心代码如下所示:
mfcc = mfcc_create(MFCC_COEFFS_LEN, MFCC_COEFFS_FIRST, MFCC_TOTAL_NUM_BANK, AUDIO_FRAME_LEN, 0.97f, true);
while(1)
{
if(use_file_flag == 0)
{
tos_event_pend(&audio_evt, 1|2|4, &evt, TOS_TIME_FOREVER, TOS_OPT_EVENT_PEND_ANY | TOS_OPT_EVENT_PEND_CLR);
if(evt & 4)
break;
if(evt & 1)
p_raw_audio = dma_audio_buffer;
else if(evt & 2)
p_raw_audio = &dma_audio_buffer[AUDIO_FRAME_LEN];
}else
{
res = f_read(fp, dma_audio_buffer, AUDIO_FRAME_LEN*sizeof(int16_t), &br);
if (res != FR_OK)
{
PRINTF("Failure:%s\r\n", RESAULT_TO_STR(res));
f_close(fp);
return ;
}
if (br == 0)
break;
p_raw_audio = dma_audio_buffer;
}
// memory move
// audio buffer = | 256 byte old data | 256 byte new data 1 | 256 byte new data 2 |
// ^------------------------------------------|
memcpy(audio_buffer_16bit, &audio_buffer_16bit[AUDIO_FRAME_LEN], (AUDIO_FRAME_LEN/2)*sizeof(int16_t));
// convert it to 16 bit.
// volume*4
for(int i = 0; i < AUDIO_FRAME_LEN; i++)
{
audio_buffer_16bit[AUDIO_FRAME_LEN/2+i] = p_raw_audio[i];
}
for(int i=0; i<2; i++)
{
mfcc_compute(mfcc, &audio_buffer_16bit[i*AUDIO_FRAME_LEN/2], mfcc_features_f);
quantize_data(mfcc_features_f, mfcc_features[mfcc_feat_index], MFCC_COEFFS, 3);
mfcc_feat_index++;
if(mfcc_feat_index >= MFCC_LEN)
mfcc_feat_index = 0;
}
uint32_t len_first = MFCC_FEAT_SIZE - mfcc_feat_index * MFCC_COEFFS;
uint32_t len_second = mfcc_feat_index * MFCC_COEFFS;
memcpy(&mfcc_features_seq[0][0], &mfcc_features[0][0] + len_second, len_first);
memcpy(&mfcc_features_seq[0][0] + len_first, &mfcc_features[0][0], len_second);
memcpy(nnom_input_data, mfcc_features_seq, MFCC_FEAT_SIZE);
nnom_predict(model, &label, &prob);
// output
if(prob > 0.5f)
{
PRINTF("time : %d ms \t",tos_tick2millisec(tos_systick_get()) - last_time);
PRINTF("%s : %d%%\r\n", (char*)&label_name[label], (int)(prob * 100));
}
last_time = tos_tick2millisec(tos_systick_get());
}
if(use_file_flag)
f_close(fp);
mfcc_delete(mfcc);
可以看到其基本逻辑为:
1. 创建mfcc对象用于生成mfcc特征图
2. 等待从文件或者麦克风过来的数据。如果是文件则直接调用fatfs的api,如果是麦克风则通过事件集等待
3. 利用mfcc对象将音频数据生成mfcc特征图
4. 将特征图送入模型输入
5. 打印输出模型结果
6. 没有音频信号后,删除mfcc对象,释放必要空间,kws线程结束
针对上述部分的命令行截图如下:
1. 在程序启动时会自动编译模型,使得之后的推理无需再次编译,缩短推理时间
2. kws命令用于读取板子上插入的sd卡中的文件,输出其wav的基本格式信息,并送入模型进行推理
3. rt_kws命令为通过内部ADC实时采集麦克风信号,并送入网络中进行推理
4. record命令主要用于采集板子上麦克风的音频信号,用于训练网络使用。同时也可以配合kws命令一起使用
视频
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。