天天看點

如何用FPGA加速卷積神經網絡(CNN)?

以下主要引用自西安郵電大學李濤老師關于連接配接智能和符号智能的報告,以及fpl2016上ASU的 Yufei Ma的文章和slide,推薦大家去讀下原文。

Scalable and Modularized RTL Compilation of Convolutional Neural Network onto FPGA

位址:http://fpl2016.org/slides/S5b_1.pdf

我做過一些計算加速的工作,個人感覺要入手先要想好幾個問題: 要加速的是什麼應用,應用的瓶頸是什麼,再針對這個瓶頸,參考前人工作選擇合适的方案。

過早地執着于fpga的技術細節(用hdl還是hls,用啥晶片,用啥接口)容易隻見樹木不見森林。現在software define network/flash/xxx,已然大勢所趨。之前開組會時跟同志們聊過,算法是綱,綱舉目張;軟體是媽,軟體是爹,軟體比基金委都親。是以推薦先把cnn的算法看一下,拿一些開源代碼跑一下經典的例子(lenet, alexnet, etc)看好輸入輸出,摸清算法。

比如以下是一個lenet的cpp和opencl的實作:

nachiket/papaa-opencl

位址:https://github.com/nachiket/papaa-opencl

以下圖檔源自Yufei Ma的Slide。

可以看到cnn算法主要由conv ,pooling,norm等幾個部分組成。工作時将image跟weight灌進去,最終得到預測結果。

接下來拿profiler(比如perf)去分析下軟體算法,找找熱點和性能瓶頸。在cnn裡面主要耗時的就是conv二維卷積了。性能瓶頸也主要在于卷積時需要大量乘加運算,參與計算的大量weight參數會帶來的很多訪存請求。

接下來考察下前人的工作和目前的灌水熱點。按理說這種大量的乘加運算用dsp應該不錯,但是在cnn中大家并不需要這麼大的位寬,有時候8位就夠了。dsp動辄32/64位的乘加器實在是浪費。于是乎大家就開始減位寬,多堆幾個運算單元。面對大量的訪存請求,大家就開始設計各種tricky的緩存了。

以下是大家的一些灌水方向:

于是就有了以下各路硬體設計:

有人照着dsp風格去設計加速器:

ceva也出了一系列面向CNN的IP:

有人用了脈動陣列或者Dataflow的風格:

有人設計了專用的晶片比如計算所的Cambricon:

還有的就是你提到的fpga。

所有的事情到了硬體層面實際上能用的手段也就有限了。不外乎堆資源和切流水兩招。再不然就是做一些bit level的小技巧,比如乘法器變查表之類的,這些技巧在很多二十年前的dsp教材裡面都描述得很細緻了,拿來用就好。比如這本書親測有效。

VLSI Digital Signal Processing System--Design and Implementation by Keshab

典型的fpga實作可以參考Yufei Ma的文章,不論是conv,還是pooling,依葫蘆畫瓢設計data path,切好流水,再想好狀态機加上控制信号。這些就看大家撸rtl的基本功了。

比如Conv子產品如下圖,主要拿一堆乘法器以及加法器樹搭好data path,切好流水,接着加上控制信号。

Pooling也是大同小異:

還有Norm:

最後把這些子產品通過router連接配接,外面再套一層控制子產品,封成ip就好了。

剩下的就是內建進你的系統(microblaze, nios還是arm,配好dma,寫好灌資料的驅動,這些就是各有各的道兒了)。推薦動手碼rtl前先寫好文檔,約定好端口,寄存器和軟體api,否則邊寫邊改容易亂。

整體來說,cnn這種應用流水線控制相對cpu簡單,沒有寫cpu的那一堆hazard讓人煩心,也不用寫彙編器啥的。太大的cnn放在fpga裡挺費勁,做出創新很難,但是fpga上寫個能用的lenet這種級别的cnn還是挺容易的。最後還可以依照慣例跟cpu比性能,跟gpu比功耗。

本文作者:Non

繼續閱讀