在MCU端部署GRU模型實(shí)現(xiàn)鼾聲檢測(cè)
掃描二維碼
隨時(shí)隨地手機(jī)看文章
1. 引言
提起打鼾,可能大家都不會(huì)陌生,打鼾是睡眠呼吸障礙的一種常見表現(xiàn),普遍存在于全球各地,影響著數(shù)百萬人的生活質(zhì)量和健康??梢哉f,打鼾是一個(gè)極端令人煩惱的生理現(xiàn)象,驗(yàn)證影響睡眠質(zhì)量。對(duì)于許多患者而言,及時(shí)檢測(cè)打鼾并采取相應(yīng)措施至關(guān)重要。然而,盡管市場(chǎng)上已有多種方法用于鼾聲檢測(cè),包括使用各種監(jiān)測(cè)設(shè)備和進(jìn)行復(fù)雜的睡眠研究,但這些方法大多數(shù)依賴于昂貴的設(shè)備和專業(yè)的操作,這在資源有限的環(huán)境中并不實(shí)用,也難以普及到廣大需要的人群,就顯得有些空中樓閣了。因此,開發(fā)一種簡(jiǎn)便、低成本且可靠的鼾聲檢測(cè)方法具有重要的實(shí)際意義,可以極大地提高普及度以及大眾的認(rèn)可讀[1]。
近年來,人工智能在處理和分析聲音數(shù)據(jù)方面取得了顯著進(jìn)展,尤其是深度學(xué)習(xí)技術(shù)已被成功應(yīng)用于各種聲音識(shí)別任務(wù),例如語音識(shí)別和異常聲音檢測(cè)。正是這些技術(shù)的進(jìn)步,為更加準(zhǔn)確、可靠的鼾聲檢測(cè)提供了新的可能性。在MCU單元上實(shí)現(xiàn)深度學(xué)習(xí)模型的嘗試,為端側(cè)的計(jì)算和邊緣智能開辟了新的可能性,使得在低成本的硬件設(shè)備上部署復(fù)雜的算法變得可行[2]。
本研究旨在探索使用深度學(xué)習(xí)架構(gòu)——門控循環(huán)單元,并對(duì)其進(jìn)行輕量級(jí)設(shè)計(jì),以實(shí)現(xiàn)對(duì)鼾聲的高效檢測(cè)。GRU模型能夠捕捉到時(shí)間序列數(shù)據(jù)中的依賴關(guān)系,如鼾聲的音頻模式,使得其更加適合實(shí)時(shí)處理和分析。選擇MCU單元作為運(yùn)行平臺(tái),不僅因?yàn)槠涑杀镜秃鸵子诩傻奖銛y式設(shè)備中,而且因?yàn)樗m合于在資源受限的環(huán)境中操作,滿足在各種環(huán)境下對(duì)鼾聲進(jìn)行實(shí)時(shí)監(jiān)測(cè)的需求。
通過將GRU模型適配到基于MCU的呼吸輔助裝置,我們可以將鼾聲檢測(cè)系統(tǒng)帶入患者的日常生活環(huán)境中,從而實(shí)現(xiàn)實(shí)時(shí)、非侵入性的監(jiān)測(cè),提供即時(shí)反饋和必要的醫(yī)療干預(yù)。此外,該方法的發(fā)展也將推動(dòng)深度學(xué)習(xí)在嵌入式系統(tǒng)中的應(yīng)用,特別是在處理生理信號(hào)和促進(jìn)移動(dòng)健康監(jiān)測(cè)方面,為廣泛的生物醫(yī)學(xué)應(yīng)用開辟新的道路。本文接下來將詳細(xì)介紹GRU模型的訓(xùn)練和調(diào)優(yōu)過程,以及如何實(shí)現(xiàn)在微控制器單元上部署該模型。
2. GRU模型簡(jiǎn)介
GRU全稱Gated Recurrent Unit,直譯叫做門控回歸單元。是一種用于處理序列數(shù)據(jù)的循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN)模型。RNN指代遞歸神經(jīng)網(wǎng)絡(luò)(Recurrent Neural Network),是一種常用于處理序列數(shù)據(jù)的神經(jīng)網(wǎng)絡(luò)架構(gòu)[3]。與傳統(tǒng)的前饋神經(jīng)網(wǎng)絡(luò)不同,RNN具有記憶功能,非常適合于對(duì)序列數(shù)據(jù)進(jìn)行處理,這是通過計(jì)算和維護(hù)狀態(tài)變量來實(shí)現(xiàn)的。相較于傳統(tǒng)的RNN,GRU具有更簡(jiǎn)單的結(jié)構(gòu)和更高效的訓(xùn)練方式。它通過一種稱為門控機(jī)制的方式來控制信息的流動(dòng),包括更新門和重置門。這些門控機(jī)制有助于模型決定在每個(gè)時(shí)間步上應(yīng)該記住什么信息,以及應(yīng)該忘記什么信息,從而更好地處理長序列數(shù)據(jù)。GRU模型包括一個(gè)更新門和一個(gè)重置門。更新門決定了新的輸入應(yīng)如何保留,而重置門則決定了狀態(tài)信息應(yīng)如何忽略[4]。
圖1是一個(gè)GRU的框圖說明。
Figure 1. GRU model. The switch is soft, is a weighted sum of the inputs, the sum of weights is 1
圖1. GRU模型示意圖。開關(guān)其實(shí)是軟的,是彼此兩個(gè)輸入的帶權(quán)和,且彼此權(quán)重的和為1
接下來介紹下這兩個(gè)門控單元的工作流程。首先是重置門r,負(fù)責(zé)對(duì)狀態(tài)量H進(jìn)行逐點(diǎn)相乘,記作r?H??? 。r和H都是相同維度的向量,相乘的結(jié)果起到對(duì)記憶的信息篩選淡出的效果。之后將輸入和計(jì)算后的狀態(tài)結(jié)合成為新的候選狀態(tài)h??? 。最終將結(jié)果進(jìn)行更新,更新就是通過這個(gè)z門。計(jì)算方式是z?Ht?1+(1?z)?H??????1+(1??)??? ,也就是說將上一次計(jì)算的狀態(tài)與當(dāng)前的候選狀態(tài)H??? 進(jìn)行加權(quán)求和,得到本次的最終狀態(tài),當(dāng)然也就是下一次的Ht?1???1 。如此循環(huán)往復(fù),直到訓(xùn)練結(jié)束,得到最終的模型[5]。
此外,與長短時(shí)記憶網(wǎng)絡(luò)(LSTM)相比,GRU模型減少了參數(shù)數(shù)量,一些情況下更容易訓(xùn)練,并且在計(jì)算上也更高效。這使得GRU成為處理序列數(shù)據(jù)時(shí)的一種流行選擇。由于GRU模型的門控結(jié)構(gòu),它具有一定的記憶能力,能夠更好地捕捉時(shí)間序列中的重要特征,并且相對(duì)于傳統(tǒng)的RNN模型,GRU模型在一定程度上緩解了梯度消失的問題,從而更適合處理長序列數(shù)據(jù)。
3. 在PC上進(jìn)行GRU模型的訓(xùn)練與測(cè)試
3.1. GRU模型訓(xùn)練
接下來,我們來看看如何訓(xùn)練一個(gè)GRU模型,模型訓(xùn)練平臺(tái)選用Keras,有需要的讀者請(qǐng)自行安裝Keras開發(fā)工具。我們這里主要給大家介紹模型搭建部分,這里假設(shè)我們的鼾聲檢測(cè)數(shù)據(jù)集已經(jīng)準(zhǔn)備好了,并將其劃分為訓(xùn)練和測(cè)試數(shù)據(jù)集,分別命名為:(x_train, y_train), (x_test, y_test)。直接進(jìn)行模型構(gòu)建與訓(xùn)練:
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import GRU, Dense
# 構(gòu)建GRU模型
model = Sequential()
model.add(GRU(128, input_shape=(64, 64), stateful=False, unroll=False))
model.add(Dense(2, activation='softmax'))
# 編譯模型
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
# 模型訓(xùn)練
model.fit(x_train, y_train, batch_size=128, epochs=10, validation_data=(x_test, y_test))
先看下這里所指定的輸入,(64, 64)。怎么理解呢?上文講過GRU模型實(shí)際上是每次只輸入一個(gè)維度的數(shù)據(jù),即數(shù)據(jù)應(yīng)該是(1, 64)。這里好像有點(diǎn)出入。這就不得不解釋下,這里的兩個(gè)64分別代表什么。前一個(gè)64表示timestep,第二個(gè)64表示音頻特征的維度。那么就可以理解為:一次訓(xùn)練,我們是一次性對(duì)64組連續(xù)的語音特征進(jìn)行訓(xùn)練,這樣能夠更好的處理他們之間的相關(guān)性。這里的音頻特征是由一段固定長度時(shí)域數(shù)據(jù)提取而來。
這里需要注意的是,GRU模型構(gòu)建的時(shí)候,有兩個(gè)參數(shù),分別是stateful以及unroll,這兩個(gè)參數(shù)是什么意思呢:
stateful參數(shù):當(dāng)stateful設(shè)置為True時(shí),表示在處理連續(xù)的數(shù)據(jù)時(shí),GRU層的狀態(tài)會(huì)被保留并傳遞到下一個(gè)時(shí)間步,而不是每個(gè)batch都重置狀態(tài)。這對(duì)于處理時(shí)間序列數(shù)據(jù)時(shí)非常有用,例如在處理長序列時(shí),可以保持模型的狀態(tài)信息,而不是在每個(gè)batch之間重置。默認(rèn)情況下,stateful參數(shù)為False。需要注意的是,若設(shè)置stateful為True,需要手動(dòng)管理狀態(tài)的重置。
unroll參數(shù):默認(rèn)情況下,unroll參數(shù)為False。當(dāng)unroll設(shè)置為True時(shí),表示在計(jì)算時(shí)會(huì)展開RNN的循環(huán)。通常情況下,對(duì)于較短的序列,unroll設(shè)置為True可以提高計(jì)算速度,但對(duì)于較長的序列,可能會(huì)導(dǎo)致內(nèi)存消耗過大,例如,上述模型如果unroll = True,會(huì)展開64次相同的GRU所執(zhí)行的操作,模型中包含大量節(jié)點(diǎn)。
我們?cè)倏纯磗tateful參數(shù)。鼾聲信號(hào)其實(shí)是時(shí)域音頻信號(hào),每個(gè)時(shí)間步之間實(shí)際上是存在有時(shí)間前后關(guān)系的,即前后的音頻片段之間會(huì)組成一段完整的音頻數(shù)據(jù)。因此,在實(shí)際使用時(shí)若要一次只處理單個(gè)時(shí)間步的數(shù)據(jù),就需要設(shè)置stateful為True。
3.2. GRU模型測(cè)試
上面通過訓(xùn)練,得到了一個(gè)龐然大物。之所以龐大,是因?yàn)槲覀儾捎昧藆nroll參數(shù)將其展開,發(fā)現(xiàn)模型其實(shí)由很多相同的模型塊組成,GRU模塊如圖2所示。
而這個(gè)模型塊的數(shù)量和所設(shè)置的時(shí)間步是相關(guān)的。這里我們要給大家?guī)鞧RU模型的一個(gè)特殊性,那就是實(shí)際推理所用到的模型和訓(xùn)練時(shí)是不一樣的。具體而言,訓(xùn)練時(shí)候,我們?yōu)榱俗孏RU模型能夠更好的學(xué)習(xí)相鄰音頻之間的關(guān)系,需要將模型輸入設(shè)置為(64, 64)。而實(shí)際測(cè)試時(shí)候,由于模型已經(jīng)具備了處理相鄰音頻的能力,我們也就不再需要將模型輸入設(shè)置為(64, 64),而是將其設(shè)置為(1, 64),即每次只輸入給模型一條音頻特征,同時(shí)我們?cè)O(shè)置stateful = True (請(qǐng)注意,與推理時(shí)相反,訓(xùn)練的時(shí)候stateful為False!),即每次模型會(huì)記錄下當(dāng)前所計(jì)算出來的狀態(tài)信息,將其用于下一次的計(jì)算。這樣化整為零,使輸入減少到了以前的1/64。隱藏狀態(tài)的計(jì)算量也就按比例一起減少了。但要注意的是,最后一步用于把隱藏狀態(tài)映射成輸出的Dense層的計(jì)算次數(shù)卻按比例增加了。不過,與減少的執(zhí)行GRU模塊的計(jì)算相比,增加的計(jì)算比減少的計(jì)算要少得多。
Figure 2. GRU model block
圖2. GRU模型塊
用于推理的模型構(gòu)建代碼修改如下:
# 構(gòu)建新模型
new_model = Sequential()
new_model.add(GRU(1, batch_input_shape=(1, 1, 64), unroll=True, stateful=True))
new_model.add(Dense(2, activation='softmax'))
new_model.set_weights(model.get_weights())
注意到,最后一行,有一個(gè)set_weights函數(shù),目的是將之前我們所訓(xùn)練出來的模型參數(shù)配置給這個(gè)新模型。看一下模型的變化,如圖3所示。
Figure 3. GRU model with time-step 1
圖3. 時(shí)間步為1的GRU模型
圖中紅圈位置有一個(gè)AssignVariable節(jié)點(diǎn),它的作用就是將本次所運(yùn)行出來的狀態(tài)量進(jìn)行保存,以供下次推理使用。
3.3. GRU模型量化
在模型部署前需要對(duì)模型進(jìn)行量化,量化的原理就是將用浮點(diǎn)數(shù)表示的模型權(quán)重,映射為(?128, 127)之間的8位整數(shù)[6]。這樣做的好處是可以減小模型尺寸,可以將其縮減到之前的近1/4。再者,MCU平臺(tái)提供了對(duì)于具有8位整數(shù)類型權(quán)重的模型的推理加速能力。不過弊端就是,精度可能會(huì)有所下降,所幸的是GRU模塊大量使用有上、下確界的Sigmoid和Tanh激活函數(shù),有助于估計(jì)中間結(jié)果的值域。模型量化可以使用NXP公司所開發(fā)的eIQ工具,打開eIQPortal軟件,找到MODELTOOL,如圖4所示:
Figure 4. eIQ Portal tools
圖4. eIQ Portal工具
用它打開我們剛才重新制作的模型,點(diǎn)擊左上角的Convert選擇轉(zhuǎn)換工具為Tensor Flow Lite,并勾選Enable Quantization,如圖5所示。
Figure 5. Model quantization
圖5. 模型量化頁面
點(diǎn)擊Convert即可獲得量化后的模型。
4. GRU模型的在端側(cè)的部署
我們選用了NXP的i.MX RT1060跨界MCU部署GRU模型。
4.1. i.MX RT1060平臺(tái)簡(jiǎn)介
i.MX RT1060跨界MCU擁有600 MHz的主頻,可以提供卓越的計(jì)算能力、多種媒體功能以及實(shí)時(shí)功能,易于使用。i.MX RT1060采用主頻達(dá)600 MHz的Cortex®-M7同時(shí)提供一流的安全保障。i.MX RT1060 MCU支持寬溫度范圍,適用于消費(fèi)電子、工業(yè)和汽車市場(chǎng)。擁有高達(dá)1 MB片上內(nèi)存,包括512 KB的FlexRAM,能被靈活的分配為ITCM/DTCM/OCRAM。集成了高級(jí)DCDC和LDO的電源管理模塊,簡(jiǎn)化電源序列。同時(shí)提供了多種內(nèi)存接口,包括SDRAM,RAWNAND FLASH,NORFLASH,SD/eMMC,Quad/Octal SPI,Hyper RAM/Flash以及其他接口,可以連接諸如WLAN,藍(lán)牙,GPS,displays以及攝像頭傳感器。同時(shí)具有豐富的音視頻特性,包括LCD顯示,顯示加速器,攝像頭接口,SPDIF以及I2S音頻接口。
4.2. 基于SDK中eIQTFLm工程進(jìn)行模型集成
首先需要指出的是,GRU模型相較于一般基于CNN的模型相比,其模型部署方法是一致的。特別地,eIQ MODEL TOOL會(huì)把GRU模塊降解成由最基本的TensorFlowLite所支持的算子所組成的模型結(jié)構(gòu)。這樣一來,就可以使用我們的TensorFlowLite引擎進(jìn)行推理了。而對(duì)應(yīng)到MCU上就是使用tflite-micro推理引擎進(jìn)行推理。Tflite-micro使用一種算子注冊(cè)機(jī)制決定哪些算子的實(shí)現(xiàn)將被鏈接到最終生成的可執(zhí)行映像中。這決定了為了將模型部署到MCU上,需要根據(jù)模型所需節(jié)點(diǎn)來修改注冊(cè)算子的源文件。這里我們已eIQ中l(wèi)abel_image的例子作為基礎(chǔ)進(jìn)行修改。找到工程中的model_ds_cnn_ops_micro.cpp文件,它就是剛才提到的注冊(cè)算子的源文件,原來的例子包含了推理label_image所需的算子,我們對(duì)其進(jìn)行修改如下:
tflite::MicroOpResolver &MODEL_GetOpsResolver()
{
static tflite::MicroMutableOpResolvers_microOpResolver;
s_microOpResolver.AddAdd();
s_microOpResolver.AddAssignVariable();
s_microOpResolver.AddCallOnce();
s_microOpResolver.AddFullyConnected();
s_microOpResolver.AddLogistic();
s_microOpResolver.AddMul();
s_microOpResolver.AddReshape();
s_microOpResolver.AddReadVariable();
s_microOpResolver.AddSub();
s_microOpResolver.AddSplit();
s_microOpResolver.AddSplitV();
s_microOpResolver.AddSoftmax();
s_microOpResolver.AddTanh();
s_microOpResolver.AddUnpack();
s_microOpResolver.AddVarHandle();
return s_microOpResolver;
}
修改好之后,將模型的二進(jìn)制數(shù)據(jù)轉(zhuǎn)換成符合C數(shù)組定義格式的文本形式(例如,使用xxd工具),并替換工程中model_data.h里面所包含的原始模型,就完成了所有關(guān)于模型的準(zhǔn)備工作。當(dāng)然對(duì)于數(shù)據(jù)預(yù)處理部分需要編寫對(duì)應(yīng)的MIC采集以及特征計(jì)算部分,限于篇幅本文就不再展開了。有興趣的讀者可以聯(lián)系作者。
5. 實(shí)驗(yàn)驗(yàn)證
選擇i.MX RT1060 EVK作為試驗(yàn)平臺(tái),整體組裝方案以及UI設(shè)計(jì)如圖6所示:
Figure 6. Overall architecture
圖6. 整體組裝方案
UI頁面主要分為三大顯示區(qū),分別是閾值調(diào)節(jié)區(qū):可以通過滑動(dòng)條靈活的調(diào)節(jié)檢測(cè)閾值,提高系統(tǒng)的抗干擾能力;音頻特征區(qū):顯示當(dāng)前音頻信號(hào)的特征圖。狀態(tài)顯示區(qū):顯示當(dāng)前模型預(yù)測(cè)結(jié)果,紅燈表示為異常,綠燈表示為正常。
6. 結(jié)語
本研究實(shí)現(xiàn)了一種能夠在資源有限的微控制器單元(MCU)上運(yùn)行的鼾聲檢測(cè)方法,采用門控循環(huán)單元(GRU)模型對(duì)音頻數(shù)據(jù)進(jìn)行處理,并且結(jié)合模型優(yōu)化方案,例如模型結(jié)構(gòu)裁剪,模型量化等,成功將GRU模型適配到MCU平臺(tái),使得系統(tǒng)能夠獨(dú)立完成鼾聲檢測(cè)無需依賴外界計(jì)算資源,且無需聯(lián)網(wǎng)。同時(shí)為了豐富產(chǎn)品顯示,設(shè)計(jì)了一個(gè)人機(jī)友好的UI界面,可以實(shí)時(shí)顯示系統(tǒng)識(shí)別狀態(tài),并可以調(diào)節(jié)系統(tǒng)檢測(cè)閾值等。實(shí)驗(yàn)表明,該模型在保持高準(zhǔn)確性的同時(shí),降低了系統(tǒng)算力需求,滿足移動(dòng)健康監(jiān)測(cè)設(shè)備的實(shí)時(shí)性和便攜性。這一研究為鼾癥患者提供了新的睡眠健康管理解決方案,并拓展了深度學(xué)習(xí)在嵌入式系統(tǒng)中的應(yīng)用前景。
NOTES
*通訊作者。