Download inference_example.py from laion/speech-artifact-detectors: direct link, hf CLI and curl.
- Browser
- Download file 4.76 kB
-
https://huggingface.co/laion/speech-artifact-detectors/resolve/main/inference_example.py
- Command line
-
hf download hf://laion/speech-artifact-detectors/inference_example.py
-
curl -L -o inference_example.py https://huggingface.co/laion/speech-artifact-detectors/resolve/main/inference_example.py
4.76 kB
| #!/usr/bin/env python3 | |
| """Inference example for Speech Artifact Detectors. | |
| Demonstrates loading models from HuggingFace Hub and scoring audio files. | |
| Usage: | |
| # Score a single file with all 10 detectors | |
| python inference_example.py audio.wav | |
| # Score a directory of files | |
| python inference_example.py /path/to/audio/ --ext wav | |
| # Only TTS/vocoder detectors | |
| python inference_example.py audio.wav --category tts_artifact | |
| # Only augmentation detectors on CPU | |
| python inference_example.py audio.wav --category augmentation --device cpu | |
| # Custom threshold for flagging artifacts | |
| python inference_example.py audio.wav --threshold 0.3 | |
| Requirements: | |
| pip install torch torchaudio soundfile numpy huggingface_hub | |
| """ | |
| import argparse | |
| import glob | |
| import os | |
| import sys | |
| import time | |
| import numpy as np | |
| import torch | |
| def main(): | |
| parser = argparse.ArgumentParser( | |
| description="Score audio files for speech artifacts", | |
| formatter_class=argparse.RawDescriptionHelpFormatter, | |
| ) | |
| parser.add_argument("input", help="Audio file or directory to score") | |
| parser.add_argument("--ext", default="wav", | |
| help="File extension when input is a directory (default: wav)") | |
| parser.add_argument("--device", default=None, | |
| help="Device: cuda, cpu, or auto-detect (default)") | |
| parser.add_argument("--category", choices=["tts_artifact", "augmentation"], | |
| help="Load only models from this category") | |
| parser.add_argument("--threshold", type=float, default=0.5, | |
| help="Score threshold for flagging artifacts (default: 0.5)") | |
| parser.add_argument("--batch-size", type=int, default=16, | |
| help="Batch size for inference (default: 16)") | |
| args = parser.parse_args() | |
| device = args.device or ("cuda" if torch.cuda.is_available() else "cpu") | |
| # ββ Load models from HuggingFace Hub βββββββββββββββββββββββββββββββββ | |
| from speech_artifact_detector import load_from_hub | |
| print(f"Loading models on {device}...") | |
| categories = [args.category] if args.category else None | |
| t0 = time.time() | |
| models = load_from_hub(device=device, categories=categories) | |
| print(f" Loaded {len(models)} models in {time.time() - t0:.1f}s: " | |
| f"{', '.join(models.keys())}\n") | |
| # ββ Collect input files ββββββββββββββββββββββββββββββββββββββββββββββ | |
| if os.path.isdir(args.input): | |
| files = sorted(glob.glob(os.path.join(args.input, f"*.{args.ext}"))) | |
| if not files: | |
| print(f"No .{args.ext} files found in {args.input}") | |
| sys.exit(1) | |
| elif os.path.isfile(args.input): | |
| files = [args.input] | |
| else: | |
| print(f"File not found: {args.input}") | |
| sys.exit(1) | |
| print(f"Scoring {len(files)} file(s)...\n") | |
| # ββ Score each file ββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| from speech_artifact_detector import score_file_all | |
| model_names = list(models.keys()) | |
| all_results = [] | |
| for fpath in files: | |
| fname = os.path.basename(fpath) | |
| scores = score_file_all(models, fpath, device) | |
| mean_score = np.mean(list(scores.values())) | |
| verdict = "ARTIFACT" if mean_score >= args.threshold else "clean" | |
| all_results.append({"file": fname, "scores": scores, | |
| "mean": mean_score, "verdict": verdict}) | |
| # Print per-file results | |
| print(f"{'=' * 60}") | |
| print(f" {fname} β {verdict} (mean={mean_score:.4f})") | |
| print(f"{'=' * 60}") | |
| for name in model_names: | |
| s = scores[name] | |
| bar = "#" * int(s * 30) + "." * (30 - int(s * 30)) | |
| flag = " <<<" if s >= args.threshold else "" | |
| print(f" {name:>25s}: {s:.4f} [{bar}]{flag}") | |
| print() | |
| # ββ Summary ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| if len(files) > 1: | |
| n_artifact = sum(1 for r in all_results if r["verdict"] == "ARTIFACT") | |
| print(f"\nSummary: {n_artifact}/{len(files)} files flagged as ARTIFACT " | |
| f"(threshold={args.threshold})") | |
| print(f"\nPer-detector averages across all files:") | |
| for name in model_names: | |
| avg = np.mean([r["scores"][name] for r in all_results]) | |
| print(f" {name:>25s}: {avg:.4f}") | |
| if __name__ == "__main__": | |
| main() | |