機器學習已從一個有趣的研究課題迅速發展成為廣泛應用的有效解決方案,它顯而易見的有效性迅速吸引了人工智慧理論學者群體之外的開發者社群的興趣。在某些方面,機器學習開發能力已經擴展到其他基於強大理論基礎的技術應用層面。

要開發有價值、高精度的機器學習應用絕非易事,但不斷成長的機器學習生態系統已經大大降低了對底層演算法深入理解的門檻,並使機器學習開發越來越容易被嵌入式系統開發人員使用,而不僅僅是理論上的研究。本文著重介紹一些神經網路模型開發中使用的主要概念和方法,機器學習本身是一個非常多樣化的領域,不過目前有一種實用的機器學習方法可供嵌入式開發人員使用。

機器學習方法

工程師可以找到能夠支援廣泛機器學習類型的最佳化函式庫,包括非監督式學習(unsupervised learning)、強化學習(reinforcement learning)和監督式學習(supervised learning)。

非監督式學習可以揭示出大量資料中的模式(pattern),但是這種方法不能將這些模式明確地標記為屬於特定類別的資料。儘管本文未涉及非監督式學習,但這些技術在物聯網(IoT)等應用中可能非常重要,可以揭示資料集中的異常值或表明存在偏離資料趨勢的情況。強化學習是一種透過實驗進行有效學習的應用方法,利用正面回饋(positive feedback,或獎勵)來學習對事件的成功反應。

監督式學習方法消除了在識別哪組輸入資料對應於哪個特定狀態(或物件)時進行的猜測。利用這種方法,開發人員明確識別出與特定物件、狀態或條件相對應的輸入值或特徵組合。在一個假設的機器範例中,工程師透過一組由n和x組成的函數來表徵要解決的問題,其中x是函數運算式(如x2),而n代表不同的特徵參數,例如感測器輸入、機器執行時間、最後服務日期、機器年齡和其他可測量參數。然後工程師根據他們的專業知識建立一個訓練資料集,即這些特徵向量的多個實例(x1 x2 ... xn),每個特徵向量都有n個觀察值與已知輸出狀態相關聯,標記(label)為y:

20190214_ML_TA31F1.png

給定所測量特徵值與相對應標記之間的已知關係,開發人員就可以為訓練集中的每個特徵向量(x1k、x2k...xnk)生成預期標記yk的模型(方程組)。在這一訓練過程期間,訓練演算法使用反覆運算方法,透過調整構成該模型的方程組的參數來最小化預測標記與其實際標記之間的差異。將訓練集中的所有樣本都訓練一次,稱為「一次反覆運算(epoch)」,而每一次epoch都會產生一組新的參數、一組與這些參數相關的新預測標記,以及相關的差異或損失。

針對損失進行繪圖,在每次反覆運算時產生的參數值集合是具有一些最小值的多維表面。該最小值對應於訓練集中提供的實際標記,與模型推斷的預測標記之間的最接近一致性。因此,訓練的目標是調整模型的內部參數以達到最小損失值,使用方法來尋求最小的「下坡」路徑。在多維表面上,透過計算每個參數相對於其他參數的斜率──即每個參數的偏導數(partial derivative),可以確定導致最佳下坡路徑的方向。

訓練演算法通常使用矩陣方法,稱為梯度下降法(gradient descent),以便在每個epoch透過模型運行訓練資料的全部或子集之後來調整模型參數值。為了最小化這種調整的幅度,訓練演算法將每個步長(step size)調整一些值,稱為學習速率(learning rate),這有助於訓練過程收斂。在沒有受控學習速率的情況下,由於模型參數的過大調整,梯度下降可能超過最小值。在模型達到(或可接受地收斂)最小損失之後,工程師就可以測試模型的標記預測能力。

一旦經過訓練和評估,就可以在生產環境中部署合適的模型,作為推理模型來預測實際應用資料的標記。請注意,推理會為訓練中使用的每個標記生成一組概率值。因此,用標記為「y1」、「y2」或「y3」的特徵向量訓練的模型,可能在呈現與y1相關的特徵向量時產生這樣的推斷結果,例如「y1:0.8; y2:0.19;y3:0.01」。

神經網路的發展

建立精確的推理模型當然是對監督式學習過程的回報,該過程能夠利用各種基礎模型的類型和體系結構。在這些模型類型中,神經網路因為在影像識別、自然語言處理和其他應用領域的成功而迅速普及。實際上,當先進的神經網路在影像識別中顯著優於早期演算法之後,神經網路架構已經成為這類問題實際上的解決方案。

隨著GPU等能夠快速執行基礎運算的硬體的出現,演算法開發者和使用者可以快速獲得這些技術;而有效的硬體平台和神經網路的廣泛被接受,又推動了各種方便開發人員使用的框架,包括Facebook的Caffe2、H2O、英特爾(Intel)的neon、MATLAB、微軟(Microsoft)認知工具套件、Apache MXNet、三星(Samsung) Veles、TensorFlow、Theano和PyTorch等。結果是開發人員可以輕鬆地找到合適的環境來評估機器學習,特別是神經網路。

神經網路的開發始於使用任意數量的可用安裝選項來部署框架。儘管依賴性通常很小,但所有流行的框架都能夠利用GPU加速的函式庫。因此,開發人員可以透過安裝NVIDA CUDA工具套件和NVIDIA深度學習SDK中的一個或多個函式庫──例如用於多節點/多GPU平台的NCCL (NVIDIA集體通訊函式庫)或NVIDIA cuDNN (CUDA深度神經網路)函式庫──來大幅提高運算速度。機器學習框架在GPU加速模式下運作,可充分利用cuDNN針對標準神經網路常式(routine)的最佳化實現,包括卷積(convolutions)、池化(pooling)、正規化(normalization)和活化層(activation layers)。

無論是否使用GPU,框架的安裝都很簡單,通常需要為這些以Python語言為基礎的軟體套件安裝pip;舉例來說,要安裝TensorFlow,可以使用與任何Python模組相同的Python安裝方法(或僅適用於Python 2.7環境):

20190214_ML_TA31F2

此外,開發人員可能希望添加其他Python模組以加速不同方面的開發。例如,Python pandas模組提供了一個功能強大的工具,用於建立所需的資料格式,執行不同的資料轉換,或者只處理機器學習模型開發中經常需要的各種資料整理操作。

經驗豐富的Python開發人員通常會為Python開發建立一個虛擬環境,例如,流行的框架都可以透過Anaconda取得。開發人員可以使用容器(container)技術來簡化devops,也可以找到其所用框架內建的合適容器。例如,TensorFlow在Dockerhub上的Docker容器中就支持兩個版本,一個是僅支援CPU的、一個是支援GPU的。Python wheel檔案中也提供了一些框架;例如Microsoft在CPU和GPU兩個版本中都提供Linux CNTK wheel檔案,開發人員也可以在Raspberry Pi 3上找到用於安裝TensorFlow的wheel 檔案。

資料準備

雖然設置機器學習框架已經變得簡單,但真正的工作始於選擇和準備資料。如前所述,資料在模型訓練中起著核心作用,因此決定著一個推理模型的有效性。之前未提及的事實是,訓練集通常包括數十萬、甚至數百萬個特徵向量和標記以達到足夠的準確度水準。這些資料集的龐大規模使得對輸入資料的隨意檢查變得不可能或基本上無效。然而,糟糕的訓練資料會直接影響模型品質;錯誤標記的特徵向量、缺失資料,以及「太乾淨」的資料集,可能導致推理模型無法提供準確的預測或很好地歸納。

對於整體應用而言可能更糟糕的是,選擇統計上不具代表性的訓練集,預示著模型會因為那些缺失的特徵向量及其所代表的實體(entities)而偏離實際。由於訓練資料的重要性以及建立資料的難度很大,業界已經發展了大量的標記資料集,這些資料集可從諸如UCI Machine Learning Repository機器學習資料庫等來源取得。對於僅僅探索不同機器學習演算法的開發人員,Kaggle資料集則通常可以提供一個很有用的起點。

當然,對於從事獨特的機器學習應用開發的組織來說,模型開發需要自己獨特的資料集。即使有足夠大的可用資料池,標記資料也是一個龐大工程。實際上,標記資料的過程主要還是人工來完成的。因此,建立一個準確標記資料的系統本身就是一個過程,需要結合心理學理解人類如何解釋指令(如標記方式和內容),以及技術支援來加速資料的呈現、標記和驗證。有了一組合格的標記資料,開發人員就需要將資料分成訓練集(training set)和測試集(test set),通常使用90:10左右的比例進行分割。注意測試集是一個有代表性但又與訓練集截然不同的資料集。

模型開發

在許多方面,建立合適的訓練和測試資料可能比建立實際模型本身更困難;例如使用TensorFlow,開發人員可以在TensorFlow的Estimator類(class)中使用內建模型種類來構建模型。例如以下的單次呼叫(single call): 20190214_ML_TA31F3

使用內建的DNNClassifier類自動建立一個基本的完全連結神經網路模型(如圖1),它包括一個有3個神經元的輸入層(Input layer,支援的特徵數量),一個有4個神經元的隱藏層(Hidden layer),以及一個有兩個神經元的輸出層(Output layer,支援的標記數量)。在每個神經元內,相對簡單的活化函數對其輸入組合執行一些轉換以產生其輸出。

20190214_ML_TA31P1

圖1:最簡單的神經網路包括輸入層、隱藏層和輸出層,而有用的推理依賴於包含大量隱藏層的深度神經網路模型,每個隱藏層包含大量神經元。
(來源:維基百科)

為了訓練模型,開發人員只需在產生實體的估算器(estimator)物件中呼叫訓練方法──在此範例中為classifier.train(input_fn = this_input_function),並使用TensorFlow資料集API透過輸入函數提供正確形成的資料(本範例中為this_input_function)。需要這樣的預處理或「形塑」(sharping),來將輸入資料流程轉換為具有輸入層所期望的維度(形狀)的矩陣,但是這一預處理步驟還可能包括資料縮放(data scaling)、正規化以及特定模型所需的任何數量轉換。

神經網路是許多高階識別系統的核心,但實際應用所採用的神經網路,其結構比本範例要複雜得多;這些「深度神經網路」架構具有許多隱藏層,每層都有大量神經元。雖然開發人員可以簡單地使用內建的Estimator類來添加更多層及更多神經元,但成功的模型架構往往會混合不同類型的層和功能。

舉例來說,AlexNet是一種卷積神經網路(CNN,或稱ConvNet),它在ImageNet競賽(以及之後的許多影像識別應用)中引發了CNN的廣泛使用,共有8層(見圖2)。每一層包含非常多的神經元,在第一層中有253,440個,第二層及以後依次為186,624、64,896、64,896、43,264、4,096、4,096和1,000個神經元。不是使用觀察資料的特徵向量,ConvNets掃描影像透過一個視窗(n×n像素濾鏡)、將視窗移動幾個像素(stride-步幅)並重複該過程,直到影像被完全掃描。每個過濾結果都透過ConvNet的各個層來完成影像識別模型。

20190214_ML_TA31P2

圖2:AlexNet展示了使用深度卷積神經網路架構來降低影像識別中的錯誤率。
(來源:ImageNet大規模視覺識別競賽)

即使採用這種「簡單」配置,與前一年的領先解決方案相比,使用CNN可以顯著降低ImageNet大規模視覺識別競賽(ILSVRC)中的前五大錯誤率(top-5 error)。Top-5錯誤率是一個常見指標,表示該模型對輸入資料可能標記的前五個預測中,未包含正確標記的推斷百分比。ILSVRC的參賽作品在隨後的幾年中顯示了層數的急遽增加,Top-5錯誤率也顯著降低(參考圖3)。

20190214_ML_TA31P3

圖3:由於AlexNet在2012年大幅降低了ImageNet的Top-5錯誤率,ILSVRC中表現最佳的模型架構明顯具有更深層次的模型架構。
(來源:The Computer Vision Foundation)

開發人員可以使用任何一種流行的框架來建立ConvNets和其他複雜的自訂模型。使用TensorFlow,開發人員使用方法呼叫(methods calls)逐層構建ConvNet模型,以構建卷積層,使用池化層聚合結果,並將結果正規化,通常重複該組合以根據需要建立盡可能多的卷積層。實際上,在設計用於完成CIFAR-10分類集的ConvNet的TensorFlow示範中,前三層是使用三種關鍵方法構建的:tf.nn.conv2d、tf.nn.max_pool和tf.nn.lrn:

20190214_ML_TA31F3

模型訓練

開發人員使用清單1 (Listing 1)顯示的訓練方法來訓練完整的TensorFlow模型。其中,train_op引用cifar10類物件的訓練方法來執行訓練,直到滿足開發人員在其他地方定義的停止條件。 cifar10訓練方法處理實際的訓練週期,包括損失計算、梯度下降、參數更新,以及將指數衰減函數應用於學習率本身(清單2)。

20190214_ML_TA31F4

清單1:在這個來自TensorFlow CIFAR-10 ConvNet展示的範例中,TensorFlow會話控制(session) mon_sess運作方法執行訓練週期,引用cifar10實例本身包含的損失函數和其他訓練參數。
(來源:TensorFlow)

20190214_ML_TA31F5

清單2:在TensorFlow CIFAR-10 ConvNet實現中,cifar10物件執行梯度下降,使用指數衰減計算損耗,並更新模型參數。
(來源:TensorFlow)

TensorFlow方法提供了強大的功能和靈活性,但程式碼可以說是比較笨拙的。好消息是,Keras作為一個更直觀的神經網路API,可以運行在TensorFlow之上。使用Keras,開發人員只需幾行程式碼即可建構CIFAR-10 ConvNet,例如添加所需的層、活化函數、聚合(池化)等等(參考清單3)。

20190214_ML_TA31F6

清單3:Keras提供了一種逐層建構ConvNet模型的直觀方法。
(來源:Keras)

在Keras中定義模型之後,開發人員呼叫模型的編譯方法來指定所期望的損耗計算演算法和最佳化演算法(例如梯度下降)。為了訓練模型,開發人員稱之為模型的擬合(fit)方法。或者,模型的fit_generator方法提供了一種更簡單的訓練方法,即使用Python的產生器功能對從Keras預處理類別生成的批量資料進行處理,以此來訓練模型。

要將模型部署到目標裝置(如邊緣裝置),開發人員通常可以從其開發環境中匯出模型。例如使用TensorFlow,開發人員可以使用TensorFlow freeze_graph.py工具程式(utility),以pb格式匯出模型,這是一種基於Google協議緩衝器(protocol buffer)的序列化格式。在目標裝置中,開發人員可以使用TensorFlow C ++ API建立TensorFlow執行時期會話(runtime session)、載入pb檔,並以應用程式的輸入資料執行。

對於能夠使用容器的目標平台,開發人員通常可以在Docker Hub上找到他們喜歡的框架Docker容器,添加他們的模型執行應用程式,並將應用程式容器匯出到他們的目標平台。在實踐中,重新佈署模型的過程需要額外注意,特別在將從開發環境中提取訓練資料而建構的功能,更換成專門為生產環境資料處理而最佳化的功能時。

開發方法

TensorFlow、Keras和其他神經網路框架顯著簡化了建構複雜模型的任務,但打造一個能有效滿足設計目標的模型完全是另一回事。與傳統的軟體開發不同,開發有效的模型可能需要更多的推測來嘗試不同的解決方案,以便「看出哪種方案可行」。研究人員正在積極研究能夠建立最佳化模型的演算法,但神經網路最佳化的一般定理仍然難以捉摸。就此而言,建立模型沒有通用的最佳實踐或啟發式方法:每個應用在前端都有其獨特的資料特徵,而在後端都有性能、準確性和功耗的獨特要求。

一種有效的方法是自動化模型構建工具,例如Google的Cloud AutoML,它使用遷移學習(transfer learning)和強化學習在特定領域找到良好的模型架構。到目前為止,Google已經發佈了一款還處於早期測試階段的產品AutoML Vision。就算不是馬上就會問世,自動化模型建構工具的出現勢不可擋;因為AI工具供應商在爭奪機器學習的主導地位,想借此改變遊戲規則,因此AutoML類型的工具仍是一個活躍的研究領域。

在此同時,雲端服務供應商和框架開發人員也在不斷改善更即時的功能,以簡化機器學習解決方案的開發。開發人員可以使用TensorFlow除錯器(debugger)等工具深入瞭解模型和TensorBoard的內部狀態,以便更輕鬆地視覺化和探索複雜的模型拓撲和節點互動。例如,TensorBoard提供了損失與epoch的互動圖,可以對模型有效性和學習速率適用性做出早期衡量(參考圖4)。

20190214_ML_TA31P4

圖4:TensorBoard幫助開發人員將模型內部結構和訓練過程視覺化,顯示損失函數(此處使用損失函數的交叉條目)與epoch的關係。
(來源:TensorFlow)

最終,找到最合適的架構和配置是經驗和反覆嘗試錯誤的結果;即使是最有經驗的神經網路研究人員也建議,找到最佳機器學習架構和特定拓撲結構的方法就是嘗試,看看哪種方法效果最好。從這個意義上說,神經網路發展與傳統應用程式開發有很大不同。不要期望對模型編碼後,就萬事大吉了,經驗豐富的機器學習開發人員,特別是神經網路開發人員,會將每個模型構建視為一個試驗,使用不同的模型架構和配置運行多個實驗,以找到最適合自己應用需要的模型。

開發人員也可以利用框架提供商和開放源碼社群提供的大量預建模型,來加速模型開發過程。預建模型具備通用資料集,甚至特定應用的資料集,但很少有開發人員所期望模型的最佳選擇。然而,採用遷移學習方法,這些模型不僅可以加速開發,而且得到的結果通常比使用自己的資料集來訓練初級模型更好。實際上,開發人員可以從很多管道找到開放源碼的預訓練模型,例如Caffe2 Model Zoo、Microsoft CNTK Model Gallery、Keras和TensorFlow等。

平台要求

然而,即使可用的模型建立技術不斷增加,模型選擇的關鍵約束仍然是目標平台的性能。為多GPU系統而設計的模型,將無法在基於通用處理器的系統上有效運行。如果沒有適當的硬體支援,通用處理器無法快速完成主導機器學習演算法的矩陣乘法(matrix multiplication 乘法)運算(參考圖5)。

20190214_ML_TA31P5

圖5:通用矩陣乘法(gemm)運算是一般機器學習的主流,特別是神經網路架構。
(來源:IBM)

儘管如此,開發人員仍然可以使用前面提到的TensorFlow for Raspberry Pi的版本來開發神經網路模型,能夠在Raspberry Pi這樣的系統上運行。更普遍地,Arm的Compute Library提供了針對Arm Cortex-A系列CPU最佳化的機器學習功能,比如Raspberry Pi 3使用的CPU就是Arm處理器。開發人員甚至可以使用Arm的CMSIS-NN為Arm Cortex-M7 MCU建立普通但有效的神經網路庫。實際上,Arm曾介紹過,利用在NUCLEO Mbed開發板上執行的標準216MHz Cortex-M7處理器,就可以支援為CIFAR-10預建的Caffe ConvNet,並在合理的時間內完成推理(圖6)。

20190214_ML_TA31P6

圖6:Arm展示Caffe CIFAR-10 ConvNet模型能夠在標準Arm Cortex-M7處理器上執行,並實現合理的推理時間。
(來源:Arm)

FPGA可以提供顯著的性能升級和快速開發平台。例如, 萊迪思半導體(Lattice Semiconductor)的SensAI平台使用神經網路編譯器,能夠將TensorFlow pb檔和其他檔案編譯到Lattice 神經網路IP核心上,以便在其FPGA上實現人工智慧。

專用的AI元件則更進一步,它們採用特別設計的硬體來加速針對大眾市場的機器學習應用。例如Intel Movidius Neural Compute Stick、NVIDIA Jetson TX2模組和高通(Qualcomm) Snapdragon模組等硬體設備可讓開發人員在各種系統中嵌入高性能機器學習演算法。

專門針對AI應用的架構旨在減少CPU對記憶體容量需求的瓶頸。例如,IBM在2018年VLSI Circuits Symposium上描述的AI加速器晶片將用於加速矩陣乘法的處理單元,與用於減少外部記憶體存取的「草稿記憶體」(scratchpad memory)層級結合在一起(圖7)。同樣地,新興的高階AI晶片利用各種方法將微架構中的邏輯和記憶體合併,以加速AI應用的各種運作。

20190214_ML_TA31P7

圖7:使用了諸如IBM AI晶片中描述的草稿記憶體層級結構等技術的新興AI晶片架構,旨在降低CPU對記憶體容量需求瓶頸的影響。
(來源:IBM)

專用框架和架構

專用硬體旨在充分發揮機器學習的潛力,IC產業繼續提供更強大的AI處理器;在此同時,框架開發人員和機器學習演算法專家也在不斷尋找最佳化框架和神經網路架構的方法,以便更有效地支援資源受限的平台,包括智慧型手機、物聯網邊緣裝置和其他性能一般的系統。雖然Apple Core ML和Android神經網路API都為各自的環境提供了解決方案,但TensorFlow Mobile等框架(及其演化版本TensorFlow Lite)提供了更通用的解決方案。

模型結構本身在不斷演進,以解決嵌入式裝置的資源限制。SqueezeNet就是透過擠壓模型架構的元素,從而顯著減少了模型大小和參數。MobileNet採用不同的架構方法,可達到與其他方法相當的top-1 精度,但所需要的乘法-加法運作卻少得多(圖8)。機器學習開發商Neurala使用自己的獨創方法打造出很小的模型,但仍然能夠達到很高的精度。

20190214_ML_TA31P8

圖8:Google的MobileNet等專用模型架構透過減少資源受限的嵌入式應用所需的矩陣乘法-加法運算,仍可提供具競爭力的精度。
(來源:TensorFlow)

結論

演算法和工具的融合減少了從頭建構機器學習模型的需要,開發人員利用越來越強大的框架和工具,更多地在預建模型上開發,來滿足他們自己的獨特需求;因此開發人員可以在流行的平台上佈署推理模型,以執行影像識別等簡單任務。延伸利用同樣的技術來建立有用的高性能生產模型絕非易事,但任何開發人員都很容易取得和使用那些技術。隨著專用AI硬體在低功耗系統中的發展,機器學習很可能成為嵌入式開發人員常用的工具。

本文同步刊登於電子工程專輯2019年2月刊雜誌

(參考原文:Applying machine learning in embedded systems,by Stephen Evanczuk;本文原刊於EE Times姊妹刊,ASPENCORE旗下Embedded網站)