読者です 読者をやめる 読者になる 読者になる

雑記帳

ソフトを中心に雑記を書いてる割とすぐ転職したい28歳。

Pythonのコードを高速化(はじめてのNumba)

大昔の記事を書き足してなんとかしたいなぁと思いつつ、いつまでも更新出来ずにいました。
少し諦めてもう少し最近のことを書くことにしました。

背景

最近仕事でPythonのコードでツールを作って間に合わせることが増えたけれど、
実行時間が遅くてコマリンスなことになることもあったので、高速化のアプローチをしてみましたとさ。

最近はこんな本を読んでます。

Cython ―Cとの融合によるPythonの高速化

Cython ―Cとの融合によるPythonの高速化

英語kindle版がとてもとても安かったので買ってしまいました。

で、Pythonでは下のように色々な高速化手法が色々あるけど、さてどんな感じかなと。

  • Numpy
  • MultiProcessing
  • Cython
  • C拡張
  • Numba
  • ???

紹介した本と関係なしに、今回は聞いたこともなかったNumba様を使ってみます。

 やってみよう!

本サイトはこちら。 解説本とかは探したけど見つかりませんでした。

Numba — Numba

時間測定方法

ipythonsample.pyに対して実行するときは大体こんな感じ。

> %timeit -n 5 %run sample

普通に書く

何もしない時

def fibo(n):
    if n < 2: return n
    return fibo(n-1) + fibo(n-2)


if __name__=="__main__":
    fibo(38)
In [83]: %timeit -n 1 %run sample
1 loops, best of 3: 15.7 s per loop

メモ化的なやつ

def fibo(n):
    a,b = 0,1
    for x in range(n):
        a,b = b,a+b
    return a
In [86]: %timeit -n 5 %run sample
5 loops, best of 3: 745 µs per loop

nを増やす

if __name__=="__main__":
    n = 10**6
    fibo2(n)
In [92]: %timeit -n 1 %run sample
1 loops, best of 3: 11 s per loop

Numba1

単にjitを使ってみる

@jit
def numfibo(n):
    a,b = 0,1
    for x in range(n):
        a,b = b,a+b
    return a
In [98]: %timeit -n 5 %run sample
5 loops, best of 3: 42.6 ms per loop

もっと増やす

if __name__=="__main__":
    n = 10**10
    numfibo(n)
In [116]: %timeit -n 1 %run sample
1 loops, best of 3: 3.32 s per loop

Numba2

型定義を入れる

@jit(int64(int64))
def numfibo2(n):
    a,b = 0,1
    for x in range(n):
        a,b = b,a+b
    return a
In [118]: %timeit -n 1 %run sample
1 loops, best of 3: 3.23 s per loop

少し条件を変えてみる

if __name__=="__main__":
    n = 10**10
    numfibo2(n-2)
    numfibo2(n-1)
    numfibo2(n)

Numba2

In [120]: %timeit -n 1 %run sample
1 loops, best of 3: 9.61 s per loop

ベクトル化

@vectorize([int64(int64)])
def numvfibo(n):
    a,b = 0,1
    for x in range(n):
        a,b = b,a+b
    return a
In [122]: %timeit -n 1 %run sample
1 loops, best of 3: 9.66 s per loop

結果

単にJITを入れるだけでも割と高速化されそうな印象。
型定義はおまけ程度に早くなるのかな?何度やっても多少早かったので。
ベクトル化は使いどころを知らないと高速化出来なさそう。
guvectorizeもあるけど、チュートリアルを見ても使い方がぱっとは分からない割に早くなってくれなかったのでアレゲ。。。

雑記

仕事中に遊びで少し使ってみたけど、数値計算的な所以外ではjitを入れても速くはならなかった。
というより、JIT分遅くなっている所もあるので闇雲に突っ込んでも逆効果かも。
普通のWebアプリケーションだと、計算よりも分岐とか文字列の分離結合のが多いと思うので、案外使い道が無いのではなかろうか?