case-kの備忘録

日々の備忘録です。データ分析とか基盤系に興味あります。

Kaggleのコンテナイメージを使ったGPU環境をGoogle Compute Engineに作る

画像系などでGPUを使いたくてGCE上でKaggleのコンテナイメージを使ったGPU環境をつくりました。以下自分用の備忘録となります。

割り当てリクエスト(はじめにやること)

最初に行うことはGPUの割り当てリクエストを送ることです。GPUをGCE上で使うためにはGoogle側に割り当てをリクエストする必要があります。
割り当てないと、GPUのドライバインストール後の確認じに以下のようなエラーがでます。
GPU の追加または削除  |  Compute Engine ドキュメント  |  Google Cloud

Quota 'NVIDIA_P100_GPUS' exceeded. Limit: 1.0 in region us-east1.

注意事項として、割り当てリクエストは対象のGPU(例えば'NVIDIA_P100_GPUS)に加えて、
GPUグローバルリージョンでの割り当ても必要となります。割り当てないと以下のようなエラーがでます。

Quota 'GPUS_ALL_REGIONS' exceeded. Limit: 0.0 globally.

qiita.com

GPUグローバルリージョン

  • サービス:Compute Engine API
  • 名前:GPUs (all regions)
  • 割り当て指標:compute.googleapis.com/gpus_all_regions

割り当てをリクエストする際用途を問われます。2日以内に審査されます。
私は最初審査が通らなかったので、サポートに問い合わせたところ通りました。

Google Compute Engineを立てる

Google Compute Engineインスタンスを立てます。リージョンとインスタンスタイプによって割り当て可能なGPUは異なります。私は次のスペックのものを選びました。GPUを追加するにはGCEの編集画面から「CPU プラットフォーム」を選び GPUよりGPUを追加する。

リージョン:1-standard-8
ゾーン:us-central1-a
インスタンスタイプ:n1-standard-8
OS:Ubuntu 16.04 LTS(試せてませんが他のバージョンだとドライバのインストールがうまくいかない等の記事をみました)
ディスクサイズ:500GB
GPU のタイプ: NVIDIA Tesla T4(安い)

NVIDIA ドライバが含まれる CUDAをいれる

次のドキュメントにしたがってドライバとCUDAを入れます。
cloud.google.com

curl -O https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/cuda-ubuntu1604.pin
sudo mv cuda-ubuntu1604.pin /etc/apt/preferences.d/cuda-repository-pin-600
sudo apt-key adv --fetch-keys http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/7fa2af80.pub
sudo add-apt-repository "deb http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/ /"
sudo apt update
sudo apt install cuda

次のような画面が出ればOKです。

 nvidia-smi
Wed Sep 30 10:50:27 2020
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 455.23.05    Driver Version: 455.23.05    CUDA Version: 11.1     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|                               |                      |               MIG M. |
|===============================+======================+======================|
|   0  Tesla V100-SXM2...  Off  | 00000000:00:04.0 Off |                    0 |
| N/A   33C    P0    48W / 300W |      0MiB / 16160MiB |      0%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+
|   1  Tesla V100-SXM2...  Off  | 00000000:00:05.0 Off |                    0 |
| N/A   33C    P0    47W / 300W |      0MiB / 16160MiB |      0%      Default |
|                               |                      |                  N/A |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                                  |
|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |
|        ID   ID                                                   Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+

コンテナ環境を作る

ここからが本題です。コンテナ側からGPUを使えるようにします。

DockerとDocker-composeをインストールしておきます。OSに合わせてUbuntuのインストール方法に従います。

  • Docker

docs.docker.com

  • docker-compose

docs.docker.com


バージョンを確認

19.03以降はGPUのビルド方法が異なります。今回は19.03.13で動かしています。
バージョン確認するとこんなかんじです。

 sudo docker version
Client: Docker Engine - Community
 Version:           19.03.13
 API version:       1.40
 Go version:        go1.13.15
 Git commit:        4484c46d9d
 Built:             Wed Sep 16 17:02:59 2020
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.13
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.13.15
  Git commit:       4484c46d9d
  Built:            Wed Sep 16 17:01:30 2020
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.3.7
  GitCommit:        8fba4e9a7d01810a393d5d25a3621dc101981175
 runc:
  Version:          1.0.0-rc10
  GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dd
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683

「--gpus all」でコンテナを起動してみると次のエラーが出ます。

docker run --gpus all nvidia/cuda nvidia-smi

エラーが出た場合
次のようなエラーが出た場合はのたいしょ方について書きます。

docker: Error response from daemon: linux runtime spec devices: could not select device driver "" with capabilities: [[gpu]].

次のようなスクリプトをつくります。

vi nvidia-container-runtime-script.sh

スクリプトには以下の内容おw記載します。

curl -s -L https://nvidia.github.io/nvidia-container-runtime/gpgkey | \
  sudo apt-key add -
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-container-runtime/$distribution/nvidia-container-runtime.list | \
  sudo tee /etc/apt/sources.list.d/nvidia-container-runtime.list
sudo apt-get update
Execute the script
$ sh nvidia-container-runtime-script.sh
$ sudo apt-get install nvidia-container-runtime
$ docker run -it --rm --gpus all ubuntu nvidia-smi

再起動してみます。私の場合再起動してやってのコンテナ側でGPUを認識できるようになりました。

sudo reboot

無事コンテナを起動できました。

$ sudo docker run --name notebook -t -d  --gpus all -p 8888:8888 tensorflow/tensorflow:latest-gpu
________                               _______________
___  __/__________________________________  ____/__  /________      __
__  /  _  _ \_  __ \_  ___/  __ \_  ___/_  /_   __  /_  __ \_ | /| / /
_  /   /  __/  / / /(__  )/ /_/ /  /   _  __/   _  / / /_/ /_ |/ |/ /
/_/    \___//_/ /_//____/ \____//_/    /_/      /_/  \____/____/|__/


WARNING: You are running this container as root, which can cause new files in
mounted volumes to be created as the root user on your host machine.

To avoid this, run the container by specifying your user's userid:

$ docker run -u $(id -u):$(id -g) args...

qiita.com
qiita.com
qiita.com

sudo docker exec -it notebook bash
root@db527145397e:/#  pip install jupyter
root@db527145397e:/# jupyter notebook --port 8888 --ip=0.0.0.0 --allow-root

コンテナからGPUの動作確認

コンテナで認識できてるかノートブックから確認してみます。

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

次のような結果であれば大丈夫です。

  ...
 incarnation: 17636037438262103350
 physical_device_desc: "device: XLA_GPU device",
 name: "/device:XLA_GPU:1"
 device_type: "XLA_GPU"
 memory_limit: 17179869184
 locality {
 }
 ....

Kaggle のコンテナイメージを使ってGPU環境を作る

ここまででコンテナを使ってGPU環境を使いました。ただし、使いたいライブラリとかいれるのが少しめんどくさいのでノートブックはKaggleのを使いたいと思います。
KaggleのイメージでGPUを使いたい場合は現時点だとビルドしてイメージを作る必要があります。

Kaggleではイメージをビルドする必要があります。

# clone
git clone https://github.com/Kaggle/docker-python.git
cd docker-python

# --gpuオプションでビルド
sudo ./build --gpu

# イメージを確認
$ sudo docker image ls

次のようなイメージが作られてると思います。(結構時間かかります)

$ sudo docker image ls
REPOSITORY                                   TAG                             IMAGE ID            CREATED             SIZE
kaggle/python-gpu-build                      latest                          2f9b2c1b22f0        45 hours ago        26.8GB
tensorflow/tensorflow                        latest-gpu                      8a8486aa1902        3 days ago          3.05GB
gcr.io/kaggle-images/python                  staging                         f21a22cf6451        3 days ago          17.6GB
nvidia/cuda                                  10.0-cudnn7-devel-ubuntu16.04   925d6a4390fd        3 weeks ago         3.28GB
gcr.io/kaggle-images/python-tensorflow-whl   2.3.0-py37                      5b7404d41bb2        2 months ago        14.4GB
gcr.io/kaggle-images/python                  v78                             bccb00c5ef95        3 months ago        16.6GB

qiita.com


blog.uni-3.app

docker-compose.ymlの定義

ビルドしたKaggleのコンテナイメージを参照する次のようなymlをつくります。

version: "2.4"
services:
  jupyter:
    image: kaggle/python-gpu-build:latest # tensorflow/tensorflow:latest-gpu
    container_name: notebook
    runtime: nvidia
    environment:
      - NVIDIA_VISIBLE_DEVICES=all
      - NVIDIA_DRIVER_CAPABILITIES=all
    volumes:
      - ./:/home
    working_dir: /home
    ports:
      - 8888:8080
    command: jupyter notebook --ip=0.0.0.0 --allow-root --no-browser
    # sudo docker exec -it notebook  jupyter notebook list
こんなエラーが出た場合

パラメータで渡してるruntime: nvidiaでエラーが出るケースです、

Unsupported config option for services.jupyter: 'runtime'

次の記事によるとdocker-composeの場合は設定ファイルをつくり実行する必要があるようです。
> docker-compose の場合 2019/11/29 現在、docker-compose では Docker の --gpus と同等のオプションはサポートされていないようです。そのため、別途 nvidia-container-runtime をインストールして、/etc/docker/daemon.json に設定ファイルを作成します。

sudo apt-get install nvidia-container-runtime 
sudo tee /etc/docker/daemon.json <<EOF
{
    "runtimes": {
        "nvidia": {
            "path": "/usr/bin/nvidia-container-runtime",
            "runtimeArgs": []
        }
    }
}
EOF
sudo pkill -SIGHUP dockerd

https://blog.mahoroi.com/posts/2019/12/docker-gpus-nvidia/
github.com

私の場合はバージョンが要因で同様にruntimeオプションを選べませんでした。2.4で動くようになりました。

version: "3.2" → version: "2.4"

起動して動作確認を行います。

$ sudo docker-compose up -d --build

動作確認

コンテナ側でGPUを認識できてることを確認します。

from tensorflow.python.client import device_lib
device_lib.list_local_devices()
  ...
 incarnation: 17636037438262103350
 physical_device_desc: "device: XLA_GPU device",
 name: "/device:XLA_GPU:1"
 device_type: "XLA_GPU"
 memory_limit: 17179869184
 locality {
 }
 ....
>>>
import pandas as pd
import numpy as np
import json
import tensorflow.keras.layers as L
import keras.backend as K
import tensorflow as tf
import plotly.express as px
from sklearn.model_selection import StratifiedKFold, KFold, GroupKFold
from sklearn.cluster import KMeans
import os

os.environ['CUDA_VISIBLE_DEVICES'] = '0'
def allocate_gpu_memory(gpu_number=0):
    physical_devices = tf.config.experimental.list_physical_devices('GPU')

    if physical_devices:
        try:
            print("Found {} GPU(s)".format(len(physical_devices)))
            tf.config.set_visible_devices(physical_devices[gpu_number], 'GPU')
            tf.config.experimental.set_memory_growth(physical_devices[gpu_number], True)
            print("#{} GPU memory is allocated".format(gpu_number))
        except RuntimeError as e:
            print(e)
    else:
        print("Not enough GPU hardware devices available")
allocate_gpu_memory()
Found 1 GPU(s)
#0 GPU memory is allocated

コンテナ側でGPUを認識できてるので大丈夫そうです。