KubeflowでChainerを動かす環境をつくってみます。
途中まではKubeflowのインストール手順になってます。
https://www.kubeflow.org/docs/started/getting-started-gke/
Kubeflow?
Kubernetes上で機械学習環境を動かすものです。
このへん見てもらった方がいいかも
https://www.slideshare.net/shunyaueta/kubeflow-devfest18
Chainer?
日本のPreferred Networksが主導で開発している、機械学習のOSSライブラリです。
https://chainer.org/
自分が所属するAlpacaJapan株式会社では、ChainerのエバンジェリストがいてChainerがよく使われているみたいなので、この環境をつくってみました。
https://www.wantedly.com/companies/alpacadb/post_articles/114959
手順
k8s環境はGKEに、環境を構築するクライアントはMacという前提です。
Macの準備
ksonnet というk8s manifestを管理するフレームワークが必要になるので、brewでインストールします。
$ brew install ksonnet/tap/ks
GKEでCloudIAP設定
kubeflowにJupyterHub環境へのログインはGCPのCloudIAPを使って認証します。
APIとサービス
→ 認証情報
→ OAuth同意画面
を選択します。
認証情報のページで下記を入力して保存します。
認証情報を作成
→ OAuthクライアントID
に進みます。
CloudIAPの情報を入力します。
- アプリケーションの種類
- ウェブアプリケーション
- 名前
- 任意
- 承認済みのリダイレクトURI
- https://
KFAPPの名前
.endpoints.GCPのProjectID
.cloud.goog/_gcp_gatekeeper/authenticate
- https://
クライアントIDとクライアントシークレットが表示されます。
この情報が次のステップで必要になります。
k8sクラスタをつくってkubeflowを動かす
ここからはMacでの作業です。
Mac側で環境変数を定義します。
$ export PROJECT=#GCPのProjectID
$ export KUBEFLOW_SRC=#kubeflowをインストールするディレクトリ
$ export KUBEFLOW_TAG=v0.3.1
$ export KFAPP=#KFAPPの名前 前ステップの承認済みのリダイレクトURIのKFAPPの名前と合わせる)
$ export CLIENT_ID=#前ステップで出力されたクライアントID
$ export CLIENT_SECRET=#前ステップで出力されたクライアントシークレット
kubeflowをダウンロードして、kfctl.shを実行します。
$ mkdir ${KUBEFLOW_SRC}
$ cd ${KUBEFLOW_SRC}
$ curl https://raw.githubusercontent.com/kubeflow/kubeflow/${KUBEFLOW_TAG}/scripts/download.sh | bash
kuctl.sh init
でKFAPPを作成します。
${KUBEFLOW_SRC}/scripts/kfctl.sh init ${KFAPP} --platform gcp --project ${PROJECT}
cd ${KFAPP}
env.sh
という変数定義ファイルが作成されます。
Zoneやk8sのバージョンなんかはこのファイルで修正できそうです。
PLATFORM=gcp
:
K8S_NAMESPACE=kubeflow
KUBEFLOW_CLOUD=gke
:
DEPLOYMENT_NAME=kf
:
ZONE=us-central1-a
:
KUBEFLOW_IP_NAME=kf-ip
KUBEFLOW_ENDPOINT_NAME=kf
:
CLUSTER_VERSION=1.10.9-gke.7
env.sh
をもとに設定ファイルを作成します。
$ ${KUBEFLOW_SRC}/scripts/kfctl.sh generate platform
gcp_config
、 k8s_specs
に設定ファイルができます。
gcp_config
├── cluster-kubeflow.yaml
├── cluster.jinja
├── cluster.jinja.schema
└── iam_bindings.yaml
k8s_specs
├── agents.yaml
├── daemonset-preloaded.yaml
└── rbac-setup.yaml
GPUインスタンスを使いたいので、cluster-kubeflow.yaml
の
cpu-pool-initialNodeCount: 2
gpu-pool-initialNodeCount: 0
を
cpu-pool-initialNodeCount: 2
gpu-pool-initialNodeCount: 2
に変更します。
これでCPUノードが2台、GPUノードが2台の計4台のインスタンスが起動します。
Zoneについての注意点なのですが、gcp_config/cluster.jinja
を見ると、
minCpuPlatform: 'Intel Haswell'
accelerators:
- acceleratorCount: 1
acceleratorType: nvidia-tesla-k80
という記述があります。
Zoneによって使えるCPUやGPUが違うので、env.sh
でZoneを変えるとこのへんも修正しないといけないようです。
https://cloud.google.com/compute/docs/regions-zones/
https://cloud.google.com/compute/docs/gpus/
日本ではまだGPUインスタンスが提供されていないので、env.sh
を asia-northeast1-a
にして変更すると次のようなエラーになります。
message: '{"ResourceType":"container.v1.nodePool","ResourceErrorCode":"400","ResourceErrorMessage":{"code":400,"message":"Accelerator
type \"nvidia-tesla-k80\" does not exist in zone asia-northeast1-a.","status":"INVALID_ARGUMENT","statusMessage":"Bad
Request",・・・
下記のコマンドでk8sのクラスタの作成からkubeflowのデプロイまでできます。
完了まで20〜30分かかります。
$ ${KUBEFLOW_SRC}/scripts/kfctl.sh apply platform
$ ${KUBEFLOW_SRC}/scripts/kfctl.sh generate k8s
$ ${KUBEFLOW_SRC}/scripts/kfctl.sh apply k8s
Compute EngineのところをみるとGPUインスタンスも起動してます。
Kubernetes Engine
の サービス
を開くと、接続を受け付ける envoy-ingress
が作られますので、ステータスがOKになったら、https://(KFAPP名).endpoints.(GCPのProjectID).cloud.goog
にアクセスしてみます。
CloudIAPで認証が通れば、こんな画面が開きますので、JUPYTERHUBを開きます。
Chainerを動かしてみる
つくったKubeflow環境でChainerを使えるようにしてみます。
手順はここ
https://www.kubeflow.org/docs/guides/components/chainer/
まず、Chainer Operator っていうものをインストールします。
$ cd ks_app $ ks pkg install kubeflow/chainer-job
$ ks generate chainer-operator chainer-operator
environment
を確認します。
$ ks env list
NAME OVERRIDE KUBERNETES-VERSION NAMESPACE SERVER
==== ======== ================== ========= ======
default v1.10.9 kubeflow https://35.193.63.167
default
っていう名前らしいので、
$ ks apply default -c chainer-operator [14:54:05]
INFO Applying customresourcedefinitions chainerjobs.kubeflow.org
INFO Creating non-existent customresourcedefinitions chainerjobs.kubeflow.org
INFO Applying clusterroles chainer-operator
INFO Creating non-existent clusterroles chainer-operator
INFO Applying serviceaccounts kubeflow.chainer-operator
INFO Creating non-existent serviceaccounts kubeflow.chainer-operator
INFO Applying clusterrolebindings kubeflow.chainer-operator
INFO Creating non-existent clusterrolebindings kubeflow.chainer-operator
INFO Applying deployments kubeflow.chainer-operator
INFO Creating non-existent deployments kubeflow.chainer-operator
これでインストールは完了です。
ChainerのJobをつくります。
apiVersion: kubeflow.org/v1alpha1
kind: ChainerJob
metadata:
name: example-job-mn
spec:
backend: mpi
master:
mpiConfig:
slots: 1
activeDeadlineSeconds: 6000
backoffLimit: 60
template:
spec:
containers:
- name: chainer
image: everpeace/chainermn:1.3.0
command:
- sh
- -c
- |
mpiexec -n 3 -N 1 --allow-run-as-root --display-map --mca mpi_cuda_support 0 \
python3 /train_mnist.py -e 2 -b 1000 -u 100
workerSets:
ws0:
replicas: 2
mpiConfig:
slots: 1
template:
spec:
containers:
- name: chainer
image: everpeace/chainermn:1.3.0
command:
- sh
- -c
- |
while true; do sleep 1 & wait; done
つくったyamlをk8sに食わせます。
$ kubectl create -f example-job-mn.yaml
chainerjob.kubeflow.org "example-job-mn" created
$ kubectl get pods -l chainerjob.kubeflow.org/name=example-job-mn
NAME READY STATUS RESTARTS AGE
example-job-mn-master-lv96v 0/1 Init:1/2 0 1m
example-job-mn-workerset-ws0-0 0/1 PodInitializing 0 1m
example-job-mn-workerset-ws0-1 0/1 PodInitializing 0 1m
$ kubectl get pods -l chainerjob.kubeflow.org/name=example-job-mn
NAME READY STATUS RESTARTS AGE
example-job-mn-master-lv96v 0/1 Completed 0 1m
example-job-mn-workerset-ws0-0 1/1 Terminating 0 1m
example-job-mn-workerset-ws0-1 1/1 Terminating 0 1m
終わったっぽい
$ PODNAME=$(kubectl get pods -l chainerjob.kubeflow.org/name=example-job-mn,chainerjob.kubeflow.org/role=master -o name)
$ kubectl logs -f ${PODNAME}
Data for JOB [34829,1] offset 0
======================== JOB MAP ========================
Data for node: example-job-mn-workerset-ws0-0 Num slots: 1 Max slots: 0 Num procs: 1
Process OMPI jobid: [34829,1] App: 0 Process rank: 0 Bound: UNBOUND
Data for node: example-job-mn-workerset-ws0-1 Num slots: 1 Max slots: 0 Num procs: 1
Process OMPI jobid: [34829,1] App: 0 Process rank: 1 Bound: UNBOUND
Data for node: example-job-mn-master-lv96v Num slots: 1 Max slots: 0 Num procs: 1
Process OMPI jobid: [34829,1] App: 0 Process rank: 2 Bound: UNBOUND
=============================================================
Warning: using naive communicator because only naive supports CPU-only execution
Warning: using naive communicator because only naive supports CPU-only execution
Warning: using naive communicator because only naive supports CPU-only execution
==========================================
Num process (COMM_WORLD): 3
Using hierarchical communicator
Num unit: 100
Num Minibatch-size: 1000
Num epoch: 2
==========================================
epoch main/loss validation/main/loss main/accuracy validation/main/accuracy elapsed_time
1 1.68391 0.898411 0.525 0.812094 1.47055
2 0.59408 0.393784 0.84855 0.894968 3.65354
$ kubectl get -o yaml chainerjobs example-job-mn
apiVersion: kubeflow.org/v1alpha1
kind: ChainerJob
metadata:
clusterName: ""
:
status:
completionTime: 2018-12-10T05:58:21Z
conditions:
- lastProbeTime: 2018-12-10T05:58:21Z
lastTransitionTime: 2018-12-10T05:58:21Z
status: "True"
type: Complete
startTime: 2018-12-10T05:56:25Z
succeeded: 1
成功したらしい
削除
下記のコマンドでまるっと環境を削除できます。
$ cd ${KFAPP}
$ ${KUBEFLOW_SRC}/scripts/kfctl.sh delete platform
GPUインスタンスの消し忘れには注意です!!
まとめ
とりあえずChainerつかったk8sのJobを走らせるところまではできたみたいなので、うちのML Engineerに試してもらいます。
ついでに
AlpacaJapanではエンジニア募集しています!!
https://www.wantedly.com/projects/233473
https://www.wantedly.com/projects/200300
https://www.wantedly.com/projects/217110