作為一個AI工程師,對Linux的一些技能的掌握也能從一定層面反應工程師的資深水平。

要求1:基於SSH的遠端訪問(本篇文章)

  1. 能用一臺膝上型電腦,遠端登陸一臺linux伺服器
  2. 能隨時使用膝上型電腦啟動訓練任務
  3. 能熟練的讓程式碼和檔案在膝上型電腦與LINUX伺服器之間的傳輸

要求2:Linux系統的檔案系統(Linux指令學習

  1. 知道什麼是硬碟的掛載
  2. 能合理的使用伺服器的硬碟空間
  3. 不要求,但建議學會如何在LINUX系統上自建邏輯卷(LVM)

要求3:LINUX系統的賬戶管理

  1. 知道root賬戶與普通賬戶的區別
  2. 能夠對賬戶許可權有基本的規劃
  3. 能在普通賬戶下,完成基於Tensorflow的AI開發

要求4:LINUX系統的驅動安裝(本篇文章

  1. 能夠獨立的在Ubuntu Linux 上搭建NVIDIA GPU的深度學習環境

要求5:GIT和Github(Git從入門到精通

  1. 有程式碼的版本控制意識
  2. 能夠掌握基本的Git使用方法
  3. 能夠掌握基本的Github使用方法

上面的知識點我都寫過部落格,寫完這篇文章我就能集齊龍珠,召喚神龍了。


SSH遠端連線伺服器

例子:

  • IP地址:111.44.254.168
  • 埠號:21665
  • 登入名:root
  • 密碼:123456

linux \ MAC連線

  如果本地電腦是inux或者mac系統,則遠端伺服器SSH登陸資訊是: ssh -p 21665 [email protected]

window系統連線

  如果本地電腦是 window系統用cmd登陸(需要先安裝 OpenSSL),則遠端伺服器SSH登陸資訊是: ssh -p 21665 [email protected]

Xshell軟體連線

我們需要用到的軟體是:Xshell (命令列控制伺服器) 和 Xffp(傳輸檔案)

       

進入官網:https://www.netsarang.com/zh/,滑到最下面點選 家庭/學校免費,輸入姓名和郵箱,勾選兩者,點選下載。隨後郵箱會收到兩個郵件,點選郵件中的連結就可以下載安裝包。

putty,pscp、Filezila等軟體也比較主流,但可能不太穩定,這裡不做介紹

搭建深度學習環境

我們首先確定自己想要安裝的版本,CUDA與顯示卡驅動對應的版本關係TensorFlow-GPU與CUDA cudnn Python版本關係

我想安裝的版本是:

安裝python

  python環境我們選擇的是Anaconda,我選擇的安裝版本是 Anaconda3-5.2.0-Linux-x86_64.sh ,對應的python版本是python 3.6.5,建議到清華映象源下載,更快!

開啟Xftp,連線伺服器,在伺服器建立一個DL_package資料夾,將 Anaconda3-5.2.0-Linux-x86_64.sh 上傳到資料夾裡(不放也行,我是想要統一管理,因為後面還要安裝cuda和NVIDIA驅動)

安裝過程不要瞎點,看清楚底部的英文再確定 yes or no。

1、找到Anaconda3-2019.07-Linux-x86_64.sh安裝包,用 sh 命令執行 .sh 檔案,開始安裝

2、按回車觀看更多許可資訊,按 Q 鍵跳過

3、是否接受許可條款, 輸入yes回車

4、最後他會提示是否安裝 VS Code,我選了no,介面都沒有用個毛線VS Code!

5、這時關閉當前終端,再開啟一個新的終端會預設開啟在conda環境下

6、輸入  conda -V  可以檢視安裝的Anaconda版本

7、輸入  conda list  可以檢視已安裝的科學包

8、在終端輸入 python 可以看當前的python版本,並進入python程式設計環境

anaconda會自動將環境變數新增到PATH裡面,如果後面你發現輸出 conda ,提示沒有該命令,那麼需要新增環境變數

開啟~/.basrc 檔案c (例如:  vim ~/.bashrc ),在最後面加上

export PATH=/home/aeasringnar/anaconda3/bin:$PATH

更新環境變數: source ~/.bashrc

再次輸入 conda list 測試看看,應該就是沒有問題啦!

如果你想刪除Anaconda,切換到你安裝anaconda的目錄,直接 rm -rf anaconda3,然後在去/etc/profile,把配置的刪除就OK了

安裝NVIDA顯示卡驅動

禁用nouveau驅動

禁用nouveau驅動

sudo vim /etc/modprobe.d/blacklist.conf

在文字最後新增:

blacklist nouveau
options nouveau modeset=0

然後執行:

sudo update-initramfs -u

重啟後,執行以下命令,如果沒有螢幕輸出,說明禁用nouveau成功:

lsmod | grep nouveau

下載驅動

nividia 顯示卡驅動下載地址:NVIDIA 驅動程式下載,根據自己的顯示卡型號選擇驅動程式

解除安裝舊驅動

以下操作都需要在命令介面操作,執行以下快捷鍵進入命令介面,並登入:

Ctrl-Alt+F1

執行以下命令禁用X-Window服務,否則無法安裝顯示卡驅動:

sudo service lightdm stop

執行以下三條命令解除安裝原有顯示卡驅動:

sudo apt-get remove --purge nvidia*
sudo chmod +x NVIDIA-Linux-x86_64-410.93.run
sudo ./NVIDIA-Linux-x86_64-410.93.run --uninstall

安裝新驅動

下載驅動,官網下載地址,根據自己顯示卡的情況下載對應版本的顯示卡驅動,直接執行驅動檔案即可安裝新驅動,一直預設即可:

sudo ./NVIDIA-Linux-x86_64-410.93.run

執行以下命令啟動X-Window服務

sudo service lightdm start

最後執行重啟命令,重啟系統即可:

reboot

注意: 如果系統重啟之後出現重複登入的情況,多數情況下都是安裝了錯誤版本的顯示卡驅動。需要下載對應本身機器安裝的顯示卡版本。

安裝CUDA

由於 Pytorch 和 TensorFlow 對於 CUDA 都有特定的版本需求,所以在安裝 CUDA 之前,我們首先需要查詢,我們想要安裝的 pytorch 版本對應的 CUDA 版本。

pytorch 的配套環境要求見:https://pytorch.org/

在 https://developer.nvidia.com/cuda-toolkit-archive 中選擇你要安裝的CUDA版本

sudo sh cuda_11.2.2_460.32.03_linux.run

開始安裝。終端會在後臺執行一段時間,看起來像是卡住了,並不是沒有反應,請耐心等待。

然後選擇:accept

這裡將游標移到[X]Driver處,按enter鍵,取消勾選安裝驅動。

===========
= Summary =
=========== Driver: Not Selected
Toolkit: Installed in /usr/local/cuda-11.2/
Samples: Installed in /home/user/ Please make sure that
- PATH includes /usr/local/cuda-11.2/bin
- LD_LIBRARY_PATH includes /usr/local/cuda-11.2/lib64, or, add /usr/local/cuda-11.2/lib64 to /etc/ld.so.conf and run ldconfig as root To uninstall the CUDA Toolkit, run cuda-uninstaller in /usr/local/cuda-11.2/bin
***WARNING: Incomplete installation! This installation did not install the CUDA Driver. A driver of version at least 460.00 is required for CUDA 11.2 functionality to work.
To install the driver using this installer, run the following command, replacing <CudaInstaller> with the name of this run file:
sudo <CudaInstaller>.run --silent --driver Logfile is /var/log/cuda-installer.log

安裝完成之後,可以配置他們的環境變數,在 vim ~/.bashrc 的最後加上以下配置資訊:

export CUDA_HOME=/usr/local/cuda-11.2
export LD_LIBRARY_PATH=${CUDA_HOME}/lib64
export PATH=${CUDA_HOME}/bin:${PATH}

最後使用命令 source ~/.bashrc 使它生效。

可以使用命令 nvcc -V 檢視安裝的版本資訊:

$ nvcc -V
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2021 NVIDIA Corporation
Built on Sun_Feb_14_21:12:58_PST_2021
Cuda compilation tools, release 11.2, V11.2.152
Build cuda_11.2.r11.2/compiler.29618528_0

出現上圖所示介面說明已經安裝完成

測試安裝是否成功,執行以下幾條命令:

cd /usr/local/cuda-11.2/samples/1_Utilities/deviceQuery
make -j32
./deviceQuery

解除安裝cuda

cd /usr/local/cuda-11.2/bin/
sudo ./cuda-uninstaller
sudo rm -rf /usr/local/cuda-11.2

安裝CUDNN

進入到CUDNN的下載官網,然點選Download開始選擇下載版本,當然在下載之前還有登入,選擇版本介面如下

下載之後是一個壓縮包:cudnn-11.2-linux-x64-v8.1.1.33.tar,然後對它進行解壓,命令如下:

tar -zxvf cudnn-11.2-linux-x64-v8.1.1.33.tar

解壓之後可以得到以下檔案:

cuda/include/cudnn.h
cuda/NVIDIA_SLA_cuDNN_Support.txt
cuda/lib64/libcudnn.so
cuda/lib64/libcudnn.so.7
cuda/lib64/libcudnn.so.7.4.2
cuda/lib64/libcudnn_static.a

使用以下兩條命令複製這些檔案到CUDA目錄下:

cp cuda/lib64/* /usr/local/cuda-11.2/lib64/
cp cuda/include/* /usr/local/cuda-11.2/include/

拷貝完成之後,可以使用以下命令檢視CUDNN的版本資訊:

cat /usr/local/cuda/include/cudnn.h | grep CUDNN_MAJOR -A 2

檢視 Nvidia 顯示卡利用率:視訊記憶體佔用和算力情況。

# 0.5 秒更新一次顯示卡利用情況,並檢視 NVIDIA 驅動版本
watch -n 0.5 nvidia-smi 

安裝TensorFlow

TensorFlow經歷過一次變革,從 Tensorflow 1.* 變革到了現在的 Tensorflow 2.*,從靜態變成了動態。

如果想要安裝tensorflow 1.*,需要:

# 支援CPU的版本,版本可更改
pip install tensorflow==1.15
# 支援GPU的版本,版本可更改
pip install tensorflow-gpu==1.15

如果想要安裝tensorflow 2.*,只需要:

pip install tensorflow
  • 若要支援 Python 3.9,需要使用 TensorFlow 2.5 或更高版本。
  • 若要支援 Python 3.8,需要使用 TensorFlow 2.2 或更高版本。

更詳細情況,請移步Tensorflow官網

Tensorflow 檢視GPU是否可用,返回True則代表可用

import tensorflow as tf
tf.test.is_gpu_available()

安裝pytorch

pytorch的安裝沒啥好說的,因為 任何人的介紹或轉述 都不如官網寫的明白,請直接移步 pytorch官網首頁

pytorch 檢視GPU是否可用,返回True則代表可用,返回False則代表不可用。

import torch
torch.cuda.is_available()

搭建Jupyter Notebook遠端雲伺服器

為什麼要使用Jupyter Notebook

  • 隨時可在未安裝Python的電腦上使用Python(可以分享給別人)
  • 藉助伺服器的效能,在伺服器上做分析,解放本地計算機的CPU
  • 不同電腦間,使用伺服器jupyter可避免資料不一致
  • Jupyter Notebook能幫助我們有效地組織輸入輸出,將探索資料的過程記錄下來,
  • Jupyter Notebook支援Markdown,也支援Python、R甚至Julia等語言,完全可以支援一個數據工作者的大多數分析需求。

完工後的介面如下,輸入密碼就可以開始使用啦:

安裝過程

1、安裝 Jupyter Notebook 庫

我安裝的是 Ananconda ,這是 Python 的科學計算包,自帶了 Jupyter,因此無需此步驟。若未安裝,也可單獨安裝

$ pip install Jupyter

2、生成 Jupyter Notebook 配置檔案

$ jupyter notebook --generate-config

生成的配置檔案,後來用來設定伺服器的配置

3、設定Jupyter Notebook密碼

設定密碼用於設定伺服器配置,以及登入Jupyter。開啟Python終端,輸入以下:

$ python
>> from notebook.auth import passwd
>> passwd()
此時會讓你兩次輸入密碼,然後就會生成祕鑰
sha1************

4、設定伺服器配置檔案

$ vim ~/.jupyter/jupyter_notebook_config.py

在末尾增加以下幾行配置資訊(此配置資訊,也可在啟動Jupyter時在引數中新增,但我認為那樣看起來比較亂)

c.NotebookApp.ip = '*'                    # 所有繫結伺服器的IP都能訪問,若想只在特定ip訪問,輸入ip地址即可
c.NotebookApp.port = 8888                  # 將埠設定為自己喜歡的吧,預設是8888
c.NotebookApp.open_browser = False             # 我們並不想在伺服器上直接開啟Jupyter Notebook,所以設定成False
c.NotebookApp.notebook_dir = '/home/user/Desktop/jupyter_projects' # 這裡是設定Jupyter的根目錄,若不設定將預設root的根目錄,不安全
c.NotebookApp.allow_root = True              # 為了安全,Jupyter預設不允許以root許可權啟動jupyter
c.NotebookApp.password = 'sha1:7a80c9a4cec6:9fcda0d4be1fb9d2181c9912c931689c49f6179a' # 設定之前生成的sha1

不過我建議你通過Xftp把jupyter_notebook_config.py拉下來,在本地更改後再上傳上去(要更改的地方取消註釋)

5、啟動Jupyter 遠端伺服器

$ jupyter notebook

# 或者指定埠和IP地址
$ jupyter notebook --no-browser --port 6000 --ip=192.168.1.103

至此,Jupyter遠端伺服器以搭建完畢。在本地瀏覽器上,輸入 ip地址:8888,將會開啟遠端Jupyter。接下來就可以像在本地一樣使用伺服器上的Jupyter啦~~

按下ctrl+C鍵,可以退出

Jupyter notebook 更換kernel

由於jupyter notebook訪問的時候,預設使用了anaconda的base環境,這裡就需要更換環境。

具體方式如下:

1、安裝ipykernel:

# 新建虛擬環境
(base) [root]$ conda activate your_eniv
# 安裝nb_conda_kernels
(your_eniv) [root]$ conda install nb_conda_kernels
Collecting package metadata (current_repodata.json): done
Solving environment: done
2、啟用conda環境: source activate 環境名稱,將環境寫入notebook的kernel中
python -m ipykernel install --user --name 環境名稱 --display-name "顯示的名稱"

3、開啟notebook伺服器:jupyter notebook,瀏覽器開啟對應地址,就會有對應的環境提示了。

快速搭建JupyterLab服務

  JupyterLab與Jupyter Notebook師出同源,可以憑個人愛好進行選擇。因為我想把部落格寫全,所以再介紹一下JupyterLab服務搭建

jupyter lab的每一步都和jupyter一樣,就是啟動的時候,加了lab而已。

1、安裝 Jupyter Notebook 庫

pip install jupyterlab

2、生成 Jupyter Notebook 配置檔案

$ jupyter lab --generate-config

生成的配置檔案,後來用來設定伺服器的配置

3、設定Jupyter Notebook密碼

設定密碼用於設定伺服器配置,以及登入Jupyter。開啟Python終端,輸入以下:

$ python
>> from notebook.auth import passwd
>> passwd()
此時會讓你兩次輸入密碼,然後就會生成祕鑰
sha1************

4、設定伺服器配置檔案

$ vim /home/ubuntu/.jupyter/jupyter_notebook_config.py

我們看到了一大串的配置選項,一入眼就有點懵了。不要慌,我們只需要修改其中的四行即可。我們使用vim的快捷鍵/來搜尋以下幾項,將他們之前的註釋去掉,並按照如下配置修改。

# 將ip設定為*,意味允許任何IP訪問
c.NotebookApp.ip = '*'
# 這裡的密碼就是上邊我們生成的那一串
c.NotebookApp.password = u'sha1:1e39d24dcd6c:b265321ca0c4cb798888bcb69b0024983a8ac439'
# 伺服器上並沒有瀏覽器可以供Jupyter開啟
c.NotebookApp.open_browser = False
# 監聽埠設定為8888或其他自己喜歡的埠
c.NotebookApp.port = 8888
# 我們可以修改jupyter的工作目錄,也可以保持原樣不變,如果修改的話,要保證這一目錄已存在
c.MappingKernelManager.root_dir = '/home/ubuntu/.jupyter_run/root'
# 允許遠端訪問
c.NotebookApp.allow_remote_access = True

好了,儲存輸入:wq退出vim。

不過我建議你通過Xftp把jupyter_notebook_config.py拉下來,在本地更改後再上傳上去(要更改的地方取消註釋)

5、啟動Jupyter 遠端伺服器

$ jupyter lab --allow-root

# 或者指定埠和IP地址
$ jupyter lab notebook --no-browser --port 6000 --ip=***.***.**.***

至此,Jupyter遠端伺服器以搭建完畢。在本地瀏覽器上,輸入 ip地址:8888,輸入密碼,也就是我們自己設定並確認的密碼。將會開啟遠端Jupyter lab。

按下ctrl+C鍵,可以退出

搭建虛擬環境

  在Python中,虛擬環境(virtual enviroment)就是隔離的Python直譯器環境。通過建立虛擬環境,我們可以擁有一個獨立的Python直譯器環境。這樣做的好處是可以為每一個專案建立獨立的Python直譯器環境,因為不同的專案常常會依賴不同版本的庫或Python版本。使用虛擬環境可以保持全域性Python直譯器環境的乾淨,避免包和版本的混亂,並且可以方便地區分和記錄每個專案的依賴,以便在新環境下復現依賴環境。

  我總結了多種建立虛擬環境的方法,我推薦conda方法,你們可以根據自己的愛好選擇。

conda搭建虛擬環境(推薦)

1、新建虛擬環境

conda create --name <env_name> <package_names>

# 建立一個名為 python_2 的環境,環境中python版本為2.7
# conda create --name python_2 python=2.7 # 建立一個名為 conda-test 的環境,環境中python版本為3.6,同時也安裝了numpy和pandas。
# conda create -n conda-test python=3.6 numpy pandas
  • –name 同樣可以替換為-n。
  • <env_name> 建立的環境名。建議以英文命名,且不加空格,名稱兩邊不加尖括號“<>”
  • <package_names> 即安裝在環境中的包名。名稱兩邊不加尖括號“<>”

檢視建立的虛擬環境

conda env list
# 或:conda info --envs
# 或:conda info -e

2、啟用虛擬環境

Linux:  source activate your_env_name(虛擬環境名稱)
Windows: activate your_env_name(虛擬環境名稱)

檢視安裝了哪些庫

conda list

3、退出虛擬環境

conda deactivate

若配置好環境後需要別的包,用conda或者pip下載皆可

# 在當前環境安裝包
pip install 安裝的包名
conda install 要安裝的包名
# 指定環境安裝包
conda install --name 環境名 要安裝的包名

4、刪除虛擬環境

conda remove -n your_env_name --all

複製環境

conda create --name new_env_name --clone copied_env_name

virtualenv搭建虛擬環境

首先,我們用pip安裝virtualenv:

$ pip3 install virtualenv

然後,假定我們要開發一個新的專案,需要一套獨立的Python執行環境,可以這麼做:

1、建立目錄

$ mkdir myproject
$ cd myproject/

2、建立一個虛擬環境,命名為venv

$ virtualenv venv

若想要指定Python3

$ virtualenv -p python3 newEnv

檢視newEnv資料夾中的內容

$ cd newEnv
$ ls
bin include lib pip-selfcheck.json

3、啟用虛擬環境

$ source venv/bin/activate

4、在虛擬環境中安裝python第三方庫

  在venv環境下,用pip安裝的包都被安裝到venv這個環境下,系統Python環境不受任何影響。也就是說,venv環境是專門針對myproject這個應用建立的。

$ pip install ***

5、關閉虛擬環境

$ deactivate

依據當前環境中的依賴包生成requirements.txt文件

$ pip freeze > requirements.txt

依據requirements.txt文件重建環境

$ pip install -r < requirements.txt

Pipenv搭建虛擬環境

  Pipenv是基於pip的Python包管理工具,它和pip的用法非常相似,可以看作pip的加強版,它的出現解決了舊的pip virtualenv + requirements.txt的工作方式的弊端。具體來說,它是pip、Pipfile和Virtualenv(虛擬環境)的結合體,它讓包安裝、包依賴管理和虛擬環境管理更加方便,使用它可以實現高效的Python專案開發工作流。如果你還不熟悉這些工具,不用擔心,我會在下面逐一進行介紹。

通過pip安裝Pipenv:

$ pip install pipenv

1、建立虛擬環境

  虛擬環境通常使用Virtualenv來建立,但是為了更方便地管理虛擬環境和依賴包,我們將會使用集成了Virtualenv的Pipenv。首先確保我們當前工作目錄在示例程式專案的根目錄,然後使用pipenv install命令為當前的專案建立虛擬環境:

$ pipenv install

  初始化好虛擬環境後,會在專案目錄下生成2個檔案PipfilePipfile.lock。為pipenv包的配置檔案,代替原來的 requirement.txt。專案提交時,可將 Pipfile 檔案和Pipfile.lock檔案一併提交,待其他開發克隆下載,根據此Pipfile 執行命令pipenv install --dev生成自己的虛擬環境。

Pipfile.lock 檔案是通過hash演算法將包的名稱和版本,及依賴關係生成雜湊值,可以保證包的完整性。

2、進入虛擬環境

$ pipenv shell

3、退出虛擬環境

$ exit

4、在虛擬環境中建立python包

$ pipenv install <某個包的名稱>

檢視安裝包及依賴關係

$ pipenv graph

5、生成 requirements.txt 檔案

pipenv可以像virtualenv一樣用命令生成requirements.txt 檔案

$ pipenv lock -r --dev > requirements.txt

6、pipenv也可以通過requirements.txt安裝python包

$ pipenv install -r requirements.txt

執行python程式碼

方法一:pipenv run python xxx.py

$ pipenv run python xxx.py

方法二:啟動虛擬環境的shell環境

$ pipenv shell
$ python xxx.py

7、刪除虛擬環境

$ pipenv --rm

常用命令一覽

pipenv --where                 列出本地工程路徑
pipenv --venv 列出虛擬環境路徑
pipenv --py 列出虛擬環境的Python可執行檔案
pipenv install 建立虛擬環境
pipenv isntall [moduel] 安裝包
pipenv install [moduel] --dev 安裝包到開發環境
pipenv uninstall[module] 解除安裝包
pipenv uninstall --all 解除安裝所有包
pipenv graph 檢視包依賴
pipenv lock 生成lockfile
pipenv run python [pyfile] 執行py檔案
pipenv --rm 刪除虛擬環境

使用GPU

檢視GPU的執行情況,同時我們也可以看到驅動和CUDA的版本號

nvidia-smi
# 檢視訓練程序時的GPU情況一般需要持續監視該輸出
# 即每隔0.5秒執行一次nvidia-smi;
# watch -n 0.5 nvidia-smi

使用指定GPU

  做好GPU的分配,比如我們有四張顯示卡,只想使用第1個和第4個,則只需要在程式的最開頭使用如下命令:

1、直接終端中設定:

CUDA_VISIBLE_DEVICES=0,3 python my_script.py

2、python程式碼中設定

import os
os.environ['CUDA_VISIBLE_DEVICES'] = '0,3'

tensorflow使用多GPU

以後再來補全

pytorch使用多GPU

  加速神經網路訓練最簡單的辦法就是上GPU,如果一塊GPU還是不夠,就多上幾塊。

  事實上,比如BERTGPT-2這樣的大型語言模型甚至是在上百塊GPU上訓練的。

  為了實現多GPU訓練,我們必須想一個辦法在多個GPU上分發資料和模型,並且協調訓練過程。

機多卡的辦法還有很多(如下)

  1. nn.DataParallel簡單方便的 nn.DataParallel
  2. torch.distributed 使用 torch.distributed 加速並行訓練
  3. apex 使用 Apex 再加速

這裡,記錄了使用 4 塊 Tesla V100-PICE 在 ImageNet 進行了執行時間的測試,測試結果發現 Apex 的加速效果最好,但與 Horovod/Distributed 差別不大,平時可以直接使用內建的 Distributed。Dataparallel 較慢,不推薦使用。

torch.nn.DataParallel

torch.nn.DataParallel(module, device_ids=None, output_device=None, dim=0)

DataParallel 會自動幫我們將資料切分 load 到相應 GPU,將模型複製到相應 GPU,進行正向傳播計算梯度並彙總

  • module:要並行化的模型
  • device_ids:參與訓練的 GPU 有哪些,(預設:所有裝置)
  • output_device:用於彙總梯度的 GPU 是哪個,(預設:device_ids[0])

  這裡需要注意,模型和資料都需要先 load 進 GPU 中,DataParallel 的 module 才能對其進行處理,否則會報錯:

# main.py
import torch
import torch.distributed as dist gpus = [0, 1, 2, 3]
torch.cuda.set_device('cuda:{}'.format(gpus[0])) train_dataset = ... train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=...) model = ...
if torch.cuda.device_count() > 1:
print("Let's use", torch.cuda.device_count(), "GPUs!")
model = nn.DataParallel(model.to(device), device_ids=gpus, output_device=gpus[0]) optimizer = optim.SGD(model.parameters()) for epoch in range(100):
for batch_idx, (data, target) in enumerate(train_loader):
images = images.cuda(non_blocking=True)
target = target.cuda(non_blocking=True)
...
output = model(images)
loss = criterion(output, target)
...
optimizer.zero_grad()
loss.backward()
optimizer.step()

缺點:

  • 在每個訓練批次(batch)中,因為模型的權重都是在 一個程序上先算出來 然後再把他們分發到每個GPU上,所以網路通訊就成為了一個瓶頸,而GPU使用率也通常很低。
  • 除此之外,nn.DataParallel 需要所有的GPU都在一個節點(一臺機器)上,且並不支援 Apex 的 混合精度訓練

一句話,一個程序算權重使通訊成為瓶頸,nn.DataParallel慢而且不支援混合精度訓練。

使用 torch.distributed 加速並行訓練

  • DataParallel:單程序控制多 GPU。
  • DistributedDataParallel:多程序控制多 GPU,一起訓練模型。

  在 1.0 之後,官方終於對分散式的常用方法進行了封裝,支援 all-reduce,broadcast,send 和 receive 等等。通過 MPI 實現 CPU 通訊,通過 NCCL 實現 GPU 通訊。官方也推薦使用 DistributedDataParallel 解決 DataParallel 速度慢,GPU 負載不均衡的問題,目前已經很成熟了。

  與 DataParallel 的單程序控制多 GPU 不同,在 distributed 的幫助下,我們只需要編寫一份程式碼,torch 就會自動將其分配給n個程序,分別在n個 GPU 上執行。

多程序訓練需要注意以下事項:

  • 在喂資料的時候,一個batch被分到了好幾個程序,每個程序在取資料的時候要確保拿到的是不同的資料(DistributedSampler);
  • 要告訴每個程序自己是誰,使用哪塊GPU(args.local_rank);
  • 在做BatchNormalization的時候要注意同步資料。

啟動方式的改變

在多程序的啟動方面,我們不用自己手寫 multiprocess 進行一系列複雜的CPU、GPU分配任務,PyTorch為我們提供了一個很方便的啟動器 torch.distributed.launch 用於啟動檔案,所以我們執行訓練程式碼的方式就變成了這樣:

CUDA_VISIBLE_DEVICES=0,1,2,3 python -m torch.distributed.launch --nproc_per_node=4 main.py

其中的 --nproc_per_node 引數用於指定為當前主機建立的程序數,由於我們是單機多卡,所以這裡node數量為4,所以我們這裡設定為所使用的GPU數量即可。

初始化

  在啟動器為我們啟動python指令碼後,在執行過程中,啟動器會將當前程序的 index 通過引數傳遞給 python,我們可以這樣獲得當前程序的 index:即通過引數 local_rank 來告訴我們當前程序使用的是哪個GPU,用於我們在每個程序中指定不同的device:

def parse():
parser = argparse.ArgumentParser()
parser.add_argument('--local_rank', type=int, default=0, help='node rank for distributed training')
args = parser.parse_args()
return args def main():
args = parse()
torch.cuda.set_device(args.local_rank)
torch.distributed.init_process_group('nccl', init_method='env://')
device = torch.device(f'cuda:{args.local_rank}')
...

其中 torch.distributed.init_process_group 用於初始化GPU通訊方式(NCCL)和引數的獲取方式(env代表通過環境變數)。

使用 init_process_group 設定GPU之間通訊使用的後端和埠,通過 NCCL 實現 GPU 通訊。

DataLoader

  在讀取資料的時候,我們要保證一個batch裡的資料被均攤到每個程序上,每個程序都能獲取到不同的資料,但如果我們手動去告訴每個程序拿哪些資料的話太麻煩了,PyTorch也為我們封裝好了這一方法。之後,使用 DistributedSampler 對資料集進行劃分。如此前我們介紹的那樣,它能幫助我們將每個 batch 劃分成幾個 partition,在當前程序中只需要獲取和 rank 對應的那個 partition 進行訓練。

所以我們在初始化 data loader 的時候需要使用到 torch.utils.data.distributed.DistributedSampler  這個特性:

train_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset)

train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=..., sampler=train_sampler)

這樣就能給每個程序一個不同的 sampler,告訴每個程序自己分別取哪些資料。

模型的初始化

和  nn.DataParallel  的方式一樣,我們對於模型的初始化也是簡單的一句話就行了

model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.local_rank])

使用 DistributedDataParallel 包裝模型,它能幫助我們為不同 GPU 上求得的梯度進行 all reduce(即彙總不同 GPU 計算所得的梯度,並同步計算結果)。all reduce 後不同 GPU 中模型的梯度均為 all reduce 之前各 GPU 梯度的均值。

彙總

至此,我們就可以使用 torch.distributed 給我們帶來的多程序訓練的效能提升了,彙總程式碼結果如下:

# main.py
import torch
import argparse
import torch.distributed as dist parser = argparse.ArgumentParser()
parser.add_argument('--local_rank', default=-1, type=int,
help='node rank for distributed training')
args = parser.parse_args() dist.init_process_group(backend='nccl')
torch.cuda.set_device(args.local_rank) train_dataset = ...
#每個程序一個sampler
train_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset) train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=..., sampler=train_sampler) model = ...
model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.local_rank]) optimizer = optim.SGD(model.parameters()) for epoch in range(100):
for batch_idx, (data, target) in enumerate(train_loader):
images = images.cuda(non_blocking=True)
target = target.cuda(non_blocking=True)
...
output = model(images)
loss = criterion(output, target)
...
optimizer.zero_grad()
loss.backward()
optimizer.step()

但是這裡需要注意的是,如果使用這句程式碼,直接在pycharm或者別的編輯器中,是沒法正常執行的,因為這個需要在shell的命令列中執行,如果想要正確執行這段程式碼,需要呼叫 torch.distributed.launch 啟動器啟動:

CUDA_VISIBLE_DEVICES=0,1,2,3 python -m torch.distributed.launch --nproc_per_node=4 main.py

在 ImageNet 上的完整訓練程式碼,請點選Github

最後總結歸納下單機單卡 [snsc.py],單機多卡 (with DataParallel) [snmc_dp.py]和多機多卡 (with DistributedDataParallel)這3種訓練方式的程式碼段,方便讀者參考。

可惜的是pytorch並沒有為我們同步BN,詳細內容參見:PyTorch 21.單機多卡操作(分散式DataParallel,混合精度,Horovod)

參考

【部落格園文章】關於部落格園內嵌入bilibili視訊

【嗶哩嗶哩視訊】【ssh遠端連線伺服器教程】租了GPU伺服器不知道怎麼深度學習?看完不會你打我

【知乎】深度學習 | Linux安裝Anaconda

【CSDN】Ubuntu安裝和解除安裝CUDA和CUDNN

【CSDN】Ubuntu16.04下安裝NVIDIA驅動 + cuda 11.2 + cudnn 8.1

【CSDN】ubuntu16.04安裝NIVIDIA顯示卡驅動,cuda8.0,cuDNN6.0以及基於Anaconda安裝Tensorflow-GPU

【個人部落格】搭建Jupyter Notebook遠端雲伺服器

【知乎】Jupyter Notebook配置

【知乎】Jupyter lab 和避免伺服器連線斷開會關閉執行jupyter

【CSDN】前臺執行和後臺執行,以及遇到的Bug如何解決 ★

【pytorch官網】DATAPARALLEL

【知乎】Anaconda-用conda建立python虛擬環境

【知乎】 Virtualenv搭建python虛擬環境

【知乎】PyTorch 21.單機多卡操作(分散式DataParallel,混合精度,Horovod)