BLAS 및 LAPACK 선형 대수 기능을 광범위하게 사용하는 프로그램을 작성하고 싶습니다. 성능이 문제이기 때문에 몇 가지 벤치마킹을 수행했으며 내가 취한 접근 방식이 합법적인지 알고 싶습니다.
말하자면 3 명의 참가자가 있고 간단한 행렬-행렬 곱셈으로 그들의 성능을 테스트하고 싶습니다. 참가자는 다음과 같습니다.
- NumPy와 만의 기능을 활용
dot
. - 공유 객체를 통해 BLAS 기능을 호출하는 Python.
- C ++, 공유 객체를 통해 BLAS 기능을 호출합니다.
대본
다른 차원에 대한 행렬-행렬 곱셈을 구현했습니다 i
. i
5 개에서 500 개까지 5 개 단위로 실행되며 다음 m1
과 m2
같이 설정됩니다.
m1 = numpy.random.rand(i,i).astype(numpy.float32)
m2 = numpy.random.rand(i,i).astype(numpy.float32)
1. Numpy
사용 된 코드는 다음과 같습니다.
tNumpy = timeit.Timer("numpy.dot(m1, m2)", "import numpy; from __main__ import m1, m2")
rNumpy.append((i, tNumpy.repeat(20, 1)))
2. Python, 공유 객체를 통해 BLAS 호출
기능으로
_blaslib = ctypes.cdll.LoadLibrary("libblas.so")
def Mul(m1, m2, i, r):
no_trans = c_char("n")
n = c_int(i)
one = c_float(1.0)
zero = c_float(0.0)
_blaslib.sgemm_(byref(no_trans), byref(no_trans), byref(n), byref(n), byref(n),
byref(one), m1.ctypes.data_as(ctypes.c_void_p), byref(n),
m2.ctypes.data_as(ctypes.c_void_p), byref(n), byref(zero),
r.ctypes.data_as(ctypes.c_void_p), byref(n))
테스트 코드는 다음과 같습니다.
r = numpy.zeros((i,i), numpy.float32)
tBlas = timeit.Timer("Mul(m1, m2, i, r)", "import numpy; from __main__ import i, m1, m2, r, Mul")
rBlas.append((i, tBlas.repeat(20, 1)))
3. C ++, 공유 객체를 통해 BLAS 호출
이제 C ++ 코드는 자연스럽게 조금 더 길어 지므로 정보를 최소한으로 줄입니다.
함수를로드합니다.
void* handle = dlopen("libblas.so", RTLD_LAZY);
void* Func = dlsym(handle, "sgemm_");
다음과 gettimeofday
같이 시간을 측정합니다 .
gettimeofday(&start, NULL);
f(&no_trans, &no_trans, &dim, &dim, &dim, &one, A, &dim, B, &dim, &zero, Return, &dim);
gettimeofday(&end, NULL);
dTimes[j] = CalcTime(start, end);
j
20 번 실행되는 루프는 어디에 있습니까 ? 나는 지나간 시간을 계산한다
double CalcTime(timeval start, timeval end)
{
double factor = 1000000;
return (((double)end.tv_sec) * factor + ((double)end.tv_usec) - (((double)start.tv_sec) * factor + ((double)start.tv_usec))) / factor;
}
결과
결과는 아래 플롯에 나와 있습니다.
질문
- 내 접근 방식이 공정하다고 생각합니까, 아니면 피할 수있는 불필요한 오버 헤드가 있습니까?
- 결과가 C ++와 파이썬 접근 방식 사이에 엄청난 불일치를 보일 것이라고 기대하십니까? 둘 다 계산을 위해 공유 객체를 사용하고 있습니다.
- 내 프로그램에 파이썬을 사용하고 싶기 때문에 BLAS 또는 LAPACK 루틴을 호출 할 때 성능을 향상시키기 위해 무엇을 할 수 있습니까?
다운로드
전체 벤치 마크는 여기에서 다운로드 할 수 있습니다 . (JF Sebastian이 그 링크를 가능하게 만들었습니다 ^^)
r
매트릭스에 대한 메모리 할당 이 불공평합니다. 지금 "문제"를 해결하고 새로운 결과를 게시합니다.
np.ascontiguousarray()
(C 대 Fortran 순서 고려). 2. np.dot()
동일한 libblas.so
.
m1
및 m2
이 ascontiguousarray
같은 플래그를 True
. 그리고 numpy는 C와 동일한 공유 객체를 사용합니다. 배열의 순서에 관해서는 : 현재 계산 결과에 관심이 없으므로 순서는 관련이 없습니다.