由於課題的原因,筆者主要通過 Pytorch 框架進行深度學習相關的學習和實驗。在運行和學習網絡上的 Pytorch 應用代碼的過程中,不少項目會標注作者在運行和實驗時所使用的 Pytorch 和 cuda 版本信息。由於 Pytorch 和 cuda 版本的更新較快,可能出現程序的編譯和運行需要之前版本的 Pytorch 和 cuda 進行運行環境支持的情況。比如筆者遇到的某個項目中編寫了 CUDAExtension 拓展,而其中使用的 cuda 接口函數在新版本的 cuda 中做了修改,使得直接使用系統上已有的新版本 cuda 時會無法編譯使用。
為了滿足應用程序和框架本身對不同版本的 cuda 的需求,(如上面遇到的問題中,即需要 Pytorch 能夠切換使用系統上不同版本的 cuda ,進而編譯對應的 CUDAExtension),這里即記錄筆者了解到的 Ubuntu 環境下 Pytorch 在編輯 cpp 和 cuda 拓展時確定所使用 cuda 版本的基本流程以及 Pytorch 使用不同版本的 cuda 進行運行的方法。


Pytorch 確定所使用的 cuda 版本
實際使用過程中,Pytorch 檢測運行時使用的 cuda 版本的代碼位於 torch/utils/cpp_extension.py 的_find_cuda_home 函數 ( Pytorch 1.1.0, Line 24 )中.這里主要介紹 Linux 環境下的 cuda 版本的確認過程,關於 Windows 環境下多版本 cuda 的使用可以參考上述文件中的具體實現.
確定 cuda 路徑
若在運行時需要使用 cuda 進行程序的編譯或其他 cuda 相關的操作,Pytorch 會首先定位一個 cuda 安裝目錄( 來獲取所需的特定版本 cuda 提供的可執行程序、庫文件和頭文件等文件 )。具體而言,Pytorch 首先嘗試獲取環境變量 CUDA_HOME/CUDA_PATH 的值作為運行時使用的 cuda 目錄。若直接設置了 CUDA_HOME/CUDA_PATH 變量,則 Pytorch 使用 CUDA_HOME/CUDA_PATH 指定的路徑作為運行時使用的 cuda 版本的目錄。
若上述環境變量不存在,則 Pytorch 會檢查系統是否存在固定路徑 /usr/local/cuda 。默認情況下,系統並不存在對環境變量 CUDA_HOME 設置,故而 Pytorch 運行時默認檢查的是 Linux 環境中固定路徑 /usr/local/cuda 所指向的 cuda 目錄。 /usr/local/cuda 實際上是一個軟連接文件,當其存在時一般被設置為指向系統中某一個版本的 cuda 文件夾。使用一個固定路徑的軟鏈接的好處在於,當系統中存在多個安裝的 cuda 版本時,只需要修改上述軟連接實際指向的 cuda 目錄,而不需要修改任何其他的路徑接口,即可方便的通過唯一的路徑使用不同版本的 cuda. 如筆者使用的服務器中,上述固定的 /usr/local/cuda 路徑即指向一個較老的 cuda-8.0 版本的目錄。
需要注意的是, /usr/local/cuda 並不是一個 Linux 系統上默認存在的路徑,其一般在安裝 cuda 時創建( 為可選項,不強制創建 )。故而 Pytorch 檢測上述路徑時也可能會失敗。
若 CUDA_HOME 變量指定的路徑和默認路徑 /usr/local/cuda 均不存在安裝好的 cuda 目錄,則 Pytorch 通過運行命令 which nvcc 來找到一個包含有 nvcc 命令的 cuda 安裝目錄,並將其作為運行時使用的 cuda 版本。具體而言,系統會根據環境變量 PATH 中的目錄去依次搜索可用的 nvcc 可執行文件,若環境變量 PATH 中包含多個安裝好的 cuda 版本的可執行文件目錄( 形如/home/test/cuda-10.1/bin ),則排在 PATH 中的第一個 cuda 的可執行文件目錄中的 nvcc 命令會被選中,其所對應的路徑被選為 Pytorch 使用的 cuda 路徑。同樣的,若 PATH 中不存在安裝好的 cuda 版本的可執行目錄,則上述過程會失敗,Pytorch 最終會由於找不到可用的 cuda 目錄而無法使用 cuda.比較推薦的做法是保持 PATH 路徑中存在唯一一個對應所需使用的 cuda 版本的可執行目錄的路徑。
在確定好使用的 cuda 路徑后,基於 cuda 的 Pytorch 拓展即會使用確定好的 cuda 目錄中的可執行文件( /bin )、頭文件( /include )和庫文件( /lib64 )完成所需的編譯過程。
sudo rm -rf /usr/local/cuda //刪除軟鏈接,注意是 /usr/local/cuda 而不是 /usr/local/cuda/,前者僅刪除軟鏈接,而后者會刪除軟鏈接所指向的目錄的所有內容,操作請小心 sudo ln -s cuda_path /usr/local/cuda //創建名為 /usr/local/cuda 的軟鏈接,其指向 cuda_path 所指定的 cuda 安裝目錄
sudo ln -sf cuda_path /usr/local/cuda //修改或創建軟鏈接 /usr/local/cuda 使其指向指定版本的 cuda 目錄
export CUDA_HOME=/home/test/cuda-10.1/ //設置全局變量 CUDA_HOME export PATH=$PATH:/home/test/cuda-10.1/bin/ //在 PATH 變量中加入需要使用的 cuda 版本的路徑,使得系統可以使用 cuda 提供的可執行文件,包括 nvcc
想要永久設置上述 cuda 設置,用戶可以直接在自己的 bash 設置文件 ~/.bashrc 文件尾部加入上述命令,保存后再通過 source ~/.bashrc 執行文件,即可完成當前終端的環境變量修改。如果需要使用新的 cuda 來編譯文件,還可以通過 LD_LIBRARY_PATH 變量指定進行鏈接的 cuda 庫文件的路徑。
位於 ~/.bashrc 文件中的指令在每次終端啟動時均會自動運行,后續本用戶所打開的終端中的環境變量均會首先執行上述文件中的命令,從而獲得對應的 cuda 變量。
>>>import torch >>>torch.version.cuda #輸出一個 cuda 版本
如筆者環境下上述命令的輸出如下圖所示。
conda list | grep pytorch //查看安裝的 Pytorch 的信息
筆者環境下上述命令的結果如圖所示,可以看到顯示的 cuda 信息與 torch.version.cuda 保持一致。
想要查看 Pytorch 實際使用的運行時的 cuda 目錄,可以直接輸出之前介紹的 cpp_extension.py 中的 CUDA_HOME 變量。
>>> import torch >>> import torch.utils >>> import torch.utils.cpp_extension >>> torch.utils.cpp_extension.CUDA_HOME #輸出 Pytorch 運行時使用的 cuda