論文閱讀筆記:Espresso

論文閱讀筆記:Espresso

摘要

這篇文章的主要貢獻是開源了一個基於C與CUDA的self-contained的神經網路量化的庫,利用這個庫能夠構建出在前向時實際能夠達到加速的程序。其中主要利用的技術是bit-packing、register-blocking以及基本的xnor,bit-count和bit-shift。在我實際測試中,能夠達到X10以上的加速比。這篇文章主要按照一下的順序介紹:

  • 基礎知識介紹
  • 論文要點回顧
  • 實驗結果

由於原文提供的代碼CmakeList.txt文件有些問題,且部分測試代碼並未公布。目前我還在整理代碼,後續我會將測試代碼即更新過的CmakeList.txt文件分享到我的項目文件夾


基礎知識介紹

Cmake語法

  • add_subdirectory():指定在指定的subdirectory中再繼續找CmakeList.txt
  • add_library():指定編譯目標是編譯出一個庫
  • find_package(CUDA):找某個包,例如CUDA

GEMM運算的定義

對於矩陣運算:

C=alphaAB+beta*C ,其中alpha,beta是實數,A,B,C是矩陣

可以利用SGEMM( TRANSA, TRANSB, M, N, K, alpha, A, LDA, B, LDB, beta, C, LDC)完成相應的運算。這樣其實可以通用地定義了矩陣的點積和加法等多種運算。推薦擴展閱讀這篇文章函數(其實並不是函數,而是一個規範)的參數解釋如下:

  • transa、transb:分別表示A,B是否需要轉置
  • M:A和矩陣C的行數
  • N:B和C的列數
  • K:A和B的列數
  • alpha,beta:實數係數
  • A,B,C:矩陣A,B,一般用 T **A表示,T屬於{uint8,uint64,float}
  • LDA,LDB,LDC:遞增步長,及第一維坐標增加1,相應的地址增量是多少,用於區別行列主序

CUDA中提供的高效率的函數/操作

  • bit-count:

    __device__ ? int __popcll ( unsigned long long int x )

    Count the number of bits that are set to 1 in a 64 bit integer.

  • 位運算
    • >>:算術右移
    • >>>:邏輯右移
    • <<,<<<:也類似的是算術、邏輯左移
    • ^:xnor即同或運算

論文要點回顧

實現量化的流程

  • bit-packing:將64個參數量化(即按符號轉化為0/1)之後放入一個64位的整型,整型中的每一位表示一個參數。
  • 基於bit-packing向量點積
    • 可以證明兩個個量化後向量的點積運算可以等價與異或運算與bitcount運算的組合。
    • 但需要滿足向量的長度是64的倍數
    • 注意:向量運算完的結果還是利用浮點型存儲
    • 量化GEMM:兩個矩陣相乘可以看成對應的行向量與列向量相乘,再求和。即可以轉化為之前定義的量化的向量積運算。
  • 由此可以按照一般的方式定義dense、conv、pool等層級

Hybrid DNNs:

  • 論文分別提供了CPU、GPU、 GPUOPT的代碼。
  • CPU上的全精度的kernel
  • GPU全精度的kernel
  • GPU上的BDNN的kernel

Memory layout:

  • 在內存中張量的存儲形式,類似矩陣中對行主序和列主序的約定
  • 在L維(channel)上進行bit-packing,在L==1時,在N維上
  • 這樣的設計在lifting、UNROLL的時候會比較快

input-binarizartion:

  • 即對輸入在bit-plane上展開,針對每個bit做運算,最終再合併
  • 以[0,255]的顏色為例,像素值若是127
  • 則變成0111,1111
  • 相乘的結果再根據位置做weight
  • 實際上沒有實現(參見src/kernel/pinputl.cu)

bit-packing帶來的問題:

  • 若不滿足64位填不滿的填-1可能造成很嚴重的誤差比如
  • 因此,嚴格要求進行矩陣運算的張量A(D,M,N,L)中M*N*L是64的倍數。由此對在此之上定義的層級、網路都有限制。但對一般的網路而言影響不大,因為一般都是64的倍數。

實驗結果

GEMM速度

  • configuration :1060,8192*8192相乘,Batchsize=1,Average on 10
  • 不包含設置時間,啟動時間
  • 0.8us pgemm 得到float數,9us得到量化數
  • 16.6us sgemm得到float數
  • 注意,當重複測試10次時速度較快,隨重複測試次數增加速度減慢

在minist上inference的性能

  • configuration: 1060,cuda 8.0、mnist、batch_size=512、average on 10000 iters、mlp(無卷積)
  • 不包含啟動時間、不包含數據讀取時間
  • pytorch上的全精度相同結構的對照:173.22 us/input
  • espresso:13 us/input

正確性驗證

  • 全精度全連接層(輸入1*2*3*1,權重2*6,輸出2*1)

輸入:35.000000 23.000000 34.000000 -43.000000 -45.000000 62.000000 | 113.000000 124.000000 121.000000 -7.000000 -21.000000 -46.000000 |權重:-108.000000 -109.000000 105.000000 | 98.000000 -83.000000 -47.000000 |輸出:-6110.000000 -9796.000000 |正確

  • 量化的全連接層(對輸入的形狀是有要求的!)

經測試(在test.cu中)正確

推薦閱讀:

稀疏編碼在推薦系統中的應用
細粒度分類SCDA&Recurrent Attention Convolutional Neural Networ
每周一個機器學習小項目002-卷積網路實現與圖片
神經網路梯度與歸一化問題總結+highway network、ResNet的思考

TAG:神經網路 | 讀書筆記 |