GUIでDeep Learning用のDockerコンテナを作って学習する話(portainer)

# はじめに
この記事はDockerでDeep LearningやってみたいけどCUIはめんどくさいという人向けの記事です。

Docker と nvidia-dockerのインストール方法等はもっとわかりやすい記事があるので、そちらをご覧ください。

>Docker入門 ~Tensorflowも超簡単に！！~
>https://qiita.com/yakigac/items/f14f12f182a564c091d0

**今回の最終目標はDockerコンテナでTensorflow-gpuを動かすことです。**

# 動作環境
- Ubuntu 18.04.2 LTS
- Docker 18.09.5
- nvidia-docker 2.0.3
- portainer 1.20.2

# portainarインストール
以下のコマンドを順に実行

```
docker volume create portainer_data
```
</br>

```
docker run -d -p 9000:9000 --name portainer --restart always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer
```
</br>

ブラウザから`http://localhost:9000`で接続できるます。

ポートを変えたいときはコマンド内の`9000`の部分を置き換えればいいです。

>Deployment &mdash; Portainer 1.20.2 documentation
>https://portainer.readthedocs.io/en/stable/deployment.html

## portainerの初期設定
下の画面が表示されるので、ユーザー登録をします。

|![create_user.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252166/79d751f1-482c-cc41-b15e-9cfa12815a6d.png)|
|:-:|

続いて、どこのDockerに接続するか聞かれるので`local`を選択。

|![connect_docker.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252166/fc54d582-930d-9a34-447e-c761cddb8fb9.png)|
|:-:|

`Home`に移動できるので、`Endpoints`の中の`local`をクリックすると`Dashboard`に移動できます。

|![home.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252166/a5ab1930-cc19-bdcc-aff4-85c9148e3aa7.png)|
|:-:|

|![Dashboard.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252166/c2628c7b-4c1f-57da-a7a6-a87e84416f7c.png)|
|:-:|

基本的にportainerは`Dashboard`から操作します。次回からはログインをすると`Home`を開けます。

# コンテナを作る
今回はTensorflow公式のイメージを使用します([公式ページ](https://www.tensorflow.org/install/docker))。

使用するイメージは`tensorflow/tensorflow:latest-gpu-py3`としました。
(tensolflowの最新バージョンのGPU版でpython3系のイメージ)

## コンテナの一覧を開く
`Dashboard`の`Containers`を選択すると, 以下のように現在のコンテナ一覧が表示されます(起動していないものも含む)。

|![container_list.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252166/459ceac0-6728-263b-b8d7-2a90a00e6ba8.png)|
|:-:|

## コンテナの新規作成画面を開く
`Container list`の`Add container`をクリックすると`Create container`画面が開きます。

|![Create_container.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252166/ceacb3b2-4c22-bca6-6b61-212505c086b0.png)|
|:-:|

## コンテナ名とイメージ名を入力
`Name`にコンテナ名を入力する。今回はコンテナ名をTensorflowとしました。
先ほどのイメージ名を入力。このイメージはDockerHubにあるので`Registry`はDockerHubでいいです。

|![name_image.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252166/629c4f72-9ea5-0fc9-ca30-9777ec17dd5c.png)|
|:-:|

## Interactive & TTYを有効にする
Docker内のコンソールに接続できるように`Interactive & TTY`を有効にします。
`docker run`のコマンドのオプションで言うと`-it`です。

変更する場所は、`Create container`画面の下側の`Advanced container settings`内の`Command & logging`です。
`Console`の`Interactive & TTY`のチェックします。

|![tty.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252166/d9dbf0db-9381-6000-dd53-51f480004cbf.png)|
|:-:|

## ランタイムの変更
GPUを使用するコンテナを作成するときは、nvidia-dockerを使用することを明示しなければなりません。
`docker run`のオプションで言うと`--runtime=nvidia`の部分です。

変更する場所は、`Create container`画面の下側の`Advanced container settings`内の`Runtime & Resources`です。
`Runtime`を`nvidia`に変更してください。

|![runtime.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252166/f7a26927-7c03-4b7f-a60f-fadc6d307bae.png)|
|:-:|

## 共有フォルダの作成
ホスト側とコンテナ内に共有フォルダを作成します。必須ではありませんが`docker cp`とかしなくていいので楽です。

`Create container`画面の下側の`Advanced container settings`内の`Volumes`から設定できます。

`Volume mapping`の`map additional volume`をクリックしてボリュームを追加します。

`Bind`と`Writable`を選択します。
`container`側にコンテナ側の共有フォルダのパス、`host`側にホスト側の共有フォルダのパスを入力します。

|![volumes.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252166/120dcb1b-e78b-6fae-0959-bc0acd22c829.png)|
|:-:|

## コンテナを作成
最後に`Deploy the container`をクリックすればコンテナが作成されます。

|![container_list_after.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252166/bba669c7-fa37-89f1-7cdd-5d8fe2c8bca2.png)|
|:-:|

## 共有フォルダの権限変更
今のままでは共有フォルダの権限のせいでホスト側から書き込めません。
なので、コンテナ内から権限を付与する必要があります(もっといい方法あれば教えてください…)。

`Container list`の作成したコンテナの`Quick actions`の`>_`をクリックすると、`Container console`画面が開くので、`Connect`をクリック。

|![console_connect.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252166/2dedc03a-642b-a653-32a9-dd2edee3df5c.png)|
|:-:|

するとコンソールが開くので、次のコマンドを入力。

```
chmod a+rwx <共有フォルダのパス>
```

これでTensorflowが動くコンテナ完成です。

## 動作確認
コンテナ内のコンソールで以下を実行してください。

```
python -c "from tensorflow.python.client import device_lib;device_lib.list_local_devices()"
```

実行結果

```
2019-05-02 19:53:24.463116: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2FMA
2019-05-02 19:53:24.601321: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:998] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2019-05-02 19:53:24.610259: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:998] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2019-05-02 19:53:24.610914: I tensorflow/compiler/xla/service/service.cc:150] XLA service 0x4cbebd0 executing computations on platform CUDA. Devices:
2019-05-02 19:53:24.610929: I tensorflow/compiler/xla/service/service.cc:158]   StreamExecutor device (0): GeForce GTX 1080 Ti, Compute Capability 6.1
2019-05-02 19:53:24.610934: I tensorflow/compiler/xla/service/service.cc:158]   StreamExecutor device (1): GeForce GTX 1080 Ti, Compute Capability 6.1
2019-05-02 19:53:24.630432: I tensorflow/core/platform/profile_utils/cpu_utils.cc:94] CPU Frequency: 3192000000 Hz
2019-05-02 19:53:24.631122: I tensorflow/compiler/xla/service/service.cc:150] XLA service 0x4d305d0 executing computations on platform Host. Devices:
2019-05-02 19:53:24.631140: I tensorflow/compiler/xla/service/service.cc:158]   StreamExecutor device (0): <undefined>, <undefined>
2019-05-02 19:53:24.631495: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1433]Found device 0 with properties:
name: GeForce GTX 1080 Ti major: 6 minor: 1 memoryClockRate(GHz): 1.6325
pciBusID: 0000:01:00.0
totalMemory: 10.91GiB freeMemory: 10.68GiB
2019-05-02 19:53:24.631743: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1433]Found device 1 with properties:
name: GeForce GTX 1080 Ti major: 6 minor: 1 memoryClockRate(GHz): 1.6325
pciBusID: 0000:02:00.0
totalMemory: 10.92GiB freeMemory: 10.77GiB
2019-05-02 19:53:24.632553: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1512]Adding visible gpu devices: 0, 1
2019-05-02 19:53:24.633699: I tensorflow/core/common_runtime/gpu/gpu_device.cc:984] Device interconnect StreamExecutor with strength 1 edge matrix:
2019-05-02 19:53:24.633719: I tensorflow/core/common_runtime/gpu/gpu_device.cc:990]    0 1
2019-05-02 19:53:24.633727: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1003]0:   N Y
2019-05-02 19:53:24.633733: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1003]1:   Y N
2019-05-02 19:53:24.634226: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1115]Created TensorFlow device (/device:GPU:0 with 10389 MB memory) -> physical GPU (device: 0, name: GeForce GTX 1080 Ti, pci bus id: 0000:01:00.0, compute capability: 6.1)
2019-05-02 19:53:24.634577: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1115]Created TensorFlow device (/device:GPU:1 with 10479 MB memory) -> physical GPU (device: 1, name: GeForce GTX 1080 Ti, pci bus id: 0000:02:00.0, compute capability: 6.1)
```

GPUが認識できているのがわかります。

# 最後に
コンテナがGUIで全部使えるのほんとに楽でいいです。portainerすごい。

Deep LearningをちゃんとやっていくにはDockerは必須なんじゃないかなぁと個人的には思うので、もっと勉強しなきゃと思う次第です。

portainerには、まだよくわかってない機能がたくさんありそうなのでもっと使いこなしていきたい所存。

時間があったら、portainerでimageビルドする記事も書きます。