壞了,我的RTX 3090 GPU在對我唱歌!
机器之心發表於2024-05-13
在一個昏暗的機箱裡,一臺 RTX 3090 GPU「唱」著經典英語兒歌《一閃一閃亮晶晶》(Twinkle,Twinkle,Little Star)的旋律。這不是靈異事件,也不是科幻電影,而是一位 AI 科學家在「整活」。這位科學家名叫 Vrushank Desai。據他介紹,機箱中的旋律是由 GPU 的電感線圈發出來的。GPU 如何發出這種聲音,別急,Desai 在 X 上給出瞭解釋。事情的起因是這樣的,今年年初,Desai 花了幾個月的時間學習 GPU 程式設計,並嘗試最佳化《Diffusion Policy》論文中的推理。在此過程中,Desai 將去噪 U-Net 的推理時間提高到 Pytorch eager 模式的約 3.4 倍、Pytorch compile 模式的 2.65 倍。不過這次嘗試讓 Desai 印象最深的事情,當屬這個意外發現,即 RTX 3090 GPU「唱」起了《一閃一閃亮晶晶》。雖然這個發現和擴散推理毫無關係,但在 Desai 看來,卻是最有趣的事情。Desai 在 X 上激動的表示:「我能夠讓 RTX 3090 電感線圈使用核心(GPU 程式設計)在正確的頻率下調節功耗來播放《一閃一閃亮晶晶》。每次核心啟動都會觸發 GPU 的 DC-DC 降壓電感中的湧流。由電流變化引起的洛倫茲力使線圈輕微移動,如果進一步控制核心發射頻率,使線圈震盪,就能把噪音控制在可聽到的範圍內。」不幸的是,Desai 不能讓裝置發出低於 2000Hz 的聲音,因此《一閃一閃亮晶晶》音符都向上移動了好幾個八度。進一步的,Desai 在部落格中詳細描述了自己發現 RTX 3090 發出聲音的過程,我們接著往下看。Desai 表示,在 GPU 中,電壓調節模組(VRM)負責將輸入功率的 12V 電壓降至約 1V,以驅動 GPU 核上的電晶體,要求是 VRM 輸出的電壓必須非常純淨。VRM 利用複雜的電力電子技術可以提供這種純淨的輸出,其中一部分轉換過程涉及電感器,這些電感器本質上充當低通濾波器。當 GPU 核的負載發生顯著波動時,這些電感器會產生快速振盪的磁場(與電流變化率 dI/dT 成正比),進而誘發洛倫茲力,使線圈振動。這種現象就是導致 GPU 線圈噪音的原因。然而,這一發現,並不能讓 GPU 唱歌。接著,Desai 發現了一個有趣的現象,即與執行 CUDA 圖形或自定義核心相比,Pytorch Eager 模式會導致更響的 GPU 線圈噪音 ——Desai 表示甚至能聽到程式碼執行的聲音!這個發現讓 Desai 感到非常困惑,因為 nvidia-smi 顯示加速模式比 Eager 模式多消耗約 40W 的功率,通常來說更高的負載會產生更大的噪音。Desai 推測這可能是因為 Eager 模式在核心啟動之間有更長的延遲,導致 GPU 核心負載的變化更大,從而在 GPU 的電感器中產生更強的磁場振盪。為了測試這一點,Desai 編寫了一個核心,該核心可以從全域性記憶體中執行大量載入,這是一項非常耗能的操作,並改變核心啟動之間的持續時間,Desai 發現確實可以透過這種方式控制線圈噪音!Desai 開始沉迷於這個發現,即讓 GPU 線圈發聲的能力,並編寫了一個核心程式來演奏特定的音符,因而用 RTX 3090 演奏《一閃一閃亮晶晶》的曲子誕生了。不幸的是,發出的聲音無法達到較低的頻率,所以所有音符都被提高了好幾個八度。想要讓自己的 GPU 唱歌的小夥伴可以參考以下程式碼:程式碼地址:https://github.com/vdesai2014/inference-optimization-blog-post/tree/main/part-9/gpu-piano讓 RTX 3090 演奏《一閃一閃亮晶晶》只是 Desai 在研究過程中的一次意外發現。部落格中,Desai 用了大量篇幅介紹了自己年初以來幾個月的學習經歷,透過嘗試最佳化擴散策略的推理過程來學習 GPU 程式設計。部落格地址:https://www.vrushankdes.ai/diffusion-inference-optimizationDesai 介紹瞭如何最佳化擴散策略,Desai 表示 GPU 具有記憶體層次結構,其範圍從大容量、低頻寬、高延遲(全域性記憶體)到低容量、高頻寬、低延遲。晶片中執行實際計算的部分(FP32 / INT8 單元、張量核等)比位元從記憶體儲存移動到計算電路的速度快得多。這導致 GPU 工作負載變得受記憶體限制 —— 與計算相關的位元從記憶體移動到計算所需的時間比實際執行計算所需的時間更長。Desai 認為近年來計算每秒可以執行的浮點運算次數與記憶體儲存可以提供的浮點數之間的差距越來越大。對於 Desai 研究的擴散策略推理最佳化工作來說,幾乎所有的速度提升都來自最佳化記憶體訪問模式以實現更好的記憶體利用率。下圖表明,與記憶體儲存(綠色)相比,FP32 計算單元 / 張量核(紅色)的速度快得多。全域性記憶體訪問如此慢是有物理原因的。全域性記憶體將位(bits)儲存在 DRAM 單元中,而該單元由一個電容器和一個電晶體(控制電容訪問)組成。每次訪問都需要對行緩衝區預充電以達到中性線電壓,將需要訪問的行連線到行緩衝區,選擇要讀取的正確的列,並將資料傳輸到匯流排。所有這些步驟需要花費大量時間來執行。因此,最有效的 GPU 效能最佳化手段之一是從全域性記憶體載入資料時訪問連續儲存器地址。DRAM 的物理結構是其發揮作用的原因。由於每次訪問一行需要將該行所有的位拉入到行緩衝區,因此同時訪問彼此相鄰的多個位是高效的做法。DRAM 的優點是,雖然速度相對較慢,但成本低並且易於密集封裝,畢竟只需要一個電容器和一個電晶體。如下為一個 DRAM 單元的 SEM(掃描電子顯微鏡)影像。在儲存器中儲存一個 FP16 GPT-4 例項需要大約 30 萬億個這樣的單元。Desai 感嘆,從事矽硬體設計和製造的人是真正的魔法師。相反,GPU 執行緒暫存器、L1/L2 記憶體使用 SRAM 進行儲存。SRAM 單元由 6 - 電晶體觸發器電路組成,並且由於這裡涉及到的唯一電容是電晶體柵極,因此訪問資料的速度變快了很多。但是,SRAM 也有缺點,它的晶片面積和製造複雜性導致了更高的成本。下面的 SEM 影像為一個 FinFET SRAM 單元。實際上,當有人聽到「CUDA 核心」這個詞時,並沒有任何硬體可以對映成這個人可能想到的東西。CPU 領域的核心要比 FP32 ALU 更加強大,大致對應了英偉達 GPU 的「CUDA 核心」。因此,為了好玩,我們可以試著猜測有多少個電晶體被分配給了一個 RTX 3090 CUDA 核心,它與 AMD Ryzen 7950X CPU 的比較結果見下表。為了記錄自己的學習過程,Desai 撰寫的部落格文章得到了 AI 大牛 Andrej Karpathy 的好評。Karpathy 表示,這篇文章讀起來很棒,依據他個人經驗,在 AI 研究中,你不僅在與物理規律作鬥爭,同時也在與 nvidia 編譯器和堆疊作鬥爭,即使在使用了很多技巧之後,我們仍然無法在許多核心上實現超過約 80-90% 的記憶體頻寬,而你原本可能會天真地認為這些核心應該接近 100%,而且這個問題的複雜性非常深。看似一項平常的研究,Desai 卻收到了意外驚喜,看來一些有趣而偉大的創造,似乎都在不經意間誕生。