Files
doctate/canary/probe_canary_ts.py
T
Brummel 6b7a1cea49 feat: Add Canary ASR model service and sweep experiments
This commit introduces the `doctate-canary` service and associated sweep
experiments.

The service provides access to the `nvidia/canary-1b-v2` ASR model via a
native FastAPI API. It includes deployment scripts, Docker
configurations, and detailed documentation on installation, API usage,
and environment variables.

The sweep experiments aim to thoroughly evaluate the Canary model's
performance under various configurations. This includes testing
different inference pipelines (single-shot vs. buffered), decoding
strategies (greedy vs. beam search), and parameter tuning (chunk length,
overlap, batch size, precision). The goal is to reproduce previous
findings and identify optimal settings.

The commit also includes:
- Utility scripts for audio transcoding and manipulation.
- Comprehensive logging and result collection mechanisms for the sweep
  runs.
- Detailed analysis of `dur=0` occurrences and word confidence,
  concluding they are not reliable indicators of hallucination.
- Documentation on the interaction between decoding parameters,
  especially `return_hypotheses`, and the availability of confidence
  scores.
2026-04-30 14:30:12 +02:00

70 lines
2.1 KiB
Python

"""Show forced-alignment timestamps from Canary's main transcribe(timestamps=True).
Demonstrates the full Hypothesis structure produced by:
AED text + CTC submodel acoustic alignment via Viterbi.
Output:
/sweep/canary_timestamps_demo.json — full pretty-printed dict
stdout — short summary
"""
import json
import os
import subprocess
import tempfile
import torch
from nemo.collections.asr.models import EncDecMultiTaskModel
WAV_SRC = "/sweep/case_c414cf52_15-01-39.m4a"
OUT_PATH = "/sweep/canary_timestamps_dosing.json"
def transcode(src: str) -> str:
dst = tempfile.NamedTemporaryFile(suffix=".wav", delete=False)
dst.close()
subprocess.run(["ffmpeg", "-y", "-loglevel", "error", "-i", src,
"-ac", "1", "-ar", "16000",
"-f", "wav", dst.name], check=True)
return dst.name
def to_jsonable(o):
if hasattr(o, "tolist"):
return o.tolist()
if hasattr(o, "item"):
return o.item()
return str(o)
def main():
print("loading Canary 1B v2", flush=True)
model = EncDecMultiTaskModel.from_pretrained("nvidia/canary-1b-v2")
model = model.to("cuda").to(torch.bfloat16)
model.eval()
wav = transcode(WAV_SRC)
print(f"running model.transcribe(timestamps=True) on {WAV_SRC}", flush=True)
with torch.amp.autocast("cuda", enabled=True, dtype=torch.bfloat16):
with torch.no_grad():
hyps = model.transcribe([wav], source_lang="de", target_lang="de",
pnc="yes", timestamps=True, batch_size=4)
h = hyps[0]
out = {"text": getattr(h, "text", None),
"timestamp": getattr(h, "timestamp", None)}
with open(OUT_PATH, "w") as f:
json.dump(out, f, default=to_jsonable, ensure_ascii=False, indent=2)
print(f"\ntext: {h.text}", flush=True)
ts = h.timestamp if isinstance(h.timestamp, dict) else {}
for k, v in ts.items():
n = len(v) if hasattr(v, "__len__") else "?"
print(f"timestamp[{k}]: {n} entries", flush=True)
print(f"\nfull dump -> {OUT_PATH}", flush=True)
if __name__ == "__main__":
main()