1. 简介
Kubeflow 是适用于 Kubernetes 的机器学习工具包。该项目旨在让您以简单、可移植且可扩缩的方式在 Kubernetes 上部署机器学习 (ML) 工作流。我们的目标是提供一种简单直接的方法,将用于机器学习的卓越开源系统部署到各种基础架构中。 | |
从数据准备和分析到训练、评估再到部署,机器学习工作流可能涉及许多相互依赖的步骤。很难以临时方式(例如在一组笔记本或脚本中)编写和跟踪这些流程,审核和可再现性等问题会越来越多。Kubeflow 流水线 (KFP) 提供了一种部署可靠且可重复的机器学习流水线的方法,同时还能执行监控、审核、版本跟踪和可再现性,从而帮助解决这些问题。Cloud AI Pipelines 使设置 KFP 安装变得简单。 |
构建内容
在此 Codelab 中,您将构建一个 Web 应用,该应用使用 Kubeflow 流水线训练和部署模型来汇总 GitHub 问题。它基于 Kubeflow 示例代码库中的示例。完成后,您的基础架构将包含:
- 已安装 Kubeflow Pipelines 的 Google Kubernetes Engine (GKE) 集群(通过 Cloud AI Pipelines)。
- 在 GPU 上训练 Tensor2Tensor 模型的流水线
- 一个服务容器,用于根据经过训练的模型提供预测结果
- 一个界面,用于解读预测结果,为 GitHub 问题提供摘要
- 使用 Kubeflow Pipelines (KFP) SDK 从头开始创建流水线的笔记本
学习内容
您将构建的流水线基于 GitHub 问题数据训练 Tensor2Tensor 模型,学习通过问题正文预测问题标题。然后,它会导出经过训练的模型,并使用 Tensorflow Serving 部署导出的模型。流水线的最后一步启动一个 Web 应用,该应用会与 TF-Serving 实例交互以获取模型预测结果。
- 如何在 GKE 集群上安装 Kubeflow Pipelines
- 如何使用 Kubeflow 流水线构建和运行机器学习工作流
- 如何通过 AI Platform Notebook 定义和运行流水线
所需条件
- 对 Kubernetes 有基本的了解将有所帮助,但不是硬性要求
- 您拥有所有者权限的有效 GCP 项目
- (可选)一个 GitHub 账号
- 访问 Google Cloud Shell,可从 Google Cloud Platform (GCP) 控制台
2. 设置
Cloud Shell
在浏览器中访问 GCP Console,并使用您的项目凭据登录:
点击“选择项目”以便处理 Codelab 项目。
然后点击“激活 Cloud Shell”图标,启动 Cloud Shell。
启动 Cloud Shell 时,您会看到设定了要使用的项目的名称。检查此设置是否正确。
如需查找项目 ID,请访问 GCP 控制台的“首页”面板。如果屏幕为空,请点击“是”以创建信息中心。
然后,在 Cloud Shell 终端中根据需要运行以下命令,将 gcloud
配置为使用正确的项目:
export PROJECT_ID=<your_project_id> gcloud config set project ${PROJECT_ID}
创建存储分区
创建用于存储流水线文件的 Cloud Storage 存储分区。您需要使用全局唯一 ID,因此定义包含项目 ID 的存储分区名称会比较方便。使用 gsutil mb
(make bucket) 命令创建存储分区:
export PROJECT_ID=<your_project_id> export BUCKET_NAME=kubeflow-${PROJECT_ID} gsutil mb gs://${BUCKET_NAME}
或者,您可以通过 GCP Console 创建存储分区。
可选**:创建 GitHub 令牌**
此 Codelab 会调用 GitHub API 来检索公开提供的数据。为防止速率限制,尤其是在向 GitHub API 发送大量匿名请求的事件中,请设置一个不具有权限的访问令牌。这只是为了将您授权为个人而非匿名用户。
- 前往 https://github.com/settings/tokens,然后生成一个没有范围的新令牌。
- 将其保存在安全的地方。如果丢失,您需要将其删除,然后创建一个新令牌。
如果您跳过此步骤,此实验仍然可以正常运行,但可用于生成输入数据以测试模型的方式会稍有局限。
可选:固定有用的信息中心
在 GCP 控制台中,固定 Kubernetes Engine 和 Storage 信息中心以便于访问。
创建 AI Platform Pipelines(托管 Kubeflow 流水线)安装
请按照“在开始之前”中的说明进行操作然后点击“设置实例”此处部分,设置安装了 KFP 的 GKE 实例。请务必选中允许访问以下 Cloud API 复选框,如文档中所述。(否则,示例流水线将无法成功运行)。将安装命名空间保留为 default
。
您需要选择一个支持 Nvidia k80s 的可用区。您可以使用 us-central1-a 或 us-central1-c 作为默认设置。
安装完成后,请记下 AI Pipelines 信息中心中针对安装列出的 GKE 集群名称和可用区,为方便起见,请将环境变量设置为这些值。
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 地址、操作系统映像、内核版本和容器运行时的其他信息。
配置集群以在启用 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. 从流水线信息中心运行流水线
打开 Pipelines 信息中心
如果您尚未在 Cloud 控制台中访问“流水线”面板,请访问该面板。然后点击打开流水线信息中心以进行安装,然后点击左侧菜单栏中的流水线。如果收到加载错误,请刷新标签页。您应该会看到如下所示的新页面:
流水线说明
您将运行的流水线包含几个步骤(如需了解详情,请参阅此 Codelab 的附录):
- 现有模型检查点会复制到您的存储分区。
- Tensor2Tensor 模型是使用预处理的数据进行训练的。
- 训练从第一步中复制的现有模型检查点开始,然后再训练几百步。(在此 Codelab 期间,完全训练该模型需要很长时间)。
- 训练完成后,流水线步骤会以适合 TensorFlow Serving 处理的形式导出模型。
- 使用该模型部署 TensorFlow - 应用实例。
- 启动 Web 应用,与提供的模型交互以检索预测。
下载并编译流水线
在本部分中,我们将了解如何编译流水线定义。首先,我们需要安装 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 Pipelines,然后选择 Import by 网址。复制下面的网址,然后粘贴该网址,该网址指向您刚才编译的同一流水线。(从 Cloud Shell 上传文件需要执行一些额外的步骤,所以我们采用快捷方式。)
为流水线命名(例如 gh_summ
)。
运行流水线
点击列表中已上传的流水线(这样您就可以查看流水线的静态图表),然后点击创建实验以使用流水线创建新的实验。实验是将语义相关的运行组合在一起的方式。
为实验命名(例如,与流水线相同的名称 gh_summ
),然后点击下一步进行创建。
这将打开一个页面,您可以在其中输入运行的参数并启动运行。
建议您在 Cloud Shell 中执行以下命令,以帮助填写参数。
gcloud config get-value project echo "gs://${BUCKET_NAME}/codelab"
“运行”名称将自动填充,但您可以根据需要指定其他名称。
然后填写三个参数字段:
project
- (可选)
github-token
working-dir
对于工作目录,请输入您创建的 GCS 存储分区下的某个路径。添加“gs://
”前缀。对于 github-token
字段,输入您之前选择生成的令牌,或保留占位符字符串(如果您未生成令牌)。
填写相应字段后,点击开始,然后点击列出的运行作业以查看其详细信息。当给定的流水线步骤正在运行时,您可以点击该步骤获取其详细信息,包括查看其 pod 日志。(即使集群节点已中断,您也可以通过指向流水线步骤 Cloud Logging (Stackdriver) 日志的链接来查看流水线步骤的日志)。
查看流水线定义
当流水线运行时,您可能需要更详细地了解其如何组合在一起以及执行哪些操作。如需了解详情,请参阅此 Codelab 的附录部分。
在 TensorBoard 中查看模型训练信息
训练步骤完成后,选择其 Visualizations(可视化)标签页并点击蓝色的 Start TensorBoard 按钮,然后在准备就绪后点击 Open Tensorboard(打开 Tensorboard)。
探索“制品和执行”信息中心
在流水线执行时,Kubeflow 流水线会自动记录有关流水线步骤的元数据。系统会记录Artifact和Artifact信息。点击信息中心左侧导航栏中的这些条目可进一步探索。
对于工件,您可以查看概览面板和沿袭探索器面板。
启动由流水线创建的 Web 应用并进行预测
流水线中的最后一步部署一个 Web 应用,该应用提供了一个界面来查询经过训练的模型(通过 TF Serving 提供),以进行预测。
流水线完成后,通过端口转发连接到 Web 应用的服务(我们执行端口转发,因为在本 Codelab 中,Web 应用未设置为具有外部端点)。
在 Cloud Shell 中运行以下命令来查找服务名称:
kubectl get services
在列表中查找如下所示的服务名称:ghsumm-*-webappsvc
。
然后,在 Cloud Shell 中,按如下方式将端口转发到该服务,同时更改以下命令以使用 webappsvc 的名称:
kubectl port-forward svc/ghsumm-xxxxx-webappsvc 8080:80
运行端口转发后,点击“预览”图标,然后在下拉菜单中点击“在端口 8080 上预览”。
您应该会在新标签页中看到如下页面:
点击 Populate Random Issue 按钮可检索文本块。点击 Generate TItle(生成 TItle)以调用经过训练的模型并显示预测。
如果您的流水线参数包含有效的 GitHub 令牌,您还可以尝试在第二个字段中输入 GitHub 网址,然后点击“Generate Title”(生成标题)。如果您未设置有效的 GitHub 令牌,请仅使用“填充随机问题”字段。
4. 从 AI Platform Notebook 运行流水线
您还可以使用 KFP SDK 从 Jupyter 笔记本以交互方式定义和运行 Kubeflow 流水线。在本 Codelab 中,我们使用的 AI Platform Notebooks 使这一操作变得非常简单。
创建笔记本实例
我们将使用 Cloud Shell 的 API 来创建笔记本实例。(或者,您也可以通过 Cloud 控制台创建笔记本。如需了解详情,请参阅相关文档)。
在 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 控制台中列出您的笔记本实例。
上传 Codelab 笔记本
创建笔记本实例后,点击此链接上传 Codelab 的 Jupyter 笔记本。选择要使用的笔记本实例。该笔记本会自动打开。
执行笔记本
在本实验的剩余步骤中,请按照笔记本中的说明操作。请注意,在“设置”部分,则您需要先填写自己的值,然后才能运行笔记本的其余部分。
(如果您使用的是自己的项目,请不要忘记返回,并完成本实验的“清理”部分)。
5. 清理
如果您使用的是临时 Codelab 账号,则无需执行此操作;但如果您使用的是自己的项目,则可能需要移除 Pipelines 安装和笔记本。
移除 Pipelines GKE 集群
您可以从 Cloud 控制台中删除流水线集群。(如果您想重复使用 GKE 集群,可以选择仅删除流水线安装)。
删除 AI 笔记本实例
如果您运行“Notebook”部分,您可以通过 Cloud 控制台删除或停止笔记本实例。
可选:移除 GitHub 令牌
前往 https://github.com/settings/tokens,然后移除生成的令牌。
6. 附录
查看代码
定义流水线
此 Codelab 中使用的流水线在此处定义。
我们来看一下它的定义方式,以及其组件(步骤)的定义方式。我们将介绍一些要点,如需了解更多详情,请参阅文档。
Kubeflow 流水线步骤基于容器。构建流水线时,您可以将预构建组件与已构建的容器映像结合使用,也可以构建自己的组件。对于此 Codelab,我们构建了自己的 Codelab。
四个流水线步骤由可重复使用的组件定义,可通过其组件定义文件访问。在第一个代码段中,我们将通过网址访问这些组件定义文件,并使用这些定义创建“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
以内嵌方式执行步骤,直接指定容器映像和入口点参数。
您可以看到,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)
流水线中的最后一步(也以内嵌方式定义)是基于条件的。它会在“serve
”之后运行仅当训练步 launch_server
输出为字符串“true”时,此步骤才完成了。它会启动“预测 Web 应用”,我们用于向经过训练的 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 流水线文档介绍了一些有关构建您自己的组件的最佳实践。在此过程中,您需要定义和构建容器映像。您可以在此处查看此 Codelab 流水线的组件步骤。Dockerfile 定义位于 containers
子目录中,例如:此处。
使用具有 GPU 的抢占式虚拟机进行训练
抢占式虚拟机是 Compute Engine 虚拟机实例,最多可存在 24 小时,并且不提供任何可用性保证。抢占式虚拟机的价格低于标准 Compute Engine 虚拟机的价格。
借助 Google Kubernetes Engine (GKE),您可以轻松设置使用抢占式虚拟机的集群或节点池。您可以设置此类节点池,将 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 流水线,其中一个或多个流水线步骤(组件)在抢占式节点上运行,从而降低运行作业的费用。如需使用抢占式虚拟机提供正确的结果,您标识为抢占式的步骤应该是幂等的步骤(也就是说,如果您多次运行某个步骤,结果将是相同的),或者应该执行检查点操作,以便该步骤在中断时能够从中断的地方继续。
定义 Kubeflow 流水线时,您可以通过按如下方式修改操作,指示指定步骤应在抢占式节点上运行:
your_pipelines_op.apply(gcp.use_preemptible_nodepool())
如需了解详情,请参阅文档。
如果节点被抢占,您可能还需要重试该步骤多次。您可以按如下方式执行此操作 - 这里我们指定重试 5 次。
your_pipelines_op.set_gpu_limit(1).apply(gcp.use_preemptible_nodepool()).set_retry(5)
尝试修改我们在此 Codelab 中使用的 Kubeflow 流水线,以在抢占式虚拟机上运行训练步骤。
更改流水线规范中的以下行,以额外使用上文所述的抢占式节点池(确保您已按上述方法创建一个抢占式节点池),并重试 5 次:
train.set_gpu_limit(1)
然后,重新编译该流水线,上传新版本(为其指定新名称),然后运行新版流水线。