Sto cercando di capire come velocizzare una funzione Python che usa numpy. L'output che ho ricevuto da lineprofiler è sotto, e questo dimostra che la maggior parte del tempo viene speso sulla linea ind_y, ind_x = np.where(seg_image == i)
.Accelera numpy.where per l'estrazione di segmenti interi?
seg_image
è un array intero che è il risultato del segmentare un'immagine, trovando quindi i pixel dove seg_image == i
estrae uno specifico oggetto segmentato. Sto eseguendo il looping di molti di questi oggetti (nel codice qui sotto sto solo eseguendo il ciclo 5 per il test, ma eseguirò un ciclo di oltre 20.000) e ci vorrà molto tempo per essere eseguito!
Esiste un modo per velocizzare la chiamata np.where
? O, in alternativa, che la penultima riga (che prende anche una buona parte del tempo) può essere accelerata?
La soluzione ideale sarebbe quella di eseguire il codice sull'intera matrice in una volta, piuttosto che in loop, ma non penso che questo sia possibile in quanto vi sono effetti collaterali ad alcune delle funzioni che devo eseguire (per Ad esempio, la dilatazione di un oggetto segmentato può renderlo "collide" con la regione successiva e quindi fornire risultati errati in seguito).
Qualcuno ha qualche idea?
Line # Hits Time Per Hit % Time Line Contents
==============================================================
5 def correct_hot(hot_image, seg_image):
6 1 239810 239810.0 2.3 new_hot = hot_image.copy()
7 1 572966 572966.0 5.5 sign = np.zeros_like(hot_image) + 1
8 1 67565 67565.0 0.6 sign[:,:] = 1
9 1 1257867 1257867.0 12.1 sign[hot_image > 0] = -1
10
11 1 150 150.0 0.0 s_elem = np.ones((3, 3))
12
13 #for i in xrange(1,seg_image.max()+1):
14 6 57 9.5 0.0 for i in range(1,6):
15 5 6092775 1218555.0 58.5 ind_y, ind_x = np.where(seg_image == i)
16
17 # Get the average HOT value of the object (really simple!)
18 5 2408 481.6 0.0 obj_avg = hot_image[ind_y, ind_x].mean()
19
20 5 333 66.6 0.0 miny = np.min(ind_y)
21
22 5 162 32.4 0.0 minx = np.min(ind_x)
23
24
25 5 369 73.8 0.0 new_ind_x = ind_x - minx + 3
26 5 113 22.6 0.0 new_ind_y = ind_y - miny + 3
27
28 5 211 42.2 0.0 maxy = np.max(new_ind_y)
29 5 143 28.6 0.0 maxx = np.max(new_ind_x)
30
31 # 7 is + 1 to deal with the zero-based indexing, + 2 * 3 to deal with the 3 cell padding above
32 5 217 43.4 0.0 obj = np.zeros((maxy+7, maxx+7))
33
34 5 158 31.6 0.0 obj[new_ind_y, new_ind_x] = 1
35
36 5 2482 496.4 0.0 dilated = ndimage.binary_dilation(obj, s_elem)
37 5 1370 274.0 0.0 border = mahotas.borders(dilated)
38
39 5 122 24.4 0.0 border = np.logical_and(border, dilated)
40
41 5 355 71.0 0.0 border_ind_y, border_ind_x = np.where(border == 1)
42 5 136 27.2 0.0 border_ind_y = border_ind_y + miny - 3
43 5 123 24.6 0.0 border_ind_x = border_ind_x + minx - 3
44
45 5 645 129.0 0.0 border_avg = hot_image[border_ind_y, border_ind_x].mean()
46
47 5 2167729 433545.8 20.8 new_hot[seg_image == i] = (new_hot[ind_y, ind_x] + (sign[ind_y, ind_x] * np.abs(obj_avg - border_avg)))
48 5 10179 2035.8 0.1 print obj_avg, border_avg
49
50 1 4 4.0 0.0 return new_hot
Questo è meraviglioso, fantastico e sorprendente - grazie! La prima volta che l'ho eseguito ho scoperto che era in realtà più lento del mio codice originale, ma poi ho modificato parte del codice in modo che facesse tutto il lavoro (dilatazione, bordi, ecc.) In un piccolo array piuttosto che nell'array enorme - modificando come è stato calcolato new_shape. Ora ho avuto un enorme aumento di velocità. Su una delle immagini con cui sto lavorando, la vecchia versione impiegava due ore e mezza, la nuova versione impiegava 11 secondi! – robintw
Oops! Sì, sembra che l'espressione del generatore debba essere 'new_shape = tuple (dim + 6 per dim in hot_image_view.shape)', e non 'new_shape = tuple (dim + 6 per dim in hot_image.shape)'. È quello che hai cambiato? Per favore, sentiti libero di modificare la mia risposta per riflettere il codice di lavoro. – Jaime