Spaces:
Running on Zero
Running on Zero
Warm CPU acoustic verifiers
Browse files- README.md +5 -4
- app.py +30 -6
- tests/test_inference_cleanup.py +5 -3
README.md
CHANGED
|
@@ -335,10 +335,11 @@ Median-F0 只在 multi-chunk lattice 真的出現兩條以上可選路徑、必
|
|
| 335 |
時,才對 retained DP candidates 延遲計算一次;單一路徑、single/K32、semantic reject、
|
| 336 |
joined 與 final waveform 不再支付無用的 pYIN latency。真正進入多路徑排序時,pYIN 演算法與
|
| 337 |
transition score 定義沒有變更。
|
| 338 |
-
Pinned ECAPA
|
| 339 |
-
不保存的合成波形
|
| 340 |
-
SpeechBrain import、權重初始化、encoder 建構及第一次 CPU kernel/page-fault
|
| 341 |
-
正式請求仍
|
|
|
|
| 342 |
|
| 343 |
Generation work 以實際產生的 chunks 與其 speech units 累計:初始 trajectory 花費
|
| 344 |
`chunk count` 與全文 speech units;每次 refill 再加 1 chunk 與該段 units。任一 request 最多
|
|
|
|
| 335 |
時,才對 retained DP candidates 延遲計算一次;單一路徑、single/K32、semantic reject、
|
| 336 |
joined 與 final waveform 不再支付無用的 pYIN latency。真正進入多路徑排序時,pYIN 演算法與
|
| 337 |
transition score 定義沒有變更。
|
| 338 |
+
Pinned ECAPA、SQUIM 與 pYIN runtime 會在 Space 啟動階段於 CPU 完成載入,並以固定、非語音、
|
| 339 |
+
不保存的合成波形執行 local-batch、release-third 與 acoustic dry-run;因此第一次公開合成
|
| 340 |
+
不再承擔 SpeechBrain import、權重初始化、encoder 建構及第一次 CPU kernel/page-fault/JIT
|
| 341 |
+
的冷啟動成本。正式請求仍對真實 waveform 重跑所有量測;warmup 不寫入 request cache,
|
| 342 |
+
也不改 speaker、SQUIM、F0 transition 或 echo gate 數值。
|
| 343 |
|
| 344 |
Generation work 以實際產生的 chunks 與其 speech units 累計:初始 trajectory 花費
|
| 345 |
`chunk count` 與全文 speech units;每次 refill 再加 1 chunk 與該段 units。任一 request 最多
|
app.py
CHANGED
|
@@ -564,10 +564,10 @@ def _get_ecapa_encoder():
|
|
| 564 |
return _ECAPA_ENCODER
|
| 565 |
|
| 566 |
|
| 567 |
-
def
|
| 568 |
-
"""Move deterministic CPU
|
| 569 |
|
| 570 |
-
print("[BlueMagpie] preloading release
|
| 571 |
encoder = _get_ecapa_encoder()
|
| 572 |
if encoder is None:
|
| 573 |
raise RuntimeError("release speaker verifier preload failed")
|
|
@@ -575,7 +575,8 @@ def _preload_release_speaker_runtime() -> None:
|
|
| 575 |
timeline = np.arange(sample_count, dtype=np.float64) / float(SR)
|
| 576 |
warmup_waveform = np.asarray(
|
| 577 |
0.08 * np.sin(2.0 * np.pi * 180.0 * timeline)
|
| 578 |
-
+ 0.
|
|
|
|
| 579 |
dtype=np.float32,
|
| 580 |
)
|
| 581 |
anchor = _speaker_anchor_array(DEFAULT_CENTROID)
|
|
@@ -601,7 +602,30 @@ def _preload_release_speaker_runtime() -> None:
|
|
| 601 |
for evidence in warmup_evidence
|
| 602 |
):
|
| 603 |
raise RuntimeError("release speaker verifier warmup failed")
|
| 604 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 605 |
|
| 606 |
|
| 607 |
def _apply_speed(
|
|
@@ -982,7 +1006,7 @@ def _speaker_anchor_array(centroid: torch.Tensor) -> np.ndarray:
|
|
| 982 |
return np.asarray(anchor / norm, dtype=np.float32)
|
| 983 |
|
| 984 |
|
| 985 |
-
|
| 986 |
|
| 987 |
|
| 988 |
def _generate_trajectory(
|
|
|
|
| 564 |
return _ECAPA_ENCODER
|
| 565 |
|
| 566 |
|
| 567 |
+
def _preload_release_cpu_runtime() -> None:
|
| 568 |
+
"""Move deterministic CPU verifier loads and first forwards out of requests."""
|
| 569 |
|
| 570 |
+
print("[BlueMagpie] preloading release CPU verifiers ...")
|
| 571 |
encoder = _get_ecapa_encoder()
|
| 572 |
if encoder is None:
|
| 573 |
raise RuntimeError("release speaker verifier preload failed")
|
|
|
|
| 575 |
timeline = np.arange(sample_count, dtype=np.float64) / float(SR)
|
| 576 |
warmup_waveform = np.asarray(
|
| 577 |
0.08 * np.sin(2.0 * np.pi * 180.0 * timeline)
|
| 578 |
+
+ 0.04 * np.sin(2.0 * np.pi * 360.0 * timeline)
|
| 579 |
+
+ 0.02 * np.sin(2.0 * np.pi * 540.0 * timeline),
|
| 580 |
dtype=np.float32,
|
| 581 |
)
|
| 582 |
anchor = _speaker_anchor_array(DEFAULT_CENTROID)
|
|
|
|
| 602 |
for evidence in warmup_evidence
|
| 603 |
):
|
| 604 |
raise RuntimeError("release speaker verifier warmup failed")
|
| 605 |
+
squim_evidence = squim_objective_evidence_from_audio(
|
| 606 |
+
warmup_waveform,
|
| 607 |
+
SR,
|
| 608 |
+
)
|
| 609 |
+
if not all(
|
| 610 |
+
np.isfinite(value)
|
| 611 |
+
for value in (
|
| 612 |
+
squim_evidence.stoi,
|
| 613 |
+
squim_evidence.pesq,
|
| 614 |
+
squim_evidence.si_sdr,
|
| 615 |
+
)
|
| 616 |
+
):
|
| 617 |
+
raise RuntimeError("release SQUIM verifier warmup failed")
|
| 618 |
+
median_f0_hz = active_audio_median_f0_hz(
|
| 619 |
+
warmup_waveform,
|
| 620 |
+
SR,
|
| 621 |
+
)
|
| 622 |
+
if (
|
| 623 |
+
median_f0_hz is None
|
| 624 |
+
or not np.isfinite(median_f0_hz)
|
| 625 |
+
or median_f0_hz < 1.0
|
| 626 |
+
):
|
| 627 |
+
raise RuntimeError("release F0 transition runtime warmup failed")
|
| 628 |
+
print("[BlueMagpie] release CPU verifiers ready")
|
| 629 |
|
| 630 |
|
| 631 |
def _apply_speed(
|
|
|
|
| 1006 |
return np.asarray(anchor / norm, dtype=np.float32)
|
| 1007 |
|
| 1008 |
|
| 1009 |
+
_preload_release_cpu_runtime()
|
| 1010 |
|
| 1011 |
|
| 1012 |
def _generate_trajectory(
|
tests/test_inference_cleanup.py
CHANGED
|
@@ -633,7 +633,7 @@ def test_space_defers_transition_f0_to_actual_multi_path_ranking():
|
|
| 633 |
assert "_apply_speed(\n audio,\n final_speed" in generate
|
| 634 |
|
| 635 |
|
| 636 |
-
def
|
| 637 |
source = (ROOT / "app.py").read_text(encoding="utf-8")
|
| 638 |
tree = ast.parse(source)
|
| 639 |
functions = {
|
|
@@ -647,15 +647,17 @@ def test_space_preloads_release_speaker_runtime_before_serving_requests():
|
|
| 647 |
if isinstance(node, ast.Expr)
|
| 648 |
and isinstance(node.value, ast.Call)
|
| 649 |
and isinstance(node.value.func, ast.Name)
|
| 650 |
-
and node.value.func.id == "
|
| 651 |
]
|
| 652 |
|
| 653 |
assert len(preload_calls) == 1
|
| 654 |
assert preload_calls[0].lineno > functions["_speaker_anchor_array"].end_lineno
|
| 655 |
preload_source = ast.get_source_segment(
|
| 656 |
source,
|
| 657 |
-
functions["
|
| 658 |
)
|
| 659 |
assert "speaker_evidence_from_audio(" in preload_source
|
| 660 |
assert "release_speaker_evidence_from_audio(" in preload_source
|
|
|
|
|
|
|
| 661 |
assert "np.arange(sample_count" in preload_source
|
|
|
|
| 633 |
assert "_apply_speed(\n audio,\n final_speed" in generate
|
| 634 |
|
| 635 |
|
| 636 |
+
def test_space_preloads_release_cpu_runtime_before_serving_requests():
|
| 637 |
source = (ROOT / "app.py").read_text(encoding="utf-8")
|
| 638 |
tree = ast.parse(source)
|
| 639 |
functions = {
|
|
|
|
| 647 |
if isinstance(node, ast.Expr)
|
| 648 |
and isinstance(node.value, ast.Call)
|
| 649 |
and isinstance(node.value.func, ast.Name)
|
| 650 |
+
and node.value.func.id == "_preload_release_cpu_runtime"
|
| 651 |
]
|
| 652 |
|
| 653 |
assert len(preload_calls) == 1
|
| 654 |
assert preload_calls[0].lineno > functions["_speaker_anchor_array"].end_lineno
|
| 655 |
preload_source = ast.get_source_segment(
|
| 656 |
source,
|
| 657 |
+
functions["_preload_release_cpu_runtime"],
|
| 658 |
)
|
| 659 |
assert "speaker_evidence_from_audio(" in preload_source
|
| 660 |
assert "release_speaker_evidence_from_audio(" in preload_source
|
| 661 |
+
assert "squim_objective_evidence_from_audio(" in preload_source
|
| 662 |
+
assert "active_audio_median_f0_hz(" in preload_source
|
| 663 |
assert "np.arange(sample_count" in preload_source
|