對(duì)于個(gè)人和公司來(lái)說(shuō),存在許多狀況是更希望在本地設(shè)備上做深度學(xué)習(xí)推斷的:想象一下當(dāng)你在旅行途中沒有可靠的互聯(lián)網(wǎng)鏈接時(shí)瓶蚂,或是要處理傳輸數(shù)據(jù)到云服務(wù)的隱私問(wèn)題和延遲問(wèn)題時(shí)撕捍。
邊緣計(jì)算(Edge computing)是一種在物理上靠近數(shù)據(jù)生成的位置從而對(duì)數(shù)據(jù)進(jìn)行處理和分析的方法涯呻,為解決這些問(wèn)題提供了方案。
以「Ok Google」這個(gè)功能為例:用一名用戶的聲音來(lái)訓(xùn)練「Ok Google」,他的手機(jī)在接收到這個(gè)關(guān)鍵詞的時(shí)候就會(huì)被喚醒典鸡。這種小型關(guān)鍵詞檢測(cè)(small-footprint keyword-spotting,KWS)推斷通常在本地設(shè)備上運(yùn)行家夺,所以你不必?fù)?dān)心服務(wù)提供商隨時(shí)監(jiān)聽你的聲音猫态。而云服務(wù)只在你發(fā)出指令后才啟動(dòng)。類似的概念可以擴(kuò)展到智能家用電器或其他物聯(lián)網(wǎng)設(shè)備上的應(yīng)用兆解,在這些應(yīng)用中我們需要不依靠互聯(lián)網(wǎng)進(jìn)行免提語(yǔ)音控制馆铁。
更重要的是,邊緣計(jì)算不僅為物聯(lián)網(wǎng)世界帶來(lái)了人工智能锅睛,還提供了許多其他的可能性和好處埠巨。例如,我們可以在本地設(shè)備上將圖像或語(yǔ)音數(shù)據(jù)預(yù)處理為壓縮表示现拒,然后將其發(fā)送到云辣垒。這種方法解決了隱私和延遲問(wèn)題。
在 Insight 任職期間印蔬,我用 TensorFlow 在安卓上部署了一個(gè)預(yù)訓(xùn)練的 WaveNet 模型勋桶。我的目標(biāo)是探索將深度學(xué)習(xí)模型部署到設(shè)備上并使之工作的工程挑戰(zhàn)!這篇文章簡(jiǎn)要介紹了如何用 TensorFlow 在安卓上構(gòu)建一個(gè)通用的語(yǔ)音到文本識(shí)別應(yīng)用程序。
開發(fā)環(huán)境信息:
- Pixel, cpu type: ARM64
- Android 7.1.1
- Android NDK 15.2
- Android gradle plugin 2.3.0
- TensorFlow 1.3.0
- bazel 0.5.4-homebrew
詳細(xì)教程和實(shí)現(xiàn):https://github.com/chiachunfu/speech
第一步:模型壓縮
為了將深度學(xué)習(xí)模型部署到移動(dòng)/嵌入式設(shè)備上,我們應(yīng)該致力于減少模型的內(nèi)存占用陵究,縮短推斷時(shí)間眠饮,減少耗電。有幾種方法可以實(shí)現(xiàn)這些要求铜邮,如量化仪召、權(quán)重剪枝或?qū)⒋竽P吞釤挸尚∧P汀?/p>
在這個(gè)項(xiàng)目中,我使用了 TensorFlow 中的量化工具來(lái)進(jìn)行模型壓縮松蒜。目前我只使用權(quán)重量化來(lái)減小模型大小扔茅,因?yàn)楦鶕?jù) Mac 上的測(cè)試結(jié)果,完整 8 位轉(zhuǎn)換沒有提供額外的好處秸苗,比如縮短推斷時(shí)間召娜。(由于 requant_range 中的錯(cuò)誤,無(wú)法在 Pixel 上運(yùn)行完整的 8 位模型)惊楼。由于 8 位量化工具不適合 CPU玖瘸,時(shí)間甚至翻了一倍秸讹。如果你有興趣了解更多關(guān)于量化的實(shí)用建議,可以閱讀 Pete Warden 這篇很棒的文章(https://petewarden.com/2017/06/22/what-ive-learned-about-neural-network-quantization/)雅倒。
對(duì)模型進(jìn)行權(quán)重量化:
- 將模型寫入?yún)f(xié)議緩沖區(qū)文件璃诀。
- 從源安裝和配置 TensorFlow(https://www.tensorflow.org/install/install_sources)。
- 在 TensorFlow 目錄下運(yùn)行下列命令行:
bazel build tensorflow/tools/graph_transforms:transform_graph
bazel-bin/tensorflow/tools/graph_transforms/transform_graph \
--in_graph=/your/.pb/file
--outputs="output_node_name"
--out_graph=/the/quantized/.pb/file
--transforms='quantize_weights'
以我的項(xiàng)目為例蔑匣,在量化權(quán)重后劣欢,預(yù)訓(xùn)練的 WaveNet 模型的大小從 15.5Mb 下降到了 4.0Mb。現(xiàn)在可以將這個(gè)模型文件移動(dòng)到安卓項(xiàng)目中的「assets」文件夾裁良。
第二步:適用于安卓的 TensorFlow 庫(kù)
要用 TensorFlow 構(gòu)建安卓應(yīng)用程序凿将,我推薦從 TensorFlow Android Demo開始。在我的項(xiàng)目中价脾,我把 TF speech example 作為模板牧抵。這個(gè)示例中的 gradle 文件幫助我們構(gòu)建和編譯安卓的 TF 庫(kù)。但是彼棍,這個(gè)預(yù)構(gòu)建的 TF 庫(kù)可能不包括模型所有必要的 ops灭忠。我們需要想清楚 WaveNet 中需要的全部 ops膳算,并將它們編譯成適合安卓 apk 的.so 文件座硕。為了找到 ops 的完整列表,我首先使用 tf.train.write_graph 輸出圖的詳細(xì)信息涕蜂。然后在終端中運(yùn)行下列命令:
grep "op: " PATH/TO/mygraph.txt | sort | uniq | sed -E 's/^.+"(.+)".?$/\1/g'
接著华匾,編輯/tensorflow/tensorflow/core/kernels/里的 BUILD 文件,在 Android libraries section 中的「android_extended_ops_group1」或「android_extended_ops_group2」里添加缺失的 ops机隙。我們也可以刪除不必要的 ops蜘拉,使 .so 文件變得更小。現(xiàn)在有鹿,運(yùn)行下列命令:
bazel build -c opt //tensorflow/contrib/android:libtensorflow_inference.so
--crosstool_top=//external:android/crosstool
--host_crosstool_top=@bazel_tools//tools/cpp:toolchain
--cpu=armeabi-v7a
你將在這里找到 libtensorflow_inference.so 文件:
bazel-bin/tensorflow/contrib/android/libtensorflow_inference.so
除了 .so 文件之外旭旭,我們還需要一個(gè) JAR 文件。運(yùn)行:
bazel build
//tensorflow/contrib/android:android_tensorflow_inference_java
你將在這里找到該文件:
bazel-bin/tensorflow/contrib/android/libandroid_tensorflow_inference_java.jar
現(xiàn)在葱跋,可以將 .so 和 .jar 文件一起移到你的安卓項(xiàng)目中的「libs」文件夾持寄。
第三步:在安卓上的數(shù)據(jù)預(yù)處理
最后,讓我們將輸入數(shù)據(jù)處理成模型訓(xùn)練所需格式娱俺。對(duì)于音頻系統(tǒng)來(lái)說(shuō)稍味,原始的語(yǔ)音波被轉(zhuǎn)換成梅爾頻率倒譜系數(shù)(MFCC)來(lái)模擬人耳感知聲音的方式。TensorFlow 有一個(gè)音頻 op荠卷,可以執(zhí)行該特征提取模庐。然而,事實(shí)證明油宜,實(shí)現(xiàn)這種轉(zhuǎn)換存在一些變體掂碱。如圖 2 所示怜姿,來(lái)自 TensorFlow audio op 的 MFCC 不同于 librosa 提供的 MFCC。librosa 是一個(gè)被預(yù)訓(xùn)練的 WaveNet 作者們用來(lái)轉(zhuǎn)換訓(xùn)練數(shù)據(jù)的 Python 庫(kù)疼燥。
如果您正在訓(xùn)練自己的模型或重訓(xùn)練一個(gè)預(yù)先訓(xùn)練好的模型,那么在處理訓(xùn)練數(shù)據(jù)時(shí)悴了,一定要考慮設(shè)備上的數(shù)據(jù)通道搏恤。最終,我在 Java 中重寫了 librosa MFCC 來(lái)處理轉(zhuǎn)換問(wèn)題湃交。
結(jié)果
圖 3 展示了 app 的截圖和示例熟空。由于模型中沒有語(yǔ)言模型,而且識(shí)別僅在字符級(jí)搞莺,因此句子中出現(xiàn)了一些拼寫錯(cuò)誤息罗。雖然沒有經(jīng)過(guò)嚴(yán)格的測(cè)試,但在量化之后才沧,我確實(shí)發(fā)現(xiàn)準(zhǔn)確率略有下降迈喉,以及整個(gè)系統(tǒng)對(duì)周圍的噪聲很敏感。
下表所示推斷時(shí)間是對(duì) 5 秒音頻的 10 次測(cè)試的平均值挨摸。推斷時(shí)間在兩個(gè)平臺(tái)上都略有增加,而不是減少岁歉,因?yàn)闄?quán)重量化有助于縮小文件大小得运,但不太能優(yōu)化推斷時(shí)間或耗電情況。
接下來(lái)做些什么?
有兩件重要的事情可以讓這個(gè)項(xiàng)目更進(jìn)一步,也可以為社區(qū)提供額外的教程和演練非剃,以便在邊緣設(shè)備上部署一個(gè)現(xiàn)實(shí)語(yǔ)音識(shí)別系統(tǒng)置逻。
提高語(yǔ)音識(shí)別性能:添加拼寫校正的語(yǔ)言模型和噪聲下采樣模型,以降低周圍噪聲的影響备绽。
改善推斷時(shí)間和耗電情況:用 NEON 或其他架構(gòu)進(jìn)行低層次優(yōu)化券坞,用 gemmlowp 進(jìn)行低精度矩陣計(jì)算。
GitHub 地址:https://github.com/chiachunfu/speech
選自DataScience
作者:Chia-Chun
機(jī)器之心編譯
參與:Edison Ke疯坤、路雪