社区分享 | 从零开始学习 TinyML(一)
TinyML 簡介
1. 概要
Pete Warden 與?Daniel Situnayake 合著了一本介紹在 Arduino 和超低功耗微控制器上如何運(yùn)行 ML 的書,?TinyML:Machine Learning with TensorFlow Lite on Arduino and Ultra-Low-Power Microcontrollers,這本書由 O’Reilly 于 2019 年 12 月 13 號出版。
?
我作為國內(nèi) IoT 和 ML 兩個方向的 GDE,對 AI 在嵌入式系統(tǒng)和物聯(lián)網(wǎng)上的應(yīng)用也一直在持續(xù)關(guān)注。得到書本出版的消息之后,就迫不及待的入手了一本英文原板紙質(zhì)書,看后愛不釋手,同時也想以書本的概念為原型,把如何去搭建 TinyML 完整的工程流程分享給大家。
?
2.?ML 以及 TinyML 簡介
在閱讀本文之前,我先簡單介紹一下 TinyML 。
?
Machine Learning (ML) 這一個學(xué)科,在學(xué)術(shù)界有 40 年左右的歷史,但是前面的 30 多年研究,只是在學(xué)術(shù)上有一些突破。
?
真正讓 ML 從學(xué)界走入產(chǎn)業(yè)界的劃時代改革的里程碑,源于 2010 年 ImageNet 挑戰(zhàn)賽 (ILSVRC)。2012 年,Hiton (ML 業(yè)界元老級人物) 課題組首次參加 ImageNet 圖像識別比賽,AlexNet 奪得冠軍,并碾壓了第二名 (SVM) 的分類性能。ML 在工業(yè)應(yīng)用的熱情在這一年被徹底點(diǎn)燃。
?
ML 最近幾年已經(jīng)在工業(yè)、消費(fèi)領(lǐng)域獲得了大量的應(yīng)用,隨著云資源的不斷完善,研發(fā)了更多的激動人心的 AI 模型。云端 AI 的應(yīng)用,已經(jīng)獲得長足的進(jìn)步。
?
在 ML 的工業(yè)應(yīng)用發(fā)展的這幾年,物聯(lián)網(wǎng)也處于快速處在發(fā)展期。從最早的智能家居,到現(xiàn)在遍地的物聯(lián)網(wǎng)智能設(shè)備。AI 應(yīng)用逐步從云端走向了設(shè)備端,現(xiàn)在設(shè)備端的 AI 應(yīng)用已經(jīng)占了很大的比例,手機(jī)上 AI 的應(yīng)用已經(jīng)非常普遍。
?
但是,在物聯(lián)網(wǎng)世界里,有數(shù)以億計的體積小、功耗低、資源受限的設(shè)備支撐著物聯(lián)網(wǎng)應(yīng)用。如何在超低功耗 (mV 功率范圍) 的設(shè)備上運(yùn)行人工智能應(yīng)用,同時又要滿足設(shè)備長時間低功耗的運(yùn)行 AI 應(yīng)用的需求,已經(jīng)形成了一個新的課題。
?
TinyML 指的是在 mW 功率的微處理器上,實(shí)現(xiàn)機(jī)器學(xué)習(xí)的方法、工具和技術(shù)。它連接了物聯(lián)網(wǎng)設(shè)備,邊緣計算和機(jī)器學(xué)習(xí)。
?
TinyML 基金會在 2019 年組織了第一屆峰會,這屆峰會的成果如下:
TinyML 的技術(shù)硬件已經(jīng)進(jìn)入了實(shí)用性的階段;
算法,網(wǎng)絡(luò)以及低于 100KB 的 ML 模型,已經(jīng)取得重大突破;
視覺,音頻的低功耗需求快速增長。
?
TinyML 將在以后幾年,隨著智能化的發(fā)展,獲得更快的發(fā)展。這一領(lǐng)域也有著巨大的機(jī)會。
?
3. 書籍作者介紹
Pete Warden 原是 Jetpac 的 CTO 和創(chuàng)始人。于 2014 年正式加入 Google,現(xiàn)在為移動和嵌入式端 TensorFlow 的技術(shù)負(fù)責(zé)人(Technical Leader)。需要解釋一下的是 Jetpac 公司擁有強(qiáng)大的分析社交媒體照片能力,為旅行者提供城市指南服務(wù),這家公司在 2014 年被 Google 收購。
?
Daniel Situnayake 曾是 Google 的TensrorFlow Lite 的技術(shù)推廣工程師 (Developer Advocate),同時一直積極參與 Meetup 上 TinyML 社區(qū)的工作。他也是美國第一家以工業(yè)自動化的方式生產(chǎn)昆蟲蛋白質(zhì)的公司 Tiny Farm 的聯(lián)合創(chuàng)始人。
?
兩位作者中的一位側(cè)重于物聯(lián)網(wǎng)上的 AI 技術(shù)研發(fā),另一位則側(cè)重于運(yùn)用 AI 技術(shù)去實(shí)現(xiàn)工業(yè)化,他們強(qiáng)強(qiáng)聯(lián)合出版了這本書,帶我們進(jìn)一步探索物聯(lián)網(wǎng)端 AI 的所有技術(shù)環(huán)節(jié)工業(yè)化實(shí)現(xiàn),原汁原味的體現(xiàn)了利用 Google 的技術(shù)去促進(jìn)發(fā)展的思考脈絡(luò)。
?
4. 開發(fā)環(huán)境
作為開發(fā)環(huán)境,我們只需要在電腦上用 USB 接口實(shí)現(xiàn)外設(shè)接入就行了。當(dāng)然根據(jù)每一個讀者的習(xí)慣,可以用自己所熟悉的編譯工具來編譯這個環(huán)境,所有的這些代碼都可以在 Windows,Linux 或者 macOS 上運(yùn)行。當(dāng)然,已經(jīng)訓(xùn)練出來許多模型在 Google Cloud 中可以下載。也可以用 Google Colab 來運(yùn)行所有的代碼。就不必要去擔(dān)心需要擁有獨(dú)特的硬件開發(fā)環(huán)境。
?
推薦使用大概 $15 可以買到的 Spark Fun Edge 開發(fā)板。由于在這本書發(fā)布的時候。Spark Fun 的第 2 版已經(jīng)開發(fā)出來了,并可支持運(yùn)行所有的示例項目。讀者對硬件開發(fā)板的硬件版本兼容性亦無需太多擔(dān)心。
?
當(dāng)然,也有另外兩款開發(fā)板的支持:Arduino Nano 33 BLE 和 STM32F746G 開發(fā)板,開發(fā)者可以根據(jù)自己的需求靈活選用。
?
我們這一系列主要分享如何用 Arduino Nano 33 BLE 開發(fā)板運(yùn)行最簡單的示例代碼。
?
5. 軟件準(zhǔn)備
這本書所有的項目是依賴于 TensorFlow Lite 在微控制器上的開發(fā)框架,所依賴的硬件環(huán)境,只有幾十 kb 左右的存儲空間。
-
項目
https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/micro
?
我們也知道,對于開源軟件來說,由于軟件不斷的更新,包括優(yōu)化,bug 修改以及其他設(shè)備的支持,造成代碼一直在不斷的變動。或許書中舉出例子的代碼跟 Github 的代碼不太一致,但是最基本的原則是相通的。
?
在軟件開發(fā)中間,我們也可以選擇適合自己的 IDE 開發(fā)工具。但是由于我(非原書作者,是本人)已經(jīng)用于 Linux 很多年,是 Vim 的死忠粉,所以我后面給大家介紹的內(nèi)容全部是基于 Vim+ 終端的模式進(jìn)行講解。如果涉及到開發(fā)工具相關(guān)的問題,歡迎在本文末留言,我們一起討論。關(guān)于命令的運(yùn)行,在 Linux 和 macOS 中,我們很輕易的用終端。在 Windows 系中,可以用命令行工具去解決開發(fā)問題。
?
嵌入式開發(fā)另外一個問題就是需要和開發(fā)板進(jìn)行通訊。如果用 Spark Fun 開發(fā)板,需要用 Python 命令來做項目的編譯,如果用 Arduino 開發(fā)板,只需要在 Arduino 的開發(fā)環(huán)境中,加載開發(fā)包就可以了。
?
6. 機(jī)器學(xué)習(xí)工程化流程
整個機(jī)器學(xué)習(xí)工程部署的大體流程如下:
確定目標(biāo)
收集數(shù)據(jù)集
設(shè)計模型架構(gòu)
訓(xùn)練模型:注意一下過擬合和欠擬合所產(chǎn)生的各種問題
轉(zhuǎn)換模型
運(yùn)行推斷
評估并排除故障
?
工程流程一般都是基于以上的步驟進(jìn)行部署的。在下一章中,我們將用學(xué)習(xí)任何語言的經(jīng)典入門 “Hello World”,來闡述基于項目的 TinyML 工程開發(fā)流程。
?
?
Hello World — 夢開始的地方(上)
Hello World 是每一個程序員進(jìn)入程序世界,學(xué)說的第一句話。它的意義并不在于可以以一種特殊的方式去輸入一串字符,而在于用一句簡單的話,去了解最基本的流程,為自己的新世界打開一扇大門。
?
我們將 “Hello World — 夢開始的地方”分為上、中、下,三個部分來講述如何去構(gòu)建一個完整的、可以運(yùn)行的、基于 TensorFlow Micro 的工程系統(tǒng)。其中上篇是手把手教開發(fā)者如何去建立并且訓(xùn)練模型,中篇主要講解如何創(chuàng)建工程應(yīng)用,下篇主要是講解如何把工程部署到微控制器上。
?
事不宜遲,我們趕緊進(jìn)入上篇吧。
?
1.?環(huán)境準(zhǔn)備
項目在三個不同的開發(fā)板上都可以正常運(yùn)行,我們以Arduino? Nano 33 BLE Sense?(https://www.arduino.cc/en/Guide/NANO33BLE)?為硬件,來實(shí)現(xiàn)基于 TensorFlow 的 ML 項目。
?
2.?項目流程
實(shí)現(xiàn)基于微控制器的 ML 項目開發(fā)流程如下所示:
1. 獲得簡單數(shù)據(jù)集
2. 訓(xùn)練深度學(xué)習(xí)模型
3. 評估模型性能
4. 轉(zhuǎn)換成設(shè)備上運(yùn)行的模型
5. 將代碼轉(zhuǎn)換成二進(jìn)制文件
6. 部署二進(jìn)制文件到微控制器
?
文章中所有的代碼都基于?TensorFlow Micro?上的代碼。當(dāng)然,代碼中也包括許多注釋,我們會一一的分析代碼中的最關(guān)鍵的部分以及為何要這么實(shí)現(xiàn)。
-
TensorFlow Micro
https://github.com/tensorflow/tensorflow/tree/master/tensorflow/lite/micro?
?
3.?準(zhǔn)備前的工作
我們分享的 Hello World 示例,是用數(shù)學(xué)中的最基本的sine函數(shù)為原型,用 ML 的方式去預(yù)測數(shù)據(jù)。關(guān)于 sine 函數(shù),我們在初中學(xué)三角函數(shù)時就接觸過。這個函數(shù)在工業(yè)應(yīng)用中非常廣泛。一般的函數(shù)圖形如圖所示:
?
我們的目標(biāo)是,如果有一個 x 值,我們能夠預(yù)測出 x 的 sin 值 y。在真實(shí)的環(huán)境中,用數(shù)學(xué)計算的方法可以更快速的得到結(jié)果。這個例子是用 ML 的方法去實(shí)現(xiàn)預(yù)測,從而了解 ML 的整個流程。
?
整從數(shù)學(xué)角度來看,sine 函數(shù)能夠在 -1 到 1 之間,周期性的平滑波動。我們可以用這種平滑的值,來控制 LED 燈光的亮度。
?
利用 Arduino 開發(fā)板運(yùn)行這個項目的效果如圖所示:
?
工具準(zhǔn)備:
配置開發(fā)環(huán)境,所用的編程語言當(dāng)然是當(dāng)之無愧的 Python,這是現(xiàn)在使用最廣泛的,運(yùn)用于科學(xué)、數(shù)學(xué)、以及 AI 領(lǐng)域的編程語言。版本為 3.x Python 可以在命令行下運(yùn)行,但是還是推薦用 Jupyter Notebook 來開發(fā),它的好處是可以把代碼、文檔、還有圖片放在一起,既能當(dāng)教程,又能分步運(yùn)行。
?
如果有條件上 Google Colab,這個編譯環(huán)境也是一個很好的選擇。Colab 一直是由 Google 開發(fā)并維護(hù)的平臺,并且在云平臺上,已經(jīng)安裝了各種依賴軟件。并且還可以免費(fèi)去用 Google TPU 的服務(wù)。通過 Web 瀏覽器,可以運(yùn)行自己編寫的任何代碼。甚至可以用 Colab 的配置文件,來選擇加速硬件,從而加速模型訓(xùn)練。
?
ML 平臺的選擇,毫無疑問,選擇 TensorFlow。因為 TensorFlow 是現(xiàn)在使用最廣泛的AI加速平臺,并且有成熟的 pip 安裝包可以用。當(dāng)然,在接下來的應(yīng)用中,我們需要用 TensorFlow Lite,能得模型在嵌入式硬件上運(yùn)行,我們也會用 TensorFlow 的高階 API,Keras 來完成一些編程工作。
?
4.?創(chuàng)建模型
項目相關(guān)代碼:
-
https://github.com/tensorflow/tensorflow/blob/master/tensorflow/lite/micro/examples/hello_world/create_sine_model.ipynb
?
當(dāng)然,如果在 Google Colab 上運(yùn)行項目,可以直接運(yùn)行。
?
我們就在本地以 Jupter notebook 的方式,運(yùn)行我們的代碼。我是以 git clone 的方式下載了 TensorFlow 的所有源碼,從本地的 Linux 命令行進(jìn)行操作。由于我運(yùn)行環(huán)境的 Linux 系統(tǒng),已經(jīng)安裝了所有的依賴軟件,所以在 Jupter 的環(huán)境中,涉及到 Linux 中相關(guān)的 pip 安裝和 apt 安裝的代碼都注釋掉了。
?
首先運(yùn)行 Jupyter:
?
啟動之后彈出 chrome 瀏覽器,內(nèi)容如圖所示:
?
其中需要注意的是,在右上角的區(qū)域,如果提示不受信任,點(diǎn)擊“不受信任”的文字,按提示操作,最終文字變成“信任”。如果說右上角區(qū)域 Python 版本為 2,那么需要在 Jupyter 的菜單欄中,Kernel ?Change Kernel 中選擇 Python 3。
?
當(dāng)然,代碼的第一步是導(dǎo)入 TensorFlow、Numpy、Matplotlib 以及Math 庫。其中 Numpy 用于數(shù)據(jù)處理。Matplotlib 用于數(shù)據(jù)的可視化。
?
其實(shí)在代碼中,我注釋掉了 #!pip install tensorflow==2.0.0-beta0 這一行,原因是因為我的 PC 機(jī)已經(jīng)安裝完了 TensorFlow 的最新版。
?
5.?產(chǎn)生數(shù)據(jù)
首先基于 sin 函數(shù)產(chǎn)生一系列的標(biāo)準(zhǔn)化數(shù)據(jù)。
可以看出,運(yùn)行之后,數(shù)據(jù)相當(dāng)規(guī)范。作者為了讓大家細(xì)致入微的去理解代碼,對這一段代碼做了一些解釋說明。當(dāng)然,如果是要處理數(shù)據(jù)的話,Numpy 是一個最優(yōu)的數(shù)學(xué)處理函數(shù)庫。x_values = np.random.uniform(low=0, high=2*math.pi, size=SAMPLES), 用來產(chǎn)生特定范圍內(nèi)的一系列隨機(jī)數(shù)。
?
當(dāng)原始數(shù)據(jù)產(chǎn)生之后,我們要接著做的事情,便是數(shù)據(jù)清洗。我們要確保數(shù)據(jù)以真正的隨機(jī)的方式反饋。很幸運(yùn),Numpy 的radom.shuffle()提供了這樣的方法。
?
最后再把數(shù)據(jù)以二維坐標(biāo)的方式畫在圖片上。
?
這么漂亮的數(shù)據(jù),直接去訓(xùn)練可好?當(dāng)然沒有問題,但是,ML 做的是什么樣的事情?從各種噪音中篩選數(shù)據(jù),經(jīng)過訓(xùn)練,最后預(yù)測的準(zhǔn)確率越來越高。第一部操作,我們需要加入一些噪音進(jìn)來。這也是機(jī)器學(xué)習(xí)中常用的方法。當(dāng)樣本的容易不夠時,我們?nèi)绾卧黾訕颖镜臄?shù)量,以便訓(xùn)練時準(zhǔn)確率更高。
?
我們就完全創(chuàng)建的所有的數(shù)據(jù)。
?
接下來便是分成訓(xùn)練集和測試集:
?
就這一部分的關(guān)鍵代碼詳細(xì)解釋一下:
TRAIN_SPLIT = int(0.6 * SAMPLES) TEST_SPLIT = int(0.2 * SAMPLES + TRAIN_SPLIT)?
整個數(shù)據(jù)集包括三個部分,訓(xùn)練集,測試集,驗證集。示例中用了 60% 的數(shù)據(jù)當(dāng)訓(xùn)練集,20% 的數(shù)據(jù)當(dāng)測試集,20% 的數(shù)據(jù)當(dāng)驗證集。這個比例不是恒定的,可以按需求調(diào)整。
?
x_train, x_test, x_validate = np.split(x_values, [TRAIN_SPLIT, TEST_SPLIT]),雖然輸入?yún)?shù)中只包括了訓(xùn)練的測試的部分,但是由于整個數(shù)據(jù)集分割了三部分,所以 np.split 的返回結(jié)果是三個,代碼我們的三種場景。
?
6.?定義基本模型
?
我們用 Keras 來構(gòu)建最開始的模型。
?
第一層采用標(biāo)量輸入,并且基于 “relu” 激活,用了 16 個神經(jīng)元的密集層 (Dense Layer,也可叫做全連接層)。當(dāng)我們進(jìn)行預(yù)測時,它是推理過程中的神經(jīng)元之一。每個神經(jīng)元將然后被激活到一定程度。每個神經(jīng)元的激活量是基于在訓(xùn)練過程中獲得的 weight 和 bias 值來定義激活功能。神經(jīng)元的激活將作為數(shù)字輸出。激活是通過一個簡單的公式來計算的,如 Python 中所示。我們將永遠(yuǎn)不需要自己編寫此代碼,因為它由 Keras 和 TensorFlow 處理, 在深入學(xué)習(xí)時但會有所幫助,計算公式的偽代碼如下所示:
activation = activation_function((input * weight) + bias)?
要計算神經(jīng)元的激活程度,需要將其輸入乘以權(quán)重和偏差被添加到結(jié)果中。計算出的值被傳遞到激活函數(shù)中。結(jié)果就是神經(jīng)元的激活。激活函數(shù)是一種數(shù)學(xué)函數(shù),用于塑造神經(jīng)元的輸出。在我們的網(wǎng)絡(luò)中,我們使用的是稱為整流線性單元 (Rectified Linear Unit) 的激活函數(shù),或簡稱為 ReLU。這在 Keras 中由參數(shù) activation = relu 指定。ReLU 是一個簡單的函數(shù),如 Python 所示:
def relu(input): return max(0.0, input)?
ReLU 返回較大的值:如果其輸入值為負(fù),ReLU 返回零。如果其輸入值大于零,則輸出保持不變。
?
用 ReLU 做為激活函數(shù)意義在哪兒?
?
沒有激活函數(shù),神經(jīng)元的輸出將始終是線性函數(shù).這意味著網(wǎng)絡(luò)只能建模線性關(guān)系,其中 x 和 y 之比在整個值范圍內(nèi)保持不變。但是正弦波又是非線性的,這將阻止網(wǎng)絡(luò)對我們的正弦波進(jìn)行建模。由于 ReLU 是非線性的,因此它允許多層神經(jīng)元聯(lián)合作用并建立模型復(fù)雜的非線性關(guān)系,每次x增量不會使y值以相同的方式增加。還有其他激活功能,但是ReLU是最常用的功能。作為ML算法,運(yùn)用最優(yōu)的激活函數(shù)是必要的。
?
我們再對輸入、輸出層做一些解讀:
由于輸出層是單個神經(jīng)元,它將接收 16 個輸入。由于這是我們的輸出層,因此我們不指定確定激活功能-我們只需要原始結(jié)果。由于此神經(jīng)元有多個輸入,因此每個神經(jīng)元都有一個對應(yīng)的權(quán)重值。神經(jīng)元的輸出通過以下公式計算得出,如 Python 中所示:其中 “inputs” 和 “weights” 都是 NumPy 數(shù)組,每個數(shù)組有 16 個元素
output = sum((inputs * weights)) + bias?
通過將每個輸入與其對應(yīng)的乘積獲得輸出值 weights,對結(jié)果求和,然后加上神經(jīng)元的 bias。該網(wǎng)絡(luò)的 weights 和 bias 是在培訓(xùn)期間學(xué)習(xí)的。?
?
接下來,編譯階段的關(guān)鍵點(diǎn),便是優(yōu)化器的損失函數(shù)了。
model_1.compile(optimizer='rmsprop', loss='mse', metrics=['mae'])?
其中優(yōu)化器,損失函數(shù)以及指標(biāo),都有許多種選擇,我們不展開詳述。您可以去以下鏈接去做更多的了解。
-
https://keras.io/optimizers/
-
https://keras.io/losses/
?
最后我們再來看看模型概況:
?
其中輸入層有 16 個神經(jīng)元,共 2 層連接,所以全部的連接數(shù)為 16x2=32,每一個神經(jīng)元都有一個 bias,網(wǎng)絡(luò)總共有 17 個 bias。輸入的 16,以及輸出的 1。所以總的參數(shù)為 32+17=49。
?
7.?訓(xùn)練模型
?
利用 keras 的 fit() 方法能夠很好的訓(xùn)練。下面就一些參數(shù)做一下最基本的解釋:
-
X_train, y_train 表示最基本的訓(xùn)練數(shù)據(jù)。
-
epochs 訓(xùn)練的周期,一般來說,周期越長,訓(xùn)練越精確,但是,一般來說,訓(xùn)練的時間到一定階段,訓(xùn)練精度不會有很大差別。在這種清況下,一般要考慮去優(yōu)化模型了。
-
batch_size 用于往網(wǎng)絡(luò)中一次送入多少數(shù)據(jù),如果值為 1,我們每一次會更新 weight 和 bias,并且會估計網(wǎng)絡(luò)預(yù)測的損失,為下一次的運(yùn)行做更精確的估計。越小的值,會帶來很大的計算量,占用更多的計算資源。如果我們把值定要 600,一次性可以計算出更多的數(shù)據(jù),但是會降低模型的精度。所以最好的方式是把值設(shè)置為 16 或者是 32。這個值的選擇,實(shí)際上精度與時間花費(fèi)權(quán)衡的結(jié)果。
?
接下來,我們最關(guān)心的,當(dāng)然是訓(xùn)練的結(jié)果了。
?
該圖顯示了每個時期的損失(或模型的預(yù)測與實(shí)際數(shù)據(jù)之間的差異)。有幾種計算損失的方法,我們使用的方法是均方誤差。對于訓(xùn)練和驗證數(shù)據(jù)有明顯的損失值。
?
我們可以看到,損失的數(shù)量在前 25 個時期迅速減少,然后趨于平穩(wěn)。這意味著該模型正在改進(jìn)并產(chǎn)生更準(zhǔn)確的預(yù)測!
?
我們的目標(biāo)是在模型不再改善或訓(xùn)練損失小于驗證損失 (Validation Loss) 時停止訓(xùn)練,這意味著該模型已經(jīng)學(xué)會了很好地預(yù)測訓(xùn)練數(shù)據(jù),也不需要新的數(shù)據(jù)來提高精度。
?
為了使圖表的平坦部分更具可讀性,我們用代碼 SKIP = 50 跳過前 50 個 epochs,這僅僅是便于我們看圖方便。
?
從圖中可以分析出,大概 epochs 到了 600 左右,訓(xùn)練開始趨于穩(wěn)定。意味著我們的 epochs 應(yīng)該不需要超過 600。
?
但是,我們還可以看到最低的損失值仍在 0.155 左右。這意味著我們網(wǎng)絡(luò)的預(yù)測平均降低了約 15%。另外,驗證損失值 (Validation loss) 產(chǎn)生的很大的跳躍,并不穩(wěn)定。我們需要改進(jìn)方法。這次,我們將繪制平均絕對誤差 (Mean Absolute Error)圖,這是另一種衡量網(wǎng)絡(luò)預(yù)測與實(shí)際數(shù)字的距離的方法:
?
?
從平均絕對誤差圖可以看到,訓(xùn)練數(shù)據(jù)顯示出的錯誤始終比驗證數(shù)據(jù)低,這意味著網(wǎng)絡(luò)可能存在過擬合 (Overfit),或者過分地學(xué)習(xí)了訓(xùn)練數(shù)據(jù),從而無法對新數(shù)據(jù)做出有效的預(yù)測。
?
此外,平均絕對誤差值非常高,最多約為 0.305,這意味著該模型的某些預(yù)測至少可降低 30%。30% 的誤差意味著我們離精確建模正弦波函數(shù)還很遙遠(yuǎn)。
?
?
該圖清楚地表明,我們的網(wǎng)絡(luò)已經(jīng)學(xué)會了以非常有限的方式近似正弦函數(shù)。從 0 <= x <= 1.1 開始,該行最適合,但是對于我們的其他 x 值,充其量只是一個大概的近似值。
?
結(jié)果表明,該模型沒有足夠的能力來學(xué)習(xí)正弦波函數(shù)的全部復(fù)雜度,因此只能以過于簡單的方式對其進(jìn)行近似。通過優(yōu)化模型,我們應(yīng)該能夠改善其性能。
?
8.?優(yōu)化模型
優(yōu)化的關(guān)鍵是增加全連接層,這一層包含了 16 個神經(jīng)元。
?
我們再對模型做評估:
?
?
通過圖片分析,我們的網(wǎng)絡(luò)達(dá)到了峰值精度的速度要快得多(在 200 個時期內(nèi),而不是 600 個時期內(nèi))。總損失和 MAE 比我們以前的網(wǎng)絡(luò)要好得多。驗證結(jié)果比訓(xùn)練結(jié)果更好,這意味著網(wǎng)絡(luò)不會過度擬合。驗證指標(biāo)優(yōu)于訓(xùn)練指標(biāo)的原因是,驗證指標(biāo)是在每個時期結(jié)束時計算的,而訓(xùn)練指標(biāo)是在整個時期計算的。
?
這一切都意味著我們的網(wǎng)絡(luò)似乎運(yùn)行良好!為了確認(rèn)這一點(diǎn),讓我們對照我們先前放置的測試數(shù)據(jù)集檢查其預(yù)測:
?
最終的測試結(jié)果如下所示:
?
我們來看這張圖片,并不能說明這預(yù)測值完全跟 sine 的曲線一模一樣。但是現(xiàn)在預(yù)測精度不是主要問題了,我們只想通過平滑的曲線來對開關(guān)進(jìn)行控制。模型精度已經(jīng)足夠了。
?
9.?模型轉(zhuǎn)換
模型轉(zhuǎn)換的要點(diǎn),就是 TensorFlow 到 TensorFlow Lite 的轉(zhuǎn)換。其中有兩個主要的組成部分:
?
TensorFlow Lite 轉(zhuǎn)換器 (TensorFlow Lite Converter)
這會將 TensorFlow 模型轉(zhuǎn)換為一種節(jié)省空間的特殊格式,以用于內(nèi)存受限的設(shè)備,并且可以應(yīng)用進(jìn)一步減少并優(yōu)化模型尺寸,使其在小型設(shè)備上運(yùn)行更快。
?
TensorFlow Lite 解釋器 (Tensorflow Lite Interpreter)
這會使用最有效的方式運(yùn)行經(jīng)過適當(dāng)轉(zhuǎn)換的 TensorFlow Lite 模型到給定設(shè)備的有效操作。
?
同樣,我們不需要操作,但是需要了解 convert 的 python API,以及創(chuàng)建 FlatBuffer,當(dāng)然,還包括量化,即浮點(diǎn)精度的轉(zhuǎn)換問題。這一類的話題,在我以前關(guān)于 TensorFlow Lite 的許多線下分享中都有過詳細(xì)的原理上的分析及解釋。
?
整個轉(zhuǎn)換代碼如下:
?
產(chǎn)生了兩個模型,第一個模型是沒有經(jīng)過量化的。第二個模型是經(jīng)過量化的。
?
對 TF Lite 模型進(jìn)行預(yù)測,我們還需要完成如下的工作:
申明解釋器對象實(shí)體
為模型分配內(nèi)存
加載模型
從傳感器中讀取輸出數(shù)據(jù)
?
由于這一段代碼比較長,我們就看一下最終的分析結(jié)果:
?
我們再用代碼來對比一下,量化和非量化模型的大小區(qū)別:
?
差距有20個字節(jié)。
?
10.?模型轉(zhuǎn)換成二進(jìn)制文件
準(zhǔn)備模型以用于 TensorFlow Lite for Microcontrol 的最后一步。
?
到目前為止,在本章中,我們一直在使用 TensorFlow Lite 的 Python API。表示我們已經(jīng)能夠使用 Interpreter 構(gòu)造函數(shù)加載模型磁盤中的文件。但是,大多數(shù)微控制器都沒有文件系統(tǒng),即使有,鑒于我們的限制,從磁盤加載模型所需的額外代碼將很浪費(fèi)空間。相反,作為一種優(yōu)雅的解決方案,我們在 C 源文件中提供了該模型,包含在我們的二進(jìn)制文件中并直接加載到內(nèi)存中。
?
在文件中,模型定義為字節(jié)數(shù)組。幸運(yùn)的是,有一個名為 xxd 的 Unix 工具,它能夠?qū)⒔o定的文件轉(zhuǎn)換為所需的格式。
?
以下輸出為在我們的量化模型上運(yùn)行 xxd,將輸出寫入名為sine_model_quantized.cc,并將其打印到屏幕上:
?
最終,生成二進(jìn)制模型代碼的工作搞定。
?
11.?結(jié)論
至此,我們完成了模型的構(gòu)建。我們已經(jīng)進(jìn)行了訓(xùn)練,評估和配置建立了一個 TensorFlow 深度學(xué)習(xí)網(wǎng)絡(luò),該網(wǎng)絡(luò)可以采用 0 到 2π 之間的數(shù)字并輸出正弦的近似值。
?
這是我們使用 Keras 訓(xùn)練小模型的初次體驗。在未來的項目中,我們將訓(xùn)練模型仍然很小,但是要復(fù)雜得多。
?
在下一篇中,我們將會分析如何去編寫微控制器能夠運(yùn)行的 ML 應(yīng)用。
總結(jié)
以上是生活随笔為你收集整理的社区分享 | 从零开始学习 TinyML(一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 启动FastDFS服务,使用python
- 下一篇: Flask项目--爱家租房项目结构图