UbuntuにCUDA10.0+cuDNNを導入してaptのPinでマイナーアップデートに追従させた

## 概要

`tensorflow-gpu` を動かすためにUbuntu 18.04 LTSにCUDA 10.0 [^cuda]とそれ用のcuDNNを導入する必要があったけれども，aptで素朴にやるとcuDNNの `+cuda10.1` を入れたがられたため，優先度を変更するPinを設定した。
導入したCUDAおよびcuDNNは `apt upgrade` によって10.0を保ったままマイナーアップデートに追従した。

## 環境

- Ubuntu 18.04 LTS
- tensorflow-gpu 2.0
- CUDA 10.0 + cuDNN 7.6
- apt 1.6

## 設定

次の記事を参考にした： [Ubuntu 18.04へのCUDAインストール方法 - Qiita](https://qiita.com/yukoba/items/4733e8602fa4acabcc35)

CUDAについては [CUDA Toolkit 10.1 Update 2 Download | NVIDIA Developer](https://developer.nvidia.com/cuda-downloads) にて， `Linux > x86_64 > Ubuntu > 18.04 > deb (network)` を辿った。
cuDNNについては参考記事をみてリポジトリURLを直打ちした。

本稿作成時点では次のようにした（公式の指示をやや変更したもの）：

```bash
cd ~
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/cuda-ubuntu1804.pin
sudo mv cuda-ubuntu1804.pin /etc/apt/preferences.d/cuda-repository-pin-600
sudo apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/7fa2af80.pub
echo "deb https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/ /" | sudo tee /etc/apt/sources.list.d/nvidia-cuda.list
echo "deb https://developer.download.nvidia.com/compute/machine-learning/repos/ubuntu1804/x86_64/ /" | sudo tee /etc/apt/sources.list.d/nvidia-ml.list
```

さらにCUDA 10.0系を優先するPin設定ファイルを作成した [^pin]。
Pin記述については次の記事を参考にした：

- [Debian(Ubuntu)で apt-get upgrade で自動更新したくない場合の対応 | レンタルサーバー・自宅サーバー設定・構築のヒント](https://server-setting.info/debian/debian-no-apt-upgrade.html)
- [apt_preferences(5) — apt — Debian stretch — Debian Manpages](https://manpages.debian.org/stretch/apt/apt_preferences.5.ja.html)

```bash:
sudo vim /etc/apt/preferences.d/cuda-10-0-pin-700
```

```/etc/apt/preferences.d/cuda-10-0-pin-700
Package: cuda
Pin: version 10.0.*
Pin-Priority: 700

Package: libcudnn* libnccl* *libnvinfer* libnvonnxparsers* libnvparsers*
Pin: version *+cuda10.0
Pin-Priority: 700
```

## インストール

次のようにした [^inst]：

```bash
sudo apt update
sudo apt install cuda libcudnn7-dev libnccl-dev libnvinfer-dev
sudo reboot now  # cuda-driversの更新が入った場合は再起動したほうが良い
```

Pin設定をしない場合，CUDA 10.1の最新版が選択され（ただし `cuda` の代わりに `cuda-10-0` を指定すれば回避できる），cuDNN 7.6+cuda10.1 の最新版が選択された。

Pin設定を施すことで，CUDA 10.0の最新版およびcuDNN 7.6+cuda10.0の最新版が選択された。

```bash
sudo apt list --installed cuda "libcudnn*" "libnccl*" "libnvinfer*"
```

```
一覧表示... 完了
cuda/不明,now 10.0.130-1 amd64 [インストール済み]
libcudnn7/不明,now 7.6.4.38-1+cuda10.0 amd64 [インストール済み、自動]
libcudnn7-dev/不明,now 7.6.4.38-1+cuda10.0 amd64 [インストール済み]
libnccl-dev/不明,now 2.4.8-1+cuda10.0 amd64 [インストール済み]
libnccl2/不明,now 2.4.8-1+cuda10.0 amd64 [インストール済み、自動]
libnvinfer-dev/不明,now 6.0.1-1+cuda10.0 amd64 [インストール済み]
libnvinfer6/不明,now 6.0.1-1+cuda10.0 amd64 [インストール済み、自動]
```

試しに手動でダウングレードしてみると，適切に +cuda10.0 へのアップグレードを提示してくれた。

```bash
sudo apt install libcudnn7-dev=7.6.3.30-1+cuda10.0 libcudnn7=7.6.3.30-1+cuda10.0
sudo apt list --upgradable
```

```
一覧表示... 完了
libcudnn7/不明 7.6.4.38-1+cuda10.0 amd64 [7.6.3.30-1+cuda10.0 からアップグレード可]
libcudnn7-dev/不明 7.6.4.38-1+cuda10.0 amd64 [7.6.3.30-1+cuda10.0 からアップグレード可]
```

以上。

## あとがき

以前はバージョン指定インストールと `apt-mark hold` によるバージョン固定を使っていたが，

- マイナーアップデートに追従してくれない
- `apt update` でアップグレード可能の数に計上される
- いちいち `apt upgrade` で保留と表示される
- 手動で更新すると `apt-mark hold` が外れる

という不満があった。
そこで，最近Pin機能の存在を知って，上記の設定を作った。
`tensorflow-gpu` のためのCUDA 10.0の導入として上記のように言及している記事は私の知る限り見かけない。みんなDocker使ってるんだろうか……。

[^cuda]: CUDA 10.1が本来の最新（本稿作成時点）。 `tensorflow-gpu` は少し古いCUDAを要求することが多い。
[^pin]: nvidia-mlのリポジトリに入っているやつはとりあえず引っかかるように含めて記述した。なお最初は `Package: *` でやろうとしたが， `apt update` するとversionの正規表現の解釈に失敗したと言われて動かなかったのでやめた。
[^inst]: CUDAとcuDNNに加え，ついでにNCCLとTensorRTも入れる手順を示した。