0

Salut je dois accélérer ce codetraitement parallèle d'une matrice 3D en Python

import numpy as np 
matrix3d=np.empty([10,10,1000]) 
matrix3d[:]=np.random.randint(10) 
matrix3d_1=np.empty([10,10,1000]) 
x=10 
y=1 
for z in range(0,1000): 
    matrix3d_1[:,:,z]=func(matrix3d[:,:,z],x,y) 


def func(matrix,x,y): 
    return matrix*x+y 

J'ai essayé d'utiliser multiprocessig en utilisant Pool.map() mais il ne fonctionne pas.

from functools import partial 
import multiprocessing as mp 

pool=mp.Pool(processes=2) 
args=partial(func,x,y) 
matrix3d_2=np.empty([10,10,1000]) 
matrix3d_2=pool.map(args,matrix3d) 
pool.close() 

Si je compare les deux matrices matrix3d_1==matrix3d_2 les résultats sont faux.

Comment est-ce que ceci peut être fixé?

+2

Est-ce que 'matrix * x + y' est l'implémentation réelle de' func'? – Divakar

+0

Non, 'func' n'est qu'un exemple. En fait j'utilise cette [fonction] (https://stackoverflow.com/questions/26912112/resample-2d-numpy-array-to-arbitrary-dimensions) dans la réponse. Mais je crois qu'il n'y a pas de grande différence. –

+0

Le code que vous ne voulez pas utiliser contient des boucles imbriquées (4). Ceux-ci sont extrêmement lents en python pur. En utilisant simplement un compilateur jit, vous pouvez obtenir plus de 100x accélérer ici. En fonction de votre plate-forme (Python 2.7 et Unix ou Python 3), la parallélisation est généralement très facile à réaliser. C'est beaucoup plus que ce que vous pouvez obtenir de la parallélisation du code python pur avec le multitraitement. Jetez un coup d'oeil à ceci par exemple https://stackoverflow.com/a/45337873/4045774. Votre principale préoccupation est-elle vraiment de faire fonctionner le multitraitement python? – max9111

Répondre

1

traitement en parallèle d'une matrice 3d

La méthode de la carte de python ainsi que la methode de pool.map ne peut avoir un objet d'entrée. Voir par exemple https://stackoverflow.com/a/10973817/4045774

Pour réduire les entrées à une entrée, nous pouvons utiliser par exemple functools. L'entrée qui reste doit être sur la dernière place.

from functools import partial 
import numpy as np 
import multiprocessing as mp 

def main(): 
    matrix3d=np.empty([10,10,1000]) 
    matrix3d[:]=np.random.randint(10) 
    matrix3d_1=np.empty([10,10,1000]) 
    x=10 
    y=1 

    pool=mp.Pool(processes=4) 
    func_p=partial(func,x,y) 

    #parallel map returns a list 
    res=pool.map(func_p,(matrix3d[:,:,z] for z in xrange(0,matrix3d.shape[2]))) 

    #copy the data to array 
    for i in xrange(0,matrix3d.shape[2]): 
     matrix3d_1[:,:,i]=res[i] 

def func(x,y,matrix): 
    return matrix*x+y 

Version parallèle en utilisant numba

Cette version échelle bien sur tous les noyaux et au moins 200 fois plus rapide que multitraitement simples ci-dessus. J'ai modifié le code que vous avez lié à un peu, pour se débarrasser de toutes les dépendances que numpy.

import numpy 
from numba import njit, prange 

nb_meanInterp = njit("float32[:,:](float32[:,:],int64,int64)")(meanInterp) 
resample_3d_nb = njit("float32[:,:,:](float32[:,:,:],int64,int64)",parallel=True)(resample_3d) 

def resample_3d(matrix_3d,x,y): 
    matrix3d_res=numpy.empty((x,y,matrix_3d.shape[2]),dtype=numpy.float32) 
    for z in prange(0,matrix_3d.shape[2]): 
    matrix3d_res[:,:,z]=nb_meanInterp(matrix_3d[:,:,z],x,y) 

    return matrix3d_res 

def meanInterp(data, m, n): 
    newData = numpy.zeros((m,n),dtype=numpy.float32) 
    mOrig, nOrig = data.shape 

    hBoundariesOrig, vBoundariesOrig = numpy.linspace(0,1,mOrig+1), 
numpy.linspace(0,1,nOrig+1) 
    hBoundaries, vBoundaries = numpy.linspace(0,1,m+1), numpy.linspace(0,1,n+1) 


    for iOrig in range(mOrig): 
    for jOrig in range(nOrig): 
     for i in range(m): 
     if hBoundaries[i+1] <= hBoundariesOrig[iOrig]: continue 
     if hBoundaries[i] >= hBoundariesOrig[iOrig+1]: break 
     for j in range(n): 
      if vBoundaries[j+1] <= vBoundariesOrig[jOrig]: continue 
      if vBoundaries[j] >= vBoundariesOrig[jOrig+1]: break 

      #boxCoords = ((hBoundaries[i], vBoundaries[j]),(hBoundaries[i+1], vBoundaries[j+1])) 
      #origBoxCoords = ((hBoundariesOrig[iOrig], vBoundariesOrig[jOrig]),(hBoundariesOrig[iOrig+1], vBoundariesOrig[jOrig+1])) 
      #area=overlap(boxCoords, origBoxCoords) 

      #hopefully this is equivivalent (not tested)----- 
      T_x=(hBoundaries[i],hBoundaries[i+1],hBoundariesOrig[iOrig],hBoundariesOrig[iOrig+1]) 
      T_y=(vBoundaries[j],vBoundaries[j+1],vBoundariesOrig[jOrig],vBoundariesOrig[jOrig+1]) 

      tx=(T_x[1]-T_x[0]+T_x[3]-T_x[2])-(max(T_x)-min(T_x)) 
      ty=(T_y[1]-T_y[0]+T_y[3]-T_y[2])-(max(T_y)-min(T_y)) 

      area=tx*ty 
      #------------------------ 
      newData[i][j] += area * data[iOrig][jOrig]/(hBoundaries[1] * vBoundaries[1]) 

return newData