Ultralytics YOLO27:
Get Started

Inferência segura para threads com modelos YOLO#

Para executar inferências do Ultralytics YOLO com segurança em threads Python, instancia um modelo YOLO separado dentro de cada thread, em vez de partilhar uma única instância entre elas. Partilhar um único modelo causa condições de corrida que corrompem o seu estado interno e produzem resultados imprevisíveis, pois o módulo threading do Python executa as threads em simultâneo sobre o mesmo objeto. Este guia explica por que motivo a partilha falha, mostra o padrão seguro com uma instância por thread e aborda o decorador ThreadingLocked para os casos em que é necessário partilhar uma instância.

Vai diretamente para o motivo pelo qual a partilha de um modelo falha, o padrão seguro para threads ou o decorador ThreadingLocked.



Assista: Como executar inferência thread-safe com modelos Ultralytics YOLO em Python | Multithreading 🚀

Compreender as threads do Python#

As threads do Python são uma forma de paralelismo que permite ao teu programa executar várias operações ao mesmo tempo. No entanto, o Bloqueio Global do Interpretador (GIL) do Python significa que apenas uma thread pode executar bytecode Python de cada vez.

Single-thread vs multi-thread inference

Embora isto pareça uma limitação, as threads ainda podem proporcionar concorrência, sobretudo em operações limitadas por E/S ou quando se usam operações que libertam o GIL, como as executadas pelas bibliotecas C subjacentes ao YOLO.

O perigo de partilhar instâncias de modelos#

Instanciar um modelo YOLO fora das tuas threads e partilhar essa instância entre várias threads pode causar condições de corrida, nas quais o estado interno do modelo é modificado de forma inconsistente devido a acessos simultâneos. Isto é especialmente problemático quando o modelo ou os seus componentes mantêm um estado que não foi concebido para ser seguro para threads.

Exemplo não seguro para threads: uma única instância de modelo#

Ao usar threads em Python, é importante reconhecer os padrões que podem causar problemas de concorrência. Eis o que deves evitar: partilhar uma única instância do modelo YOLO26 entre várias threads.

# Inseguro: partilhar uma única instância de modelo entre threads
from threading import Thread

from ultralytics import YOLO

# Instanciar o modelo fora da 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)
    # Processa os resultados

# Iniciar threads que partilham a mesma instância de modelo
Thread(target=predict, args=("image1.jpg",)).start()
Thread(target=predict, args=("image2.jpg",)).start()

No exemplo acima, várias threads usam shared_model, o que pode produzir resultados imprevisíveis, pois predict pode ser executado simultaneamente por várias threads.

Exemplo seguro: uma instância dedicada por thread#

É seguro ter várias instâncias de modelo separadas, desde que cada thread seja proprietária da sua instância e nunca a partilhe com outra thread. Não importa que as instâncias abaixo sejam criadas antes de as threads começarem — o único padrão inseguro é partilhar uma instância entre threads:

# Seguro: cada thread usa a sua própria instância de modelo dedicada
from threading import Thread

from ultralytics import YOLO

# Instanciar um modelo por 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)
    # Processa os resultados

# Cada thread usa uma instância de modelo separada e dedicada
Thread(target=predict, args=(model_1, "image1.jpg")).start()
Thread(target=predict, args=(model_2, "image2.jpg")).start()

Como cada thread trabalha com a sua própria instância dedicada, não há estado de modelo partilhado que as threads possam corromper. Instanciar o modelo dentro de cada thread, como mostrado a seguir, é simplesmente a forma mais fácil de garantir que uma instância nunca é partilhada acidentalmente.

Inferência segura para threads#

Para executar inferências seguras para threads, deves instanciar um modelo YOLO separado dentro de cada thread. Assim, cada thread terá a sua própria instância de modelo isolada, eliminando o risco de condições de corrida.

Exemplo seguro para threads#

Eis como instanciar um modelo YOLO dentro de cada thread para executar inferências paralelas com segurança:

# Seguro: instanciar um único modelo dentro de cada 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)
    # Processa os resultados

# Inicia threads, cada uma com sua própria instância do modelo
Thread(target=thread_safe_predict, args=("image1.jpg",)).start()
Thread(target=thread_safe_predict, args=("image2.jpg",)).start()

Neste exemplo, cada thread cria a sua própria instância YOLO. Isto impede que uma thread interfira com o estado do modelo de outra e garante que cada thread executa inferências com segurança e sem interações inesperadas com as outras threads.

Usar o decorador ThreadingLocked#

A Ultralytics fornece um decorador ThreadingLocked que pode ser usado para garantir a execução segura para threads de funções. Este decorador usa um bloqueio para garantir que apenas uma thread de cada vez pode executar a função decorada.

from ultralytics import YOLO
from ultralytics.utils import ThreadingLocked

# Criar uma instância de modelo
model = YOLO("yolo26n.pt")

# Aplicar o decorador à função de previsão para a tornar segura para threads
@ThreadingLocked()
def thread_safe_predict(image_path):
    """Thread-safe prediction using a shared model instance."""
    results = model.predict(image_path)
    return results

# Agora podes chamar esta função com segurança a partir de várias threads

O decorador ThreadingLocked é particularmente útil quando precisas de partilhar uma instância de modelo entre threads, mas queres garantir que apenas uma thread pode aceder à instância de cada vez.

Equilíbrio entre memória e concorrência

Partilhar uma instância de modelo protegida por bloqueio poupa memória em comparação com carregar um modelo em cada thread, mas reduz a concorrência, porque as threads ficam serializadas pelo bloqueio e aguardam a sua vez. Prefere o padrão de uma instância por thread quando tiveres memória disponível e quiseres o máximo paralelismo; usa ThreadingLocked quando a memória do modelo for o fator limitante.

Conclusão#

Ao usar modelos YOLO com threading do Python, atribui a cada thread a sua própria instância de modelo dedicada e nunca partilhes uma instância entre threads. Instanciar o modelo dentro da thread que o utiliza é a forma mais simples de garantir isso, evitar condições de corrida e manter a fiabilidade das tarefas de inferência.

Para cenários mais avançados e para otimizar ainda mais o desempenho das inferências multithread, considera usar paralelismo baseado em processos com multiprocessing ou recorrer a uma fila de tarefas com processos de trabalho dedicados.

Perguntas frequentes#

  • Para evitar condições de corrida ao usar modelos Ultralytics YOLO num ambiente Python multithread, instancia um modelo YOLO separado dentro de cada thread. Assim, cada thread terá a sua própria instância de modelo isolada, evitando modificações simultâneas do estado do modelo.

    Exemplo:

    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)
        # Processa os resultados
    
    Thread(target=thread_safe_predict, args=("image1.jpg",)).start()
    Thread(target=thread_safe_predict, args=("image2.jpg",)).start()

    Para mais informações sobre como garantir a segurança das threads, visita Inferência segura para threads com modelos YOLO.

  • Para executar inferências multithread com modelos YOLO em Python com segurança, segue estas práticas recomendadas:

    1. Instancia modelos YOLO dentro de cada thread, em vez de partilhar uma única instância entre threads.
    2. Usa o módulo multiprocessing do Python para processamento paralelo e evita problemas relacionados com o Bloqueio Global do Interpretador (GIL).
    3. Lembra-te de que as bibliotecas C subjacentes ao YOLO (PyTorch, OpenCV) libertam automaticamente o GIL durante cálculos intensivos, pelo que as threads ainda podem executar inferências em simultâneo.
    4. Considera usar o decorador ThreadingLocked para instâncias de modelos partilhadas quando a memória for uma preocupação.

    Exemplo de instanciação de modelo segura para threads:

    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)
        # Processa os resultados
    
    # Iniciar várias threads
    Thread(target=thread_safe_predict, args=("image1.jpg",)).start()
    Thread(target=thread_safe_predict, args=("image2.jpg",)).start()

    Para mais contexto, consulta a secção sobre inferência segura para threads.

  • Cada thread deve ter a sua própria instância de modelo YOLO para evitar condições de corrida. Quando uma única instância de modelo é partilhada entre várias threads, os acessos simultâneos podem causar um comportamento imprevisível e modificar o estado interno do modelo. Ao usar instâncias separadas, garantes o isolamento entre threads e tornas as tarefas multithread fiáveis e seguras.

    Para obter orientações detalhadas, consulta as secções Exemplo não seguro para threads: uma única instância de modelo e Exemplo seguro para threads.

  • O Bloqueio Global do Interpretador (GIL) do Python permite que apenas uma thread execute bytecode Python de cada vez, o que pode limitar o desempenho de tarefas multithread limitadas pela CPU. No entanto, ainda é possível obter concorrência em operações limitadas por E/S ou em processos que usam bibliotecas que libertam o GIL, como as bibliotecas C subjacentes ao YOLO. Para melhorar o desempenho, considera usar paralelismo baseado em processos com o módulo multiprocessing do Python.

    Para saber mais sobre threads em Python, consulta a secção Compreender as threads do Python.

  • Sim, usar o módulo multiprocessing do Python é mais seguro e muitas vezes mais eficiente para executar inferências com modelos YOLO em paralelo. O paralelismo baseado em processos cria espaços de memória separados, evitando o Bloqueio Global do Interpretador (GIL) e reduzindo o risco de problemas de concorrência. Cada processo funciona de forma independente e tem a sua própria instância de modelo YOLO.

    Para mais informações sobre paralelismo baseado em processos com modelos YOLO, consulta a página sobre inferência segura para threads.

Comentários