PyTorchでdevice-sideの例外が起きた

諸事情でコード例を出せてないので、
エラー原因特定までの忘備録ぐらいにしかなりません。

Azureは関係なかったです。

# 現象

https://azure.microsoft.com/ja-jp/services/virtual-machines/data-science-virtual-machines/
を使ってみたんだけど、

実際に学習を走らせようとしたときに、device側(GPU?)でエラーが起きてしまった。

```
  File "train.py", line 180, in <module>
    trainer.training(epoch)
  File "train.py", line 112, in training
    loss.backward()
  File "/data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/tensor.py", line 107, in backward
    torch.autograd.backward(self, gradient, retain_graph, create_graph)
  File "/data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/autograd/__init__.py", line 93, in backward
    allow_unreachable=True)  # allow_unreachable flag
  File "/data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/autograd/function.py", line 77, in apply
    return self._forward_cls.backward(self, *args)
  File "/data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/nn/parallel/_functions.py", line 32, in backward
    return (None,) + ReduceAddCoalesced.apply(ctx.input_device, ctx.num_inputs, *grad_outputs)
  File "/data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/nn/parallel/_functions.py", line 43, in forward
    return comm.reduce_add_coalesced(grads, destination)
  File "/data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/cuda/comm.py", line 120, in reduce_add_coalesced
    flat_tensors = [_flatten_dense_tensors(chunk) for chunk in chunks]
  File "/data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/cuda/comm.py", line 120, in <listcomp>
    flat_tensors = [_flatten_dense_tensors(chunk) for chunk in chunks]
  File "/data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/_utils.py", line 192, in _flatten_dense_tensors
    flat = torch.cat([t.contiguous().view(-1) for t in tensors], dim=0)
RuntimeError: CUDA error: device-side assert triggered

terminate called after throwing an instance of 'c10::Error'
  what():  CUDA error: device-side assert triggered (insert_events at /opt/conda/conda-bld/pytorch_1556653109872/work/c10/cuda/CUDACachingAllocator.cpp:564)
frame #0: c10::Error::Error(c10::SourceLocation, std::string const&) + 0x45 (0x7f849c0e3dc5 in /data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/lib/libc10.so)
frame #1: <unknown function> + 0x14792 (0x7f84964d5792 in /data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/lib/libc10_cuda.so)
frame #2: c10::TensorImpl::release_resources() + 0x50 (0x7f849c0d3640 in /data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/lib/libc10.so)
frame #3: <unknown function> + 0x3067fb (0x7f8496bf47fb in /data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/lib/libtorch.so.1)
frame #4: <unknown function> + 0x36fc50 (0x7f8496c5dc50 in /data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/lib/libtorch.so.1)
frame #5: <unknown function> + 0x3095ea (0x7f8496bf75ea in /data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/lib/libtorch.so.1)
frame #6: torch::autograd::deleteFunction(torch::autograd::Function*) + 0xa2 (0x7f8496bf76a2 in /data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/lib/libtorch.so.1)
frame #7: std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() + 0xa2 (0x7f84cb0dc592 in /data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/lib/libtorch_python.so)
frame #8: <unknown function> + 0x13ffcb (0x7f84cb0fffcb in /data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/lib/libtorch_python.so)
frame #9: <unknown function> + 0x140039 (0x7f84cb100039 in /data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/lib/libtorch_python.so)
frame #10: torch::autograd::Variable::Impl::release_resources() + 0x1b (0x7f8497223a6b in /data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/lib/libtorch.so.1)
frame #11: <unknown function> + 0x13ff1b (0x7f84cb0fff1b in /data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/lib/libtorch_python.so)
frame #12: <unknown function> + 0x3bf384 (0x7f84cb37f384 in /data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/lib/libtorch_python.so)
frame #13: <unknown function> + 0x3bf3d1 (0x7f84cb37f3d1 in /data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/lib/libtorch_python.so)
<omitting python frames>
frame #24: __libc_start_main + 0xf0 (0x7f84d8e83830 in /lib/x86_64-linux-gnu/libc.so.6)
```

多分、ドライバが古いか、ライブラリのバグかな、とあたりを付けた。

# 調べたこと

同じソースコードで、AWSのPyTorch 1.1.0 CUDA10環境では例外が起きなかった。

pipでバージョンを見たら、Azureのほうは若干古そうだった。



```
$ python --version
Python 3.5.5 :: Anaconda custom (64-bit)

$ pip show torch
Name: torch
Version: 1.0.1.post2
Summary: Tensors and Dynamic neural networks in Python with strong GPU acceleration
Home-page: UNKNOWN
Author: UNKNOWN
Author-email: UNKNOWN
License: UNKNOWN
Location: /data/anaconda/envs/py35/lib/python3.5/site-packages

Requires: numpy
Required-by: torchvision, ...
```

# 試行1

ライブラリバージョンが原因と判断。
1.1.0を入れることにした。
最新には1.2.0。
念のためバージョンをキッチリ合わせることにした。

https://pytorch.org/get-started/previous-versions/#via-pip
のCUDA10のリンクから。
https://download.pytorch.org/whl/cu100/torch_stable.html
1.1.0で、cp35で、linuxのwheelファイルを探した。

```
$ pip install https://download.pytorch.org/whl/cu100/torch-1.1.0-cp35-cp35m-linux_x86_64.whl
```

だめだ、動かん。

# 試行2

そもそも、環境的にはanacondaの下にある。
まっさらな環境を作って試してみる。

```
conda create -n fastfcn python=3.5
conda activate fastfcn
conda install pytorch=1.1.0 cuda100 -c pytorch
conda install torchvision cudatoolkit=10.0 -c pytorch
conda install ............ # 試しているNNライブラリの依存
```

だが同じエラーになる。

# ドライバの情報など

```shell-session

$ lspci | grep -i nvidia
79b9:00:00.0 VGA compatible controller: NVIDIA Corporation GM204GL [Tesla M60] (rev a1)
a2fe:00:00.0 VGA compatible controller: NVIDIA Corporation GM204GL [Tesla M60] (rev a1)
```

```
$ cat /proc/driver/nvidia/version 
NVRM version: NVIDIA UNIX x86_64 Kernel Module  410.79  Thu Nov 15 10:41:04 CST 2018
GCC version:  gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.11) 
```

ドライバがちょっと古い。

# 試行3

Nvidia Driverは410.104が出ているようなので更新してみる。

```shell-session

$ sudo apt update
$ apt list --upgradable | grep nvidia

nvidia-410/unknown 410.104-0ubuntu1 amd64 [upgradable from: 410.79-0ubuntu1]
nvidia-410-dev/unknown 410.104-0ubuntu1 amd64 [upgradable from: 410.79-0ubuntu1]
nvidia-modprobe/unknown 418.87.00-0ubuntu1 amd64 [upgradable from: 410.79-0ubuntu1]
nvidia-opencl-icd-410/unknown 410.104-0ubuntu1 amd64 [upgradable from: 410.79-0ubuntu1]
nvidia-settings/unknown 418.87.00-0ubuntu1 amd64 [upgradable from: 410.79-0ubuntu1]

$ sudo apt upgrade
....
$ sudo shutdown -r now
``` 

これだけではだめっぽい。

# 試行4

試行3の状態で、condaで新しい環境を作りなおしてみる。

```shell

conda remove -n fastfcn --all
conda create -n fastfcn python=3.5
conda activate fastfcn
conda install pytorch=1.1.0 cuda100 -c pytorch
conda install torchvision cudatoolkit=10.0 -c pytorch
conda install ............ # 試しているNNライブラリの依存
```

うごいた！

# ？？？

何度か試していると、またエラーが起きた…

```
Traceback (most recent call last):
  File "train.py", line 180, in <module>
    trainer.training(epoch)
  File "train.py", line 112, in training
    loss.backward()
  File "/data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/tensor.py", line 107, in backward
    torch.autograd.backward(self, gradient, retain_graph, create_graph)
  File "/data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/autograd/__init__.py", line 93, in backward
    allow_unreachable=True)  # allow_unreachable flag
RuntimeError: cuDNN error: CUDNN_STATUS_EXECUTION_FAILED

terminate called after throwing an instance of 'c10::Error'
  what():  CUDA error: device-side assert triggered (insert_events at /opt/conda/conda-bld/pytorch_1556653109872/work/c10/cuda/CUDACachingAllocator.cpp:564)
frame #0: c10::Error::Error(c10::SourceLocation, std::string const&) + 0x45 (0x7fe1a52e3dc5 in /data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/lib/libc10.so)
frame #1: <unknown function> + 0x14792 (0x7fe19f6d5792 in /data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/lib/libc10_cuda.so)
frame #2: c10::TensorImpl::release_resources() + 0x50 (0x7fe1a52d3640 in /data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/lib/libc10.so)
frame #3: <unknown function> + 0x3067fb (0x7fe19fdf47fb in /data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/lib/libtorch.so.1)
frame #4: <unknown function> + 0x36fc50 (0x7fe19fe5dc50 in /data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/lib/libtorch.so.1)
frame #5: <unknown function> + 0x3095ea (0x7fe19fdf75ea in /data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/lib/libtorch.so.1)
frame #6: torch::autograd::deleteFunction(torch::autograd::Function*) + 0xa2 (0x7fe19fdf76a2 in /data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/lib/libtorch.so.1)
frame #7: std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() + 0xa2 (0x7fe1d42dc592 in /data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/lib/libtorch_python.so)
frame #8: <unknown function> + 0x13ffcb (0x7fe1d42fffcb in /data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/lib/libtorch_python.so)
frame #9: <unknown function> + 0x140039 (0x7fe1d4300039 in /data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/lib/libtorch_python.so)
frame #10: torch::autograd::Variable::Impl::release_resources() + 0x1b (0x7fe1a0423a6b in /data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/lib/libtorch.so.1)
frame #11: <unknown function> + 0x13ff1b (0x7fe1d42fff1b in /data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/lib/libtorch_python.so)
frame #12: <unknown function> + 0x3bf384 (0x7fe1d457f384 in /data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/lib/libtorch_python.so)
frame #13: <unknown function> + 0x3bf3d1 (0x7fe1d457f3d1 in /data/anaconda/envs/fastfcn/lib/python3.5/site-packages/torch/lib/libtorch_python.so)
<omitting python frames>
frame #24: __libc_start_main + 0xf0 (0x7fe1e2083830 in /lib/x86_64-linux-gnu/libc.so.6)
```

# 試行5

CUDAは、CPUと非同期で動くため、例外が出る箇所は、基本的には不定らしい。
僕の理解では、「次にGPUにコマンドを発行したときに一緒にエラーをとってくる」ぐらいのイメージ。
つまり、コード上のfail箇所自体にヒントはない。

デバッグのためには、同期的に動くようにするとよい。

`CUDA_LAUNCH_BLOCKING=1`という環境変数を与える

ref: http://torch.classcat.com/2018/05/25/pytorch-docs-notes-cuda/

が、今回のケースはだめだった。
対象としているコードに、複数のGPUをマルチスレッドで動かしつつ同期処理を行うnodeが含まれていて、デッドロックでhangupしてしまった…

# 最終的にエスパー

テンソルのshapeがおかしかった！！
複数ラベル領域付きの教師データと画像を与えて学習していたんだけど、

`(NUM,総ラベル数,W,H)`のShapeを与えていたけど、教師データとの整合性のために背景を追加していたので
`(NUM,総ラベル数+1,W,H)`のShapeでなければならなかった…

Shapeが異なるなら、Python側でエラーがでるだろう、という先入観があった。

# まとめ

Shapeが異なる場合、CUDA側でエラーが起きる場合がある

# 余談

Azureさん、ready-to-useなイメージを用意してくれてるのはいいんだけど、諸々のバージョンが古いのは、ちょっと価値を減じてしまっているように思う。頻繁に最新版にしておいてくれたらなあ。

最近さらに調査すすめた結果、managed serviceな、Machine Learning Studioとかのほうを推してる様子。
jupyter notebook / labとか使えるしソッチのほうが良いかもしれない。(筆者はまだjupyter xxを試してない)