Inference an toàn luồng với các model YOLO#
Để chạy inference Ultralytics YOLO an toàn trên các luồng Python, hãy khởi tạo một model YOLO riêng bên trong mỗi luồng thay vì chia sẻ một instance giữa các luồng. Việc chia sẻ một model duy nhất gây ra race condition, làm hỏng trạng thái nội bộ và tạo ra kết quả khó đoán, vì module threading của Python chạy đồng thời các luồng trên cùng một đối tượng. Hướng dẫn này giải thích vì sao việc chia sẻ không an toàn, trình bày cách thực hiện an toàn với từng luồng riêng và giới thiệu decorator ThreadingLocked cho trường hợp bạn bắt buộc phải chia sẻ một instance.
Chuyển đến phần vì sao chia sẻ model không an toàn, cách làm an toàn cho luồng hoặc decorator ThreadingLocked.
Xem: Cách thực hiện inference an toàn đa luồng với model Ultralytics YOLO trong Python | Multi-threading 🚀
Tìm hiểu về luồng trong Python#
Luồng Python là một dạng song song hóa, cho phép chương trình chạy nhiều thao tác cùng lúc. Tuy nhiên, Global Interpreter Lock (GIL) của Python đồng nghĩa với việc tại một thời điểm chỉ có một luồng thực thi được bytecode Python.
Dù có vẻ đây là một hạn chế, luồng vẫn có thể hỗ trợ xử lý đồng thời, đặc biệt với các thao tác phụ thuộc I/O hoặc các thao tác giải phóng GIL, chẳng hạn như những thao tác do các thư viện C nền tảng của YOLO thực hiện.
Rủi ro khi dùng chung instance model#
Khởi tạo model YOLO bên ngoài các luồng rồi chia sẻ instance đó giữa nhiều luồng có thể dẫn đến race condition, khi 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 có vấn đề khi model hoặc các thành phần của model lưu giữ trạng thái không được thiết kế để an toàn luồng.
Ví dụ không an toàn luồng: Một instance model#
Khi sử dụng luồng trong Python, cần nhận biết các mẫu có thể dẫn đến vấn đề đồng thời. Sau đây là điều bạn nên tránh: chia sẻ một instance model YOLO26 duy nhất giữa nhiều luồng.
# Không an toàn: Chia sẻ một instance model duy nhất giữa các luồng
from threading import Thread
from ultralytics import YOLO
# Khởi tạo model bên ngoài luồng
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)
# # Xử lý kết quả
# Khởi chạy các luồng dùng chung cùng một instance model
Thread(target=predict, args=("image1.jpg",)).start()
Thread(target=predict, args=("image2.jpg",)).start()Trong ví dụ trên, nhiều luồng cùng sử dụng shared_model, điều này có thể dẫn đến kết quả khó đoán vì predict có thể được nhiều luồng thực thi đồng thời.
Ví dụ an toàn: Mỗi luồng có một instance riêng#
Có thể dùng nhiều instance model riêng biệt miễn là mỗi luồng sở hữu instance của mình và không bao giờ chia sẻ instance đó với luồng khác. Việc các instance bên dưới được tạo trước khi khởi chạy luồng không quan trọng — mẫu duy nhất không an toàn là chia sẻ một instance giữa các luồng:
# An toàn: mỗi luồng dùng instance model riêng của mình
from threading import Thread
from ultralytics import YOLO
# Khởi tạo một model cho mỗi luồng
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)
# # Xử lý kết quả
# Mỗi luồng sử dụng một instance model riêng biệt
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 riêng, không có trạng thái model dùng chung để các luồng làm hỏng. Khởi tạo model bên trong từng luồng như minh họa tiếp theo đơn giản là cách dễ nhất để đảm bảo instance không vô tình bị chia sẻ.
Suy luận an toàn luồng#
Để chạy inference an toàn luồng, bạn nên khởi tạo một model YOLO riêng trong mỗi luồng. Cách này đảm bảo mỗi luồng có instance model tách biệt, loại bỏ nguy cơ xảy ra race condition.
Ví dụ an toàn luồng#
Sau đây là cách khởi tạo model YOLO bên trong mỗi luồng để chạy inference song song an toàn:
# An toàn: Khởi tạo một model riêng bên trong mỗi luồng
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)
# # Xử lý kết quả
# # Khởi chạy các luồng, mỗi luồng có một instance model riêng
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 instance YOLO riêng. Cách này ngăn các luồng ảnh hưởng đến trạng thái model của nhau, nhờ đó đảm bảo mỗi luồng chạy inference an toàn và không gây tương tác ngoài dự kiến với các luồng khác.
Sử dụng decorator ThreadingLocked#
Ultralytics cung cấp decorator ThreadingLocked, có thể dùng để đảm bảo các hàm được thực thi an toàn luồng. Decorator này sử dụng khóa để đảm bảo tại mỗi thời điểm chỉ có một luồng thực thi hàm được trang trí.
from ultralytics import YOLO
from ultralytics.utils import ThreadingLocked
# Tạo một instance model
model = YOLO("yolo26n.pt")
# Trang trí hàm dự đoán để đảm bảo an toàn luồng
@ThreadingLocked()
def thread_safe_predict(image_path):
"""Thread-safe prediction using a shared model instance."""
results = model.predict(image_path)
return results
# Giờ đây, bạn có thể gọi hàm này an toàn từ nhiều luồngDecorator ThreadingLocked đặc biệt hữu ích khi bạn cần chia sẻ một instance model giữa các luồng nhưng muốn đảm bảo mỗi lần chỉ có một luồng truy cập instance đó.
Chia sẻ một instance model có khóa tiết kiệm bộ nhớ so với việc tải model trong từng luồng, nhưng giảm tính đồng thời vì các luồng phải lần lượt chờ khóa. Nếu có đủ bộ nhớ và muốn đạt mức song song tối đa, hãy ưu tiên mẫu mỗi luồng một model; nếu bộ nhớ model là nút thắt cổ chai, hãy dùng ThreadingLocked.
Kết luận#
Khi sử dụng model YOLO với threading của Python, hãy cấp cho mỗi luồng một instance model riêng và tuyệt đối không chia sẻ một instance giữa các luồng. Khởi tạo model bên trong luồng sử dụng model là cách đơn giản nhất để đảm bảo điều này, tránh race condition và giữ cho các tác vụ inference đáng tin cậy.
Đối với các kịch bản nâng cao hơn và để tối ưu thêm hiệu năng inference đa luồng, hãy cân nhắc dùng song song hóa dựa trên tiến trình với multiprocessing hoặc sử dụng hàng đợi tác vụ với các tiến trình worker riêng.
Câu hỏi thường gặp#
Để ngăn race condition khi sử dụng model Ultralytics YOLO trong môi trường Python đa luồng, hãy khởi tạo một model YOLO riêng trong mỗi luồng. Cách này đảm bảo mỗi luồng có một instance model tách biệt, tránh việc trạng thái model bị thay đổi đồ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) # # Xử lý kết quả 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ề cách đảm bảo an toàn luồng, hãy truy cập Inference an toàn luồng với các model YOLO.
Để chạy inference model YOLO đa luồng an toàn trong Python, hãy làm theo các phương pháp tốt nhất sau:
- Khởi tạo model YOLO trong từng luồng thay vì chia sẻ một instance model duy nhất giữa các luồng.
- Sử dụng module
multiprocessingcủa Python để xử lý song song, tránh các vấn đề liên quan đến Global Interpreter Lock (GIL). - 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 đồng thời.
- Khi cần tiết kiệm bộ nhớ, hãy cân nhắc dùng decorator
ThreadingLockedcho các instance model được chia sẻ.
Ví dụ khởi tạo model an toàn 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) # # Xử lý kết quả # Khởi chạy nhiều luồng 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, hãy tham khảo phần Inference an toàn luồng.
Mỗi luồng nên có instance model YOLO riêng để tránh race condition. 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ó đoán và làm thay đổi trạng thái nội bộ của model. Dùng các instance riêng biệt giúp cô lập luồng, nhờ đó các tác vụ đa luồng đáng tin cậy và an toàn.
Để xem hướng dẫn chi tiết, hãy tham khảo các phần Ví dụ không an toàn luồng: Một instance model và Ví dụ an toàn luồng.
Global Interpreter Lock (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 năng của các tác vụ đa luồng phụ thuộc CPU. Tuy nhiên, bạn vẫn có thể xử lý đồng thời các thao tác phụ thuộc I/O hoặc các tiến trình dùng thư viện giải phóng GIL, chẳng hạn như các thư viện C nền tảng của YOLO. Để tăng hiệu năng, hãy cân nhắc dùng song song hóa dựa trên tiến trình với module
multiprocessingcủa Python.Để tìm hiểu thêm về luồng trong Python, hãy xem phần Tìm hiểu về luồng trong Python.
Có, sử dụng module
multiprocessingcủa Python an toàn hơn và thường hiệu quả hơn khi chạy inference model YOLO song song. Song song hóa dựa trên tiến trình tạo các không gian bộ nhớ riêng biệt, tránh Global Interpreter Lock (GIL) và giảm nguy cơ gặp vấn đề đồng thời. Mỗi tiến trình hoạt động độc lập với instance model YOLO riêng.Để biết thêm chi tiết về song song hóa dựa trên tiến trình với các model YOLO, hãy tham khảo trang Inference an toàn luồng.