voice_audio_multi/tests/perf/model_perf.py
Fabio c36510c21e
Some checks failed
Linux Build / Linux cpu (push) Has been cancelled
Linux Build / Linux cpu-clang (push) Has been cancelled
Linux Build / Linux vulkan (push) Has been cancelled
mac-build / macOS CPU (push) Has been cancelled
Nix Build / Nix (cpu) (push) Has been cancelled
Nix Build / Nix (vulkan) (push) Has been cancelled
windows-build / Windows CPU (push) Has been cancelled
Initial import: audio.cpp with Orange Pi documentation
2026-11-04 19:05:22 +01:00

1632 lines
68 KiB
Python

#!/usr/bin/env python3
from __future__ import annotations
import argparse
import importlib.util
import json
import os
import shutil
import sys
import time
import wave
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Callable
import numpy as np
import soundfile as sf
# Prefer the bundled CUDA libraries in the active conda env over any
# incompatible system cuDNN injected through LD_LIBRARY_PATH.
os.environ.pop("LD_LIBRARY_PATH", None)
import torch
import torch.nn.functional as F
from safetensors import safe_open
REPO_ROOT = Path(__file__).resolve().parents[2]
DEFAULT_PERF_CASES = REPO_ROOT / "tools" / "perf" / "model_perf_cases.json"
DEFAULT_REQUEST_CASES = REPO_ROOT / "tools" / "perf" / "model_perf_request_cases.json"
@dataclass
class PerfCase:
id: str
family: str
case_id: str
request_id: str
warmup_request_id: str | None = None
request_overrides: dict[str, Any] | None = None
warmup_request_overrides: dict[str, Any] | None = None
request_remove_keys: list[str] | None = None
warmup_request_remove_keys: list[str] | None = None
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description="Serial Python performance harness for audio.cpp model references.")
parser.add_argument("--perf-cases", type=Path, default=DEFAULT_PERF_CASES)
parser.add_argument("--request-cases", type=Path, default=DEFAULT_REQUEST_CASES)
parser.add_argument("--id", default="")
parser.add_argument("--backend", choices=("cpu", "cuda"), default="cuda")
parser.add_argument("--device", type=int, default=0)
parser.add_argument("--threads", type=int, default=1)
parser.add_argument("--summary-out", type=Path, default=None)
return parser.parse_args()
def read_json(path: Path) -> Any:
return json.loads(path.read_text(encoding="utf-8"))
def ensure_absolute_path(value: str) -> Path:
path = Path(value)
return path if path.is_absolute() else REPO_ROOT / path
def shorten_text(text: str, limit: int) -> str:
if len(text) <= limit:
return text
cut = text.rfind(" ", 0, limit)
if cut < max(8, limit // 2):
cut = limit
return text[:cut].rstrip()
def read_wav_mono_f32(path: Path) -> tuple[np.ndarray, int]:
pcm, sample_rate = sf.read(str(path), dtype="float32", always_2d=False)
pcm = np.asarray(pcm, dtype=np.float32)
if pcm.ndim == 2:
pcm = pcm.mean(axis=1)
return pcm, sample_rate
def write_wav_mono_f32(path: Path, audio: np.ndarray, sample_rate: int) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
audio = np.asarray(audio, dtype=np.float32).reshape(-1)
pcm = np.clip(audio, -1.0, 1.0)
pcm16 = np.round(pcm * 32767.0).astype(np.int16, copy=False)
with wave.open(str(path), "wb") as wav:
wav.setnchannels(1)
wav.setsampwidth(2)
wav.setframerate(sample_rate)
wav.writeframes(pcm16.tobytes())
def write_clipped_wav(source: Path, temp_dir: Path, seconds: float) -> Path:
samples, sample_rate = read_wav_mono_f32(source)
limit = max(1, min(len(samples), int(round(sample_rate * seconds))))
target = temp_dir / source.name
write_wav_mono_f32(target, samples[:limit], sample_rate)
return target
def resolve_request_paths(request: dict[str, Any]) -> dict[str, Any]:
out = dict(request)
for key in ("audio", "voice_ref", "source_audio", "target_voice", "prosody_ref", "style_ref"):
value = out.get(key)
if isinstance(value, str) and value:
out[key] = str(ensure_absolute_path(value))
return out
def derive_warmup_request(request: dict[str, Any], temp_dir: Path) -> dict[str, Any]:
out = resolve_request_paths(request)
for key, limit in (
("text", 80),
("target_text", 80),
("style_ref_text", 80),
("reference_text", 80),
("lyrics", 80),
("instruct", 64),
):
value = out.get(key)
if isinstance(value, str) and value:
out[key] = shorten_text(value, limit)
for key in ("audio", "voice_ref", "source_audio", "target_voice", "prosody_ref", "style_ref"):
value = out.get(key)
if isinstance(value, str) and value:
out[key] = str(write_clipped_wav(Path(value), temp_dir, 2.0))
if isinstance(out.get("duration_seconds"), (int, float)):
out["duration_seconds"] = min(float(out["duration_seconds"]), 4.0)
if isinstance(out.get("max_tokens"), (int, float)):
out["max_tokens"] = min(int(out["max_tokens"]), 64)
if isinstance(out.get("num_inference_steps"), (int, float)):
out["num_inference_steps"] = min(int(out["num_inference_steps"]), 8)
return out
def audio_duration_sec(audio: np.ndarray, sample_rate: int) -> float:
return float(len(np.asarray(audio).reshape(-1))) / float(sample_rate) if sample_rate > 0 else 0.0
def input_audio_duration_sec(request: dict[str, Any]) -> float:
for key in ("audio", "source_audio"):
value = request.get(key)
if isinstance(value, str) and value:
samples, sample_rate = read_wav_mono_f32(Path(value))
return audio_duration_sec(samples, sample_rate)
return 0.0
def load_perf_cases(path: Path) -> list[PerfCase]:
root = read_json(path)
return [
PerfCase(
id=item["id"],
family=item["family"],
case_id=item["case_id"],
request_id=item["request_id"],
warmup_request_id=item.get("warmup_request_id"),
request_overrides=item.get("request_overrides"),
warmup_request_overrides=item.get("warmup_request_overrides"),
request_remove_keys=item.get("request_remove_keys"),
warmup_request_remove_keys=item.get("warmup_request_remove_keys"),
)
for item in root["cases"]
]
def find_case(request_cases: dict[str, Any], case_id: str) -> dict[str, Any]:
for item in request_cases["cases"]:
if item["id"] == case_id:
return item
raise KeyError(case_id)
def find_request(case: dict[str, Any], request_id: str) -> dict[str, Any]:
for item in case["requests"]:
if item["id"] == request_id:
return item
raise KeyError(f"{case['id']}:{request_id}")
def materialize_perf_request(
request: dict[str, Any],
overrides: dict[str, Any] | None,
remove_keys: list[str] | None,
) -> dict[str, Any]:
out = dict(request)
for key in remove_keys or []:
out.pop(key, None)
if overrides:
out.update(overrides)
return out
def set_threads(threads: int) -> None:
os.environ["OMP_NUM_THREADS"] = str(max(1, threads))
os.environ["MKL_NUM_THREADS"] = str(max(1, threads))
def load_module(name: str, path: Path):
spec = importlib.util.spec_from_file_location(name, path)
if spec is None or spec.loader is None:
raise RuntimeError(f"failed to load module: {path}")
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
return module
def use_transformers457() -> None:
import transformers457 as _transformers457
import transformers457.dynamic_module_utils as _dynamic_module_utils
sys.modules["transformers"] = _transformers457
_dynamic_module_utils.transformers = _transformers457
def enable_legacy_llama_config_positional_args() -> None:
import transformers
original = transformers.LlamaConfig
if getattr(original, "_audiocpp_legacy_positional_enabled", False):
return
class LegacyLlamaConfig(original):
_audiocpp_legacy_positional_enabled = True
def __init__(self, *args: Any, **kwargs: Any) -> None:
if args:
if len(args) != 5:
raise TypeError(f"Legacy LlamaConfig positional compatibility expects 5 args, got {len(args)}")
vocab_size, hidden_size, intermediate_size, num_hidden_layers, num_attention_heads = args
kwargs = {
"vocab_size": vocab_size,
"hidden_size": hidden_size,
"intermediate_size": intermediate_size,
"num_hidden_layers": num_hidden_layers,
"num_attention_heads": num_attention_heads,
**kwargs,
}
super().__init__(**kwargs)
transformers.LlamaConfig = LegacyLlamaConfig
def force_attention_implementation(module: object, value: str) -> None:
if hasattr(module, "attn_implementation"):
setattr(module, "attn_implementation", value)
if hasattr(module, "config"):
config = getattr(module, "config")
if hasattr(config, "attn_implementation"):
setattr(config, "attn_implementation", value)
if hasattr(config, "local_transformer_attn_implementation"):
setattr(config, "local_transformer_attn_implementation", value)
if hasattr(config, "gpt2_config") and getattr(config, "gpt2_config") is not None:
gpt2_config = getattr(config, "gpt2_config")
if hasattr(gpt2_config, "_attn_implementation"):
setattr(gpt2_config, "_attn_implementation", value)
if hasattr(gpt2_config, "attn_implementation"):
setattr(gpt2_config, "attn_implementation", value)
named_children = getattr(module, "named_children", None)
if callable(named_children):
for _, child in named_children():
force_attention_implementation(child, value)
def resample_linear_mono(waveform: np.ndarray, input_sample_rate: int, output_sample_rate: int) -> np.ndarray:
if input_sample_rate == output_sample_rate:
return waveform
scale = output_sample_rate / input_sample_rate
output_samples = int(round(len(waveform) * scale))
pos = np.arange(output_samples, dtype=np.float64) / scale
left = np.floor(pos).astype(np.int64)
right = np.minimum(left + 1, len(waveform) - 1)
frac = (pos - left).astype(np.float32)
return waveform[left] * (1.0 - frac) + waveform[right] * frac
class RefCitrinet:
LOG_EPS = float(np.ldexp(1.0, -24))
BN_EPS = 1.0e-3
NORM_EPS = 1.0e-5
def __init__(self, model_dir: Path, device: torch.device):
model_path = model_dir / "citrinet_256.safetensors"
self.device = device
self.tensors: dict[str, torch.Tensor] = {}
with safe_open(str(model_path), framework="pt", device="cpu") as f:
self.metadata = {
key: json.loads(value)
if value.startswith(("[", "{", "\"")) or value in {"true", "false", "null"} or value.lstrip("-").isdigit()
else value
for key, value in f.metadata().items()
}
for key in f.keys():
self.tensors[key] = f.get_tensor(key).float().contiguous().to(device)
self.sample_rate = int(self.metadata["sample_rate"])
self.n_mels = int(self.metadata["n_mels"])
self.n_fft = int(self.metadata["n_fft"])
self.hop = int(round(float(self.metadata["window_stride"]) * self.sample_rate))
self.win = int(round(float(self.metadata["window_size"]) * self.sample_rate))
self.pad_to = int(self.metadata["pad_to"])
self.blank_id = int(self.metadata["blank_id"])
self.jasper = list(self.metadata["jasper"])
self.window = self.tensors["preprocessor.featurizer.window"]
self.fb = self.tensors["preprocessor.featurizer.fb"].view(self.n_mels, self.n_fft // 2 + 1)
vocab_path = model_dir / str(self.metadata["vocab_file"])
self.vocab = [piece[:-1] if piece.endswith("\r") else piece for piece in vocab_path.read_text().split("\n")]
def bn(self, x: torch.Tensor, prefix: str) -> torch.Tensor:
w = self.tensors[f"{prefix}.weight"].view(1, -1, 1)
b = self.tensors[f"{prefix}.bias"].view(1, -1, 1)
mean = self.tensors[f"{prefix}.running_mean"].view(1, -1, 1)
var = self.tensors[f"{prefix}.running_var"].view(1, -1, 1)
return (x - mean) / torch.sqrt(var + self.BN_EPS) * w + b
def conv1d(self, x: torch.Tensor, prefix: str, stride: int, dilation: int, padding: int, groups: int, bias: bool) -> torch.Tensor:
weight = self.tensors[f"{prefix}.weight"]
if weight.ndim == 2:
weight = weight.unsqueeze(-1)
bias_t = self.tensors[f"{prefix}.bias"] if bias else None
return F.conv1d(x, weight, bias=bias_t, stride=stride, padding=padding, dilation=dilation, groups=groups)
def squeeze_excite(self, x: torch.Tensor, block: int, repeat: int) -> torch.Tensor:
se_index = 3 if repeat == 1 else repeat * 5 - 2
y = x.mean(dim=-1, keepdim=True)
y = self.conv1d(y, f"encoder.encoder.{block}.mconv.{se_index}.fc.0", 1, 1, 0, 1, False)
y = F.relu(y)
y = self.conv1d(y, f"encoder.encoder.{block}.mconv.{se_index}.fc.2", 1, 1, 0, 1, False)
return x * torch.sigmoid(y)
def block(self, x: torch.Tensor, block_index: int, cfg: dict) -> torch.Tensor:
residual_x = x
repeat = int(cfg["repeat"])
kernel = int(cfg["kernel"])
dilation = int(cfg["dilation"])
for r in range(repeat):
base = r * 5 if cfg["separable"] else r * 3
stride = int(cfg["stride"]) if r + 1 == repeat else 1
padding = dilation * (kernel - 1) // 2
if cfg["separable"]:
x = self.conv1d(x, f"encoder.encoder.{block_index}.mconv.{base}.conv", stride, dilation, padding, x.shape[1], False)
x = self.conv1d(x, f"encoder.encoder.{block_index}.mconv.{base + 1}.conv", 1, 1, 0, 1, False)
x = self.bn(x, f"encoder.encoder.{block_index}.mconv.{base + 2}")
else:
x = self.conv1d(x, f"encoder.encoder.{block_index}.mconv.{base}.conv", stride, dilation, padding, 1, False)
x = self.bn(x, f"encoder.encoder.{block_index}.mconv.{base + 1}")
if r + 1 != repeat:
x = F.relu(x)
if cfg.get("se", False):
x = self.squeeze_excite(x, block_index, repeat)
if cfg["residual"]:
residual_stride = int(cfg["stride"]) if cfg.get("residual_mode") == "stride_add" else 1
res = self.conv1d(residual_x, f"encoder.encoder.{block_index}.res.0.0.conv", residual_stride, 1, 0, 1, False)
res = self.bn(res, f"encoder.encoder.{block_index}.res.0.1")
x = x + res
return F.relu(x)
def compute_features(self, waveform: np.ndarray) -> tuple[torch.Tensor, int]:
xt = torch.from_numpy(waveform.astype(np.float32, copy=False)).to(self.device).unsqueeze(0)
stft = torch.stft(xt, n_fft=self.n_fft, hop_length=self.hop, win_length=self.win, window=self.window, center=True, pad_mode="constant", normalized=False, onesided=True, return_complex=True)
mel = torch.matmul(self.fb, stft.abs().pow(2.0)[0]).transpose(0, 1)
feats = torch.log(mel + self.LOG_EPS)
raw_frames = int(feats.shape[0])
mean = feats.mean(dim=0, keepdim=True)
var = ((feats - mean) ** 2).sum(dim=0, keepdim=True) / max(raw_frames - 1, 1)
feats = (feats - mean) / (torch.sqrt(var) + self.NORM_EPS)
if self.pad_to > 1:
padded = ((raw_frames + self.pad_to - 1) // self.pad_to) * self.pad_to
if padded != raw_frames:
feats = F.pad(feats, (0, 0, 0, padded - raw_frames))
return feats, raw_frames
def output_frames(self, input_frames: int) -> int:
frames = input_frames
for cfg in self.jasper:
stride = int(cfg["stride"])
if stride > 1:
frames = (frames + stride - 1) // stride
return frames
def infer_features(self, features: torch.Tensor) -> torch.Tensor:
x = features.float().t().unsqueeze(0)
for block_index, cfg in enumerate(self.jasper):
x = self.block(x, block_index, cfg)
logits = self.conv1d(x, "decoder.decoder_layers.0", 1, 1, 0, 1, True)
return logits.squeeze(0).transpose(0, 1).contiguous()
def greedy_decode(self, logits: torch.Tensor) -> str:
rows = logits.detach().cpu().numpy()
ids: list[int] = []
prev = -1
for row in rows:
best = int(np.argmax(row))
if best == prev:
continue
prev = best
if best != self.blank_id:
ids.append(best)
text = ""
for idx in ids:
piece = self.vocab[idx]
if piece.startswith("##"):
text += piece[2:]
elif not text or text[-1] in {"'", "-"} or piece in {".", ",", "!", "?", ":", ";", "'", "\"", ")", "]", "}", "-", "/", "\\"}:
text += piece
else:
text += " " + piece
return text
def transcribe(self, audio_path: Path) -> str:
waveform, sample_rate = read_wav_mono_f32(audio_path)
waveform = resample_linear_mono(waveform, sample_rate, self.sample_rate)
features, raw_frames = self.compute_features(waveform)
logits = self.infer_features(features)
return self.greedy_decode(logits[: self.output_frames(raw_frames)])
class RefMarbleNet:
FEATURE_DIM = 80
TARGET_SR = 16000
N_FFT = 512
HOP = 160
WIN = 400
LOG_EPS = float(np.ldexp(1.0, -24))
BN_EPS = 1.0e-3
OUTPUT_STRIDE = 2
def __init__(self, model_dir: Path, device: torch.device):
self.device = device
self.tensors: dict[str, torch.Tensor] = {}
with safe_open(str(model_dir / "marblenet_vad.safetensors"), framework="pt", device="cpu") as f:
for key in f.keys():
self.tensors[key] = f.get_tensor(key).float().contiguous().to(device)
self.window = self.tensors["preprocessor.featurizer.window"]
self.fb = self.tensors["preprocessor.featurizer.fb"].view(self.FEATURE_DIM, self.N_FFT // 2 + 1)
def bn(self, x: torch.Tensor, prefix: str) -> torch.Tensor:
w = self.tensors[f"{prefix}.weight"].view(1, -1, 1)
b = self.tensors[f"{prefix}.bias"].view(1, -1, 1)
mean = self.tensors[f"{prefix}.running_mean"].view(1, -1, 1)
var = self.tensors[f"{prefix}.running_var"].view(1, -1, 1)
return (x - mean) / torch.sqrt(var + self.BN_EPS) * w + b
def conv1d(self, x: torch.Tensor, prefix: str, stride: int, dilation: int, padding: int, groups: int, bias: bool) -> torch.Tensor:
weight = self.tensors[f"{prefix}.weight"]
if weight.ndim == 2:
weight = weight.unsqueeze(-1)
bias_t = self.tensors[f"{prefix}.bias"] if bias else None
return F.conv1d(x, weight, bias=bias_t, stride=stride, padding=padding, dilation=dilation, groups=groups)
def block(self, x: torch.Tensor, block: int, repeat: int, kernel: int, stride: int, dilation: int, residual: bool, separable: bool) -> torch.Tensor:
residual_x = x
for r in range(repeat):
if separable:
base = r * 5
x = self.conv1d(x, f"encoder.encoder.{block}.mconv.{base}.conv", stride, dilation, dilation * (kernel - 1) // 2, x.shape[1], False)
x = self.conv1d(x, f"encoder.encoder.{block}.mconv.{base + 1}.conv", 1, 1, 0, 1, False)
x = self.bn(x, f"encoder.encoder.{block}.mconv.{base + 2}")
else:
base = r * 3
x = self.conv1d(x, f"encoder.encoder.{block}.mconv.{base}.conv", stride, dilation, dilation * (kernel - 1) // 2, 1, False)
x = self.bn(x, f"encoder.encoder.{block}.mconv.{base + 1}")
if r + 1 != repeat:
x = F.relu(x)
if residual:
res = self.conv1d(residual_x, f"encoder.encoder.{block}.res.0.0.conv", 1, 1, 0, 1, False)
res = self.bn(res, f"encoder.encoder.{block}.res.0.1")
x = x + res
return F.relu(x)
def detect(self, audio_path: Path, threshold: float = 0.5) -> list[dict[str, float | int]]:
waveform, sample_rate = read_wav_mono_f32(audio_path)
waveform = resample_linear_mono(waveform, sample_rate, self.TARGET_SR)
xt = torch.from_numpy(waveform.astype(np.float32, copy=False)).to(self.device).unsqueeze(0)
stft = torch.stft(xt, n_fft=self.N_FFT, hop_length=self.HOP, win_length=self.WIN, window=self.window, center=True, pad_mode="constant", normalized=False, onesided=True, return_complex=True)
mel = torch.matmul(self.fb, stft.abs().pow(2.0)[0]).transpose(0, 1)
feats = torch.log(mel + self.LOG_EPS)
if feats.shape[0] % 2 != 0:
feats = F.pad(feats, (0, 0, 0, 1))
x = feats.float().t().unsqueeze(0)
x = self.block(x, 0, repeat=1, kernel=11, stride=2, dilation=1, residual=False, separable=True)
x = self.block(x, 1, repeat=2, kernel=13, stride=1, dilation=1, residual=True, separable=True)
x = self.block(x, 2, repeat=2, kernel=15, stride=1, dilation=1, residual=True, separable=True)
x = self.block(x, 3, repeat=2, kernel=17, stride=1, dilation=1, residual=True, separable=True)
x = self.block(x, 4, repeat=1, kernel=29, stride=1, dilation=2, residual=False, separable=True)
x = self.block(x, 5, repeat=1, kernel=1, stride=1, dilation=1, residual=False, separable=False)
logits = self.conv1d(x, "decoder.layer0", 1, 1, 0, 1, True).squeeze(0).transpose(0, 1).contiguous().detach().cpu().numpy()
if logits.shape[1] == 1:
probabilities = 1.0 / (1.0 + np.exp(-logits[:, 0]))
else:
shifted = logits[:, :2] - logits[:, :2].max(axis=1, keepdims=True)
exp = np.exp(shifted)
probabilities = exp[:, 1] / exp.sum(axis=1)
segments: list[dict[str, float | int]] = []
active = False
start_frame = 0
confidence_sum = 0.0
confidence_count = 0
for frame, probability in enumerate(probabilities):
if float(probability) >= threshold:
if not active:
active = True
start_frame = frame
confidence_sum = 0.0
confidence_count = 0
confidence_sum += float(probability)
confidence_count += 1
continue
if active:
segments.append({
"start_sample": int(start_frame * self.HOP * self.OUTPUT_STRIDE * sample_rate / self.TARGET_SR),
"end_sample": int(frame * self.HOP * self.OUTPUT_STRIDE * sample_rate / self.TARGET_SR),
"confidence": confidence_sum / confidence_count,
})
active = False
if active:
segments.append({
"start_sample": int(start_frame * self.HOP * self.OUTPUT_STRIDE * sample_rate / self.TARGET_SR),
"end_sample": int(len(probabilities) * self.HOP * self.OUTPUT_STRIDE * sample_rate / self.TARGET_SR),
"confidence": confidence_sum / confidence_count,
})
return segments
RunnerFn = Callable[[dict[str, Any], argparse.Namespace], tuple[float, float]]
LoaderFn = Callable[[dict[str, Any], argparse.Namespace], tuple[Any, RunnerFn]]
def qwen3_asr_loader(case: dict[str, Any], args: argparse.Namespace) -> tuple[Any, RunnerFn]:
import torch
set_threads(args.threads)
use_transformers457()
sys.path.insert(0, str(REPO_ROOT / "reference" / "Qwen3-ASR"))
from qwen_asr import Qwen3ASRModel
device_map = f"cuda:{args.device}" if args.backend == "cuda" else "cpu"
model = Qwen3ASRModel.from_pretrained(
str(ensure_absolute_path(case["model"])),
device_map=device_map,
)
def run(request: dict[str, Any], _args: argparse.Namespace) -> tuple[float, float]:
started = time.perf_counter()
model.transcribe(
audio=request["audio"],
context=request.get("context", ""),
language=request.get("language") or None,
return_time_stamps=False,
)
if args.backend == "cuda":
torch.cuda.synchronize(args.device)
wall_ms = (time.perf_counter() - started) * 1000.0
return wall_ms, input_audio_duration_sec(request)
return model, run
def ace_step_loader(case: dict[str, Any], args: argparse.Namespace) -> tuple[Any, RunnerFn]:
set_threads(args.threads)
ref_root = REPO_ROOT / "reference" / "ACE-Step-1.5"
if str(REPO_ROOT) not in sys.path:
sys.path.insert(0, str(REPO_ROOT))
if str(ref_root) not in sys.path:
sys.path.insert(0, str(ref_root))
from acestep.handler import AceStepHandler
from acestep.inference import GenerationConfig, GenerationParams, generate_music
from acestep.llm_inference import LLMHandler
backend = "cuda" if args.backend == "cuda" else "cpu"
checkpoint_dir = ensure_absolute_path(case["model"])
os.environ["ACESTEP_CHECKPOINTS_DIR"] = str(checkpoint_dir)
dit_model_path = case.get("load_options", {}).get("ace_step.dit_model_path", "acestep-v15-turbo")
lm_model_path = case.get("load_options", {}).get("ace_step.lm_model_path", "acestep-5Hz-lm-1.7B")
dit_handler = AceStepHandler()
init_message, ok = dit_handler.initialize_service(
project_root=str(checkpoint_dir),
config_path=dit_model_path,
device=backend,
force_dtype=None,
use_flash_attention=False,
compile_model=False,
offload_to_cpu=False,
offload_dit_to_cpu=False,
quantization=None,
)
if not ok:
raise RuntimeError(f"ACE-Step DiT init failed: {init_message}")
llm_handler = LLMHandler()
init_message, ok = llm_handler.initialize(
checkpoint_dir=str(checkpoint_dir),
lm_model_path=lm_model_path,
backend="pt",
device=backend,
offload_to_cpu=False,
dtype=None,
)
if not ok:
raise RuntimeError(f"ACE-Step LM init failed: {init_message}")
def run(request: dict[str, Any], _args: argparse.Namespace) -> tuple[float, float]:
options = dict(request.get("options", {}))
params_dict = {
"task_type": request.get("task_route", "text2music"),
"caption": request.get("text", ""),
"lyrics": request.get("lyrics", ""),
"vocal_language": request.get("language", "unknown"),
"duration": request.get("duration_seconds"),
"inference_steps": request.get("num_inference_steps"),
"guidance_scale": request.get("guidance_scale"),
"seed": request.get("seed"),
"src_audio": request.get("audio"),
"reference_audio": request.get("reference_audio"),
"instruction": request.get("instruction"),
"audio_codes": request.get("audio_codes", ""),
"repainting_start": request.get("repaint_start"),
"repainting_end": request.get("repaint_end"),
"lm_cfg_scale": options.get("lm_cfg_scale"),
"lm_temperature": options.get("lm_temperature"),
"lm_top_k": options.get("lm_top_k"),
"lm_top_p": options.get("lm_top_p"),
}
negative_prompt = request.get("negative_prompt")
if negative_prompt is not None:
params_dict["lm_negative_prompt"] = negative_prompt
params_dict = {key: value for key, value in params_dict.items() if value is not None}
params = GenerationParams(**params_dict)
config = GenerationConfig(
batch_size=int(request.get("batch_size", 1)),
allow_lm_batch=False,
use_random_seed=not ("seed" in request),
seeds=[int(request.get("seed", 0))],
noise_file=None,
lm_batch_chunk_size=1,
constrained_decoding_debug=False,
audio_format="wav",
)
started = time.perf_counter()
results = generate_music(
dit_handler=dit_handler,
llm_handler=llm_handler,
params=params,
config=config,
)
if args.backend == "cuda":
torch.cuda.synchronize(args.device)
if not results.success or not results.audios:
raise RuntimeError(results.error or "ACE-Step returned no output")
first_audio = results.audios[0]
audio = np.asarray(first_audio["tensor"], dtype=np.float32).reshape(-1)
sample_rate = int(first_audio["sample_rate"])
wall_ms = (time.perf_counter() - started) * 1000.0
return wall_ms, audio_duration_sec(audio, sample_rate)
return (dit_handler, llm_handler), run
def qwen3_forced_aligner_loader(case: dict[str, Any], args: argparse.Namespace) -> tuple[Any, RunnerFn]:
import torch
set_threads(args.threads)
use_transformers457()
sys.path.insert(0, str(REPO_ROOT / "reference" / "Qwen3-ASR"))
from qwen_asr.inference.qwen3_forced_aligner import Qwen3ForcedAligner
device_map = f"cuda:{args.device}" if args.backend == "cuda" else "cpu"
model = Qwen3ForcedAligner.from_pretrained(
str(ensure_absolute_path(case["model"])),
device_map=device_map,
)
def run(request: dict[str, Any], _args: argparse.Namespace) -> tuple[float, float]:
started = time.perf_counter()
model.align(
audio=request["audio"],
text=request["text"],
language=request.get("language") or "English",
)
if args.backend == "cuda":
torch.cuda.synchronize(args.device)
wall_ms = (time.perf_counter() - started) * 1000.0
return wall_ms, input_audio_duration_sec(request)
return model, run
def qwen3_tts_loader(case: dict[str, Any], args: argparse.Namespace) -> tuple[Any, RunnerFn]:
import torch
set_threads(args.threads)
use_transformers457()
sys.path.insert(0, str(REPO_ROOT / "reference" / "Qwen3-TTS"))
from qwen_tts import Qwen3TTSModel
device_map = f"cuda:{args.device}" if args.backend == "cuda" else "cpu"
model = Qwen3TTSModel.from_pretrained(
str(ensure_absolute_path(case["model"])),
device_map=device_map,
)
def run(request: dict[str, Any], _args: argparse.Namespace) -> tuple[float, float]:
started = time.perf_counter()
if case["task"] == "vdes":
audio_list, sample_rate = model.generate_voice_design(
text=request["text"],
instruct=request["instruct"],
language=request.get("language", "English"),
max_new_tokens=int(request.get("max_tokens", 512)),
do_sample=bool(request.get("do_sample", True)),
)
elif request.get("speaker"):
audio_list, sample_rate = model.generate_custom_voice(
text=request["text"],
speaker=request["speaker"],
instruct=request.get("instruct", ""),
language=request.get("language", "English"),
max_new_tokens=int(request.get("max_tokens", 512)),
do_sample=bool(request.get("do_sample", True)),
)
else:
prompt = model.create_voice_clone_prompt(
ref_audio=request["voice_ref"],
ref_text=request["reference_text"],
)
audio_list, sample_rate = model.generate_voice_clone(
text=request["text"],
voice_clone_prompt=prompt,
language=request.get("language", "English"),
max_new_tokens=int(request.get("max_tokens", 512)),
do_sample=bool(request.get("do_sample", True)),
)
if args.backend == "cuda":
torch.cuda.synchronize(args.device)
wall_ms = (time.perf_counter() - started) * 1000.0
return wall_ms, audio_duration_sec(np.asarray(audio_list[0], dtype=np.float32), int(sample_rate))
return model, run
def chatterbox_loader(case: dict[str, Any], args: argparse.Namespace) -> tuple[Any, RunnerFn]:
import torch
set_threads(args.threads)
torch.backends.cudnn.enabled = False
sys.path.insert(0, str(REPO_ROOT / "reference" / "chatterbox" / "src"))
language = "en"
request_language = ""
if case["requests"]:
request_language = case["requests"][0].get("language", "en")
if request_language.lower() == "en":
from chatterbox.tts import ChatterboxTTS
else:
from chatterbox.mtl_tts import ChatterboxMultilingualTTS as ChatterboxTTS
language = request_language
device = f"cuda:{args.device}" if args.backend == "cuda" else "cpu"
model = ChatterboxTTS.from_local(ensure_absolute_path(case["model"]), device=device)
def run(request: dict[str, Any], _args: argparse.Namespace) -> tuple[float, float]:
started = time.perf_counter()
if language == "en":
wav = model.generate(request["text"], audio_prompt_path=request["voice_ref"])
else:
wav = model.generate(request["text"], language_id=language, audio_prompt_path=request["voice_ref"])
if args.backend == "cuda":
torch.cuda.synchronize(args.device)
audio = wav.detach().cpu().numpy().astype(np.float32)
wall_ms = (time.perf_counter() - started) * 1000.0
return wall_ms, audio_duration_sec(audio, int(model.sr))
return model, run
def miocodec_loader(case: dict[str, Any], args: argparse.Namespace) -> tuple[Any, RunnerFn]:
import torch
set_threads(args.threads)
sys.path.insert(0, str(REPO_ROOT / "reference" / "MioCodec" / "src"))
from miocodec import MioCodecModel, load_audio
model_dir = ensure_absolute_path(case["model"])
model = MioCodecModel.from_pretrained(
config_path=str(model_dir / "config.yaml"),
weights_path=str(model_dir / "model.safetensors"),
).eval()
device = torch.device(f"cuda:{args.device}" if args.backend == "cuda" else "cpu")
model = model.to(device)
def run(request: dict[str, Any], _args: argparse.Namespace) -> tuple[float, float]:
source = load_audio(request["audio"], sample_rate=model.config.sample_rate).to(device)
target = load_audio(request["voice_ref"], sample_rate=model.config.sample_rate).to(device)
started = time.perf_counter()
with torch.inference_mode():
decoded = model.voice_conversion(source, target)
if args.backend == "cuda":
torch.cuda.synchronize(args.device)
audio = decoded.detach().cpu().float().numpy()
wall_ms = (time.perf_counter() - started) * 1000.0
return wall_ms, audio_duration_sec(audio, int(model.config.sample_rate))
return model, run
def miotts_loader(case: dict[str, Any], args: argparse.Namespace) -> tuple[Any, RunnerFn]:
from transformers import AutoModelForCausalLM, AutoTokenizer
set_threads(args.threads)
ref_root = REPO_ROOT / "reference" / "MioTTS-Inference"
codec_root = REPO_ROOT / "reference" / "MioCodec" / "src"
if str(codec_root) not in sys.path:
sys.path.insert(0, str(codec_root))
if str(ref_root) not in sys.path:
sys.path.insert(0, str(ref_root))
from miocodec import MioCodecModel
from miotts_server.audio import load_reference_audio_path
from miotts_server.codec import MioCodecService
from miotts_server.text import normalize_text
from miotts_server.token_parser import parse_speech_tokens
device = f"cuda:{args.device}" if args.backend == "cuda" else "cpu"
model_path = ensure_absolute_path(case["model"])
tokenizer = AutoTokenizer.from_pretrained(str(model_path), local_files_only=True)
model = AutoModelForCausalLM.from_pretrained(str(model_path), local_files_only=True).to(device).eval()
codec = MioCodecService(model_id=str(REPO_ROOT / "models" / "MioCodec-25Hz-44.1kHz-v2"), device=device, presets_dir=REPO_ROOT / "presets")
codec_model_dir = REPO_ROOT / "models" / "MioCodec-25Hz-44.1kHz-v2"
codec._codec = MioCodecModel.from_pretrained(
config_path=str(codec_model_dir / "config.yaml"),
weights_path=str(codec_model_dir / "model.safetensors"),
).eval().to(device)
def run(request: dict[str, Any], _args: argparse.Namespace) -> tuple[float, float]:
text = normalize_text(request["text"])
messages = [{"role": "user", "content": text}]
inputs = tokenizer.apply_chat_template(
messages,
tokenize=True,
add_generation_prompt=True,
return_dict=True,
return_tensors="pt",
).to(device)
reference_waveform = load_reference_audio_path(request["voice_ref"], codec.sample_rate).to(device)
started = time.perf_counter()
with torch.inference_mode():
output_ids = model.generate(
**inputs,
do_sample=bool(request.get("do_sample", True)),
max_new_tokens=int(request.get("max_tokens", 700)),
temperature=0.8,
top_p=1.0,
repetition_penalty=1.0,
pad_token_id=tokenizer.eos_token_id,
eos_token_id=tokenizer.eos_token_id,
)
prompt_length = inputs["input_ids"].shape[1]
generated_text = tokenizer.decode(output_ids[0, prompt_length:], skip_special_tokens=False)
speech_tokens = parse_speech_tokens(generated_text)
audio = codec.synthesize(speech_tokens, reference_waveform=reference_waveform)
if args.backend == "cuda":
torch.cuda.synchronize(args.device)
audio_tensor = audio if isinstance(audio, torch.Tensor) else torch.tensor(audio)
audio_np = audio_tensor.detach().cpu().numpy().astype(np.float32, copy=False).reshape(-1)
wall_ms = (time.perf_counter() - started) * 1000.0
return wall_ms, audio_duration_sec(audio_np, codec.sample_rate)
return (model, tokenizer, codec), run
def voxcpm2_loader(case: dict[str, Any], args: argparse.Namespace) -> tuple[Any, RunnerFn]:
import torch
set_threads(args.threads)
sys.path.insert(0, str(REPO_ROOT / "reference" / "VoxCPM" / "src"))
from voxcpm import VoxCPM
model = VoxCPM.from_pretrained(str(ensure_absolute_path(case["model"])), load_denoiser=False)
if args.backend == "cuda":
torch.cuda.set_device(args.device)
def run(request: dict[str, Any], _args: argparse.Namespace) -> tuple[float, float]:
kwargs = {
"text": request["text"],
"cfg_value": float(request.get("guidance_scale", 2.0)),
"inference_timesteps": int(request.get("num_inference_steps", 10)),
}
if request.get("voice_ref"):
kwargs["reference_wav_path"] = request["voice_ref"]
started = time.perf_counter()
wav = model.generate(**kwargs)
if args.backend == "cuda":
torch.cuda.synchronize(args.device)
audio = np.asarray(wav, dtype=np.float32)
wall_ms = (time.perf_counter() - started) * 1000.0
return wall_ms, audio_duration_sec(audio, int(model.tts_model.sample_rate))
return model, run
def kokoro_loader(case: dict[str, Any], args: argparse.Namespace) -> tuple[Any, RunnerFn]:
import torch
from safetensors.torch import load_file
set_threads(args.threads)
ref_root = REPO_ROOT / "reference" / "kokoro"
if str(ref_root) not in sys.path:
sys.path.insert(0, str(ref_root))
from kokoro.pipeline import KPipeline
from kokoro.model import KModel
model_dir = ensure_absolute_path(case["model"])
device = f"cuda:{args.device}" if args.backend == "cuda" else "cpu"
checkpoint_path = model_dir / "kokoro-v1_0.safetensors"
original_torch_load = torch.load
def patched_torch_load(path, *load_args, **load_kwargs):
if Path(path) == checkpoint_path:
flat_state = load_file(str(checkpoint_path), device="cpu")
grouped: dict[str, dict[str, object]] = {}
for name, tensor in flat_state.items():
prefix, rest = name.split(".", 1)
grouped.setdefault(prefix, {})[rest] = tensor
return grouped
return original_torch_load(path, *load_args, **load_kwargs)
torch.load = patched_torch_load
try:
model = KModel(
repo_id="hexgrad/Kokoro-82M",
config=str(model_dir / "config.json"),
model=str(checkpoint_path),
).to(device).eval()
finally:
torch.load = original_torch_load
voice_id = case.get("session_options", {}).get("voice", "af_heart")
lang_code = voice_id[0]
pipeline = KPipeline(lang_code=lang_code, model=model, repo_id="hexgrad/Kokoro-82M")
voices = json.loads((model_dir / "voices.json").read_text(encoding="utf-8"))
voice_info = voices[voice_id]
voice_pack = np.fromfile(model_dir / "voices" / voice_info["path"], dtype=np.float32).reshape(
int(voice_info["rows"]),
int(voice_info["cols"]),
)
voice_tensor = torch.from_numpy(voice_pack).unsqueeze(1)
def run(request: dict[str, Any], _args: argparse.Namespace) -> tuple[float, float]:
started = time.perf_counter()
outputs = [
item
for item in pipeline(
request["text"],
voice=voice_tensor,
speed=1.0,
split_pattern=r"\n+",
)
if getattr(item, "audio", None) is not None
]
if args.backend == "cuda":
torch.cuda.synchronize(args.device)
if not outputs:
raise RuntimeError("Kokoro produced no audio")
audio = np.concatenate([np.asarray(item.audio, dtype=np.float32) for item in outputs])
wall_ms = (time.perf_counter() - started) * 1000.0
return wall_ms, audio_duration_sec(audio, 24000)
return (pipeline, voice_tensor), run
def pocket_tts_loader(case: dict[str, Any], args: argparse.Namespace) -> tuple[Any, RunnerFn]:
import yaml
import torch
set_threads(args.threads)
ref_root = REPO_ROOT / "reference" / "pocket-tts"
if str(ref_root) not in sys.path:
sys.path.insert(0, str(ref_root))
from pocket_tts import TTSModel
model_dir = ensure_absolute_path(case["model"])
language = case.get("session_options", {}).get("language", "english")
config_src = ref_root / "pocket_tts" / "config" / f"{language}.yaml"
config = yaml.safe_load(config_src.read_text(encoding="utf-8"))
bundle_dir = model_dir / "languages" / language if (model_dir / "languages" / language).exists() else model_dir
config["weights_path"] = str(bundle_dir / "model.safetensors")
config["weights_path_without_voice_cloning"] = str(bundle_dir / "model.safetensors")
config["flow_lm"]["lookup_table"]["tokenizer_path"] = str(bundle_dir / "tokenizer.model")
config_dir = REPO_ROOT / "build" / "perf" / "pocket_tts"
config_dir.mkdir(parents=True, exist_ok=True)
config_path = config_dir / f"{language}.yaml"
config_path.write_text(yaml.safe_dump(config, sort_keys=False), encoding="utf-8")
device = torch.device(f"cuda:{args.device}" if args.backend == "cuda" else "cpu")
model = TTSModel.load_model(config=str(config_path)).to(device).eval()
def run(request: dict[str, Any], _args: argparse.Namespace) -> tuple[float, float]:
voice_state = model.get_state_for_audio_prompt(request["voice_ref"])
started = time.perf_counter()
audio = model.generate_audio(voice_state, request["text"])
if args.backend == "cuda":
torch.cuda.synchronize(args.device)
audio_np = audio.detach().cpu().numpy().astype(np.float32, copy=False)
wall_ms = (time.perf_counter() - started) * 1000.0
return wall_ms, audio_duration_sec(audio_np, int(model.sample_rate))
return model, run
def omnivoice_loader(case: dict[str, Any], args: argparse.Namespace) -> tuple[Any, RunnerFn]:
import torch
set_threads(args.threads)
ref_root = REPO_ROOT / "reference" / "OmniVoice"
if str(ref_root) not in sys.path:
sys.path.insert(0, str(ref_root))
from omnivoice.models.omnivoice import OmniVoice
device_map = f"cuda:{args.device}" if args.backend == "cuda" else "cpu"
model = OmniVoice.from_pretrained(str(ensure_absolute_path(case["model"])), device_map=device_map)
def run(request: dict[str, Any], _args: argparse.Namespace) -> tuple[float, float]:
started = time.perf_counter()
audio = model.generate(
text=request["text"],
language=request.get("language", "en"),
ref_audio=request.get("voice_ref"),
ref_text=request.get("reference_text"),
instruct=request.get("instruct"),
num_step=int(request.get("num_inference_steps", 16)),
guidance_scale=float(request.get("guidance_scale", 2.0)),
audio_chunk_duration=float(request.get("options", {}).get("audio_chunk_duration", 15.0)),
)[0]
if args.backend == "cuda":
torch.cuda.synchronize(args.device)
audio_np = np.asarray(audio, dtype=np.float32)
wall_ms = (time.perf_counter() - started) * 1000.0
return wall_ms, audio_duration_sec(audio_np, int(model.sampling_rate))
return model, run
def moss_tts_loader(case: dict[str, Any], args: argparse.Namespace) -> tuple[Any, RunnerFn]:
import torch
use_transformers457()
from transformers import AutoConfig, AutoModelForCausalLM
set_threads(args.threads)
device = f"cuda:{args.device}" if args.backend == "cuda" else "cpu"
model_path = ensure_absolute_path(case["model"])
config = AutoConfig.from_pretrained(str(model_path), trust_remote_code=True, local_files_only=True)
attention_impl = "sdpa" if args.backend == "cuda" else "eager"
config.attn_implementation = attention_impl
config.local_transformer_attn_implementation = attention_impl
if getattr(config, "gpt2_config", None) is not None:
config.gpt2_config._attn_implementation = attention_impl
model = AutoModelForCausalLM.from_pretrained(
str(model_path),
config=config,
trust_remote_code=True,
local_files_only=True,
).to(device).eval()
force_attention_implementation(model, attention_impl)
audio_tokenizer_path = str(REPO_ROOT / "models" / "MOSS-Audio-Tokenizer-Nano")
text_tokenizer_path = str(model_path / "tokenizer.model") if (model_path / "tokenizer.model").is_file() else str(model_path)
def run(request: dict[str, Any], _args: argparse.Namespace) -> tuple[float, float]:
out_path = REPO_ROOT / "build" / "perf" / "moss_tts_request.wav"
started = time.perf_counter()
model.inference(
text=request["text"],
output_audio_path=str(out_path),
mode="voice_clone",
prompt_audio_path=request["voice_ref"],
text_tokenizer_path=text_tokenizer_path,
audio_tokenizer_pretrained_name_or_path=audio_tokenizer_path,
device=device,
nq=16,
max_new_frames=int(request.get("max_tokens", 120)),
do_sample=bool(request.get("do_sample", False)),
use_kv_cache=True,
)
if args.backend == "cuda":
torch.cuda.synchronize(args.device)
audio, sample_rate = read_wav_mono_f32(out_path)
wall_ms = (time.perf_counter() - started) * 1000.0
return wall_ms, audio_duration_sec(audio, sample_rate)
return model, run
def demucs_loader(case: dict[str, Any], args: argparse.Namespace) -> tuple[Any, RunnerFn]:
import torch
set_threads(args.threads)
ref_root = REPO_ROOT / "reference" / "demucs"
if str(ref_root) not in sys.path:
sys.path.insert(0, str(ref_root))
from demucs.api import Separator
device = f"cuda:{args.device}" if args.backend == "cuda" else "cpu"
model_path = ensure_absolute_path(case["model"])
model_name = "htdemucs"
repo_arg: Path | None = model_path
manifest_path = model_path / "manifest.json"
if manifest_path.is_file():
repo_arg = None
separator = Separator(
model=model_name,
repo=repo_arg,
device=device,
shifts=0,
overlap=0.25,
split=True,
segment=None,
jobs=0,
progress=False,
)
def run(request: dict[str, Any], _args: argparse.Namespace) -> tuple[float, float]:
started = time.perf_counter()
separator.separate_audio_file(Path(request["audio"]))
if args.backend == "cuda":
torch.cuda.synchronize(args.device)
wall_ms = (time.perf_counter() - started) * 1000.0
return wall_ms, input_audio_duration_sec(request)
return separator, run
def roformer_loader(case: dict[str, Any], args: argparse.Namespace) -> tuple[Any, RunnerFn]:
import types
import yaml
import soundfile as sf
import torch
set_threads(args.threads)
ref_root = REPO_ROOT / "reference" / "Mel-Band-Roformer-Vocal-Model"
if str(ref_root) not in sys.path:
sys.path.insert(0, str(ref_root))
if "ml_collections" not in sys.modules:
class ConfigDict(dict):
def __init__(self, *args, **kwargs):
super().__init__()
payload = dict(*args, **kwargs)
for key, value in payload.items():
self[key] = self._convert(value)
@classmethod
def _convert(cls, value):
if isinstance(value, dict):
return cls(value)
if isinstance(value, list):
return [cls._convert(item) for item in value]
if isinstance(value, tuple):
return tuple(cls._convert(item) for item in value)
return value
def __getattr__(self, name):
return self[name]
def __setattr__(self, name, value):
self[name] = self._convert(value)
module = types.ModuleType("ml_collections")
module.ConfigDict = ConfigDict
sys.modules["ml_collections"] = module
from ml_collections import ConfigDict
from inference import run_folder
from utils import get_model_from_config
ckpt_path = ensure_absolute_path("models/melbandroformer/MelBandRoformer.ckpt")
config_path = REPO_ROOT / "reference" / "Mel-Band-Roformer-Vocal-Model" / "configs" / "config_vocals_mel_band_roformer.yaml"
config = ConfigDict(yaml.load(config_path.read_text(encoding="utf-8"), Loader=yaml.FullLoader))
model = get_model_from_config("mel_band_roformer", config)
state = torch.load(ckpt_path, map_location="cpu")
model.load_state_dict(state, strict=False)
device = torch.device(f"cuda:{args.device}" if args.backend == "cuda" else "cpu")
model = model.to(device=device).eval()
def run(request: dict[str, Any], _args: argparse.Namespace) -> tuple[float, float]:
work_dir = REPO_ROOT / "build" / "perf" / "roformer"
input_dir = work_dir / "input"
store_dir = work_dir / "store"
input_dir.mkdir(parents=True, exist_ok=True)
store_dir.mkdir(parents=True, exist_ok=True)
staged = input_dir / Path(request["audio"]).name
shutil.copyfile(request["audio"], staged)
started = time.perf_counter()
run_folder(model, argparse.Namespace(input_folder=str(input_dir), store_dir=str(store_dir)), config, device, verbose=False)
if args.backend == "cuda":
torch.cuda.synchronize(args.device)
wall_ms = (time.perf_counter() - started) * 1000.0
return wall_ms, input_audio_duration_sec(request)
return model, run
def seed_vc_loader(case: dict[str, Any], args: argparse.Namespace) -> tuple[Any, RunnerFn]:
import os
import importlib
import torch
from types import SimpleNamespace
set_threads(args.threads)
ref_root = REPO_ROOT / "reference" / "SeedVC"
sys.path.insert(0, str(ref_root))
bigvgan_module = importlib.import_module("modules.bigvgan.bigvgan")
bigvgan_from_pretrained = bigvgan_module.BigVGAN._from_pretrained.__func__
def patched_bigvgan_from_pretrained(
cls,
*,
model_id,
revision,
cache_dir,
force_download,
proxies=None,
resume_download=False,
local_files_only=False,
token=None,
map_location="cpu",
strict=False,
use_cuda_kernel=False,
**model_kwargs,
):
return bigvgan_from_pretrained(
cls,
model_id=model_id,
revision=revision,
cache_dir=cache_dir,
force_download=force_download,
proxies=proxies,
resume_download=resume_download,
local_files_only=local_files_only,
token=token,
map_location=map_location,
strict=strict,
use_cuda_kernel=use_cuda_kernel,
**model_kwargs,
)
bigvgan_module.BigVGAN._from_pretrained = classmethod(patched_bigvgan_from_pretrained)
cwd = os.getcwd()
os.chdir(ref_root)
try:
module = load_module("seedvc_reference_inference_v2_perf", ref_root / "inference_v2.py")
finally:
os.chdir(cwd)
model_root = ensure_absolute_path(case["model"])
if (model_root / "v2" / "ar.safetensors").is_file():
official_root = REPO_ROOT / "models" / "SeedVC"
if official_root.is_dir():
model_root = official_root
device = f"cuda:{args.device}" if args.backend == "cuda" else "cpu"
load_args = SimpleNamespace(
ar_checkpoint_path=str(model_root / "seed-vc/v2/ar_base.pth"),
cfm_checkpoint_path=str(model_root / "seed-vc/v2/cfm_small.pth"),
compile=False,
output=str(REPO_ROOT / "build" / "perf" / "seedvc"),
)
cwd = os.getcwd()
os.chdir(ref_root)
try:
wrapper = module.load_v2_models(load_args)
module.vc_wrapper_v2 = wrapper
finally:
os.chdir(cwd)
def run(request: dict[str, Any], _args: argparse.Namespace) -> tuple[float, float]:
run_args = SimpleNamespace(
diffusion_steps=int(request.get("num_inference_steps", 30)),
length_adjust=float(request.get("options", {}).get("length_adjust", 1.0)),
intelligibility_cfg_rate=float(request.get("options", {}).get("intelligibility_cfg_rate", 0.7)),
similarity_cfg_rate=float(request.get("options", {}).get("similarity_cfg_rate", 0.7)),
top_p=0.9,
temperature=1.0,
repetition_penalty=1.0,
convert_style=False,
anonymization_only=False,
)
started = time.perf_counter()
cwd_inner = os.getcwd()
os.chdir(ref_root)
try:
audio = module.convert_voice_v2(request["audio"], request["voice_ref"], run_args)
finally:
os.chdir(cwd_inner)
if args.backend == "cuda":
torch.cuda.synchronize(args.device)
sample_rate, waveform = audio
audio_np = np.asarray(waveform, dtype=np.float32).reshape(-1)
wall_ms = (time.perf_counter() - started) * 1000.0
return wall_ms, audio_duration_sec(audio_np, int(sample_rate))
return wrapper, run
def vevo2_loader(case: dict[str, Any], args: argparse.Namespace) -> tuple[Any, RunnerFn]:
import torch
set_threads(args.threads)
use_transformers457()
enable_legacy_llama_config_positional_args()
ref_root = REPO_ROOT / "reference" / "Amphion"
if str(ref_root) not in sys.path:
sys.path.insert(0, str(ref_root))
from models.svc.vevo2.vevo2_utils import Vevo2InferencePipeline
model_root = ensure_absolute_path(case["model"])
device = torch.device(f"cuda:{args.device}" if args.backend == "cuda" else "cpu")
cwd = os.getcwd()
os.chdir(ref_root)
try:
pipeline = Vevo2InferencePipeline(
prosody_tokenizer_ckpt_path=str(model_root / "tokenizer" / "prosody_fvq512_6.25hz"),
content_style_tokenizer_ckpt_path=str(model_root / "tokenizer" / "contentstyle_fvq16384_12.5hz"),
ar_cfg_path=str(model_root / "contentstyle_modeling" / "posttrained" / "amphion_config.json"),
ar_ckpt_path=str(model_root / "contentstyle_modeling" / "posttrained"),
fmt_cfg_path=str(model_root / "acoustic_modeling" / "fm_emilia101k_singnet7k_repa" / "config.json"),
fmt_ckpt_path=str(model_root / "acoustic_modeling" / "fm_emilia101k_singnet7k_repa"),
vocoder_cfg_path=str(model_root / "vocoder" / "config.json"),
vocoder_ckpt_path=str(model_root / "vocoder"),
device=device,
)
finally:
os.chdir(cwd)
def run(request: dict[str, Any], _args: argparse.Namespace) -> tuple[float, float]:
started = time.perf_counter()
cwd_inner = os.getcwd()
os.chdir(ref_root)
try:
audio = pipeline.inference_ar_and_fm(
target_text=request["target_text"],
prosody_wav_path=request.get("style_ref"),
style_ref_wav_path=request.get("style_ref"),
style_ref_wav_text=request.get("style_ref_text", ""),
timbre_ref_wav_path=request.get("target_voice"),
top_k=int(request.get("top_k", 25)),
top_p=float(request.get("top_p", 0.8)),
temperature=float(request.get("temperature", 1.0)),
flow_matching_steps=int(request.get("num_inference_steps", 32)),
display_audio=False,
)
finally:
os.chdir(cwd_inner)
if args.backend == "cuda":
torch.cuda.synchronize(args.device)
audio_np = np.asarray(audio, dtype=np.float32).reshape(-1)
wall_ms = (time.perf_counter() - started) * 1000.0
return wall_ms, audio_duration_sec(audio_np, 24000)
return pipeline, run
def parakeet_loader(case: dict[str, Any], args: argparse.Namespace) -> tuple[Any, RunnerFn]:
set_threads(args.threads)
driver = load_module("parakeet_test_driver_perf", REPO_ROOT / "reference" / "parakeet-tdt" / "tools" / "test_driver.py")
driver_args = argparse.Namespace(
model=str(ensure_absolute_path(case["model"])),
audio="",
backend=args.backend,
device=args.device,
mode="perf",
run_mode="offline",
trace_log=None,
timing_log=None,
batch_size=1,
timestamps=False,
timestamp_levels="char,word,segment",
self_attention_model="rel_pos_local_attn",
att_context_left=256,
att_context_right=256,
chunk_secs=2.0,
left_context_secs=10.0,
right_context_secs=2.0,
clean_groundtruth_text=False,
langid="en",
)
driver.configure_runtime(driver_args)
nemo_asr, open_dict, torch, _timing_log_scalar, _trace_log_scalar = driver.import_runtime_modules()
torch.set_num_threads(args.threads)
if hasattr(torch, "set_num_interop_threads"):
try:
torch.set_num_interop_threads(1)
except RuntimeError:
pass
model = driver.resolve_model(nemo_asr, driver_args.model)
driver.configure_device(torch, model, driver_args.backend)
driver.configure_timestamps(model, open_dict)
def run(request: dict[str, Any], _args: argparse.Namespace) -> tuple[float, float]:
started = time.perf_counter()
model.transcribe(
[request["audio"]],
batch_size=1,
return_hypotheses=False,
timestamps=False,
)
if args.backend == "cuda":
torch.cuda.synchronize(args.device)
wall_ms = (time.perf_counter() - started) * 1000.0
return wall_ms, input_audio_duration_sec(request)
return model, run
def sortformer_loader(case: dict[str, Any], args: argparse.Namespace) -> tuple[Any, RunnerFn]:
import librosa
import torch
set_threads(args.threads)
ref_root = REPO_ROOT / "reference" / "nemo"
if str(ref_root) not in sys.path:
sys.path.insert(0, str(ref_root))
from nemo.collections.asr.models import SortformerEncLabelModel
from nemo.collections.asr.parts.mixins.diarization import DiarizeConfig
map_location = torch.device(f"cuda:{args.device}" if args.backend == "cuda" else "cpu")
model_path = ensure_absolute_path(case["model"])
model_name = str(model_path)
if model_name.endswith(".nemo"):
model = SortformerEncLabelModel.restore_from(model_name, map_location=map_location).to(map_location)
elif model_path.is_dir():
model = SortformerEncLabelModel.from_pretrained(model_name=f"nvidia/{model_path.name}", map_location=map_location).to(map_location)
else:
model = SortformerEncLabelModel.from_pretrained(model_name=model_name, map_location=map_location).to(map_location)
model.eval()
def run(request: dict[str, Any], _args: argparse.Namespace) -> tuple[float, float]:
audio_np, sample_rate = librosa.load(request["audio"], sr=None, mono=False)
started = time.perf_counter()
diarize_cfg = DiarizeConfig(
session_len_sec=20.0,
batch_size=1,
num_workers=0,
sample_rate=sample_rate,
verbose=False,
include_tensor_outputs=False,
)
model.diarize(
audio=audio_np,
sample_rate=sample_rate,
override_config=diarize_cfg,
)
if args.backend == "cuda":
torch.cuda.synchronize(args.device)
wall_ms = (time.perf_counter() - started) * 1000.0
return wall_ms, input_audio_duration_sec(request)
return model, run
def citrinet_loader(case: dict[str, Any], args: argparse.Namespace) -> tuple[Any, RunnerFn]:
set_threads(args.threads)
device = torch.device(f"cuda:{args.device}" if args.backend == "cuda" else "cpu")
model = RefCitrinet(ensure_absolute_path(case["model"]), device)
def run(request: dict[str, Any], _args: argparse.Namespace) -> tuple[float, float]:
started = time.perf_counter()
model.transcribe(Path(request["audio"]))
if args.backend == "cuda":
torch.cuda.synchronize(args.device)
wall_ms = (time.perf_counter() - started) * 1000.0
return wall_ms, input_audio_duration_sec(request)
return model, run
def marblenet_loader(case: dict[str, Any], args: argparse.Namespace) -> tuple[Any, RunnerFn]:
set_threads(args.threads)
device = torch.device(f"cuda:{args.device}" if args.backend == "cuda" else "cpu")
model = RefMarbleNet(ensure_absolute_path(case["model"]), device)
def run(request: dict[str, Any], _args: argparse.Namespace) -> tuple[float, float]:
started = time.perf_counter()
model.detect(Path(request["audio"]))
if args.backend == "cuda":
torch.cuda.synchronize(args.device)
wall_ms = (time.perf_counter() - started) * 1000.0
return wall_ms, input_audio_duration_sec(request)
return model, run
def silero_vad_loader(case: dict[str, Any], args: argparse.Namespace) -> tuple[Any, RunnerFn]:
import torch
set_threads(args.threads)
sys.path.insert(0, str(REPO_ROOT / "reference" / "silero-vad" / "src"))
from silero_vad import get_speech_timestamps, load_silero_vad
model = load_silero_vad(onnx=False)
device = torch.device(f"cuda:{args.device}" if args.backend == "cuda" else "cpu")
if args.backend == "cuda":
model = model.to(device)
def run(request: dict[str, Any], _args: argparse.Namespace) -> tuple[float, float]:
waveform, sample_rate = read_wav_mono_f32(Path(request["audio"]))
audio = torch.from_numpy(waveform.astype(np.float32, copy=False)).to(device)
started = time.perf_counter()
get_speech_timestamps(audio, model, sampling_rate=sample_rate, return_seconds=False, visualize_probs=False)
if args.backend == "cuda":
torch.cuda.synchronize(args.device)
wall_ms = (time.perf_counter() - started) * 1000.0
return wall_ms, audio_duration_sec(waveform, sample_rate)
return model, run
LOADERS: dict[str, LoaderFn] = {
"ace_step": ace_step_loader,
"qwen3_asr": qwen3_asr_loader,
"qwen3_forced_aligner": qwen3_forced_aligner_loader,
"qwen3_tts": qwen3_tts_loader,
"chatterbox": chatterbox_loader,
"miocodec": miocodec_loader,
"miotts": miotts_loader,
"voxcpm2": voxcpm2_loader,
"kokoro_tts": kokoro_loader,
"pocket_tts": pocket_tts_loader,
"omnivoice": omnivoice_loader,
"moss_tts_nano": moss_tts_loader,
"seed_vc": seed_vc_loader,
"vevo2": vevo2_loader,
"parakeet_tdt": parakeet_loader,
"sortformer_diar": sortformer_loader,
"citrinet_asr": citrinet_loader,
"marblenet_vad": marblenet_loader,
"htdemucs": demucs_loader,
"mel_band_roformer": roformer_loader,
"silero_vad": silero_vad_loader,
}
def measure_cold(loader: LoaderFn, case: dict[str, Any], request: dict[str, Any], args: argparse.Namespace) -> dict[str, Any]:
wall_ms: list[float] = []
duration_sec = 0.0
for _ in range(3):
started = time.perf_counter()
_model, run = loader(case, args)
run_wall_ms, duration_sec = run(request, args)
total_ms = (time.perf_counter() - started) * 1000.0
if total_ms < run_wall_ms:
total_ms = run_wall_ms
wall_ms.append(total_ms)
average_wall_ms = float(sum(wall_ms) / len(wall_ms))
return {
"wall_ms": wall_ms,
"average_wall_ms": average_wall_ms,
"duration_sec": duration_sec,
"rtf": (average_wall_ms / 1000.0 / duration_sec) if duration_sec > 0.0 else 0.0,
}
def measure_warm(loader: LoaderFn, case: dict[str, Any], warmup_request: dict[str, Any], request: dict[str, Any], args: argparse.Namespace) -> dict[str, Any]:
_model, run = loader(case, args)
run(warmup_request, args)
wall_ms: list[float] = []
duration_sec = 0.0
for _ in range(3):
run_wall_ms, duration_sec = run(request, args)
wall_ms.append(run_wall_ms)
average_wall_ms = float(sum(wall_ms) / len(wall_ms))
return {
"wall_ms": wall_ms,
"average_wall_ms": average_wall_ms,
"duration_sec": duration_sec,
"rtf": (average_wall_ms / 1000.0 / duration_sec) if duration_sec > 0.0 else 0.0,
}
def main() -> int:
args = parse_args()
perf_cases = load_perf_cases(args.perf_cases)
request_cases = read_json(args.request_cases)
timestamp = time.strftime("%Y%m%d-%H%M%S")
summary_out = args.summary_out or (REPO_ROOT / "build" / "logs" / "perf" / f"python_{args.backend}_{timestamp}" / "summary.json")
summary_out.parent.mkdir(parents=True, exist_ok=True)
summaries: list[dict[str, Any]] = []
for perf_case in perf_cases:
if args.id and args.id != perf_case.id:
continue
if perf_case.family not in LOADERS:
raise RuntimeError(f"python perf harness does not support family yet: {perf_case.family}")
case = find_case(request_cases, perf_case.case_id)
request = resolve_request_paths(materialize_perf_request(
find_request(case, perf_case.request_id),
perf_case.request_overrides,
perf_case.request_remove_keys,
))
if perf_case.warmup_request_id:
warmup_request = resolve_request_paths(materialize_perf_request(
find_request(case, perf_case.warmup_request_id),
perf_case.warmup_request_overrides,
perf_case.warmup_request_remove_keys,
))
else:
temp_dir = (summary_out.parent / "_warmup_temp" / perf_case.id).resolve()
temp_dir.mkdir(parents=True, exist_ok=True)
warmup_request = derive_warmup_request(request, temp_dir)
cold = measure_cold(LOADERS[perf_case.family], case, request, args)
warm = measure_warm(LOADERS[perf_case.family], case, warmup_request, request, args)
summary = {
"id": perf_case.id,
"family": perf_case.family,
"case_id": perf_case.case_id,
"request_id": perf_case.request_id,
"task": case["task"],
"mode": case["mode"],
"cold": cold,
"warm": warm,
}
summaries.append(summary)
print(
f"{perf_case.id} cold_avg_ms={cold['average_wall_ms']} cold_rtf={cold['rtf']} "
f"warm_avg_ms={warm['average_wall_ms']} warm_rtf={warm['rtf']}",
flush=True,
)
payload = {
"backend": args.backend,
"device": args.device,
"threads": args.threads,
"cases": summaries,
}
summary_out.write_text(json.dumps(payload, ensure_ascii=False) + "\n", encoding="utf-8")
print(f"summary_json={summary_out}", flush=True)
return 0
if __name__ == "__main__":
raise SystemExit(main())