複数のconda仮想環境に異なるバージョンのTensorFlowをインストールする

Tensorflowをインストールする系の記事は大量にあるので現状の個人的ベストプラクティスのメモ
結論だけ見たい人は下の[まとめ](#まとめ)まで飛んでください。
以下の思想を持つ人には役立つと思います。

## こんな人向け

### GPU対応したTensorflowを動かしたい

TendorFlowでGPUを使うにはNvidia Driverの他に対応したバージョンのCUDAとCuDNNも入れないといけない。
一つ一つインストール方法を確認するのが面倒な人。パスを通したりして環境をごちゃごちゃさせたくない人。

### 複数のバージョンのTensorflowを使いたい

CUDAとCuDNNをインストールする際、OSに直インストールしたり環境変数を設定してしまうと異なるバージョンのTensorflowへの切り替えが面倒なので、CUDAとCuDNN自体を仮想環境毎にインストールしたいという人。
開発は最新バージョンで行うが、他の人が昔書いたレガシーコードの動作確認も行うような人。

### Windowsにインストールしたい

Tensorflowは公式のDockerコンテナが提供されているのでそれを使えば上記はすべて解決する。
しかし、WindowsでDockerを使うことが問題で、Windowsの仕様とLinuxカーネルの仕様の相違から[WSL2がメモリを食いつぶす](https://github.com/microsoft/WSL/issues/4166)バグが存在し当面解決する様子もない。こういった問題からDockerを使いたくない人。
Dockerについて学びたくない人やとにかくローカル志向の人。

### Anaconda.orgのdefaultsチャンネルを使いたくない

Anacondaの営利使用有料化などの影響でdefaultsチャネルを使用したくない人も一定数いるはず。
defaults(anaconda)チャンネルではTensorflowのGPU対応版含む各ディストリビューションが提供されているが、conda-forgeではWindows版においてTensorflowのバージョン2以降が提供されていない。
Windowsでanacondaを使わずに最新のバージョンのTensorflowをインストールするには（自前でビルドしない限り）pipを使うしかない。
~~pytorchみたいに固有チャネル作って提供してほしい~~

## conda 仮想環境とパッケージ管理

Tensorflowは `pip` で入れるしかないのですが、仮想環境やCUDAなどのインストールは `conda` で行います。
`pip` と `conda` で環境が混ざって～という話はよく聞きますが、 `conda` でPythonの最低限の環境を構築してそれ以外のpythonパッケージを `pip` で管理するようにすれば大丈夫です。

Pythonを使っている人が誤解しがちだと思うのですが
`conda` は **Pythoのパッケージを管理するツールではありません** 。
`conda` はPythonで作られていてPythonも同時にインストールされる、かつPythonパッケージのほとんどが `conda` によって管理できることや、（国内外含め）ネット記事のほとんどがそのように記載してしまっているためそう思われがちですが、実際には `conda` は **仮想環境とAnaconda.orgコミュニティのリポジトリが提供するパッケージを管理するツール** です。

Pythonに限らず `conda` が参照するリポジトリにパッケージが存在していれば各プログラミング言語やツール、ソフトウェアをインストールすることができます。

<details><summary>Pythonのない仮想環境を作ることもできます</summary><div>

例えば、LLVM-Clangなら以下のようにすることで環境作成、インストールができ、 `conda` で管理できます。

```powershell
$ conda create -n test -c conda-forge clangdev
Collecting package metadata (current_repodata.json): ...working... done
Solving environment: ...working... done

## Package Plan ##

  environment location: ~\conda\envs\test

  added / updated specs:
    - clangdev


The following packages will be downloaded:

    package                    |            build
    ---------------------------|-----------------
    clang-15.0.4               |       h8e541a6_0       101.5 MB  conda-forge
    clang-15-15.0.4            |default_h66ee7f4_0        34.5 MB  conda-forge
    clang-format-15.0.4        |default_h66ee7f4_0         1.3 MB  conda-forge
    clang-tools-15.0.4         |default_h66ee7f4_0       245.7 MB  conda-forge
    clangdev-15.0.4            |default_h66ee7f4_0        70.2 MB  conda-forge
    clangxx-15.0.4             |default_h66ee7f4_0        33.9 MB  conda-forge
    libclang-15.0.4            |default_h77d9078_0         144 KB  conda-forge
    libclang-cpp-15.0.4        |default_hf9e4a47_0         127 KB  conda-forge
    libclang13-15.0.4          |default_h77d9078_0        25.9 MB  conda-forge
    libiconv-1.17              |       h8ffe710_0         698 KB  conda-forge
    libllvm15-15.0.4           |       h2c25772_1          52 KB  conda-forge
    libxml2-2.10.3             |       hc3477c8_0         3.6 MB  conda-forge
    libzlib-1.2.13             |       hcfcfb64_4          70 KB  conda-forge
    llvm-tools-15.0.4          |       h2c25772_1       388.7 MB  conda-forge
    llvmdev-15.0.4             |       h2c25772_1       117.7 MB  conda-forge
    ucrt-10.0.22621.0          |       h57928b3_0         1.2 MB  conda-forge
    vc-14.3                    |       h3d8a991_9          14 KB  conda-forge
    vs2015_runtime-14.32.31332 |       h1d6e394_9         1.2 MB  conda-forge
    zstd-1.5.2                 |       h7755175_4         401 KB  conda-forge
    ------------------------------------------------------------
                                           Total:        1.00 GB

The following NEW packages will be INSTALLED:

  clang              conda-forge/win-64::clang-15.0.4-h8e541a6_0 None
  clang-15           conda-forge/win-64::clang-15-15.0.4-default_h66ee7f4_0 None
  clang-format       conda-forge/win-64::clang-format-15.0.4-default_h66ee7f4_0 None
  clang-tools        conda-forge/win-64::clang-tools-15.0.4-default_h66ee7f4_0 None
  clangdev           conda-forge/win-64::clangdev-15.0.4-default_h66ee7f4_0 None
  clangxx            conda-forge/win-64::clangxx-15.0.4-default_h66ee7f4_0 None
  libclang           conda-forge/win-64::libclang-15.0.4-default_h77d9078_0 None
  libclang-cpp       conda-forge/win-64::libclang-cpp-15.0.4-default_hf9e4a47_0 None
  libclang13         conda-forge/win-64::libclang13-15.0.4-default_h77d9078_0 None
  libiconv           conda-forge/win-64::libiconv-1.17-h8ffe710_0 None
  libllvm15          conda-forge/win-64::libllvm15-15.0.4-h2c25772_1 None
  libxml2            conda-forge/win-64::libxml2-2.10.3-hc3477c8_0 None
  libzlib            conda-forge/win-64::libzlib-1.2.13-hcfcfb64_4 None
  llvm-tools         conda-forge/win-64::llvm-tools-15.0.4-h2c25772_1 None
  llvmdev            conda-forge/win-64::llvmdev-15.0.4-h2c25772_1 None
  ucrt               conda-forge/win-64::ucrt-10.0.22621.0-h57928b3_0 None
  vc                 conda-forge/win-64::vc-14.3-h3d8a991_9 None
  vs2015_runtime     conda-forge/win-64::vs2015_runtime-14.32.31332-h1d6e394_9 None
  zstd               conda-forge/win-64::zstd-1.5.2-h7755175_4 None


Proceed ([y]/n)? 
```

</div></details>

Anacondaのインストール後にはパスを通す方も多いと思いますが他の仮想環境からbase環境のpythonなどが参照されてしまう可能性があるため `conda` をフル活用するなら気を付けたほうが良いです。

## CUDAとCuDNNのインストール

`conda` でCUDAとCuDNNをインストールしようとするとどうなるのか見てみましょう。

```powershell
$ conda create -n test -c conda-forge cudnn=8.1
Collecting package metadata (current_repodata.json): ...working... done
Solving environment: ...working... failed with repodata from current_repodata.json, will retry with next repodata source.
Collecting package metadata (repodata.json): ...working... done
Solving environment: ...working... done

## Package Plan ##

  environment location: ~\envs\conda\envs\test

  added / updated specs:
    - cudnn=8.1


The following packages will be downloaded:

    package                    |            build
    ---------------------------|-----------------
    cudatoolkit-11.7.0         |      ha6f8bbd_10       965.6 MB  conda-forge
    cudnn-8.1.0.77             |       h3e0f4f4_0       610.8 MB  conda-forge
    ucrt-10.0.22621.0          |       h57928b3_0         1.2 MB  conda-forge
    vc-14.3                    |       h3d8a991_9          14 KB  conda-forge
    vs2015_runtime-14.32.31332 |       h1d6e394_9         1.2 MB  conda-forge
    ------------------------------------------------------------
                                           Total:        1.54 GB

The following NEW packages will be INSTALLED:

  cudatoolkit        conda-forge/win-64::cudatoolkit-11.7.0-ha6f8bbd_10 None
  cudnn              conda-forge/win-64::cudnn-8.1.0.77-h3e0f4f4_0 None
  ucrt               conda-forge/win-64::ucrt-10.0.22621.0-h57928b3_0 None
  vc                 conda-forge/win-64::vc-14.3-h3d8a991_9 None
  vs2015_runtime     conda-forge/win-64::vs2015_runtime-14.32.31332-h1d6e394_9 None


Proceed ([y]/n)?
```

一緒にインストールされる `cudatoolkit` がCUDA、 `vc` はVC++ Build Tool、 `vs2015_runtime` はVC++再頒布パッケージです。
CUDAのバージョンもこだわりたいなら `cudatoolkit=11.2` も併せて指定しましょう。
また、Pythonとの依存関係がないこともわかるので、もし実際に使ってみてバージョンが合わなかったら `conda install cudnn=8.2 cudatoolkit=11.7` のようにコマンドを実行することで容易にバージョンを変えることができます。

## Pythonのインストール

Pythonも `conda` でインストールします。
一応 [PyPIのTensorflowのページ](https://pypi.org/project/tensorflow/)を確認して対応するPythonのバージョンを確認しましょう。

```powershell
$ conda create -n test -c conda-forge python=3.10
Collecting package metadata (current_repodata.json): ...working... done
Solving environment: ...working... done

## Package Plan ##

  environment location: ~\conda\envs\test

  added / updated specs:
    - python=3.10


The following packages will be downloaded:

    package                    |            build
    ---------------------------|-----------------
    bzip2-1.0.8                |       h8ffe710_4         149 KB  conda-forge
    ca-certificates-2022.9.24  |       h5b45459_0         189 KB  conda-forge
    libffi-3.4.2               |       h8ffe710_5          41 KB  conda-forge
    libsqlite-3.39.4           |       hcfcfb64_0         642 KB  conda-forge
    libzlib-1.2.13             |       hcfcfb64_4          70 KB  conda-forge
    openssl-3.0.7              |       hcfcfb64_0         7.9 MB  conda-forge
    pip-22.3.1                 |     pyhd8ed1ab_0         1.5 MB  conda-forge
    python-3.10.6              |hcf16a7b_0_cpython        16.5 MB  conda-forge
    setuptools-65.5.1          |     pyhd8ed1ab_0         731 KB  conda-forge
    tk-8.6.12                  |       h8ffe710_0         3.5 MB  conda-forge
    tzdata-2022f               |       h191b570_0         118 KB  conda-forge
    ucrt-10.0.22621.0          |       h57928b3_0         1.2 MB  conda-forge
    vc-14.3                    |       h3d8a991_9          14 KB  conda-forge
    vs2015_runtime-14.32.31332 |       h1d6e394_9         1.2 MB  conda-forge
    wheel-0.38.4               |     pyhd8ed1ab_0          32 KB  conda-forge
    xz-5.2.6                   |       h8d14728_0         213 KB  conda-forge
    ------------------------------------------------------------
                                           Total:        34.0 MB

The following NEW packages will be INSTALLED:

  bzip2              conda-forge/win-64::bzip2-1.0.8-h8ffe710_4 None
  ca-certificates    conda-forge/win-64::ca-certificates-2022.9.24-h5b45459_0 None
  libffi             conda-forge/win-64::libffi-3.4.2-h8ffe710_5 None
  libsqlite          conda-forge/win-64::libsqlite-3.39.4-hcfcfb64_0 None
  libzlib            conda-forge/win-64::libzlib-1.2.13-hcfcfb64_4 None
  openssl            conda-forge/win-64::openssl-3.0.7-hcfcfb64_0 None
  pip                conda-forge/noarch::pip-22.3.1-pyhd8ed1ab_0 None
  python             conda-forge/win-64::python-3.10.6-hcf16a7b_0_cpython None
  setuptools         conda-forge/noarch::setuptools-65.5.1-pyhd8ed1ab_0 None
  tk                 conda-forge/win-64::tk-8.6.12-h8ffe710_0 None
  tzdata             conda-forge/noarch::tzdata-2022f-h191b570_0 None
  ucrt               conda-forge/win-64::ucrt-10.0.22621.0-h57928b3_0 None
  vc                 conda-forge/win-64::vc-14.3-h3d8a991_9 None
  vs2015_runtime     conda-forge/win-64::vs2015_runtime-14.32.31332-h1d6e394_9 None
  wheel              conda-forge/noarch::wheel-0.38.4-pyhd8ed1ab_0 None
  xz                 conda-forge/win-64::xz-5.2.6-h8d14728_0 None


Proceed ([y]/n)?
```

いくつかのライブラリとPython、pip、setuptools、wheelがインストールされることがわかります。
一部被っているパッケージがあるので、仮想環境の作成時はPythonとCuDNNのバージョン指定は同時に入れたほうが良いかもしれませんね。

## Tensorflowのインストール

あとは、 `pip` でTensorFlowをインストールするだけです。

```powershell
(base) $ conda activate test
(test) $ pip install tensorflow=2.10
```

TensorflowはCUDAとCuDNNが見つかれば自動でGPUを使うようになっています。
`conda` でCUDAとCuDNNをインストールし、その環境の中にTensorflowをインストールすれば環境変数などを設定しなくてもGPUが認識されるようになっています。



# まとめ

* [Miniforge](https://github.com/conda-forge/miniforge/releases)をインストール
* `conda create -n tf_xxx -c conda-forge cudnn=8.x python=3.xx`
* `conda activate tf_xxx`
* `pip install tensorflow=2.x`

または

```yaml: pip-tensorflow.yaml
name: tf_210
channels:
  - conda-forge
dependencies:
  - cudatoolkit=11.2
  - cudnn=8.1
  - python=3.10
  - pip
  - pip:
    - tensorflow=2.10
```

<details><summary></summary><div>

```yaml: pip-tensorflow-2-9.yaml
name: tf_209
channels:
  - conda-forge
dependencies:
  - cudatoolkit=11.2
  - cudnn=8.1
  - python=3.10
  - pip
  - pip:
    - tensorflow=2.9
```

```yaml: pip-tensorflow-2-8.yaml
name: tf_208
channels:
  - conda-forge
dependencies:
  - cudatoolkit=11.2
  - cudnn=8.1
  - python=3.10
  - pip
  - pip:
    - tensorflow=2.8
```

```yaml: pip-tensorflow-2-7.yaml
name: tf_209
channels:
  - conda-forge
dependencies:
  - cudatoolkit=11.2
  - cudnn=8.1
  - python=3.9
  - pip
  - pip:
    - tensorflow=2.7
```

```yaml: pip-tensorflow-2-6.yaml
name: tf_206
channels:
  - conda-forge
dependencies:
  - cudatoolkit=11.2
  - cudnn=8.1
  - python=3.9
  - pip
  - pip:
    - tensorflow=2.6
```

```yaml: pip-tensorflow-2-5.yaml
name: tf_205
channels:
  - conda-forge
dependencies:
  - cudatoolkit=11.2
  - cudnn=8.1
  - python=3.9
  - pip
  - pip:
    - tensorflow=2.5
```

```yaml: pip-tensorflow-2-4.yaml
name: tf_204
channels:
  - conda-forge
dependencies:
  - cudatoolkit=11.0
  - cudnn=8.0
  - python=3.8
  - pip
  - pip:
    - tensorflow=2.4
```

```yaml: pip-tensorflow-2-3.yaml
name: tf_203
channels:
  - conda-forge
dependencies:
  - cudatoolkit=10.1
  - cudnn=7.6
  - python=3.8
  - pip
  - pip:
    - tensorflow=2.3
```

```yaml: pip-tensorflow-2-2.yaml
name: tf_202
channels:
  - conda-forge
dependencies:
  - cudatoolkit=10.1
  - cudnn=7.6
  - python=3.8
  - pip
  - pip:
    - tensorflow=2.2
```

```yaml: pip-tensorflow-2-1.yaml
name: tf_201
channels:
  - conda-forge
dependencies:
  - cudatoolkit=10.1
  - cudnn=7.6
  - python=3.7
  - pip
  - pip:
    - tensorflow=2.1
```

```yaml: pip-tensorflow-2-0.yaml
name: tf_200
channels:
  - conda-forge
dependencies:
  - cudatoolkit=10.0
  - cudnn=7.4
  - python=3.7
  - pip
  - pip:
    - tensorflow=2.0
```

</div></details>

***

TensorFowの日本語インストールガイドページの更新がVer.2.6以降止まっているのってどうしてなんでしょうね？
と思っていたら、書き終えてから気付いたのですが[英語版ページ](https://www.tensorflow.org/install/pip?hl=en#windows-native)だと普通にcondaでcudnn入れてpipでtensorflow入れてました...
Tensorflow公式としては「WindowsでTensorflow使うときはWSL2使ってね❤️」という方針ぽい
日本語翻訳に個人的所感を入れただけの記事になってしまった...