Help us understand the problem. What is going on with this article?

Docker(19.03)でgpu有効化してpytorchで訓練するまでやる(Ubuntu18.04)

はじめに

Dockerの解説記事は多くありますが、情報が結構ばらばらで実際に機械学習できるようになるまでには、ネットの海を漂い続けなければなりませんでした。
またDockerのバージョンが新しめなせいもあってか、以前のバージョン通りではうまく行かないことも多々ありました。
今回、dockerのインストールからcudaイメージ、pytorchを使った機械学習まで通してやっていきます。
参考になれば幸いです。

環境

ubuntu 18.04
Geforce 1080ti
nvidia driver 430.26

dockerインストール

まずはdockerのインストールからです。
docker公式に従ってコマンドを打ち込んでいきます。

$ sudo apt-get update
$ sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo apt-key fingerprint 0EBFCD88
$ sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"
$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io

上から順に実行していき、最後にバージョンを確認します。

$ docker version
>Client: Docker Engine - Community
 Version:           19.03.2
 API version:       1.40
 Go version:        go1.12.8
 Git commit:        6a30dfc
 Built:             Thu Aug 29 05:29:11 2019
 OS/Arch:           linux/amd64
 Experimental:      false

最後にdockerコマンドにsudoをつけるのがめんどくさい人は以下を実行して再起動します。
ただしdockerに権限を与えてしまうので自己責任で。

$ sudo usermod -aG docker __username__

参考

Ubuntuにdockerをインストールする

CUDAイメージをプル

最初からpytorchをいれても動く可能性はありますが、まずcudaイメージをいれて、gpuを認識できるか確認しましょう。
cudaイメージをダウンロードします。(もしかするとこの章自体いらないかもしれないです。次の章のpytorchプルをしちゃってください)

$ docker pull nvidia/cuda:10.0-cudnn7-devel-ubuntu16.04

$ docker pull nvidia/cudaだと最新版が入りますが後のpytorchのベースイメージに合わせました。
そしてnvidia-smiでgpuを確認します。

$ docker run --rm --gpus all nvidia/cuda:10.0-cudnn7-devel-ubuntu16.04 nvidia-smi
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 430.26       Driver Version: 430.26       CUDA Version: 10.2     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX 108...  Off  | 00000000:17:00.0 Off |                  N/A |
| 23%   28C    P8     9W / 250W |      2MiB / 11178MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

ちなみに多くのサイトで書いてある、runオプションのruntimeは自分の環境ではエラーが出てできませんでした、
これにも書いてあるとおり、その代わりに--gpusを使うようです。

エラーが出た人へ

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

もし上記のようなエラーが出たとき、ありがたいことに解決策書いてる方がいらっしゃったので紹介します。
New Docker CLI API Support for NVIDIA GPUs under Docker Engine 19.03.0 Pre-Release

場所はどこでもいいのでshファイルを作ります。

$ gedit nvidia-container-runtime-script.sh

そのshファイルに以下を打ち込み、実行します。

nvidia-container-runtime-script.sh
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が認識されていたら成功です!

参考

dockerでgpuコンテナの作成

pytorchをビルド

https://github.com/pytorch/pytorch
まずは上のgitからクローンします。
クローンしたら、pytorchディレクトリに移動してビルドをします。

docker build -t pytorch -f docker/pytorch/Dockerfile .

結構時間がかかりますが、気長に待ちましょう。
終わったら確認してみます。

docker images
REPOSITORY          TAG                             IMAGE ID            CREATED             SIZE
pytorch             latest                          47ea93f4ed87                       6.12GB
nvidia/cuda         10.0-cudnn7-devel-ubuntu16.04   b739d7317c55                       3.12GB

pytorchのイメージがあればokです。(作成日時は抜きました。)

(追記)

別にbuildしなくてもpullするだけでよかった
docker pull pytorch/pytorch

コンテナを作成して起動

これでやっと学習のためのコンテナを作成できます。

$ docker run -it --gpus all -v マウントしたい場所:docker側の場所 --shm-size 8G --name ml pytorch

コマンドの説明をします。
docker runはイメージからコンテナを作成し、起動をします。

-itはそのままコンテナ内でbashを起動してくれます。つまり、runをしてそのままコンテナ内で作業することができます。

-vはホストpcのディレクトリをdockerにマウントします。
例えばホストPC側で~/ML/が機械学習のディレクトリであるとき、-v ~/ML:/MLとすることで、マウントをすることができ、好きなエディタで編集して実行する事ができます。

--shm-sizeはコンテナに割り当てるメモリの量です。今回は8GB割り当てています。

--nameはそのコンテナの名前です。起動やログイン時に使います。

起動が成功するとbashの前にroot@0f5c51d62772のようなコンテナidが付きます。

学習

先程の例のように/ML/train.pyを置いて学習させます。
コードはPytorchチュートリアルを参考にしたものです。

train.py
import torch
import torchvision
import torchvision.transforms as transforms
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim


transform = transforms.Compose(
    [transforms.ToTensor(),
     transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=4, shuffle=True, num_workers=2)

classes = ('plane', 'car', 'bird', 'cat',
           'deer', 'dog', 'frog', 'horse', 'ship', 'truck')

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.pool = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 16 * 5 * 5)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

net = Net().cuda()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

for epoch in range(10):
    running_loss = 0.0
    for i, data in enumerate(trainloader, 0):
        inputs, labels = data
        inputs, labels = inputs.cuda(), labels.cuda()
        optimizer.zero_grad()
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
        running_loss += loss.item()
        if i % 2000 == 1999:
            print('[%d, %5d] loss: %.3f' %
                  (epoch + 1, i + 1, running_loss / 2000))
            running_loss = 0.0

print('Finished Training')

 
python train.pyで訓練が始まったら成功です!

おまけ

コンテナに入るときはそのコンテナが起動していないといけません。
コンテナが起動状態を見るにはdocker ps -aで確認できます。
起動はdocker start コンテナの名前、入るときはdocker attach コンテナの名前を使います。
コンテナから抜けるときはctrl P Qを同時に押します。

tomp
大学生。 強化学習と物体検出、セグメンテーション等に興味があります。 備忘録的にアウトプットしていきたい。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away