1. 程式人生 > >面向嵌入式 AI 晶片上視覺任務的神經網路設計

面向嵌入式 AI 晶片上視覺任務的神經網路設計

隨著這幾年神經網路和硬體(GPU)的迅猛發展,深度學習在包括網際網路,金融,駕駛,安防等很多行業都得到了廣泛的應用。然而在實際部署的時候,許多場景例如無人駕駛,安防等對裝置在功耗,成本,散熱性等方面都有額外的限制,導致了無法大規模應用深度學習解決方案。

雷鋒網 AI 研習社直播課上地平線初創人員黃李超介紹了 AI 晶片的背景以及怎麼從演算法角度去設計適合嵌入式平臺高效的神經網路模型,並應用於視覺任務中。

提綱

  1. 介紹當前 AI 晶片概況,包括現有的深度學習硬體發展情況,以及為何要為神經網路去設計專用晶片。

  2. 從演算法角度,講解如何設計高效能的神經網路結構,使其既滿足嵌入式裝置的低功耗要求,又滿足應用場景下的效能要求。

  3. 分享高性價比的神經網路,在計算機視覺領域的應用,包括實時的物體檢測,語義分割等。

當前 AI 晶片發展的現狀

可以首先閱讀《AI晶片的歷史和現狀》。大家都知道,最早神經網路是執行在 CPU 上的。但是 CPU 並不能非常高效地去執行神經網路,因為 CPU 是為通用計算而設計的,而且其計算方式以序列為主——雖然一些執行指令可以同時處理較多資料。除此之外,CPU 在設計上也花了很多精力去優化多級快取,使得程式能夠相對高效地讀寫資料,但是這種快取設計對神經網路來講並沒有太大的必要。另外,CPU 上也做了很多其他優化,如分支預測等,這些都是讓通用的運算更加高效,但是對神經網路來說都是額外的開銷。所以神經網路適合用什麼樣的硬體結構呢?

640?wx_fmt=png

在講這個問題之前,我們先從神經網路的特性說起:

第一,神經網路的運算具有大規模的並行性,要求每個神經元都可以獨立平行計算;

第二,神經網路運算的基本單元主要還是相乘累加,這就要求硬體必須有足夠多的運算單元;

第三,神經元每一次運算都會產生很多中間結果,這些中間結果最後並不會複用,這就要求裝置有足夠的頻寬。一個理想的裝置,它應該有就比較大的片上儲存,並且頻寬也要足夠,這樣才能放下網路的權重和網路的輸入;

第四,由於神經網路對計算的精度並沒有那麼敏感,所以在硬體設計的時候可以使用更簡單的資料型別,比如整型或者 16bit 的浮點數。因此,這幾年大家使用的神經網路解決方案,都是 CPU+比較適合於神經網路運算的硬體(可以是 GPU、DSP、FPGA、TPU、ASIC 等)組成異構的計算平臺。

最常用的方案是 CPU+GPU,這個是深度學習訓練的一個標配好處是算力和吞吐量大,而且程式設計比較容易,但是它存在的問題是,GPU 的功耗比較高,延遲比較大,特別是在應用部署領域的場景下,幾乎沒有人會用伺服器級別的 GPU。

應用場景下用的更多的方案是 FPGA 或者 DSP它們功耗比 GPU 低很多,但是相對的開發成本較大。DSP 依賴專用的指令集,它也會隨著 DSP 的型號變化有所差異。FPGA 則是用硬體語言去開發,開發難度會更大。其實也有一起企業會用 CPU+FPGA 去搭建訓練平臺,來緩解 GPU 訓練部署的功耗問題。

雖然剛剛提了很多神經網路加速的解決方案但是最合適的還是 CPU+專用晶片我們需要專用 AI 晶片的主要原因是: 雖然現在的硬體工藝不斷在發展,但是發展的速度很難滿足深度學習對計算力的需求。其中,最重要有兩點:

第一,過去人們認為電晶體的尺寸變小,功耗也會變小,所以在相同面積下,它的功耗能保持基本不變,但其實這條定律在 2006 年的時候就已經終結了

第二點,我們熟悉的摩爾定律其實在這幾年也已經終結了。

我們可以看到晶片在這幾年工藝的發展變得越來越慢,因此我們需要依靠專門的晶片架構去提升神經網路對計算平臺的需求。

640?wx_fmt=png

最著名的的一個例子就是 Google 的 TPU,第一版在 2013 年開始開發,歷時大約 15 個月。TPU 裡面使用了大量乘法單元,有 256*256 個 8 位的乘法器;片上有 28MB 的快取,能夠儲存網路的引數和輸入。同時,TPU 上的資料和指令經過 PCN 匯流排一起發過來,然後經過片上記憶體重新排布,最後計算完放回緩衝區,最後直接輸出。第一版 TPU 有 92TOPS 的運算能力,但是隻針對於神經網路的前向預測,支援的網路型別也很有限,主要以多層感知器為主。

而在第二版的 TPU 裡面,已經能夠支援訓練、預測,也能夠使用浮點數進行訓練,單個 TPU 就有 45TFLOPS 的算力,比 GPU 要大得多。

640?wx_fmt=png

其實我們地平線也研發了專用的 AI 晶片,叫做 BPU,第一代從 2015 年開始設計,到 2017 年最終流片回來,有兩個系列——旭日和征程系列,都針對影象和視訊任務的計算,包括影象分類、物體檢測、線上跟蹤等,作為一個神經網路協處理器,側重於嵌入式的高效能、低功耗、低成本的方案。

640?wx_fmt=png

比較值得一提的是,我們在我們的 BPU 架構上設計了彈性的 Tensor Core,它能夠把影象計算所需要的基本單元,常用操作例如卷積、Pooling 等硬體化,非常高效地去執行這些操作。中間通過資料路由橋(Data Routing Bridge)從片上讀取資料,並負責資料的傳輸和排程,同時,整個資料儲存資源和計算資源都可以通過編輯器輸出的指令來執行排程,從而實現更靈活地演算法,包括各種型別的模型結構以及不同的任務。

總的來說,CPU+專用硬體是當前神經網路加速的一個較好的解決方案。針對專用硬體,我們可以根據功耗、開發容易度和靈活性進行排序,其能耗跟其他兩者(開發容易度和靈活性)是相互矛盾的——晶片的能效比非常高,但是它的開發難度和靈活度最低。

如何設計高效的神經網路

說了這麼多硬體知識,接下來我們討論怎麼樣從演算法角度,也就是從神經網路設計的角度去談怎麼加速神經網路。相信這個也是大家比較關心的問題。

我們先看 AI 解決方案,它從資料處理的方式可以分為雲端 AI 和前端 AI。雲端 AI 是說我們把計算放在遠端伺服器上去執行,然後把結果傳到本地,這個就要求裝置能夠時刻連線網路。前端 AI 是指裝置本身就能夠進行計算,不需要聯網,其在安全性、實時性、適用性都會比雲端 AI 更有優勢,而有一些場景下,也只能使用嵌入式的前端 AI 去解決。

嵌入式前端的場景落地難點在於功耗、成本和算力都是有限的。以網路攝像頭即 IP Camera 為例,它通過網線供電,所以功耗只有 12.5 瓦,而常用的嵌入式 GPU——Nvidia TX2,為 10-15 瓦。另外這個 TX2 雖然在計算資源、算力方面都比較強,能達到 1.5T,但它的價格是 400 美元,對於很多嵌入式方案來說都是不可接受的。因此要做好前端嵌入式方案,我們需要在給定的功耗、算力下,最大限度地去優化演算法和神經網路模型,達到符合場景落地的需求。

640?wx_fmt=png

我們加速神經網路的最終目標是:讓網路在保持不錯的效能下,儘量去降低計算代價和頻寬需求。常用的一些方法有:網路量化、網路減支和引數共享、知識蒸餾以及模型結構優化,其中,量化和模型結構優化是目前看來最有效的方式,在業界也得到比較廣泛的應用。接下來會重點講一下這幾個方法。

第一個是量化,它是指將連續的變數通過近似從而離散化其實在計算機中,所有的數值表示都是離散化的,包括浮點數等,但是神經網路中的量化,是指用更低 bit 的數字去執行神經網路,而是不是直接使用 32bit 的浮點數(去執行神經網路)。近幾年的一些研究發現,其實數值表達的精度對神經網路並沒有太大的影響,所以常用的做法是使用 16bit 的浮點數去代替 32bit 的浮點數來進行計算,包括訓練和前項預測。這個在 GPU 以及 Google 的 TPU 第二代中已經被廣泛採用。此外,我們甚至發現,用半精度浮點數去訓練資料,有時候還能得到更好的識別效能。實際上,量化本身就是對資料集正則化的一種方式,可以增加模型的泛化能力。

640?wx_fmt=png

此外,我們還可以將資料精度進行進一步壓縮使用,將 8 bit 的整數作為計算的計算單元,包括訓練和前項預測,這樣頻寬就只有 32bit 浮點數的四分之一,這類方法近年來也有不少工作,且已被業界所採用,比如 Tensorflow Lite 已經支援訓練時模擬 8bit 整數的運算,部署時真正採用 8 bit 整數去代替,其在浮點和影象分類的效能上相當。我們地平線也有類似的工作,訓練工具也是用 Int 8 bit 去訓練、預測,並且我們的晶片支援 MXNet 和 TensorFlow 框架訓練出來的模型。

能不能把精度壓得更低呢,4 bit、2bit 甚至 1 bit?也是有的,但是會帶來精度的極大損失,所以沒被採用。

量化神經網路模型分為神經網路的權重量化、神經網路特徵的量化。權重量化對於結果輸出的損失比較小,特徵量化其實對模型的輸出損失會比較大,另外,大模型和小模型的量化造成的損失也不一樣,大模型如 VGG16、AlexNet 這種網路模型,量化後幾乎沒有損失;而小模型則會有一些損失。現在 8bit 引數和特徵量化可以說是一個比較成熟的方案,基本上可以做到跟浮點一樣好,並且對硬體也更加友好。下面這個表,是在 Image Net 資料集上的進行的量化結果的評測,也是 Google Tensorflow Lite 的量化方案與我們地平線內部的量化方案的一個對比。

640?wx_fmt=png

我們可以看到,無論是哪一家的方案,損失其實都非常小,其中,小模型 MobileNet 0.25 在 Image Net 的損失方面,Google 在 1.6% 左右,而我們的量化方案能夠維持在 0.5% 以內。同時我們這個量化方案在 2016 年就已經成熟了,而 Google 的去年才放出來,從這個角度上講,我們這方面在業界內是領先的。

除了量化,模型加速還可以通過模型剪枝和引數共享實現一個典型的案例就是韓鬆博士的代表性工作——Deep Compression。減支可以是對整個卷積核、卷積核中的某些通道以及卷積核內部任意權重的剪枝,這裡就不多說,大家有興趣可以去看一下原論文。

640?wx_fmt=png

與網路量化相比,剪枝和引數共享從應用角度上來看,並非一個好的解決方案。因為關於剪枝方面的研究,現在這些論文在大模型上做的比較多,所以在大模型上效果比較好,但是在小模型上的損失比較大,當然我們這裡說的小模型是比 MobileNet 等模型更小的一些模型。另外,剪枝所帶來的資料稀疏(任意結構稀疏),通常需要一個明顯的稀疏比例才能帶來一個實質性的的加速。結構化的稀疏加速比相對更容易達到,但是結構化的稀疏比較難訓練。同時從硬體角度上講,如果要高效地執行稀疏化的網路結構或者帶共享的網路,就要專門設計硬體去支援它,而這個開發成本也比較高。

知識蒸餾也是很常用的壓縮模型方法它的思想很想簡單,用一個小模型去學習一個大模型,從而讓小模型也能實現大模型的效果,大模型在這裡一般叫 Teacher net,小模型叫 Student net,學習的目標包括最終輸出層,網路中間的特徵結果,以及網路的連線方式等。知識蒸餾本質上是一種遷移學習,只能起到錦上添花的作用,比直接用資料去訓練小模型的效果要好。

640?wx_fmt=png

最後講一講模型結構優化,它是對模型加速最有效的方式下圖可以看到從最初的 AlexNet 到今年的 MobileNetV2,引數已經從原來的 240MB 縮小到 35MB,模型的計算量也有了一定的減少,但是在影象分類的準確率上,從 57% 提到到了 75%,模型結構優化最直接的方式就是,有經驗的工程師去探索小模型結構,而這些年來也有通過機器去進行搜尋模型結構的工作。

640?wx_fmt=png

接下來講一下在模型結構優化中,怎麼去設計一個高效的神經網路結構,它需要遵循的一些基本原則。

640?wx_fmt=png

首先,要糾正幾個誤區:第一,是不是小模型跑得比大模型快?這個顯然是不成立,我們可以看下圖中 Google Net 和 AlexNet 箭頭指向的方向,AlexNet 顯然大一些,但它比 Google Net 跑得快一些,計算量更小一些。第二,網路計算量小是不是就跑得更快呢?其實也不是,因為最終的執行速度取決於計算量和頻寬,計算量只是決定執行速度的一個因素。

640?wx_fmt=png

所以說,一個好的、跑起來比較快的神經網路結構,必須要平衡計算量和頻寬的需求,這裡我們跟隨 ShuffleNetV2 論文的一些觀點——雖然這個並不是我們的工作,但是文章寫得很好,其中有不少觀點也和我們在模型結構優化過程中得到的一些結論是一樣的。在分析的時候,我們以 1x1 的卷積為例,假設所有的引數和輸入輸出特徵都可以被放到快取當中,我們需要特別關注的是卷積的計算量——用 FLOPs(Float-Point Operations) 即浮點數的操作次數去表述,頻寬用 MAC(Memorry Access Cost) 即記憶體訪問的次數去表示。同時,我們需要額外關注的是頻寬和計算量的比。對於嵌入式的裝置來講,頻寬往往是瓶頸。拿 Nvidia 的嵌入式平臺 TX2 為例,它的頻寬比上計算力大概是 1:26。

640?wx_fmt=png

第一,要分析一下輸入通道數、輸出通道數以及輸入大小對頻寬和計算量的影響,ShuffleNetV2 提出的準則第一條是,在同等的計算量下、輸入通道數和輸出通道數下,頻寬是最節省的公式為:640?wx_fmt=jpeg。其實輸入通道、輸出通道和輸入大小任意一個過小的話,對頻寬都會產生不友好的影響,並且會花很多時間去讀取引數而不是真正去計算。

640?wx_fmt=png

第二,卷積中 Group 的個數又對效能有什麼影響呢?ShuffleNetV2 這篇文章指出,過多的 Group 個數會增加單位計算量的頻寬,我們可以看到計算量的頻寬和 Group 的個數近似為正比從這一點上來看,MobileNet 裡頭的 Depthwise Convolution 實際上是一個頻寬需求量非常大的操作,因為頻寬和計算量的比值接近於 2。而實際運用的時候,只要頻寬允許,我們還是可以適當增加 GROUP 個數來節省計算量,因為很多時候,頻寬實際上是沒有跑滿的。

640?wx_fmt=png

第三,ShuffleNetV2 說到的第三條準則是,過度的網路碎片化會降低硬體的並行度,這就是說,我們需要思考 operator 的個數對於最後執行速度的影響。其實 ShuffleNetV2 這種觀點不夠嚴謹,準確來說,我們需要把 operator 分為兩類:一類是可以並行的(如左圖),兩個框可以平行計算,concat 的記憶體也可以提前分配好;另一類是必須序列去進行計算,沒有辦法並行的 operator 則會降低硬體的並行度。對於硬體來說,可以並行的 operator 可以通過指令排程來充分利用硬體的並行能力。從這條準測上看,DenseNet 這種網路結構在應用實際上非常不友好。它每次的卷積操作計算量很小,而且每次計算需要依賴先前所有的結果,操作之間不能並行化,跑起來很慢。另外,太深的網路跑起來也比較慢。

最後,ShuffleNetV2 也指出,Element-wise 對於速度的影響也是不可忽視的——一定程度上可以這麼說。因為 Element-wise 雖然計算量很小,但是它的頻寬需求比較大。其實如果把 Element-wise 的操作和卷積結合在一起,那麼 Element-wise 的操作對最後頻寬帶來的影響幾乎為 0。常用的例子是,我們可以把卷積、啟用函式和 BN 放在一起,這樣的話,資料可以只讀一次。

講到這裡,我們做一下總結設計高效的神經網路,我們需要儘可能讓 operator 做並行化計算,同時去減少頻寬的需求因為最後的速度由頻寬和計算量共同決定的,所以這兩者哪個存在瓶頸,都會制約執行速度。

高效神經網路的自動設計

過去優化神經網路結構往往依靠非常有經驗的工程師去調參,我們能不能直接讓機器去自動搜尋網路結構呢?

640?wx_fmt=png

其實也是可以的,比如說 Google 前段時間進行一項工作叫 NASNet,就是通過強化學習,把影象分類的準確率和網路本身的計算量作為反饋,去訓練網路結構生成器,讓網路結構生成器去生成比較好的網路結構。

640?wx_fmt=png

Google 的這項工作大概用了 450 GPUs 和 4 天,搜尋出了效能和計算量都還不錯的網路結構,這兩個圖是網路結構的基本單元。然而,通過我們之前的分析,它這兩個基本單元肯定是跑不快的,因為操作太零碎,而且很多操作沒有辦法並行。所以對於搜尋網路結構,考慮真實的執行速度是一個更合適的選擇。所以就有了後續的工作,叫做 MnasNet。

640?wx_fmt=png

Google 這次直接把手機上的執行速度作為強化網路的反饋。我們可以看到用這種方法搜尋出來的網路結構合理很多,同時效能也比之前稍微好一些。

640?wx_fmt=png

在同時期,我們也有進行了類似的工作——RENAS,它實際上借鑑了 NASNet,但我們側重於去解決搜尋效率低下的問題。和 NASNet 不同,我們採用進化演算法搜尋網路結構,同時用強化學習去學習進化的策略。工作方式的連結放在上面,大家感興趣也可以去看一下。

640?wx_fmt=png

RENAS 的一個優點是,它的網路搜尋的效率要高得多:我們用了 4GPU 和 1.5 天就搜出比 NASNet 更好的結構。不過它的缺點也跟 NASNet 一樣,都用了計算量作為一個衡量指標,因此它搜尋出來的所有結果只是計算量低,但是執行速度並不一定特別快。

演算法+硬體在計算機應用上的一些成果

講了這麼多,最後我們可以展示一下,經過優化後的網路在主流視覺任務上的應用效果:

最常見的影象級別的感知任務比如影象分類、人臉識別等,由於它們輸入比較小,所以整體計算量並不大,對於網路的效率要求也沒有那麼苛刻。而在影象分類以外的工作比如物體檢測 語義分割等等,它們的輸入比影象分類大得多,往往在 1280x720 這種解析度或者更大的解析度。MobileNet 或者 ShuffleNet 在這個解析度下的計算量,還是挺高的。另外在物體檢測、語義分割的問題當中,尺度是一個要考慮的因素,所以我們在設計網路的時候,要針對尺度問題做一些額外的配置,包括並引入更多分支,調整合適的感受野等等。

640?wx_fmt=png

對於物體檢測、語義分割任務,我們專門設定了一個網路結構,它的大概樣子如上圖中的右圖所示,特點是我們使用了很多跨尺度的特徵融合模組,使網路能夠處理不同尺度的物體,另外,我們這個網路的基本單元都遵循了簡單、高效的原則,用硬體最友好、最容易實現的操作去組建基本模組。

640?wx_fmt=png

我們在一些公開資料集上測試了這個模型的效能,主要有兩個資料集,一個是 Cityscapes,它是語義分割資料集,影象解析度很大,原始影象解析度為 2048x1024,標註有 19 類。在這些資料集上,我們的網路跟曠世最新的一篇論文 BiSeNet 做比較——BiSeNet 是目前能夠找到的在語義分割領域中速度最快的一個方法,它的計算在右邊的表格中,其中的計算模型*Xception39 在 640x320 的解析度,大概需要 2.9G 的計算量,而我們的一個小模型在同等規模的輸入下,達到幾乎一樣的效果,只需要 0.55G 的計算量。

同時,在效能上,——語義分割裡面我們用 mIoU 作為指標,在 2048x1 024 的解析度下,我們稍微大一點點的網路跟 Xception39 非常接近。我們的網路還在 KITTI 資料集上做了一個測試,它的解析度大概為 1300x300 多,特別是車和人的檢測任務上所表現出來的效能,和 Faster RCNN,SSD,YOLO 等常見的方法的模型相比,具有非常高的價效比。

下面展示一下我們演算法在 FPGA 平臺上實施的一個 Demo。

我們這個網路同時去做物體檢測和語義分割,以及人體姿態估計。FPGA 也是我們第二代晶片的一個原型,第二代晶片年底會流片回來,單塊晶片效能會是 FPGA 這個平臺的 2-4 倍。這個資料是在美國的拉斯維加斯採集的,除了人體姿態的檢測,我們還做了車載三維關鍵點定位,它的執行速度可以達到實時,也作為我們重要的產品在車廠中使用。Demo 只是我們工作的冰山一角,我們還有很多其他的方向的工作,比如智慧攝像頭、商業場景下的應用,目標是為萬物賦予智慧,從而讓我們的生活更美好。

【文章摘自機器學習研究會】

輕輕一掃  歡迎關注~

640?wx_fmt=jpeg

如果覺得好,請

轉發

轉發

轉發