溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

怎么在Kubernetes集群中利用GPU進(jìn)行AI訓(xùn)練

發(fā)布時間:2021-08-20 20:00:10 來源:億速云 閱讀:156 作者:chen 欄目:云計算

本篇內(nèi)容介紹了“怎么在Kubernetes集群中利用GPU進(jìn)行AI訓(xùn)練”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!


注意事項

截止Kubernetes 1.8版本:

  • 對GPU的支持還只是實驗階段,仍停留在Alpha特性,意味著還不建議在生產(chǎn)環(huán)境中使用Kubernetes管理和調(diào)度GPU資源。

  • 只支持NVIDIA GPUs。

  • Pods不能共用同一塊GPU,即使同一個Pod內(nèi)不同的Containers之間也不能共用同一塊GPU。這是Kubernetes目前對GPU支持最難以接受的一點(diǎn)。因為一塊PU價格是很昂貴的,一個訓(xùn)練進(jìn)程通常是無法完全利用滿一塊GPU的,這勢必會造成GPU資源的浪費(fèi)。

  • 每個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)圖如下:

怎么在Kubernetes集群中利用GPU進(jìn)行AI訓(xùn)練

讓kubelet發(fā)現(xiàn)GPU資源并可被調(diào)度

  • 請確認(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-gatesflag中都包含Accelerators=true(雖然實際上不是每個組件都需要配置這一項,比如kube-proxy)

注意在BIOS里面檢查你的UEFI是否開啟,如果開啟的話請立馬關(guān)掉它,否則nvidia驅(qū)動可能會安裝失敗。

關(guān)注Nvidia k8s-device-plugin

如果你使用的是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,后面有機(jī)會我再單獨(dú)寫一篇博文來深入分析。

如何在Pod中使用GPU

不同于cpu和memory,你必須強(qiáng)制顯式申明你打算使用的GPU number,通過在container的resources.limits中設(shè)置alpha.kubernetes.io/nvidia-gpu為你想要使用的GPU數(shù),通過設(shè)置為1就已經(jīng)足夠了,應(yīng)該沒多少訓(xùn)練場景一個worker需要獨(dú)占幾塊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

注意,需要將主機(jī)上的nvidia_driver通過hostpath掛載到容器內(nèi)的/usr/local/nvidia

有些同學(xué)或許已經(jīng)有疑問了:為啥沒看到設(shè)置resources.requests,直接設(shè)置resources.limits?

熟悉Kubernetes中LimitRangerResource QoS的同學(xué)應(yīng)該就發(fā)現(xiàn)了,這種對GPU resources的設(shè)置是屬于QoS為Guaranteed,也就是說:

  • 你可以只顯式設(shè)置limits,不設(shè)置requests,那么requests其實就等于limits。

  • 你可以同時顯示設(shè)置limitsrequests,但兩者必須值相等。

  • 你不能只顯示設(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機(jī)制解讀。

使用NodeAffinity增強(qiáng)GPU調(diào)度

前面提到,Kubernetes默認(rèn)不支持GPU硬件的區(qū)別和差異化調(diào)度,如果你需要這種效果,可以通過NodeAffinity來實現(xiàn),或者使用NodeSelector來實現(xiàn)(不過,NodeAffinity能實現(xiàn)NodeSelector,并且強(qiáng)大的多,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

通常,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中進(jìn)行GPU訓(xùn)練

參考如何落地TensorFlow on Kubernetes將TensorFlow跑在Kubernetes集群中,并且能創(chuàng)建Distributed TensorFlow集群啟動訓(xùn)練。

怎么在Kubernetes集群中利用GPU進(jìn)行AI訓(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, ...進(jìn)行加速訓(xùn)練了。

“怎么在Kubernetes集群中利用GPU進(jìn)行AI訓(xùn)練”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI