對於如機器翻譯、語言模型、觀點挖掘、問答系統等都依賴於RNN模型,而序列的先後依賴致使RNN並行化較爲困難,因此其計算速度遠沒有CNN那麼快。即便無論訓練的耗時程度,部署時候只要模型稍微大點,實時性也會受到影響。python
Tao Lei等人基於對LSTM、GRU等模型的研究,提出了SRU模型。在保證速度的前提下,準確度也是沒有多少損失。git
Tao Lei等人經過將每一時間步的主要計算部分,優化爲不要去依賴以前時間步的完整計算,從而可以容易的並行化。其結果示意圖如圖1.1。
github
ps:其中所謂的門就是將輸入向量鏈接到一個門層(向量),而後以sigmoid激活函數來計算當前的可流通量(通俗點說,就是獲得一個sigmoid的值向量,去與所須要的其餘狀態向量逐點相乘,即每一個維度上都有門控制)編程
在前饋神經網絡中,特別是矩陣相乘是最耗時的部分了,而若是是兩個矩陣逐點相乘,那計算量卻是少了好多。因此SRU的主要設計原理就是:門計算只依賴於當前輸入的循環。這樣就使得模型只有逐點矩陣相乘的計算是依賴於以前的時間步的。從而可以讓網絡容易的進行並行化。網絡
咱們基於參考文獻[1]來進行對應的結構展現:
多線程
SRU完整的公式以下:
ide
優化SRU和在cuDNN LSTM中優化LSTM的套路差很少,其中主要涉及到2點:函數
- 全部時間步的矩陣相乘能夠批次處理,這能夠明顯提高計算效率和GPU的使用。如將圖1.5中的式子1-3的三個權重矩陣合併成一個大矩陣。以下:
\[U^T= \begin{pmatrix} W \\ W_f \\ W_r \end{pmatrix} [x_1,x_2,...,x_n ]\]
其中n表示序列的長度,是將n個輸入向量聯合起來,即每一個\(x_i\)都是一個向量,\(U\in R^{n \times 3d}\),d表示SRU模塊中的隱藏層維度,當輸入是一個mini-batch爲k個序列的時候,U就是一個size爲\((n,k,3d)\)的張量;- 全部逐元素相乘的操做均可以放入一個kernel函數(cuda中的一個術語)中。若是不這麼作。那麼加法和sigmoid的激活函數就會分別須要調用各自獨立的函數,而且增長額外的kernel運行延遲和數據移動的開銷(這些都和gpu的計算有關,感興趣的能夠學習cuda)。
下面就是kernel函數的僞代碼(CUDA的),其中省略了輸入向量\(x_i\)自己的維度,只涉及到序列的長度,mini-batch的大小和SRU模塊中隱藏層的維度:
post
#python形式的cuda僞代碼,由於gpu編程的特性,因此都是基於標量進行具體的操做的 def kernel(xTensor, UTensor, bFVector, bRVector, c0Matrix): #xTensor:tensor for input, size is (n, k, d), means sequenceLength by minibatch by hiddenState #UTensor:tensor for weight, size is (n, k, 3d) means sequenceLength by minibatch by [W,Wf,Wr],3d #bFVector:vector for forget bias, size is (1,d) #bRVector:vector for reset bias, size is (1,d) #c0Matrix: matrix for SRU state,size is (k,d) means minibatch by hiddenState h, c = np.zeros([n,k,d]), np.zeros([n,k,d]) #one sample in minibatch for i in range(1,k): #one dimension in for j in range(1,d): c = c0Matrix[i,j] for l in range(1,n): W, Wf, Wr = UTensor[l,i,j], UTensor[l,i,j+d], UTensor[l,i,j+2d] f = sigmoid(Wf+bFVector[j]) r = sigmoid(Wr+bRVector[j]) c = f*c+(1-f)*W h = f*tanh(c)+(1-r)*xTensor[l,i,j] c[l,i,j] = c h[l,i,j] = h return h,c
如上面所示,經過GPU的網格等多線程操做,在外面2個for能夠實現並行操做,最內部的for是基於序列順序的,也就是在實現的時候,只有這個維度上是須要先後關聯的,而在minibatch這個維度和hiddenState這個維度均可以分開,也就是均可以並行,只有sequence維度須要先後管理啊,那麼這個維度放入寄存器中保持前後關係便可,而minibatch和hiddenState這兩個維度能夠當作是網格的x,y軸。
這就是矩陣逐元素相乘比矩陣相乘塊的好處:gpu特喜歡這種逐元素相乘的;對矩陣相乘的,若是矩陣大了,還須要作分塊處理。學習
經過如圖2.2的結構設計,在實驗上,能夠發現速度仍是有很可觀的提高的。
參考文獻: