Pythonは遅いと言われていますが、実はPythonを高速化する方法はたくさんあります。Numpy、Scipyを使って行列計算を行ったり、NumbaやPyPyと行ったツールでJITコンパイルしたり。
その中でもこの記事ではCythonというPythonのスーパーセットを使ってPythonを高速化する方法を紹介します。
Cythonを使うことで、Pythonにちょっと手を加えたコードをCにコンパイルしたり、Cの関数をPythonから呼び出したりと行ったことが手軽にできます。
この記事では
- Cythonとは
- Cythonの一番簡単な試し方
- CythonとPythonの速度比較
などの話をまとめました。
この記事でCythonの勉強をスタートしましょう!
Cythonとは
Pythonの遅さ
Pythonは他の言語と比べると、そこまで速い言語ではありません。
近年ではPythonのように手軽に書けるのにC並に速い言語としてJuliaが注目されていますが、そのJuliaの公式ページでは以下のような速度比較が掲載されています。
このグラフを見てもわかるように、Pythonの速度はお世辞にも速いとは言えません。
Pythonを高速化する仕組み
Pythonはそんなに速くない、ということはわかりました。
ですが、実際にPythonは、Deep Learningや機械学習のような高度で高速な計算が求められる場面で使われています。
このような膨大な計算を行ったり速度が求められたりする場面では、生のPythonを使うのではなく、高速なライブラリに力を貸してもらうのがPythonの流儀です。
これらを支える技術としてNumPy、SciPyなどの行列計算ライブラリやその派生があります。
また、これらでもまだ足りない場合には、ChainerやTensorflowでGPUを使った高速化が行われます。
GPUはCPUと比べて圧倒的に速いので、大変な処理をそちらに回すことで、コントロールしているのがPythonであってもJavaであっても対して変わらない体感速度になります。
さて、こんなPython高速化界隈でPythonのコードをC/C++に変換することで高速化を目指すのがCythonです。
Cython
CythonはPythonにC言語の型が導入された言語です。
CythonコードをC/C++に変換してネイティブコンパイルするので、Pythonのようなインタプリタ型言語より速くなりそうですね。
Pythonっぽいコードの書き方をPythonic(パイソニック)と呼びますが、CythonではPythonicなままでC並の速度を得られることになります。
Cythonの使い方
Cythonを最も簡単に試すには、Jupyterを使います。ここではJupyterlabを使って、Cythonを試してみましょう。
インストール
まずはCythonをインストールします。
# Anaconda Pythonの場合 conda install cython # それ以外のPythonの場合 pip install cython
これでCythonのインストールは完了です。
もしもJupyterがインストールされていない場合は、Jupyterもインストールしましょう。
# Anaconda Pythonの場合 conda install Jupyter # それ以外のPythonの場合 pip install jupyter
これでJupyterのインストールもできました。Jupyterの使い方が不安な場合は、以下の記事を参考にしてください。
JupyterlabでCythonを実行
実際にCythonを試してみましょう。
Jupyter NotebookやJupyterlabでCythonを試すには、まず最初に、JupyterにCythonを有効にさせるマジックコマンドを実行します。
%load_ext Cython
これをnotebookで実行。
あとは、Cythonで実行したいセルの先頭に以下のマジックコマンドを設置します。
%%cython
これで実行ができます。
Cythonの書き方と速度比較
フィボナッチ数列でスピードテストをしてみましょう。
Cythonの実験コード
条件は以下の4つです。
- ただのPython(pure Python)で書いた関数
- 関数1を単純にCythonにした関数
- 関数2の引数に型アノテーションをつけた関数
- 関数3の関数内の変数全てに型アノテーションをつけた関数
[関数1]
def fib_python(n): a, b = 0, 1 for i in range(n): a, b = a + b, a return a
[関数2]
%%cython def fib_cython(n): a, b = 0, 1 for i in range(n): a, b = a + b, a return a
[関数3]
%%cython def fib_typed_cython(int n): a, b = 0, 1 for i in range(n): a, b = a + b, a return a
引数をみてください。
int n という感じで型情報がついていますね。変更点はここだけです。
[関数4]
%%cython def fib_all_typed_cython(int n): cdef int a,b,i a, b = 0, 1 for i in range(n): a, b = a + b, a return a
三行目のcdef int a,b,iというところで、a, b, iの各変数に型情報をつけています。cdefという宣言はCythonの中でのみ有効な宣言なので注意してください。
そのかなり超高速です!
速度比較
これらの関数の速さを、jupyterの%timeitで計測します。
%timeitは処理の速度を測るマジックコマンドです!
便利なので使ってみてください!
%timeit fib_python(5000) # 関数1 %timeit fib_cython(5000) # 関数2 %timeit fib_typed_cython(5000) # 関数3 %timeit fib_all_typed_cython(5000) # 関数4
[出力結果]
664 µs ± 85.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) 415 µs ± 19.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) 346 µs ± 5.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) 2.01 µs ± 235 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
なかなかおもしろい結果になりました。
分かりやすいように棒グラフに起こします。
型情報をたくさんつけたほうが高速になっていますね。何もつけていない関数2でもpure pythonと比べればかなり速いです。特にガリガリにチューニングした関数4は圧倒的です。
ですが、普段使いするには関数4のチューニング方法だとPythonらしさが足りないかもしれません。引数の型アノテーションをつけた関数3くらいまでのチューニングなら簡単ですし、Jupyter上で手軽に使うならオススメです!
まとめ
この記事ではCythonの紹介と速度比較を行いました。
Cythonは機械学習のライブラリでも使われているPython高速化ツールの虎の子です。
ここで紹介したもの以外にも更にCythonらしいチューニングをする方法はたくさんありますが、Cythonの威力、わかっていただけたんじゃないでしょうか。
ここで紹介しなかったチューニング方法や、Cythonを使った機械学習の実装がやってみたい!という方は、是非侍エンジニアのマン・ツー・マンレッスンを考えてみてください。
[su_button url=”https://lp.sejuku.net/lp1_blog_01/?cid=ai_btn1_60454″ target=”blank” background=”#409fdf” color=”#fff88f” size=”10″ center=”yes” radius=”10″ icon=”icon: external-link” icon_color=”#fff88f” text_shadow=”0px 0px 10px #808080″]侍エンジニアとは?
詳細はこちらから[/su_button]
私もインストラクターとして所属しているプログラミングスクールです。レッスンや質問対応などであなたのプログラミングや人工知能などの勉強をサポートします!