本篇內(nèi)容介紹了“怎么在Kubernetes集群中利用GPU進行AI訓(xùn)練”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
成都創(chuàng)新互聯(lián)堅持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:做網(wǎng)站、網(wǎng)站設(shè)計、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時代的天峻網(wǎng)站設(shè)計、移動媒體設(shè)計的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!
截止Kubernetes 1.8版本:
對GPU的支持還只是實驗階段,仍停留在Alpha特性,意味著還不建議在生產(chǎn)環(huán)境中使用Kubernetes管理和調(diào)度GPU資源。
只支持NVIDIA GPUs。
Pods不能共用同一塊GPU,即使同一個Pod內(nèi)不同的Containers之間也不能共用同一塊GPU。這是Kubernetes目前對GPU支持最難以接受的一點。因為一塊PU價格是很昂貴的,一個訓(xùn)練進程通常是無法完全利用滿一塊GPU的,這勢必會造成GPU資源的浪費。
每個Container請求的GPU數(shù)要么為0,要么為正整數(shù),不允許為為分?jǐn)?shù),也就是說不支持只請求部分GPU。
無視不同型號的GPU計算能力,如果你需要考慮這個,那么可以考慮使用NodeAffinity來干擾調(diào)度過程。
只支持docker作為container runtime,才能使用GPU,如果你使用rkt等,那么你可能還要再等等了。
目前,Kubernetes主要負(fù)責(zé)GPU資源的檢測和調(diào)度,真正跟NVIDIA Driver通信的還是docker,因此整個邏輯結(jié)構(gòu)圖如下:
請確認(rèn)Kubernetes集群中的GPU服務(wù)器已經(jīng)安裝和加載了NVIDIA Drivers,可以使用nvidia-docker-plugin
來確認(rèn)是否已加載Drivers。
如何安裝,請參考nvidia-docker 2.0 installation。
如何確定NVIDIA Drivers Ready呢?執(zhí)行命令 kubectl get node $GPU_Node_Name -o yaml
查看該Node的信息,如果看到.status.capacity.alpha.kubernetes.io/nvidia-gpu: $Gpu_num
,則說明kubelet已經(jīng)成功通過driver識別到了本地的GPU資源。
請確認(rèn)kube-apiserver, kube-controller-manager, kube-scheduler, kubelet, kube-proxy
每個組件的--feature-gates
flag中都包含Accelerators=true
(雖然實際上不是每個組件都需要配置這一項,比如kube-proxy
)
注意在BIOS里面檢查你的UEFI是否開啟,如果開啟的話請立馬關(guān)掉它,否則nvidia驅(qū)動可能會安裝失敗。
如果你使用的是Kubernetes 1.8,那么也可以利用kubernetes device plugin
這一Alpha特性,讓第三方device plugin發(fā)現(xiàn)和上報資源信息給kubelet,Nividia有對應(yīng)的plugin,請參考nvidia k8s-device-plugin。nvidia k8s-device-plugin通過DaemonSet方式部署到GPUs Server中,下面是其yaml描述文件內(nèi)容:
apiVersion: extensions/v1beta1 kind: DaemonSet metadata: name: nvidia-device-plugin-daemonset spec: template: metadata: labels: name: nvidia-device-plugin-ds spec: containers: - image: nvidia-device-plugin:1.0.0 name: nvidia-device-plugin-ctr imagePullPolicy: Never env: - name: NVIDIA_VISIBLE_DEVICES value: ALL - name: NVIDIA_DRIVER_CAPABILITIES value: utility,compute volumeMounts: - name: device-plugin mountPath: /var/lib/kubelet/device-plugins volumes: - name: device-plugin hostPath: path: /var/lib/kubelet/device-plugins
關(guān)于Kubernetes Device Plugin,后面有機會我再單獨寫一篇博文來深入分析。
不同于cpu和memory,你必須強制顯式申明你打算使用的GPU number,通過在container的resources.limits
中設(shè)置alpha.kubernetes.io/nvidia-gpu
為你想要使用的GPU數(shù),通過設(shè)置為1就已經(jīng)足夠了,應(yīng)該沒多少訓(xùn)練場景一個worker需要獨占幾塊GPU的。
kind: Pod apiVersion: v1 metadata: name: gpu-pod spec: containers: - name: gpu-container-1 image: gcr.io/google_containers/pause:2.0 resources: limits: alpha.kubernetes.io/nvidia-gpu: 1 volumeMounts: - mountPath: /usr/local/nvidia name: nvidia volumes: - hostPath: path: /var/lib/nvidia-docker/volumes/nvidia_driver/384.98 name: nvidia
注意,需要將主機上的nvidia_driver通過hostpath掛載到容器內(nèi)的/usr/local/nvidia
有些同學(xué)或許已經(jīng)有疑問了:為啥沒看到設(shè)置resources.requests
,直接設(shè)置resources.limits
?
熟悉Kubernetes中LimitRanger
和Resource QoS
的同學(xué)應(yīng)該就發(fā)現(xiàn)了,這種對GPU resources的設(shè)置是屬于QoS為Guaranteed
,也就是說:
你可以只顯式設(shè)置limits
,不設(shè)置requests
,那么requests
其實就等于limits
。
你可以同時顯示設(shè)置limits
和requests
,但兩者必須值相等。
你不能只顯示設(shè)置requests
,而不設(shè)置limits
,這種情況屬于Burstable
。
注意,在Kubernetes 1.8.0 Release版本中,存在一個bug:設(shè)置GPU requests小于limits是允許的,具體issue可以參考Issue 1450,代碼已經(jīng)合并到v1.8.0-alpha.3
中,請使用時注意。下面是對應(yīng)的修改代碼。
pkg/api/v1/validation/validation.go func ValidateResourceRequirements(requirements *v1.ResourceRequirements, fldPath *field.Path) field.ErrorList { ... // Check that request <= limit. limitQuantity, exists := requirements.Limits[resourceName] if exists { // For GPUs, not only requests can't exceed limits, they also can't be lower, i.e. must be equal. if quantity.Cmp(limitQuantity) != 0 && !v1helper.IsOvercommitAllowed(resourceName) { allErrs = append(allErrs, field.Invalid(reqPath, quantity.String(), fmt.Sprintf("must be equal to %s limit", resourceName))) } else if quantity.Cmp(limitQuantity) > 0 { allErrs = append(allErrs, field.Invalid(reqPath, quantity.String(), fmt.Sprintf("must be less than or equal to %s limit", resourceName))) } } else if resourceName == v1.ResourceNvidiaGPU { allErrs = append(allErrs, field.Invalid(reqPath, quantity.String(), fmt.Sprintf("must be equal to %s request", v1.ResourceNvidiaGPU))) } } return allErrs }
關(guān)于Kubernetes Resource QoS的更多知識,請參考我的另一篇博文:Kubernetes Resource QoS機制解讀。
前面提到,Kubernetes默認(rèn)不支持GPU硬件的區(qū)別和差異化調(diào)度,如果你需要這種效果,可以通過NodeAffinity來實現(xiàn),或者使用NodeSelector來實現(xiàn)(不過,NodeAffinity能實現(xiàn)NodeSelector,并且強大的多,NodeSelector應(yīng)該很快會Deprecated。)
首先,給GPU服務(wù)器打上對應(yīng)的Label,你有兩種方式:
在kubelet啟動flag中添加--node-labels='alpha.kubernetes.io/nvidia-gpu-name=$NVIDIA_GPU_NAME'
,當(dāng)然alpha.kubernetes.io/nvidia-gpu-name
你可以換成其他你自定義的key,但要注意可讀性。這種方式,需要重啟kubelet才能生效,屬于靜態(tài)方式。
通過rest client修改對應(yīng)的Node信息,加上對應(yīng)的Label。比如執(zhí)行kubectl label node $GPU_Node_Name alpha.kubernetes.io/nvidia-gpu-name=$NVIDIA_GPU_NAME
,這是實時生效的,可隨時增加刪除,屬于動態(tài)方式。
然后,在需要使用指定GPU硬件的Pod Spec中添加對應(yīng)的NodeAffinity Type為requiredDuringSchedulingIgnoredDuringExecution的相關(guān)內(nèi)容,參考如下:
kind: pod apiVersion: v1 metadata: annotations: scheduler.alpha.kubernetes.io/affinity: > { "nodeAffinity": { "requiredDuringSchedulingIgnoredDuringExecution": { "nodeSelectorTerms": [ { "matchExpressions": [ { "key": "alpha.kubernetes.io/nvidia-gpu-name", "operator": "In", "values": ["Tesla K80", "Tesla P100"] } ] } ] } } } spec: containers: - name: gpu-container-1 resources: limits: alpha.kubernetes.io/nvidia-gpu: 1 volumeMounts: - mountPath: /usr/local/nvidia name: nvidia volumes: - hostPath: path: /var/lib/nvidia-docker/volumes/nvidia_driver/384.98 name: nvidia
其中Tesla K80, Tesla P100都是NVIDIA GPU的型號。
通常,CUDA Libs安裝在GPU服務(wù)器上,那么使用GPU的Pod可以通過volume type為hostpath
的方式使用CUDA Libs。
kind: Pod apiVersion: v1 metadata: name: gpu-pod spec: containers: - name: gpu-container-1 image: gcr.io/google_containers/pause:2.0 resources: limits: alpha.kubernetes.io/nvidia-gpu: 1 volumeMounts: - mountPath: /usr/local/nvidia name: nvidia volumes: - hostPath: path: /var/lib/nvidia-docker/volumes/nvidia_driver/384.98 name: nvidia
參考如何落地TensorFlow on Kubernetes將TensorFlow跑在Kubernetes集群中,并且能創(chuàng)建Distributed TensorFlow集群啟動訓(xùn)練。
不同的是,在worker對應(yīng)的Job yaml中按照上面的介紹:
將docker image換成tensorflow:1.3.0-gpu;
給container加上GPU resources limits, 去掉cpu和memory的相關(guān)resources requests設(shè)置;
并掛載對應(yīng)的CUDA libs,然后在訓(xùn)練腳本中就能使用/device:GPU:1, /device:GPU:2, ...
進行加速訓(xùn)練了。
“怎么在Kubernetes集群中利用GPU進行AI訓(xùn)練”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!