ML Engineering 101: Una explicación detallada del error “El trabajador del cargador de datos (pid(s) xxx) salió inesperadamente” |  de Mengliu Zhao |  junio de 2024

Mejores prácticas de multiprocesamiento de Torch.

Sin embargo, la memoria virtual es sólo una cara de la historia. ¿Qué pasa si el problema no desaparece después de ajustar el disco de intercambio?

La otra cara de la historia son los problemas subyacentes del módulo de multiprocesamiento torch. Hay una serie de recomendaciones de mejores prácticas en la página web oficial:

Pero además de estos, se deben considerar tres enfoques más, especialmente en lo que respecta al uso de la memoria.

Lo primero es la pérdida de memoria compartida.. La fuga significa que la memoria no se libera correctamente después de cada ejecución del trabajador secundario y observará este fenómeno cuando supervise el uso de la memoria virtual en tiempo de ejecución. El consumo de memoria seguirá aumentando y llegará al punto de quedarse “sin memoria”. Esta es una pérdida de memoria muy típica.

Entonces, ¿qué causará la fuga?

Echemos un vistazo a la clase DataLoader en sí:

https://github.com/pytorch/pytorch/blob/main/torch/utils/data/dataloader.py

Mirando debajo del capó de DataLoader, veremos que cuando nums_worker > 0, se llama a _MultiProcessingDataLoaderIter. Dentro de _MultiProcessingDataLoaderIter, Torch.multiprocessing crea la cola de trabajadores. Torch.multiprocessing utiliza dos estrategias diferentes para compartir memoria y almacenar en caché: descriptor_archivo y sistema_archivos. Mientras sistema_archivos No requiere almacenamiento en caché de descriptores de archivos, es propenso a sufrir pérdidas de memoria compartida.

Para comprobar qué estrategia de uso compartido está utilizando su máquina, simplemente agregue el script:

torch.multiprocessing.get_sharing_strategy()

Para obtener el límite de descriptores de archivos de su sistema (Linux), ejecute el siguiente comando en la terminal:

ulimit -n

Para cambiar su estrategia para compartir a descriptor de archivo:

torch.multiprocessing.set_sharing_strategy(‘file_descriptor’)

Para contar la cantidad de descriptores de archivos abiertos, ejecute el siguiente comando:

ls /proc/self/fd | wc -l

Mientras el sistema lo permita, el descriptor_archivo Se recomienda la estrategia.

El segundo es el método de inicio del trabajador multiprocesamiento. En pocas palabras, es el debate sobre si se debe utilizar una bifurcación o un spawn como método de inicio de trabajadores. Fork es la forma predeterminada de iniciar el multiprocesamiento en Linux y puede evitar la copia de ciertos archivos, por lo que es mucho más rápido, pero puede tener problemas para manejar tensores CUDA y bibliotecas de terceros como OpenCV en su DataLoader.

Para usar el método spawn, simplemente puedes pasar el argumento contexto_multiprocesamiento= “Aparecer”. al cargador de datos.

Tres, hacer que los objetos del conjunto de datos sean seleccionables/serializables

Hay una publicación muy agradable que analiza más a fondo el efecto de “copia en lectura” para el plegado de procesos: https://ppwwyyxx.com/blog/2022/Demystify-RAM-Usage-in-Multiprocess-DataLoader/

En pocas palabras, es ya no es un buen enfoque para crear una lista de nombres de archivos y cargarlos en el método __getitem__. Cree una matriz numpy o un marco de datos panda para almacenar la lista de nombres de archivos con fines de serialización. Y si está familiarizado con HuggingFace, usar un CSV/marco de datos es la forma recomendada de cargar un conjunto de datos local: https://huggingface.co/docs/datasets/v2.19.0/en/package_reference/loading_methods#datasets.load_dataset.example-2