Tensorflow2.3を、GeForce 1650、Windows10でソースからコンパイルとXLA有効化

# 概要
TensorflowでXLAを有効にしたくて、ソースからコンパイルする事にした。
1年格闘した。先達の情報をちゃんと読めばよかった。
環境はWindows10、Geforce 1650が1台と1080Tiが1台。

ここでは、TensorFlow r2.3、Python3.7.9、CUDA10.1、cuDNN7.6.5、Visual Studio 2015 の Microsoft Visual C++ 再頒布可能パッケージ、Build Tools for Visual Studio 2015を入れる。
何故か？後で書く。

# tensorflowのアンインストール。

多用するので最初に書く。
トラブルの元になるので、既存のtensorflow環境を壊しても良ければだがアンインストールする。
なお、アンインストールしなくても、バージョンの不整合が発生すると思われる。

```
python -m pip uninstall -y tensorflow tensorflow-cpu tensorflow-gpu tf-models-official tensorflow_datasets tensorflow-hub keras tensorflow-text tensorboard
```


こちらの人が、GPU Pascalで入れてるので、従ってみます。
https://qiita.com/kHz/items/6af115d04628ecc82c43

# 調査

## TensorFlowのバージョンを調べる

早々に見つけていた先達のページなんですが(バージョンアップはしてるかも)、ちゃんと読んでなかった。
https://qiita.com/kHz/items/6af115d04628ecc82c43

所持しているグラフィックカードで、入るCUDA及びTensorFlowのバージョンが異なります。

グラフィックカードのアーキテクチャについては下記がよくまとまっていると思います。
https://qiita.com/k_ikasumipowder/items/1142dadba01b42ac6012

適切なページが見つけられないのだけれども、
https://itips.krsw.biz/tensorflow-gpu-version/
https://tecsingularity.com/cuda/version-2/
https://create-it-myself.com/research/survey-about-cuda-version-for-geforce/

GeForce1080や1650はPascalアーキテクチャ。
ややこしいのですが、
Pascalアーキテクチャが対応するCUDAは10.1まで。

そしてGoogleさんのページも嘘はついていないのだが
https://www.tensorflow.org/install/source_windows?hl=ja
こちらによるとtensorflow_gpu-2.3.0までがCUDA10.1に対応してる事になります。

## Pythonのバージョン

先達のページにも書いてあったのだが見ていなかった。
https://qiita.com/kHz/items/6af115d04628ecc82c43
TensorFlow2.3に対するPythonのバージョンには縛りがあります。
私の環境では、3.7.9でないと動かなかった。3.6系でも3.8系でも通りません。

## CUDAとcuDNNのバージョン

前述のとおり、Pascalアーキテクチャが対応するCUDAは10.1まで。
(11系でも動くは動くのだが、コンパイルが通らなかったり通っても何かと制限がある)

そしてGoogleさんのページも嘘はついていないのだが
https://www.tensorflow.org/install/source_windows?hl=ja

うっかり10.2を入れると動かないんですよ
Googleさんの中の人がだって試してないし10.2対応させる気も無いんだもの、と応えてます。
https://github.com/tensorflow/tensorflow/issues/44622

## Visual Studio

バージョンという程では無いですが、2015。
Microsoft Visual C++ 2015 再頒布可能パッケージ Update3
Microsoft Build Tools 2015 Update 3

先達のページにも書いてあって、
https://qiita.com/kHz/items/6af115d04628ecc82c43

そしてGoogleさんのページは嘘つきで(いや通したのかもしれない)
https://www.tensorflow.org/install/source_windows?hl=ja

nVidiaではVisual Studio 2015にして下さい、と書いてあった、筈なんだが表記が消えている。
https://docs.nvidia.com/deeplearning/cudnn/archives/cudnn_765/cudnn-support-matrix/index.html
10.1の場合、2015が必要と明記してあった。

新しいカード使っている方はこちら。
https://docs.nvidia.com/deeplearning/cudnn/support-matrix/index.html


# インストール

## pythonのインストール

「python-3.7.9-amd64.exe」を「管理者モードで実行」しました。

インストールする時は、初期画面で全てのチェックボックスをチェックしないとはまります。

「Add Python 3.7 to PATH」指定。

「Customize installation」選んでインストールした方が良さそう。

「Install for all users」指定しておいた方が、その後のPathの扱いなどが楽。

「Disable path length limit」表示されたらクリックしてパス長の制限を解除。

Pathに、下記があればOK。

```C:\Program Files\Python37\Scripts\```
```C:\Program Files\Python37\```

なお、もっと新しいPythonを使う事もあるという人の為に、
(例えば私は3.9.10を他の目的で入れている)、
Pathにおいて、使いたいバージョンのPythonを先に持ってきた上で、
IDEなりプロンプトなりを再起動すれば解決します。

バージョン確認。

```
python --version
```

## 番外編、プロキシ環境でのセットアップ

プロキシ認証のせいでこのままだと動かない。どこかファイルに設定する解決法がある筈だが(実際、１台のPCは何もしていない)。
これを打っても出てこなかった。

```
pip config -v list
```

結局わからなかった為に、同じコマンドプロンプトで下記実施。

```
set HTTP_PROXY=http://アカウント:パスワード@プロキシURL:ポート
set HTTPS_PROXY=http://アカウント:パスワード@プロキシURL:ポート
```

ちなみに、set HTTPS_PROXY=http://、についてはhttpsの打ち間違いでは無くてhttpです。

なお、パスワードで記号を使っている場合は、例えば@なら%40などの回避が必要。昨今、パスワードの強度から記号が必須な事が多いが、こういう場合は極めて面倒臭い…。

2-3. Visual Studio系ツールのインストール

先達に従い
https://qiita.com/kHz/items/6af115d04628ecc82c43
・Microsoft Visual C++ 2015 再頒布可能パッケージ Update 3
・Microsoft Build Tools 2015 Update 3
入れます。
両方入れないとうまくいかないらしい。インストール後、再起動した方が無難。

以前は下記の様に書いたが、これはCUDA11系を使う場合の話で、10.1を使う時は無意味。
Visual Studioのダウンロードサイトから以下をダウンロード&インストールする
Visual Studio 2019 の Microsoft Visual C++ 再頒布可能パッケージ
Build Tools for Visual Studio 2019

下記先達によると、
https://qiita.com/TrashBoxx/items/2e884998cd1193f73e2f
「インストールする場合、「C++によるデスクトップ開発」にチェックオプションに「MSVC v142 - VS 2019 C++ x64/x86 ビルドツール」にチェックが入っていることを確認してください。」となってはいますが -> 自分用のメモ。
他、自分の過去メモによると「MSVC v141及びv140も入れた方がいい様です、Pythonが不具合起こす可能性があります」と書いてますが、そもそも2019だと動かないとわかったのが今回ですので…。

## JIT有効化 (たぶんいらない)

要らない気はするのですが、JIT有効化です(XLAでJIT使うので)。英語の場合どうするんだろうか。

次のレジストリ キーに [無効] の [DWORD 値] を [値のデータ] を 1 として追加します。

```HKEY_LOCAL_MACHINE\Software\WOW6432Node\Microsoft\Windows\Windows Error Reporting```

そして、次のレジストリ キーに [自動] の [DWORD 値] を [値のデータ] を 1 として追加します。

```HKEY_LOCAL_MACHINE\Software\WOW6432Node\Microsoft\Windows NT\CurrentVersion\AeDebug```

Visual Studioをインストールしている場合は下記を実施します。
[ツール] > [オプション] > [デバッグ] > [Just-In-Time] で、Just-In-Time デバッグが 有効になっていることを確認します。

## MSYS2インストール

Windowsで基本的なLinuxコマンドを使えるようになる、らしい。
MSYS2の公式サイトからダウンロード&インストールする。

### MSYS2の動作環境を整える。

上手くいかないのでWindowsメニューから「管理者権限」でMSYS2を起動、もしくは「ファイルがあるフォルダ開く」して「管理者権限で起動」した。

### MSYS2のアップデート

MSYS2を管理者権限で起動し、pacmanのパッケージを一括アップグレードする
(-Sy: 最新のパッケージデータベースをダウンロードする）
-Su: インストールしたパッケージをアップグレードする）
以下、全てMSYS2で実行。

```
pacman -Syu
```

MSYS2を再起動して以下のコマンドを実行する （[Y]でインストールを完了）

```
pacman -Su
pacman -Sy git patch unzip zip ed
```

上記をやらないと、最後の方でビルドファイルを作成する時にこける。
特にPythonを再インストールすると顕著。

### MSYS2文字コード設置

MYSYS2の文字コードを変更しておかないと、後でエラーメッセージに苦しむことになる。
端末上で「右クリック」→「Options...」→「Text」の「locale」を「ja_JP」、「Character set」を「SJIS」

### MSYS2パス設定
Windows側のPATHを読み込めるようにする
Windowsの システムのプロパティ＞詳細設定＞環境変数 にて、以下を[新規]で追加する。
変数 

```MSYS2_PATH_TYPE```

値 

```inherit```

同時に下記を実施。

ファイル名を指定して実行（Windowsキー+R）でgpedit.mscを実行して、ローカルグループポリシーエディターを起動。
コンピューターの構成> 管理者用テンプレート> システム> ファイルシステム を選択し、その中にある「Win32の長いパスを有効にする」を「有効」に変更。

Pathに、下記を追加しておく。
C:\msys64にインストールされている場合は、 

```C:\msys64\usr\bin```

## Bazelインストール

下記に従って0.17.2にしようかと思ったのだが、どうもエラーになる。
https://qiita.com/kHz/items/6af115d04628ecc82c43
バージョンを2.0以上にしないと出てくるエラーがあった様な。

私の中ですっかり信用が無くなってるGoogleさんのページだが、そこにはtensorflow_gpu-2.3.0にはバゼル3.1.0だと書いてあった為、試してみる事にして、それで成功した。
https://www.tensorflow.org/install/source_windows?hl=ja
なお、3.7.2だと新しすぎる模様。

bazel.exeをダウンロードするディレクトリを作成し、wgetで取得する。
Bazel 実行可能ファイルの場所を%PATH%環境変数に追加します。
最後の--no-check-certificateは、カスペルスキー入れてるが故に必要だった。

```
cd /c/
mkdir bazel
cd bazel/
wget https://github.com/bazelbuild/bazel/releases/download/3.1.0/bazel-3.1.0-windows-x86_64.exe -O bazel.exe --no-check-certificate
```

## CUDA(NVIDIAグラフィックスドライバ)のインストール -> 要るか要らないかわからない

下記悪影響を及ぼしそうな気もするが、別に何も起きなかった。
NVIDIAグラフィックスドライバ
最新の NVIDIA 公式ドライバーをダウンロード
https://www.nvidia.co.jp
から、セットアップするPCに該当するドライバをダウンロード、インストール。
おそらく再起動を要求される。

## CUDAインストール

前述の通り、自分のグラフィックカードに合わせたバージョンを入れて下さい。
といっても、11.8.0 or 10.1 Update2の2択なんでしょうけど(前者は適当)。

下記より、グラボに合わせたCuda Toolkit 10.1 update2を入れます。
10.2はダメです。下記が理由。ちゃんとtensorflowのページに書いて欲しい。
https://github.com/tensorflow/tensorflow/issues/44622

下記より、CUDAを入手します。
CUDA Toolkit Archive
https://developer.nvidia.com/cuda-toolkit-archive

「Windows」「x86_64」「10」(おそらくWindows10)「exe(local)」選択。

これで、「cuda_10.1.243_426.00_win10.exe」をダウンロードしてきます。

PATH、CUDA_PATHにインストールしたCUDAのフォルダが含まれている事を確認。
PATHにおける場所ですが、どうも先頭の方に有った方が確実な模様(最後に書いていたら失敗した)。
私の場合、最初にPythonのPathを書いて、次にCUDAのPATHを書いている。

```C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\bin```
```C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\libnvvp```

一応、CUDAのインストール確認。

```
nvcc -V
```

## cuDNNのインストール

CUDAのバージョンに対応するcuDNNを落として入れる。
cuDNN Archive
https://developer.nvidia.com/rdp/cudnn-archive

「今でも残ってる」バージョンで、「CUDA10.1」に対応する最新のバージョンの7.6.5を選択します。
(以前はもっと新しいバージョンがあったのだが)

これで、「cudnn-10.1-windows10-x64-v7.6.5.32.zip」をダウンロードしてきます。

ダウンロードした .zip ファイルを解凍し、「cuda」フォルダ下に展開された全フォルダとファイルを、先ほどCUDA ツールキットをインストールしたディレクトリ(C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1)にコピーする。

cuDNNのインストール確認

```
where cudnn64_7.dll
```

## zlibのインストール

nVidiaのページに書いてあるのだが、zlibなるものを入れる必要があるらしい。入れないと、学習など実行時に下記のエラーが出る。

```Could not load library cudnn_cnn_infer64_8.dll. Error code 126```
```Please make sure cudnn_cnn_infer64_8.dll is in your library path!```

対処としては、cuDNNを8.1系にするか8.2系にするか、という対処法もあった模様(今は公開停止で使えない手段)だが、
nVidiaのページにzlib入れろと書いてあるのでそちらを採用。
下記ページの「2.1.3. Installing zlib」に「Download and extract the zlib package from ZLIB DLL.」とあるので、「ZLIB DLL」にカーソルを合わせて、「名前を付けてリンク先を保存」する。
Installation Guide :: NVIDIA Deep Learning cuDNN Documentation
https://docs.nvidia.com/deeplearning/cudnn/install-guide/index.html#install-zlib-windows

zlib123dllx64.zip
がダウンロードされるので、解凍してzlib123dllx64 -> dll_x64 と辿って、下記をパスの通ったディレクトリに入れる。
「zlibwapi.dll」

下記で良いと思います。

```C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.5\bin```

システムの環境変数に下記がある事を確認。なければ作る。

```CUDNN_PATH=C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1```

## deviceQuery.exeのビルド

直接は関係ないが、動作確認の為にdeviceQuery.exeをビルドしておいた方が良い。
「C:\ProgramData\NVIDIA Corporation\CUDA Samples\v10.1\1_Utilities\deviceQuery」
にある、「deviceQuery_vs2019.sln」をVisual Studio 2019 (コミュニティ版で良い)で開き、
「deviceQuery」を右クリック -> ビルド、で、「deviceQuery.exe」が「C:\ProgramData\NVIDIA Corporation\CUDA Samples\v10.1\bin\win64\Debug」に作られる。

## Pythonの各種パッケージインストール

トラブルの元になるので、既存のtensorflow環境を壊しても良ければだがアンインストールする。
なお、アンインストールしなくても、バージョンの不整合が発生すると思われる。

```
python -m pip uninstall -y tensorflow tensorflow-cpu tensorflow-gpu tf-models-official tensorflow_datasets tensorflow-hub keras tensorflow-text tensorboard
```

pipでインストールする、ただしpipのアップデートの必要性は不明。

```
pip install --upgrade pip==20.3.3
```

```
pip install six
```

numpyについては
https://maxigundan.com/deeplearning/2020/07/%E3%80%90tf2%E3%80%91bazel%E3%83%93%E3%83%AB%E3%83%89-bfloat16-cc635-error-c2664-pyufuncgenericfunction-%E3%81%B8%E5%A4%89%E6%8F%9B%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%9B%E3%82%93/
見て(半日で解決するとか凄いです…私1年がかり…)
https://github.com/tensorflow/tensorflow/issues/40688
に載ってるそうです。
稀に、Tensorflowをビルドする段になって勝手にバージョンアップされて不具合を起こすことがある為、
ビルド前に再確認した方が良さそう。

```
pip install numpy==1.18
```

なおwheelは入れておかないと、最後にビルドしたtensorflowをpipで入れられなくなる。

```
pip install wheel mock setuptools pandas  seaborn scikit-learn scikit-learn-intelex packaging
```

Kerasについてはデフォルトで最新バージョンを入れて不具合を起こす為、指定する。
もしかすると、2.3.1かも知れない。私の場合、GeForce1650では2.4で無いと不具合を起こし、GeForce1080Tiでは2.3.1でないと不具合を起こした。
https://qiita.com/Hiroki-Fujimoto/items/8afacc9609c34a2d6c56

GeForce1650の場合

```
pip install keras==2.3.1
```

GeForce1080Tiの場合

```
pip install keras==2.4
```

keras_applicationsとkeras_preprocessingもバージョン指定する必要性があったと思われるが失念。

```
pip install keras_applications==1.0.8 --no-deps
pip install keras_preprocessing==1.1.0 --no-deps
```

他に、過去に下記を実施している。

```
python -m pip install -U matlablib
python -m pip install scipy
python -m pip install -U opencv-python opencv-contrib-python
python -m pip install opencv-python

pip install pillow
pip install lxml
pip install Cython
pip install jupyter
pip install matplotlib
pip install pandas
pip install opencv-python
```

# コンパイル及びビルド

## 事前準備

### Bazelのパスを通す。

bashだからですね。

```
export PATH=/c/bazel:$PATH
```

### MSYS2またはコマンドプロンプトの環境変数設定について。

設定しない。
過去には下記を設定したが、かえって悪さをする模様。
正確には、BAZELのバージョンによって、書式は異なるが、それはBAZELのページに記載があり、
それ以前にこのあたりを設定したら不具合を起こした。
下記については過去の経緯を残すためにだけ記載。
ここから過去のメモ。

---------------
Progra~2にした理由は、どうもProgram Files (x86)の記載が悪さしている疑いがあったから。MIB055~1はMicrosoft Visual Studioの略です。NVIDIA~2はNVIDIA GPU Computing Toolkitの略です。

下記コマンドで、8.3形式のフォルダ名は調査可能。
dir /x

Windows SDKのバージョンを調べる方法。
https://oneuro.net/where-is-windows-sdk-version

set BAZEL_VS=C:\Progra~2\MICROS~1.0
set BAZEL_VC=C:\Progra~2\MICROS~1.0VC
set BAZEL_VC_FULL_VERSION="16.11.23"
set BAZEL_WINSDK_FULL_VERSION="10.0.22621.0"

export PATH=C:\Progra~1\NVIDIA~2\CUDA\v10.1\bin:$PATH
export PATH=C:\Progra~1\NVIDIA~2\CUDA\v10.1\extras\CUPTI\lib64:$PATH
export PATH=C:\Progra~1\NVIDIA~2\CUDA\v10.1\include:$PATH
export XLA_BUILD=true
export XLA_TARGET=cuda

export BAZEL_VS=C:\Progra~2\MICROS~1.0
export BAZEL_VC=C:\Progra~2\MICROS~1.0VC

ここまで過去のメモ。

-------

### Windowsの設定。
設定 - 更新とセキュリティ - 開発者モード をオンにする

## Tensorflowのソース準備

### TensorFlowのGitリポジトリを取得する

```
cd /c/
git clone https://github.com/tensorflow/tensorflow.git
cd tensorflow/
```

### チェックアウト

チェックアウト。なお、r2.3の「r」をつけ忘れると見つからない。

```
git checkout r2.3
```

## コンフィグ

### 入力コマンドと、少し解説。

```
python configure.py
```

特にエラーが出なかった場合は、いくつか質問されるのでYやNなどを入力していく。
なのだが、ここで注意ではないが特記事項。
私の場合、XLAを有効化したくて実行しているのだが、何故か質問でその項目が出てこない。
何故か悩んだのだが、Tensorflow1系の場合はその項目は出てくるのだが、TensorFlow2系ではその項目は出てこない、らしい。

### 各項目について

Please specify the location of python. [Default is C:\Program Files\Python39\python.exe]:

どうも「Program Files」の指定が悪さするので、「Progra~1」にして下記入力。

```C:\Progra~1\Python37\python.exe```

Found possible Python library paths: C:\Program Files\Python37\lib\site-packages
Please input the desired Python library path to use. Default is [C:\Program Files\Python37\lib\site-packages\

同上。

```C:\Progra~1\Python37\lib\site-packages```

Do you wissh to build TensorFlow with ROCm support？

CUDAをYにするならここは絶対にN。

```N```

Do you wieh to build TensorFlow with CUDA support？
CUDA使いたいのでY。

```Y```

Please note that each additioinal compute capability signigficantly increases your buid time and binari size, and that TensoFlow only supports compute capabilities >= 3.5
下記を見て決める。
CUDA GPUs
https://developer.nvidia.com/cuda-gpus

GeForce 1080Tiなら6.1。1650なら7.5。ただし自動判別されてる模様で何故この項目があるのかわからない。

GeForce1650

```3.5,7.5```

GeForce1080Ti

```3.5,6.1```

Please specify optimization flags to use during compilation when bazel option "--config=opt" is specified [Default is /arch:AVX]:
ここでおそらくtensorflow v2を指定するのだと思う。

```/arch:AVX```

Woud you like to override eigen storong inline for some C++ compilatoin to reduce the complaton time？
よくわからないがY

```Y```

Would you like to nteractively configure ./WORKSPACE for Android builds？
Android使わないのでN

```N```

## ビルドファイル生成

BazelでTensorFlowビルドファイルを生成する

### ディレクトリ移動

whlファイルを生成するディレクトリを作成した後、ビルドするディレクトリに移動する

```
cd /c/
mkdir tmp
cd /c/tensorflow/
```

### ビルドファイル生成前のビルド

一度、bazel cleanした方がいいかもしれない。
なお、何度か失敗した場合は確実にbazel cleanが効く。

```
bazel clean
```

オプションの類は、下記から持ってきた。
Windowsでのソースからのビルド | TensorFlow
https://tensorflow.google.cn/install/source_windows?hl=ja


C:\tensorflow\tensorflow\python\lib\core\bfloat16.cc
の改行に疑問が残るところを修正したが、意味があったか不明。

ビルドコマンド。最終的に、Googleのページを採用。CUDAに関して二重指定だよとエラーが出る。

```
bazel build --config=opt --config=cuda --define=no_tensorflow_py_deps=true //tensorflow/tools/pip_package:build_pip_package
```

## パッケージ作成

ビルドを実行する。

長時間かかると聞いていたがそんなに掛からなかった。20分程度。何か間違えたか？

```
bash bazel-bin/tensorflow/tools/pip_package/build_pip_package /c/tmp/tensorflow_pkg
```

## ビルドファイル、すなわちtensorflowインストール

```
cd /c/tmp/tensorflow_pkg
pip install tensorflow-2.3.4-cp37-cp37m-win_amd64.whl
```

## 確認

```
python -c "import tensorflow as tf; print( tf.__version__ )"
python -c "from tensorflow.python.client import device_lib; print(device_lib.list_local_devices())"
```

無事、ここでXLA_GPUとXLA_CPUが表示されました。