ゼロからの深層学習用PC最速セットアップ

# はじめに
何度となく深層学習用PCのセットアップをやってきたが、やっては忘れ、やっては忘れの繰り返し。今後も何度も同じことをやることになるはずなので、将来の自分のために作業メモを残すことにした。

(2023.10.6) だいぶ古くなってきたので更新。Anacondaは自分でも使うことがなくなってきたので削除。

この記事は、深層学習用にGPUを積んだLinuxマシンを最速でセットアップするためのメモである。目的は

- NVIDIA Dockerを使わない環境の構築 (~~Anaconda,~~ PyTorch, TensorFlow)
- NVIDIA Dockerのセットアップ

の2つである。もちろん、両方でもどちらかでも構わない。

なお、設置するのは大学内で、残念なことに今どきプロキシ環境。以下の説明にはプロキシの設定が何ヶ所かで出てくるが、プロキシが不要な幸運な読者は、読み飛ばして問題なし。

# OSイメージのダウンロード
深層学習用なので、OSはUbuntuの一択。これまではデスクトップ版を使ってきたが、別にデスクトップは要らないのでサーバ版の方がインストールが早いかも。と考え、今回はサーバ版にする。

今回はUbuntuの最新版20.04ではなく、枯れた版である18.04をインストールするため、[Alternative downloadsページ](https://ubuntu.com/download/alternative-downloads)のPast releases and other flavoursから[20.04のSelect an imageページ](https://releases.ubuntu.com/20.04.6/)に行く。

CPUがIntel Core i7なので、[64-bit PC (AMD64) server install image](https://releases.ubuntu.com/20.04.6/ubuntu-20.04.6-live-server-amd64.iso)を選択してダウンロード。

# ブート用のUSBメモリの準備
Ubuntuチュートリアルの[Create a bootable USB stick on Ubuntu](https://ubuntu.com/tutorials/create-a-usb-stick-on-ubuntu)に出ている Etcher は以前動かなかったので、やや力技だが dd でイメージをUSBメモリにコピーする。以下を実行する前に、USBメモリデバイスの正しいパスを `diskutil list` で調べておくこと！ 自分の場合はたまたま /dev/disk2 だったけど、よく確認しないで eraseDisk をやって、大事なデータを失っても知らんよ。

```sh
sudo diskutil eraseDisk FAT32 NAME MBRFormat /dev/disk2
diskutil unmountdisk /dev/disk2
sudo dd if=$HOME/Downloads/ubuntu-20.04.6-live-server-amd64.iso \
  of=/dev/rdisk2 bs=2m conv=sync
```

実行が終わると、ディスクユーティリティから読めないぞと怒られるが、読めなくて当然なので気にしなくてよい。

# PCをUSBメモリからブート
PCに電源ケーブルとネットワークケーブルをつなぎ、USBメモリを刺した状態で電源を入れる。F11か何かを押してブートメニューを出し、USBメモリに入ったインストールディスクからブートする。自分の場合は、まごまごしているうちに、勝手にUSBメモリから起動して結果オーライだった。

起動した後は、だいたい[【Ubuntu 18.04 LTS Server】インストールする](https://www.yokoweb.net/2018/05/04/ubuntu-18_04-lts-server-install/)に書いてある通り。ここでプロキシの設定をやっておくと、aptのプロキシ設定まで済んだ状態にインストールしてくれるので楽。あと、ここでOpenSSHを入れておくと、この後リモートで作業できて都合が良い。

# 論理ボリュームの容量変更

Ubuntu Server 20.04 をデフォルトでインストールすると、/ (ルートボリューム) がなぜか100GBしか確保されない。LVMを設定して、ディスク目一杯使えるようにしておく。[Ubuntu Server 18.04 LVM out of space with improper default partitioning](https://askubuntu.com/questions/1106795/ubuntu-server-18-04-lvm-out-of-space-with-improper-default-partitioning)

<!--
# SSH切断対策

長いことsshで接続していると、

```console
packet_write_wait: Connection to 192.168.1.18 port 22: Broken pipe
```

と出て切られてしまうことがある。これを防ぐため、エディタで /etc/ssh/sshd_config を開き、ClientAliveInterval の行と ClientAliveCountMax の行を探す。行頭の `#` を削除し、ClientAliveInterval を適当な値に設定する。うちでは以下のようにした。

```:sshd_config
ClientAliveInterval 60
ClientAliveCountMax 3
```
-->

# プロキシ関連環境変数の設定
インストール時にプロキシサーバは指定しているが、環境変数の設定は別途必要。エディタで /etc/environment というファイルを開き、以下を追加する。

```:/etc/environment
HTTP_PROXY=http://プロキシサーバのアドレス:ポート/
HTTPS_PROXY=http://プロキシサーバのアドレス:ポート/
FTP_PROXY=http://プロキシサーバのアドレス:ポート/
ALL_PROXY=http://プロキシサーバのアドレス:ポート/
http_proxy=http://プロキシサーバのアドレス:ポート/
https_proxy=http://プロキシサーバのアドレス:ポート/
ftp_proxy=http://プロキシサーバのアドレス:ポート/
```

以上の設定を反映させるため、ログインし直す。

# NVIDIAドライバのインストール
[NVIDIA Docker って今どうなってるの？ (20.09版)の「NVIDIA ドライバのインストール」](https://medium.com/nvidiajapan/nvidia-docker-って今どうなってるの-20-09-版-558fae883f44#86f4)に従う。

```sh
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/cuda-ubuntu2004.pin
sudo mv cuda-ubuntu2004.pin /etc/apt/preferences.d/cuda-repository-pin-600
wget https://developer.download.nvidia.com/compute/cuda/12.2.2/local_installers/cuda-repo-ubuntu2004-12-2-local_12.2.2-535.104.05-1_amd64.deb
sudo dpkg -i cuda-repo-ubuntu2004-12-2-local_12.2.2-535.104.05-1_amd64.deb
sudo cp /var/cuda-repo-ubuntu2004-12-2-local/cuda-*-keyring.gpg /usr/share/keyrings/
sudo apt-get update
sudo apt-get -y install cuda-drivers
```

インストールできたら、`sudo reboot` としてリブートする。

再度ログインして、`nvidia-smi` を実行して確認する。

```console
+---------------------------------------------------------------------------------------+
| NVIDIA-SMI 535.104.05             Driver Version: 535.104.05   CUDA Version: 12.2     |
|-----------------------------------------+----------------------+----------------------+
| 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 GTX 1080        On  | 00000000:03:00.0 Off |                  N/A |
|  0%   56C    P8              18W / 240W |      1MiB /  8192MiB |      0%      Default |
|                                         |                      |                  N/A |
+-----------------------------------------+----------------------+----------------------+
|   1  NVIDIA GeForce GTX 1080        On  | 00000000:04:00.0 Off |                  N/A |
|  0%   47C    P8              10W / 240W |      1MiB /  8192MiB |      0%      Default |
|                                         |                      |                  N/A |
+-----------------------------------------+----------------------+----------------------+

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

# Minicondaのダウンロードとインストール
以下ではシステムに Miniconda をインストールするが、これはあくまで各自が conda コマンドで独自の環境を作る目的のためだけである。

なお、Miniconda は別にシステムに入れる必要もなく、各自が自分のホームの下に入れても良い。

```sh
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
sudo sh Miniconda3-latest-Linux-x86_64.sh -p /usr/local/miniconda3 -s -b
```

# Conda による環境構築

各ユーザは、自分のホーム直下の設定ファイルに以下を追加しておく。これで conda コマンドが使えるようになる。

```bash:.bash_profile
. /usr/local/miniconda3/etc/profile.d/conda.sh
```

## PyTorch環境の構築

[公式](https://pytorch.org)の INSTALL PYTORCH の手順に従う。あらかじめ CUDA とか cuDNN とかをインストールする必要はない。

condaコマンドで、自分だけのPyTorch環境を作る。名前は mytorch にしておいた。

```sh
conda create -n mytorch pytorch torchvision torchaudio pytorch-cuda=12.1 -c pytorch -c nvidia
```

新しい環境ができたら、アクティベートする。

```sh
conda activate mytorch
```

テストのため、[【Diffusers】Stable Diffusion v2モデルの利用方法](https://self-development.info/【diffusers】stable-diffusion-v2モデルの利用方法/) を実行してみる。

```sh
pip install --upgrade git+https://github.com/huggingface/diffusers.git transformers accelerate scipy
```

```python
import torch
from diffusers import StableDiffusionPipeline, EulerDiscreteScheduler
 
model_id = "stabilityai/stable-diffusion-2"
 
scheduler = EulerDiscreteScheduler.from_pretrained(model_id, subfolder="scheduler")
pipe = StableDiffusionPipeline.from_pretrained(model_id, scheduler=scheduler, revision="fp16",
                                               torch_dtype=torch.float16, safety_checker=None)
pipe = pipe.to("cuda")
# pipe.enable_attention_slicing() 
 
prompt = "A cuty pussycat sleeping"
image = pipe(prompt, height=768, width=768).images[0]
 
image.save("cat.png")
```
かわいい猫の画像を堪能したら終了。

## TensorFlow環境の構築

[conda install のみでTensorFlowとGPU環境（CUDA、cuDNN）を構築する](https://qiita.com/ktokey/items/7ee9c112198a6b0b5709)の内容。あらかじめ CUDA とか cuDNN とかをインストールする必要がない。
```sh
conda create -n tf2 tensorflow=2.8.2=gpu_py39hc0c9373_0
```

# NVIDIA Dockerのセットアップ
このセクションは、全般に[NVIDIA Docker って今どうなってるの？ (20.09 版)](https://medium.com/nvidiajapan/nvidia-docker-って今どうなってるの-20-09-版-558fae883f44)を参考にした。

## Dockerそのもののインストール
[ここ](https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository)に従う。

```sh
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo \
  "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
  "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
```

## Dockerのプロキシ設定
[Configure the daemon with systemd](https://docs.docker.com/config/daemon/systemd/)にやり方が書いてある。

以下の手順で /etc/systemd/system/ の下に docker.service.d というディレクトリを作り、その下に http-proxy.conf というファイルを作る。

```sh
sudo mkdir -p /etc/systemd/system/docker.service.d
sudo vi /etc/systemd/system/docker.service.d/http-proxy.conf
```

```:http-proxy.conf
[Service]
Environment="HTTP_PROXY=http://プロキシサーバのアドレス:ポート/" "HTTPS_PROXY=http://プロキシサーバのアドレス:ポート/" "NO_PROXY=localhost,127.0.0.1,.lab"
```

設定を有効化するために Docker を再起動する。

```sh
sudo systemctl daemon-reload
sudo systemctl restart docker
```

## Dockerのテスト
ここまでうまく行ったか、Docker Hub から hello-world イメージをダウンロードして実行してみる。

```sh
sudo docker run hello-world
```

それっぽいメッセージが出ればOK。

## [NVIDIA Container Toolkit](https://github.com/NVIDIA/nvidia-docker/tree/master#quickstart)のインストール

```sh
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list
sudo apt-get update
sudo apt-get install -y nvidia-docker2
sudo systemctl restart docker
```

以下を実行する。nvidia-smi の出力が出ればOK。

```sh
sudo docker run --rm --gpus all nvidia/cuda:12.1.0-base-ubuntu20.04 nvidia-smi
```

## 非rootユーザでDockerを実行できるようにする

```sh
sudo usermod -aG docker `whoami`
```

一度 `sudo reboot` で再起動した後、非rootで docker コマンドを実行できるかテスト。

```shell-session
$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
```

## NVIDIA Docker のテスト

[Tacotron 2 And WaveGlow v1.10 For PyTorch](https://github.com/NVIDIA/DeepLearningExamples/tree/master/PyTorch/SpeechSynthesis/Tacotron2) を実行してみる。

プロキシ環境の場合、scripts/docker/build.sh 実行時に環境変数HTTP_PROXY等を引き継ぐ設定が必要。
```sh
#!/bin/bash

docker build --build-arg http_proxy --build-arg https_proxy . --rm -t tacotron2
```

```sh
git clone https://github.com/NVIDIA/DeepLearningExamples.git
cd DeepLearningExamples/PyTorch/SpeechSynthesis/Tacotron2
bash scripts/prepare_dataset.sh
bash scripts/docker/build.sh
```

以下のコマンドで、Docker の環境に入る。

```sh
bash scripts/docker/interactive.sh
```

前処理

```sh
bash scripts/prepare_mels.sh
```

後は学習だが、自分の環境だとGPUのメモリ不足で落ちてしまうので、scripts/train_tacotron2.sh のバッチサイズを指定するところを `-bs 32` に書き換えておいた。

```sh
bash scripts/train_tacotron2.sh
```

時間がかかるので、100エポックくらい進んだら ctrl+C で止めてしまった。

合成のテスト。WaveGlow のモデル学習はせず、学習済みのものをダウンロードして使った。以下のコマンドで、output の下に合成音声 audio_0_.wav ができる。

```
python inference.py --tacotron2 output/checkpoint_Tacotron2_last.pt --waveglow waveglow_1076430_14000_amp --wn-channels 256 -o output/ -i phrases/phrase.txt --fp16
```

# おわりに
深層学習用PCのセットアップでは、実は CUDA や cuDNN のインストールは要らないことがわかった。深層学習用の環境は、各ユーザが独自 conda 環境の中に整備したり、Dockerを利用すればよく、逆にシステムに CUDA や cuDNN を入れると、バージョン問題で運用が大変になる。すっきりした。