Inferencia segura para subprocesos con modelos YOLO#
Para ejecutar la inferencia de Ultralytics YOLO de forma segura entre hilos de Python, instancia un modelo YOLO separado dentro de cada hilo en lugar de compartir una única instancia entre ellos. Compartir un único modelo provoca condiciones de carrera que corrompen su estado interno y producen resultados impredecibles, porque el módulo threading de Python ejecuta los hilos de manera concurrente sobre el mismo objeto. Esta guía explica por qué falla compartirlo, muestra el patrón seguro por hilo y cubre el decorador ThreadingLocked para los casos en los que debas compartir una instancia.
Salta a por qué falla compartir un modelo, al patrón seguro para hilos o al decorador ThreadingLocked.
Watch: How to Perform Thread Safe Inference with Ultralytics YOLO Models in Python | Multi-Threading 🚀
Comprender el uso de subprocesos en Python#
Los subprocesos en Python son una forma de paralelismo que permite que tu programa ejecute varias operaciones a la vez. Sin embargo, el Bloqueo Global del Intérprete (GIL, por sus siglas en inglés) de Python significa que solo un subproceso puede ejecutar código de bytes de Python a la vez.
Aunque esto parece una limitación, los subprocesos aún pueden proporcionar concurrencia, especialmente para operaciones vinculadas a E/S o cuando se utilizan operaciones que liberan el GIL, como las realizadas por las bibliotecas C subyacentes de YOLO.
El peligro de las instancias de modelos compartidas#
Crear una instancia de un modelo YOLO fuera de tus subprocesos y compartir esta instancia entre múltiples subprocesos puede provocar condiciones de carrera, donde el estado interno del modelo se modifica de manera inconsistente debido a accesos concurrentes. Esto es particularmente problemático cuando el modelo o sus componentes mantienen un estado que no está diseñado para ser seguro para subprocesos.
Ejemplo no seguro para subprocesos: instancia de modelo único#
Al utilizar hilos en Python, es importante reconocer los patrones que pueden provocar problemas de concurrencia. Esto es lo que debes evitar: compartir una única instancia del modelo YOLO26 entre varios hilos.
# Unsafe: Sharing a single model instance across threads
from threading import Thread
from ultralytics import YOLO
# Instantiate the model outside the thread
shared_model = YOLO("yolo26n.pt")
def predict(image_path):
"""Predicts objects in an image using a preloaded YOLO model, take path string to image as argument."""
results = shared_model.predict(image_path)
# Process results
# Starting threads that share the same model instance
Thread(target=predict, args=("image1.jpg",)).start()
Thread(target=predict, args=("image2.jpg",)).start()En el ejemplo anterior, el shared_model es utilizado por varios hilos, lo que puede provocar resultados impredecibles porque predict podría ejecutarse simultáneamente por varios hilos.
Ejemplo seguro: una instancia dedicada por hilo#
Varias instancias de modelo por separado funcionan bien siempre que cada hilo sea propietario de su instancia y nunca la comparta con otro hilo. No importa que las instancias siguientes se creen antes de que los hilos comiencen; el único patrón inseguro es compartir una instancia entre hilos:
# Safe: each thread uses its own dedicated model instance
from threading import Thread
from ultralytics import YOLO
# Instantiate one model per thread
model_1 = YOLO("yolo26n.pt")
model_2 = YOLO("yolo26n.pt")
def predict(model, image_path):
"""Runs prediction on an image using a specified YOLO model, returning the results."""
results = model.predict(image_path)
# Process results
# Each thread uses a separate, dedicated model instance
Thread(target=predict, args=(model_1, "image1.jpg")).start()
Thread(target=predict, args=(model_2, "image2.jpg")).start()Debido a que cada hilo trabaja con su propia instancia dedicada, no hay estado de modelo compartido que los hilos puedan corromper. Instanciar el modelo dentro de cada hilo, como se muestra a continuación, es simplemente la forma más fácil de garantizar que una instancia nunca se comparta accidentalmente.
Inferencia segura para subprocesos#
Para realizar una inferencia segura para subprocesos, debes crear una instancia de un modelo YOLO independiente dentro de cada subproceso. Esto garantiza que cada subproceso tenga su propia instancia de modelo aislada, eliminando el riesgo de condiciones de carrera.
Ejemplo seguro para subprocesos#
Aquí tienes cómo crear una instancia de un modelo YOLO dentro de cada subproceso para una inferencia paralela segura:
# Safe: Instantiating a single model inside each thread
from threading import Thread
from ultralytics import YOLO
def thread_safe_predict(image_path):
"""Predict on an image using a new YOLO model instance in a thread-safe manner; takes image path as input."""
local_model = YOLO("yolo26n.pt")
results = local_model.predict(image_path)
# Process results
# Starting threads that each have their own model instance
Thread(target=thread_safe_predict, args=("image1.jpg",)).start()
Thread(target=thread_safe_predict, args=("image2.jpg",)).start()En este ejemplo, cada hilo crea su propia instancia de YOLO. Esto evita que cualquier hilo interfiera con el estado del modelo de otro, garantizando así que cada hilo realice la inferencia de forma segura y sin interacciones inesperadas con los demás hilos.
Uso del decorador ThreadingLocked#
Ultralytics proporciona un decorador ThreadingLocked que se puede utilizar para garantizar la ejecución segura para hilos de las funciones. Este decorador utiliza un bloqueo para garantizar que solo un hilo a la vez pueda ejecutar la función decorada.
from ultralytics import YOLO
from ultralytics.utils import ThreadingLocked
# Create a model instance
model = YOLO("yolo26n.pt")
# Decorate the prediction function to make it thread-safe
@ThreadingLocked()
def thread_safe_predict(image_path):
"""Thread-safe prediction using a shared model instance."""
results = model.predict(image_path)
return results
# Now you can safely call this function from multiple threadsEl decorador ThreadingLocked es especialmente útil cuando necesitas compartir una instancia de modelo entre hilos, pero quieres asegurarte de que solo un hilo pueda acceder a ella a la vez.
Compartir una instancia de modelo bloqueada ahorra memoria en comparación con cargar un modelo en cada hilo, pero reduce la concurrencia porque los hilos se serializan en el bloqueo y esperan su turno. Prefiere el patrón por hilo cuando te sobre memoria y quieras el máximo paralelismo, y recurre a ThreadingLocked cuando la memoria del modelo sea el cuello de botella.
Conclusión#
Cuando utilices modelos YOLO con el threading de Python, dale a cada hilo su propia instancia de modelo dedicada y no compartas nunca una sola instancia entre hilos. Instanciar el modelo dentro del hilo que lo utiliza es la manera más sencilla de garantizar esto, evitando condiciones de carrera y manteniendo tus tareas de inferencia fiables.
Para escenarios más avanzados y para optimizar aún más el rendimiento de tu inferencia multihilo, considera utilizar paralelismo basado en procesos con multiprocessing o aprovechar una cola de tareas con procesos de trabajo dedicados.
FAQ#
¿Cómo puedo evitar las condiciones de carrera al usar modelos YOLO en un entorno Python con múltiples subprocesos?#
Para evitar condiciones de carrera al usar modelos YOLO de Ultralytics en un entorno Python con múltiples subprocesos, crea una instancia de un modelo YOLO independiente dentro de cada subproceso. Esto asegura que cada subproceso tenga su propia instancia de modelo aislada, evitando la modificación concurrente del estado del modelo.
Ejemplo:
from threading import Thread
from ultralytics import YOLO
def thread_safe_predict(image_path):
"""Predict on an image in a thread-safe manner."""
local_model = YOLO("yolo26n.pt")
results = local_model.predict(image_path)
# Process results
Thread(target=thread_safe_predict, args=("image1.jpg",)).start()
Thread(target=thread_safe_predict, args=("image2.jpg",)).start()Para obtener más información sobre cómo garantizar la seguridad de los hilos, visita la sección Thread-Safe Inference with YOLO Models.
¿Cuáles son las mejores prácticas para ejecutar inferencias de modelos YOLO con múltiples subprocesos en Python?#
Para ejecutar la inferencia de modelos YOLO con múltiples subprocesos de forma segura en Python, sigue estas mejores prácticas:
- Crea instancias de los modelos YOLO dentro de cada subproceso en lugar de compartir una única instancia de modelo entre ellos.
- Utiliza el módulo
multiprocessingde Python para el procesamiento en paralelo para evitar problemas relacionados con el bloqueo del intérprete global (GIL). - Recuerda que las bibliotecas C subyacentes de YOLO (PyTorch, OpenCV) liberan automáticamente el GIL durante cálculos pesados, por lo que los hilos aún pueden ejecutar inferencia de forma concurrente.
- Considera usar el decorador
ThreadingLockedpara instancias de modelos compartidos cuando la memoria sea un problema.
Ejemplo para la creación segura de instancias de modelo:
from threading import Thread
from ultralytics import YOLO
def thread_safe_predict(image_path):
"""Runs inference in a thread-safe manner with a new YOLO model instance."""
local_model = YOLO("yolo26n.pt")
results = local_model.predict(image_path)
# Process results
# Initiate multiple threads
Thread(target=thread_safe_predict, args=("image1.jpg",)).start()
Thread(target=thread_safe_predict, args=("image2.jpg",)).start()Para obtener contexto adicional, consulta la sección sobre Thread-Safe Inference.
¿Por qué cada subproceso debería tener su propia instancia de modelo YOLO?#
Cada subproceso debe tener su propia instancia de modelo YOLO para evitar condiciones de carrera. Cuando se comparte una única instancia de modelo entre varios subprocesos, los accesos concurrentes pueden provocar un comportamiento impredecible y modificaciones del estado interno del modelo. Al utilizar instancias separadas, garantizas el aislamiento de los subprocesos, haciendo que tus tareas con múltiples subprocesos sean fiables y seguras.
Para obtener una guía detallada, consulta las secciones Non-Thread-Safe Example: Single Model Instance y Thread-Safe Example.
¿Cómo afecta el Bloqueo Global del Intérprete (GIL) de Python a la inferencia de modelos YOLO?#
El bloqueo del intérprete global (GIL) de Python permite que un solo hilo ejecute código de bytes de Python a la vez, lo que puede limitar el rendimiento de las tareas multihilo vinculadas a la CPU. Sin embargo, para operaciones vinculadas a E/S o procesos que utilizan bibliotecas que liberan el GIL, como las bibliotecas de C subyacentes de YOLO, aún puedes lograr concurrencia. Para un rendimiento mejorado, considera usar el paralelismo basado en procesos con el módulo multiprocessing de Python.
Para obtener más información sobre el uso de hilos en Python, consulta la sección Understanding Python Threading.
¿Es más seguro usar paralelismo basado en procesos en lugar de subprocesos para la inferencia de modelos YOLO?#
Sí, utilizar el módulo multiprocessing de Python es más seguro y a menudo más eficiente para ejecutar la inferencia del modelo YOLO en paralelo. El paralelismo basado en procesos crea espacios de memoria separados, evitando el bloqueo del intérprete global (GIL) y reduciendo el riesgo de problemas de concurrencia. Cada proceso funcionará de forma independiente con su propia instancia del modelo YOLO.
Para más detalles sobre el paralelismo basado en procesos con modelos YOLO, consulta la página sobre Thread-Safe Inference.