質問

ここ HDF5を使用したマトリックス乗算 私は大きなマトリックスの乗算にHDF5(pytables)を使用していますが、HDF5を使用すると、Plane numpy.dotとストアマトリックスを使用してより速く動作するため、この動作の理由は何ですか?

また、Pythonのマトリックス乗算にはいくつかの高速な関数があるかもしれません。なぜなら、私はまだ小さなブロックマトリックスの乗算にnumpy.dotを使用しているためです。

ここにいくつかのコードがあります:

マトリックスがRAMに収まると仮定します:マトリックス10*1000 x 1000でテストします。

デフォルトのnumpyを使用しています(Blas Libはないと思います)。プレーンなnumpyアレイはRAM:時間9.48にあります

a、b in ram、c on disk:time 1.48の場合

ディスク上のa、b、cの場合:時間372.25

MKLでnumpyを使用する場合、結果は次のとおりです。0.15,0.45,43.5。

結果は合理的に見えますが、1つ目のケースブロックの乗算がより速くなる理由をまだ理解していません(A、BをRAMに保存するとき)。

n_row=1000
n_col=1000
n_batch=10

def test_plain_numpy():
    A=np.random.rand(n_row,n_col)# float by default?
    B=np.random.rand(n_col,n_row)
    t0= time.time()
    res= np.dot(A,B)
    print (time.time()-t0)

#A,B in RAM, C on disk
def test_hdf5_ram():
    rows = n_row
    cols = n_col
    batches = n_batch

    #using numpy array
    A=np.random.rand(n_row,n_col)
    B=np.random.rand(n_col,n_row)

    #settings for all hdf5 files
    atom = tables.Float32Atom() #if store uint8 less memory?
    filters = tables.Filters(complevel=9, complib='blosc') # tune parameters
    Nchunk = 128  # ?
    chunkshape = (Nchunk, Nchunk)
    chunk_multiple = 1
    block_size = chunk_multiple * Nchunk

    #using hdf5
    fileName_C = 'CArray_C.h5'
    shape = (A.shape[0], B.shape[1])

    h5f_C = tables.open_file(fileName_C, 'w')
    C = h5f_C.create_carray(h5f_C.root, 'CArray', atom, shape, chunkshape=chunkshape, filters=filters)

    sz= block_size

    t0= time.time()
    for i in range(0, A.shape[0], sz):
        for j in range(0, B.shape[1], sz):
            for k in range(0, A.shape[1], sz):
                C[i:i+sz,j:j+sz] += np.dot(A[i:i+sz,k:k+sz],B[k:k+sz,j:j+sz])
    print (time.time()-t0)

    h5f_C.close()
def test_hdf5_disk():
    rows = n_row
    cols = n_col
    batches = n_batch

    #settings for all hdf5 files
    atom = tables.Float32Atom() #if store uint8 less memory?
    filters = tables.Filters(complevel=9, complib='blosc') # tune parameters
    Nchunk = 128  # ?
    chunkshape = (Nchunk, Nchunk)
    chunk_multiple = 1
    block_size = chunk_multiple * Nchunk


    fileName_A = 'carray_A.h5'
    shape_A = (n_row*n_batch, n_col)  # predefined size

    h5f_A = tables.open_file(fileName_A, 'w')
    A = h5f_A.create_carray(h5f_A.root, 'CArray', atom, shape_A, chunkshape=chunkshape, filters=filters)

    for i in range(batches):
        data = np.random.rand(n_row, n_col)
        A[i*n_row:(i+1)*n_row]= data[:]

    rows = n_col
    cols = n_row
    batches = n_batch

    fileName_B = 'carray_B.h5'
    shape_B = (rows, cols*batches)  # predefined size

    h5f_B = tables.open_file(fileName_B, 'w')
    B = h5f_B.create_carray(h5f_B.root, 'CArray', atom, shape_B, chunkshape=chunkshape, filters=filters)

    sz= rows/batches
    for i in range(batches):
        data = np.random.rand(sz, cols*batches)
        B[i*sz:(i+1)*sz]= data[:]


    fileName_C = 'CArray_C.h5'
    shape = (A.shape[0], B.shape[1])

    h5f_C = tables.open_file(fileName_C, 'w')
    C = h5f_C.create_carray(h5f_C.root, 'CArray', atom, shape, chunkshape=chunkshape, filters=filters)

    sz= block_size

    t0= time.time()
    for i in range(0, A.shape[0], sz):
        for j in range(0, B.shape[1], sz):
            for k in range(0, A.shape[1], sz):
                C[i:i+sz,j:j+sz] += np.dot(A[i:i+sz,k:k+sz],B[k:k+sz,j:j+sz])
    print (time.time()-t0)

    h5f_A.close()
    h5f_B.close()
    h5f_C.close()
役に立ちましたか?

解決

np.dot にディスパッチ ブラズ いつ

  • numpyはBLAを使用するために編集されています、
  • BLAS実装は実行時に利用できます、
  • データにはDTYPEの1つがあります float32, float64, complex32 また complex64, 、 と
  • データはメモリに適切に揃っています。

それ以外の場合、デフォルトでは、独自の遅いマトリックス乗算ルーチンを使用することになります。

BLAのリンケージを確認します ここ. 。要するに、ファイルがあるかどうかを確認してください _dotblas.so またはnumpyインストールで同様です。あるときは、どのBlasライブラリに対してリンクされているかを確認します。参照BLAは遅く、Atlasは高速で、OpenblasとIntel MKLなどのベンダー固有のバージョンはさらに高速です。マルチスレッドのBLAの実装に気をつけてください うまくプレイしないでください Pythonと multiprocessing.

次に、検査してデータのアライメントを確認します flags あなたの配列の。 1.7.2以前のnumpyのバージョンでは、両方の議論 np.dot C順序である必要があります。 numpy> = 1.7.2では、Fortranアレイの特別なケースが導入されているほど、これはもはや重要ではありません。

>>> X = np.random.randn(10, 4)
>>> Y = np.random.randn(7, 4).T
>>> X.flags
  C_CONTIGUOUS : True
  F_CONTIGUOUS : False
  OWNDATA : True
  WRITEABLE : True
  ALIGNED : True
  UPDATEIFCOPY : False
>>> Y.flags
  C_CONTIGUOUS : False
  F_CONTIGUOUS : True
  OWNDATA : False
  WRITEABLE : True
  ALIGNED : True
  UPDATEIFCOPY : False

あなたのnumpyがBlasに対してリンクされていない場合、それを(簡単)再インストールするか、(ハード)BLAを使用します gemm (一般化されたマトリックスが掛けられます)scipyの関数:

>>> from scipy.linalg import get_blas_funcs
>>> gemm = get_blas_funcs("gemm", [X, Y])
>>> np.all(gemm(1, X, Y) == np.dot(X, Y))
True

これは簡単に見えますが、エラーチェックはほとんどないため、自分が何をしているのか本当に知る必要があります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top