로컬 whisper STT 사이드카 디바이스 폴백과 deprecated audioop 제거
cuDNN 부재 환경에서 ctranslate2 는 Python 예외가 아니라 네이티브 크래시로 죽어 프로세스가 통째로 사라진다. 같은 프로세스의 try/except 로는 절대 잡을 수 없어 디바이스 확인을 버릴 수 있는 자식 프로세스(--self-check)로 분리했다. auto 는 CUDA 프로브 실패 시 CPU(int8)로 폴백하고, 명시적 --device cuda 는 조용히 강등하지 않는다. 함께 고친 것: - warmup PCM 생성의 연산자 우선순위 버그(b"\x00\x00" * N // 2 가 바이트열 정수 나눗셈이 되어 TypeError). warmup_pcm() 으로 분리하고 테스트로 고정했다. - audioop 은 Python 3.13 에서 제거되므로 array + 정수 연산으로 RMS 를 직접 구한다. 실측(저장소 무참조 synthetic seed 8.72초, CPU int8 small): interim 9 · final 5 · word timestamp 12개 present, 전사는 원문과 한 글자 차이. 사이드카 회귀 37/37.
This commit is contained in:
parent
16e791e044
commit
05aa7b312e
9 changed files with 252 additions and 30 deletions
|
|
@ -326,42 +326,72 @@ class _FakeTranscriberFactory:
|
|||
|
||||
|
||||
class TranscriberBuildTest(unittest.TestCase):
|
||||
def test_auto_falls_back_to_cpu_when_cuda_warmup_fails(self) -> None:
|
||||
"""cuDNN 부재처럼 '장치는 보이지만 추론이 죽는' 경우를 잡는다."""
|
||||
def test_auto_falls_back_to_cpu_when_the_cuda_probe_fails(self) -> None:
|
||||
"""cuDNN 부재는 네이티브 크래시라 자식 프로세스 프로브로만 잡힌다."""
|
||||
|
||||
factory = _FakeTranscriberFactory()
|
||||
probes: list[tuple[str, str]] = []
|
||||
|
||||
def prober(model: str, device: str) -> bool:
|
||||
probes.append((model, device))
|
||||
return False
|
||||
|
||||
factory = _FakeTranscriberFactory(failing_device="cuda")
|
||||
transcriber = MODULE.build_transcriber(
|
||||
"small", "auto", factory=factory, cuda_available=True
|
||||
"small", "auto", factory=factory, cuda_available=True, prober=prober
|
||||
)
|
||||
self.assertEqual(probes, [("small", "cuda")])
|
||||
self.assertEqual(transcriber.device, "cpu")
|
||||
self.assertEqual(transcriber.compute_type, "int8")
|
||||
self.assertEqual(
|
||||
factory.built, [("small", "cuda", "float16"), ("small", "cpu", "int8")]
|
||||
)
|
||||
# CUDA 로는 아예 모델을 올리지 않는다. 올렸다면 그 자리에서 죽는다.
|
||||
self.assertEqual(factory.built, [("small", "cpu", "int8")])
|
||||
|
||||
def test_auto_keeps_cuda_when_warmup_succeeds(self) -> None:
|
||||
def test_auto_keeps_cuda_when_the_probe_succeeds(self) -> None:
|
||||
factory = _FakeTranscriberFactory()
|
||||
transcriber = MODULE.build_transcriber(
|
||||
"small", "auto", factory=factory, cuda_available=True
|
||||
"small",
|
||||
"auto",
|
||||
factory=factory,
|
||||
cuda_available=True,
|
||||
prober=lambda model, device: True,
|
||||
)
|
||||
self.assertEqual(transcriber.device, "cuda")
|
||||
self.assertEqual(len(factory.built), 1)
|
||||
|
||||
def test_explicit_cuda_never_downgrades_silently(self) -> None:
|
||||
factory = _FakeTranscriberFactory(failing_device="cuda")
|
||||
with self.assertRaises(MODULE.TranscriptionError):
|
||||
MODULE.build_transcriber(
|
||||
"small", "cuda", factory=factory, cuda_available=True
|
||||
)
|
||||
self.assertEqual(factory.built, [("small", "cuda", "float16")])
|
||||
|
||||
def test_cpu_warmup_failure_is_not_retried(self) -> None:
|
||||
def test_explicit_cuda_never_downgrades_silently(self) -> None:
|
||||
factory = _FakeTranscriberFactory()
|
||||
with self.assertRaises(MODULE.TranscriptionError):
|
||||
MODULE.build_transcriber(
|
||||
"small",
|
||||
"cuda",
|
||||
factory=factory,
|
||||
cuda_available=True,
|
||||
prober=lambda model, device: False,
|
||||
)
|
||||
self.assertEqual(factory.built, [])
|
||||
|
||||
def test_cpu_path_is_not_probed(self) -> None:
|
||||
factory = _FakeTranscriberFactory()
|
||||
probes: list[tuple[str, str]] = []
|
||||
MODULE.build_transcriber(
|
||||
"small",
|
||||
"cpu",
|
||||
factory=factory,
|
||||
cuda_available=True,
|
||||
prober=lambda model, device: probes.append((model, device)) or True,
|
||||
)
|
||||
self.assertEqual(probes, [])
|
||||
self.assertEqual(factory.built, [("small", "cpu", "int8")])
|
||||
|
||||
def test_python_level_warmup_failure_still_fails_closed(self) -> None:
|
||||
factory = _FakeTranscriberFactory(failing_device="cpu")
|
||||
with self.assertRaises(MODULE.TranscriptionError):
|
||||
MODULE.build_transcriber(
|
||||
"small", "auto", factory=factory, cuda_available=False
|
||||
"small",
|
||||
"auto",
|
||||
factory=factory,
|
||||
cuda_available=False,
|
||||
prober=lambda model, device: True,
|
||||
)
|
||||
self.assertEqual(factory.built, [("small", "cpu", "int8")])
|
||||
|
||||
|
||||
class CliTest(unittest.TestCase):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue