やってみよう!

プログラミングとかでぃーぷらーにんぐとかVRとか気になったものをやってみる予定

nvidia-docker+docker-composeでtensorflow-gpuのディープラーニング環境を構築する

ubuntu18.04でディープラーニングの環境(tensorflow+keras)を整えたのでメモとして残しておきます。

本記事のゴールはtensorflow-gpuでmnistを動かすことです。

今回試した環境
  • Ubuntu 18.04
  • NVIDIA GeForce GTX 1080 Ti
  • nvidia-driver 390.48
  • CUDA 9.1(ホストOSにはいらないかも)
  • cuDNN 7.1.2(ホストOSにはいらないかも)
  • docker 18.06.1-ce
  • docker-compose 1.22.0-rc2
  • nvidia-docker

CUDA9.1とnvidia-driverのインストール

2018/8/26現在ではCUDAの最新は9.2ですが、ubuntu18.04に対応していないのでCUDA9.1をインストールします。

※ 未確認ですが、dockerで構築する場合、ホストOSにcuda入れる必要無いかもしれません。ドライバさえ入ればいいのかも...

手順は下記の記事通り行えばすんなり入ったので割愛

qiita.com

dockerでディープラーニングの環境構築

今回はdocker-compose + tensorflow で環境を作っていきます。

tensorflowと対応する cuDNN・CUDAのバージョンは下記を参照

https://www.tensorflow.org/install/install_sources#tested_source_configurations

どうやら現時点で最新のtensorflow_gpu-1.10.0はCUDA:9らしい。 9.1とか9.2だと動かなかったので、おとなしくバージョン9で動かすことにします。

nvidiaからdockerhubイメージが公開されているのでこのnvidia/cuda:9.0-cudnn7-runtime-ubuntu16.04を利用します。 ubuntu18.04は無いみたい。まぁ16.04でいっか。

https://hub.docker.com/r/nvidia/cuda/

構成

.
├── docker-compose.yml
├── Dockerfile
└── src
    └── mnist_cnn.py

docker-compose.yml

version: '2.3'
services:
  python:
    build: ./
    volumes:
      - ./src:/home/src
    runtime: nvidia
    working_dir: "/home/src"
    tty: true

バージョンが2.3なのは3だとruntimeに対応してないからです。 runtime: nvidiaが無いと

ImportError: libcuda.so.1: cannot open shared object file: No such file or directory

というエラーが出ます。

これ、かなりハマった...

Dockerfile

FROM nvidia/cuda:9.0-cudnn7-runtime-ubuntu16.04
ENV TZ=Asia/Tokyo
ENV DEBIAN_FRONTEND=noninteractive
RUN apt update
RUN apt install -y tzdata tk-dev xvfb vim wget
RUN apt install -y python3-pip python3-tk
RUN pip3 install numpy matplotlib scipy tensorflow-gpu keras

mnist.cnn.py

'''Trains a simple convnet on the MNIST dataset.

Gets to 99.25% test accuracy after 12 epochs
(there is still a lot of margin for parameter tuning).
16 seconds per epoch on a GRID K520 GPU.
'''

from __future__ import print_function
import keras
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras import backend as K

batch_size = 128
num_classes = 10
epochs = 12

# input image dimensions
img_rows, img_cols = 28, 28

# the data, split between train and test sets
(x_train, y_train), (x_test, y_test) = mnist.load_data()

if K.image_data_format() == 'channels_first':
    x_train = x_train.reshape(x_train.shape[0], 1, img_rows, img_cols)
    x_test = x_test.reshape(x_test.shape[0], 1, img_rows, img_cols)
    input_shape = (1, img_rows, img_cols)
else:
    x_train = x_train.reshape(x_train.shape[0], img_rows, img_cols, 1)
    x_test = x_test.reshape(x_test.shape[0], img_rows, img_cols, 1)
    input_shape = (img_rows, img_cols, 1)

x_train = x_train.astype('float32')
x_test = x_test.astype('float32')
x_train /= 255
x_test /= 255
print('x_train shape:', x_train.shape)
print(x_train.shape[0], 'train samples')
print(x_test.shape[0], 'test samples')

# convert class vectors to binary class matrices
y_train = keras.utils.to_categorical(y_train, num_classes)
y_test = keras.utils.to_categorical(y_test, num_classes)

model = Sequential()
model.add(Conv2D(32, kernel_size=(3, 3),
                 activation='relu',
                 input_shape=input_shape))
model.add(Conv2D(64, (3, 3), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(128, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))

model.compile(loss=keras.losses.categorical_crossentropy,
              optimizer=keras.optimizers.Adadelta(),
              metrics=['accuracy'])

model.fit(x_train, y_train,
          batch_size=batch_size,
          epochs=epochs,
          verbose=1,
          validation_data=(x_test, y_test))
score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])

これは

https://raw.githubusercontent.com/fchollet/keras/master/examples/mnist_cnn.py

このコードと全く同じです。

実行してみよう

docker-compose up -d

docker-compose exec python bash

python3 mnist_cnn.py

実行結果がこちら

root@2014d1ff6709:/home/src# python3 mnist_cnn.py
Using TensorFlow backend.
Downloading data from https://s3.amazonaws.com/img-datasets/mnist.npz
11493376/11490434 [==============================] - 66s 6us/step
x_train shape: (60000, 28, 28, 1)
60000 train samples
10000 test samples
Train on 60000 samples, validate on 10000 samples
Epoch 1/12
2018-08-26 09:59:36.423489: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
2018-08-26 09:59:36.543692: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:897] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2018-08-26 09:59:36.544016: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1405] Found device 0 with properties: 
name: GeForce GTX 1080 Ti major: 6 minor: 1 memoryClockRate(GHz): 1.645
pciBusID: 0000:01:00.0
totalMemory: 10.91GiB freeMemory: 10.11GiB
2018-08-26 09:59:36.544027: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1484] Adding visible gpu devices: 0
2018-08-26 09:59:36.710029: I tensorflow/core/common_runtime/gpu/gpu_device.cc:965] Device interconnect StreamExecutor with strength 1 edge matrix:
2018-08-26 09:59:36.710051: I tensorflow/core/common_runtime/gpu/gpu_device.cc:971]      0 
2018-08-26 09:59:36.710055: I tensorflow/core/common_runtime/gpu/gpu_device.cc:984] 0:   N 
2018-08-26 09:59:36.710189: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1097] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 9778 MB memory) -> physical GPU (device: 0, name: GeForce GTX 1080 Ti, pci bus id: 0000:01:00.0, compute capability: 6.1)
60000/60000 [==============================] - 6s 100us/step - loss: 0.2609 - acc: 0.9197 - val_loss: 0.0546 - val_acc: 0.9827
Epoch 2/12
60000/60000 [==============================] - 4s 64us/step - loss: 0.0855 - acc: 0.9751 - val_loss: 0.0441 - val_acc: 0.9854
Epoch 3/12
60000/60000 [==============================] - 4s 71us/step - loss: 0.0658 - acc: 0.9798 - val_loss: 0.0354 - val_acc: 0.9877
Epoch 4/12
60000/60000 [==============================] - 4s 67us/step - loss: 0.0540 - acc: 0.9836 - val_loss: 0.0293 - val_acc: 0.9899
Epoch 5/12
60000/60000 [==============================] - 4s 66us/step - loss: 0.0463 - acc: 0.9859 - val_loss: 0.0307 - val_acc: 0.9901
Epoch 6/12
60000/60000 [==============================] - 4s 64us/step - loss: 0.0406 - acc: 0.9879 - val_loss: 0.0268 - val_acc: 0.9910
Epoch 7/12
60000/60000 [==============================] - 4s 66us/step - loss: 0.0363 - acc: 0.9885 - val_loss: 0.0281 - val_acc: 0.9906
Epoch 8/12
60000/60000 [==============================] - 4s 69us/step - loss: 0.0334 - acc: 0.9897 - val_loss: 0.0288 - val_acc: 0.9902
Epoch 9/12
60000/60000 [==============================] - 4s 65us/step - loss: 0.0301 - acc: 0.9905 - val_loss: 0.0284 - val_acc: 0.9900
Epoch 10/12
60000/60000 [==============================] - 4s 66us/step - loss: 0.0286 - acc: 0.9911 - val_loss: 0.0275 - val_acc: 0.9911
Epoch 11/12
60000/60000 [==============================] - 5s 78us/step - loss: 0.0259 - acc: 0.9917 - val_loss: 0.0278 - val_acc: 0.9919
Epoch 12/12
60000/60000 [==============================] - 4s 74us/step - loss: 0.0263 - acc: 0.9918 - val_loss: 0.0275 - val_acc: 0.9913
Test loss: 0.027503689719716975
Test accuracy: 0.9913

一応GPU使えているみたいですね。

cpuよりは早いですけど、もっとこう劇的に早くなって1Epochあたり1秒かからないかと思ったのですが、期待しすぎでしたね。

4~6秒でした。

よーし、これで前から気になってたGANってやつを試してみるぞー!

追記

ソースコードgithubに置いてあります。

github.com