perf: keep CPU for detection, then document the measured defaults

Detection and classification share the CPU, and leaving both uncapped made them
fight: uncapped torch plus 8 workers measured 11.1 results/s single-client and
dropped to 6.3/s each with two clients. Capping torch at 4 threads and
classifying with 5 workers gives 12.2 results/s single-client (46 ms detection)
and 8.5/s each for two clients, with zero unexplained label changes.

Detection is the part that must stay real-time; classification fills in behind
it, so the defaults now protect detection's share of the CPU. Both remain
overridable (--classify-workers, DORAYAKI_TORCH_THREADS).

docs/API.md records the shipped numbers and says which configuration produced
them, including the honest gap: detection during a live pan is ~46-48 ms, not
the 28 ms of an idle measurement.

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
kiyo9w 2026-09-24 13:36:41 +09:00
parent 4960553254
commit 30c0292ed1
2 changed files with 25 additions and 6 deletions

View file

@ -78,7 +78,8 @@ class EngineSettings:
# and stays available for experiments only (bench_engine.py --compare).
live_inflight: int = 12
imgsz: int = 640
classify_workers: int = 0 # 0 -> max(2, cpu_count - 2)
# 0 -> max(2, cpu_count - 2). Measured default below (see build_default_engine).
classify_workers: int = 5
live_method: str = "hybrid"
live_conf: float = 0.1
detect_conf: float = 0.25
@ -645,6 +646,17 @@ def build_default_engine(settings: Optional[EngineSettings] = None) -> Recogniti
import sys
settings = settings or EngineSettings()
# Detection and classification share the CPU. torch defaults to every core,
# which starves the classification pool (and the pool then slows detection
# back). Measured on the M5: capping torch at 4 threads and classifying with
# 5 workers gave 12.2 results/s single-client (46 ms detect) versus 11.1/s
# (49 ms) uncapped, and 8.5/s each for two clients. Override with
# DORAYAKI_TORCH_THREADS (0 = leave torch's default).
torch_threads = int(os.environ.get("DORAYAKI_TORCH_THREADS", "4") or 0)
if torch_threads > 0:
import torch
torch.set_num_threads(torch_threads)
current_dir = os.path.dirname(os.path.abspath(__file__))
if current_dir not in sys.path:
sys.path.insert(0, current_dir)