この記事はTensorFlow Advent Calendar2018年 3日目の記事です。
今年のAdvent CalendarはKubeflow Pipeliensについて書こうと思います。
タイトルでは「動かしてみた」と言っていますが、全部を動かすことは出来ませんでした。ちゃんと動けばもう少し詳細まで見て行きたかったのですが、ひとまずやってみたところまで記事にまとめましたので、アップデートあれば追記していきます。
機械学習システムの実環境へのデプロイ&サービング
機械学習が普及した2018年ですが、PoC(Proof of Concept)を超えて実運用まで漕ぎ着けている事例が増えてきたとはいえ、実システムに組み込んで運用する場合のハードルは依然高いように見えます。 その理由としては、2014年にGoogleから出された論文[Machine Learning: The High Interest Credit Card of Technical Debt] (https://ai.google/research/pubs/pub43146) でいくつか課題が挙げられており、それらの一つの解決策として機械学習プラットフォームであるTensorFlow Extended(TFX)が提案されています。
現在、OSSとして公開されているTFXはそれぞのコンポーネントがバラバラであり、機械学習のワークフロー全体としては管理しづらいものでした。そこで機械学習のワークフロー全体をEndToEndで管理できるようにするためのコンポーネントがkubeflow pipelineです。以前から機械学習システム構築するためのツールキットであるKubeflowにTFXはその一部が取り込まれていましたが、今年11月に発表されたKubeflow pipelinesでワークフローの管理が洗練されより使いやすくなったように感じます。
2017年末にkubeflowが出てきてから一年、kubeflow自体はまだ0.4と発展途上であり、公式のexamplesもまともに動かなかったりします。このKubeflow Pipelinesも例に漏れずexampleを動かすのさえ苦行ではありますが、ユーザーが増えて知見が貯まることを願ってご紹介をしようと思います。
Kubeflow Pipelines
kubeflow pipelinesはKubeflowの新しいコンポーネントであり、機械学習システムのワークフローを管理できるツールです。ワークフローの定義はPythonをベースにしたDSLで記述し、その中でTFXのコンポーネントを活用する事ができます。また、ワークフローごとに異なる設定をして実験(Experiment)を実施したログが残せたり、ワークフローがちゃんと動いているかモニタリングができるようになっていたりと、機会学習システムのモデリング以外に必要な機能が整備されています。ワークフローマネジメント自体はKubeflowのCoreComponentである、Argoが動いているらしいですが、UIが整ったことでやっと統一感があるpipeline管理ツールが出てきたなというところです。
Kubeflow Pipelines examples
今回はkubeflowのslackで紹介されていたこのexamplesを試してみます。GKEを使ってBigQueryのChicago taxiのデータを用いて、TFXのコンポーネントを使って機械学習のワークフローを定義し、サービングまで機械学習モデルをデプロイしていく良いチュートリアルです。
基本的にはREADME.mdに書かれている通りに動かしますが、そのままではエラーが出る部分などあるのでworkaroundも示しながら進めたいと思います。
- GCP環境のセットアップ
- Kubernetes Engine (GKE) クラスタの準備
- Kubeflow Pipelinesのインストール
- Examplesを試す
GCP環境のセットアップ
まずはGCPの環境を整えます。大まかな手順としては下記です。
- GCPプロジェクトを作る
- 必要なAPIをenableにする
- Cloud Machine Learning Engine、Kubernetes Engine、オプションでTFTやTFMAをDataflow上で動かしたり、データソースをcsvファイルからBigQueryに変えるなどする場合はそれぞれEnableする必要があります
- gcloud sdkをインストールする、もしくはcloud shellを使う
- GCSのバケットを用意する
- Backet名はXXXにしてあります。
Kubernetes Engine (GKE) クラスタの準備
このREADME.mdにGKEクラスタを作成します。
gcloud beta container --project <PROJECT_NAME> clusters create "kubeflow-pipelines" --zone "us-central1-a" --username "admin" --cluster-version "1.9.7-gke.11" --machine-type "custom-8-40960" --image-type "COS" --disk-type "pd-standard" --disk-size "100" --scopes "https://www.googleapis.com/auth/cloud-platform" --num-nodes "4" --enable-cloud-logging --enable-cloud-monitoring --no-enable-ip-alias --network "projects/<PROJECT_NAME>/global/networks/default" --subnetwork "projects/<PROJECT_NAME>/regions/us-central1/subnetworks/default" --addons HorizontalPodAutoscaling,HttpLoadBalancing,KubernetesDashboard --enable-autoupgrade --enable-autorepair
PROJECT_NAMEには使っているGCPのプロジェクト名を入れて下さい。次に作ったクラスタをコンテキストに割り当て、ClusterRoleリソースを作成します。
> gcloud container clusters get-credentials kubeflow-pipelines --zone us-central1-a --project <PROJECT_NAME>
Fetching cluster endpoint and auth data.
kubeconfig entry generated for kubeflow-pipelines.
> kubectl create clusterrolebinding ml-pipeline-admin-binding --clusterrole=cluster-admin --user=$(gcloud config get-value account)
clusterrolebinding.rbac.authorization.k8s.io "ml-pipeline-admin-binding" created
> kubectl create clusterrolebinding sa-admin --clusterrole=cluster-admin --serviceaccount=kubeflow:pipeline-runner
clusterrolebinding.rbac.authorization.k8s.io "sa-admin" created
Kubeflow Pipelinesのインストール
Kubeflowのこのページの中のDeploy Kubeflow Pipelinesに従います。
Kubeflow PipelinesをGKEクラスタにデプロイします。
> PIPELINE_VERSION=0.1.2
> kubectl create -f https://storage.googleapis.com/ml-pipeline/release/$PIPELINE_VERSION/bootstrapper.yaml
clusterrole.rbac.authorization.k8s.io "mlpipeline-deploy-admin" created
clusterrolebinding.rbac.authorization.k8s.io "mlpipeline-admin-role-binding" created
job.batch "deploy-ml-pipeline-qqk9j" created
> kubectl get job
NAME DESIRED SUCCESSFUL AGE
deploy-ml-pipeline-qqk9j 1 1 7m
> kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.7.240.1 <none> 443/TCP 18m
Kubeflow Pipelines UIにローカルのブラウザからGKE上のpod内のコンテナにアクセスできるようにポートフォワードの設定をしておきます。
> export NAMESPACE=kubeflow
> kubectl port-forward -n ${NAMESPACE} `kubectl get pods -n ${NAMESPACE} --selector=service=ambassador -o jsonpath='{.items[0].metadata.name}'` 8080:80
この状態でCloud Shellから"Web Preview"するとKubeflowのとても簡素なダッシュボードに飛びます。
またそのURLの末尾に/pipelinesを追加することでKubeflow pipelinesのUIに移れます。
以上でREADME.mdに記載されているExamplesのための準備は終わりました。しかし、これ以降のExamplesを動かすためにもう少し準備をします。Examplesを完走するためには、下記2点が必要です。
- Jupyter Notebookへ設定を追加する
- 必要なJupyter extensionをインストールする
Jupyter Notebookへ設定を追加する
GKE上にJupyter Notebookのサービスは立ち上がるのですが、新しいnotebookを起動できません。しかしこのissueを参考にしてFixすることができました。
まずはJupyterHubに入ります。サインインにUsernameとPasswordを求められますが、何を使っても入れます。私はGCPのアカウントを使いました。まずはイメージを選択しSpawnします。今回はgcr.io/kubeflow-images-public/tensorflow-1.10.1-notebook-cpu:v0.3.1
を選択しました。立ち上がったら、Jupyter NotebookのPodに入り、jupyterのコンフィグファイルに設定を追記します。
# Jupyter pod nameを調べます `jupyter-<USER>` (Here user is 'admin')
> kubectl get pods -n kubeflow
> kubectl exec -it -n kubeflow jupyter-<USER> bash
# 設定ファイルを変更します。
> jovyan@jupyter-admin:~$ vim .jupyter/jupyter_notebook_config.py
上記のようにc.NotebookApp.allow_origin='*'
を追記します。そしてPodを再起動。
> jovyan@jupyter-admin:~$ ps -auxw
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
jovyan 1 0.0 0.0 4528 820 ? Ss 12:44 0:00 tini -- start-singleuser.sh --ip="0.0.0.0" --port=8888 --allow-root
jovyan 5 0.1 0.8 292128 62168 ? Sl 12:44 0:01 /opt/conda/bin/python /opt/conda/bin/jupyterhub-singleuser --ip="0.0.0.0" --port=8888 --allow-root
jovyan 33 0.0 0.0 20316 4108 ? Ss 12:52 0:00 bash
jovyan 41 0.0 0.0 36080 3300 ? R+ 12:53 0:00 ps -auxw
> jovyan@jupyter-admin:~$ kill 1
> jovyan@jupyter-admin:~$ command terminated with exit code 137
> export NAMESPACE=kubeflow
> kubectl port-forward -n ${NAMESPACE} `kubectl get pods -n ${NAMESPACE} --selector=service=ambassador -o jsonpath='{.items[0].metadata.name}'` 8080:80
これでnotebookを立ち上げることができるようになりました。
Juptyter notebookでTFMAを可視化するための extensionのインストール
TFMAはインタラクティブにデータをスライスし、その結果をjupyter notebook上で可視化することができます。しかし後述するTFMAのパートでうまくレンダリングできませんでした。 こちらを参考にレンダリングに必要なExtensionを入れましたが下記のようなエラーが出ています。
> jupyter nbextension enable --py widgetsnbextension
> jupyter nbextension install --py --symlink tensorflow_model_analysis
OSError: [Errno 13] Permission denied: '/usr/local/share/jupyter/nbextensions'
> jupyter nbextension enable --py tensorflow_model_analysis
きっとExamplesのイメージもすでにエクステンションを入れた状態で作られているとは思いますが、うまく入れられていないのでレンダリングできなかったのでしょうね。解決しましたら追記します!
Running the examples
Kubeflow Pipelineに機械学習のPipelineを定義していきます。Kubeflow pipelinesのUIに入るとすでにいくつかサンプルのPipelineが定義されています。
ワークフローはここにあるように、DSLで書かれた.pyファイルをコンパイルして、Kubeflow PipelinesのUIにアップロードすることでデプロイできます。
現在、サンプルとして挙げられているものはそれぞれ、ここのSampleにあげられているもののようです。特にML-TFXはExample pipeline that does classification with model analysis based on a public tax cab BigQuery dataset.とあるように、workflowと基本的には同じっぽいです。(ちなみに、試しにやってみたら途中でエラー吐くので諦めました)。
workflowをやってみる
ここではすでにUI上にあるPipelineではなくて、新しくPipelineをアップロードして実行するようです。まずはDSLで書かれたスクリプトをコンパイルします。手順はこちらです。
> cd ~/code-snippets/ml/kubeflow-pipelines/samples/kubeflow-tf
> python3 workflow1.py
> ls
README.md workflow1.py workflow1.py.tar.gz workflow2.py
Kubeflow pipelines UIにこのworkflow1.py.tar.gz
をアップロードするとpipelineができます。
UIからExperimentsを設定し、Runさせます。
このときpreprocess-mode
とtfma-mode
をlocal
で実行していますが、ここをcloud
にするとDataflowで動作します。
この後ワークフローが走ります。UI眺めているだけではあまり実感無いですが、CSVでGCSに保存されていたデータがTFTで処理され機械学習モデルに学習され、MLEngineにデプロイされてサービングされてます。
trainのblockからはTensorboardのダッシュボードに飛ぶこともできて便利ですね。
TensorFlow Model Analysisでモデル解析
ワークフローが走り終わるとJupyterNotebook上で学習されたモデルについての解析ができます。JupyterHubにサインインします。IDもパスワードはなんでも入れますが、GCPのアカウントを使うようにしました。解析にはこのtfma_expers.ipynbを使います。OUTPUT_PATH_PREFIX = 'gs://<YOUR_BUCKET_PATH>/<WORKFLOW_NAME>/'
のはクラスタ立てるときに指定したバケット名、はCloud ConsoleでGoogle Strageの当該バケットを見に行くとディレクトリができているのでそれを使います。現状、上述したエラーからレンダリングがうまくいっていないので全く意味をなしてませんが、一応セルの実行はできているようです。
機械学習モデルのサービング
Workflow1の方はデプロイがうまくいきませんでしたが、workflow2の方はGoogle ML Engineにデプロイされて、サービングできるようになってました。
まとめ
Pipeline上で使うモデルやデータの管理など、もう少しリッチな機能が欲しい感じですが、TFXをうまく使うための素晴らしいツールだなと感じています。機械学習モデリングの後、実運用まで持っていくための試行錯誤はまだまだ続きそうですが、KubeflowやTFXなど便利なツールが普及して知見が貯まり、そのハードルがどんどん下がっていけば良いなと思いました。