wide and deep

matplotlibでTcl_AsyncDelete: async handler deleted by the wrong threadが出たときのトラブルシューティング

発生したエラー

前回記事で紹介したコールバックを使用すると学習途中に下記エラーが発生した.
catdance124.hatenablog.jp

Epoch 4/50
138/590 [======>.......................] - ETA: 8:02 - loss: 0.8965 - acc: 0.7292Exception ignored in: <bound method Image.__del__ of <tkinter.PhotoImage object at 0x00000235FB7D5198>>
Traceback (most recent call last):
  File "C:\Python36\lib\tkinter\__init__.py", line 3504, in __del__
    self.tk.call('image', 'delete', self.name)
RuntimeError: main thread is not in main loop
Exception ignored in: <bound method Image.__del__ of <tkinter.PhotoImage object at 0x00000235FB8F4F28>>
Traceback (most recent call last):
  File "C:\Python36\lib\tkinter\__init__.py", line 3504, in __del__
    self.tk.call('image', 'delete', self.name)
RuntimeError: main thread is not in main loop
Exception ignored in: <bound method Image.__del__ of <tkinter.PhotoImage object at 0x00000235FBAF2C18>>
Traceback (most recent call last):
  File "C:\Python36\lib\tkinter\__init__.py", line 3504, in __del__
    self.tk.call('image', 'delete', self.name)
RuntimeError: main thread is not in main loop
Tcl_AsyncDelete: async handler deleted by the wrong thread

解決策

下記の対応で解決する.

import matplotlib  # <--追記
matplotlib.use('Agg')  # <--追記
from matplotlib import pyplot as plt
...

なお,公開したgistは修正済み.

詳細

コールバックは繰り返し呼び出されるためfigureは多く作成され,下記warningが発生していた.

RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface 
(matplotlib.pyplot.figure) are retained until explicitly closed and may consume too much memory.
 (To control this warning, see the rcParam figure.max_open_warning).

そのため,下記記事を参考にplt.close()をコードの最後に仕込んでいた.
xartaky.hatenablog.jp
しかし,plt.close()を追記すると表題のエラーが発生した.
plt.show()をせずに(plt.savefig()とか)closeしようとするとこのエラーが発生するらしい.

pyplot maintains references to the opened figures to make show work, but this will cause memory leaks unless the figures are properly closed

matplotlib.org