Comment obtenir un code plus rapide que numpy.dot pour la multiplication de matrices?
Ici La multiplication de matrice à l'aide de hdf5 - je utiliser hdf5 (pytables) pour la multiplication de matrice, mais j'ai été surpris parce que l'utilisation de hdf5 il fonctionne encore plus rapide, puis à l'aide de la plaine de numpy.dot et de stocker des matrices dans la mémoire RAM, ce qui est la raison de ce comportement?
Et peut-être il ya une plus rapide de la fonction de multiplication de matrice en python, parce que j'ai toujours utiliser numpy.point de petit bloc de multiplication de matrice.
voici un code:
Assumer les matrices peuvent tenir en mémoire: essai sur la matrice 10*1000 x 1000.
Par défaut à l'aide de numpy(je pense que personne ne BLAS lib).
Plaine les tableaux numpy sont dans la mémoire de travail: temps 9.48
Si A,B dans la RAM, C sur le disque: le temps de 1,48
Si A,B,C sur le disque: le temps 372.25
Si je utiliser numpy avec MKL résultats sont: 0.15,0.45,43.5.
Résultats semble raisonnable, mais je ne comprends toujours pas pourquoi dans le 1er cas bloquer la multiplication est plus rapide(quand nous magasin A,B dans la 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()
source d'informationauteur mrgloom
Vous devez vous connecter pour publier un commentaire.
np.dot
distribue à BLAS quandfloat32
float64
complex32
oucomplex64
etSinon, la valeur par défaut à l'aide de son propre, lent, de la multiplication de matrice de routine.
La vérification de votre BLAS de liaison est décrite ici. En bref, vérifier s'il existe un fichier
_dotblas.so
ou similaire dans votre NumPy installation. Quand il l'est, vérifier BLAS bibliothèque c'est lié à l'encontre de; la référence BLAS est lent, ATLAS est rapide, OpenBLAS et le fournisseur des versions spécifiques tels que Intel MKL sont encore plus rapide. Attention avec multithread BLAS implémentations comme ils ne jouent pas bien avec Pythonmultiprocessing
.Ensuite, vérifiez votre alignement des données par l'inspection de l'
flags
de vos tableaux. Dans les versions de NumPy avant 1.7.2, les deux arguments denp.dot
doit être C-commandé. Dans NumPy >= 1.7.2, ce n'est pas grave autant plus que des cas particuliers pour Fortran tableaux ont été introduites.Si votre NumPy est pas lié à l'encontre de BLAS, soit (facile) à le ré-installer, ou (dur) utiliser le BLAS
gemm
(généralisée de la matrice de multiplication) de la fonction de SciPy:Cela semble facile, mais il n'a pratiquement aucun contrôle d'erreur, de sorte que vous devez vraiment savoir ce que vous faites.
Il semble numpy.dot n'est pas égal à blas de gemv/gemm, voici l'expérience:
Je ne sais pas pourquoi, pouvait-on me montrer comment la construction d'un BLAS fonction est égale à numpy.dot