PyTorchのビルド方法とビルド時間

# 1. はじめに
PyTorchで、Pythonのパッケージは、condaでインストールする場合が多い。しかし、今回は、pipベースでやってみた。また、Google Colabでも出来るのでそちらについても記載する。

# 2. パッケージの準備手順
コンパイルに使ったOSは、Ubuntu Server LTS 18.04もしくは16.04 (HVM) (EC2)である。PyTorch 1.0.0以降は、Ubuntu Server 18.04を使っている。さらに、PyTorch 1.5.0以降では、Ubuntu 20.04(x86_64/aarch64)を使っている。なお、18.04の場合、clock_gettimeのRelinkの問題があり動かない。しかし、USE_MKLDNNをdisableとすると動く。

## 2.1. CUDAライブラリの設定
CUDAライブラリのインストールは以下の通りである。なお、CUDAライブラリが不要な場合、スキップしてよい。なお、GPUが無いインスタンスでもCUDAインストールはできる。はじめのファイルは、NVIDIAのサイトから持ってくる。
また、CUDAを使う場合は、/tmpディレクトリを結構消費するので/ディレクトリのサイズを20GB程度にする必要がある。

```
sudo dpkg -i cuda-repo-ubuntu1604_9.2.148-1_amd64.deb
sudo apt-key adv --fetch-keys http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1604/x86_64/7fa2af80.pub
sudo apt-get update
sudo apt-get install cuda
sudo apt clean cache
sudo reboot
```
## 2.2. PyTorchのコンパイル環境の設定
PyTorchのコンパイル環境の設定は、以下の手順である。

```
sudo apt update
sudo apt -y upgrade
sudo apt install -y python3 python3-pip cmake
sudo pip3 install -y pyyaml numpy ninja
git clone --branch v1.5.0 --recursive http://github.com/pytorch/pytorch
```

# 3. コンパイル手順
コンパイル時、developオプションは、パッケージインストールに相当する。このため、パッケージ管理者と同等以上の権限があることが必要である。

```shell-session
cd pytorch
sudo python3 setup.py build develop
```
なお、CUDA有り無しの設定は、以下のフラグで行える。CUDAなしの場合、NO_CUDA=1と環境変数を設定する。コンパイル時のsetup.py内の変数であるUSE_CUDAのフラグが変更される。

```shell-session
export NO_CUDA=1
```
# 4. 使い方
以下の手順で打つと、PyTorchのバージョンが表示され、動作していることが確認できる。

```shell-session
python3
import torch
print(torch.__version__)
```
# 5. 時間計測
## 5.1. ソースコード取得
(AWS)git clone --recursive http://github.com/pytorch/pytorch

```
real    1m48.895s
user    0m57.228s
sys     0m9.684s
```
## 5.2. コンパイル
CPU数に比例してコンパイルは早くなる。なお、xlargeは、4CPUに相当する。また、CUDAつきは意外と(6倍ぐらい)時間がかかる。そして、0.4.1(2018/7)から1.0.0(2018/12)と版数が上がって、コンパイル時間も2倍近くに延びた。また、この傾向は続いており、1.0.1でも2割程度コンパイル時間が増えている(以下参照)
また、Google Colabでも、コンパイルできなくは無いが、CPUが2つであり実用的ではない。(CUDAなし)CPUパッケージのみでも80分近い(v1.0.0の場合)。
(コード変更後の)コンパイル時間を減らす方法としては、CONTRIBUTING.mdの[C++ Development tips](https://github.com/pytorch/pytorch/blob/master/CONTRIBUTING.md#c-development-tips)に書いてある方法がある。



|  instance    |version| CUDA|       real |    user   | sys |
|-------------:|------:|-----:|-------------:|------------:|--------:|
|(AWS)m5.xlarge |1.5.0a0+4ff3872 |×|86m36.689s|330m37.679s|12m32.014s|
|(AWS)m5.xlarge (clang)|1.5.0a0+4ff3872 |×|74m20.672s|286m26.484s|7m46.189s|
|(AWS)m6g.xlarge (clang)|1.5.0a0+4ff3872 |×|45m12.303s|174m48.702s|4m50.739s|
|||||||
|RaspberryPi4 |1.4.0a+22d8420 |×|281m58.694s|989m13.868s|48m34.519s|
|||||||
|(AWS)c3.8xlarge |1.3.0 |×|18m32.284s|429m31.298s|23m27.600s|
|||||||
|(AWS)c3.8xlarge |1.2.0 |×|11m24.062s|312m9.666s|16m26.919s|
|||||||
|(AWS)c3.8xlarge |1.1.0 |×|10m36.077s|282m10.403s|15m46.345s|
|(AWS)c3.4xlarge |1.1.0 |×|17m36.077s|254m32.921s|10m23.539s|
|(AWS)c3.4xlarge |1.1.0 |10.1|96m10.510s|1368m20.159s|73m17.280s|
|||||||
|(AWS)c3.4xlarge |1.0.1 |×|13m16.78s|186m49.56s|8m11.42s|
|(AWS)c3.8xlarge |1.0.1 |×|7m16.62s|182m44.44s|10m7.27s|
|||||||
|(AWS)c3.2xlarge |1.0.0 |×|22m8.15s|159m7.45s|8m7.67s|
|(AWS)c3.4xlarge |1.0.0 |×|11m22.72s|155m56.04s|8m23.67s|
|(AWS)c3.2xlarge |1.0.0 |10.0|108m37s|865m1.99s|41m18.91s|
|||||||
|(AWS)r3.xlarge |0.4.1 |×|15m40.01s|48m30.30s|2m1.08s|
|(AWS)c3.2xlarge |0.4.1 |×|10m8.773s|45m21.864s|2m3.844s|
|(AWS)z1d.xlarge |0.4.1 |×|10m22.22s|27m41.46s|1m13.17s|
|(AWS)c4.4xlarge |0.4.1 |×|6m25.989s|34m12.720s|1m32.732s|
|(AWS)c3.2xlarge |0.4.1 |9.2|63m2.087s|417m40.824s|17m33.224s|

1.2.0は、1.2.0a0+8554416

m6gは、Ubuntu 20.04 (aarch64)


# 6. その他のノウハウ
## 6.1. Google Colabでコンパイルから実行まで

コンパイルは、以下の手順で行う。

```
!pip3 install ninja
!git clone -b v1.0.0 --recursive http://github.com/pytorch/pytorch
!cd pytorch; export NO_CUDA=1;python3 setup.py build develop
```

実行は、以下の通りにすると実行できる。

```
!cd pytorch/test; python3 run_test.py
```

## 6.2. ソースコードだけ生成したいとき

以下のコードを実行すると、40秒程度でソースコードが生成される。ただし、Pythonコマンドが動くことが必須である。このため、python3を使っている場合は、pythonへのシンボリックリンクを張るか、スクリプトファイルをpythonからpython3へ編集する作業が必要である。

```bash
bash docs/cpp/source/check-doxygen.sh
```

## 6.3. Debugフラグをつけたい時
環境変数で、DEBUG=1とすると、torch部分がDebugモードになる。
それ以外に、cmake配下のcaffe2等のライブラリに対して、Debug追加したい場合、環境変数CFLAGSに設定する。

```
export DEBUG=1
export CFLAGS="-g -O0"
```
言うまでも無いが、gdbでデバッグ使用する場合、Docker等ではPTRACE等がデフォルトでは使えないので、設定変更が必要である。

## 6.4. torch/docsのビルド
Google Colabだと、以下のようにやってビルドできる

```
!git clone http://github.com/pytorch/pytorch
!cd pytorch/docs;pip3 install -r requirements.txt
!pip install -U sphinx
!pip3 install pytorch_sphinx_theme
!cd pytorch/docs; make html
```
なお、Webサーバとしては、pythonの標準サーバで動かせる。ただし、ngrokを使った場合、(無料版では)コネクション数の制限で、1ページ目しか表示できない。

```
!wget https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip
!unzip ngrok-stable-linux-amd64.zip

get_ipython().system_raw('./ngrok http 6006 &')
! curl -s http://localhost:4040/api/tunnels | python3 -c \
    "import sys, json; print(json.load(sys.stdin)['tunnels'][0]['public_url'])"
```
サーバ立ち上げ

```
!cd pytorch/docs/build/html;python -m  http.server 6006
```
なお、Sphnixを使っている。この為、ファイルの変更等では、pytorch/docs/source以下のrstファイルの編集等が必要になる。

+ [sphinx.ext.autodoc – Include documentation from docstrings](http://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html#module-sphinx.ext.autodoc)


## 6.5. tutorialsのビルド
tutorialsをGoogle Colabでビルドの際、以下のインストールが必要である。

- pytorch-sphinx-themes等のインストール
- sphinxがPython2になっているので、それをPython3用への更新が必要である。
- torchaudioは、pipでインストールすると別パッケージがインストールされる。gitでの処理が必須。
- マルチGPUやAWS対応のチュートリアルがあるのでそれを除去

また、サンプルコードが実際に動くので処理時間もかかる。(K80　8972.146秒) 

```
!git clone http://github.com/pytorch/tutorials
!cd tutorials;pip install -r requirements.txt
!pip install -U sphinx
!git clone http://github.com/pytorch/audio
!apt install libsox-dev
!cd audio;python3 setup.py install
!cd tutorials; mv beginner_source/aws_distributed_training_tutorial.py .
!cd tutorials; mv intermediate_source/model_parallel_tutorial.py .
!cd tutorials;make docs
```
なお、tutorialファイルは、[tutorials/advanced_source/](https://github.com/pytorch/tutorials/tree/master/advanced_source)等で、.py拡張子で作成する。.rstで作成した場合、Jupyter Notebookが作成されずWebページのみになる。

## 6.6. テストコマンド
指定したテストセットを動かすコマンドは以下の通りである。

```
!python3 pytorch/test/test_nn.py TestNN.test_affine_grid
```
## 6.7. パッケージ化
バイナリパッケージを作成する場合、dist以下にパッケージが作成される。(バイナリパッケージとソースコードのまとめを示す。)なお、wheel自体は、zipアーカイブなので、簡単に展開してチェックできる。

```
!python3 setup.py bdist_wheel
```

```
!python3 setup.py sdist
```

# A. 参考資料
- PyTorchコミュニティ
   - [Get Started.](https://pytorch.org/) (インストール方法など　conda/pip/ソースコードから)
   - [From Source](https://github.com/pytorch/pytorch/blob/master/README.md#from-source) (ソースコードのコンパイル)
   - [Contributing to PyTorch](https://github.com/pytorch/pytorch/blob/v0.4.1/CONTRIBUTING.md)　(ソースコードのコンパイル等)
   - [pytorch builder](https://github.com/pytorch/builder) (テスト環境の構築)
- [CUDA Toolkit 9.2 Download](https://developer.nvidia.com/cuda-downloads?target_os=Linux&target_arch=x86_64&target_distro=Ubuntu&target_version=1604&target_type=debnetwork)　(CUDA環境の設定)
- Python
  - [Generating distribution archives](https://packaging.python.org/tutorials/packaging-projects/#generating-distribution-archives)
  - [4. ソースコード配布物を作成する](https://docs.python.org/ja/3/distutils/sourcedist.html)
  - [PEP 427 -- The Wheel Binary Package Format 1.0](https://www.python.org/dev/peps/pep-0427/)
  - [2. setup スクリプトを書く](https://docs.python.org/ja/3/distutils/setupscript.html)

## A.1. 障害
### A.1.1. AARCH64
- [QNNPACK: GNU aarch64 assembler does not support 4s on neon mov #33124](https://github.com/pytorch/pytorch/issues/33124)
   - PyTorch 1.5.0をコンパイルする際、GNU assembler aarch64で行うとサポート命令の問題のため失敗する。
   - 暫定回避策としては、gccの代わりに、clang/clang++を使うことである。

#### A.1.1.1. 回避策1(clang)
回避手順は、clang(llvm)コンパイラを使うことである。

```bash
sudo su -
export CC=/usr/bin/clang
export CXX=/usr/bin/clang++
```
#### A.1.1.2. 回避策2(パッチを当てる)
以下のパッチを当てるとGCCでもコンパイルできる。

```asm
diff --git a/aten/src/ATen/native/quantized/cpu/qnnpack/src/q8gemm/8x8-dq-aarch64-neon.S b/aten/src/ATen/native/quantized/cpu/qnnpack/src/q8gemm/8x8-dq-aarch64-neon.S
index 7dc8611101..60ad8d1d4b 100644
--- a/aten/src/ATen/native/quantized/cpu/qnnpack/src/q8gemm/8x8-dq-aarch64-neon.S
+++ b/aten/src/ATen/native/quantized/cpu/qnnpack/src/q8gemm/8x8-dq-aarch64-neon.S
@@ -659,14 +659,14 @@ BEGIN_FUNCTION pytorch_q8gemm_dq_ukernel_8x8__aarch64_neon

     SUB x1, x1, 4

-    MOV V8.4s, V9.4s
-    MOV v10.4s, v11.4s
-    MOV v12.4s, V13.4s
-    MOV V14.4s, V15.4s
-    MOV V16.4s, V17.4s
-    MOV V18.4s, V19.4s
-    MOV V20.4s, V21.4s
-    MOV V22.4s, V23.4s
+    MOV V8.16b, V9.16b
+    MOV v10.16b, v11.16b
+    MOV v12.16b, V13.16b
+    MOV V14.16b, V15.16b
+    MOV V16.16b, V17.16b
+    MOV V18.16b, V19.16b
+    MOV V20.16b, V21.16b
+    MOV V22.16b, V23.16b

 5:
     CMP x1, 2
```


### A.1.2. ARM32
Raspberry Pi4は、以前の版と違って4GBのRAMがあり、普通の手順でコンパイルできる。ただし、protobufの版数の問題があり一コマンド余計に必要となる。

```
git submodule update --remote third_party/protobuf
```
詳細は別資料参照[１](https://qiita.com/yyojiro/items/d91b02149aa6480ded80)、[２](https://github.com/pytorch/pytorch/issues/22564)のこと