1. 程式人生 > 其它 >效能優化記錄

效能優化記錄

技術標籤:演算法深度學習神經網路pytorch資料探勘

效能優化記錄

實驗中碰到了一些效能方面的瓶頸,諸如視訊記憶體OOM之類的錯誤,特開此貼拋磚引玉,為了後面更優雅的程式碼實現。

視訊記憶體優化

圖卷積相關領域通常有公式
H l + 1 = σ ( D − 1 2 A ^ D − 1 2 H l W l ) H^{l+1}=\sigma\left(D^{-\frac{1}{2}} \hat{A} D^{-\frac{1}{2}} H^{l} W^{l}\right) Hl+1=σ(D21A^D21HlWl)
其中

D − 1 2 A ^ D − 1 2 D^{-\frac{1}{2}} \hat{A} D^{-\frac{1}{2}}

D21A^D21

一般是預先計算好的,並以稀疏矩陣的方式儲存在Model裡面。

當節點數過多的時候,這個矩陣會佔用很多視訊記憶體,同時由於一些未知原因,用這個大矩陣乘上後面的H時,視訊記憶體會佔用。在我的場景下,6個G的sparsetensor ×一個幾十M dense tensor的時候,還額外需要4個多G的空間,才可以進行乘法,如果再加上backward需要儲存梯度等中間結果,空間複雜度有些高。

一種常規思路是,這個 Sparse Tensor,是一個固定值,不需要儲存梯度等操作。
D − 1 2 A ^ D − 1 2 D^{-\frac{1}{2}} \hat{A} D^{-\frac{1}{2}}

D21A^D21

所以可以切片分Batch,分為較小的矩陣來做乘法。

但是值得一提的是,Pytorch的Sparse Tensor 不支援切片操作,原因是其Sparse Tensor格式為Coo,(每一個元素需要用一個三元組來表示,分別是行號,列號,數值)。

暫時想到的解決辦法是,scipy.sparse 可以指定Sparse Mat 為Csr格式(按行壓縮),就可以按行切片。在scipy裡面切好片,把小片轉換為sparse tensor,得到sparse tensor的List

torch.cat([G.matmul(h) for G in Gs],dim = 0)

依次求解並cat在一起,可實現同樣的計算結果,但是乘法的過程中需要的視訊記憶體量大大減少。

值得注意的是,切分等操作一定要在_init_() 函式內實現,forward()函式應儘量簡潔,減少不必要的操作,可節省大量時間。

時間優化

視訊記憶體優化結束後,只是可以運行了,但是執行時間還有待優化。

除了演算法層面的複雜度優化之外,一個簡單的trick是通過

nvidia-sim -lms

來觀察 Volatile GPU-Util(GPU利用率)

一種不太好的情況是,GPU利用率在很低和很高之間反覆橫跳。

出現這種現象的一般原因是GPU遇到的資料的瓶頸,計算的過程中利用率很高,算完需要等資料輸入,這個期間利用率很低。

解決這種現象的方法也較為簡單,例如:增大DataLoader裡面的BatchSize,num_workers, 設定pin_memory = True

可以一定程度上緩解GPU需要乾等資料的現象。