Kubernets で　GPU を使って tensorflow を学習させる（２）

前回のブログで、GPUを使いたい時は、NVIDIAのドライバをコンテナとシェアする必要性を話したが、実はそれを明示的にしなくてもいい作戦がある。

* [Kubernets で　GPU を使って tensorflow を学習させる（１）](https://qiita.com/TsuyoshiUshio@github/items/32c13b796b222b3c792e)

* [Kubernets で　GPU を使って tensorflow を学習させる（３）](https://qiita.com/TsuyoshiUshio@github/items/33217e66067891f34fd1)

最強チュートリアルを貼っておく。これを基本フォローしている。

* [wbuchwalter/tensorflow-k8s-azure](https://github.com/wbuchwalter/tensorflow-k8s-azure)


* [sensorflow/k8s](https://github.com/tensorflow/k8s)

次のコマンドでインストールできる。(helm はインストールしておくこと）

```
CHART=https://storage.googleapis.com/tf-on-k8s-dogfood-releases/latest/tf-job-operator-chart-latest.tgz
helm install ${CHART} -n tf-job --wait --replace --set cloud=azure
```

これで　TfJobというリソースが使えるようになる。

```yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: example-job
spec:
  template:
    metadata:
      name: example-job
    spec:
      restartPolicy: OnFailure
      volumes:
      - name: bin
        hostPath: 
          path: /usr/lib/nvidia-384/bin
      - name: lib
        hostPath: 
          path: /usr/lib/nvidia-384
      containers:
      - name: tensorflow
        image: tsuyoshiushio/mnst-gpu
        resources:
          requests:
            alpha.kubernetes.io/nvidia-gpu: 1 
        volumeMounts:
        - name: bin
          mountPath: /usr/local/nvidia/bin
        - name: lib
          mountPath: /usr/local/nvidia/lib64
```

がこれで済む

```yaml
apiVersion: tensorflow.org/v1alpha1
kind: TfJob
metadata:
  name: example-tfjob
spec:
  replicaSpecs:
    - template:
        spec:
          containers:
            - image: tsuyoshiushio/mnst-gpu
              name: tensorflow
              resources:
                requests:
                  alpha.kubernetes.io/nvidia-gpu: 1
          restartPolicy: OnFailure
```
中身は、`tf-job-operator-config` という `ConfigMap` にドライバの設定が書かれていてそれが適用されている。そして、新たに、`tf-job-operator`というpodがデプロイされてそれが、クラスターをモニターして、TfJobの新しいリソースを監視している。

```
$ kubectl describe configmaps tf-job-operator-config
Name:         tf-job-operator-config
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
controller_config_file.yaml:
----
grpcServerFilePath: /opt/mlkube/grpc_tensorflow_server/grpc_tensorflow_server.py
accelerators:
  alpha.kubernetes.io/nvidia-gpu:
    volumes:
      - name: lib
        mountPath: /usr/local/nvidia/lib64
        hostPath:  /usr/lib/nvidia-384
      - name: bin
        mountPath: /usr/local/nvidia/bin
        hostPath: /usr/lib/nvidia-384/bin
      - name: libcuda
        mountPath: /usr/lib/x86_64-linux-gnu/libcuda.so.1
        hostPath: /usr/lib/x86_64-linux-gnu/libcuda.so.1

Events:  <none>
```

# 学習済みモデルとログの取得

コンテナで学習させたモデルとログはどこで取得するか？というと、例えば、Azure
Fileをマウントするという方法が使える。

* [Using Azure Files with Kubernetes](https://docs.microsoft.com/en-in/azure/aks/azure-files)

具体的にはこのようなものを`kubectl create -f ` すれば良い感じ。これで、シークレットができる。

```yaml
apiVersion: v1
kind: Secret
metadata:
  name: azure-secret
type: Opaque
data:
  azurestorageaccountname: BASE64_STORAGE_ACCOUNT_NAME
  azurestorageaccountkey: BASE64_STTORAGE_ACCOUNT_KEY
```

この設定で該当の AzureFile の　`acsshare` にモデルやログが共有されるようになる。お手軽だ。

```yaml
apiVersion: tensorflow.org/v1alpha1
kind: TfJob
metadata:
  name: module5-ex2-gpu
spec:
  replicaSpecs:
    - template:
        spec:
          containers:
            - image: tsuyoshiushio/tf-mnist:gpu
              name: tensorflow
              volumeMounts:
              - name: azurefile
                subPath: module5-ex2-gpu
                mountPath: /tmp/tensorflow
              resources:
                requests:
                  alpha.kubernetes.io/nvidia-gpu: 1
          volumes:
            - name: azurefile
              azurefile:
                secretName: azure-secret
                shareName: acsshare
                readOnly: false
          restartPolicy: OnFailure
```

ついでに、TensorBoard toいうツールも使えるらしい。yaml に追加しよう。

```yaml
apiVersion: tensorflow.org/v1alpha1
kind: TfJob
metadata:
  name: module5-ex3
spec:
  replicaSpecs:
    - template:
        spec:
          volumes:
            - name: azurefile
              azureFile:
                  secretName: azure-secret
                  shareName: acsshare
                  readOnly: false
          containers:
            - image: tsuyoshiushio/tf-mnist:gpu
              name: tensorflow
              resources:
                requests:
                  alpha.kubernetes.io/nvidia-gpu: 1
              volumeMounts:
                - mountPath: /tmp/tensorflow
                  subPath: module5-ex3 # Again we isolate the logs in a new directory on Azure Files
                  name: azurefile
          restartPolicy: OnFailure
  tensorboard:
    logDir: /tmp/tensorflow/logs
    serviceType: LoadBalancer # We request a public IP for our TensorBoard instance
    volumes:
      - name: azurefile
        azureFile:
            secretName: azure-secret
            shareName: acsshare
    volumeMounts:
      - mountPath: /tmp/tensorflow/ #This could be any other path. All that maters is that LogDir reflects it.
        subPath: module5-ex3 # This should match the directory our Master is actually writing in
        name: azurefile
```

サービスの LoadBalancer で公開されるので、普通にブラウザで開ける。
<img width="953" alt="Screen Shot 2017-12-07 at 4.49.03 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/3470/e8f829ab-8e8a-914d-8872-ed956143aff9.png">


ただし、Azure File の　iops は 1000程度なので、それ以上は違う方法を考えること。