跳转至内容

使用 YOLO 模型进行线程安全推理

在多线程环境中运行 YOLO 模型需要仔细考虑,以确保线程安全。Python 的 threading 模块允许您同时运行多个线程,但当涉及到在这些线程中使用 YOLO 模型时,有一些重要的安全问题需要注意。本页将指导您创建线程安全的 YOLO 模型推理。



观看: 如何在 python 中使用 Ultralytics YOLO 模型执行线程安全推理 | 多线程 🚀

理解 Python 线程

Python 线程是一种并行形式,允许您的程序一次运行多个操作。但是,Python 的全局解释器锁 (GIL) 意味着一次只能执行一个 Python 字节码。

单线程与多线程示例

虽然这听起来像是一个限制,但线程仍然可以提供并发性,特别是对于 I/O 密集型操作,或者当使用释放 GIL 的操作时,例如 YOLO 的底层 C 库执行的操作。

共享模型实例的风险

在线程外部实例化 YOLO 模型并在多个线程之间共享此实例可能会导致竞争条件,其中模型的内部状态由于并发访问而被不一致地修改。当模型或其组件保持并非设计为线程安全的状态时,这尤其成问题。

非线程安全示例:单个模型实例

在 python 中使用线程时,重要的是要识别可能导致并发问题的模式。以下是您应该避免的情况:在多个线程之间共享单个 YOLO 模型实例。

# 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("yolo11n.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()

在上面的例子中, shared_model 被多个线程使用,这可能会导致不可预测的结果,因为 predict 可以由多个线程同时执行。

非线程安全示例:多个模型实例

类似地,这是一个包含多个 YOLO 模型实例的不安全模式:

# Unsafe: Sharing multiple model instances across threads can still lead to issues
from threading import Thread

from ultralytics import YOLO

# Instantiate multiple models outside the thread
shared_model_1 = YOLO("yolo11n_1.pt")
shared_model_2 = YOLO("yolo11n_2.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


# Starting threads with individual model instances
Thread(target=predict, args=(shared_model_1, "image1.jpg")).start()
Thread(target=predict, args=(shared_model_2, "image2.jpg")).start()

即使存在两个独立的模型实例,仍然存在并发问题的风险。如果 YOLO 不是线程安全的,使用单独的实例可能无法防止竞争条件,特别是如果这些实例共享任何非线程本地的底层资源或状态。

线程安全推理

要执行线程安全推理,您应该在每个线程中实例化一个单独的 YOLO 模型。这确保了每个线程都有其自己隔离的模型实例,从而消除了出现竞争条件的风险。

线程安全示例

以下是如何在每个线程中实例化 YOLO 模型以实现安全的并行推理:

# 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("yolo11n.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()

在此示例中,每个线程都创建了自己的 YOLO 实例。这可以防止任何线程干扰另一个线程的模型状态,从而确保每个线程安全地执行推理,并且不会与其他线程发生意外交互。

使用 ThreadingLocked 装饰器

Ultralytics 提供了一个 ThreadingLocked 装饰器,可用于确保函数的线程安全执行。此装饰器使用锁来确保一次只有一个线程可以执行被装饰的函数。

from ultralytics import YOLO
from ultralytics.utils import ThreadingLocked

# Create a model instance
model = YOLO("yolo11n.pt")


# Decorate the predict method 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

字段 ThreadingLocked 装饰器在需要在线程之间共享模型实例,但又希望确保一次只有一个线程可以访问它时特别有用。与为每个线程创建一个新的模型实例相比,这种方法可以节省内存,但可能会降低并发性,因为线程需要等待锁被释放。

结论

当将 YOLO 模型与 python 的 threading,始终在使用模型的线程中实例化模型,以确保线程安全。这种做法可以避免竞争条件,并确保推理任务可靠运行。

对于更高级的场景,并进一步优化您的多线程推理性能,请考虑使用基于进程的并行处理(使用 multiprocessing)或利用具有专用工作进程的任务队列。

常见问题

在多线程 python 环境中使用 YOLO 模型时,如何避免竞争条件?

为了防止在多线程 python 环境中使用 Ultralytics YOLO 模型时出现竞争条件,请在每个线程中实例化一个单独的 YOLO 模型。这确保了每个线程都有其自己隔离的模型实例,从而避免了模型状态的并发修改。

例子:

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("yolo11n.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()

有关确保线程安全的更多信息,请访问使用 YOLO 模型进行线程安全推理

在 Python 中运行多线程 YOLO 模型推理的最佳实践是什么?

为了在 Python 中安全地运行多线程 YOLO 模型推理,请遵循以下最佳实践:

  1. 在每个线程中实例化 YOLO 模型,而不是在线程之间共享单个模型实例。
  2. 使用 python 的 multiprocessing 模块进行并行处理,以避免与全局解释器锁 (GIL) 相关的问题。
  3. 通过使用 YOLO 底层 C 库执行的操作来释放 GIL。
  4. 考虑使用 ThreadingLocked 装饰器,用于在关注内存时共享模型实例。

线程安全模型实例化示例:

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."""
    model = YOLO("yolo11n.pt")
    results = 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()

有关其他上下文,请参阅关于线程安全推理的部分。

为什么每个线程都应该有自己的 YOLO 模型实例?

每个线程应有自己的 YOLO 模型实例,以防止出现竞争条件。当多个线程共享一个模型实例时,并发访问可能导致不可预测的行为和模型内部状态的修改。通过使用单独的实例,您可以确保线程隔离,从而使您的多线程任务可靠且安全。

有关详细指导,请查看非线程安全示例:单个模型实例线程安全示例部分。

Python 的全局解释器锁(GIL)如何影响 YOLO 模型推理?

Python 的全局解释器锁 (GIL) 允许一次只执行一个 Python 字节码,这会限制 CPU 密集型多线程任务的性能。但是,对于 I/O 密集型操作或使用释放 GIL 的库(如 YOLO 的底层 C 库)的进程,您仍然可以实现并发。为了提高性能,请考虑使用 Python 的 multiprocessing 模块。

有关 python 中线程的更多信息,请参阅理解 Python 线程部分。

对于 YOLO 模型推理,使用基于进程的并行处理是否比线程更安全?

是的,使用 python 的 multiprocessing 模块对于并行运行 YOLO 模型推理更安全,通常也更有效。基于进程的并行处理创建单独的内存空间,避免了全局解释器锁 (GIL),并降低了并发问题的风险。每个进程将使用其自己的 YOLO 模型实例独立运行。

有关使用YOLO模型进行基于进程的并行处理的更多详细信息,请参阅关于线程安全推理的页面。



📅 创建于 1 年前 ✏️ 更新于 3 个月前

评论