es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Usar el multiprocessing con la decodificación de AllenNLP es lento en comparación con el caso sin multiprocessing.

Estoy utilizando el modelo de identificación de roles semánticos AllenNLP (versión 2.6) para procesar una gran cantidad de oraciones. Mi versión de Python es 3.7.9 y estoy en MacOS 11.6.1. Mi objetivo es utilizar multiprocessing.Pool para paralelizar el trabajo, pero las llamadas a través del grupo tardan más tiempo de lo que lo hacen en el proceso principal, a veces de manera considerable.

En el proceso principal, he colocado explícitamente el modelo en memoria compartida de la siguiente manera:

from allennlp.predictors import Predictor
from allennlp.models.archival import loadarchive
import allennlpmodels.structuredprediction.predictors.srl
PREDICTORPATH = "...<ruta del="" modelo="" srl="">..."

archive = loadarchive(PREDICTORPATH)
archive.model.sharememory()
PREDICTOR = Predictor.fromarchive(archive)

Sé que el modelo se está cargando solo una vez, en el proceso principal. Y coloco el modelo en memoria compartida tanto si voy a utilizar el grupo como si no. Estoy utilizando torch.multiprocessing, como recomiendan muchos, y estoy utilizando el método de inicio “spawn”.

Llamo al predictor en el grupo utilizando Pool.apply_async y estoy midiendo las llamadas dentro de los procesos secundarios. Sé que el grupo está utilizando las CPU disponibles (tengo seis núcleos), y no estoy cerca de quedarme sin memoria física, por lo que no hay motivo para que los procesos secundarios se intercambien al disco.

Esto es lo que sucede, para un lote de 395 oraciones:

Sin multiprocessing: 638 segundos de procesamiento total (y tiempo transcurrido).
Con un grupo de 4 procesos: 293 segundos de tiempo transcurrido, 915 segundos de procesamiento total.
Con un grupo de 12 procesos: 263 segundos de tiempo transcurrido, 2024 segundos de procesamiento total.

Cuanto más procesos, peor es el tiempo total de procesamiento de AllenNLP, aunque el modelo esté explícitamente en memoria compartida, y lo único que cruza el límite de proceso durante la invocación es el texto de entrada y el JSON de salida.

He realizado algunas pruebas de perfilación y lo primero que me llama la atención es que la función torch._C._nn.linear está tardando significativamente más en los casos de multiprocesamiento. Esta función recibe dos tensores como argumentos, pero no se están pasando tensores a través del límite de proceso, y estoy descodificando, no capacitando, por lo que el modelo debería ser completamente de solo lectura. Parece que tiene que ser un problema con el bloqueo o la competencia por el recurso compartido del modelo, pero no entiendo en absoluto por qué sería así. Y no soy un programador de pytorch, por lo que mi comprensión de lo que está sucediendo es limitada.

Se agradecerían cualquier indicación o sugerencia.

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Estoy utilizando el modelo de etiquetado semántico AllenNLP (versión 2.6) para procesar una gran cantidad de oraciones. Mi versión de Python es 3.7.9. Estoy en MacOS 11.6.1. Mi objetivo es utilizar multiprocessing.Pool para paralelizar el trabajo, pero las llamadas a través del pool están tardando más que en el proceso padre, a veces sustancialmente.

    En el proceso padre, he colocado explícitamente el modelo en memoria compartida de la siguiente manera:

    from allennlp.predictors import Predictor
    from allennlp.models.archival import loadarchive
    import allennlpmodels.structuredprediction.predictors.srl
    PREDICTORPATH = "......"
    
    archive = loadarchive(PREDICTORPATH)
    archive.model.sharememory()
    PREDICTOR = Predictor.fromarchive(archive)
    

    Sé que el modelo solo se carga una vez, en el proceso padre. Y coloco el modelo en memoria compartida tanto si voy a utilizar el pool como si no. Estoy utilizando torch.multiprocessing, como recomiendan muchos, y estoy utilizando el método de inicio spawn.

    Llamo al predictor en el pool utilizando Pool.apply_async, y cronometro las llamadas dentro de los procesos secundarios. Sé que el pool está utilizando las CPU disponibles (tengo seis núcleos), y no estoy cerca de quedarme sin memoria física, por lo que no hay razón para que los procesos secundarios se intercambien en el disco.

    Esto es lo que sucede, para un lote de 395 oraciones:

    Sin multiprocessing: 638 segundos de procesamiento total (y tiempo transcurrido).
    Con un pool de 4 procesos: tiempo transcurrido de 293 segundos, 915 segundos de procesamiento total.
    Con un pool de 12 procesos: 263 segundos de tiempo transcurrido, 2024 segundos de procesamiento total.

    Cuanto más procesos, peor es el tiempo total de procesamiento de AllenNLP, incluso aunque el modelo se coloca explícitamente en memoria compartida, y lo único que cruza el límite de proceso durante la invocación es el texto de entrada y el JSON de salida.

    He hecho algunas pruebas de análisis, y lo primero que llama mi atención es que la función torch._C._nn.linear está tardando significativamente más en los casos de multiprocessing. Esta función toma dos tensores como argumentos, pero no se están pasando tensores a través del límite de proceso, y estoy decodificando, no entrenando, por lo que el modelo debería ser completamente de solo lectura. Parece que debe tratarse de un problema de bloqueo o competencia por el recurso de modelo compartido, pero no entiendo en absoluto por qué sería así. Y no soy un programador de torch, por lo que mi comprensión de lo que está sucediendo es limitada.

    Se agradecen cualquier sugerencia o consejo.

Comments are closed.