Add Edge TPU subprocess probe to safely detect segfaults
Probes the Edge TPU in a subprocess before loading — catches segfaults (libedgetpu ABI mismatch on Debian Trixie/Python 3.13) and falls back to CPU automatically. No more service crashes on Coral incompatibility. When the runtime is eventually fixed, Edge TPU will be used automatically with no config changes needed. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -469,8 +469,8 @@ async def startup():
|
|||||||
edgetpu_model_path = model_dir / "yamnet_edgetpu.tflite"
|
edgetpu_model_path = model_dir / "yamnet_edgetpu.tflite"
|
||||||
model_path = model_dir / "yamnet.tflite"
|
model_path = model_dir / "yamnet.tflite"
|
||||||
class_map_path = model_dir / "yamnet_class_map.csv"
|
class_map_path = model_dir / "yamnet_class_map.csv"
|
||||||
# Edge TPU opt-in via env var (segfaults with some libedgetpu versions)
|
# Auto-detect Edge TPU — probe in subprocess catches segfaults safely
|
||||||
use_edgetpu = os.environ.get("USE_EDGETPU", "").lower() in ("1", "true", "yes") and edgetpu_model_path.exists()
|
use_edgetpu = edgetpu_model_path.exists()
|
||||||
active_model = edgetpu_model_path if use_edgetpu else model_path
|
active_model = edgetpu_model_path if use_edgetpu else model_path
|
||||||
if active_model.exists() and class_map_path.exists():
|
if active_model.exists() and class_map_path.exists():
|
||||||
try:
|
try:
|
||||||
|
|||||||
32
sound_id.py
32
sound_id.py
@@ -85,6 +85,29 @@ CATEGORY_GROUPS = {
|
|||||||
|
|
||||||
|
|
||||||
class SoundClassifier:
|
class SoundClassifier:
|
||||||
|
@staticmethod
|
||||||
|
def _probe_edgetpu(model_path: str) -> bool:
|
||||||
|
"""Test Edge TPU in a subprocess to catch segfaults safely."""
|
||||||
|
import subprocess, sys
|
||||||
|
try:
|
||||||
|
result = subprocess.run(
|
||||||
|
[sys.executable, "-c",
|
||||||
|
"import ai_edge_litert.interpreter as tfl; "
|
||||||
|
f"d = tfl.load_delegate('libedgetpu.so.1'); "
|
||||||
|
f"i = tfl.Interpreter(model_path='{model_path}', experimental_delegates=[d]); "
|
||||||
|
"i.allocate_tensors(); "
|
||||||
|
"print('ok')"],
|
||||||
|
capture_output=True, text=True, timeout=10
|
||||||
|
)
|
||||||
|
if result.returncode == 0 and "ok" in result.stdout:
|
||||||
|
logger.info("Edge TPU probe: OK")
|
||||||
|
return True
|
||||||
|
logger.warning("Edge TPU probe failed: %s", result.stderr.strip() or f"exit {result.returncode}")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning("Edge TPU probe error: %s", e)
|
||||||
|
return False
|
||||||
|
|
||||||
def __init__(self, model_path, class_map_path, use_edgetpu=False):
|
def __init__(self, model_path, class_map_path, use_edgetpu=False):
|
||||||
# Load class names
|
# Load class names
|
||||||
self._class_names = []
|
self._class_names = []
|
||||||
@@ -105,6 +128,7 @@ class SoundClassifier:
|
|||||||
import ai_edge_litert.interpreter as tfl
|
import ai_edge_litert.interpreter as tfl
|
||||||
|
|
||||||
if use_edgetpu:
|
if use_edgetpu:
|
||||||
|
if self._probe_edgetpu(model_path):
|
||||||
delegate = tfl.load_delegate("libedgetpu.so.1")
|
delegate = tfl.load_delegate("libedgetpu.so.1")
|
||||||
self._interp = tfl.Interpreter(
|
self._interp = tfl.Interpreter(
|
||||||
model_path=str(model_path),
|
model_path=str(model_path),
|
||||||
@@ -112,7 +136,13 @@ class SoundClassifier:
|
|||||||
)
|
)
|
||||||
logger.info("YAMNet loaded on Edge TPU")
|
logger.info("YAMNet loaded on Edge TPU")
|
||||||
else:
|
else:
|
||||||
self._interp = tfl.Interpreter(model_path=str(model_path))
|
logger.warning("Edge TPU probe failed (segfault or error) — falling back to CPU")
|
||||||
|
use_edgetpu = False
|
||||||
|
|
||||||
|
if not use_edgetpu:
|
||||||
|
# Use CPU model (swap edgetpu model path for CPU model if needed)
|
||||||
|
cpu_path = str(model_path).replace("_edgetpu.tflite", ".tflite")
|
||||||
|
self._interp = tfl.Interpreter(model_path=cpu_path)
|
||||||
logger.info("YAMNet loaded on CPU")
|
logger.info("YAMNet loaded on CPU")
|
||||||
|
|
||||||
self._interp.allocate_tensors()
|
self._interp.allocate_tensors()
|
||||||
|
|||||||
Reference in New Issue
Block a user