YOLO Vision 2026:

Suy luận an toàn đa luồng với các model YOLO#

Để chạy inference của Ultralytics YOLO một cách an toàn giữa các luồng Python, hãy khởi tạo một model YOLO riêng biệt bên trong mỗi luồng thay vì chia sẻ một instance duy nhất giữa chúng. Việc chia sẻ một model duy nhất gây ra hiện tượng race condition làm hỏng trạng thái bên trong của nó và tạo ra các kết quả khó đoán, bởi vì module threading của Python chạy các luồng đồng thời trên cùng một đối tượng. Hướng dẫn này giải thích lý do tại sao việc chia sẻ thất bại, minh họa mẫu an toàn cho mỗi luồng, và đề cập đến decorator ThreadingLocked cho các trường hợp bắt buộc phải chia sẻ một instance.

Chuyển đến phần tại sao việc chia sẻ model lại thất bại, mô hình an toàn luồng, hoặc decorator ThreadingLocked.



Watch: How to Perform Thread Safe Inference with Ultralytics YOLO Models in Python | Multi-Threading 🚀

Tìm hiểu về cơ chế đa luồng (Threading) trong Python#

Các luồng (threads) trong Python là một dạng song song cho phép chương trình của bạn thực thi nhiều tác vụ cùng một lúc. Tuy nhiên, Global Interpreter Lock (GIL) của Python có nghĩa là tại mỗi thời điểm chỉ có một luồng có thể thực thi bytecode của Python.

Single-thread vs multi-thread inference

Mặc dù điều này nghe có vẻ là một hạn chế, nhưng các luồng vẫn có thể cung cấp tính đồng thời (concurrency), đặc biệt là đối với các tác vụ liên quan đến I/O hoặc khi sử dụng các tác vụ giải phóng GIL, chẳng hạn như các tác vụ được thực hiện bởi các thư viện C nền tảng của YOLO.

Sự nguy hiểm của việc chia sẻ instance model#

Việc khởi tạo một model YOLO bên ngoài các luồng và chia sẻ instance này giữa nhiều luồng có thể dẫn đến điều kiện tranh đua (race conditions), nơi trạng thái nội bộ của model bị thay đổi không nhất quán do các truy cập đồng thời. Điều này đặc biệt gây vấn đề khi model hoặc các thành phần của nó nắm giữ trạng thái không được thiết kế để hoạt động an toàn trong môi trường đa luồng.

Ví dụ không an toàn về luồng: Sử dụng chung một instance model#

Khi sử dụng các luồng trong Python, điều quan trọng là nhận biết các mô hình có thể dẫn đến vấn đề đồng thời. Dưới đây là những gì bạn nên tránh: chia sẻ một instance model YOLO26 duy nhất trên nhiều luồng.

# 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()

Trong ví dụ trên, shared_model được sử dụng bởi nhiều luồng, điều này có thể dẫn đến kết quả khó đoán vì predict có thể bị thực thi đồng thời bởi nhiều luồng.

Ví dụ an toàn: Một Instance riêng biệt cho mỗi luồng#

Nhiều instance model riêng biệt là giải pháp tốt miễn là mỗi luồng sở hữu instance của riêng mình và không bao giờ chia sẻ nó với luồng khác. Việc các instance dưới đây được tạo trước khi các luồng bắt đầu không thành vấn đề — mẫu thiết kế duy nhất không an toàn là chia sẻ một instance trên các luồng:

# 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()

Vì mỗi luồng làm việc với instance chuyên biệt của riêng nó, nên không có trạng thái model dùng chung nào để các luồng có thể làm hỏng. Việc khởi tạo model bên trong mỗi luồng, như được hiển thị tiếp theo, đơn giản là cách dễ nhất để đảm bảo rằng một instance không bao giờ vô tình bị chia sẻ.

Suy luận an toàn với đa luồng#

Để thực hiện suy luận an toàn với đa luồng, bạn nên khởi tạo một model YOLO riêng biệt bên trong mỗi luồng. Điều này đảm bảo rằng mỗi luồng có instance model cô lập của riêng mình, loại bỏ rủi ro về điều kiện tranh đua.

Ví dụ an toàn với đa luồng#

Đây là cách khởi tạo một model YOLO bên trong mỗi luồng để suy luận song song an toàn:

# 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()

Trong ví dụ này, mỗi luồng tạo ra instance YOLO của riêng nó. Điều này ngăn chặn việc bất kỳ luồng nào làm ảnh hưởng đến trạng thái model của luồng khác, từ đó đảm bảo rằng mỗi luồng thực hiện inference một cách an toàn và không có các tương tác bất ngờ với các luồng khác.

Sử dụng Decorator ThreadingLocked#

Ultralytics cung cấp một decorator ThreadingLocked có thể được sử dụng để đảm bảo việc thực thi các hàm một cách an toàn theo luồng (thread-safe). Decorator này sử dụng một khóa (lock) để đảm bảo rằng chỉ có một luồng tại một thời điểm có thể thực thi hàm được gắn decorator.

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 threads

Decorator ThreadingLocked đặc biệt hữu ích khi bạn cần chia sẻ một instance model qua các luồng nhưng muốn đảm bảo rằng chỉ có một luồng có thể truy cập nó tại một thời điểm.

Đánh đổi giữa bộ nhớ và tính đồng thời

Việc chia sẻ một instance model được khóa tiết kiệm bộ nhớ so với việc tải model trong mọi luồng, nhưng nó làm giảm tính đồng thời vì các luồng xếp hàng tuần tự dựa trên khóa và chờ lượt của mình. Hãy ưu tiên mô hình theo từng luồng khi bạn có dư dả bộ nhớ và muốn đạt mức song song hóa tối đa, đồng thời sử dụng ThreadingLocked khi bộ nhớ model là điểm nghẽn.

Kết luận#

Khi sử dụng các model YOLO với threading của Python, hãy cung cấp cho mỗi luồng một instance model riêng biệt và tuyệt đối không chia sẻ một instance qua các luồng. Việc khởi tạo model bên trong luồng sử dụng nó là cách đơn giản nhất để đảm bảo điều này, tránh các điều kiện tranh chấp và giữ cho các tác vụ inference của bạn đáng tin cậy.

Đối với các kịch bản nâng cao hơn và để tối ưu hóa hơn nữa hiệu suất inference đa luồng của bạn, hãy cân nhắc sử dụng tính song song dựa trên tiến trình với multiprocessing hoặc tận dụng hàng đợi tác vụ với các tiến trình worker chuyên dụng.

Câu hỏi thường gặp#

Làm thế nào tôi có thể tránh các điều kiện tranh đua khi sử dụng các model YOLO trong môi trường Python đa luồng?#

Để ngăn chặn các điều kiện tranh đua khi sử dụng các model Ultralytics YOLO trong môi trường Python đa luồng, hãy khởi tạo một model YOLO riêng biệt bên trong mỗi luồng. Điều này đảm bảo mỗi luồng có instance model cô lập của riêng mình, tránh việc thay đổi trạng thái model đồng thời.

Ví dụ:

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()

Để biết thêm thông tin về việc đảm bảo tính an toàn luồng, hãy truy cập Thread-Safe Inference with YOLO Models.

Đâu là các phương pháp tốt nhất để chạy suy luận model YOLO đa luồng trong Python?#

Để chạy suy luận model YOLO đa luồng một cách an toàn trong Python, hãy tuân thủ các phương pháp tốt nhất sau đây:

  1. Khởi tạo các model YOLO bên trong mỗi luồng thay vì chia sẻ một instance model duy nhất giữa các luồng.
  2. Sử dụng module multiprocessing của Python để xử lý song song nhằm tránh các vấn đề liên quan đến Khóa Thông dịch viên Toàn cục (Global Interpreter Lock - GIL).
  3. Hãy nhớ rằng các thư viện C nền tảng của YOLO (PyTorch, OpenCV) tự động giải phóng GIL trong quá trình tính toán nặng, vì vậy các luồng vẫn có thể chạy inference một cách đồng thời.
  4. Cân nhắc sử dụng decorator ThreadingLocked cho các instance model được chia sẻ khi bộ nhớ là vấn đề cần quan tâm.

Ví dụ về việc khởi tạo model an toàn với luồng:

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()

Để có thêm bối cảnh, hãy tham khảo phần về Thread-Safe Inference.

Tại sao mỗi luồng nên có instance model YOLO riêng?#

Mỗi luồng nên có instance model YOLO riêng để ngăn chặn các điều kiện tranh đua. Khi một instance model duy nhất được chia sẻ giữa nhiều luồng, các truy cập đồng thời có thể dẫn đến hành vi không dự đoán trước và thay đổi trạng thái nội bộ của model. Bằng cách sử dụng các instance riêng biệt, bạn đảm bảo sự cô lập luồng, giúp các tác vụ đa luồng của bạn đáng tin cậy và an toàn.

Để được hướng dẫn chi tiết, hãy xem các phần Non-Thread-Safe Example: Single Model InstanceThread-Safe Example.

Global Interpreter Lock (GIL) của Python ảnh hưởng như thế nào đến việc suy luận model YOLO?#

Khóa Thông dịch viên Toàn cục (GIL) của Python chỉ cho phép một luồng thực thi bytecode Python tại một thời điểm, điều này có thể hạn chế hiệu suất của các tác vụ đa luồng gắn liền với CPU (CPU-bound). Tuy nhiên, đối với các hoạt động gắn liền với I/O (I/O-bound) hoặc các tiến trình sử dụng các thư viện giải phóng GIL, giống như các thư viện C nền tảng của YOLO, bạn vẫn có thể đạt được tính đồng thời. Để nâng cao hiệu suất, hãy cân nhắc sử dụng tính song song dựa trên tiến trình với module multiprocessing của Python.

Để biết thêm về luồng trong Python, hãy xem phần Understanding Python Threading.

Liệu sử dụng tính song song dựa trên tiến trình có an toàn hơn so với luồng cho suy luận model YOLO?#

Có, việc sử dụng module multiprocessing của Python an toàn hơn và thường hiệu quả hơn để chạy inference model YOLO song song. Tính song song dựa trên tiến trình tạo ra các không gian bộ nhớ riêng biệt, tránh được Khóa Thông dịch viên Toàn cục (GIL) và giảm nguy cơ gặp các vấn đề đồng thời. Mỗi tiến trình sẽ hoạt động độc lập với instance model YOLO của riêng nó.

Để biết thêm chi tiết về tính song song dựa trên tiến trình với các model YOLO, hãy tham khảo trang về Thread-Safe Inference.

Bình luận