TadaoYamaokaの日記

山岡忠夫Homeで公開しているプログラムの開発ネタを中心に書いていきます。

ビルド済みChainerからソースビルド版に戻す

Chainer/CupyはWindowsは正式にサポートされていないが、問題なく動作する。
最近のバージョンでは、Windows向けにもビルド済みパッケージも提供されているので、以前は必要だったVisual Studioがなくてもインストールできる。

先日、開発環境をVisual Studio 2017に移行した際、Cupyをソースからインストールしようとすると、Visual Studio 2017でコンパイルエラーが起きることを書いた。
そのため、ビルド済みパッケージからインストールを行った。

しかし、長時間学習を行っていると、以前には発生しなかったエラーが発生するようになり、安定して学習ができなくなった。

発生するエラー
Traceback (most recent call last):
  File "train_rl_policy_with_value_using_hcpe_bootstrap.py", line 106, in <module>
    x1, x2, t1, t2, z, value = mini_batch(train_data[i:i+args.batchsize])
  File "train_rl_policy_with_value_using_hcpe_bootstrap.py", line 87, in mini_batch
    Variable(cuda.to_gpu(move)),
  File "C:\Anaconda3\lib\site-packages\chainer\backends\cuda.py", line 288, in to_gpu
    return _array_to_gpu(array, device_, stream)
  File "C:\Anaconda3\lib\site-packages\chainer\backends\cuda.py", line 336, in _array_to_gpu
    return cupy.asarray(array)
  File "C:\Anaconda3\lib\site-packages\cupy\creation\from_data.py", line 61, in asarray
    return core.array(a, dtype, False)
  File "cupy\core\core.pyx", line 2350, in cupy.core.core.array
  File "cupy\core\core.pyx", line 2403, in cupy.core.core.array
  File "cupy\cuda\memory.pyx", line 371, in cupy.cuda.memory.MemoryPointer.copy_from_host_async
  File "cupy\cuda\runtime.pyx", line 265, in cupy.cuda.runtime.memcpyAsync
  File "cupy\cuda\runtime.pyx", line 136, in cupy.cuda.runtime.check_status
cupy.cuda.runtime.CUDARuntimeError: cudaErrorIllegalAddress: an illegal memory access was encountered
Traceback (most recent call last):
  File "cupy\cuda\driver.pyx", line 192, in cupy.cuda.driver.moduleUnload
  File "cupy\cuda\driver.pyx", line 81, in cupy.cuda.driver.check_status
cupy.cuda.driver.CUDADriverError: CUDA_ERROR_ILLEGAL_ADDRESS: an illegal memory access was encountered
Exception ignored in: 'cupy.cuda.function.Module.__dealloc__'
(略)
Traceback (most recent call last):
  File "cupy\cuda\driver.pyx", line 192, in cupy.cuda.driver.moduleUnload
  File "cupy\cuda\driver.pyx", line 81, in cupy.cuda.driver.check_status
cupy.cuda.driver.CUDADriverError: CUDA_ERROR_ILLEGAL_ADDRESS: an illegal memory access was encountered
Error in sys.excepthook:

Original exception was:

毎回発生するわけではなく、再起動すると発生しなくなったりする。
しかし、合計3回発生したので、継続利用はできなそうなので、ソースビルド版に戻すことにした。

Visual Studio 2015と2017の共存

ソースビルドは、上記の通り、Visual Studio 2017ではできないため、Visual Studio 2015が必要になる。
Pythonは最新のAnacondaを使用しているため、Visual Studio 2017でビルドされているが、Cランタイム(VCRUNTIME140.dll)はバイナリ互換性があるため、CupyをVisual Studio 2015でビルドしても問題ない。

Visual Studio 2015と2017は両方インストールできる
インストール順番はどちらでもよさそうだが、念のため、2017をアンインストールしてから2015をインストールして2017をインストールした。

pipでインストール時にどちらのVisual Studioが使用されるかは、インストーラの作りに依存している。
cupyのインストーラは2017がインストールされていても、2015が使用された。

pip install cupy --no-cache-dir

これで、ソースからインストールできた。
続けて、Chainerもインストールする。

pip install chainer --no-cache-dir

ソースからビルドしたバージョンでは、上記のエラーは発生しなくなり、安定して学習できるようになった。


なお、Cythonを使って、C++のソースをビルドする場合は、自動で2017が選択される。
2015を使用したい場合、公式ドキュメントには特に書かれていないが、スタートメニューから「VS2015 x64 Native Tools Command Prompt」を選んでコマンドプロンプトを起動すると2015が使用された。

2019/4/24 追記

結局、ビルドしたバージョンでも同じエラーがでるようになり、原因がつかめていません。
ChainerやPythonバージョンを戻しても変わらず。困った。
一旦、別のGPUを使用して再現するか様子見する。

2019/4/27 追記

GPUを変えても発生するため、GPU故障も疑いましたが、関係なかったようです。
そして、やっと原因が特定できました。

Visual StudioとChainerのバージョンを戻しても発生しましたが、その際のエラーメッセージが、

Traceback (most recent call last):
  File "train_rl_policy_with_value_using_hcpe_bootstrap.py", line 109, in <module>
    x1, x2, t1, t2, z, value = mini_batch(train_data[i:i+args.batchsize])
  File "train_rl_policy_with_value_using_hcpe_bootstrap.py", line 88, in mini_batch
    return (Variable(cuda.to_gpu(features1)),
  File "C:\Anaconda3\lib\site-packages\chainer\backends\cuda.py", line 288, in to_gpu
    return _array_to_gpu(array, device_, stream)
  File "C:\Anaconda3\lib\site-packages\chainer\backends\cuda.py", line 336, in _array_to_gpu
    return cupy.asarray(array)
  File "C:\Anaconda3\lib\site-packages\cupy\creation\from_data.py", line 61, in asarray
    return core.array(a, dtype, False)
  File "cupy/core/core.pyx", line 2371, in cupy.core.core.array
  File "cupy/core/core.pyx", line 2418, in cupy.core.core.array
  File "cupy/core/core.pyx", line 2415, in cupy.core.core.array
  File "cupy/cuda/pinned_memory.pyx", line 212, in cupy.cuda.pinned_memory.alloc_pinned_memory
  File "cupy/cuda/pinned_memory.pyx", line 286, in cupy.cuda.pinned_memory.PinnedMemoryPool.malloc
  File "cupy/cuda/pinned_memory.pyx", line 306, in cupy.cuda.pinned_memory.PinnedMemoryPool.malloc
  File "cupy/cuda/pinned_memory.pyx", line 303, in cupy.cuda.pinned_memory.PinnedMemoryPool.malloc
  File "cupy/cuda/pinned_memory.pyx", line 177, in cupy.cuda.pinned_memory._malloc
  File "cupy/cuda/pinned_memory.pyx", line 178, in cupy.cuda.pinned_memory._malloc
  File "cupy/cuda/pinned_memory.pyx", line 29, in cupy.cuda.pinned_memory.PinnedMemory.__init__
  File "cupy/cuda/runtime.pyx", line 238, in cupy.cuda.runtime.hostAlloc
  File "cupy/cuda/runtime.pyx", line 144, in cupy.cuda.runtime.check_status
cupy.cuda.runtime.CUDARuntimeError: cudaErrorIllegalAddress: an illegal memory access was encountered
Traceback (most recent call last):
  File "cupy/cuda/driver.pyx", line 192, in cupy.cuda.driver.moduleUnload
  File "cupy/cuda/driver.pyx", line 81, in cupy.cuda.driver.check_status
cupy.cuda.driver.CUDADriverError: CUDA_ERROR_ILLEGAL_ADDRESS: an illegal memory access was encountered
Exception ignored in: 'cupy.cuda.function.Module.__dealloc__'
Traceback (most recent call last):
  File "cupy/cuda/driver.pyx", line 192, in cupy.cuda.driver.moduleUnload
  File "cupy/cuda/driver.pyx", line 81, in cupy.cuda.driver.check_status
cupy.cuda.driver.CUDADriverError: CUDA_ERROR_ILLEGAL_ADDRESS: an illegal memory access was encountered
(略)

となっており、pinned_memoryの確保に失敗しているようでした。

PinnedMemoryPoolに関するエラー情報がないか調べたところ、メモリプールは断片化される可能性があるので、free_all_blocksを呼ぶとよいことがわかりました。
Google グループ
concat_examples with various batch size causes memory leaks · Issue #4911 · chainer/chainer · GitHub

そこで、

chainer.cuda.cupy.get_default_pinned_memory_pool().free_all_blocks()

を定期的に呼ぶようにしたことろ、エラーが発生しなくなりました。
(完全に対策できたかはまだ様子見ですが)

なぜVisual Studioのバージョンアップ契機で発生するようになったかは謎ですが、同時にWindows Updateとかも行っているので他に契機があったのかもしれません。100%発生するわけでもないので、今までたまたま動いていたというだけかもしれません。

2019/4/28 追記

free_all_blocks()を呼ぶようにしても発生したので、さらに原因を調査したところやっと原因がわかりました。
自己対局プログラムにバグがあり、マルチスレッドのタイミングに依存して教師データの指し手が無効な値となったデータが混じっていたことが原因でした。
今までも不正なデータがごく稀に混じっていましたが顕在化していなかっただけでした。

発生頻度が上がったのは、プログラムにノードを再利用する修正を加えたためで、マルチスレッドの微妙なタイミングが変わったため発生しやすくなったためでした。
不正なデータを除くと、エラーは発生しなくなりました。

2週間以上、バージョンの問題を疑って時間を無駄にしてしまいましたorz
CUDAのメモリエラーは不正なデータがないか疑うべきという教訓とします。