今天就跟大家聊聊有關(guān)如何在Kuiper 中運(yùn)行TensorFlow Lite 模型,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。
成都創(chuàng)新互聯(lián)公司專注于江都網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠為您提供江都營銷型網(wǎng)站建設(shè),江都網(wǎng)站制作、江都網(wǎng)頁設(shè)計(jì)、江都網(wǎng)站官網(wǎng)定制、成都小程序開發(fā)服務(wù),打造江都網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供江都網(wǎng)站排名全網(wǎng)營銷落地服務(wù)。
EMQ X Kuiper 是一款邊緣輕量級(jí)物聯(lián)網(wǎng)數(shù)據(jù)分析/流軟件,可在各種資源受限的物聯(lián)網(wǎng)設(shè)備上運(yùn)行。
TensorFlow Lite 是一組幫助開發(fā)人員在移動(dòng)端、嵌入式和物聯(lián)網(wǎng)設(shè)備上運(yùn)行 TensorFlow 模型的工具,它使得設(shè)備上的機(jī)器學(xué)習(xí)預(yù)測(cè)具有低延遲和較小的二進(jìn)制容量。
通過集成 Kuiper 和 TensorFlow Lite,用戶可以通過包含預(yù)先構(gòu)建的 TensorFlow 模型的 AI 分析流中的數(shù)據(jù)。 在本教程中,我們將引導(dǎo)您構(gòu)建一個(gè) kuiper 插件,通過預(yù)先訓(xùn)練的圖像識(shí)別 TensorFlow 模型,標(biāo)記邊緣設(shè)備生成的流圖片(二進(jìn)制數(shù)據(jù))。
如需運(yùn)行 TensorFlow Lite 解釋器,我們需要一個(gè)經(jīng)過訓(xùn)練的模型。本篇教程將不介紹如何訓(xùn)練和涵蓋這個(gè)模型,您可以通過查看 tflite converter 了解詳情。我們既可以訓(xùn)練一個(gè)新的模型,也可以在線選擇一個(gè)。在本教程中,我們將使用 mattn/go tflite的 label image 模型。該 repo 為 tflite C API 創(chuàng)建了 golang 綁定。我們還將使用它來實(shí)現(xiàn)我們的插件。
為了集成 Kuiper 和 TensorFlow Lite,我們將開發(fā)一個(gè)定制的 Kuiper 函數(shù)插件,供 Kuiper 規(guī)則使用。例如,我們將創(chuàng)建 LabelImage
函數(shù),其輸入是表示圖像的二進(jìn)制類型數(shù)據(jù),輸出是表示圖像標(biāo)簽的字符串。例如,如果輸入圖像中有孔雀,LabelImage(col)
將輸出“孔雀”。
要開發(fā)函數(shù)插件,我們需要:
創(chuàng)建插件 go 文件。例如,在 kuiper 源代碼中,創(chuàng)建 plugins/functions/labelImage/labelImage.go 文件。
創(chuàng)建一個(gè)實(shí)現(xiàn) api.函數(shù)接口 的 struct。
導(dǎo)出 struct。
實(shí)現(xiàn)的關(guān)鍵是 Exec 函數(shù)。偽代碼如下:
func (f *labelImage) Exec(args []interface{}, ctx api.FunctionContext) (interface{}, bool) { //... 初始化和驗(yàn)證 // 解碼輸入圖像 img, _, err := image.Decode(bytes.NewReader(arg[0])) if err != nil { return err, false } var outerErr error f.once.Do(func() { // 加載標(biāo)簽、tflite模型并初始化tflite解釋器 }) // 對(duì)輸入圖像運(yùn)行解釋器 // 返回可能性最大的標(biāo)簽 return result, true }
此外還需要注意插件的導(dǎo)出。該函數(shù)是無狀態(tài)的,因此我們將僅導(dǎo)出一個(gè) struct 實(shí)例。所有使用此函數(shù)的規(guī)則都會(huì)共享一個(gè)實(shí)例,以避免創(chuàng)建實(shí)例和加載模型的開銷。模型和標(biāo)簽路徑將在實(shí)例化時(shí)指定。
var LabelImage = labelImage{ modelPath: "labelImage/mobilenet_quant_v1_224.tflite", labelPath: "labelImage/labels.txt", }
查閱 本教程 以獲得創(chuàng)建 Kuiper 插件的詳細(xì)步驟。請(qǐng)參閱 labelImage.go 以獲取完整的源代碼。
要使用該插件,我們需要在運(yùn)行 Kuiper 的環(huán)境中對(duì)其進(jìn)行構(gòu)建,然后將其安裝在 Kuiper 中。
如果使用基于 debian 的帶有 1.1.1 或 1.1.1-slim標(biāo)簽的 Kuiper docker 鏡像,我們可以安裝預(yù)構(gòu)建的 labelImage插件。例如,要在 docker image emqx/kuiper:1.1.2-slim 中安裝 Kuiper 1.1.2 插件,則預(yù)構(gòu)建的 zip 文件位于 https://www.emqx.io/downloads/kuiper-plugins/v1.1.2/debian/functions/labelImage_amd64.zip。按如下所示運(yùn)行 rest命令以進(jìn)行安裝。
POST http://{{kuiperHost:kuiperRestPort}}/plugins/functions Content-Type: application/json {"name":"labelImage", "file": "https://www.emqx.io/downloads/kuiper-plugins/v1.1.2/debian/functions/labelImage_amd64.zip"}
如果您不使用官方的 Kuiper docker 鏡像運(yùn)行 Kuiper,由于 golang 插件的限制,預(yù)構(gòu)建的 labelImage 插件將不適用。您需要手動(dòng)構(gòu)建插件。手動(dòng)創(chuàng)建插件 zip 文件有3個(gè)步驟:
構(gòu)建 TensorFlowLite C API。
構(gòu)建 labelImage 插件。
將插件與安裝腳本打包在一起。
有一個(gè)來自 tensorflow repo 的關(guān)于構(gòu)建C API的非常簡(jiǎn)單的 說明 。 我們將在本節(jié)中逐步詳細(xì)展開。 請(qǐng)注意,該插件僅針對(duì) TensorFlow v2.2.0-rc3 進(jìn)行測(cè)試,因此我們將以此版本為基礎(chǔ)進(jìn)行構(gòu)建。 以 ubuntu為例,以下是構(gòu)建步驟:
安裝 Python 3.
將 requirements.txt 復(fù)制到您指定位置。 安裝所需的 python 庫:pip3 install -r requirements.txt
。 requirements 來自相應(yīng) TensorFlow 版本的 tensorflow/tensorflow/tools/pip_package/setup.py
。
安裝 TensorFlow 的構(gòu)建工具 Bazel。
克隆 tesorflow repo,通過 git checkout v2.2.0-rc3 -b mybranch
命令切換到所需的分支。
生成目標(biāo) .so 文件,輸出將位于 ./bazel-bin 中。 將兩個(gè) so 文件復(fù)制到 tensorflow/lib 文件夾中。
$ cd $tensorflowSrc $ bazel build --config monolithic -c opt //tensorflow/lite:libtensorflowlite.so $ bazel build --config monolithic -c opt //tensorflow/lite/c:libtensorflowlite_c.so $ mkdir lib $ cp bazel-bin/tensorflow/lite/libtensorflowlite.so lib $ cp bazel-bin/tensorflow/lite/c/libtensorflowlite_c.so lib
安裝 so 文件。
更新 ldconfig 文件 sudo vi / etc / ld.so.conf.d / tflite.conf
。
將路徑 {{tensorflowPath}}/lib
添加到 tflite.conf,然后保存并退出。
運(yùn)行 ldconfig: sudo ldconfig
。
檢查安裝結(jié)果:ldconfig -p | grep libtensorflow
。 確保列出了兩個(gè)so文件。
確保已克隆 Kuiper github repo。 插件源文件位于 plugins/functions/labelImage/labelImage.go 中。 在構(gòu)建插件之前,導(dǎo)出 tensorflow repo 和構(gòu)建庫的路徑。
$ cd {{kuiperRepoPath}} $ export CGO_CFLAGS=-I/root/tensorflow $ export CGO_LDFLAGS=-L/root/tensorflow/lib $ go build -trimpath --buildmode=plugin -o plugins/functions/LabelImage.so plugins/functions/labelImage/*.go
通過這些命令,插件將構(gòu)建到 plugins/functions/LabelImage.so 中。出于開發(fā)目的,您可以重新啟動(dòng) Kuiper 以自動(dòng)加載此插件并進(jìn)行測(cè)試。測(cè)試完成后,我們應(yīng)該將其打包為一個(gè) zip 文件,該文件可供 Kuiper 插件安裝API 使用,以便可以在其他計(jì)算機(jī)(例如生產(chǎn)環(huán)境)中使用。
將 plugins/functions/labelImage 目錄中的所有文件和目錄與構(gòu)建的 LabelImage.so 一起打包到一個(gè) zip 文件中。 zip文件的文件結(jié)構(gòu)應(yīng)類似于:
etc
labels.txt
mobilenet_quant_v1_224.tflite
lib
libtensorflowlite.so
libtensorflowlite_c.so
install.sh
LabelImage.so
tflite.conf
將打包的插件安裝到目標(biāo)系統(tǒng),如 通過預(yù)構(gòu)建 zip 安裝 所示。
插件安裝后,我們就可以在規(guī)則中使用它了。 我們將創(chuàng)建一個(gè)規(guī)則用于接收來自 mqtt 主題的圖像字節(jié)數(shù)據(jù),并通過 tflite 模型標(biāo)記該圖像。
通過 Kuiper rest API 定義流。 我們創(chuàng)建一個(gè)名為 tfdemo 的流,其格式為二進(jìn)制,主題為 tfdemo。
POST http://{{host}}/streams Content-Type: application/json {"sql":"CREATE STREAM tfdemo () WITH (DATASOURCE=\"tfdemo\", FORMAT=\"BINARY\")"}
通過 Kuiper rest API 定義規(guī)則。 我們將創(chuàng)建一個(gè)名為 ruleTf 的規(guī)則。 我們只是從 tfdemo 流中讀取圖像,然后對(duì)其運(yùn)行自定義函數(shù) labelImage。 返回結(jié)果將是 AI 識(shí)別的圖像的標(biāo)簽。
POST http://{{host}}/rules Content-Type: application/json { "id": "ruleTf", "sql": "SELECT labelImage(self) FROM tfdemo", "actions": [ { "log": {} } ] }
在這里,我們創(chuàng)建了一個(gè) go 程序,用于將圖像數(shù)據(jù)發(fā)送到 tfdemo 主題以便由規(guī)則進(jìn)行處理。
package main import ( "fmt" mqtt "github.com/eclipse/paho.mqtt.golang" "io/ioutil" "time" ) func main(){ const TOPIC = "tfdemo" images := []string{ "peacock.png", "frog.jpg", // 其他你需要的圖像 } opts := mqtt.NewClientOptions().AddBroker("tcp://yourownhost:1883") client := mqtt.NewClient(opts) if token := client.Connect(); token.Wait() && token.Error() != nil { panic(token.Error()) } for _, image := range images { fmt.Println("Publishing " + image); payload, err := ioutil.ReadFile(image) if err != nil{ fmt.Println(err) continue } if token := client.Publish(TOPIC, 0, false, payload); token.Wait() && token.Error() != nil { fmt.Println(token.Error()) } else { fmt.Println("Published " + image); } time.Sleep(1 * time.Second) } client.Disconnect(0) }
運(yùn)行 pub.go,它將開始將圖像輸入 tfdemo 主題。
因?yàn)槲覀兊囊?guī)則定義只有一個(gè)目標(biāo):log,所以結(jié)果將被寫入日志文件。 我們用 peacock.png 和 frog.png 兩個(gè)圖像填充流。 檢查日志文件,我們會(huì)發(fā)現(xiàn):
time="2021-02-05 16:23:29" level=info msg="sink result for rule ruleTf: [{\"labelImage\":\"peacock\"}]" file="sinks/log_sink.go:16" rule=ruleTf time="2021-02-05 16:23:30" level=info msg="sink result for rule ruleTf: [{\"labelImage\":\"bullfrog\"}]" file="sinks/log_sink.go:16" rule=ruleTf
圖像標(biāo)記正確。
看完上述內(nèi)容,你們對(duì)如何在Kuiper 中運(yùn)行TensorFlow Lite 模型有進(jìn)一步的了解嗎?如果還想了解更多知識(shí)或者相關(guān)內(nèi)容,請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝大家的支持。