Skip to content

Commit ab348db

Browse files
committed
[feat] Add performance and separation quality benchmarks
Add benchmarking for PyTorch Demucs and C++ ONNX scripts - - Separation quality using SI-SDR - Performance metrics on CPU Signed-off-by: Anmol Mishra <anmolmishra1997@gmail.com>
1 parent 05c1919 commit ab348db

File tree

6 files changed

+2072
-0
lines changed

6 files changed

+2072
-0
lines changed

benchmark/benchmark-cpp-onnx.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
"""
2+
C++ ONNX-based Demucs benchmarking script.
3+
4+
This script uses C++ ONNX CLI tool for inference and imports common functionality
5+
from benchmark_common to avoid code duplication.
6+
"""
7+
8+
import argparse
9+
import subprocess
10+
from pathlib import Path
11+
12+
from benchmark_common import run_benchmark
13+
14+
DEFAULT_CLI_PATH = '../cppscripts/build/build-cli/demucs'
15+
DEFAULT_MODEL_PATH = '../onnx-models/htdemucs.ort'
16+
17+
18+
def separate_cpp_onnx(mixture_path, out_dir, cli_path, model_path):
19+
"""Separate audio using C++ ONNX CLI tool."""
20+
out_dir = Path(out_dir)
21+
out_dir.mkdir(parents=True, exist_ok=True)
22+
23+
cmd = [str(cli_path), str(model_path), str(mixture_path), str(out_dir)]
24+
subprocess.run(cmd, check=True)
25+
26+
27+
def main():
28+
parser = argparse.ArgumentParser(description='Benchmark Demucs separation using C++ ONNX CLI')
29+
parser.add_argument('--musdb-root', type=Path, help='Path to MusDB root', required=True)
30+
parser.add_argument('--output-root', type=Path, default=None, help='Where to store separated outputs (default: inside musdb-root)')
31+
parser.add_argument('--output-dir', type=str, default='test-separated-cpp', help='Output directory name (default: test-separated-cpp)')
32+
parser.add_argument('--json-out', type=str, default='benchmark_results_cpp.json', help='Output JSON file for benchmarks')
33+
parser.add_argument('--cli-path', type=str, default=DEFAULT_CLI_PATH, help='Path to the C++ ONNX CLI executable')
34+
parser.add_argument('--model-path', type=str, default=DEFAULT_MODEL_PATH, help='Path to the ONNX model file')
35+
parser.add_argument('--force-reseparate', action='store_true', help='Force re-separation even if files already exist')
36+
args = parser.parse_args()
37+
38+
# Setup paths
39+
musdb_root = Path(args.musdb_root)
40+
output_root = Path(args.output_root) if args.output_root else musdb_root
41+
out_dir = output_root / args.output_dir
42+
out_dir.mkdir(parents=True, exist_ok=True)
43+
44+
cli_path = Path(args.cli_path)
45+
model_path = Path(args.model_path)
46+
47+
print(f'Using CLI: {cli_path}')
48+
print(f'Using model: {model_path}')
49+
50+
# Run benchmark using common flow
51+
run_benchmark(
52+
musdb_root=musdb_root,
53+
out_dir=out_dir,
54+
force_reseparate=args.force_reseparate,
55+
json_out=args.json_out,
56+
separate_func=separate_cpp_onnx,
57+
model_identifier=str(model_path),
58+
# Arguments passed to separate_cpp_onnx
59+
cli_path=cli_path,
60+
model_path=model_path
61+
)
62+
63+
64+
if __name__ == '__main__':
65+
main()

benchmark/benchmark-pytorch.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
"""
2+
PyTorch-based Demucs benchmarking script.
3+
4+
This script uses PyTorch for inference and imports common functionality
5+
from benchmark_common to avoid code duplication.
6+
"""
7+
8+
import argparse
9+
from pathlib import Path
10+
11+
import torchaudio
12+
from demucs.apply import apply_model
13+
from demucs.pretrained import get_model
14+
15+
from benchmark_common import run_benchmark, STEM_MAP, STEM_NAMES
16+
17+
DEFAULT_MODEL = 'htdemucs'
18+
19+
20+
def separate_pytorch(mixture_path, out_dir, model_name):
21+
"""Separate audio using PyTorch Demucs model."""
22+
# Load model
23+
model = get_model(model_name)
24+
25+
# Load and preprocess audio
26+
audio, rate = torchaudio.load(str(mixture_path))
27+
if rate != 44100:
28+
audio = torchaudio.functional.resample(audio, rate, 44100)
29+
30+
# Normalize
31+
ref = audio.mean(0)
32+
audio = (audio - ref.mean()) / ref.std()
33+
34+
# Apply model
35+
sources = apply_model(model, audio[None])[0]
36+
37+
# Denormalize
38+
sources = sources * ref.std() + ref.mean()
39+
40+
# Save stems
41+
out_dir = Path(out_dir)
42+
out_dir.mkdir(parents=True, exist_ok=True)
43+
for target_idx in range(len(STEM_NAMES)):
44+
target_name = STEM_MAP[target_idx]
45+
out_audio = sources[target_idx].detach().cpu()
46+
out_path = out_dir / f'target_{target_idx}_{target_name}.wav'
47+
torchaudio.save(str(out_path), out_audio, sample_rate=44100)
48+
49+
50+
def main():
51+
parser = argparse.ArgumentParser(description='PyTorch Demucs Benchmarking Script')
52+
parser.add_argument('--musdb-root', type=Path, help='Path to MusDB root', required=True)
53+
parser.add_argument('--output-root', type=Path, default=None, help='Where to store separated outputs (default: inside musdb-root)')
54+
parser.add_argument('--output-dir', type=str, default='test-separated-pytorch', help='Output directory name (default: test-separated-pytorch)')
55+
parser.add_argument('--json-out', type=str, default='benchmark_results_pytorch.json', help='Output JSON file for benchmarks')
56+
parser.add_argument('--force-reseparate', action='store_true', help='Force re-separation even if files already exist')
57+
args = parser.parse_args()
58+
59+
# Setup paths
60+
musdb_root = Path(args.musdb_root)
61+
output_root = Path(args.output_root) if args.output_root else musdb_root
62+
out_dir = output_root / args.output_dir
63+
out_dir.mkdir(parents=True, exist_ok=True)
64+
65+
model_name = DEFAULT_MODEL
66+
print(f'Using model: {model_name}')
67+
68+
# Run benchmark using common flow
69+
run_benchmark(
70+
musdb_root=musdb_root,
71+
out_dir=out_dir,
72+
force_reseparate=args.force_reseparate,
73+
json_out=args.json_out,
74+
separate_func=separate_pytorch,
75+
model_identifier=model_name,
76+
# Arguments passed to separate_pytorch
77+
model_name=model_name
78+
)
79+
80+
81+
if __name__ == '__main__':
82+
main()

0 commit comments

Comments
 (0)