2021-05-12 14:32:11
Ubuntu 16.04 LTS+NVIDIA@GT620M+CUDA6.5環境搭建總結
引言
為了完成tensorflow中CIFAR10關於cuda-convnet最後兩層的實現聯絡,我重新搭建了一下CUDA環境。可我萬萬沒想到,這環境竟然倒騰了我兩個星期的業餘時間,搞得我心煩意亂,像個鬼影似的,在我腦子裡縈繞又揮之不去。不過最終還是走出了陰霾,我現在做一個經驗總結,把我對cuda的一些理解與我對某些問題的解決思路分享給大家。
我先介紹一下這項環境設定工作的目標,主要是為cuda-convnet搭建執行環境。因此,其實用cuda的哪一個版本都不會有太大關係,不過系統最好時使用Ubuntu,這是因為
Alex Akrizhevsky 是在Linux環境下開發這套程式,相似甚至相同的系統環境更容易復現程式的效果。然後,為什麼我採用的是CUDA6.5,而不是CUDA7.0/7.5/8.0?原因很簡單,因為我之前曾在Ubuntu14.04LTS上搭建caffe成功過,當時採用貌似也就只有CUDA6.5。那為什麼系統又成了Ubuntu16.04LTS了?下面就看看我遇到的問題。
問題
眾所周知,官方驅動對Ubuntu的貌似一向都不大給力,因此apt裡面的驅動才是王道。但這並不是絕對的,畢竟確實也有不少人用官方驅動才安裝成功NVIDIA-Linux-x86_64-xxx.xx.run的。而我其實最初的搭建目標,是打算在Ubuntu14.04安裝CUDA7.5的。當時,我還以為都更新了這麼多次,感覺Nvidia支援力度應該不差,結果出現了回圈登入介面現象,這個現象不大好解,而且貌似在tty1上用 user@machine:~$ apt-get remove --purge nvidia*
都不好使,所以我改回了cuda-6.5。然而,網上流傳著cuda-6.5只支援到nvidia-340的驅動。因此,我直接來一個apt-get install nvidia-340 把它給裝上了。本以為這問題就這麼解決了,可是卻出現了另一個問題——系統黑畫面。完了….直接連登陸介面都看不見,其實面對這個情況我還是一如既往的淡定,使用 user@machine:~$ apt-get upgrade
能進系統到system-settings了。接著安裝cuda6.5,這部分還沒多大問題,但裝完後,進入sample編譯完後跑deviceQuery的時候就悲劇了,error(30) 是一個unkown有點無語了。難道是GPU驅動沒裝好?(其實不是,後面我就介紹)最後,又因為我從win系統切換回來,不知得罪哪個系統了,又回到了,黑畫面的問題……連重灌系統都不好使,upgrade也廢了….看起來貌似真全廢了。當時,我一直嘗試各種方法,但都沒得到好結果(包括升級到16.04LTS後依然出現unkown的問題,並且因為編譯工具的更新出現各種不適)……然而,我用TRIZ仔細分析了下矛盾後,找到了突破點。
矛盾分析
TRIZ蘇聯的創新發明理論,我這裡不多做介紹,直接用它進行分析。從上面的問題描述上,我們能分析出一種東西,叫做矛盾。當下最主要的矛盾,我想可能在Nvidia的Ubuntu驅動方面。我覺著這個矛盾應該是,在Ubuntu14.04LTS環境下安裝官方驅動會登入死迴圈,安裝apt的驅動又會黑畫面,不裝又跑不起CUDA,裝了就進不了系統。這是一個技術矛盾,而我們希望得到的理想結果是,裝上驅動而且不會出現故障,但裝上驅動就一定會出現故障,其實可以認為N卡驅動壞了。因此我們需要安裝一個不是驅動的驅動。乍看這話很怪,我後面分析完就不怪了。
我們需要從微觀層面分析,到底為什麼N卡驅動是壞的,驅動是跟誰發生衝突,從而尋找物理矛盾?據我的了解加上實驗的驗證,我發現N卡驅動雖然裝上後進不了圖形介面,但實際上能進系統的tty1模式並能夠正常執行,甚至還能夠跑CUDA的程式。也就是說,N卡驅動只是跟上層圖形介面啟動器發生了衝突,而非底層驅動失效。物理矛盾找到了,那怎麼解決呢?大家都明白,換個圖形介面啟動器就好了嘛,Ubuntu14.04的Xserver啟動器,我不是很會換。但前面Ubuntu16.04LTS不是已經把驅動裝上了嗎?行,我先把系統升級,再讓驅動給安上。結果確實沒問題了,原因是Ubuntu16.04LTS已經放棄了過去的Xserver,而換成了wayland的圖形啟動器。這就是我們的那個不是(Ubuntu14.04的)驅動的(Ubuntu16.04的)驅動了。那接下來新的問題出現了,跑CUDA例程出現的unkown怎麼解決,還有編譯工具過新的問題怎麼解決?
因為Ubuntu16.04LTS更新了gnu,而且在string的memcpy方面有比較大的改動,因此老會出現問題
"/usr/include/string.h:652:42: error: 'memcpy' was not declared in this scope"
這個問題還是比較好解決的,一般我是在編譯檔案裡面,新增一個叫做-D_FORCE_INLINES 的編譯選項。不過,面對cuda6.5的編譯,由於不支援gnu-4.9及以上的版本,我是直接使用
user@machine:~$ sudo update-alternative --install /usr/bin/gcc gcc /usr/bin/gcc-4.8 0
user@machine:~$ sudo update-alternative --install /usr/bin/gcc gcc /usr/bin/gcc-5.0 1
user@machine:~$ sudo update-alternative --install /usr/bin/g++ g++ /usr/bin/g++-4.8 0
user@machine:~$ sudo update-alternative --install /usr/bin/g++ g++ /usr/bin/g++-5.0 1
這時我們就可以使用下面的兩條指令來選擇切換gnu版本
user@machine:~$ sudo update-alternative --config g++
user@machine:~$ sudo update-alternative --config gcc
解決了gnu版本問題,我們就可以開始安裝cuda工具,這部分網上的材料比較多,因此不做贅述,可以參考 http://www.linuxidc.com/Linux/2015-04/116444.htm 的CUDA安裝部分。
最後,就是編譯了CUDA提供的sample後,在跑deviceQuery時出現的unkown問題,類似如下:
./deviceQuery Starting...
CUDA Device Query (Runtime API) version (CUDART static linking)
cudaGetDeviceCount returned 30
-> unknown error
Result = FAIL
這個問題其實也很獨特,每個人這個問題都可能不一樣,我只能介紹我遇到的情況。我的這個問題主要的原因其實是因為~/.bashrc裡面沒有真正的加上LD_LIBRARY_PATH。(其實我有根據cuda的安裝提示加上,只是LD_LIBRARY_PATH我漏掉了最後的PATH成了LD_LIBRARY,結果引發了這齣慘案……)另外,還有一種可能是許可權不夠,可以通過執行的時候加上sudo解決這個問題,下面是我的log:
user@machine:~$ sudo ./deviceQuery
[sudo] password for user:
./deviceQuery Starting...
CUDA Device Query (Runtime API) version (CUDART static linking)
Detected 1 CUDA Capable device(s)
Device 0: "GeForce GT 620M"
CUDA Driver Version / Runtime Version 6.5 / 6.5
CUDA Capability Major/Minor version number: 2.1
Total amount of global memory: 1024 MBytes (1073479680 bytes)
( 2) Multiprocessors, ( 48) CUDA Cores/MP: 96 CUDA Cores
GPU Clock rate: 1250 MHz (1.25 GHz)
Memory Clock rate: 900 Mhz
Memory Bus Width: 64-bit
L2 Cache Size: 131072 bytes
Maximum Texture Dimension Size (x,y,z) 1D=(65536), 2D=(65536, 65535), 3D=(2048, 2048, 2048)
Maximum Layered 1D Texture Size, (num) layers 1D=(16384), 2048 layers
Maximum Layered 2D Texture Size, (num) layers 2D=(16384, 16384), 2048 layers
Total amount of constant memory: 65536 bytes
Total amount of shared memory per block: 49152 bytes
Total number of registers available per block: 32768
Warp size: 32
Maximum number of threads per multiprocessor: 1536
Maximum number of threads per block: 1024
Max dimension size of a thread block (x,y,z): (1024, 1024, 64)
Max dimension size of a grid size (x,y,z): (65535, 65535, 65535)
Maximum memory pitch: 2147483647 bytes
Texture alignment: 512 bytes
Concurrent copy and kernel execution: Yes with 1 copy engine(s)
Run time limit on kernels: Yes
Integrated GPU sharing Host Memory: No
Support host page-locked memory mapping: Yes
Alignment requirement for Surfaces: Yes
Device has ECC support: Disabled
Device supports Unified Addressing (UVA): Yes
Device PCI Bus ID / PCI location ID: 1 / 0
Compute Mode:
< Default (multiple host threads can use ::cudaSetDevice() with device simultaneously) >
deviceQuery, CUDA Driver = CUDART, CUDA Driver Version = 6.5, CUDA Runtime Version = 6.5, NumDevs = 1, Device0 = GeForce GT 620M
Result = PASS
出現這個log就意味著,cuda環境成功設定了。
解答總結
下面是整個CUDA環境的設定流程:
1.安裝Ubuntu16.04LTS系統,也可以從較低版本中升級上來。
2.從System Settings
中安裝Nvidia驅動。
3.用 apt-get install g++-4.8 gcc-4.8
安裝老版本gnu。
4.用update-alternative
指令設定gnu環境,使其能夠升降級。
5.編譯CUDA工具。
6.編譯CUDA的sample,並呼叫deviceQuery測試安裝是否成功。
一些注意事項:
1.Ubuntu16.04LTS使用wayland圖形介面啟動器,比原來的Xserver更容易避免N卡驅動與系統應用層的衝突。
2.安裝好N卡驅動並進入圖形介面後,可以利用Nvidia X server Settings來切換顯示卡。
3.注意用編譯選項-D_FORCE_INLINES解決“‘memcpy’ was not declared in this scope”的問題。
4.想要知道N卡驅動是否安裝成功,我們可以檢視System Settings的detail資訊,看是否又有我們的獨顯型號來判斷。
5.編譯sample的過程中可能遇到/usr/bin/ld -nvcudev:can’t find the directories 類似的現象,這是有可能是因為我們使用了nvidia-340以上的顯示卡驅動,從而找不著路徑,在預設編譯環境裡面找不到相應的庫,這時我們只要在.barshrc檔案裡面最後加上下面一行就解決問題了: export LIBRARY_PATH=/usr/lib/nvidia-xxx(版本號):LIBRARY_PATH
總的來講,CUDA其實只是一套編譯工具,它是在原有的GNU工具的基礎上加入了相容NVIDIA的GPU架構的指令集,提供了一套能呼叫GPU資源的API。因此CUDA本身的安裝並不存在多大問題,大部分都只是N卡驅動以及編譯連結的問題。所以,我建議如果在CUDA環境搭建的時候,遇到問題有優先從編譯連結上找原因,尤其是驅動已經明確安裝成功的時候,基本可以明確是編譯連結的問題。N卡驅動一般只會跟上層圖形介面應用服務產生矛盾,所以基本可以分離N卡驅動與CUDA程式碼執行的問題。不過,有一個很重要的例外,就是執行一些不符合自身顯示卡計算能力的程式碼時,同樣也會出現code=30的unknown錯誤,如下:
CUDA error at src/nvmatrix.cu:1548 code=30(cudaErrorUnknown) "cudaCreateTextureObject(&_texObj, &resDesc, &texDesc, NULL)"
這個錯誤是因為我的GT620M的計算能力只有2.1,編譯的時候使用sm_20架構的編譯選項,而這個TextureObject的程式碼只能在sm_30以上的架構使用,所以會出現這種錯誤。實際上,我很鄙視Nvidia CUDA的nvcc編譯工具。因為在編譯階段這個使用架構不相容程式碼的問題是可以提示錯誤的,從而減少開發者遇到問題的處理效率,而且我覺著這只是一個宏定義處理的問題而已,看來Nvidia在這方面的支援力度還有待提高!
Ubuntu 14.04 安裝設定CUDA http://www.linuxidc.com/Linux/2014-10/107501.htm
Ubuntu 12.04設定NVIDIA CUDA5.5實錄 http://www.linuxidc.com/Linux/2014-10/107502.htm
Ubuntu安裝Theano+CUDA http://www.linuxidc.com/Linux/2014-10/107503.htm
關於Ubuntu 12.04 下 CUDA5.5 的安裝請參看如下連結 Ubuntu 12.04 安裝 CUDA-5.5
相關文章