當前位置:
首頁 > 科技 > 清華大學副教授都志輝:如何使用GPU加速實時空間天氣預報

清華大學副教授都志輝:如何使用GPU加速實時空間天氣預報

3月23日起,智東西聯合NVIDIA推出「實戰營」第一季,共計四期。第四期於4月20日晚8點在智東西「高性能計算」系列社群開講,由清華大學計算機系副教授都志輝、NVIDIA高級系統架構師易成二位講師先後主講,主題分別為《GPU加速的實時空間天氣預報》和《NVIDIA GPU加速高性能計算》。

大型的科學應用程序往往由於其代碼量和通信量巨大,對計算力和數據傳輸性能要求非常高,如何利用高性能計算技術,設計開發高效的並行計算模型與演算法,充分利用不斷提高的硬體系統的計算能力來解決科學與工程計算問題具有重大意義,清華大學計算機系副教授都志輝團隊採用PPMLR-MHD方法並利用GPU加速運算處理有效解決了實時空間天氣預報問題。

本文為都志輝教授的主講實錄,共計7721字,預計14分鐘讀完。在瀏覽主講正文之前,可以思考以下三個問題:

-如何有效的將大量代碼從CPU移植到GPU上,並保證運算結果的一致性?

-如何準確找到對性能影響特別關健部分的代碼並進行優化?

-如何優化GPU上代碼的性能以提高計算資源利用率?

智東西「實戰營」第一季第一期由圖瑪深維首席科學家陳韻強和NVIDIA高級系統架構師付慶平,分別就《深度學習如何改變醫療影像分析》、《DGX超算平台-驅動人工智慧革命》兩個主題在智東西旗下「智能醫療」社群進行了系統講解。第二期由NVIDIA深度學習學院認證講師侯宇濤主講,主題為《手把手教你使用開源軟體DIGITS實現目標檢測》。第三期由西安交通大學人工智慧與機器人研究所博士陶小語、NVIDIA高級系統架構師易成二位講分別就《智能監控場景下的大規模並行化視頻分析方法》和《NVIDIA DGX-2 驅動智能監控革命》兩個主題在智東西旗下「智能安防」社群進行了系統講解。

主講環節

都志輝:大家好,我叫都志輝。很高興能夠在這裡跟大家一塊交流我們在GPU加速空間天氣預報方面的一些工作,我今天分享的主題是《GPU加速的實時空間天氣預報》。

今天的內容分為三個方面:

1,空間天氣預報的概念和意義;

2,空間天氣預報的計算難點及挑戰,這裡會介紹一些我們做大型科學工程計算時在GPU移植上獲得的一些經驗,以及如何在GPU上進行優化;

3,利用GPU實現加速空間天氣預報採取的方法

空間天氣預的概念和意義

首先介紹一下空間天氣預報的概念,空間天氣預報可以類比地面的天氣預報。比如颳風下雨對我們有什麼影響,只不過空間天氣預報是在更遠的地方,主要研究太陽與地球的相互作用對地球外部環境的影響。

在地球上,主要是颳風、下雨對我們有影響;而在空間是太陽風,即太陽發出很強勁的帶電粒子,會對地球造成非常大的影響。

對地球的影響有很多方面,對通信、雷達信號、發射衛星和電視轉播等都會造成影響。根本原因是這些帶電粒子干擾了地球的外層空間環境,從而對地球上的各種通信網路、電力網,甚至是臭氧層都造成影響。

如果沒有地球的磁場把太陽給推開,那麼地球上就不可能有人類,太陽粒子會直接把人類殺死。進入地區的太陽例子就像一個很強的X射線一樣進入了人體,相當於人體接觸了大量的輻射,會對人體的健康造成非常有害的影響。

空間天氣預報的計算的難點以及挑戰

如果把問題抽象起來,就是一個磁場和一個帶電的離子流之間的相互作用,在數學上可以用磁流體動力學方程來進行描述。

這個方程建立起來之後是非常複雜的,有很多不同的解法。其中我們的合作方(空間科學中心)提出了一種叫PPMLR的方法來解磁流體動力學方程。

他們用了十幾年的時間來發展這個方法,而且也已經形成了一個比較穩定的程序。這個方法的好處在於可以得到比較高精度的模擬計算結果,但計算量、通信量也非常大。

因此目前空間的空間天氣預報面臨的主要挑戰跟很多大規模科學工程計算問題一樣,都是如何才能算得更快,如何才能夠完成實時計算的問題。對於實時預報問題,空間科學中心告訴我們理想的情況是在40到50分鐘之內把全部的結果模擬出來。用原來的程序完成這個計算需要2-3個小時,所以我們面對的問題是如何把2-3小時的計算時間壓縮到1小時之內。

他們的方法非常好,所有的科學工程計算問題都首先得有數值計算方法,然後才是實現。這裡就不進行仔細地介紹了,當然一個好的數值計算方法也是非常重要的,這裡我們重點講一下如何在GPU上進行程序代碼的實現和優化。

這是SCALE CHALLENGE AWARD證書,是我們把空間科學中心的大型應用程序放在GPU集群上進行性能優化,實現了實時的計算,我們把這個成果參加了一個比賽,在IEEE的可擴展計算委員會經過答辯評審後授予了這個證書。

如果大家也做了相關的事情,比如做了科學工程計算,解決了一個很實際的問題,效果也非常好,也可以試著去參加一下這個競賽,在CCGRID的會議投稿期間,可以把你的工作寫成類似於論文的東西投過去,同時需要指明你是要參加這個競賽。他們首先要進行評審,評審之後還要去進行答辯,答辯完了之後再評價,最後挑選出他們認為做得比較好的項目,並授予相應的獎項。

這是空間科學中心已有程序的大概計算流程。這個程序分為兩部分,一部分是計算太陽風和地球磁層之間的相互作用;另一部分是計算地球的電離層。將這兩部分相互計算的結果最後綜合到一起形成總的模擬結果。

計算量比較大的是太陽風和磁層的相互作用這一部分,而右邊相對來說計算量很小,所以在他們的程序裡面就出現了跟一般的並行不太一樣的地方,就是用一個MPI進程來專門計算電離層這部分的任務,而其他所有的進程來計算太陽風和磁層相互作用這一部分。

我們在GPU上加速以及原來在MPI並行的也主要是左邊這一部分。大家可以看到有sweepx、y、z三個過程,同時最主要的計算量也是在這三個過程裡面,而我們做的事情就是對這三個過程分別在GPU上又進一步進行加速。

在具體介紹我們怎麼優化這個程序之前,先大概講一下我們在優化這個程序時獲得的一些體會。在優化這個程序的同時,我們還做了一個大型雙黑洞模擬的MPI並行程序,將其放在GPU集群上進行了性能優化,這些大型應用程序的代碼比較多,一般有幾十萬行,而這個程序只有幾萬行。

通過把這個大型的科學工程應用程序進行性能優化,在GPU上進行移植等,完成這件事情得到的體會是它和一般的小程序Benchmark有非常大的不同:

1,源程序的代碼量不一樣,一般大型程序都在幾萬行以上,而一般Benchmark只有幾百行,最多是一兩千行。對於Benchmark這樣的小程序來說,由於代碼量很少,因此在優化的過程中,你就可以非常仔細地對每一條語句進行研究。而對於十幾萬行代碼的大型程序,這樣操作的工作量就非常大。這也是大型程序性能優化在GPU上進行移植面臨的一個非常大的問題;

2,控制邏輯和數據結構不同,由於大型應用程序代碼量大,必然導致其控制邏輯和數據結構與benchmark非常不同,對於大型程序來說不是那麼簡單就可以搞得明白,而Benchmark可以很容易把整個代碼做的事情搞得一清二楚。

我們在將空間天氣預報程序在GPU集群上進行移植以及將更大的雙黑洞模擬程序在GPU上的移植時,發現一個相同的規律,就是代碼移植本身並不是太難,對於一個對CUDA編程非常熟練的人來說,只要用一個月的時間就可以把上萬行甚至幾十萬行的代碼移植到GPU上,而難的是將代碼移植到GPU上之後,一開始運行就會出現這樣那樣的意外與錯誤,就算你把這些問題都解決了之後,也會發現一個非常難解決的問題,就是在GPU和CPU上運行的結果不一樣。

我們的學生,他們之前用GPU用得很熟,算是CUDA編程高手,所以一開始對這麼大的程序代碼是非常有信心的,覺得移植到GPU上沒有問題,事實上一開始的代碼移植也的確是這樣,但問題是將代碼移植到GPU上之後,不能保證這些代碼是正確的。

這兩個大型程序的移植都出現了相同的情況,我們調試錯誤所花的時間要遠遠超過代碼移植所花的時間,甚至有些學生調試到最後都已經完全崩潰了,感到非常絕望,並且不知道該從哪下手了,雖然他們一開始都覺得自己是GPU編程的高手,但是對於大型程序中出現的各種莫名其妙的錯誤都感到束手無策。

利用GPU實現加速空間天氣預報採取的方法

下面我來講一下我們是如何在GPU集群上移植代碼的。

首先這個代碼不是串列代碼,前面已經介紹過,它是空間科學中心花了多年的時間,用MPI在CPU集群上可以穩定並行運行的並行代碼。

這個代碼有些特殊的地方,就是實際應用程序和Benchmark不同,用Benchmark實現的某些方法和手段,在實際應用程序中,經常發現是不能解決問題的,原因就是大型應用程序總有很多特殊的情況,而這些特殊的情況會讓那些從Benchmark裡面總結的經驗變得不可行。

比如上圖這個程序,它對網格的劃分比較特殊,它不是均勻的劃分,大概意思是,越靠近地球的地方相對來說越稠密,而離地球越遠的地方相對稀疏一些,這也是所有的網格劃分中基本的指導思想。

這個演算法的實現還有一個特點,在對空間網格劃分以後,對各個坐標軸的約束也不一樣。它需要專門拿出一個進程來模擬電離層的計算,而其他的進程用來模擬太陽風與地球的相互作用,為了讓地球都處在特定的位置,就要求它坐標軸的y和z軸的進程所劃分的塊數必須是奇數。

如上圖所示,以地球為中心進行156*150*150的空間網格劃分,在這個基礎上可以並行的進程數並不能隨便選,而只能是某些特定的值,比如4,28,37等這些值。

這裡我跟大家介紹的這些特別細節的內容,我覺得大家可能沒必要去掌握。我想從中說明一件事情,就是對大型應用程序來說,往往會有很多特殊的要求,而這些特殊的要求可能會對你的性能優化或者以前在別的地方積累起來的一些經驗造成很大的障礙,在這樣的場景下已有的經驗可能並不適用或者說效果並不好。

同時這也說明一件事情,我們經常說GPU的性能非常高,有成百甚至上千倍的加速。這個加速往往是在Benchmark理想情況下得到的,而在真實的大型應用程序上,如果想得到非常高的性能加速,一般來說是特別難的,難的原因就是大型應用程序本身不管是CPU還是GPU並行都不是特別理想,與理想情況不太吻合,因此給並行和優化加速製造了非常多的困難和障礙。

我們把程序在GPU集群上進行移植和優化的過程分為兩步:

第一步,是一個摸索的過程,在MPI並行程序的基礎上,對代碼進行處理,其中代碼分兩部分,一部分是計算量比較少的,用一個MPI進程在CPU上計算就可以完成。另一部分是計算量比較大的,就是太陽風與地球磁層相互作用的那一部分,需要將它全部移植到GPU上進行計算。

我們之所以把這麼多的代碼全都移植到GPU上,而不是將一部分放在CPU上一部分核心的sweepX、Y、Z三個過程放在GPU上執行,主要是因為如果你把一部分代碼放在CPU上,一部分放在GPU上,計算是可以大大的加速的,但是部分代碼放在CPU上會導致CPU和GPU之間存在大量的數據交換,如此一來,之前得到的加速計算的效果都會被這些數據交換的開銷所淹沒。

正是因為這個原因,所以我們才不得不把這麼多的代碼放在GPU上進行移植,儘管有些代碼並不是計算密集部分的代碼或者也不是一些瓶頸的代碼,這個問題在很多GPU性能優化上都會存在的,其根本原因是因為目前在GPU上執行代碼,得先把它需要的數據放上去,放數據是需要很大的開銷的。因此為了避免反反覆復地在CPU和GPU之間來回拷貝數據,我們才把更多的代碼放到GPU上來執行。

對於這個過程,像剛才說的,一開始看了這個代碼之後很有信心,認為移植上去不會有問題。然後不到一個月,就把原來在MPI在 CPU上並行的代碼全都移植到GPU上去了,但是到後來一測試,就發現會出現各種各樣的錯誤。開始我們還是比較有信心的,也很快地把很多錯誤都搞定了。但是後面不斷測試,就不斷會有新的錯誤出來,一直到最後,就發現有些錯誤根本就不知道是什麼原因導致的。

在這種情況下,我們不得不反思,移植上去的代碼可能是一個失敗的嘗試,換句話說我們根本沒有辦法保證這些代碼是正確的,也不可能通過調試把每一條的錯誤都找出來。在經過思考以後,我們就提出了第二版移植方案,其中的基本想法就是分步走,不要想著一步就把原來的代碼直接移植到GPU上,這也是從CPU程序向GPU移植經常會犯的一個錯誤,一般將代碼直接直截了當地移植到GPU上往往都是有問題的。

因為CPU程序的執行流程和計算方式與GPU有很大的不同,包括它們的數據結構和流程都不一樣。如果將代碼直接移植到GPU上,它的性能是會受影響的,或者你要改動非常大才能滿足性能要求,所以這種Straight forward移植是有很大問題的。而我們認識到這個錯誤以後,我們的方案是不把代碼直接移植到GPU上,而是先分析原來的代碼,如果要準備移植到GPU上,什麼樣的一個代碼結構與數據結構更有利於移植。

第二步,先把數據結構和代碼結構分別進行重組,但都還是用C或者用Fortran在CPU上進行編程,比如循環結構和數據結構,CPU上的哪些數據結構跟GPU的特性有關聯,相關聯的結構重組後,將代碼移植到GPU上後才不會造成混亂的局面。

把這些代碼捋順以後,看上去這些代碼看上去還是CPU上的代碼,但是它是按照GPU上的邏輯,為了能在GPU上執行的邏輯和數據組織方式去重寫的。通過調試,確保這部分代碼是正確的。

在這樣的基礎上,我們才將代碼往GPU上進行移植。剛才也說到,代碼量太大,為了避免CPU和GPU之間頻繁的數據交換,需要將很多代碼都轉移到GPU上,很明顯這工作量太大。但是如果特別影響性能的那部分核心代碼又不是特別多,我們可以採取引入Open ACC的方法。

引入Open ACC的目的,是對於那些我們不得不移植到GPU上的、但即使這部分代碼經過優化以後也不可能對性能有非常大的提升的不太核心的代碼來說,我們可以通過Open ACC加一些簡單的注釋語句,將它變成能在GPU上執行的代碼。而對於那小部分對性能影響非常大的代碼,可以專門用CUDA來進行重寫。

通過這種方式,就達到了以下的效果:

第一,通過使用Open ACC的方式,使得工作量大大降低,而且不容易出錯,降低了出錯的概率;

第二,通過手寫對性能影響特別關健的部分的代碼,用CUDA來重新修改、優化,可以大幅度提高最終代碼的性能。

以上說的就是我們在整個移植過程中總結出來的一些經驗,就是通過這種方式,既避免了CPU上大量的代碼移植到GPU上重寫的繁瑣過程,又能保證對性能沒有造成很大的影響。

因此大型應用程序在GPU或者GPU集群上的移植和性能優化,它的第一個難點並不是性能的提升,而是如何有效地控制代碼移植的複雜性。

我們採取的辦法就是,首先經過代碼的重組,構造一個中間版本,而這個中間版本跟原來的程序一樣,都是用C或者用Fortran語言來寫的,但是它比原來的程序更容易移植到GPU上去,因為它是按照GPU的邏輯來組織、重寫的,但它又是CPU的代碼,這樣的中間代碼就容易符合GPU上的邏輯;第二步就是採用Open ACC方法,避免了手工重寫大量與性能無關的代碼。

還有一個難點,對大型程序來說,要找到真正影響性能的地方往往也是很難的。有時候可能自己感覺用shared memory能提高性能,但是用了以後效果可能不一定真的好。我們在做用GPU來加速引力波數據處理的時候,就發現如果用shared memory來進行優化,還不如用atomic操作最終得到的效果要好。

NVIDIA的編程指導中講了很多通用的GPU性能優化的方法,比如提高occupancy,使用shared memory等這些手段,但是在真實的應用場景下,這些優化手段並不是用了就一定能夠得到好的結果,有的時候用了可能還會帶來另外的負面影響,從而導致整體性能沒有提高,反而可能有下降的情況。

這就是我想說的另外一個難點,如何才能找到真正可以影響性能的優化點,這個是非常難的,因為大型程序它存在很多會影響性能優化的因素,可能計算性能提高了,但是通信的開銷大了,性能也不一定好,或者是並行計算提高了,但數據訪問的次數提高了,開銷大了,也有可能會影響性能。

下面具體講講我們對大型應用程序,再深入到具體的GPU代碼編程大概用哪些優化手段和方法。

第一個比較簡單,對每一個MPI進程都調用一個CUDA核心來並行實現,就是把原來CPU上一個進程的執行代碼變成一個CUDA的並行執行(代碼)。

另外一個方面是如何提高訪存的效率。由於我們在具體應用中,在解方程的過程中,幾乎沒有數據的重用,因此我們沒必要再用shared memory,並且在這時候用,並不能帶來性能的提升。而能夠提高性能的,就是想辦法重新調整數據的結構,讓數據訪問時局部性高一點,一次可以讀入更多的數據,以這種方式來提高數據訪問的效率。

這裡我想再強調一下,根據我們在GPU上進行性能優化的工作體會,在大部分情況下,將CPU的代碼移植到GPU上的時候,數據結構都需要進行重組,如果不進行數據結構的重組,往往對性能會帶來負面的影響,而且GPU上的性能優化有很大的程度是在優化對數據的訪問,就是如何才能更有效、更快地得到一些數據。

還有一個優化的方面就是使用Stream(流),我們編寫了很多不同的核心,通過這些核心把它們形成Stream,由於GPU的計算能力很強,通過Stream這種方式,讓它們可以共享GPU資源,提高GPU資源的利用率。

這也是一種比較通用的提高GPU上代碼性能的方式。由於現在GPU的能力越來越強,單個的Kernel不可能充分地利用GPU的資源,因此在很多情況下,Kernel都不能把GPU上的資源用滿,這時利用Stream的優化方法去提高GPU資源的利用率也是非常重要的。

上圖是對通信優化的結果,我們對大型應用程序進行通信優化,最主要的一點,也最有效的一點就是用GPU NVLink的特點進行優化,就是GPU和GPU之間可以不通過CPU直接進行數據交換。我們在測試以後發現這種方式對性能的提高非常大。

這個應該是目前世界上最大的GPU集群,它是由美國橡樹嶺國家重點實驗室在Titan GPU集群上測試的結果。總的來說與在CPU上MPI並行版本相比,性能提高了2到3倍。

以上就是我要介紹的內容。謝謝大家。

Q&A環節

問題

李敏-中科院軟體所-高性能計算與並行計算方向博士

1,對一個大型應用程序,在GPU上並行加速的時候,一般的步驟都有哪些?可否分享一下您的經驗?

2,對應用進行並行加速這個工作,比較偏工程一些,如果對於博士從事這個方向的同學來說,如果想發論文,一般從哪些方面著手,找一些創新點?因為一邊是具體的應用領域,一邊是計算機領域的並行優化,其實是一個交叉的方向,如果權衡這兩方面?

都志輝:1,其實我在前面講的時候也大概說了一下,對一個大型應用程序在GPU上並行加速的時候,不要直接就往上移植,最好是先好好分析一下這個程序,先把問題、結構和流程搞清楚。然後再把你往GPU移植所要採取的手段和方法也想清楚,之後再動手。我們一般說性能優化,包括三個方面:應用、演算法和硬體體系結構。那麼移植也差不多,先把應用搞明白,再去移植,然後你再考慮如何用演算法來實現,最後再結合GPU和硬體來做這件事情。

2,這個問題比較通用,干我們這一行的很多人都有同感。我要給你一點建議是:其實對於我們一開始做優化的人來說,可能上來的想法是我如何把性能提高就行了,如果你想在博士期間做這件事情,想發論文,想找創新點,我覺得不是一上來就想著怎麼去優化的問題,而是要先多想想問題的本質在哪裡,別人是怎麼做的,為什麼不行,你打算怎麼做,這個方法為什麼可以或者你覺得他為什麼有可能不行,在優化之前或者是優化過程中,如果你把這些問題都弄明白了,那麼你動手有了優化結果後,也就意味著你寫的文章或者是你的創新點也比較容易找到了。

我們之前也犯過毛病,那時候我們覺得反正有這麼一個任務,想著快點完成就行了,然後這樣弄完之後,你只能說我把這性能提高了多少倍,但是有很多問題都沒有想清楚,比如你這麼做比別人做有什麼好處,為什麼不用別的方法,有沒有更好的方法,你這個方法的極限和瓶頸在哪等,可能都沒有想清楚,所以如果想發論文或者是找創新點,那就在動手之前先多考慮考慮,多問些問題。這就是我的一點建議。

對於權衡這方面,首先你說的非常對,如何去權衡目前確實沒有特別好的辦法,只能硬著頭皮去做,在做應用領域時就得先把應用問題搞清楚,如果搞不清楚就不可能把這個優化做好,這是我的一點體會。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 智東西 的精彩文章:

深度學習如何改變醫療影像分析?圖瑪深維首席科學家給出了答案!
被忽視的安防肥肉:觸景無限給傻瓜攝像頭安裝嵌入式AI板卡

TAG:智東西 |