Kubeflow 管道 - GitHub 問題摘要

1. 簡介

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

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

建構項目

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

課程內容

您要建構的管道會根據 GitHub 問題資料訓練 Tensor2Tensor 模型,學習根據問題內容預測問題標題。接著,它會匯出訓練好的模型,並使用 Tensorflow Serving 部署匯出的模型。管道的最後一個步驟會啟動網頁應用程式,與 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-a 或 us-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),然後點選「下一步」建立實驗。

d9f7d2177efad53.png

系統會顯示頁面,供您輸入 Run 的參數並啟動 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 會在管道執行時,自動記錄管道步驟的中繼資料。系統會記錄 Artifact 和 Execution 資訊。按一下資訊主頁左側導覽列中的這些項目,即可進一步探索。

3002c4055cc8960b.png

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

7885776e899d1183.png40c4f7e5b6545dec.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」。

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

206adf3905413dfa.png

上傳程式碼研究室筆記本

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

執行筆記本

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

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

5. 清理

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

關閉 Pipelines GKE 叢集

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

刪除 AI Notebook 執行個體

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

選用:移除 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」步驟,直接指定容器映像檔和進入點引數。

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

@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 管道,在先占 VM 上執行訓練步驟。

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

  train.set_gpu_limit(1)

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