通過Docker命令行使用cGPU服務(wù)
使用cGPU服務(wù)可以隔離GPU資源,實現(xiàn)多個容器共用一張GPU卡。該服務(wù)作為阿里云容器服務(wù)Kubernetes版ACK(Container Service for Kubernetes)的組件對外提供服務(wù),應(yīng)用于高性能計算能力的場景,例如機器學(xué)習(xí)、深度學(xué)習(xí)、科學(xué)計算等,方便您更高效地利用GPU資源,以加速計算任務(wù)。本文介紹如何通過安裝并使用cGPU服務(wù)。
cGPU服務(wù)的隔離功能不支持以UVM的方式(即調(diào)用CUDA API cudaMallocManaged())申請顯存,請您使用其他方式申請顯存,例如調(diào)用cudaMalloc()等。更多信息,請參見NVIDIA官方文檔。
前提條件
在進行本操作前,請確保GPU實例滿足以下要求:
GPU實例規(guī)格為gn7i、gn6i、gn6v、gn6e、gn5i、gn5、ebmgn7i、ebmgn6i、ebmgn7e、ebmgn6e、ebmgn7ex或sccgn7ex。
GPU實例操作系統(tǒng)為CentOS、Ubuntu或Alibaba Cloud Linux。
GPU實例已安裝Tesla 418.87.01或更高版本的驅(qū)動。
GPU實例已安裝Docker 19.03.5或更高版本。
安裝cGPU服務(wù)
無論您是企業(yè)認(rèn)證用戶還是個人實名認(rèn)證用戶,推薦您通過ACK的Docker運行時環(huán)境安裝和使用cGPU服務(wù)。
安裝1.5.7版本的cGPU組件,可能會導(dǎo)致cGPU內(nèi)核驅(qū)動出現(xiàn)死鎖現(xiàn)象(即并發(fā)執(zhí)行的進程互相牽制),從而導(dǎo)致Linux Kernel Panic(即內(nèi)核錯誤)問題,建議您安裝1.5.8及以上版本的cGPU,或?qū)⒌桶姹綾GPU逐步升級到1.5.8及以上版本,避免在新業(yè)務(wù)上出現(xiàn)內(nèi)核錯誤問題。
創(chuàng)建集群。
具體操作,請參見創(chuàng)建ACK托管集群。
在集群列表頁面,單擊目標(biāo)集群名稱,然后在左側(cè)導(dǎo)航欄,選擇 。
在基礎(chǔ)能力區(qū)域,選中調(diào)度策略擴展(批量任務(wù)調(diào)度、GPU共享、GPU拓?fù)涓兄?/b>
單擊頁面底部的部署云原生AI套件。
組件安裝成功后,在云原生AI套件頁面的組件列表中能看到已安裝的共享GPU組件ack-ai-installer。
在云原生AI套件頁面,單擊一鍵部署。
使用cGPU服務(wù)
本文以ecs.gn6i-c4g1.xlarge為例演示2個容器共用1張顯卡。
創(chuàng)建容器時指定環(huán)境變量的值,該值可以控制容器通過cGPU服務(wù)獲得算力。
環(huán)境變量名稱 | 取值類型 | 說明 | 示例 |
CGPU_DISABLE | Boolean | 是否禁用cGPU服務(wù),取值范圍:
默認(rèn)值:false。 | true |
ALIYUN_COM_GPU_MEM_DEV | Integer | 設(shè)置GPU實例上每張顯卡的總顯存大小。 該參數(shù)值與實例規(guī)格有關(guān),顯存大小按GiB取整數(shù)。例如: 對于ecs.gn6i-c4g1.xlarge實例,配備1張NVIDIA Tesla T4顯卡,在GPU實例上執(zhí)行nvidia-smi可查看總顯存大小。 | 總顯存大小為15109 MiB,取整數(shù)為15 GiB。 |
ALIYUN_COM_GPU_MEM_CONTAINER | Integer | 設(shè)置容器內(nèi)可見的顯存大小,與 在一張總顯存大小為15 GiB的顯卡上,設(shè)置 說明 如果不指定本參數(shù)或指定為0,則不使用cGPU服務(wù),使用默認(rèn)的NVIDIA容器服務(wù)。 | 1 GiB |
ALIYUN_COM_GPU_VISIBLE_DEVICES | Integer或uuid | 指定容器內(nèi)可見的GPU顯卡。例如: 在一臺有4張顯卡的GPU實例上,執(zhí)行nvidia-smi -L查看GPU顯卡設(shè)備號和UUID。返回示例如下所示:
然后,您可以指定該參數(shù)為以下環(huán)境變量:
|
|
ALIYUN_COM_GPU_SCHD_WEIGHT | Integer | 設(shè)置容器的算力權(quán)重,取值范圍:1~max_inst。 | 無 |
ALIYUN_COM_GPU_HIGH_PRIO | Integer | 設(shè)置容器的高優(yōu)先級,取值范圍:
默認(rèn)值:0。 說明 建議每張GPU卡設(shè)置一個高優(yōu)先級,多個高優(yōu)先級容器之間遵循相應(yīng)的調(diào)度策略(policy)。
| 0 |
運行cGPU服務(wù)
執(zhí)行以下命令,創(chuàng)建容器并設(shè)置容器內(nèi)可見的顯存。
本示例中,設(shè)置
ALIYUN_COM_GPU_MEM_CONTAINER
和ALIYUN_COM_GPU_MEM_DEV
環(huán)境變量指定顯卡的總顯存和容器內(nèi)可見的顯存。例如創(chuàng)建2個容器:gpu_test1:分配6 GiB顯存。
sudo docker run -d -t --gpus all --shm-size=1g --ulimit memlock=-1 --ulimit stack=67108864 --name gpu_test1 -v /mnt:/mnt -e ALIYUN_COM_GPU_MEM_CONTAINER=6 -e ALIYUN_COM_GPU_MEM_DEV=15 nvcr.io/nvidia/tensorflow:19.10-py3
gpu_test2:分配8 GiB顯存。
sudo docker run -d -t --gpus all --shm-size=1g --ulimit memlock=-1 --ulimit stack=67108864 --name gpu_test2 -v /mnt:/mnt -e ALIYUN_COM_GPU_MEM_CONTAINER=8 -e ALIYUN_COM_GPU_MEM_DEV=15 nvcr.io/nvidia/tensorflow:19.10-py3
說明該命令以使用TensorFlow鏡像
nvcr.io/nvidia/tensorflow:19.10-py3
為例,請根據(jù)實際情況更換為您自己的容器鏡像。使用TensorFlow鏡像搭建TensorFlow深度學(xué)習(xí)框架的操作,請參見部署NGC環(huán)境構(gòu)建深度學(xué)習(xí)開發(fā)環(huán)境。執(zhí)行以下命令,查看容器的顯存等GPU信息。
sudo docker exec -i gpu_test1 nvidia-smi
以gpu_test1為例,容器gpu_test1中可見的顯存為6043 MiB,如下圖所示:
通過procfs節(jié)點查看cGPU服務(wù)
cGPU服務(wù)運行時會在/proc/cgpu_km下生成并自動管理多個procfs節(jié)點,您可以通過procfs節(jié)點查看和配置cGPU服務(wù)相關(guān)的信息。
執(zhí)行以下命令,查看procfs節(jié)點信息。
ls /proc/cgpu_km/
執(zhí)行結(jié)果如下所示:
節(jié)點信息
讀寫類型
說明
0
讀寫
cGPU服務(wù)會針對GPU實例中的每張顯卡生成一個目錄。并使用數(shù)字作為目錄名稱,例如0、1、2。
本示例中只有一張顯卡,對應(yīng)的目錄為0。
default_memsize
讀寫
如果沒有設(shè)置ALIYUN_COM_GPU_MEM_CONTAINER參數(shù),默認(rèn)為新創(chuàng)建的容器分配的顯存大小。
inst_ctl
讀寫
控制節(jié)點。
upgrade
讀寫
控制cGPU服務(wù)的熱升級。
version
只讀
cGPU的版本。
執(zhí)行以下命令,查看GPU實例的顯卡目錄內(nèi)容。
本示例中,以顯卡0為例。
ls /proc/cgpu_km/0
執(zhí)行結(jié)果如下所示:
顯卡目錄
讀寫類型
說明
012b2edccd7a
或0852a381c0cf
讀寫
容器對應(yīng)的目錄。
cGPU服務(wù)會針對運行在GPU實例中的每個容器生成一個的目錄,并使用容器ID作為目錄名稱。
說明您可以執(zhí)行docker ps查看已創(chuàng)建的容器。
free_weight
只讀
用于查詢和修改顯卡上可用的權(quán)重。
如果
free_weight=0
,新創(chuàng)建容器的權(quán)重值為0,該容器不能獲取GPU算力,不能用于運行需要GPU算力的應(yīng)用。major
只讀
表示cGPU的major number,即不同的設(shè)備類型。
max_inst
讀寫
用于設(shè)置容器的最大數(shù)量,取值范圍為1~25。
policy
讀寫
cGPU服務(wù)支持以下算力調(diào)度策略:
0:平均調(diào)度。每個容器占用固定的時間片,時間片占比為
1/max_inst
。1:搶占調(diào)度。每個容器占用盡量多的時間片,時間片占比為
1/當(dāng)前容器數(shù)
。2:權(quán)重?fù)屨颊{(diào)度。當(dāng)ALIYUN_COM_GPU_SCHD_WEIGHT的取值大于1時,自動使用權(quán)重?fù)屨颊{(diào)度。
3:固定算力調(diào)度。用于固定算力的百分比。
4:算力弱調(diào)度。隔離性弱于搶占調(diào)度。
5:原生調(diào)度。即GPU驅(qū)動本身的調(diào)度方式。
您可以通過修改policy的值實時調(diào)整調(diào)度策略。更多調(diào)度策略說明,請參見cGPU服務(wù)使用示例。
prio_ratio
讀寫
在線和離線混合使用場景下,高優(yōu)先級容器最大可以搶占的算力。取值范圍:20~99。
執(zhí)行以下命令,查看容器對應(yīng)的目錄內(nèi)容。
本示例中,以012b2edccd7a容器為例。
ls /proc/cgpu_km/0/012b2edccd7a
執(zhí)行結(jié)果如下所示:
容器目錄
讀寫類型
說明
highprio
讀寫
用于設(shè)置容器的優(yōu)先級,默認(rèn)值為0。
當(dāng)
ALIYUN_COM_GPU_HIGH_PRIO
參數(shù)取值為1時,表示容器最大可以搶占prio_ratio
參數(shù)的算力。說明該功能用于在線和離線混合使用場景。
id
只讀
容器的ID。
memsize
讀寫
用于設(shè)置容器內(nèi)的顯存大小。cGPU服務(wù)會根據(jù)ALIYUN_COM_GPU_MEM_DEV參數(shù)自動設(shè)定此值。
meminfo
只讀
包括容器內(nèi)剩余顯存容量、正在使用GPU的進程ID及其顯存用量。輸出如下所示:
Free: 6730809344 PID: 19772 Mem: 200278016
weight
讀寫
用于設(shè)置容器獲取顯卡最大算力的權(quán)重,默認(rèn)值為1。所有運行中的容器的權(quán)重之和必須小于等于
max_inst
。(可選)執(zhí)行以下命令,配置cGPU服務(wù)。
了解procfs節(jié)點的用途后,您可以在GPU實例中執(zhí)行命令進行切換調(diào)度策略、修改權(quán)重等操作,示例命令如下表所示。
命令
效果
echo 2 > /proc/cgpu_km/0/policy
將調(diào)度策略切換為權(quán)重?fù)屨颊{(diào)度。
cat /proc/cgpu_km/0/free_weight
查看顯卡上可用的權(quán)重。如果
free_weight=0
,新創(chuàng)建容器的權(quán)重值為0,該容器不能獲取GPU算力,不能用于運行需要GPU算力的應(yīng)用。cat /proc/cgpu_km/0/$dockerid/weight
查看指定容器的權(quán)重。
echo 4 > /proc/cgpu_km/0/$dockerid/weight
修改容器獲取GPU算力的權(quán)重。
通過cgpu-smi工具查看cGPU容器
您可以通過cgpu-smi工具查看cGPU容器的相關(guān)信息,包括容器ID、GPU利用率、算力限制、使用的顯存以及分配顯存的總量等信息。
cgpu-smi是cGPU的監(jiān)控示例。部署k8s時,您可以參考或使用cgpu-smi的示例做二次開發(fā)集成。
cgpu-smi的監(jiān)控展示信息如下所示:
升級或卸載cGPU服務(wù)
升級cGPU服務(wù)
升級cGPU服務(wù)支持冷升級和熱升級兩種方式。
冷升級
Docker未使用cGPU服務(wù)的情況下,采用冷升級方式升級cGPU服務(wù),操作步驟如下:
執(zhí)行以下命令,關(guān)閉所有運行中的容器。
sudo docker stop $(docker ps -a | awk '{ print $1}' | tail -n +2)
執(zhí)行以下命令,升級cGPU服務(wù)至最新版本。
sudo sh upgrade.sh
熱升級
Docker使用cGPU服務(wù)的情況下,可以采用熱升級方式升級cGPU內(nèi)核驅(qū)動,但是對于升級的版本有一定限制。 如需任何協(xié)助,請聯(lián)系阿里云售后技術(shù)團隊。
卸載cGPU服務(wù)
關(guān)于如何卸載節(jié)點上舊版本cGPU服務(wù),具體操作,請參見通過命令升級節(jié)點cGPU版本。
cGPU服務(wù)使用示例
cGPU服務(wù)算力調(diào)度示例
cGPU服務(wù)加載cgpu_km的模塊時,會按照容器最大數(shù)量(max_inst)為每張顯卡設(shè)置時間片(X ms),用于為容器分配GPU算力,本示例中以Slice 1、Slice 2或Slice N表示。使用不同調(diào)度策略時的調(diào)度示例如下所示。
平均調(diào)度(policy=0)
在創(chuàng)建容器時,為容器分配時間片。cGPU服務(wù)會從Slice 1時間片開始調(diào)度,提交任務(wù)到物理GPU,并執(zhí)行一個時間片(X ms)的時間,然后切換到下一個時間片。每個容器獲得的算力相同,都為
1/max_inst
,如下所示。搶占調(diào)度(policy=1)
在創(chuàng)建容器時,為容器分配時間片。cGPU服務(wù)會從Slice 1開始調(diào)度,但如果沒有使用某個容器,或者容器內(nèi)沒有進程打開GPU設(shè)備,則跳過調(diào)度,切換到下一個時間片。
示例如下:
只創(chuàng)建一個容器Docker 1,獲得Slice 1時間片,在Docker 1中運行2個TensorFlow進程,此時Docker 1最大獲得整個物理GPU的算力。
再創(chuàng)建一個容器Docker 2,獲得Slice 2時間片。如果Docker 2內(nèi)沒有進程打開GPU設(shè)備,調(diào)度時會跳過Docker 2的時間片Slice 2。
當(dāng)Docker 2有進程打開GPU設(shè)備時,Slice 1和Slice 2都加入調(diào)度,Docker 1和Docker 2最大分別獲得1/2物理GPU的算力,如下所示。
權(quán)重?fù)屨颊{(diào)度(policy=2)
如果在創(chuàng)建容器時設(shè)置ALIYUN_COM_GPU_SCHD_WEIGHT大于1,則自動使用權(quán)重?fù)屨颊{(diào)度。cGPU服務(wù)按照容器數(shù)量(max_inst)將物理GPU算力劃分成max_inst份,但如果ALIYUN_COM_GPU_SCHD_WEIGHT大于1,cGPU服務(wù)會將多個時間片組合成一個更大的時間片分配給容器。
設(shè)置示例如下:
Docker 1:ALIYUN_COM_GPU_SCHD_WEIGHT=m
Docker 2:ALIYUN_COM_GPU_SCHD_WEIGHT=n
調(diào)度效果如下:
如果只有Docker 1運行, Docker 1搶占整個物理GPU的算力。
如果Docker 1和Docker 2同時運行,Docker 1和Docker 2獲得的理論算力比例是m:n。和搶占調(diào)度不同的是,即使Docker 2中沒有GPU進程也會占用n個時間片的時間。
說明m:n設(shè)置為2:1和8:4時的運行表現(xiàn)存在差別。在1秒內(nèi)切換時間片的次數(shù),前者是后者的4倍。
權(quán)重?fù)屨颊{(diào)度限制了容器使用GPU算力的理論最大值。但對算力很強的顯卡(例如NVIDIA V100顯卡),如果顯存使用較少,在一個時間片內(nèi)即可完成計算任務(wù)。此時如果m:n值設(shè)置為8:4,則剩余時間片內(nèi)GPU算力會閑置,限制基本失效。
固定算力調(diào)度(policy=3)
您可以通過指定ALIYUN_COM_GPU_SCHD_WEIGHT和max_inst的占比,固定算力的百分比。
算力弱調(diào)度(policy=4)
在創(chuàng)建容器時,為容器分配時間片,隔離性弱于搶占調(diào)度。更多信息,請參見搶占調(diào)度(policy=1)。
原生調(diào)度(policy=5)
只用來做顯存的隔離。原生調(diào)度表示NVIDIA GPU驅(qū)動本身的調(diào)度方式。
算力調(diào)度策略支持阿里云所有的異構(gòu)GPU實例,以及GPU實例所配備的NVIDIA顯卡,其型號包含Tesla P4、Tesla P100、Tesla T4、Tesla V100、Tesla A10。以下測試項使用2個容器共享一臺單卡A10的GPU實例,并將2個容器的算力比設(shè)置為1:2,將顯存均分,每個容器的顯存為12 G。
以下性能測試結(jié)果數(shù)據(jù)為實驗室數(shù)據(jù),僅供參考。
測試項1: 在基于TensorFlow框架訓(xùn)練的ResNet50模型、精度為FP16的場景下,測試不同batch_size下的性能數(shù)據(jù)比較。結(jié)果如下所示:
框架
模型
batch_size
精度
images/sec(容器1)
images/sec(容器2)
TensorFlow
ResNet50
16
FP16
151
307
TensorFlow
ResNet50
32
FP16
204
418
TensorFlow
ResNet50
64
FP16
247
503
TensorFlow
ResNet50
128
FP16
257
516
測試項2:在基于TensorRT框架訓(xùn)練的ResNet50模型、精度為FP16的場景下,測試不同batch_size下的性能數(shù)據(jù)比較。結(jié)果如下所示:
框架
模型
batch_size
精度
images/sec(容器1)
images/sec(容器2)
TensorRT
ResNet50
1
FP16
568.05
1132.08
TensorRT
ResNet50
2
FP16
940.36
1884.12
TensorRT
ResNet50
4
FP16
1304.03
2571.91
TensorRT
ResNet50
8
FP16
1586.87
3055.66
TensorRT
ResNet50
16
FP16
1783.91
3381.72
TensorRT
ResNet50
32
FP16
1989.28
3695.88
TensorRT
ResNet50
64
FP16
2105.81
3889.35
TensorRT
ResNet50
128
FP16
2205.25
3901.94
cGPU服務(wù)多卡劃分示例
本示例以設(shè)置4卡為例,設(shè)置0卡為3 G、1卡為4 G、2卡為5 G、3卡為6 G。多卡劃分示例代碼如下所示:
docker run -d -t --runtime=nvidia --name gpu_test0123 --shm-size=1g --ulimit memlock=-1 --ulimit stack=67108864 -v /mnt:/mnt -e ALIYUN_COM_GPU_MEM_CONTAINER=3,4,5,6 -e ALIYUN_COM_GPU_MEM_DEV=23 -e NVIDIA_VISIBLE_DEVICES=0,1,2,3 nvcr.io/nvidia/tensorflow:21.03-tf1-py3
docker exec -i gpu_test0123 nvidia-smi
執(zhí)行結(jié)果顯示如下,您可以看到4卡顯存詳情。
多卡設(shè)置顯存參數(shù)(即ALIYUN_COM_GPU_MEM_CONTAINER
參數(shù))說明如下所示:
參數(shù)取值 | 說明 |
ALIYUN_COM_GPU_MEM_CONTAINER=3 | 表示4卡的顯存都被設(shè)置為3 G。 |
ALIYUN_COM_GPU_MEM_CONTAINER=3,1 | 表示4卡的顯存依次被設(shè)置為3 G、1 G、1 G、1 G。 |
ALIYUN_COM_GPU_MEM_CONTAINER=3,4,5,6 | 表示4卡的顯存依次被設(shè)置為3 G、4 G、5 G、6 G。 |
ALIYUN_COM_GPU_MEM_CONTAINER未設(shè)置 | 表示禁用cGPU服務(wù)。 |
ALIYUN_COM_GPU_MEM_CONTAINER=0 | |
ALIYUN_COM_GPU_MEM_CONTAINER=1,0,0 |