cuDNN 5对RNN模型的性能优化
原文:Optimizing Recurrent Neural Networks in cuDNN 5
作者:Jeremy Appleyard
翻譯:趙屹華 審校:劉翔宇
責編:周建丁(zhoujd@csdn.net)
在GTC2016大會上,NVIDIA發(fā)布了最新版本的深度學習開發(fā)包,其中包括了cuDNN 5。第五代cuDNN引入了新的特性,提升了性能,并且支持最新一代的NVIDIA Tesla P100 GPU。cuDNN的新特性包括:
- 使用Winograd卷積算法,計算前向、后向卷積速度更快;
- 支持3D FFT Tiling;
- 支持空間轉移網(wǎng)絡;
- 更優(yōu)的性能,在Pascal GPU上使用半精度函數(shù)節(jié)省了內存空間;
-
支持用于序列學習的LSTM遞歸神經網(wǎng)絡,速度提升6倍。
圖1:cuDNN 5 + Torch speedup vs. Torch-rnn ,M40, Intel:emoji: Xeon:emoji: Processor E5-2698。網(wǎng)絡模型A:RNN維度2560,輸出維度2560,1層,序列長度200,批大小為64。網(wǎng)絡模型B:RNN維度256,輸入維度64,3層,批大小為64。網(wǎng)絡模型C:RNN維度256,輸入維度256,1層,批大小為32,序列長度1000。
cuDNN 5的新特性之一就是它可以支持遞歸神經網(wǎng)絡(Recurrent Neural Networks)。RNN是各個領域用于序列學習的強大工具,從語音識別到圖像配字。若想簡單了解RNNs,LSTM和序列學習的內容,我推薦閱讀Tim Dettmers最近的文章Deep Learning in a Nutshell: Sequence Learning ,更深入的理解可以閱讀Soumith Chintala的文章Understanding Natural Language with Deep Neural Networks Using Torch。
我對cuDNN 5支持RNN的能力感到非常激動;我們投入了大量的精力來優(yōu)化它們在NVIDIA GPU上的性能,我在本文中將會介紹這些優(yōu)化的一部分細節(jié)。
cuDNN 5支持四種RNN模式:ReLU激活函數(shù)模式,tanh激活函數(shù)模式,門控遞歸單元(Gated Recurrent Units)和長短期記憶(LSTM)。在這類,我將以LSTM網(wǎng)絡的性能為例,但大多數(shù)的優(yōu)化可以用在任意RNN模型。
第一步:優(yōu)化單次迭代
下列方程組表示了數(shù)據(jù)如何在LSTM單元正向傳播。圖2展示了LSTM單元的示意圖。
從計算的角度來看,這里需要8次矩陣的乘法運算(GEMM)—— 有四次對輸入i,有四次對輸入h —— 以及大量逐點運算。
這個案例分析的出發(fā)點是LSTM的逐步實現(xiàn)。對于每次迭代的每一層計算,系統(tǒng)調用cuBLAS sgemm分別來完成那8次GEMM運算。人工編寫的CUDA內核調用每個逐點運算。這種方法的偽代碼如下所示:
for layer in layers:for iteration in iterations:perform 4 SGEMMs on input from last layerperform 4 SGEMMs on input from last iterationperform point-wise operations我在Tesla M40 GPU上逐步、逐層地記錄了運行耗時,作為對照數(shù)據(jù)。我的對照LSTM模型有512個隱藏單元,每批次的樣本數(shù)為64.對照組的性能很一般,在M40上只達到了大約350 GFLOPs。這個GPU的峰值性能是6000 GFLOPs,因此還有很大的優(yōu)化空間。我們開始吧。
優(yōu)化1:組合GEMM操作
GPU有非常高的浮點數(shù)吞吐量峰值,但是需要大量的并行化才能達到這個峰值。你設計的任務越是并行化,能達到的性能越好。測試這段LSTM代碼后發(fā)現(xiàn),GEMM操作所用的CUDA thread block個數(shù)遠遠少于GPU的SM個數(shù),也就是說GPU遠未被充分利用。
GEMM往往在輸出矩陣維度上做并行化,每個線程計算很多輸出元素。在這里,8個輸出矩陣的每一個都有512x64個元素,只用到4個thread block。理想情況下block的運行個數(shù)可以遠大于GPU的SM個數(shù),需要最大化這個內核的理論占用值,至少達到每個SM有4個block(或者總共96個)。(參見 CUDA Best Practices guide for more on occupancy)
如果n個獨立的矩陣乘法共用同一份輸入數(shù)據(jù),那么它們可以被合并為一個大的矩陣乘法,輸出結果擴大n倍。因此,第一個優(yōu)化方法就是把遞歸階段的四次W矩陣操作合并為一次,并且把輸入數(shù)據(jù)的四次W矩陣操作也做合并。我們剩下了兩個矩陣乘法,而不是原來的八個,但是每次結果擴大了四倍,并行能力擴大四倍(每個GMM有16個block)。這種優(yōu)化在大部分框架中都很常見:很簡單的變化確帶來了顯著的性能提升:代碼運行速度大約翻倍。
優(yōu)化2:流式GEMMS
盡管GEMMs被合并了,性能仍舊收到缺少并行的限制:盡管從4個提升到16個,但是我們的目標是至少96個。剩余的兩個GEMM相互獨立,因此它們可以用CUDA stream并行計算。這又將并行的block個數(shù)翻倍,達到了32個。
優(yōu)化3:融合逐點運算
圖3顯示目前大部分的時間消耗在了逐點運算上。沒必要在獨立的內核中進行這些;將它們融合到同一個內核可以減少數(shù)據(jù)在全局內存中的傳遞,并且大大減少了內核加載的開銷。
至此,我非常欣慰地看到單次迭代的性能改善:大部分的計算量在于GEMM,并且盡可能地做了并行計算。這種實現(xiàn)方法比對照組快了5倍,但是仍有提升的余地。
for layer in layers:for iteration in iterations:perform sgemm on input from last layer in stream Aperform sgemm on input from last iteration in stream Bwait for stream A and stream Bperform point-wise operations in one kernel第二步:優(yōu)化多次迭代
在RNN模型中,單次迭代的操作會被重復很多次。這也意味著很有必要讓這些重復操作有效率地執(zhí)行,即使需要先增加一部分開銷。
優(yōu)化4:預轉置權重矩陣
在進行一次GEMM計算時,標準的BLAS接口允許我們對兩個輸入矩陣的任意一個做轉置。兩個矩陣是否轉置的四種組合中,其中某幾種組合會比其它幾種算得更快或者更慢。這取決于方程組到計算過程的映射方式,可能使用了較慢版本的GEMM。通過預先對權重矩陣的轉置操作,每一次迭代會略微快一些。盡管多了一步轉置操作的開銷,但是開銷也不大,所以如果在多次迭代中用到了轉置矩陣,也是值得的。
優(yōu)化5:合并輸入GEMMs
許多情況下,在RNN計算開始之時所有的輸入就已經就緒。也就是說對這些輸入的矩陣運算操作可以立即開始。這也意味著它們能夠被合并為更大的GEMMs。盡管起初這似乎是件好事(合并的GEMMs有更好的并行化),遞歸GEMM的傳遞依賴于輸入GEMMs的完成度。因此需要我們做出取舍:合并輸入GEMMs使得操作的并行化程度更高,但也阻止了遞歸GEMMs的過程重疊。這里的最佳策略往往取決于RNN的超參數(shù)。在我們的例子里,合并兩個輸入GEMM是最合適的。
for layer in layers:transpose weight matricesfor iteration in iterations / combination size:perform sgemm on combined input from last layer in stream Afor sub-iteration in combination size:perform sgemm on input from last iteration in stream Bwait for stream A wait for stream Bfor sub-iteration in combination size;perform pointwise operations in one kernel第三步:優(yōu)化多個層次
最后一步是考慮層與層的優(yōu)化。這里仍然有大量的并行化空間。圖4顯示了RNN的依賴關系圖。某一層的第n次迭代僅依賴于該層的第n-1次迭代和前一層的第n次迭代,因此有可能在前一層結束之前開始下一層的計算。這相當有用;如果網(wǎng)絡有兩層,則并行能力提升一倍。
從一層網(wǎng)絡到四層網(wǎng)絡,吞吐量大約提升了1.7倍:從2.3TFLOPs到3.9TFLOPs。此時,并行化所帶來的收益已經有限了。相比最初只有4個block的實現(xiàn)方法,這種方法可以同時運行128個block。這足以充分利用M40的資源,達到近70%的峰值浮點性能,運行速度比原來的快10倍。
下面的表格顯示了我所描述的每一次優(yōu)化之后的性能,以及相比于對照代碼的效率提升。
| Baseline | 349 | (1.0x) |
| Combined GEMMs | 724 | 2.1x |
| GEMM Streaming | 994 | 2.8x |
| Fused point-wise operations | 1942 | 5.5x |
| Matrix pre-transposition | 2199 | 6.3x |
| Combining Inputs | 2290 | 6.5x |
| Four layers | 3898 | 11.1x |
反向傳播
反向傳播梯度與值的正向傳播非常相似。一旦梯度被傳播,權重值將會被更新:不再有任何遞歸性的依賴。這使我們得到了一個非常大、非常高效的矩陣乘法。
總結
為了得到最好的性能,你需要經常要更多地提高并行性,而不是直截了當?shù)貙崿F(xiàn)方程。在cuDNN,我們將這些優(yōu)化用在四種常見的RNN模型。因此如果你正在序列學習中用到這些RNN模型,我強烈推薦你使用cuDNN 5。
總結
以上是生活随笔為你收集整理的cuDNN 5对RNN模型的性能优化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 人脸识别技术大总结(1)——Face D
- 下一篇: 给ADAS泼冷水?不,是客观评价