python - sklearn - joblib parallel
¿Qué hace la función delayed()(cuando se usa con joblib en Python) (3)
He leído la documentation , pero no entiendo qué se entiende por: The delayed function is a simple trick to be able to create a tuple (function, args, kwargs) with a function-call syntax.
Lo estoy usando para iterar sobre la lista en la que quiero operar (todas las imágenes) de la siguiente manera:
def joblib_loop():
Parallel(n_jobs=8)(delayed(getHog)(i) for i in allImages)
Esto devuelve mis funciones de HOG, como quiero (y con la ganancia de velocidad usando todos mis 8 núcleos), pero no estoy seguro de lo que realmente está haciendo.
Mi conocimiento de Python está bien en el mejor de los casos, y es muy posible que me esté perdiendo algo básico. Cualquier puntero en la dirección correcta sería más apreciado
De la referencia https://wiki.python.org/moin/ParallelProcessing El objeto Parallel crea un grupo de multiprocesamiento que procesa al intérprete de Python en varios procesos para ejecutar cada uno de los elementos de la lista. La función retardada es un truco simple para poder crear una tupla (función, args, kwargs) con una sintaxis de llamada de función.
Otra cosa que me gustaría sugerir es que, en lugar de definir explícitamente varios núcleos, podemos generalizar así:
import multiprocessing
num_core=multiprocessing.cpu_count()
Entonces, lo que quiere hacer es acumular un conjunto de llamadas a funciones y sus argumentos de tal manera que pueda pasarlas de manera eficiente a un programador / ejecutor. Delayed es un decorator que toma una función y sus argumentos y los envuelve en un objeto que se puede colocar en una lista y se puede desplegar según sea necesario. Dask tiene la misma cosa que utiliza en parte para alimentar su programador gráfico.
Tal vez las cosas se aclaran si observamos lo que sucedería si en lugar de eso simplemente escribiéramos
Parallel(n_jobs=8)(getHog(i) for i in allImages)
De la forma en que funciona Python, getHog(i) for i in allImages
crea una lista en la que cada elemento ya está evaluado . Esto significa que todas getHog
llamadas a getHog
ya han regresado cuando la lista se pasa a su objeto Parallel
, ¡y no queda nada para que Parallel
ejecute en paralelo! Todo el trabajo ya se ha hecho en el hilo en el que estamos ahora, secuencialmente.
Así que tenemos que retrasar la ejecución conservando a.) La función que queremos llamar y la b.) Los argumentos con los que queremos llamar a la función, pero sin ejecutar la función en realidad.
Esto es lo que delayed
convenientemente hace por nosotros con una sintaxis clara. Si queremos "conservar" la llamada foo(2, g=3)
para más adelante, simplemente podemos llamar con delayed(foo)(2, g=3)
y la tupla (foo, [2], {g: 3})
es devuelto, listo para ser ejecutado por otra persona.
Entonces, en su ejemplo, en pocas palabras, sucede lo siguiente.
Ha creado una lista de
delayed(getHog)(i)
Cada uno de esos
delayed(getHog)(i)
devuelve la tupla(function, args, kwargs)
(como leíste en los documentos) que en este caso es la tupla(getHog, [i], {})
Su objeto
Parallel
creado anteriormente crea un nuevo hilo para cada elemento en la lista y distribuye las tuplas a ellos- En cada uno de esos nuevos hilos, ejecuta uno de los elementos de la lista: llama al primer elemento de la tupla con el segundo y el tercer elemento desempaquetado como argumentos
el[0](*el[1], **el[2])
ofunction(*args, **kwargs)
, que en este caso da como resultado la llamadagetHog(i)
.