Inferencia segura para subprocesos con modelos YOLO#
Para ejecutar inferencias de Ultralytics YOLO de forma segura en varios subprocesos de Python, crea una instancia independiente del modelo YOLO dentro de cada subproceso, en lugar de compartir una instancia entre ellos. Compartir un único modelo provoca condiciones de carrera que corrompen su estado interno y generan resultados impredecibles, porque el módulo threading de Python ejecuta los subprocesos simultáneamente sobre el mismo objeto. Esta guía explica por qué falla el uso compartido, muestra el patrón seguro por subproceso y presenta el decorador ThreadingLocked para los casos en los que tengas que compartir una instancia.
Ve directamente a por qué falla compartir un modelo, al patrón seguro para subprocesos o al decorador ThreadingLocked.
Ver: Cómo realizar inferencias seguras para subprocesos con modelos Ultralytics YOLO en Python | Multihilo 🚀
Introducción a los subprocesos de Python#
Los subprocesos de 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) de Python significa que solo se puede ejecutar bytecode de Python en un subproceso cada vez.
Aunque pueda parecer una limitación, los subprocesos pueden proporcionar concurrencia, sobre todo en operaciones limitadas por la E/S o al utilizar operaciones que liberan el GIL, como las que realizan las bibliotecas C subyacentes de YOLO.
El peligro de compartir instancias de modelos#
Crear una instancia de un modelo YOLO fuera de los subprocesos y compartirla entre varios puede provocar condiciones de carrera, en las que el estado interno del modelo se modifica de forma incoherente debido a accesos simultáneos. Esto resulta especialmente 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: una sola instancia de modelo#
Al utilizar subprocesos 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 subprocesos.
# # Inseguro: compartir una única instancia de modelo entre subprocesos
from threading import Thread
from ultralytics import YOLO
# # Crear una instancia del modelo fuera del subproceso
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)
# Procesa los resultados
# # Iniciar subprocesos que comparten la misma instancia de modelo
Thread(target=predict, args=("image1.jpg",)).start()
Thread(target=predict, args=("image2.jpg",)).start()En el ejemplo anterior, varios subprocesos utilizan shared_model, lo que puede generar resultados impredecibles porque varios subprocesos podrían ejecutar predict simultáneamente.
Ejemplo seguro: una instancia dedicada por subproceso#
Puedes utilizar varias instancias de modelo independientes siempre que cada subproceso sea propietario de su instancia y no la comparta nunca con otro subproceso. No importa que las instancias de abajo se creen antes de iniciar los subprocesos: el único patrón inseguro es compartir una instancia entre subprocesos:
# # Seguro: cada subproceso utiliza su propia instancia de modelo dedicada
from threading import Thread
from ultralytics import YOLO
# # Crear un modelo por subproceso
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)
# Procesa los resultados
# # Cada subproceso utiliza una instancia de modelo independiente y dedicada
Thread(target=predict, args=(model_1, "image1.jpg")).start()
Thread(target=predict, args=(model_2, "image2.jpg")).start()Como cada subproceso trabaja con su propia instancia dedicada, no hay un estado de modelo compartido que los subprocesos puedan corromper. Crear la instancia del modelo dentro de cada subproceso, como se muestra a continuación, es simplemente la forma más sencilla de garantizar que nunca se comparta una instancia por accidente.
Inferencia segura para subprocesos#
Para realizar inferencias seguras para subprocesos, crea una instancia de un modelo YOLO independiente dentro de cada subproceso. Así te aseguras de que cada subproceso tenga su propia instancia aislada del modelo y eliminas el riesgo de condiciones de carrera.
Ejemplo seguro para subprocesos#
Así puedes crear una instancia de un modelo YOLO dentro de cada subproceso para ejecutar inferencias en paralelo de forma segura:
# # Seguro: crear una única instancia de modelo dentro de cada subproceso
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)
# Procesa los resultados
# Inicia subprocesos, cada uno con su propia instancia del modelo
Thread(target=thread_safe_predict, args=("image1.jpg",)).start()
Thread(target=thread_safe_predict, args=("image2.jpg",)).start()En este ejemplo, cada subproceso crea su propia instancia de YOLO. Así se evita que un subproceso interfiera con el estado del modelo de otro y se garantiza que cada uno realice inferencias de forma segura, sin interacciones inesperadas con los demás.
Uso del decorador ThreadingLocked#
Ultralytics proporciona un decorador ThreadingLocked que puedes utilizar para garantizar que las funciones se ejecuten de forma segura para subprocesos. Este decorador utiliza un bloqueo para garantizar que solo se ejecute la función decorada en un subproceso cada vez.
from ultralytics import YOLO
from ultralytics.utils import ThreadingLocked
# # Crear una instancia del modelo
model = YOLO("yolo26n.pt")
# # Aplicar el decorador a la función de predicción para que sea segura para subprocesos
@ThreadingLocked()
def thread_safe_predict(image_path):
"""Thread-safe prediction using a shared model instance."""
results = model.predict(image_path)
return results
# # Ahora puedes llamar a esta función de forma segura desde varios subprocesosEl decorador ThreadingLocked resulta especialmente útil cuando necesitas compartir una instancia de modelo entre subprocesos, pero quieres garantizar que solo un subproceso pueda acceder a ella cada vez.
Compartir una instancia de modelo bloqueada ahorra memoria frente a cargar un modelo en cada subproceso, pero reduce la concurrencia porque los subprocesos se serializan al usar el bloqueo y esperan su turno. Elige el patrón por subproceso si tienes memoria disponible y quieres el máximo paralelismo; recurre a ThreadingLocked cuando la memoria del modelo sea el factor limitante.
Conclusión#
Al utilizar modelos YOLO con threading de Python, asigna a cada subproceso su propia instancia de modelo dedicada y no compartas nunca una instancia entre subprocesos. Crear el modelo dentro del subproceso que lo utiliza es la forma más sencilla de garantizarlo, evitar condiciones de carrera y mantener la fiabilidad de las tareas de inferencia.
Para escenarios más avanzados y para optimizar aún más el rendimiento de las inferencias multiproceso, plantéate utilizar el paralelismo basado en procesos con multiprocessing o una cola de tareas con procesos de trabajo dedicados.
Preguntas frecuentes#
Para evitar condiciones de carrera al utilizar modelos Ultralytics YOLO en un entorno Python multiproceso, crea una instancia de un modelo YOLO independiente dentro de cada subproceso. Así te aseguras de que cada subproceso tenga su propia instancia aislada del modelo y evitas que varios subprocesos modifiquen su estado simultáneamente.
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) # Procesa los resultados 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 para subprocesos, visita la guía sobre inferencia segura para subprocesos con modelos YOLO.
Para ejecutar inferencias de modelos YOLO multiproceso de forma segura en Python, sigue estas prácticas recomendadas:
- Crea instancias de modelos YOLO dentro de cada subproceso en lugar de compartir una sola instancia entre varios subprocesos.
- Utiliza el módulo
multiprocessingde Python para el procesamiento en paralelo y evitar problemas relacionados con el bloqueo global del intérprete (GIL). - Ten en cuenta que las bibliotecas C subyacentes de YOLO (PyTorch, OpenCV) liberan automáticamente el GIL durante los cálculos intensivos, por lo que los subprocesos pueden seguir ejecutando inferencias simultáneamente.
- Si te preocupa el consumo de memoria, plantéate utilizar el decorador
ThreadingLockedpara las instancias de modelos compartidas.
Ejemplo de creación de instancias de modelo segura para subprocesos:
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) # Procesa los resultados # # Iniciar varios subprocesos Thread(target=thread_safe_predict, args=("image1.jpg",)).start() Thread(target=thread_safe_predict, args=("image2.jpg",)).start()Para obtener más información, consulta la sección sobre inferencias seguras para subprocesos.
Cada subproceso debería tener su propia instancia de modelo YOLO para evitar condiciones de carrera. Cuando se comparte una sola instancia de modelo entre varios subprocesos, los accesos simultáneos pueden provocar un comportamiento impredecible y modificar el estado interno del modelo. Al utilizar instancias independientes, garantizas el aislamiento entre subprocesos, lo que hace que tus tareas multiproceso sean fiables y seguras.
Para obtener instrucciones detalladas, consulta las secciones Ejemplo no seguro para subprocesos: una sola instancia de modelo y Ejemplo seguro para subprocesos.
El bloqueo global del intérprete (GIL) de Python solo permite que un subproceso ejecute bytecode de Python cada vez, lo que puede limitar el rendimiento de las tareas multiproceso limitadas por la CPU. Sin embargo, puedes conseguir concurrencia en operaciones limitadas por la E/S o en procesos que utilizan bibliotecas que liberan el GIL, como las bibliotecas C subyacentes de YOLO. Para mejorar el rendimiento, plantéate utilizar el paralelismo basado en procesos con el módulo
multiprocessingde Python.Para obtener más información sobre los subprocesos en Python, consulta la sección Introducción a los subprocesos de Python.
Sí, utilizar el módulo
multiprocessingde Python es más seguro y, a menudo, más eficiente para ejecutar inferencias de modelos YOLO en paralelo. El paralelismo basado en procesos crea espacios de memoria independientes, evita el bloqueo global del intérprete (GIL) y reduce el riesgo de problemas de concurrencia. Cada proceso funciona de forma independiente con su propia instancia de modelo YOLO.Para obtener más información sobre el paralelismo basado en procesos con modelos YOLO, consulta la página sobre inferencias seguras para subprocesos.