Kubeflow 管道 - GitHub 問題摘要

1. 簡介

KubeflowKubernetes 專用的機器學習工具包。這項專案旨在簡化在 Kubernetes 中部署機器學習 (ML) 工作流程的作業,並提高其可攜性與可擴充性。此專案目標是提供直觀的方式,協助使用者將領先業界的 ML 專屬開放原始碼系統部署至各個不同的基礎架構。

機器學習工作流程可能包含許多步驟,彼此之間存在依附元件,從資料準備和分析,到訓練、評估、部署等等。以臨時方式 (例如在一組筆記本或指令碼中) 撰寫及追蹤這些程序並不容易,稽核和重現性等事項也會日益成問題。Kubeflow Pipelines (KFP) 提供部署穩健且可重複執行的機器學習管道的方法,以及監控、稽核、版本追蹤和重現性等功能,有助於解決這些問題。Cloud AI Pipelines 可讓您輕鬆設定 KFP 安裝作業。

建構項目

在本程式碼研究室中,您將建構一個網路應用程式,使用 Kubeflow Pipelines 訓練及提供模型,以摘要說明 GitHub 問題。這個範例是以 Kubeflow Examples 存放區中的範例為基礎。完成後,基礎架構會包含:

課程內容

您建構的管道會根據 GitHub 問題資料訓練 Tensor2Tensor 模型,學習根據問題內容預測問題標題。接著,它會匯出訓練好的模型,並使用 Tensorflow Serving 部署匯出的模型。pipeline 的最後一個步驟會啟動網頁應用程式,與 TF-Serving 執行個體互動,以取得模型預測結果。

  • 如何在 GKE 叢集上安裝 Kubeflow Pipelines
  • 如何使用 Kubeflow Pipelines 建構及執行機器學習工作流程
  • 如何從 AI 平台筆記本定義及執行管道

軟硬體需求

2. 設定

Cloud Shell

在瀏覽器中前往 GCP 主控台,並使用專案憑證登入:

視需要按一下「選取專案」,確保您使用的是程式碼研究室專案。

4f23e1fe87a47cb2.png

然後點選控制台右上角的「啟用 Cloud Shell」圖示,啟動 Cloud Shell

ecf212797974dd31.png

啟動 Cloud Shell 時,系統會顯示目前使用的專案名稱。確認這項設定是否正確。

如要尋找專案 ID,請前往 GCP 主控台的「首頁」面板。如果畫面空白,請在提示中按一下「是」建立資訊主頁。

115cdf745978ad.png

接著,視需要執行下列指令,將 gcloud 設定為使用正確的專案:

export PROJECT_ID=<your_project_id>
gcloud config set project ${PROJECT_ID}

建立儲存空間 bucket

建立 Cloud Storage bucket,用來儲存管道檔案。您必須使用全域不重複的 ID,因此定義包含專案 ID 的 bucket 名稱很方便。使用 gsutil mb (建立值區) 指令建立值區:

export PROJECT_ID=<your_project_id>
export BUCKET_NAME=kubeflow-${PROJECT_ID}
gsutil mb gs://${BUCKET_NAME}

或者,您也可以透過 GCP 主控台建立 bucket。

選用**:建立 GitHub 權杖**

本程式碼研究室會呼叫 GitHub API,擷取公開資料。為避免受到速率限制,特別是在大量匿名要求傳送至 GitHub API 的活動中,請設定沒有權限的存取權權杖。這只是為了授權您個人,而非匿名使用者。

  1. 前往 https://github.com/settings/tokens,產生沒有範圍的新權杖。
  2. 請將救援碼儲存在安全的地方。如果遺失,請刪除並建立新金鑰。

如果略過這個步驟,實驗室仍可運作,只是在產生輸入資料來測試模型時,選項會比較有限。

選用:釘選實用資訊主頁

在 GCP 主控台中,釘選「Kubernetes Engine」和「Storage」資訊主頁,方便存取。

2a50622902d75f6a.png

建立 AI 平台管道 (託管 Kubeflow 管道) 安裝項目

請按照這個網頁的「事前準備」和「設定執行個體」一節中的說明,設定已安裝 KFP 的 GKE 執行個體。請務必勾選「允許存取下列 Cloud API」方塊,如說明文件所示。(否則範例管道將無法順利執行)。將安裝命名空間保留為 default

您需要選取支援 Nvidia k80 的區域。您可以將 us-central1-aus-central1-c 設為預設值。

安裝完成後,請記下 AI Pipelines 資訊主頁中列出的 GKE 叢集名稱區域,並為這些值設定環境變數,方便後續使用。

6f0729a4fdee88ac.png

export ZONE=<your zone>
export CLUSTER_NAME=<your cluster name>

設定 kubectl 以使用新 GKE 叢集的憑證

建立 GKE 叢集後,請在 Cloud Shell 中執行下列指令,設定 kubectl 使用新叢集的憑證:

gcloud container clusters get-credentials ${CLUSTER_NAME} \
  --project ${PROJECT_ID} \
  --zone ${ZONE}

或者,按一下 AI Pipelines 資訊主頁中的叢集名稱,前往該叢集的 GKE 頁面,然後按一下頁面頂端的「連線」。在彈出式視窗中,將指令貼入 Cloud Shell。

這會設定 kubectl 環境,方便您與叢集互動。如要驗證設定,請執行下列指令:

kubectl get nodes -o wide

您應該會看到節點列出,狀態為「Ready」,以及節點年齡、版本、外部 IP 位址、OS 映像檔、核心版本和容器執行階段等其他資訊。

設定叢集,在啟用 GPU 的節點集區中安裝 Nvidia 驅動程式

接著,我們會將 daemonset 套用至叢集,在所有啟用 GPU 的叢集節點上安裝 Nvidia 驅動程式:

kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/container-engine-accelerators/master/nvidia-driver-installer/cos/daemonset-preloaded.yaml

接著執行下列指令,授予 KFP 元件建立新 Kubernetes 資源的權限:

kubectl create clusterrolebinding sa-admin --clusterrole=cluster-admin --serviceaccount=kubeflow:pipeline-runner

建立 GPU 節點集區

接著,我們要設定大小為 1 的 GPU 節點集區:

gcloud container node-pools create gpu-pool \
    --cluster=${CLUSTER_NAME} \
    --zone ${ZONE} \
    --num-nodes=1 \
    --machine-type n1-highmem-8 \
    --scopes cloud-platform --verbosity error \
    --accelerator=type=nvidia-tesla-k80,count=1

3. 從「管道」資訊主頁執行管道

開啟管道資訊主頁

如果尚未前往 Cloud 控制台,請前往 Pipelines 面板。然後點選安裝項目的「OPEN PIPELINES DASHBOARD」(開啟管線資訊主頁),並點選左選單列中的「Pipelines」(管線)。如果發生載入錯誤,請重新整理分頁。您應該會看到類似下方的頁面:

7bb5a9cf0773c3bc.png

管道說明

您將執行的管道包含幾個步驟 (詳情請參閱本程式碼研究室的附錄):

  1. 現有模型檢查點會複製到值區。
  2. 使用預先處理的資料訓練 Tensor2Tensor 模型。
  • 訓練作業會從第一個步驟中複製的現有模型檢查點開始,然後再訓練幾百個步驟。(在本程式碼研究室中完整訓練模型會花費太多時間)。
  • 訓練完成後,管道步驟會匯出模型,並以適合 TensorFlow Serving 的形式提供模型。
  1. 並使用該模型部署 TensorFlow Serving 執行個體。
  2. 啟動網頁應用程式,與提供的模型互動,以擷取預測結果。

下載及編譯管道

在本節中,我們將瞭解如何編譯管道定義。首先,我們需要安裝 KFP SDK。在 Cloud Shell 中執行下列指令:

pip3 install -U kfp

如要下載管道定義檔案,請從 Cloud Shell 執行下列指令:

curl -O https://raw.githubusercontent.com/amygdala/kubeflow-examples/ghsumm/github_issue_summarization/pipelines/example_pipelines/gh_summ_hosted_kfp.py

接著,執行管道定義檔案,如下所示:

python3 gh_summ_hosted_kfp.py

結果會顯示檔案 gh_summ_hosted_kfp.py.tar.gz

上傳已編譯的管道

在 Kubeflow Pipelines 網頁介面中,按一下「Upload pipeline」,然後選取「Import by URL」。複製下列網址,然後貼上。這個網址指向您剛編譯的相同管道。(從 Cloud Shell 上傳檔案需要幾個額外步驟,因此我們採取捷徑)。

https://storage.googleapis.com/aju-dev-demos-codelabs/KF/compiled_pipelines/gh_summ_hosted_kfp.py.tar.gz

為管道命名 (例如 gh_summ)。

867fdbe248d13bab.png

執行管道

在清單中按一下已上傳的管道 (這會顯示管道的靜態圖),然後按一下「建立實驗」,使用管道建立新的「實驗」。實驗可將語意相關的執行作業分組。

d4b5b1a043d32d4a.png

為實驗命名 (例如與管道相同的名稱 gh_summ),然後按一下「Next」(下一步) 建立實驗。

d9f7d2177efad53.png

系統會顯示頁面,供您輸入 Run 的參數並啟動。

您可能需要在 Cloud Shell 中執行下列指令,協助填入參數。

gcloud config get-value project
echo "gs://${BUCKET_NAME}/codelab"

系統會自動填入執行名稱,但您也可以視需要變更名稱。

然後填寫三個參數欄位:

  • project
  • (選填) github-token
  • working-dir

在 working-dir 中,輸入您建立的 GCS bucket 下方的路徑。請加入「gs://」前置字元。在 github-token 欄位中,輸入您先前選擇性產生的權杖,或將預留位置字串保留原樣 (如果您未產生權杖)。

8676afba6fd32ac1.png

填寫完欄位後,按一下「開始」,然後點選列出的執行作業來查看詳細資料。在特定管道步驟執行期間,您可以點選該步驟來取得更多資訊,包括查看 Pod 記錄。(您也可以透過管道步驟的 Cloud Logging (Stackdriver) 記錄連結查看記錄,即使叢集節點已終止也沒問題)。

db2dc819ac0f5c1.png

查看管道定義

在管道執行期間,您可能想進一步瞭解管道的組合方式和執行作業。程式碼研究室的「附錄」一節提供更多詳細資料。

在 TensorBoard 中查看模型訓練資訊

訓練步驟完成後,選取「Visualizations」(視覺化) 分頁標籤,然後按一下藍色的「Start TensorBoard」(啟動 TensorBoard) 按鈕,準備就緒後,按一下「Open Tensorboard」(開啟 TensorBoard)

6cb511540a64b9e5.png

d55eb03c4d04f64d.png

探索構件和執行作業資訊主頁

Kubeflow Pipelines 會在管道執行時,自動記錄管道步驟的中繼資料。系統會記錄 ArtifactExecution 資訊。按一下資訊主頁左側導覽列中的這些項目,即可進一步探索。

3002c4055cc8960b.png

如果是構件,您可以查看總覽面板和歷程探索器面板。

7885776e899d1183.png

40c4f7e5b6545dec.png

啟動管道建立的網頁應用程式,並進行一些預測

pipeline 的最後一個步驟會部署網頁應用程式,提供查詢訓練模型的 UI (透過 TF Serving 提供),以進行預測。

管道完成後,請轉送通訊埠至其服務,連線至 Web 應用程式 (我們轉送通訊埠是因為在本程式碼研究室中,Web 應用程式服務未設定外部端點)。

在 Cloud Shell 中執行下列指令,找出服務名稱:

kubectl get services

在清單中尋找類似 ghsumm-*-webappsvc 的服務名稱。

接著,在 Cloud Shell 中,將通訊埠轉送至該服務,如下所示變更下列指令,使用您的 webappsvc 名稱

kubectl port-forward svc/ghsumm-xxxxx-webappsvc 8080:80

通訊埠轉送作業執行完畢後,請點選 Cloud Shell 窗格上方的「預覽」圖示,然後在下拉式選單中點選「透過以下通訊埠預覽:8080」。

65572bb3b12627cc.png

新分頁中應會顯示類似下方的頁面:

902ad2d555281508.png

按一下「Populate Random Issue」(填入隨機問題) 按鈕,即可擷取一段文字。按一下「Generate Title」(產生標題),呼叫訓練好的模型並顯示預測結果。

b7c39ce51ee603bd.png

如果管道參數包含有效的 GitHub 權杖,您也可以嘗試在第二個欄位中輸入 GitHub 網址,然後按一下「產生標題」。如果沒有設定有效的 GitHub 權杖,請只使用「Populate Random Issue」欄位。

4. 從 AI Platform Notebook 執行管道

您也可以使用 KFP SDK,從 Jupyter 筆記本以互動方式定義及執行 Kubeflow Pipelines。AI Platform Notebooks (本程式碼研究室將使用這項服務) 可讓您輕鬆完成這項作業。

建立筆記本執行個體

我們將使用 Cloud Shell 的 API 建立筆記本執行個體。(或者,您也可以透過 Cloud Console 建立筆記本。詳情請參閱說明文件

在 Cloud Shell 中設定下列環境變數:

export INSTANCE_NAME="kfp-ghsumm"
export VM_IMAGE_PROJECT="deeplearning-platform-release"
export VM_IMAGE_FAMILY="tf2-2-3-cpu"
export MACHINE_TYPE="n1-standard-4"
export LOCATION="us-central1-c"

接著,在 Cloud Shell 中執行指令,建立筆記本執行個體:

gcloud beta notebooks instances create $INSTANCE_NAME \
  --vm-image-project=$VM_IMAGE_PROJECT \
  --vm-image-family=$VM_IMAGE_FAMILY \
  --machine-type=$MACHINE_TYPE --location=$LOCATION

首次執行這項指令時,系統可能會要求您為專案啟用 notebooks API。如果同意,請回覆「y」。

幾分鐘後,筆記本伺服器就會開始運作。您可以在 Cloud Console 中查看 Notebook 執行個體

206adf3905413dfa.png

上傳程式碼研究室筆記本

建立筆記本執行個體後,按一下這個連結,上傳程式碼研究室的 Jupyter 筆記本。選取要使用的筆記本執行個體。系統會自動開啟筆記本。

執行筆記本

按照筆記本中的指示完成實驗室的其餘部分。請注意,在筆記本的「設定」部分,您需要填入自己的值,才能執行筆記本的其餘部分。

(如果您使用自己的專案,請記得返回並完成本實驗室的「清除」部分)。

5. 清除所用資源

如果您使用臨時 Codelab 帳戶,則不需要執行這項操作,但如果您使用自己的專案,可能需要移除 Pipelines 安裝項目和 Notebook。

關閉 Pipelines GKE 叢集

您可以從 Cloud 控制台刪除 Pipelines 叢集。(如要重複使用 GKE 叢集,可以選擇只刪除 Pipelines 安裝項目)。

刪除 AI Notebook 執行個體

如果您已執行程式碼研究室的「筆記本」部分,可以從 Cloud Console 刪除停止筆記本執行個體。

選用:移除 GitHub 權杖

前往 https://github.com/settings/tokens,然後移除產生的權杖。

6. 附錄

程式碼概覽

定義管道

本程式碼研究室使用的管道定義請見這裡

讓我們看看如何定義轉換路徑,以及如何定義轉換路徑的元件 (步驟)。我們將介紹一些重點,詳情請參閱說明文件

Kubeflow Pipeline 步驟是以容器為基礎。建構管道時,您可以使用預先建構的元件 (內含已建構的容器映像檔),也可以自行建構元件。在本程式碼研究室中,我們已建構自己的應用程式。

其中四個管道步驟是從可重複使用的元件定義,並透過元件定義檔案存取。在第一個程式碼片段中,我們會透過網址存取這些元件定義檔案,並使用這些定義建立「ops」,用於建立管道步驟。

import kfp.dsl as dsl
import kfp.gcp as gcp
import kfp.components as comp

...

copydata_op = comp.load_component_from_url(
  'https://raw.githubusercontent.com/kubeflow/examples/master/github_issue_summarization/pipelines/components/t2t/datacopy_component.yaml'
  )

train_op = comp.load_component_from_url(
  'https://raw.githubusercontent.com/kubeflow/examples/master/github_issue_summarization/pipelines/components/t2t/train_component.yaml'
  )

以下是其中一個元件定義 (訓練作業),格式為 YAML。您會看到已定義的輸入、輸出、容器映像檔和容器進入點引數。

name: Train T2T model
description: |
  A Kubeflow Pipeline component to train a Tensor2Tensor
  model
metadata:
  labels:
    add-pod-env: 'true'
inputs:
  - name: train_steps
    description: '...'
    type: Integer
    default: 2019300
  - name: data_dir
    description: '...'
    type: GCSPath
  - name: model_dir
    description: '...'
    type: GCSPath
  - name: action
    description: '...'
    type: String
  - name: deploy_webapp
    description: '...'
    type: String
outputs:
  - name: launch_server
    description: '...'
    type: String
  - name: train_output_path
    description: '...'
    type: GCSPath
  - name: MLPipeline UI metadata
    type: UI metadata
implementation:
  container:
    image: gcr.io/google-samples/ml-pipeline-t2ttrain:v3ap
    args: [
      --data-dir, {inputValue: data_dir},
      --action, {inputValue: action},
      --model-dir, {inputValue: model_dir},
      --train-steps, {inputValue: train_steps},
      --deploy-webapp, {inputValue: deploy_webapp},
      --train-output-path, {outputPath: train_output_path}
    ]
    env:
      KFP_POD_NAME: "{{pod.name}}"
    fileOutputs:
      launch_server: /tmp/output
      MLPipeline UI metadata: /mlpipeline-ui-metadata.json

您也可以透過 dsl.ContainerOp 建構函式定義管道步驟,如下所示。

以下是管道定義的大部分內容。我們將定義管道輸入內容 (及其預設值)。接著定義管道步驟。我們大多使用上述定義的「ops」,但也會透過 ContainerOp 定義「serve」步驟,直接指定容器映像檔和進入點引數。

您可以看到 trainlog_modelserve 步驟會將前幾個步驟的輸出內容做為輸入內容。如要進一步瞭解如何指定這項設定,請參閱這篇文章

@dsl.pipeline(
 name='Github issue summarization',
 description='Demonstrate Tensor2Tensor-based training and TF-Serving'
)
def gh_summ(  #pylint: disable=unused-argument
 train_steps: 'Integer' = 2019300,
 project: str = 'YOUR_PROJECT_HERE',
 github_token: str = 'YOUR_GITHUB_TOKEN_HERE',
 working_dir: 'GCSPath' = 'gs://YOUR_GCS_DIR_HERE',
 checkpoint_dir: 'GCSPath' = 'gs://aju-dev-demos-codelabs/kubecon/model_output_tbase.bak2019000/',
 deploy_webapp: str = 'true',
 data_dir: 'GCSPath' = 'gs://aju-dev-demos-codelabs/kubecon/t2t_data_gh_all/'
 ):


 copydata = copydata_op(
   data_dir=data_dir,
   checkpoint_dir=checkpoint_dir,
   model_dir='%s/%s/model_output' % (working_dir, dsl.RUN_ID_PLACEHOLDER),
   action=COPY_ACTION,
   )


 train = train_op(
   data_dir=data_dir,
   model_dir=copydata.outputs['copy_output_path'],
   action=TRAIN_ACTION, train_steps=train_steps,
   deploy_webapp=deploy_webapp
   )

 serve = dsl.ContainerOp(
     name='serve',
     image='gcr.io/google-samples/ml-pipeline-kubeflow-tfserve:v6',
     arguments=["--model_name", 'ghsumm-%s' % (dsl.RUN_ID_PLACEHOLDER,),
         "--model_path", train.outputs['train_output_path']
         ]
     )

 train.set_gpu_limit(1)

請注意,我們要求「train」步驟在叢集節點上執行,且該節點至少有 1 個可用的 GPU。

  train.set_gpu_limit(1)

管道的最後一個步驟 (同樣是內嵌定義) 是有條件的。只有在訓練步驟 launch_server 輸出字串「true」時,這個步驟才會在「serve」步驟完成後執行。這會啟動「預測網頁應用程式」,我們曾使用這個應用程式,向訓練後的 T2T 模型要求問題摘要。

 with dsl.Condition(train.outputs['launch_server'] == 'true'):
   webapp = dsl.ContainerOp(
       name='webapp',
       image='gcr.io/google-samples/ml-pipeline-webapp-launcher:v1',
       arguments=["--model_name", 'ghsumm-%s' % (dsl.RUN_ID_PLACEHOLDER,),
           "--github_token", github_token]

       )
   webapp.after(serve)

元件容器映像檔定義

Kubeflow Pipeline 文件說明瞭建構自有元件的一些最佳做法。在這個過程中,您需要定義及建構容器映像檔。您可以在這裡查看本程式碼研究室 pipeline 的元件步驟。Dockerfile 定義位於 containers 子目錄中,例如這裡

使用搭載 GPU 的先占 VM 進行訓練

先占 VM 是 Compute Engine VM 執行個體,生命週期最長可達 24 小時,但不提供可用性保證。先占 VM 的價格比標準 Compute Engine VM 低。

使用 Google Kubernetes Engine (GKE),您可以輕鬆設定使用可搶占 VM 的叢集或節點集區。您可以設定這類節點集區,並將 GPU 附加至先占執行個體。這些節點的運作方式與一般啟用 GPU 的節點相同,但 GPU 只會在執行個體存留時常駐。

如要為叢集設定啟用 GPU 的先占節點集區,請執行類似下列的指令,並根據您的叢集名稱和區域編輯下列指令,然後根據需求調整加速器類型和數量。您可以選擇定義節點集區,根據目前的工作負載自動調度資源。

gcloud container node-pools create preemptible-gpu-pool \
    --cluster=<your-cluster-name> \
    --zone <your-cluster-zone> \
    --enable-autoscaling --max-nodes=4 --min-nodes=0 \
    --machine-type n1-highmem-8 \
    --preemptible \
    --node-taints=preemptible=true:NoSchedule \
    --scopes cloud-platform --verbosity error \
    --accelerator=type=nvidia-tesla-k80,count=4

您也可以透過 Cloud 控制台設定節點集區。

定義使用可搶占 GKE 節點的 Kubeflow 管道

如果您在 GKE 上執行 Kubeflow,現在可以輕鬆定義及執行 Kubeflow Pipelines,其中一或多個管道步驟 (元件) 會在可搶占節點上執行,進而降低執行工作的成本。如要使用先佔 VM 取得正確結果,您識別為先佔的步驟應為冪等 (也就是說,如果多次執行步驟,結果會相同),或應檢查點工作,以便步驟在遭到中斷時從中斷處繼續執行。

定義 Kubeflow Pipeline 時,您可以修改作業,指出特定步驟應在可搶占節點上執行,如下所示:

your_pipelines_op.apply(gcp.use_preemptible_nodepool())

詳情請參閱說明文件

如果節點遭到先占,您可能也會想重試步驟幾次。您可以按照下列方式操作,這裡我們指定 5 次重試。

your_pipelines_op.set_gpu_limit(1).apply(gcp.use_preemptible_nodepool()).set_retry(5)

嘗試編輯本程式碼研究室中使用的 Kubeflow pipeline,在先占 VM 上執行訓練步驟

在管道規格中變更下列行,額外使用可搶占式節點集區 (請務必如上所示建立節點集區),並重試 5 次:

  train.set_gpu_limit(1)

接著重新編譯管道、上傳新版本 (並命名),然後執行新版管道。