Windows 10 Docker Desktop ( based WSL2 ) で 手持ちのGPU環境を Google Colaboratory の ローカルランタイム として接続する 【Preview release利用】



<!-- 

## やりたいこと  
1. [Google Colaboratory](https://colab.research.google.com/notebooks/welcome.ipynb?hl=ja)のGPU利用制限を回避したい :cry: :cold_sweat: :sob:
![スクリーンショット 2020-12-25 184352.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360662/3b7298a6-a2d7-efc9-fef5-da8f3b15e88f.png)
1. [Docker Desktop WSL 2 GPU Support](https://www.docker.com/blog/wsl-2-gpu-support-is-here/) を試したい :whale2:


## なにが嬉しい？
1. WSL2で動作するので、Windows10 Homeでも動作する :blush:
1. Colabの使用制限で学習が停止しない :blush:
1. ローカルGPU環境でもColabのエコシステムが使える :blush:  
(Colabのgithub連携とか非常に便利)
![スクリーンショット 2020-12-25 191633.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360662/9eac0495-7283-2296-7840-02c77eb396b1.png)

## アプローチ
1. Windows 10 Docker Desktop ( based WSL2 ) でGPU環境入りコンテナを用意
2. ポートフォワーディング
2. 仮想環境をGoogle Colaboratryのローカルランタイムとして接続
![スクリーンショット 2020-12-25 191324.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360662/a870d33d-45cd-c1ec-3e94-22d37098dc50.png)
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360662/2fd3ac3f-f3bf-9960-83ae-b5c3bfa6b2d3.png)

## 検証環境
1. OS: Windows 10 Pro (OSビルド 20279.1)
2. GPU: RTX 2070 Super
2. WSL2 (Ubuntu 20.04 LTS)
2. Docker Desktop ([developer preview build of Docker Desktop for WSL 2 supporting GPU](https://www.docker.com/blog/wsl-2-gpu-support-is-here/))
4. CUDA ([NVIDIA Drivers for CUDA on WSL, including DirectML Support](https://developer.nvidia.com/cuda/wsl/download))


## 構築手順
主に [このdocker Blog](https://www.docker.com/blog/wsl-2-gpu-support-is-here/) を参考にしています。

### 環境構築
1. Docker Desktop の [technical preview build](https://desktop.docker.com/win/preview/50723/Docker%20Desktop%20Installer.exe) を入手
2. [Windows Insider version @Dev preview](https://insider.windows.com/ja-jp/getting-started#flight) を導入し最新ビルドのOSを入手  
(2020/12/26時点では`ver.20279.1`が最新)
3. [WSL2の導入](https://docs.microsoft.com/ja-jp/windows/wsl/install-win10)
4. Nvidia の [CUDA supporting WSL 2 GPU Beta Driver](https://developer.nvidia.com/cuda/wsl) を導入
5. WSL2 上で`docker pull` して、CUDA の image を取得

```terminal
$ docker pull nvidia/cuda
```

DockerがGPUを認識できているかチェック

```terminal
$ docker run --rm -it --gpus=all nvcr.io/nvidia/k8s/cuda-sample:nbody nbody -gpu -benchmark
```  


↓ Docker Desktop (based WSL2) がGPUを認識していれば、こんな感じの結果が出る ↓

```terminal
PS C:\Users\*****> docker run --rm -it --gpus=all nvcr.io/nvidia/k8s/cuda-sample:nbody nbody -gpu -benchmark
Run "nbody -benchmark [-numbodies=<numBodies>]" to measure performance.
        -fullscreen       (run n-body simulation in fullscreen mode)
        -fp64             (use double precision floating point values for simulation)
        -hostmem          (stores simulation data in host memory)
        -benchmark        (run benchmark to measure performance)
        -numbodies=<N>    (number of bodies (>= 1) to run in simulation)
        -device=<d>       (where d=0,1,2.... for the CUDA device to use)
        -numdevices=<i>   (where i=(number of CUDA devices > 0) to use for simulation)
        -compare          (compares simulation results running once on the default GPU and once on the CPU)
        -cpu              (run n-body simulation on the CPU)
        -tipsy=<file.bin> (load a tipsy model file for simulation)

NOTE: The CUDA Samples are not meant for performance measurements. Results may vary when GPU Boost is enabled.

> Windowed mode
> Simulation data stored in video memory
> Single precision floating point simulation
> 1 Devices used for simulation
MapSMtoCores for SM 7.5 is undefined.  Default to use 64 Cores/SM
GPU Device 0: "GeForce RTX 2070 SUPER" with compute capability 7.5

> Compute 7.5 CUDA device: [GeForce RTX 2070 SUPER]
40960 bodies, total time for 10 iterations: 59.828 ms
= 280.426 billion interactions per second
= 5608.513 single-precision GFLOP/s at 20 flops per interaction
```

### 機械学習環境を構築
お好みの環境を構築して、Jupyter Notebookとcolab拡張の`jupyter_http_over_ws`を導入すればOK
今回は [DockerHub](https://hub.docker.com/) 上の [Tensoflowのimage](https://hub.docker.com/r/tensorflow/tensorflow/tags?page=1&ordering=last_updated) を利用する。

```terminal
$ docker pull tensorflow/tensorflow:1.15.4-gpu-py3-jupyter
```

上記のコマンドで`Tensoflow==1.15.4 gpu version`,`python3`, `jupyter notebook` all in の環境が手に入る。
自分に必要な環境に合わせて`pull`するとよい。
tensorflowなら、[DockerHub tensorflow/tensorflow](https://hub.docker.com/r/tensorflow/tensorflow/tags?page=1&ordering=last_updated) からimageを選べる。
`tensorflow/tensorflow:***-jupyter`のようなタグのimageを選べばJupyter Notebookを自分で導入する手間も省ける。


### 仮想環境の立ち上げ
先程`pull`したimageを立ち上げる
**Google Colabolatry**で仮想環境をローカルランタイムに指定するために`run`の際に`jupyter notebook`の設定を加えています。[参考元: stackoverflow](https://stackoverflow.com/questions/61024722/how-to-use-google-colab-with-a-local-tensorflow-jupyter-server-using-powershell)

```terminal
$ docker run -it --rm --gpus=all -p 8888:8888 tensorflow/tensorflow:1.15.4-gpu-py3-jupyter \
jupyter notebook --notebook-dir=/tf --ip 0.0.0.0 --no-browser --allow-root \
--NotebookApp.allow_origin='https://colab.research.google.com'
```
↓ 実行結果 ↓
`http://127.0.0.1:8888/?token=****`を使って**Colaboratory**にローカルランタイムとしてアクセスします。

```terminal
PS C:\Users\****> docker run -it --rm --gpus=all -p 8888:8888 tensorflow/tensorflow:1.15.4-gpu-py3-jupyter jupyter notebook --notebook-dir=/tf --ip 0.0.0.0 --no-browser --allow-root --NotebookApp.allow_origin='https://colab.research.google.com'
[I 16:24:42.162 NotebookApp] Writing notebook server cookie secret to /root/.local/share/jupyter/runtime/notebook_cookie_secret
jupyter_http_over_ws extension initialized. Listening on /http_over_websocket
[I 16:24:42.372 NotebookApp] Serving notebooks from local directory: /tf
[I 16:24:42.372 NotebookApp] Jupyter Notebook 6.1.4 is running at:
[I 16:24:42.372 NotebookApp] http://42009a4c9bbb:8888/?token=*************************************************
[I 16:24:42.372 NotebookApp]  or http://127.0.0.1:8888/?token=*************************************************
[I 16:24:42.372 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
[C 16:24:42.376 NotebookApp]

    To access the notebook, open this file in a browser:
        file:///root/.local/share/jupyter/runtime/nbserver-1-open.html
    Or copy and paste one of these URLs:
        http://42009a4c9bbb:8888/?token=*************************************************
     or http://127.0.0.1:8888/?token=******************************************************
```

### Colaboratoryに接続
1. [Google Colaboratory](https://colab.research.google.com/notebooks/welcome.ipynb?hl=ja)にアクセスします
1. `接続` から `ローカルランタイムに接続`を選択
![スクリーンショット 2020-12-26 013248.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360662/49f92d1b-fa79-0c22-5b95-306a1ce15281.png)
1. 先程取得したリンク`http://127.0.0.1:8888/?token=****`を使って接続  
http://**localhost**:8888/?token=**** に変更して入力 ( `127.0.0.1` → `localhost` )
![スクリーンショット 2020-12-26 013738.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360662/cc795e86-d74a-fb5c-eeb3-a46e1fc09386.png)
1. 接続完了！！  
![スクリーンショット 2020-12-26 014202.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/360662/5506d059-d5ba-14dc-693b-1996d198bbe4.png)  
1. Colabで下記を実行して、機械学習ライブラリがGPUを認識しているか確認しましょう。(Tensorflowの場合)

```python
from tensorflow.python.client import device_lib
device_lib.list_local_devices()
```

下記のようにGPUを認識できていれば完了！！

```terminal
[name: "/device:CPU:0"
 device_type: "CPU"
 memory_limit: 268435456
 locality {
 }
 incarnation: 265271654709027711,
 name: "/device:XLA_CPU:0"
 device_type: "XLA_CPU"
 memory_limit: 17179869184
 locality {
 }
 incarnation: 12989474002923935858
 physical_device_desc: "device: XLA_CPU device",
 name: "/device:XLA_GPU:0"
 device_type: "XLA_GPU"
 memory_limit: 17179869184
 locality {
 }
 incarnation: 12219956629618833082
 physical_device_desc: "device: XLA_GPU device",
 name: "/device:GPU:0"
 device_type: "GPU"
 memory_limit: 7125876736
 locality {
   bus_id: 1
   links {
   }
 }
 incarnation: 1423521064690955886
 physical_device_desc: "device: 0, name: GeForce RTX 2070 SUPER, pci bus id: 0000:01:00.0, compute capability: 7.5"]
```

## さいごに
最近 (2020/12/26現在) のPreview releaseで`Win10` x `WSL2` x `Docker` x `CUDA` が動作するようになったので、`Google Colaboratory`のローカルランタイム接続に応用してみました。
しばらくしたら諸々の機能はメジャーリリースされると思うので、[環境構築](#環境構築)の欄は不要になるかと思います。

-->