【メモ】matplotlibで作成したアニメーションが保存できないときの対応

IT関連

matplotlibのanimationを保存するときにハマった話

こんにちは、novです。

最近、業務で扱う深層学習についてもう少し理解を深めようと、ゼロから作るDeep Learning3(フレームワーク編)を、手を動かしながら読んでいます。
機械学習の話なので、当然重要トピックとして

「最適化数学」

の話が出てきます。この書籍も例にもれず、有名なベンチマーク関数を用いて、

  • 勾配法
  • ニュートン法

についてコードを交えて紹介しています。ただ、紙面の関係か最適化した結果を描画するコードについては書籍の中で触れられていません(dezeroのgithubリポジトリにはあります)。

https://github.com/oreilly-japan/deep-learning-from-scratch-3/tree/master/dezero

「書籍にはコード紹介されていないけど、自分で何か数値計算を行ったときの可視化もやっておくとブログやTwitterの投稿で使いやすそうだなー」

と思い、プロットの他にアニメーションも作成してみた訳です。

何かと書籍の内容を可視化したり、仕事でも時系列の画像データの加工結果を見るのにアニメーションは作ったりしていましたが、mp4やgif形式で保存するところまでは基本的にやっていませんでした(その場でプログラム動かして確認していたので)。

という訳で、Twitterとかに投稿する段になって、初めてこういう「プログラムで作成したアニメーションを保存する」という作業を行ったのですが、ネットに転がっている記事・matplotlibのドキュメントに記載されている通りに動かしても以下のようにエラーしか吐かなかったんですね。

'MovieWriterRegistry' object is not an iterator animation

...(省略)... list index out of range

特に後者は、これと言った複雑なリストなども扱っていなかったので「何でかなー」と1日くらい悩んでいました。

結果としては解決したのですが、その対応方法が

「ffmpegというソフトウェアをダウンロードし、matplotlibの設定ファイル(matplotlibrc)にパスを通す」

というものでした(ffmpegの部分はImageMagicでもOK。なんならImageMagicのインストール時にffmpegもインストールされるとか)。

保存用のプログラムは色々な記事で紹介されているのですが、そのために必要な作業について触れている記事はなかなか見つけられなかったので、今回記事化しようと思ったわけです。

ちなみに今回やったのは、この画像のような最適化の進行状況をアニメーションで保存することです。

さて、経緯はこんなものにして細かい解決方法について見ていきましょう。

なお、動作確認を行ったOSはWindows10です。

matplotlibrcの格納場所

matplotlibrc(matplotlibの設定ファイル)は、次の関数で取得可能です。

matplotlib.matplotlib_fname()

【出力】
(path_to_matplotlib)/matplotlib/mpl-data/matplotlibrc

matplotlib公式ドキュメント

で、matplotlibrcの場所を特定したら、適当なエディタでそれを開きます。
730行目あたり(要はファイルの最後の方)に、以下のようなパートがあるので、そこを編集します。

## ***************************************************************************
## * ANIMATION                                                               *
## ***************************************************************************
#animation.html: none  # How to display the animation as HTML in
                       # the IPython notebook:
                       #     - 'html5' uses HTML5 video tag
                       #     - 'jshtml' creates a Javascript animation
#animation.writer:  ffmpeg        # MovieWriter 'backend' to use
#animation.codec:   h264          # Codec to use for writing movie
#animation.bitrate: -1            # Controls size/quality tradeoff for movie.
                                  # -1 implies let utility auto-determine
#animation.frame_format: png      # Controls frame format used by temp files
#animation.ffmpeg_path:           # Path to ffmpeg binary. Without full path
                                  # $PATH is searched
#animation.ffmpeg_args:           # Additional arguments to pass to ffmpeg
#animation.convert_path: convert  # Path to ImageMagick's convert binary.
                                  # On Windows use the full path since convert
                                  # is also the name of a system tool.
#animation.convert_args:          # Additional arguments to pass to convert
#animation.embed_limit:  20.0     # Limit, in MB, of size of base64 encoded
                                  # animation in HTML (i.e. IPython notebook)

#mpl_toolkits.legacy_colorbar: True

このうち、#animation.ffmepeg_path: と書かれている部分を、次のように変更します。

animation.ffmpeg_path: (path_to_ffmpeg_bianry)/ffmpeg.exe

path_to_ffmpeg_binaryのところは、適宜環境に応じて変更してください(要は、ffmpeg.exeの絶対パスを記載すればOK)

これでひとまずffmpegを使用したコードは問題なく動作するはずです。

ffmpegのダウンロード方法

ffmpegがインストール済みならば上記の作業だけで事足りるのですが、そうでない場合は、ffmpegのインストール作業も忘れずに行ってください。

やり方は簡単で、以下のgithub repositoryから、該当するzipファイルをダウンロードしてくるだけです(画像は2020/12/24現在のもの)。

Releases · BtbN/FFmpeg-Builds
Contribute to BtbN/FFmpeg-Builds development by creating an account on GitHub.

あとは、このzipファイルを解凍し、Cドライブなどの適当な場所に配置すればOKです。
(C:\Program Files 以下に配置するのが無難だとは思います)

あとは、配置したパスを、上記matplotlibrcにコピペすれば動作するはずです。

matplotlib.animationでの動画保存について

ffmpegを使用する際の保存方法についても触れておきます。
細かいことは他の記事に譲ります。

from matplotlib.animation import FuncAnimation

# --- 中略 --- #

anim = FuncAnimation(fig, update, frames=frames, interval=interval)

anim.save("anim.mp4", writer="ffmpeg", dpi=300)

といったように使います。FuncAnimationオブジェクトのsaveメソッドにて、writerで “ffmpeg”を指定すれば保存できます。

なお、上記の例ではmp4に保存していますが、それをgif形式に変換したい場合は、

ffmpeg -i anim.mp4 anim.gif

のようにすればよいです。今回題材とした最適化の様子をgifに変換したものが以下になります。

少々画質が荒いのは改善点ですね。。。

まとめ

今回はmatplotlib.animation で作成したアニメーションを保存するときにハマった部分と、その解決策について述べました。
ffmpegをインストールすることで解決していますが、Pillowというモジュールを使用すればPython内で完結するという話もあります(自分の環境では上手くいきませんでした。また試してみようとは思います。)

この辺の内容で詰まっている人の助けになれば幸いです。
では今回は以上とします。最後までお読みいただき、ありがとうございましたー

コメント

タイトルとURLをコピーしました