内容介绍
内容介绍
FUNPACK2_1
- 平台硬件介绍
- 如图所示为Syntiant TinyML Board的基本结构框图,本项目使用到RGBLED,SAMD21,NDP101,Micro-phone,收集音频执行相应命令。
- SAMD21
- 该 SAMD21 系列微控制器基于 ARM Cortex-M0+ 32 位处理器。其工作最高频率可达 48MHz,并且带有最高 256K 字节的可编程闪存。
- NDP101
- Syntiant ® NDP101 神经决策处理器™,可以使语音和传感器应用程序分别在 140 和 100 微瓦以下运行。其主要功能是加速处理神经网络的决策功能,连接了两个传感器:BMI160 6 轴运动传感器・SPH0641LM4H 麦克风。NDP101 支持多达 560k 个参数和 64 种输出分类
- 网络模型训练以及部署
- edge impuse平台
- 而 Edge impulse 是一个免费的模型训练平台,非常便捷的使用方法,致力于实现嵌入式系统的边缘计算开发,可以上传被训练的数据、打标、NN 模型训练、优化、部署。
- 收集数据
- 可以使用电脑麦克风、手机麦克风、TinyML板载麦克风收集数据;或者直接上传WAV音频文件。在收集数据使,可选择相对安静的环境进行多次采集,时音频数据集中在1s时间内。在收集完需要的指令数据后,还需采集一定的环境噪声进行训练。
- 采集熟虑的方式
- 本项目中共采集5种指令标签,每种标签各50条音频,另外有噪声和官方提供的环境音。
- edge impuse平台
- 处理数据
- 模型测试
- 创建和下载测试模型文件。
- 环境部署
- 需要安装Arduino-cil(1.81版本)高版本不可用,之后根据网站提示,烧录麦克风固件去录制声音。arduino-ide和官方的例程需要下载并根据提示使用。
- 小结
- 我认为edge impuse是一个非常方便的平台。在多人合作,大量样本支持的情况之下,可玩性非常的高,训练出来的模型非常的惊艳。但是我仅仅录制了5条双音节的指令,每条指令50个左右,而且录制时间很集中,没考虑到人声音的不用时间段的差异!后续希望能有一个多人合作的平台。
- 部分代码讲解
- NDP中断任务
- 利用外部中断,告知主控制器信息匹配完成。将定时器4重置,标志位置1。
-
int ints = 0; int old_int = 0; // INT pin interrupt from NDP. Simply flag form main() routine to process void ndpInt() { SCB->SCR &= !SCB_SCR_SLEEPDEEP_Msk; // Don't Allow Deep Sleep doInt = 1; ledTimerCount = 1 * (1000000 / timer_in_uS); // flash LED for 1 second if (!doingMgmtCmd) { timer4.enableInterrupt(true); } ints++; // Serial.print(ints); }
- 定时器4中断任务
- Timer 4 interrupt. Handles ALL touches of NDP. Also services USB Audio,当进入timer中断后,会获取匹配信息,并打印出相应的标签。
-
// Timer 4 interrupt. Handles ALL touches of NDP. Also services USB Audio void isrTimer4(struct tc_module *const module_inst) { digitalWrite(0, LOW); int s; unsigned int len; SCB->SCR &= !SCB_SCR_SLEEPDEEP_Msk; // Don't Allow Deep Sleep if ((ledTimerCount < 0xffff) && (ledTimerCount > 0)) { ledTimerCount--; if (ledTimerCount == 0) { timer4TimedOut = 1; } } #ifdef WITH_AUDIO if (runningFromFlash) { uint32_t tankRead; int i; for (i = 0; i < 32; i += 4) { tankRead = indirectRead(tankAddress + ((currentPointer - 32 + i) % tankSize)); audioBuf[i / 2] = tankRead & 0xffff; audioBuf[(i / 2) + 1] = (tankRead >> 16) & 0xffff; } currentPointer += 32; currentPointer %= tankSize; } AudioUSB.write(audioBuf, 32); // write samples to AudioUSB #else if (runningFromFlash) { currentPointer = indirectRead(startingFWAddress); int32_t diffPointer = ((int32_t)currentPointer - prevPointer); if (diffPointer < 0) { diffPointer = (64000 - prevPointer) + currentPointer; } if (diffPointer >= dataLengthToBeSaved) { len = sizeof(dataBuf); int ret = NDP.extractData((uint8_t *)dataBuf, &len); if (ret != SYNTIANT_NDP_ERROR_NONE) { ei_printf("Extracting data failed with error : %d\r\n", ret); } else { if (imu_active == false) { imu_active = true; for (int i = 0; i < (dataLengthToBeSaved / 2); i++) { imu[i] = dataBuf[i]; } imu_active = false; } } prevPointer = currentPointer; } } #endif if (doInt) { doInt = 0; // Poll NDP for cause of interrupt (if running from flash) if (runningFromFlash) { match = NDP.poll(); //从ndp101获取匹配到的数据 if (match) { // Light Arduino LED // digitalWrite(LED_BUILTIN, HIGH); ei_classification_output(match - 1); //打印出匹配到的标签。 printBattery(); // Print current battery level } } else { match = 1; } } digitalWrite(0, HIGH); }
- 匹配成功
- 调用ei_classification_output(match - 1);函数,打印出匹配到的信息。
-
void ei_classification_output(int matched_feature) { if (ei_run_impulse_active()) { ei_printf("\nPredictions:\r\n"); for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) { ei_printf(" %s: \t%d\r\n", ei_classifier_inferencing_categories[ix], (matched_feature == ix) ? 1 : 0); } on_classification_changed(ei_classifier_inferencing_categories[matched_feature], 0, 0); } }
- 处理任务字节
-
打印出匹配信息后调用on_classification_changed(ei_classifier_inferencing_categories[matched_feature], 0, 0);函数。此函数是用户可自定义的标签。这里我使用的是抛出标志位。
void on_classification_changed(const char *event, float confidence, float anomaly_score) { // here you can write application code, e.g. to toggle LEDs based on keywords if (strcmp(event, "blink") == 0) { Flag.sta = 2; } if (strcmp(event, "open") == 0) { Flag.sta = 1; } if (strcmp(event, "close") == 0) { Flag.sta = 0; Serial.print(Flag.sta); } if (strcmp(event, "red") == 0) { Flag.red = 1; } if (strcmp(event, "green") == 0) { Flag.green = 1; } }
- 在得到标志位之后,会在loop中循环检测标志位,循环执行任务。
static uint16_t count, co_steep; if (Flag.sta != 2) { if (Flag.red == 1) { switch (Flag.sta) { case 0: digitalWrite(LED_RED, LOW); Flag.red = 0; Flag.sta = 4; break; case 1: digitalWrite(LED_RED, HIGH); Flag.red = 0; Flag.sta = 4; break; case 2: digitalWrite(LED_RED, HIGH); break; default: break; } } if (Flag.green == 1) { switch (Flag.sta) { case 0: digitalWrite(LED_GREEN, LOW); Flag.green = 0; Flag.sta = 4; break; case 1: digitalWrite(LED_GREEN, HIGH); Flag.green = 0; Flag.sta = 4; break; default: break; } } digitalWrite(LED_BLUE, LOW); } else { // count++; if (count == 1000) { static uint8_t co, flag = 1; Flag.red = 0; Flag.green = 0; if (flag == 1) { co++; if (co == 255) { flag = 0; } } else { co--; if (co == 1) { flag = 1; } } analogWrite(LED_RED, co); analogWrite(LED_GREEN, 255 - co); analogWrite(LED_BLUE, co); co_steep = 50; count = 0; } } if ((Flag.green == 0) && (Flag.red == 0) && (Flag.sta == 0)) { digitalWrite(LED_RED, LOW); analogWrite(LED_BLUE, 0); digitalWrite(LED_GREEN, LOW); } if ((Flag.green == 0) && (Flag.red == 0) && (Flag.sta == 1)) { digitalWrite(LED_RED, HIGH); digitalWrite(LED_GREEN, HIGH); } if (count == 1000) { int a = Flag.red; int b = Flag.sta; int c = Flag.green; char str[50]; sprintf(str, "GREEN:%d,RED:%d,FLAG:%d\r\n", c, a, b); Serial.print(str); co_steep = 1; count = 0; } count += co_steep;
-
- NDP中断任务
- 功能展示
- 指令:红灯+打开:红灯亮;红灯+关闭:红灯灭;闪烁:灯光变换;打开:所有灯光打开;关闭:所有灯光关闭。
- ps:打开指令虽然模型识别度准确度98以上,但是语音识别不灵敏,需要用到训练模型时的声音。
- 心得体会
- 这是我第一次接触到机器学习,训练模型。在此之前,仅仅使用过opencv的人脸调捡器,和一些简单的基础滤波。但是在此项目中的声音采集有很大的难度,第一次采集,没有考虑到周边噪声导致训练的模型准确率不高,而且在不说话的情况加会一直匹配到声音。在群友的提示下,我找到安静的环境下去录制声音,并且加上一个噪声的标签来录制环境音。关于对数据的处理edge impuse给出了很好的数据筛选和滤波器,让训练的模型的准确度更加的高。我还有一些不明白的事情,关于我的设备在不同的时间段对声音识别的准确度不一致,例如,"open"我在早上刚训练完测试的时候,是很准确的,但是晚上录制视频的时候就不行了。我认为可能的原因有三种:1.环境温度的改变。2.人声音因为过度使用嗓子,造成音色有偏差。3.板载麦克风采集声音的角度不同。总而言之,在训练出来的模型是可以使用的,在调整各种训练参数后,每一次都会有所提高。这款模块有很好的前景,可以个人很方便的部署离线语音识别,对比之前使用的语音识别块只能找厂家定制声音,我认为DIY一些家庭小设备上非常的好用。
附件下载
funpack2_1_syntiant-syntiant-ndp101-v70.zip
模型验证固件
firmware-syntiant-tinyml.zip
arduino程序
团队介绍
个人
团队成员
sll
评论
0 / 100
查看更多
猜你喜欢
Funpack第二季第一期任务一语音识别控制LED灯使用syntiant tiny ml 实现语音控制LED灯,了解深度学习相关知识和arduino的使用。
wjhgbpqm
919
Funpack第二季第一期--基于syntaint的简单语音识别用自带的麦克风,搭建机器学习模型,使板卡上的LED灯根据中文语音指令(不少于三个指令)呈现出不同效果,如开灯、关灯、闪烁、SOS、呼吸等。本项目实现的是“开灯”,“关灯”,“闪烁”。
好喝的娃哈哈
869
Funpack第二季第一期 Syntiant TinyML 语音识别亮灯任务一Funpack第二季第一期 Syntiant TinyML 语音识别亮灯任务一
Lenor
987