NVIDIA RTX3060Tiに対応したDocker環境をゼロから構築し、WebカメラとGUIを制御する

機械学習に関するアプリを開発していると、Pythonの仮想環境へのパッケージインストール(pip)に限らず、aptコマンド等でOSを構成するアプリケーションやライブラリのパッケージのインストールをしたい場面がちょくちょくあります。

ですが、パッケージを入れるたびに管理者へお伺いを立てたり、他のユーザーが利用しているパッケージと競合しないかを調べならが慎重にインストール作業を行うことは、とても非効率的です。そこで、Dockerコンテナ上にAI/機械学習の開発環境を整備し、全ユーザーがrootとして自由に、そして他のユーザーの環境を破壊せず開発できるDockerの利用手順をまとめてみました。


# GPUのドライバ、CUDA、cuDNNをインストールする

NVIDIA RTX3060Tiのドライバと、CUDA、cuDNNは下記の手順でインストールしました。

https://qiita.com/xtrizeShino/items/56125ef057c6e88b4302

## GeForce RTX3060Tiのドライバをインストールする

#### Secure Bootを無効化する

作業を始める前に、MotherboardのUEFI画面からSecure Bootを無効にします。UEFIを起動して、Settings/Security/Secure BootのSecure BoodをDiasableにしました。Secure Bootを有効にしたままGeForceのドライバを入れる方法もあるようですが、難しいので今回はパス！

![WIN_20241109_22_04_05_Pro.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919880/c9ad86d2-65c5-5f45-fb80-492d148fe2d9.jpeg)

#### 前準備

Ubuntuのパッケージをすべて更新します

```bash
# リポジトリにアクセス
$ sudo apt update

# 更新可能なパッケージをすべてアップグレード
$ sudo apt upgrade

# 再起動
$ sudo reboot
```

続いて、作業用にsshサーバをインストールして起動します

```bash
# sshサーバをインストールします
$ sudo apt install openssh-server

# Ubuntu24.04からsshdでなくsshになっています 
# ... 起動時にサービスが開始されるように設定します
$ sudo systemctl start ssh
$ sudo systemctl enable ssh
```

GeForceドライバをインストールする前に、汎用グラフィックドライバ `nouveau` が勝手にロードされないよう無効化しておきます。

```bash
# ファイルを新規作成し、無効化設定を記述する
$ sudo vi /etc/modprobe.d/blacklist-nouveau.conf
blacklist nouveau
options nouveau modeset=0

# 保存したらinitramfsを更新して再起動
$ sudo update-initramfs -u
$ sudo reboot
```

`update-initramfs`コマンドにより、カーネルが起動してからルートファイルシステムが開始する前に実行されるinitramfsの構成をアップデートします。

### GPUを確認する

NVIDIAのGPUが搭載されていることをlspciコマンドで確認します。

```bash
$ lspci | grep -i vga
# 01:00.0 VGA compatible controller: NVIDIA Corporation GA103 [GeForce RTX 3060 Ti] (rev a1)
```

古いドライバが入っていないか確認し、削除します。

```bash
$ dpkg -l | grep nvidia
$ dpkg -l | grep cuda
$ sudo apt-get --purge remove nvidia-*
$ sudo apt-get --purge remove cuda-*
```

インストールできるドライバのリストを表示します。`ubuntu-drivers`で表示される推奨のドライバは`recommended`と書かれているものですが、[NVIDIAのドライバ配布サイト](https://www.nvidia.com/ja-jp/drivers/)からでも、どのバージョンが推奨なのか調べることができます。RTX3060Tiには`nvidia-driver-550`が良さそうです。

```bash
$ ubuntu-drivers devices
# ...
# == /sys/devices/pci0000:00/0000:00:01.0/0000:01:00.0 ==
# modalias : pci:v000010DEd00002414sv000010DEsd0000163Fbc03sc00i00
# vendor   : NVIDIA Corporation
# model    : GA103 [GeForce RTX 3060 Ti]
# driver   : nvidia-driver-470 - distro non-free
# driver   : nvidia-driver-550 - distro non-free recommended
# driver   : nvidia-driver-535-server - distro non-free
# driver   : nvidia-driver-550-open - distro non-free
# driver   : nvidia-driver-535 - distro non-free
# driver   : nvidia-driver-535-open - distro non-free
# driver   : nvidia-driver-470-server - distro non-free
# driver   : nvidia-driver-535-server-open - distro non-free
# driver   : xserver-xorg-video-nouveau - distro free builtin
```

![2024-11-09 (11).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919880/457b31a5-68d7-e55b-9696-ac46aaedcfac.png)

### ドライバをインストールする

GPUのドライバが含まれているリポジトリを登録し、リポジトリのパッケージ情報を`apt update`で取得します。最後にドライバをインストール、システムを再起動します。

```bash
# GPUのドライバが含まれているリポジトリをシステムに登録します
$ sudo add-apt-repository ppa:graphics-drivers/ppa

# パッケージ情報を最新にします
$ sudo apt update

# 推奨されている550ドライバをインストールします
$ sudo apt install nvidia-driver-550

# システムを再起動します
$ sudo reboot
```

#### インストールできていることを確認する

`nvidia-smi`を実行し、GPUの情報が出力されればドライバのインストールは成功です。

```
$ nvidia-smi
Sat Nov  9 23:19:36 2024
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 550.127.05             Driver Version: 550.127.05     CUDA Version: 12.4     |
|-----------------------------------------+------------------------+----------------------+
| 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  NVIDIA GeForce RTX 3060 Ti     Off |   00000000:01:00.0  On |                  N/A |
|  0%   30C    P8              5W /  200W |     206MiB /   8192MiB |      0%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+

+-----------------------------------------------------------------------------------------+
| Processes:                                                                              |
|  GPU   GI   CI        PID   Type   Process name                              GPU Memory |
|        ID   ID                                                               Usage      |
|=========================================================================================|
|    0   N/A  N/A      1760      G   /usr/lib/xorg/Xorg                             73MiB |
|    0   N/A  N/A      2038      G   /usr/bin/gnome-shell                          117MiB |
+-----------------------------------------------------------------------------------------+

```

## CUDAをインストールする

CUDAは以下のサイトにインストール方法が公開されています。

https://developer.nvidia.com/cuda-downloads?target_os=Linux&target_arch=x86_64&Distribution=Ubuntu&target_version=24.04&target_type=deb_local

自身の構成にあわせて項目を選択すると、下部に実行すべきコマンドが表示されます。この通りに実行すれば問題ありません。

![2024-11-09 (12).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919880/d31eccf1-af67-b02d-3fd2-b0d1bc8a2694.png)

```bash
# CUDAのダウンロードサイトに書かれた手順をそのまま実行
$ wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2404/x86_64/cuda-ubuntu2404.pin
$ sudo mv cuda-ubuntu2404.pin /etc/apt/preferences.d/cuda-repository-pin-600
$ wget https://developer.download.nvidia.com/compute/cuda/12.6.2/local_installers/cuda-repo-ubuntu2404-12-6-local_12.6.2-560.35.03-1_amd64.deb
$ sudo dpkg -i cuda-repo-ubuntu2404-12-6-local_12.6.2-560.35.03-1_amd64.deb
$ sudo cp /var/cuda-repo-ubuntu2404-12-6-local/cuda-*-keyring.gpg /usr/share/keyrings/
$ sudo apt-get update
$ sudo apt-get -y install cuda-toolkit-12-6
```

最後にパスを通します。

```bash
# 最後の行に下記の2行を追加する
$ vi ~/.bashrc
export PATH="/usr/local/cuda/bin:$PATH"
export LD_LIBRARY_PATH="/usr/local/cuda/lib64:$LD_LIBRARY_PATH"

# 設定した環境変数を反映させます
$ source ~/.bashrc
```

`nvcc`コマンドでCUDAの情報が出てくればOKです。

```bash
$ nvcc -V
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2024 NVIDIA Corporation
Built on Thu_Sep_12_02:18:05_PDT_2024
Cuda compilation tools, release 12.6, V12.6.77
Build cuda_12.6.r12.6/compiler.34841621_0
```

## cuDNNをインストールする

cuDNNのインストールには、NVIDIAのユーザー登録(無料)が必要です。登録した後はCUDA同様に構成を選択して、表示されたコマンドを実行しましょう。

https://developer.nvidia.com/cudnn-downloads?target_os=Linux&target_arch=x86_64&Distribution=Ubuntu&target_version=24.04&target_type=deb_local

![2024-11-09 (13).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3919880/2dfe026e-346f-cc85-d66e-7f8506f9c218.png)

```bash
# cuDNNのダウンロードサイトに書かれた手順をそのまま実行します
$ wget https://developer.download.nvidia.com/compute/cudnn/9.5.1/local_installers/cudnn-local-repo-ubuntu2404-9.5.1_1.0-1_amd64.deb
$ sudo dpkg -i cudnn-local-repo-ubuntu2404-9.5.1_1.0-1_amd64.deb
$ sudo cp /var/cudnn-local-repo-ubuntu2404-9.5.1/cudnn-*-keyring.gpg /usr/share/keyrings/
$ sudo apt-get update
$ sudo apt-get -y install cudnn
$ sudo apt-get -y install cudnn-cuda-12
```

# Dockerをインストールする

Dockerをインストールし、ユーザーから操作できるようにします。

```bash
# 古いパッケージを削除する
$ sudo apt-get remove docker docker-engine docker.io containerd runc

# 必要なパッケージをインストールする
$ sudo apt-get update
$ sudo apt-get install -y ca-certificates curl gnupg lsb-release

# インストール時に使用するGPG鍵をシステムに追加する
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

# Dockerをインストールする元のリポジトリをシステムに追加する
$ echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# Dockerエンジンのインストール
$ sudo apt-get update
$ sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

# Dockerが動くことを確認する
$ sudo docker run --rm hello-world
# latest: Pulling from library/hello-world
# c1ec31eb5944: Pull complete 
# Digest: sha256:305243c734571da2d100c8c8b3c3167a098cab6049c9a5b066b6021a60fcb966
# Status: Downloaded newer image for hello-world:latest
# Hello from Docker!
# ...

# 非rootユーザーもDockerを操作できるようにする
$ sudo groupadd docker
$ sudo usermod -aG docker $USER
$ newgrp docker

# Linux起動時にDockerサービスが起動するよう設定する
$ sudo systemctl start docker.service
$ sudo systemctl enable docker.service
$ sudo systemctl start containerd.service
$ sudo systemctl enable containerd.service

# 再起動
$ sudo reboot
```

再起動後、dockerコマンドをsudo無しで実行できるか確認します。

```bash
$ docker run --rm hello-world
# latest: Pulling from library/hello-world
# c1ec31eb5944: Pull complete 
# Digest: sha256:305243c734571da2d100c8c8b3c3167a098cab6049c9a5b066b6021a60fcb966
# Status: Downloaded newer image for hello-world:latest
# Hello from Docker!
# ...
```

Dockerのインストール方法は、[こちら](https://matsuand.github.io/docs.docker.jp.onthefly/engine/install/ubuntu/)のWebサイトを参照しました。


# GPUとDockerコンテナを接続するNVIDIA Container Toolkitをインストールする

続いて、NVIDIAのGPUをDockerから使えるようにする`NVIDIA Container Toolkit`をインストールします。NVIDIA Container Toolkitは下記手順を参考にインストールしました。

https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html

```bash
# NVIDIA Container Toolkitが格納されたリポジトリをシステムに追加する
$ curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg && curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list

# NVIDIA Container Toolkitをインストールする
$ sudo apt-get update
$ sudo apt-get install -y nvidia-container-toolkit

# コンテナのランタイムがDockerであることを登録する
$ sudo nvidia-ctk runtime configure --runtime=docker
# INFO[0000] Config file does not exist; using empty config 
# INFO[0000] Wrote updated config to /etc/docker/daemon.json 
# INFO[0000] It is recommended that docker daemon be restarted. 
$ sudo systemctl restart docker

# GPUが見えなくなる問題の対策
# -->> https://qiita.com/tttamaki/items/4f369633b7f53f5131a1
$ sudo vi /etc/docker/daemon.json
{   
    "runtimes": { 
        "nvidia": { 
            "args": [],
            "path": "nvidia-container-runtime"
        }
    },
    "exec-opts": ["native.cgroupdriver=cgroupfs"]
}
$ sudo systemctl restart docker
$ docker info | grep Cgroup
# Cgroup Driver: cgroupfs
# Cgroup Version: 2
```

## コンテナからGPUへアクセスできることを確認する

ホストに搭載されたGPU（nvidia-smiで見えるデバイス）を、コンテナに接続するには`--gpus`オプションを使います。コンテナを起動する際に`--gpus all`とすればすべてのGPUがコンテナに、`--gpus device=1`とすれば先頭のGPUだけがコンテナに接続されます。まずホストから正しくGPUを認識できているかチェックしておきます。

```bash
# ホストOS上でGPUが見えることを確認する
$ nvidia-smi
Sat Nov 23 12:22:19 2024       
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 550.127.05             Driver Version: 550.127.05     CUDA Version: 12.4     |
|-----------------------------------------+------------------------+----------------------+
| 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  NVIDIA GeForce RTX 3060 Ti     Off |   00000000:01:00.0  On |                  N/A |
|  0%   44C    P8              9W /  200W |     484MiB /   8192MiB |      5%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+
|   1  NVIDIA GeForce RTX 3060 Ti     Off |   00000000:04:00.0 Off |                  N/A |
| 37%   30C    P8              9W /  200W |       9MiB /   8192MiB |      0%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+
                                                                                         
+-----------------------------------------------------------------------------------------+
| Processes:                                                                              |
|  GPU   GI   CI        PID   Type   Process name                              GPU Memory |
|        ID   ID                                                               Usage      |
|=========================================================================================|
|    0   N/A  N/A      1968      G   /usr/lib/xorg/Xorg                            197MiB |
|    0   N/A  N/A      2232      G   /usr/bin/gnome-shell                           89MiB |
|    0   N/A  N/A      2951      G   ...irefox/5273/usr/lib/firefox/firefox        184MiB |
|    1   N/A  N/A      1968      G   /usr/lib/xorg/Xorg                              4MiB |
+-----------------------------------------------------------------------------------------+

# CUDAのバージョンを確認する
$ nvcc -V
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2024 NVIDIA Corporation
Built on Thu_Sep_12_02:18:05_PDT_2024
Cuda compilation tools, release 12.6, V12.6.77
Build cuda_12.6.r12.6/compiler.34841621_0
```

次にコンテナから見えることを確認します。コンテナのイメージはPyTorchを使うことのできる「[pytorch/pytorch:2.5.1-cuda12.4-cudnn9-devel](https://hub.docker.com/layers/nvidia/cuda/12.6.2-cudnn-runtime-ubuntu24.04/images/sha256-c2538a9f91d581c0e61f5b4ac4687f336064628afe5a9050a6ec7a4c9a50a09a?context=explore)」を選択しました。`--gpu all`オプションをつけて、ホストの持つすべてのGPUリソースをコンテナへ提供します。

https://hub.docker.com/layers/pytorch/pytorch/2.5.1-cuda12.4-cudnn9-devel/images/sha256-14611869895df612b7b07227d5925f30ec3cd6673bad58ce3d84ed107950e014?context=explore

なお、コンテナ内ではrootユーザーになることができますので **自由にパッケージをインストールしたり環境設定を変更したりできます。もちろんコンテナなのでいくら破壊してもホストOSのダメージはありません。**

```bash
# Dockerコンテナを取得して、コンテナにすべてのGPUを接続する
(host) $ docker run --rm -it --gpus all pytorch/pytorch:2.5.1-cuda12.4-cudnn9-devel

# コンテナにログインできた
(container) $ 

# ログイン中のユーザーを確認する
(container) $ whoami
root

# 開発ツールのバージョンを確認する
(container) $ /usr/local/cuda/bin/nvcc --version
nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2024 NVIDIA Corporation
Built on Thu_Mar_28_02:18:24_PDT_2024
Cuda compilation tools, release 12.4, V12.4.131
Build cuda_12.4.r12.4/compiler.34097967_0

# nvidia-smiでGPUリソースを確認する
(container) $ nvidia-smi
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 550.127.05             Driver Version: 550.127.05     CUDA Version: 12.4     |
|-----------------------------------------+------------------------+----------------------+
| 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  NVIDIA GeForce RTX 3060 Ti     Off |   00000000:01:00.0  On |                  N/A |
|  0%   48C    P5             16W /  200W |     548MiB /   8192MiB |      0%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+
|   1  NVIDIA GeForce RTX 3060 Ti     Off |   00000000:04:00.0 Off |                  N/A |
| 37%   32C    P8             18W /  200W |       9MiB /   8192MiB |      0%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+
                                                                                         
+-----------------------------------------------------------------------------------------+
| Processes:                                                                              |
|  GPU   GI   CI        PID   Type   Process name                              GPU Memory |
|        ID   ID                                                               Usage      |
|=========================================================================================|
+-----------------------------------------------------------------------------------------+
docker run --rm -it --gpus device=1 --device /dev/video0:/dev/video0:mwr --volume /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY pytorch/pytorch:2.5.1-cuda12.4-cudnn9-devel

# コンテナから抜ける
(container) $ exit

# ホストでプロセスやコンテナが残っていないか確認する
(host) $ docker container ls -a
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
(host) $ docker ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
```

#### GPUリソースを一部に絞ってコンテナへ提供する

`--gpus device=1`オプションをつけることで、2番目のGPUのみ見せるようにもできます。

```bash
# コンテナに片方のGPUのみ見せたい場合は --gpu device オプションで指定する
(host) $ docker run --rm --gpus device=1 pytorch/pytorch:2.5.1-cuda12.4-cudnn9-devel nvidia-smi
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 550.127.05             Driver Version: 550.127.05     CUDA Version: 12.6     |
|-----------------------------------------+------------------------+----------------------+
| 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  NVIDIA GeForce RTX 3060 Ti     Off |   00000000:04:00.0 Off |                  N/A |
| 37%   28C    P8              9W /  200W |       9MiB /   8192MiB |      0%      Default |
|                                         |                        |                  N/A |
+-----------------------------------------+------------------------+----------------------+
                                                                                         
+-----------------------------------------------------------------------------------------+
| Processes:                                                                              |
|  GPU   GI   CI        PID   Type   Process name                              GPU Memory |
|        ID   ID                                                               Usage      |
|=========================================================================================|
+-----------------------------------------------------------------------------------------+
```

#### Webカメラをコンテナに見せる

`--device`オプションを使うことにより、ホストOSが認識しているカメラデバイス`/dev/video0`を、コンテナの`/dev/video0`として使うことができます。

```bash
(host) $ docker run --rm -it --gpus device=1 --device /dev/video0:/dev/video0:mwr pytorch/pytorch:2.5.1-cuda12.4-cudnn9-devel
...
(container) ls /dev/video0 
/dev/video0
```

# コンテナを終了させずにホストに戻る

コンテナにフォーカスされていますが、一旦ホストに戻りたい場合は **【Ctrl+P】->【Ctrl+Q】** を入力します。コンテナから出た後に再度コンテナに入るには`docker ps -a`コマンドでプロセスを調べたプロセスIDに、`docker container attach`コマンドを実行し入ります。

```bash
# コンテナを起動させたまま、ホストに戻す
(container) $ ###【Ctrl+P】->【Ctrl+Q】

# ホストでプロセスを確認する
(host) $ docker ps -a
ONTAINER ID   IMAGE                                         COMMAND                   CREATED         STATUS         PORTS     NAMES
cd33a65bf053   pytorch/pytorch:2.5.1-cuda12.4-cudnn9-devel   "/opt/nvidia/nvidia_…"   8 seconds ago   Up 8 seconds             heuristic_kare

# 再度コンテナに接続する
(host) $ docker container attach cd33a65bf053
(container) $
```

#### コンテナを再起動する

コンテナのファイルを維持したまま再起動するには`docker restart`オプションを使います。再起動前後でもプロセスが維持され、PCの再起動のように振る舞うことができます。

```bash
# コンテナの再起動でもファイルが残ることの確認
(container) $ touch test.txt
(container) $ ls 
test.txt

# コンテナを起動させたまま、ホストに戻す
(container) $ ###【Ctrl+P】->【Ctrl+Q】
(host) $ 

# dockerコマンドを使って再起動する
(host) $ docker restart cd33a65bf053
cd33a65bf053

# psコマンドで確認するとプロセスはそのままになっている
(host) $ docker ps -a
CONTAINER ID   IMAGE                                         COMMAND                   CREATED              STATUS         PORTS     NAMES
cd33a65bf053   pytorch/pytorch:2.5.1-cuda12.4-cudnn9-devel   "/opt/nvidia/nvidia_…"   About a minute ago   Up 4 seconds             heuristic_kare

# 再度コンテナに接続する
(host) $ docker container attach cd33a65bf053
(container) $ ls
test.txt

```

# コンテナに接続したWebカメラの映像をGUIへ出力する

機械学習のアプリケーションでは、リアルタイムにWEBカメラの映像を解析し、推論結果を映像で出力するものも多くあります。そのため、本記事の最後にコンテナからGUIを扱う方法についてまとめます。今回のホストOSはUbuntu24.04 Desktopです。

### Webカメラの映像を出力できるパッケージを備えたDockerイメージをPyTorchイメージをベースとして作成する

GUI利用のサンプルとして、Webカメラから採取した画像をGUIへ出力できるコンテナを作ってみましょう。まず、以下のファイルを`Dockerfile`としてホストOS上に作成します。本スクリプトはベースとなる`pytorch/pytorch:2.5.1-cuda12.4-cudnn9-devel`にパッケージを追加し、GUI出力とWebカメラに対応させるものです。

```Dockerfile
FROM pytorch/pytorch:2.5.1-cuda12.4-cudnn9-devel

ARG DEBIAN_FRONTEND=noninteractive
ENV TZ=Asia/Tokyo

RUN apt update
RUN apt install -y python3-tk
RUN apt install -y v4l-utils
RUN apt install -y vim
RUN apt install -y libopencv-dev
RUN pip install --upgrade pip 
RUN apt install -y libsm6 libxext6 libxrender-dev
RUN pip install opencv-python
RUN pip install pytest
RUN pip install nose

RUN echo 'export QT_X11_NO_MITSHM=1' >> ~/.bashrc && \
. ~/.bashrc
```

Dockerfileを作成した後`docker build`コマンドを使ってイメージを作成します。

```bash
# 作業ディレクトリに上記のDockerfileを置く
(host) $ ls
Dockerfile

# Docker imageをビルドする
(host) $ docker build --tag my_pytorch_gui:0.0.1 .

# ビルドされたイメージを確認する
(host) $ docker image ls
REPOSITORY        TAG                                IMAGE ID       CREATED          SIZE
my_pytorch_gui    0.0.1                              9e18fac72b71   16 seconds ago   14.6GB
pytorch/pytorch   2.5.1-cuda12.4-cudnn9-devel        05d1b981bb5b   3 weeks ago      13.3GB
hello-world       latest                             d2c94e258dcb   19 months ago    13.3kB
```

#### 作成したイメージを実行する

最後に作成したイメージに`--volume /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY`オプションを指定して`docker run`を実行。コンテナ内にテストコード`test.py`(後述)を作成し、`python`コマンドで実行するとWEBカメラの映像がホストOSのGUIへ出力されます。

```bash
# XへDockerが書き込んでもよい許可を与える
(host) $ xhost +
# ビルドしたDockerイメージを起動する
(host) $ docker run --rm -it --gpus device=1 --device /dev/video0:/dev/video0:mwr --volume /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY my_pytorch_gui:0.0.1

# WEBカメラの画像を出力するPythonテストコードを作成
(container) $ vi test.py

# テストコードを実行
(container) $ python test.py
#【GUIにカメラの画像が出力される】【Ctrl+C で終了】
```

Webカメラの映像をGUIに出力に利用したテストコードは、以下の通りです。

```python
import cv2
camera_width = 1280
camera_height = 960
vidfps = 30

cam = cv2.VideoCapture(0)
cam.set(cv2.CAP_PROP_FPS, vidfps)
cam.set(cv2.CAP_PROP_FRAME_WIDTH, camera_width)
cam.set(cv2.CAP_PROP_FRAME_HEIGHT, camera_height)
cv2.namedWindow("USB Camera", cv2.WINDOW_AUTOSIZE)

while True:
    ret, color_image = cam.read()
    if not ret:
        continue
    cv2.imshow('USB Camera', color_image)
    if cv2.waitKey(1)&0xFF == ord('q'):
        break
```

----

GUIへの出力方法は、以下の記事を参考にさせていただきました。
本当にありがとうございます。

https://qiita.com/iwankoTG/items/95e3b453faa0c9f7f3e4

https://qiita.com/siruku6/items/b8aae4cdbf6ebc0dc5d6

https://qiita.com/ay__1130/items/d36b0673de637b675db2

https://stackoverflow.com/questions/13702425/source-command-not-found-in-sh-shell

----

以上、機械学習のアプリ開発を便利にするDocker環境の構築方法でした！
是非ご活用ください！