
1. 案例簡介
隨著機器學習的發展,TinyML(微型機器學習)已在你的家里、車里、甚至口袋里作業了,什么是TinyML呢?它是屬于機器學習的一個子領域,包含了演算法、硬體和軟體,能夠基于傳感器資料分析,并在極地功耗的設備上運行,比如家里的天貓精靈、蘋果的Siri和亞馬遜的Alexa等語音助手是TinyML的一個完美應用,它們提供了語音用戶介面(AUI),讓用戶不需要操作螢屏、滑鼠或鍵盤就可以進行互動,給用戶提供了一種全新的互動方式,這些語音助手幾乎無處不在,從獨立的智能音箱到幾乎所有手機都內置了某種語音助手,
在大部分情況下,語音識別、自然語言處理以及語音合成等飯中作業都是在云端完成的,由性能強大的服務器運行大型機器學習模型,當用戶提出問題時,將以wav或其他音頻流的形式被發送到云端,云端識別出音頻流的含義并進行回復回應,語音助手真正需要的音頻是喚醒設備后的資料,如果能在不發送資料的情況下檢測到這個喚醒詞,并在聽到喚醒詞之后才開始音頻流的傳輸,這樣既能夠保護用戶的隱私、節省電池電量和帶寬,而且可以在沒有網路的情況下喚醒,
這也是TinyML的用武之地,要在低功耗的芯片上運行,意味著要訓練一個監聽喚醒詞的微型模型,嵌入到微控制設備中,它就可以一直監聽喚醒詞,當檢測到喚醒詞后通知作業系統開始捕獲音頻并發送到云端,
在本章中,將教大家如何使用預先訓練的檢測模型,在HaaS EDU K1上進行喚醒詞檢測模型的部署,并使用Tensorflow Lite Micro推理引擎進行推理,隨后將教大家如何使用Tensorflow訓練腳本訓練一個自己的喚醒詞,再進行設備端部署,本案例主要有三個部分組成:
- 語音采集:接入模擬麥克風(Mic1輸入);
- 語音識別:說出“打開”和“關閉”識別后,OLED將顯示“Turn on...”和“Turn off”;
- 語音播報:執行指令的同時,播報本地TTS(mp3),
開始學習之前我們先看一下案例效果:
HaaS語音助手 語音控制
1.1 涉及知識點
- 喚醒詞資料采集、模型訓練、模型部署
- 設備端模擬MIC聲音采樣
- 設備端音頻特征提取
- TFLite-Micro推理引擎應用
- 設備端命令識別、回應
- 設備端喇叭播放mp3檔案
- 檔案系統應用
- OLED顯示字符
2. 方案介紹
整個方案的框架如下:

- 提供批量音頻錄制工具進行資料收集;
- 提供TF模型訓練腳本進行喚醒詞訓練;
- 提供完整設備端模型部署方案;
基于該方案,你將學習到TinyML的整個生命周期:

3. 開發環境搭建
3.1 硬體準備
如果有HaaS語音擴展板,直接插入即可:

如果沒有HaaS語音擴展板,請按照如下步驟接入麥克風和喇叭:

HaaS EDU K1硬體排線圖請參考
HaaS EDU K1說明書 - IoT物聯網作業系統 - 阿里云
購買鏈接僅供參考!!我們不負責商家發貨的品質保障等問題!!
| 名稱 | 數量 | 參考鏈接 |
| HaaS EDU K1開發版 | 1 | HaaS EDU K1購買鏈接 |
| microUSB資料線 | 1 | 普通microusb線即可 |
| 模擬MIC | 1 | 模擬MIC參考鏈接 |
| 喇叭 | 1 | 喇叭參考鏈接 |
| 杜邦線 | 數條 | NA |
3.2 環境搭建
參考《HaaS EDU K1快速開始》中HaaS Studio章節完成AliOS Things開發環境搭建,
3.2.1 案例代碼下載
該案例相關的源代碼下載可參考《創建工程》,該案例是C/C++案例,
其中:
- 選擇解決方案: “TFLite-Micro離線語音快捷詞喚醒案例”或者“tflite_micro_speech_demo”
- 選擇開發板: HaaS EDU K1

3.2.2 代碼編譯、燒錄
參考《HaaS EDU K1快速開始》完成代碼的編譯及燒錄,在燒錄前,請先完成3.2.1的步驟,再進行編譯燒錄,
3.2.2.1 檔案件系統燒錄
本組件例子中使用到到的本地語料存放在代碼中hardware/chip/haas1000/prebuild/data/目錄下mp3目錄,除燒錄tflite_micro_speech_demo image外,需燒錄littlefs檔案系統,請將hardware/chip/haas1000/package.yaml檔案中以下代碼段的注釋打開后重新編譯:
program_data_files:
- filename: release/write_flash_tool/ota_bin/littlefs.bin
address: 0xB32000
3.2.3 打開串口
參考《HaaS EDU K1快速開始》打開串口進行LOG查看,
4. 軟體架構

- KWS Demo應用程式: 主要打通實作AI語音引擎的初始化,歡迎語播報,
- ai_agent組件:是AliOS Things上的AI引擎核心模塊,后端接入不同的推理引擎,本案例中使用了TFLite-Micro推理引擎,
- uVoice組件:是AliOS Things上智能語音解決方案的核心組件,提供了本地音頻,URL音頻,TTS合成等基礎功能,音頻格式支持mp3, m4a, wav, opus等主流格式,本案例中使用它來進行本地mp3語料的回應播報,
- A2SA組件:是AliOS Things上音頻服務框架,兼容ALSA應用介面訪問,支持音頻硬體驅動抽象,多音頻驅動加載/卸載,VFS介面支持等功能,
4.1 代碼結構
├── cp_resources.py # 拷貝本地語料到/prebuild/data目錄,編譯進檔案系統
├── main.c
├── maintask.c
├── Makefile
├── micro_speech # 語音識別程式
├── oled # OLED顯示程式
│ ├── oled.c
│ └── oled.h
├── package.yaml # 編譯系統組態檔
├── player # 播放器程式
│ ├── player.c
│ └── player.h
├── README.md
├── recorder # 錄音程式
│ ├── recorder.c
│ └── recorder.h
├── resources
│ └── mp3 # 本地mp3語料
├── SConstruct
4.2 設備端作業流程
在HaaS EDU K1上的整個作業流程如下圖:

4.3 程式主體
以下代碼是執行喚醒詞識別主體,setup對TFLite-Micro模型推理引擎進行初始化,loop中執行上圖中整個流程,從音頻采集到命令回應的全部流程在該函式中實作,詳細邏輯請參考代碼,
// The name of this function is important for Arduino compatibility.
void setup()
{
// tflite::InitializeTarget();
//RegisterDebugLogCallback(callback);
// Set up logging. Google style is to avoid globals or statics because of
// lifetime uncertainty, but since this has a trivial destructor it's okay.
// NOLINTNEXTLINE(runtime-global-variables)
static tflite::MicroErrorReporter micro_error_reporter;
error_reporter = µ_error_reporter;
// Map the model into a usable data structure. This doesn't involve any
// copying or parsing, it's a very lightweight operation.
model = tflite::GetModel(g_model);
if (model->version() != TFLITE_SCHEMA_VERSION)
{
TF_LITE_REPORT_ERROR(error_reporter,
"Model provided is schema version %d not equal "
"to supported version %d.",
model->version(), TFLITE_SCHEMA_VERSION);
return;
}
// Pull in only the operation implementations we need.
// This relies on a complete list of all the ops needed by this graph.
// An easier approach is to just use the AllOpsResolver, but this will
// incur some penalty in code space for op implementations that are not
// needed by this graph.
//
// tflite::AllOpsResolver resolver;
// NOLINTNEXTLINE(runtime-global-variables)
static tflite::MicroMutableOpResolver<4> micro_op_resolver(error_reporter);
if (micro_op_resolver.AddDepthwiseConv2D() != kTfLiteOk)
{
return;
}
if (micro_op_resolver.AddFullyConnected() != kTfLiteOk)
{
return;
}
if (micro_op_resolver.AddSoftmax() != kTfLiteOk)
{
return;
}
if (micro_op_resolver.AddReshape() != kTfLiteOk)
{
return;
}
// Build an interpreter to run the model with.
static tflite::MicroInterpreter static_interpreter(
model, micro_op_resolver, tensor_arena, kTensorArenaSize, error_reporter);
interpreter = &static_interpreter;
// Allocate memory from the tensor_arena for the model's tensors.
TfLiteStatus allocate_status = interpreter->AllocateTensors();
if (allocate_status != kTfLiteOk)
{
TF_LITE_REPORT_ERROR(error_reporter, "AllocateTensors() failed");
return;
}
// Get information about the memory area to use for the model's input.
model_input = interpreter->input(0);
if ((model_input->dims->size != 2) || (model_input->dims->data[0] != 1) ||
(model_input->dims->data[1] !=
(kFeatureSliceCount * kFeatureSliceSize)) ||
(model_input->type != kTfLiteInt8))
{
TF_LITE_REPORT_ERROR(error_reporter,
"Bad input tensor parameters in model");
return;
}
model_input_buffer = model_input->data.int8;
// Prepare to access the audio spectrograms from a microphone or other source
// that will provide the inputs to the neural network.
// NOLINTNEXTLINE(runtime-global-variables)
static FeatureProvider static_feature_provider(kFeatureElementCount,
feature_buffer);
feature_provider = &static_feature_provider;
static RecognizeCommands static_recognizer(error_reporter);
recognizer = &static_recognizer;
previous_time = 0;
RespondCommandThreadInit();
}
// The name of this function is important for Arduino compatibility.
void loop()
{
// Fetch the spectrogram for the current time.
const int32_t current_time = LatestAudioTimestamp();
int how_many_new_slices = 0;
TfLiteStatus feature_status = feature_provider->PopulateFeatureData(
error_reporter, previous_time, current_time, &how_many_new_slices);
// LOG("current_time: %d, previous_time: %d, how_many_new_slices: %d\n", current_time, previous_time, how_many_new_slices);
if (feature_status != kTfLiteOk)
{
TF_LITE_REPORT_ERROR(error_reporter, "Feature generation failed");
return;
}
previous_time = current_time;
// If no new audio samples have been received since last time, don't bother
// running the network model.
if (how_many_new_slices == 0)
{
//LOG("[lk added]how_many_new_slices is 0\n");
return;
}
// Copy feature buffer to input tensor
for (int i = 0; i < kFeatureElementCount; i++)
{
model_input_buffer[i] = feature_buffer[i];
}
// Run the model on the spectrogram input and make sure it succeeds.
TfLiteStatus invoke_status = interpreter->Invoke();
if (invoke_status != kTfLiteOk)
{
TF_LITE_REPORT_ERROR(error_reporter, "Invoke failed");
return;
}
// Obtain a pointer to the output tensor
TfLiteTensor *output = interpreter->output(0);
// Determine whether a command was recognized based on the output of inference
const char *found_command = nullptr;
uint8_t score = 0;
bool is_new_command = false;
TfLiteStatus process_status = recognizer->ProcessLatestResults(
output, current_time, &found_command, &score, &is_new_command);
if (process_status != kTfLiteOk)
{
TF_LITE_REPORT_ERROR(error_reporter,
"RecognizeCommands::ProcessLatestResults() failed");
return;
}
// Do something based on the recognized command. The default implementation
// just prints to the error console, but you should replace this with your
// own function for a real application.
RespondToCommand(error_reporter, current_time, found_command, score,
is_new_command);
}
5. 案例體驗
當程式燒錄完成后,直接喊出“打開",“關閉”,就可以看到視頻所示的效果,目前只支持近場喚醒,喚醒距離1米左右,由于這個“打開”,“關閉”喚醒的語料有限,喚醒因不同人有差異,建議按照章節6中自己訓練一個喚醒詞或者使用資料集中的英文語料“on/off”試試,
6. 自訓練喚醒詞
本案例是自訓練了一個“打開”,“關閉”快捷喚醒詞,本小節將帶你訓練一個新的快捷喚醒詞,
從錄音采集到部署到HaaS EDU K1的整個詳細流程如下:

6.1 語料采集
語料采集是一個比較耗費人力的事情,通常商業化工程中語料收集有專人或專門的資料公司收集整理,這里提供了一個使用Python寫一個錄音工具,方便你快速錄音,
依賴項安裝
#pip install pyaudio
或者
#conda install pyaudio
錄音配置
- 語音檔案長度一秒
- 單聲道、16KHz、wav格式
- 快、中、慢三種不同速度進行錄制
- 錄制次數100次以上,次數越多效果越好
- 相對安靜環境
6.1.1 喚醒詞錄制
錄制時看到“開始錄音,請說話......”即可立即說出喚醒詞,比如“打開”、“關閉”,由于我們檢測一秒的喚醒詞,所以在注意要在一秒內說完整整個喚醒詞,錄制一次后會自動回放確認是否錄制完整,如果錄制完整,按回車鍵繼續下一次錄制,如果錄制不完整或有其他雜音,按其他任意鍵洗掉剛才的錄音再繼續下一次錄制,
執行命令:
#python micro_speech/train/record.py

毫無疑問,這個教學案例是教你如何錄制一個人的聲音,如果想要達到商業化的識別率,就至少需要500人以上的聲音錄制,如果僅僅錄制你一個人的喚醒詞,那么僅識別你的聲音是可以的,但其他人在喚醒時的成功率就會低很多,這個案例重點是教你了解喚醒詞訓練部署的原理,
6.1.2 背景噪音錄制
為了更好的識別,需要錄制一些背景噪音,模型訓練時會學習喚醒詞和背景噪音的差別,背景噪音可以錄制1~2分鐘,模型訓練時會自動從中隨機選擇片段作為背噪加入喚醒詞中進行學習,
執行命令:
#python micro_speech/train/record_noise.py

錄制背景噪音,放到dataset/_background_noise_目錄,
6.1.3 創建自己的資料集
訓練腳本中默認采樣的預訓練資料集是Google發布的Speech Commands(語音命令)資料集,該資料集是英文資料集,這里我們以錄制中文的“打開”,“關閉”為例,每個詞錄制100次,錄制完成后分別命名為dakai和guanbi兩個檔案夾放入自定義的my_dataset目錄,然后從Speech Commands中選擇幾個單詞house、marvin、wow等喚醒詞作為“未知”類別放入到my_only_dataset目錄,它的作用是模型訓練時能夠從這些喚醒詞中識別想要的dakai和guanbi命令,dakai和guanbi可以理解為正面示例,“未知”類別為反面示例,整個命令詞個數盡量限制在十個以下,這樣訓練的時間不會過久,如果你有其他同樣長度且與錄音配置中格式一樣的喚醒詞,也可以加入進來,另外如果錄制的是100次喚醒詞,那么其他作為“未知”類別的喚醒詞的錄音示例個數也盡量在100左右,錄制的背景噪音放入到_background_noise_目錄,訓練時腳本將自動從中隨機選取一秒片段作為背景噪音加入到“無聲”類別中,
6.2 模型訓練
6.2.1 PC端訓練
PC上在VSCode中使用jupyter notbook插件打開tflite_micro_speech_demo/micro_speech/train/train_micro_speech_model.ipynb進行其他喚醒詞的訓練,
前提:
參考《HaaS AI之VSCode中搭建Python虛擬環境》搭建完開發環境后,安裝tensorflow 1.15版本:
#conda create --name tf python=3.6
#conda activate tf
#conda install tensorflow=1.15

6.2.2 阿里云PAI平臺訓練
如果PC性能有限,使用阿里云PAI平臺進行訓練也是一個不錯的選擇,PAI-DSW是一款云端機器學習開發IDE,為您提供互動式編程環境,適用于不同水平的開發者,你可以根據根據需要選擇個人版、GPU特價版或探索者版(免費),相關使用手冊DSW新手使用手冊,
以使用DSW個人版為例:
- 登錄PAI控制臺,
- 在左側導航欄,選擇模型開發和訓練 > 互動式建模(DSW),
- 在頁面左上方,選擇目標地域,
- 在Notebook建模服務頁面,單擊創建實體,
- 在配置實體向導頁面,配置引數,鏡像選擇tensorflow1.15-gpu-py36-cu101-ubuntu18.04版本,

6.2.3 模型配置
無論在什么平臺上進行訓練,腳本中需要對訓練的引數進行一定的配置:
喚醒詞配置
WANTED_WORDS就是你訓練的喚醒詞,比如:
WANTED_WORDS="yes, on",yes/on對應于資料集dataset目錄的喚醒詞語料檔案夾,這里跟你你要訓練的喚醒詞修改,
訓練步數配置
如果你的喚醒詞僅僅走數百條甚至數10條,那么訓練的步數不用太久,修改:
TRANINGS_STEPS="1200, 300"
如果你有上千條以上,訓練的步數可以增加:
TRANINGS_STEPS="15000, 3000"
為了防止訓練欠擬合或者過擬合,訓練的時間長短需要反復驗證,找到最優的結果,
資料集配置
如果使用自己的資料集,請修改:
DATASET_DIR = './dataset/'
6.3 模型部署
模型部署在HaaS EDU K1上,主要有三個步驟:
- 模型替換:將生成的模型檔案model.cc替換micro_speech/micro_features/model.cc檔案
- 標簽更新:在cc替換micro_speech/micro_features/micro_model_settings.cc中,將標簽名更換為你訓練的快捷詞,比如“打開”、“關閉”,由于標簽與模型的輸出張量元素是按照順序進行匹配的,因此,需要按照將標簽提供給訓練腳本的順序列出這些標簽,
- 業務邏輯更新:在micro_speech/command_responder.cc中根據標簽更新相應的業務邏輯,目前在聽到“打開”后,會打開HaaS EDU K1上R/G/B LED燈,你也可以修改邏輯比如通過WiFi打開遠程的風扇或燈,這里可以充分發揮你的想象力打造一些比較有意思的場景應用,
7. 總結
本案例在HaaS EDU K1上基于TFLite-Micro推理引擎進行語音喚醒詞的部署,也提供了從喚醒詞采集到模型訓練,模型部署的全鏈路開發流程,幫助您深入理解在低功耗MCU上如何進行離線語音識別的開發部署,期待您打造更多屬于你的離線喚醒詞應用,
開發者支持
如需更多技術支持,可加入釘釘開發者群,或者關注微信公眾號,

更多技術與解決方案介紹,請訪問HaaS官方網站https://haas.iot.aliyun.com,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/299915.html
標籤:AI
