5

anaconda アクセラレータを使用して行列の計算を高速化しようとしています。私は非常に基本的な例から始めました: 2 つの行列を乗算します。

私の目標は、通常の numpy.dot よりも優れた GPU 乗算を取得することです。

これは、このドキュメントに基づいた私の基本的な例です。

from numbapro import guvectorize
from numpy import arange

@guvectorize(['void(float32[:,:], float32[:,:], float32[:,:])'], '(m,n),(n,p)->(m,p)', target='gpu')
def matmul(A, B, C):
    m, n = A.shape
    n, p = B.shape
    for i in range(m):
        for j in range(p):
            C[i, j] = 0
            for k in range(n):
                C[i, j] += A[i, k] * B[k, j]

import numpy as np
import time

for dim in [50, 100, 200]:
    rnd = np.random.RandomState(0)
    a = rnd.rand(dim, dim).astype(np.float32)
    b = rnd.rand(dim, dim).astype(np.float32)
    resgpu = np.zeros_like(a)

    start = time.time()
    rescpu = np.dot(a, b)
    print('CPU:', time.time() - start)

    start = time.time()
    resgpu = matmul(a, b)
    print('GPU:', time.time() - start)

    print(np.allclose(rescpu, resgpu))
    print(np.allclose(resgpu, rescpu))

結果が悪すぎる: GPU は CPU よりも信じられないほど遅い

CPU: 0.00011801719665527344
GPU: 0.05677294731140137
True
True
CPU: 0.00011205673217773438
GPU: 0.3881375789642334
True
True
CPU: 0.00038933753967285156
GPU: 3.018171787261963
True
True

もちろん、内部の numpy の実現が適切に最適化されていることは理解していますが、anaconda の公式の例が優れていることを期待していました。私はpython 3.4.3を使用していますが、次の 2 つの支援ライブラリを使用するとエラーが発生しました: http://www.cs.toronto.edu/~tijmen/gnumpy.htmlおよびhttps://github.com/rctn/gpupy

gpupy を使用すると、Python 2.7 で高速化に成功したと言わざるを得ません。

だから私の質問は次のとおりです:GPUを使用してnumpy-CPUよりも優れた行列乗算を取得するにはどうすればよいですか? anacondaの公式の例の何が問題なのですか? GPUをnumpyで使用できるpython3用の作業ライブラリがある場合は?

===

結果

残念ながら、Python 3 には簡単で適切な方法はありません。代わりに 2.7 を使用してください。

すばらしいライブラリscikits.cudaをお勧めする @rth に感謝します。

利用可能な機能

いくつかのベンチマーク (anaconda mkl を使用してテストされているため、numpy も高速です)

dim = 10000
rnd = np.random.RandomState(0)
a = rnd.rand(dim, dim).astype(np.float32)
b = rnd.rand(dim, dim).astype(np.float32)
a_gpu = gpuarray.to_gpu(a)
b_gpu = gpuarray.to_gpu(b)

start = time.time()
rescpu = np.dot(a, b)
print 'CPU:', time.time() - start

start = time.time()
resgpu = culinalg.dot(a_gpu, b_gpu)
print 'GPU:', time.time() - start

resgpu = resgpu.get()
print np.allclose(rescpu, resgpu)
print np.allclose(resgpu, rescpu)

そして結果

CPU: 16.4765479565
GPU: 0.000520944595337
4

1 に答える 1

3

古典的な線形代数演算用に高度に最適化されたルーチンを提供する BLAS 実装を確認する必要があります。密行列の乗算は、gemm関数で実行されます。

  • たとえばnumpy、最適化された BLAS 実装 (OpenBLAS、ATLAS、MKL など) に対してコンパイルすると、行列の乗算が大幅に改善されます。
  • GPU については、NVIDIA が cuBLAS 実装を提供しています。this answerによると、scikits.cudaモジュールを使用してnumpy配列で呼び出すことができます。使用しているAnaconda アクセラレータは、cuBLAS への直接バインディングも提供します。

ところで、行列乗算の CPU と GPU のパフォーマンスをベンチマークする場合は、結果が桁違いに異なる可能性があるため、CPU 計算に Numpy が使用する BLAS も指定する必要があります (このベンチマークを参照)。

于 2015-06-14T23:20:42.380 に答える