深刻淺出計算機組成原理學習筆記:第三十一講

1、引子

上一講,我帶你一塊兒看了三維圖形在計算機裏的渲染過程。這個渲染過程,分紅了頂點處理、圖元處理、柵格化、片斷處理,以及最後的像素操做。這一連串的過程,程序員

也被稱之爲圖形流水線或者渲染管線。算法

由於要實時計算渲染的像素特別地多,圖形加速卡登上了歷史的舞臺。經過3dFx的Voodoo或者NVidia的TNT這樣的圖形加速卡,
CPU就不須要再去處理一個個像素點的圖元處理、柵格化和片斷處理這些操做。而3D遊戲也是從這個時代發展起來的。編程

你能夠看這張圖,這是「古墓麗影」遊戲的多邊形建模的變化。這個變化,則是從1996年到2016年,這20年來顯卡的進步帶來的。
緩存

2、Shader的誕生和可編程圖形處理器

一、不管你的顯卡有多快,若是CPU不行,3D畫面同樣仍是不行

不知道你有沒有發現,在Voodoo和TNT顯卡的渲染管線裏面,沒有「頂點處理「這個步驟。在當時,把多邊形的頂點進行線性變化,轉化到咱們的屏幕的座標系的工做仍是由CPU完成的。
因此,CPU的性能越好,可以支持的多邊形也就越多,對應的多邊形建模的效果天然也就越像真人。而3D遊戲的多邊形性能也受限多線程

於咱們CPU的性能。不管你的顯卡有多快,若是CPU不行,3D畫面同樣仍是不行。架構

二、1999年NVidia推出的GeForce 256顯卡

因此,1999年NVidia推出的GeForce 256顯卡,就把頂點處理的計算能力,也從CPU裏挪到了顯卡里。不過,這對於想要作好3D遊戲的程序員們還不夠,
即便到了GeForce 256。整個圖形渲染過程都是在硬件裏面固定的管線來完成的。程序員們在加速卡上能作的事情呢,只有改配置來實現不一樣的圖形渲染效果。若是通
過改配置作不到,咱們就沒有什麼辦法了。app

三、程序員但願咱們的GPU也能有必定的可編程能力

這個時候,程序員但願咱們的GPU也能有必定的可編程能力。這個編程能力不是像CPU那樣,有很是通用的指令,能夠進行任何你但願的操做,
而是在整個的 渲染管線(Graphics Pipeline)的一些特別步驟,可以本身去定義處理數據的算法或者操做。因而,從2001年的Direct3D 8.0開始,
微軟第一次引入了 可編程管線(Programable Function Pipeline)的概念。框架

 

一開始的可編程管線呢,僅限於頂點處理(Vertex Processing)和片斷處理(Fragment Processing)部分。比起原來只能經過顯卡和Direct3D這樣的圖形接口提供的固定配置,機器學習

程序員們終於也能夠開始在圖形效果上開始大顯身手了。工具

這些能夠編程的接口,咱們稱之爲 Shader,中文名稱就是 着色器。之因此叫「着色器」,是由於一開始這些「可編程」的接口,只能修改頂點處理和片斷處理部分的程序邏輯。
咱們用這些接口來作的,也主要是光照、亮度、顏色等等的處理,因此叫着色器。

四、Shader的誕生

這些能夠編程的接口,咱們稱之爲 Shader,中文名稱就是 着色器。之因此叫「着色器」,是由於一開始這些「可編程」的接口,只能修改頂點處理和片斷處理部分的程序邏輯。
咱們用這些接口來作的,也主要是光照、亮度、顏色等等的處理,因此叫着色器

Vertex Shader和Fragment Shader這兩類Shader都是獨立的硬件電路

這個時候的GPU,有兩類Shader,也就是Vertex Shader和Fragment Shader。咱們在上一講看到,在進行頂點處理的時候,咱們操做的是多邊形的頂點;在片斷操做的時候,
咱們操做的是屏幕上的像素點。對於頂點的操做,一般比片斷要複雜一些。因此一開始,這兩類Shader都是獨立的硬件電路,也各自有獨立的編程接口。由於這麼作,
硬件設計起來更加簡單,一塊GPU上也能容納下更多的Shader。

五、獨立的硬件電路存在什麼問題

不過呢,你們很快發現,雖然咱們在頂點處理和片斷處理上的具體邏輯不太同樣,可是裏面用到的指令集能夠用同一套。並且,雖然把Vertex Shader和Fragment Shader分開,
能夠減小硬件設計的複雜程度,可是也帶來了一種浪費,有一半Shader始終沒有被使用。在整個渲染管線裏,Vertext Shader運行的時候,Fragment Shader停在那裏什麼也沒幹。
Fragment Shader在運行的時候,Vertext Shader也停在那裏發呆。

六、統一着色器架構

原本GPU就不便宜,結果設計的電路有一半時間是閒着的。喜歡精打細算摳出每一分性能的硬件工程師固然受不了了。因而, 統一着色器架構(Unified Shader Architecture)就應運而生了。

既然你們用的指令集是同樣的,那不如就在GPU裏面放不少個同樣的Shader硬件電路,而後經過統一調度,把頂點處理、圖元處理、片斷處理這些任務,都交給這些Shader去處理,

讓整個GPU儘量地忙起來。這樣的設計,就是咱們現代GPU的設計,就是統一着色器架構。

七、通用圖形處理器

有意思的是,這樣的GPU並非先在PC裏面出現的,而是來自於一臺遊戲機,就是微軟的XBox 360。後來,這個架構才被用到ATI和NVidia的顯卡里。這個時候的「着色器」的做用,
其實已經和它的名字關係不大了,而是變成了一個通用的抽象計算模塊的名字。

正是由於Shader變成一個「通用」的模塊,纔有了把GPU拿來作各類通用計算的用法,也就是 GPGPU(General-Purpose Computing on Graphics Processing Units,通用圖形處理器)。
而正是由於GPU能夠拿來作各類通用的計算,纔有了過去10年深度學習的火熱。

 

3、現代GPU的三個核心創意

講完了現代GPU的進化史,那麼接下來,咱們就來看看,爲何現代的GPU在圖形渲染、深度學習上能那麼快

一、芯片瘦身

咱們先來回顧一下,以前花了不少講仔細講解的現代CPU。現代CPU裏的晶體管變得愈來愈多,愈來愈複雜,其實已經不是用來實現「計算」這個核心功能,而是拿來實現處理亂序執行、
進行分支預測,以及咱們以後要在存儲器講的高速緩存部分。

而在GPU裏,這些電路就顯得有點多餘了,GPU的整個處理過程是一個流式處理(Stream Processing)的過程。由於沒有那麼多分支條件,或者複雜的依賴關係,
咱們能夠把GPU裏這些對應的電路均可以去掉,作一次小小的瘦身,只留下取指令、指令譯碼、ALU以及執行這些計算須要的寄存器和緩存就行了。通常來講,咱們會把這些電路抽象成三個部分,就是下面圖裏的取指令和指令譯碼、ALU和執行上下文。

 

二、多核並行和SIMT

一、多核並行

這樣一來,咱們的GPU電路就比CPU簡單不少了。因而,咱們就能夠在一個GPU裏面,塞不少個這樣並行的GPU電路來實現計算,就好像CPU裏面的多核CPU同樣。
和CPU不一樣的是,咱們不須要單獨去實現什麼多線程的計算。由於GPU的運算是自然並行的。

 

咱們在上一講裏面其實已經看到,不管是對多邊形裏的頂點進行處理,仍是屏幕裏面的每個像素進行處理,每一個點的計算都是獨立的。因此,簡單地添加多核的GPU,
就能作到並行加速。不過光這樣加速仍是不夠,工程師們以爲,性能還有進一步被壓榨的空間。

二、SIMT技術

咱們在第27講裏面講過,CPU裏有一種叫做SIMD的處理技術。這個技術是說,在作向量計算的時候,咱們要執行的指令是同樣的,只是同一個指令的數據有所不一樣而已。
在GPU的渲染管線裏,這個技術可就大有用處了。

不管是頂點去進行線性變換,仍是屏幕上臨近像素點的光照和上色,都是在用相同的指令流程進行計算。因此,GPU就借鑑了CPU裏面的SIMD,用了一種叫做SIMT(Single Instruction,Multiple Threads)的技術。SIMT呢,比SIMD更加靈活。在SIMD裏面,CPU一次性取出了固定長度的多個數據,放到寄存器裏面,用一個指令去執行。而SIMT,能夠把多條數據,交給不一樣的線程去處理。

各個線程裏面執行的指令流程是同樣的,可是可能根據數據的不一樣,走到不一樣的條件分支。這樣,相同的代碼和相同的流程,可能執行不一樣的具體的指令。這個線程走到的是if的條件分支,
另一個線程走到的就是else的條件分支了。

因而,咱們的GPU設計就能夠進一步進化,也就是在取指令和指令譯碼的階段,取出的指令能夠給到後面多個不一樣的ALU並行進行運算。這樣,咱們的一個GPU的核裏,
就能夠放下更多的ALU,同時進行更多的並行運算了。

 

三、GPU裏的「超線程」

雖然GPU裏面的主要以數值計算爲主。不過既然已是一個「通用計算」的架構了,GPU裏面也避免不了會有if…else這樣的條件分支。可是,在GPU裏咱們可沒有CPU這樣的分支預測的電路。
這些電路在上面「芯片瘦身」的時候,就已經被咱們砍掉了。

因此,GPU裏的指令,可能會遇到和CPU相似的「流水線停頓」問題。想到流水線停頓,你應該就能記起,咱們以前在CPU裏面講過超線程技術。在GPU上,咱們同樣能夠作相似的事情,
也就是遇到停頓的時候,調度一些別的計算任務給當前的ALU。

和超線程同樣,既然要調度一個不一樣的任務過來,咱們就須要針對這個任務,提供更多的 執行上下文。因此,一個Core裏面的 執行上下文的數量,須要比ALU多。

 

4、GPU在深度學習上的性能差別


在經過芯片瘦身、SIMT以及更多的執行上下文,咱們就有了一個更擅長並行進行暴力運算的GPU。這樣的芯片,也正適合咱們今天的深度學習的使用場景。

一方面,GPU是一個能夠進行「通用計算」的框架,咱們能夠經過編程,在GPU上實現不一樣的算法。另外一方面,如今的深度學習計算,都是超大的向量和矩陣,海量的訓練樣本的計算。
整個計算過程當中,沒有複雜的邏輯和分支,很是適合GPU這樣並行、計算能力強的架構。

咱們去看NVidia 2080顯卡的技術規格,就能夠算出,它到底有多大的計算能力。

2080一共有46個SM(Streaming Multiprocessor,流式處理器),這個SM至關於GPU裏面的GPU Core,所每一個SM裏面有64個Cuda Core。

你能夠認爲,這裏的Cuda Core就是咱們上面說的ALU的數量或者Pixel Shader的數量,46x64呢一共就有2944個Shader。而後,還有184個TMU,TMU就是Texture Mapping Unit,
也就是用來作紋理映射的計算單元,它也能夠認爲是另外一種類型的Shader。

2080的主頻是1515MHz,若是自動超頻(Boost)的話,能夠到1700MHz。而NVidia的顯卡,根據硬件架構的設計,每一個時鐘週期能夠執行兩條指令。因此,能作的浮點數運算的能力,就是:

(2944 + 184)× 1700 MHz × 2 = 10.06 TFLOPS

對照一下官方的技術規格,正好就是10.07TFLOPS。

那麼,最新的Intel i9 9900K的性能是多少呢?不到1TFLOPS。而2080顯卡和9900K的價格倒是差很少的。因此,在實際進行深度學習的過程當中,用GPU所花費的時間,
每每能減小一到兩個數量級。而大型的深度學習模型計算,每每又是多卡並行,要花上幾天乃至幾個月。這個時候,用CPU顯然就不合適了。

今天,隨着GPGPU的推出,GPU已經不僅是一個圖形計算設備,更是一個用來作數值計算的好工具了。一樣,也是由於GPU的快速發展,帶來了過去10年深度學習的繁榮

5、總結延伸

這一講裏面,咱們講了,GPU一開始是沒有「可編程」能力的,程序員們只可以經過配置來設計須要用到的圖形渲染效果。隨着「可編程管線」的出現,
程序員們能夠在頂點處理和片斷處理去實現本身的算法。爲了進一步去提高GPU硬件裏面的芯片利用率,微軟在XBox 360裏面,第一次引入了「統一着色器架構」,使
得GPU變成了一個有「通用計算」能力的架構。

接着,咱們從一個CPU的硬件電路出發,去掉了對GPU沒有什麼用的分支預測和亂序執行電路,來進行瘦身。以後,基於渲染管線裏面頂點處理和片斷處理就是自然能夠並行的了。
咱們在GPU裏面能夠加上不少個核。

又由於咱們的渲染管線裏面,整個指令流程是相同的,咱們又引入了和CPU裏的SIMD相似的SIMT架構。這個改動,進一步增長了GPU裏面的ALU的數量。
最後,爲了可以讓GPU不要遭遇流水線停頓,咱們又在同一個GPU的計算核裏面,加上了更多的執行上下文,讓GPU始終保持繁忙。

GPU裏面的多核、多ALU,加上多Context,使得它的並行能力極強。一樣架構的GPU,若是光是作數值計算的話,算力在一樣價格的CPU的十倍以上。
而這個強大計算能力,以及「統一着色器架構」,使得GPU很是適合進行深度學習的計算模式,也就是海量計算,容易並行,而且沒有太多的控制分支邏輯。

使用GPU進行深度學習,每每可以把深度學習算法的訓練時間,縮短一個,乃至兩個數量級。而GPU如今也愈來愈多地用在各類科學計算和機器學習上,而不只僅是用在圖形渲染上了。

相關文章
相關標籤/搜索