From 987d8eec2970da75842d5c00974f1a074fc339bf Mon Sep 17 00:00:00 2001 From: soubarnak Date: Fri, 6 Nov 2026 09:00:47 +0530 Subject: [PATCH] fix(models): use ticket 19 measured peaks for ladder thresholds q8_0 threshold becomes 1644 MiB (1132+512) and q5_0 becomes 1358 MiB (846+512) per the recorded baseline recommendation, replacing the on-disk-size proxies. Tests pin the measured values and the 1644/1358 boundaries. --- .../speech_recognition/model_ladder.py | 23 +++++++------ tests/test_model_ladder.py | 32 +++++++++++++------ 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/vocalinux/speech_recognition/model_ladder.py b/src/vocalinux/speech_recognition/model_ladder.py index 68a090a..681940e 100644 --- a/src/vocalinux/speech_recognition/model_ladder.py +++ b/src/vocalinux/speech_recognition/model_ladder.py @@ -8,13 +8,12 @@ Rungs (quantized Turbo first, small floor last):: large-v3-turbo-q8_0 -> large-v3-turbo-q5_0 -> small.en / small -Thresholds derive from the catalog on-disk sizes (874/574 MiB) plus the -512 MiB desktop headroom from the locked baseline protocol -(``scripts/measure_perf_baseline.py::recommend_thresholds``). Ticket #19 -recorded no measured per-rung footprints, so these are size-plus-headroom -proxies: recalibrate them from hardware numbers when they land. The -derivation is pinned by ``tests/test_model_ladder.py`` so a catalog size -bump forces a threshold review. +Thresholds derive from ticket #19's measured transcribe peaks (1132 MiB +for q8_0, 846 MiB for q5_0) plus the 512 MiB desktop headroom from the +locked baseline protocol +(``scripts/measure_perf_baseline.py::recommend_thresholds``). The +derivation is pinned by ``tests/test_model_ladder.py`` so a re-measure +forces a threshold review. Backend order follows the same readiness rule: CUDA ranks before Vulkan only when a complete architecture-matching CUDA toolkit is installed @@ -40,14 +39,14 @@ LADDER_RUNGS: tuple[str, ...] = (DEFAULT_RUNG, LOW_MEMORY_RUNG) #: the baseline protocol adds to measured footprints. HEADROOM_MIB: float = 512.0 -#: Catalog on-disk sizes (MiB) the thresholds below are derived from. -_Q8_0_SIZE_MIB: float = 874.0 -_Q5_0_SIZE_MIB: float = 574.0 +#: Ticket #19 measured transcribe peaks (MiB) the thresholds below derive from. +_MEASURED_Q8_0_PEAK_MIB: float = 1132.0 +_MEASURED_Q5_0_PEAK_MIB: float = 846.0 #: Free memory at or above this keeps the default q8_0 rung. -PREFER_Q8_0_ABOVE_MIB: float = _Q8_0_SIZE_MIB + HEADROOM_MIB +PREFER_Q8_0_ABOVE_MIB: float = _MEASURED_Q8_0_PEAK_MIB + HEADROOM_MIB #: Free memory at or above this keeps the q5_0 rung; below it is the floor. -PREFER_Q5_0_ABOVE_MIB: float = _Q5_0_SIZE_MIB + HEADROOM_MIB +PREFER_Q5_0_ABOVE_MIB: float = _MEASURED_Q5_0_PEAK_MIB + HEADROOM_MIB #: Minimum CUDA compute capability (major, minor) the bundled backend #: targets. Older architectures cannot run its kernels. diff --git a/tests/test_model_ladder.py b/tests/test_model_ladder.py index 84e7565..c98a16f 100644 --- a/tests/test_model_ladder.py +++ b/tests/test_model_ladder.py @@ -2,9 +2,9 @@ All behavior is exercised with mocked probes and loaders: no GPU, no network, no hardware. The threshold-derivation test pins the rung -thresholds to the catalog on-disk sizes plus the protocol headroom so a -catalog size bump forces a threshold review (ticket #19 recorded no -measured footprints, so these are size-plus-headroom proxies). +thresholds to ticket #19's measured transcribe peaks (1132 MiB for q8_0, +846 MiB for q5_0) plus the 512 MiB protocol headroom, so any re-measure +forces a threshold review. """ from unittest.mock import MagicMock, patch @@ -33,15 +33,22 @@ def _size_mb(name: str) -> float: class TestThresholdDerivation: - """Thresholds match the baseline ticket's recorded recommendation shape.""" + """Thresholds match the baseline ticket's recorded recommendation.""" - def test_q8_threshold_is_catalog_size_plus_headroom(self) -> None: - assert PREFER_Q8_0_ABOVE_MIB == _size_mb(DEFAULT_RUNG) + HEADROOM_MIB + #: Ticket #19 measured transcribe peaks (MiB) per rung. + Q8_0_MEASURED_MIB: float = 1132.0 + Q5_0_MEASURED_MIB: float = 846.0 - def test_q5_threshold_is_catalog_size_plus_headroom(self) -> None: - assert PREFER_Q5_0_ABOVE_MIB == _size_mb(LOW_MEMORY_RUNG) + HEADROOM_MIB + def test_q8_threshold_is_measured_footprint_plus_headroom(self) -> None: + assert PREFER_Q8_0_ABOVE_MIB == self.Q8_0_MEASURED_MIB + HEADROOM_MIB + assert PREFER_Q8_0_ABOVE_MIB == 1644.0 - def test_rungs_are_ordered_by_size(self) -> None: + def test_q5_threshold_is_measured_footprint_plus_headroom(self) -> None: + assert PREFER_Q5_0_ABOVE_MIB == self.Q5_0_MEASURED_MIB + HEADROOM_MIB + assert PREFER_Q5_0_ABOVE_MIB == 1358.0 + + def test_rungs_are_ordered(self) -> None: + assert PREFER_Q8_0_ABOVE_MIB > PREFER_Q5_0_ABOVE_MIB assert _size_mb(DEFAULT_RUNG) > _size_mb(LOW_MEMORY_RUNG) @@ -62,6 +69,13 @@ class TestSelectLadderRung: assert select_ladder_rung(True, 0.0) == FLOOR_RUNG_ENGLISH assert select_ladder_rung(False, 0.0) == FLOOR_RUNG_MULTILINGUAL + def test_recorded_boundaries_select_recorded_rungs(self) -> None: + assert select_ladder_rung(True, 1644.0) == DEFAULT_RUNG + assert select_ladder_rung(True, 1500.0) == LOW_MEMORY_RUNG + assert select_ladder_rung(True, 1358.0) == LOW_MEMORY_RUNG + assert select_ladder_rung(True, 1200.0) == FLOOR_RUNG_ENGLISH + assert select_ladder_rung(False, 1200.0) == FLOOR_RUNG_MULTILINGUAL + class TestResolveStartupRung: """A manual pin wins verbatim; only unpinned loads use the ladder."""