Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
Commit ·
a6beab2
1
Parent(s): 3813139
cohere fix
Browse files- app.py +2 -0
- backends/_audio_utils.py +28 -0
- constants.py +6 -3
- evaluation/orchestrator.py +1 -0
- evaluation/runtime.py +29 -0
- remote_jobs.py +1 -1
- scripts/run_eval_and_publish.py +4 -0
- scripts/run_hf_remote_job_uv.py +2 -1
app.py
CHANGED
|
@@ -460,6 +460,8 @@ with gr.Blocks(title=APP_TITLE, theme=_theme, css=LEADERBOARD_CSS) as demo:
|
|
| 460 |
gr.Markdown(
|
| 461 |
"Edit the example below: define **`evaluate(file: Path) -> str`** to transcribe one WAV. "
|
| 462 |
"Load your model **once** at module level (as in the Cohere example). "
|
|
|
|
|
|
|
| 463 |
"The function is called **once per audio sample** inside the eval loop. "
|
| 464 |
"Put extra Python dependencies in the requirements box above. "
|
| 465 |
"Custom evaluators run on a Hub Job **only** after a moderator approves them."
|
|
|
|
| 460 |
gr.Markdown(
|
| 461 |
"Edit the example below: define **`evaluate(file: Path) -> str`** to transcribe one WAV. "
|
| 462 |
"Load your model **once** at module level (as in the Cohere example). "
|
| 463 |
+
"Use **soundfile** (or numpy) to read each WAV — avoid "
|
| 464 |
+
"``transformers.audio_utils.load_audio`` (requires FFmpeg/torchcodec on the job). "
|
| 465 |
"The function is called **once per audio sample** inside the eval loop. "
|
| 466 |
"Put extra Python dependencies in the requirements box above. "
|
| 467 |
"Custom evaluators run on a Hub Job **only** after a moderator approves them."
|
backends/_audio_utils.py
CHANGED
|
@@ -4,6 +4,8 @@ Small helpers shared across backends (no heavy imports).
|
|
| 4 |
|
| 5 |
from __future__ import annotations
|
| 6 |
|
|
|
|
|
|
|
| 7 |
import numpy as np
|
| 8 |
|
| 9 |
|
|
@@ -26,3 +28,29 @@ def safe_pad_audio(audio: np.ndarray, multiple: int = 1600) -> np.ndarray:
|
|
| 26 |
return arr
|
| 27 |
pad = multiple - rem
|
| 28 |
return np.concatenate([arr, np.zeros(pad, dtype=np.float32)])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
|
| 5 |
from __future__ import annotations
|
| 6 |
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
|
| 9 |
import numpy as np
|
| 10 |
|
| 11 |
|
|
|
|
| 28 |
return arr
|
| 29 |
pad = multiple - rem
|
| 30 |
return np.concatenate([arr, np.zeros(pad, dtype=np.float32)])
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def load_wav_mono(path: str | Path, sampling_rate: int = 16000) -> np.ndarray:
|
| 34 |
+
"""
|
| 35 |
+
Load a WAV file as a 1-D float32 mono waveform at ``sampling_rate`` Hz.
|
| 36 |
+
|
| 37 |
+
Uses ``soundfile`` only (no torchcodec / FFmpeg). Eval samples and the
|
| 38 |
+
custom ``evaluate(Path)`` hook are written as 16 kHz PCM WAVs.
|
| 39 |
+
"""
|
| 40 |
+
import soundfile as sf
|
| 41 |
+
|
| 42 |
+
audio, sr = sf.read(str(path), dtype="float32", always_2d=True)
|
| 43 |
+
audio = audio.mean(axis=1)
|
| 44 |
+
if int(sr) != int(sampling_rate):
|
| 45 |
+
try:
|
| 46 |
+
import librosa
|
| 47 |
+
|
| 48 |
+
audio = librosa.resample(
|
| 49 |
+
audio, orig_sr=int(sr), target_sr=int(sampling_rate)
|
| 50 |
+
)
|
| 51 |
+
except Exception as exc:
|
| 52 |
+
raise RuntimeError(
|
| 53 |
+
f"Audio is {sr} Hz but {sampling_rate} Hz was requested; "
|
| 54 |
+
"install librosa for resampling."
|
| 55 |
+
) from exc
|
| 56 |
+
return np.asarray(audio, dtype=np.float32).reshape(-1)
|
constants.py
CHANGED
|
@@ -418,8 +418,10 @@ button.primary, .primary button {
|
|
| 418 |
)
|
| 419 |
|
| 420 |
DEFAULT_CUSTOM_EVAL_EXAMPLE = """from pathlib import Path
|
|
|
|
|
|
|
|
|
|
| 421 |
from transformers import AutoProcessor, CohereAsrForConditionalGeneration
|
| 422 |
-
from transformers.audio_utils import load_audio
|
| 423 |
|
| 424 |
processor = AutoProcessor.from_pretrained("CohereLabs/cohere-transcribe-03-2026")
|
| 425 |
model = CohereAsrForConditionalGeneration.from_pretrained(
|
|
@@ -427,8 +429,9 @@ model = CohereAsrForConditionalGeneration.from_pretrained(
|
|
| 427 |
)
|
| 428 |
|
| 429 |
def evaluate(file: Path) -> str:
|
| 430 |
-
audio =
|
| 431 |
-
|
|
|
|
| 432 |
inputs.to(model.device, dtype=model.dtype)
|
| 433 |
outputs = model.generate(**inputs, max_new_tokens=256)
|
| 434 |
return processor.decode(outputs, skip_special_tokens=True)
|
|
|
|
| 418 |
)
|
| 419 |
|
| 420 |
DEFAULT_CUSTOM_EVAL_EXAMPLE = """from pathlib import Path
|
| 421 |
+
|
| 422 |
+
import soundfile as sf
|
| 423 |
+
import torch
|
| 424 |
from transformers import AutoProcessor, CohereAsrForConditionalGeneration
|
|
|
|
| 425 |
|
| 426 |
processor = AutoProcessor.from_pretrained("CohereLabs/cohere-transcribe-03-2026")
|
| 427 |
model = CohereAsrForConditionalGeneration.from_pretrained(
|
|
|
|
| 429 |
)
|
| 430 |
|
| 431 |
def evaluate(file: Path) -> str:
|
| 432 |
+
audio, sr = sf.read(str(file), dtype="float32", always_2d=True)
|
| 433 |
+
audio = audio.mean(axis=1)
|
| 434 |
+
inputs = processor(audio, sampling_rate=int(sr), return_tensors="pt", language="en")
|
| 435 |
inputs.to(model.device, dtype=model.dtype)
|
| 436 |
outputs = model.generate(**inputs, max_new_tokens=256)
|
| 437 |
return processor.decode(outputs, skip_special_tokens=True)
|
evaluation/orchestrator.py
CHANGED
|
@@ -442,6 +442,7 @@ def run_evaluation(
|
|
| 442 |
Returns wer_clean, wer_noisy, wer_reverberant, wer_real, wer_difficult, num_samples, model_id, eval_family, plus timing.
|
| 443 |
"""
|
| 444 |
apply_cpu_thread_settings_once()
|
|
|
|
| 445 |
|
| 446 |
seg = _samples_per_gpu_segment()
|
| 447 |
|
|
|
|
| 442 |
Returns wer_clean, wer_noisy, wer_reverberant, wer_real, wer_difficult, num_samples, model_id, eval_family, plus timing.
|
| 443 |
"""
|
| 444 |
apply_cpu_thread_settings_once()
|
| 445 |
+
disable_broken_torchcodec()
|
| 446 |
|
| 447 |
seg = _samples_per_gpu_segment()
|
| 448 |
|
evaluation/runtime.py
CHANGED
|
@@ -6,6 +6,35 @@ import importlib.util
|
|
| 6 |
import os
|
| 7 |
|
| 8 |
_cpu_thread_settings_applied = False
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
|
| 10 |
|
| 11 |
def zerogpu_disabled() -> bool:
|
|
|
|
| 6 |
import os
|
| 7 |
|
| 8 |
_cpu_thread_settings_applied = False
|
| 9 |
+
_torchcodec_patch_applied = False
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def disable_broken_torchcodec() -> None:
|
| 13 |
+
"""
|
| 14 |
+
Transformers prefers torchcodec for ``load_audio`` when the package is installed,
|
| 15 |
+
but Hub Job images often lack FFmpeg shared libraries (libavutil.so.*).
|
| 16 |
+
|
| 17 |
+
If torchcodec cannot load, mark it unavailable so transformers falls back to
|
| 18 |
+
librosa / soundfile.
|
| 19 |
+
"""
|
| 20 |
+
global _torchcodec_patch_applied
|
| 21 |
+
if _torchcodec_patch_applied:
|
| 22 |
+
return
|
| 23 |
+
_torchcodec_patch_applied = True
|
| 24 |
+
|
| 25 |
+
import importlib.util
|
| 26 |
+
|
| 27 |
+
if importlib.util.find_spec("torchcodec") is None:
|
| 28 |
+
return
|
| 29 |
+
try:
|
| 30 |
+
from torchcodec.decoders import AudioDecoder # noqa: F401
|
| 31 |
+
except Exception:
|
| 32 |
+
try:
|
| 33 |
+
import transformers.utils.import_utils as import_utils
|
| 34 |
+
|
| 35 |
+
import_utils._torchcodec_available = False
|
| 36 |
+
except Exception:
|
| 37 |
+
pass
|
| 38 |
|
| 39 |
|
| 40 |
def zerogpu_disabled() -> bool:
|
remote_jobs.py
CHANGED
|
@@ -29,6 +29,7 @@ _DEFAULT_REMOTE_JOB_FLAVOR = "l4x1"
|
|
| 29 |
_DEFAULT_REMOTE_WORKER_DEVICE = "auto"
|
| 30 |
|
| 31 |
# Shared eval stack installed by uv for every remote job.
|
|
|
|
| 32 |
CORE_DEPS: list[str] = [
|
| 33 |
"pandas",
|
| 34 |
"numpy",
|
|
@@ -43,7 +44,6 @@ CORE_DEPS: list[str] = [
|
|
| 43 |
|
| 44 |
_TRANSFORMERS_DEPS: list[str] = [
|
| 45 |
"transformers @ git+https://github.com/huggingface/transformers.git",
|
| 46 |
-
"torchcodec",
|
| 47 |
"librosa",
|
| 48 |
"sentencepiece",
|
| 49 |
]
|
|
|
|
| 29 |
_DEFAULT_REMOTE_WORKER_DEVICE = "auto"
|
| 30 |
|
| 31 |
# Shared eval stack installed by uv for every remote job.
|
| 32 |
+
# Note: do not add torchcodec — Hub Job images lack FFmpeg shared libs (libavutil.so.*).
|
| 33 |
CORE_DEPS: list[str] = [
|
| 34 |
"pandas",
|
| 35 |
"numpy",
|
|
|
|
| 44 |
|
| 45 |
_TRANSFORMERS_DEPS: list[str] = [
|
| 46 |
"transformers @ git+https://github.com/huggingface/transformers.git",
|
|
|
|
| 47 |
"librosa",
|
| 48 |
"sentencepiece",
|
| 49 |
]
|
scripts/run_eval_and_publish.py
CHANGED
|
@@ -460,6 +460,10 @@ def _run_evaluation_local(
|
|
| 460 |
"""Inline orchestrator: chosen device + batched fast-path when possible."""
|
| 461 |
import torch
|
| 462 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 463 |
from backends.registry import build_transcriber, resolve_label
|
| 464 |
from benchmark.dataset import (
|
| 465 |
PACKED_FILES,
|
|
|
|
| 460 |
"""Inline orchestrator: chosen device + batched fast-path when possible."""
|
| 461 |
import torch
|
| 462 |
|
| 463 |
+
from evaluation.runtime import disable_broken_torchcodec
|
| 464 |
+
|
| 465 |
+
disable_broken_torchcodec()
|
| 466 |
+
|
| 467 |
from backends.registry import build_transcriber, resolve_label
|
| 468 |
from benchmark.dataset import (
|
| 469 |
PACKED_FILES,
|
scripts/run_hf_remote_job_uv.py
CHANGED
|
@@ -109,11 +109,12 @@ def main() -> int:
|
|
| 109 |
os.chdir(workdir)
|
| 110 |
|
| 111 |
from evaluation.remote_artifact import ARTIFACT_SCHEMA_VERSION, build_artifact
|
| 112 |
-
from evaluation.runtime import apply_cpu_thread_settings_once
|
| 113 |
from evaluation.orchestrator import run_evaluation
|
| 114 |
from storage import HF_BUCKET_ID, upload_to_bucket
|
| 115 |
|
| 116 |
apply_cpu_thread_settings_once()
|
|
|
|
| 117 |
custom_b64 = os.environ.get("FFASR_CUSTOM_SCRIPT_B64", "").strip()
|
| 118 |
custom_script = (
|
| 119 |
base64.b64decode(custom_b64).decode("utf-8") if custom_b64 else ""
|
|
|
|
| 109 |
os.chdir(workdir)
|
| 110 |
|
| 111 |
from evaluation.remote_artifact import ARTIFACT_SCHEMA_VERSION, build_artifact
|
| 112 |
+
from evaluation.runtime import apply_cpu_thread_settings_once, disable_broken_torchcodec
|
| 113 |
from evaluation.orchestrator import run_evaluation
|
| 114 |
from storage import HF_BUCKET_ID, upload_to_bucket
|
| 115 |
|
| 116 |
apply_cpu_thread_settings_once()
|
| 117 |
+
disable_broken_torchcodec()
|
| 118 |
custom_b64 = os.environ.get("FFASR_CUSTOM_SCRIPT_B64", "").strip()
|
| 119 |
custom_script = (
|
| 120 |
base64.b64decode(custom_b64).decode("utf-8") if custom_b64 else ""
|