Help us understand the problem. What is going on with this article?

kubeflowでChainerしてみる

More than 1 year has passed since last update.

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同意画面 を選択します。

image.png

認証情報のページで下記を入力して保存します。

  • アプリケーション名
    • 任意
  • サポートメール
    • メールアドレス(自分のが入ってるはず)
  • 承認済みドメイン
    • GCPのProjectID.cloud.goog image.png

認証情報を作成OAuthクライアントID に進みます。

image.png

CloudIAPの情報を入力します。

  • アプリケーションの種類
    • ウェブアプリケーション
  • 名前
    • 任意
  • 承認済みのリダイレクトURI
    • https://KFAPPの名前.endpoints.GCPのProjectID.cloud.goog/_gcp_gatekeeper/authenticate

image.png

クライアントIDとクライアントシークレットが表示されます。
この情報が次のステップで必要になります。

image.png

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_configk8s_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.shasia-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インスタンスも起動してます。
image.png

Kubernetes Engineサービス を開くと、接続を受け付ける envoy-ingress が作られますので、ステータスがOKになったら、https://(KFAPP名).endpoints.(GCPのProjectID).cloud.goog にアクセスしてみます。
image.png

CloudIAPで認証が通れば、こんな画面が開きますので、JUPYTERHUBを開きます。
image.png

Start My Serverを押します。
image.png

詳しくは知りませんが、とりあえず Spawnを。
image.png

なんかが動いて・・・
image.png

起動完了!
image.png

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をつくります。

example-job-mn.yaml
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

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away