[python高速化] pythonからfortranを呼び出す最も簡単な方法

2020 3/04
[python高速化] pythonからfortranを呼び出す最も簡単な方法

私は元々はfortranを第一言語として、長年使ってきたが、現在の仕事では基本的にpythonを使って計算コードを書いています。

pythonは便利なモジュールがたくさん用意されており、計算原理を理解せずとも簡単に色々できます。

例えば顔認識、機械学習などの高度な数学知識が必要な計算でも10分程度でコードが組めました。

しかし、pythonの計算速度は速くないようです。

最近も仕事で重い計算をしないといけなくなったが、pythonで組んだら超絶時間がかかって、高速化しないといけなくなって、重い計算部分のみをfortranに書き換えました。

今回はそこで使用した、pythonからfortranを呼び出す方法を記しておきます。

ネット上はいろいろと手法はあるが、かなり複雑だったり、fortranへは入力変数しかなかったり、逆に出力変数しかなかったりするので、今回は最も簡単な方法でかつ、入力・出力変数がある場合を紹介する。3分でできます!

目次

概要: “f2py”を使って、fortranをpythonのモジュールにする

概要図を下記に示しました。

fig_1

calc_for.f90に計算(例えばとても重い計算)を書き、これを”f2py”でコンパイルします。

こうすると、pythonから呼び出せるsoファイルができ、あとはpythonから呼び出せば良いのです。

f2pyはnumpyのインストールがされていれば、同時にインストールされているようです。もし無ければpipなどを使ってnumpyをインストールしてみてください。

例1: fortranへの入力変数と、fortranからの出力変数があるケース

単にa+bを計算して、その結果としてcを出力するfortranコードを作ってみました。このfortran計算部分をpythonコードから呼び出しています。

まずはfortranコードについて。

これを次のようなコマンドでコンパイルします。

f2py -m calc_for -c calc_for.f90

これによって、「calc_for.f90」がコンパイルされて、「calc_for」という名前のpythonモジュールとして呼び出せるようになります。

実体としては「calc_for.cpython-38-darwin.so」が作成されています。これがsoファイルという実行ファイルです。このファイル名はシステムによって違ってきますが気にしなくて良いようです。

このファイル「calc_for.f90」はmain関数を含まないので、普通にgfortranでのコンパイルではエラーが出るかも。

また”f2py”では自動的に使用可能なコンパイラーが選択されます。ということは、コンピュータ内にgfortranなどのfortran用コンパイラーが一つもない時には次のようなエラーが出されます。

Could not locate executable gfortran
Could not locate executable f95

この場合には、別途fortran用コンパイラーをインストールする必要があります。

一方で、メインのpythonは次のように書きます。

これを実行すれば、fortranでの計算の結果「3」が画面に出力されます。

fortranを呼び出す行では、「calc_for」というファイル(モジュール)内の「calc_sub」というサブルーチンが呼び出す、という意味です。もちろん変数を入力する順番は気にする必要があります。

ちなみに単に「c = calc_for(a,b)」としてしまった場合には、次のようなエラーが出ます。

TypeError: ‘module’ object is not callable

モジュールをそのまま呼ぶなよ、っていう意味。

下記ではもう少し違う例を示したいと思います。

例2: 1次元配列の入出力

1次元配列を2つ入力して、その成分の和を1つの1次元配列として返す例です。

fortranコードが下記。

注意点としては、あらかじめ入力、出力される変数の次元数、要素数を記述しておく必要があります。

つまり、allocateableとして定義するとうまくいかないので、注意。

コンパイルのための命令文は上と同じです。

f2py -m calc_for -c calc_for.f90

fortranファイルの名前が同じなので、命令文が同じなのも当たり前ですね。1つのファイルにsubroutineはいくらでもかけるので、先のsubroutineの下に付きたしても問題ないです。

次にpythonコード。

これで難なく配列を入力して、その計算結果として配列を受け取ることができました。

例3: 多次元配列の入出力

次に、多次元配列の例を示したいと思います。

2次元配列ができれば、n次元配列も同様にできるだろうから、2次元配列の場合を示します。

今回もfortan内のsubroutineの名前は変えておきました。

コンパイルは先と同様に下記ように行います。

f2py -m calc_for -c calc_for.f90

次にpythonファイルは次のように書きます。

fortranを呼び出す部分は、ファイル名「calc_for」のsubroutine「calc_sub_3」を呼び出すということを表していて、もちろん変数を入力する順番は気にしないといけないです。

計算速度比較: フィボナッチ数計算を題材に

最後にpythonと、fortran(+python)の計算速度の比較をしてみます。

計算の題材は、フィボナッチ数の計算で、このような計算速度比較ではよく使われる題材のようです。

フィボナッチ数(Fibonacci number)とは次のような数字です。

$$ F_0 = 0 \\ F_1 = 1 \\ F_2 = F_1+F_0 = 1 \\ F_3 = F_2 + F_1 = 2 \\ F_4 = F_3 + F_2 = 3 \\ F_5 = F_4 + F_3 = 5 \\ F_n=F_{n-1}+F_{n-2} $$

Pythonのみの場合

まずはpythonのみで、計算してみました。コードは下記です。F_40を100000回計算させています。

計算時間も測定させます。

Fortran (+python)の場合

次にメインの重い計算をfortranにさせた場合のコード。

コンパイルコマンドは下記。

f2py -m calc_fibo -c calc_fibo.f90

ファイル名を変えたので、先とは少しだけ違います。

一方で呼び出すpythonファイルは次のようにしました。

実行結果の比較

計算自体の結果はもちろん同じ「165580141」という数字が出力されます。これが40番目のフィボナッチ数の値です。

一方で計算時間は下記のように大きな差がでました。

計算時間[s]
pythonのみ0.52399
fortran (+python)0.00119

なんと、fortranの方が、pythonよりも500倍も早い速度で計算できたことになります。

もちろんpythonコードの方はもっと「pythonらしい書き方」をすればもっと早く計算できるだろうが、それでもfortranの方がはるかに速いことに間違いはないです。

いくつかの言語の計算速度比較を行ったページを貼っておきます。

Qiita
【まとめ】フィボナッチ数だけで60ぐらいのプログラム言語に精通したつもりになる - Qiita
【まとめ】フィボナッチ数だけで60ぐらいのプログラム言語に精通したつもりになる - Qiita フィボナッチ数だけでプログラム言語に精通したつもりになる 簡単なサンプルでプログラム言語の基本をおさえる フィボナッチ数を求めるプログラムで各言語の基本仕様をマ...

pythonからfortranを呼び出すときにも余分に時間が必要なので、pythonの一部のみをfortranに任せる時には、ある程度重い計算を、ゴソっと任せないと意味はないので注意が必要だが、pythonを高速化したい時にfortranを使用するのは1つの手でしょう。

皆さんも時には古典言語と現代言語を混ぜてみては?

関連記事

応援よろしくお願いします☆

この記事を書いた人

天文の博士号をもつ理系パパ。
3歳の娘を子育て中。
最近はダイエットに挑戦中!

コメント

コメントする

目次
閉じる