numba guvectorize 활용하기

numba의 guvectorize를 사용하면 array 형태의 값 처리의 속도를 매우 빠르게 할 수 있다.

우선 실행 결과를 먼저 보겠다. aaa는 guvectorize를 사용해서 연산한 경우이고, bbb는 그냥 python 코드로 실행한 결과이다. ccc는 numpy의 벡터 연산을 실시한 결과다. guvectorize를 적용했을 때 단순 for loop를 사용했을 때에 비해 약 300배 가까이 빠른 실행을 보였다. numpy의 벡터 연산을 활용하면 for loop을 사용했을 때 보다 1400배 가까이 빠르게 실행되었다.

aaa: elapsed=0.0275056362s
bbb: elapsed=9.2325780392s
ccc: elapsed=0.0066127777s
>>> 9.2325780392 / 0.0275056362
335.6613158142476
>>> 9.2325780392 / 0.0066127777
1396.1724494685493

결론부터 말하자면, Array의 단순 연산은 numpy의 벡터연산이 가장 빠르다. 특정 로직에 따른 연산이 필요할 땐 guvectorize를 활용하자.

guvectorize의 사용법을 간단히 살펴보자. guvectorize의 경우에는 값을 return하지 않는다. 대신에 파라미터에 대한 선언을 정확히 해 주면 된다.

@guvectorize(['void(int64[:], int64[:])'], '(n) -> (n)')
def function_name(x, y):

순서대로 int64[:], int64[:]는 뒤의 (n) -> (n)과 매칭된다.

Array가 아닌 단순 값을 파라미터로 추가하는 경우에는 아래와 같이 처리하면 된다. 데이터 타입의 정의 개수와 입력, 출력 파라미터의 형식, 그리고 함수의 정의까지 모두 일치해야 한다.

@guvectorize(['void(int64[:], boolean, int64[:])'], '(n),() -> (n)')
def function_name(x, twist, y):

아래에는 위의 결과를 만든 소스 코드를 붙인다.

import time
import numpy as np
from numba import guvectorize


def timer(func):
    def measure(*args, **kwargs):
        begin = time.time()
        val = func(*args, **kwargs)
        end = time.time()
        print(f">> {func.__name__}: elapsed={'%.10f' % (end - begin)}s")
        return val

    return measure

@timer
@guvectorize(['void(int64[:], int64[:])'], '(n) -> (n)')
def aaa(x, y):
    for i, val in enumerate(x):
        y[i] = val + 3 * 3 / 5 * 1.23 / 6.53

@timer
def bbb(x):
    y = np.empty([len(x), 1])
    for i, val in enumerate(x):
        y[i] = (val + 3 * 3 / 5 * 1.23 / 6.53)
    return y

@timer
def ccc(x):
    return x + 3 * 3 / 5 * 1.23 / 6.53

a = np.int32(np.round(np.random.rand(5000000) * 1000))
out = aaa(a)
out = bbb(a)
out = ccc(a)

답글 남기기

Specify Facebook App ID and Secret in the Super Socializer > Social Login section in the admin panel for Facebook Login to work

이메일 주소를 발행하지 않을 것입니다. 필수 항목은 *(으)로 표시합니다