gombeのブログ

マイコンの電子工作系PIC32/KiCad/C/C++/3D/

科学計算にPythonとC++どっちがいいか、いやjuliaを検討すべきかも

データサイエンス分野

データを扱ううえで、行列計算などのタスクはnumpyを使って処理することが増えてきました。 pythonの特徴である動的な型付けによる気軽なプログラミングは、他のC++などの言語よりもっと簡単にいろいろな作業ができるようになってきました。 より具体的に言えば、pythonはより簡潔に高速なプロトタイピングをすることができ、研究活動やテストなどを高速化してきました。

一方でC++は、コンパイルという作業を必要とし、さらに静的な型付けにより、Pythonより多くのコーディングが必要です。 しかし、逆に性的な型付けとコンパイルのおかげで局所的な最適化が可能になり、高速な実行が可能です。 データ同化のテストでは、実行時間がC++のほうが100倍くらい速くなりました。 まだ、C++も素人ですが、お互いにどのような場面で向いていて、どのような場面で不向きなのかを考察してみました。

コード

Pythonは、numpyを使うことで科学計算を高速化することができました。 動的な型付けやリスト内方表記などは、コードを簡潔にわかりやすく書くことができます。

c++ with Eigen 3

return MatrixXf::Identity(J,J).topRows(n);

python with Numpy

return np.identity(J)[:n]

C++では、Eigen3という算術演算のライブラリを用いて比較しました。リスト内方表記等はなく、代わりにジェネレータ等の他の文法で補うこともありますが、Pythonほどシンプルに書くことはできません。

時間

開発というのは、環境整備からコーディングとコンパイル、実行、検証に分かれます。

環境整備

Pythonは包括的なライブラリが充実していることから、そのままで様々なテストを強力に推し進めることができます。 また、何かあってもpip等で管理もできます。

一方でC++は自分で管理する必要があります。必要なライブラリをそろえて組み込むことはユーザーの責任で行います。面倒ですね。

コーディング

C++よりpythonのほうが簡潔にかけてコードを書く量が短いと思います。

コンパイル

Pythonにはコンパイルという概念がありません。C++では、ファイルの分割により、コンパイル時間は短縮しますが、テストしたLETKFのコードだけの関数でも15秒程度ビルドに時間が必要でした。 すべてのファイルをコンパイルするとき、一番長いコンパイル時間に足を引っ張られるので、最低でも15秒程度はかかりそうです。結構イライラします。

実行時間

私のテストしたコードではPythonは実行が長いです。C++のほうがパフォーマンスの最適化がしやすいので、私が簡単にチューニングした結果、100倍ものスピードアップを達成しました。後でもう少し詳しく書いています。

検証

検証は、何をもって検証というかにもよりますが、一般的にPythonのほうがコンパイルの時間がない分、実行途中で中止することで最後まで実行しなければ繰り返し試行することができます。 一方で、最後まで実行して誤差のパフォーマンス比較をしたいときは、繰り返し実行時はC++のほうが高いパフォーマンスを発揮できます。検証もC++のほうが早く終わると思われます。

合計時間

重めの検証から、誤差のパフォーマンスまで完全にするならC++で実装するのがよいと思います。 ただ、既存の軽めの技術を追試するだけだったらPythonでいいと思います。

実行時間について

1年分(1460ステップ)、40要素のデータ同化を100メンバー、8モンテカルロサンプリングのPFで実行時間がどう変化するかを観測しました。 計算のオーダーは上の示した数値の積になります。

結果としては、C++が2.28秒、pythonが数分だったので、かなり速くなりました。ほかのデータ同化テスト(フィルターテスト)でも、100倍程度のパフォーマンスゲインが得られています。

考えられる理由は以下の通りです。

  1. 小さなデータを繰り返し処理することが多く、PythonだとAPIオーバーヘッドが大きい
  2. C++では、ベクトル演算を有効に使って計算できた
  3. C++では局所的な最適化により、不必要な計算が省略された
  4. openmpによる並列化による性能向上(Pythonでは、アルゴリズムに並列化を入れることが難しい)

まとめ

PythonAPIのオーバーヘッドが大きく、局所的なコードが大きく足を引っ張ることになりそうです。 一方で記述が簡潔であることから、プロトタイプに向いているとも言えます。

一方で、C++は計算のアルゴリズムを記述するとオーバーヘッドも少なく、高速な実行ができ、局所的な最適化も可能です。

おっと、そういえば思い出したわ。 Julia が強いらしいので、それも検証してみたいと思います。simd演算や、並列計算などをサポートしていて、かなり速いらしいです。

そしてすべて検証し終わったところでQiitaにでも投稿しようかな。