摘要
算法、資料和算力稱為人工智能的三大要素,如果沒有算力的支撐,人工智能難以落地。而Nvidia GPU的強勁算力是AI模型訓練加速的首選,但是它的價格也确實不菲。如何能夠簡單,有效同時低成本的使用Nvidia GPU的算力,使用阿裡雲容器服務+ECI+Arena的方案是一個可以參考的選項。
而一談起Nvidia GPU,大家首先會想到的就是深度學習,傳統的機器學習和資料分析的方法對GPU的利用卻很少,實際上Nvidia有一個非常優秀的項目RAPIDS,全稱Real-time Acceleration Platform for Integrated Data Science,是NVIDIA針對資料科學和機器學習推出的GPU加速庫。更多RAPIDS資訊請參見官方網站。這是一個緻力于将GPU加速帶給傳統算法的項目,并且提供了與Pandas和scikit-learn一緻的用法和體驗。實際上RAPIDS有三個子產品:cuDF相當于Pandas,cuML相當于scikit-learn,cuGraph則是處理圖資料的。由于它的相容性很好,我們可以把RAPIDS與深度學習架構結合,用cuDF來利用GPU加速處理資料,然後使用TensorFlow和PyTorch的深度學習模型架構處理任務。

執行步驟
步驟1:準備叢集
準備托管k8s的叢集,所謂托管k8s的叢集就是這個k8s的管控節點由阿裡雲承擔資源和運維成本,并且建立了虛拟的Kubelet節點
需要您已建立好容器服務 Kubernetes叢集。 您可以選擇管版的Kubernetes叢集。
由于需要運作系統元件容器,節點中至少有一個Worker節點。
- 安裝虛拟節點,具體可以參考 虛拟節點 。
- 配置virtual-kubelet-autoscaler,當叢集内的GPU資源不足的時候,通過virtual-kubelet-autoscaler将彈出使用GPU的ECI執行個體。具體參考 文檔
步驟2:從無到有運作arena建立RAPIDS服務
1.安裝arena
$ wget http://kubeflow.oss-cn-beijing.aliyuncs.com/arena-installer-0.3.0-b556a36-linux-amd64.tar.gz
$ tar -xvf arena*.tar.gz
$ cd arena-installer
$ ./install.sh
2.先運作一下arena指令檢視叢集的GPU資源, 可以看到在該使用者叢集下,有一個真實節點并沒有包含GPU資源,同時存在了一個虛拟節點,該節點并不真實存在,無需付費,同時它提供了無限的GPU資源可以擴充。
$ arena top node
arena top node
NAME IPADDRESS ROLE STATUS GPU(Total) GPU(Allocated)
cn-shanghai.192.168.1.248 192.168.1.248 <none> ready 0 0
virtual-kubelet 172.20.2.18 agent ready 1000 0
-----------------------------------------------------------------------------------------
Allocated/Total GPUs In Cluster:
0/1000 (0%)
3.再送出rapids任務前,我們需要做一些準備。準備的目的是加速建立過程和簡化通路操作。
3.1.設定通路方式。将通路方式設定為LoadBalancer(該方法隻是為了示例簡單,并不推薦您在生産環境開放外網ip方通路)
$ find /charts/ -name "*.yaml" | xargs sed -i "s/NodePort/LoadBalancer/g"
3.2.加速啟動速度
3.2.1.GPU的容器鏡像通常很大,以本實驗要使用的rapids容器鏡像為例,它的容量為14.7GB.通常啟動時間會在10分鐘左右。而通過
鏡像緩存的能力可以将這個從無到有的過程縮短到20s左右。
docker images | grep rapids
registry.cn-shanghai.aliyuncs.com/tensorflow-samples/rapids-samples 0.8.2-cuda10.0-runtime-ubuntu16.04 4597a0334d41 12 days ago 14.7GB
3.2.2.而在serverless kubernetes中,你隻需要建立一個ImageCache CRD,就可以直接使用鏡像緩存的能力。
$ cat > imagecache.yaml << EOF
apiVersion: eci.alibabacloud.com/v1
kind: ImageCache
metadata:
name: imagecache-rapids
spec:
images:
- registry.cn-shanghai.aliyuncs.com/tensorflow-samples/rapids-samples:0.8.2-cuda10.0-runtime-ubuntu16.04
imageCacheSize:
50
EOF
$ kubectl create -f imagecache.yaml
3.2.3.送出後稍等片刻。檢視ImageCache狀态,其中CACHID可以做後面送出任務時指定的snapshot-id
$ kubectl get imagecache
NAME AGE CACHEID PHASE PROGRESS
imagecache-rapids 3d9h imc-uf6dxdji7txxxxx Ready 100%
具體操作可以參考
4.送出rapids的開發環境
$ arena serve custom \
--name=rapids \
--selector=type=virtual-kubelet \
--toleration=all \
--annotation=k8s.aliyun.com/eci-image-snapshot-id=imc-uf6dxdji7txxxxx \
--annotation=k8s.aliyun.com/eci-instance-type=ecs.gn5i-c8g1.2xlarge \
--gpus=1 \
-e=PASSWORD=mypassw0rd \
--restful-port=80 \
--image=registry.cn-shanghai.aliyuncs.com/tensorflow-samples/rapids-samples:0.8.2-cuda10.0-runtime-ubuntu16.04
configmap/rapids-201912011815-custom-serving created
configmap/rapids-201912011815-custom-serving labeled
service/rapids-201912011815 created
deployment.extensions/rapids-201912011815-custom-serving created
--selector=type=virtual-kubelet表示通過Virtual Node啟動Pod
--annotation=k8s.aliyun.com/eci-instance-type=ecs.gn5i-c8g1.2xlarge表示指定使用ECI的執行個體類型,ecs.gn5i-c8g1.2xlarge代表阿裡雲P4機型。具體規格可以檢視文檔
--annotation=k8s.aliyun.com/eci-image-snapshot-id=imc-uf6dxdji7txxxxx指定3.2.3步中的CACHEID
-e=PASSWORD=mypassw0rd就是通過環境變量PASSWORD設定通路RAPIDS notebook
--gpus=1表示申請的GPU數目
4.檢視通路位址,這裡是ENDPOINT_ADDRESS和PORTS的組合, 在本示例中它是106.15.173.2:80。同時發現該任務在32秒的時候就可以變成Running狀态
$ arena serve list
NAME TYPE VERSION DESIRED AVAILABLE ENDPOINT_ADDRESS PORTS
rapids CUSTOM 201911181827 1 1 105.13.58.3 restful:80
$ arena serve get rapids
arena serve get rapids
NAME: rapids
NAMESPACE: default
VERSION: 201912011815
DESIRED: 1
AVAILABLE: 1
SERVING TYPE: CUSTOM
ENDPOINT ADDRESS: 106.15.173.2
ENDPOINT PORTS: restful:80
AGE: 32s
INSTANCE STATUS AGE READY RESTARTS NODE
rapids-201912011815-custom-serving-6b54d5cd-swcwz Running 32s 1/1 0 N/A
5.再次檢視叢集的GPU使用情況,發現已經有一個GPU資源被占用了
$ arena top node
NAME IPADDRESS ROLE STATUS GPU(Total) GPU(Allocated)
cn-shanghai.192.168.1.248 192.168.1.248 <none> ready 0 0
virtual-kubelet 172.20.2.20 agent ready 1000 1
-----------------------------------------------------------------------------------------
Allocated/Total GPUs In Cluster:
1/1000 (0%)
6.如果想查詢是哪個Pod占用了這個GPU, 可以在原有指令中加一個-d就可以看到具體的Pod名稱。
$ arena top node -d
NAME: cn-shanghai.192.168.1.248
IPADDRESS: 192.168.1.248
ROLE: <none>
Total GPUs In Node cn-shanghai.192.168.1.248: 0
Allocated GPUs In Node cn-shanghai.192.168.1.248: 0 (0%)
-----------------------------------------------------------------------------------------
NAME: virtual-kubelet
IPADDRESS: 172.20.2.20
ROLE: agent
NAMESPACE NAME GPU REQUESTS
default rapids-201912011815-custom-serving-6b54d5cd-swcwz 1
Total GPUs In Node virtual-kubelet: 1000
Allocated GPUs In Node virtual-kubelet: 1 (0%)
-----------------------------------------------------------------------------------------
Allocated/Total GPUs In Cluster: 1/1000 (0%)
7.根據步驟4中的通路位址和端口,打開本地浏覽器。輸入
http://{ENDPOINT ADDRESS}:{ENDPOINT PORT},在本例子中是
http://105.13.58.3:80說明: 推薦使用Chrome浏覽器。
8.輸入啟動指令中設定的密碼,然後單擊Log in。 在本例子中,密碼為mypassw0rd
步驟三:執行以圖搜圖的示例
1.進入示例所在目錄cuml。
2.輕按兩下cuml_knn.ipynb檔案。
3.單擊
說明: 單擊一次執行一個cell,請單擊至示例執行結束,詳細說明請參見示例執行過程。
示例執行過程
圖像搜尋示例的執行過程分為三個步驟:處理資料集、提取圖檔特征和搜尋相似圖檔。本文示例結果中對比了GPU加速的RAPIDS cuml KNN與CPU實作的scikit-learn KNN的性能。
1.處理資料集。
1.1 下載下傳和解壓資料集。 本文示例中使用了STL-10資料集,該資料集中包含10萬張未打标的圖檔,圖檔的尺寸均為:96 x 96 x 3, 您可以使用其他資料集,為便于提取圖檔特征,請確定資料集中圖檔的尺寸相同。
本文示例提供了download_and_extract(data_dir)方法供您下載下傳和解壓STL-10資料集。RAPIDS鏡像中已經将資料集下載下傳到./data目錄,您可以執行download_and_extract()方法直接解壓資料集。
1.2. 讀取圖檔。 從資料集解壓出的資料為二進制格式,執行read_all_images(path_to_data)方法加載資料并轉換為NHWC(batch, height, width, channels)格式,以便用Tensorflow提取圖檔特征。
1.3. 展示圖檔。 執行show_image(image)方法随機展示一張資料集中的圖檔。
1.4. 分割資料集。 按照9:1的比例把資料集分為兩部分,分别用于建立圖檔索引庫和搜尋圖檔。
2.提取圖檔特征。 使用開源架構Tensorflow和Keras提取圖檔特征,其中模型為基于ImageNet資料集的ResNet50(notop)預訓練模型。
2.1 設定Tensorflow參數。 Tensorflow預設使用所有GPU顯存,我們需要留出部分GPU顯存供cuML使用。您可以選擇一種方法設定GPU顯存參數:
- 方法1:依據運作需求進行顯存配置設定。
config.gpu_options.allow_growth = True
- 方法2:設定可以使用的GPU顯存比例。本示例中使用方法2,并且GPU顯存比例預設設定為0.3,即Tensorflow可以使用整塊GPU顯存的30%,您可以依據應用場景修改比例。
config.gpu_options.per_process_gpu_memory_fraction = 0.3
2.2 下載下傳ResNet50(notop)預訓練模型。 連接配接公網下載下傳模型(大小約91M),目前該模型已經被儲存到/root/.keras/models/目錄。
您可以執行model.summary()方法檢視模型的網絡結構。
2.2 提取圖檔特征。 對分割得到的兩個圖檔資料集執行model.predict()方法提取圖檔特征。
搜尋相似圖檔。
3.1 使用cuml KNN搜尋相似圖檔。 通過k=3設定K值為3,即查找最相似的3張圖檔,您可以依據使用場景自定義K值。
其中,knn_cuml.fit()方法為建立索引階段,knn_cuml.kneighbors()為搜尋近鄰階段。
KNN向量檢索耗時791 ms。
3.2 使用scikit-learn KNN搜尋相似圖檔。 通過n_neighbors=3設定K值為3,通過n_jobs=-1設定使用所有CPU進行近鄰搜尋。
說明: ecs.gn5i-c8g1.2xlarge的配置為8 vCPU。
KNN向量檢索耗時7分34秒。
3.3 對比cuml KNN和scikit-learn KNN的搜尋結果。 對比兩種方式的KNN向量檢索速度,使用GPU加速的cuml KNN耗時791 ms,使用CPU的scikit-learn KNN耗時7min 34s。前者為後者的近600倍。
驗證兩種方式的輸出結果是否相同,輸出結果為兩個數組:
- distance:最小的K個距離值。本示例中搜尋了10000張圖檔,K值為3,是以distance.shape=(10000,3)。
-
indices:對應的圖檔索引。indices.shape=(10000, 3)。
由于本示例所用資料集中存在重複圖檔,容易出現圖檔相同但索引不同的情況,是以使用distances,不使用indices對比結果。考慮到計算誤差,如果兩種方法得出的10000張圖檔中的3個最小距離值誤差都小于1,則認為結果相同。
圖檔搜尋結果
本示例從1萬張搜尋圖檔中随機選擇5張圖檔并搜尋相似圖檔,最終展示出5行4列圖檔。
第一列為搜尋圖檔,第二列至第四列為圖檔索引庫中的相似圖檔,且相似性依次遞減。每張相似圖檔的标題為計算的距離,數值越大相似性越低。
步驟4:清理工作
$ arena serve delete rapids
service "rapids-201912011815" deleted
deployment.extensions "rapids-201912011815-custom-serving" deleted
configmap "rapids-201912011815-custom-serving" deleted
INFO[0000] The Serving job rapids with version 201912011815 has been deleted successfully
總結
本文介紹通過Arena+阿裡雲
Serverless Kubernetes快速,簡單,低成本的使用RAPIDS加速資料科學。