music3lab / tests /test_inversion_v2.py
coolpoodle's picture
code and training scripts
90884df verified
Raw
History Blame Contribute Delete
7.79 kB
"""CPU-only mechanical contract for the frozen v2 inversion policy.
Expected public API: music3lab.inversion_v2 exposes the pure functions/classes
called below. Metric inputs are [batch, 2, samples] float tensors. The v1.3
loader returns all four bound E2 final latents, never a selected-only latent.
"""
from __future__ import annotations
import hashlib
from pathlib import Path
import pytest
import torch
from safetensors.torch import save as save_safetensors
from music3lab import inversion_v2 as v2
def _audio(samples: int = 128) -> torch.Tensor:
time = torch.arange(samples, dtype=torch.float32) / samples
return torch.stack((0.25 * torch.sin(2 * torch.pi * 7 * time), 0.20 * torch.cos(2 * torch.pi * 5 * time))).unsqueeze(0)
def test_time_nmse_and_stft_distinguish_identity_distortion_and_polarity() -> None:
target = _audio()
assert torch.equal(v2.target_energy_normalized_time_nmse(target, target), torch.zeros(1))
assert v2.target_energy_normalized_time_nmse(target + 0.2, target).item() > 0.1
assert v2.mrstft_magnitude_distance(-target, target, fft_sizes=(32, 64)).item() < 1e-6
assert v2.time_and_complex_stft_distance(-target, target, fft_sizes=(32, 64)).item() > 0.5
def test_selection_score_is_identical_at_every_training_stage() -> None:
metrics = {
"time_nmse": 0.125,
"complex_stft_nmse": 0.25,
"legacy_mrstft": 0.375,
"mid_side_nmse": 0.2,
"relative_envelope": 0.1,
}
scores = [v2.selection_score(metrics, stage=stage) for stage in ("fp32", "bf16", "handoff")]
assert scores == [scores[0]] * 3
@pytest.mark.parametrize(("stage", "warmup", "total", "peak"), (("fp32", 4, 20, 0.02), ("bf16", 2, 10, 0.01)))
def test_warmup_cosine_schedule_has_exact_frozen_endpoints(stage: str, warmup: int, total: int, peak: float) -> None:
minimum = peak / 10
schedule = v2.FrozenStageSchedule(
name=stage,
warmup_steps=warmup,
total_steps=total,
maximum_learning_rate=peak,
minimum_learning_rate=minimum,
)
assert v2.warmup_cosine_learning_rate(schedule, 0) == 0.0
assert v2.warmup_cosine_learning_rate(schedule, warmup) == peak
with pytest.raises(ValueError, match="step"):
v2.warmup_cosine_learning_rate(schedule, total + 1)
def _authority(path: Path) -> dict[str, object]:
data = path.read_bytes()
return {"path": path.name, "sha256": hashlib.sha256(data).hexdigest(), "size": len(data), "required_restart_count": 4, "tensor_key": "final_latents"}
def test_v11_e2_loader_requires_all_four_bound_final_latents(tmp_path: Path) -> None:
path = tmp_path / "latents.safetensors"
expected = torch.arange(24, dtype=torch.float32).reshape(4, 2, 3)
path.write_bytes(save_safetensors({"final_latents": expected, "selected_latent": expected[:1].clone()}))
authority = _authority(path)
path.chmod(0o644)
assert torch.equal(v2.load_v11_e2_final_latents(path, authority), expected)
selected_only = tmp_path / "selected-only.safetensors"
selected_only.write_bytes(save_safetensors({"selected_latent": expected[:1]}))
selected_only.chmod(0o644)
with pytest.raises((ValueError, RuntimeError), match="final|four|restart|sha|authority"):
v2.load_v11_e2_final_latents(selected_only, authority)
cherry_picked = tmp_path / "cherry-picked.safetensors"
cherry_picked.write_bytes(save_safetensors({"final_latents": expected[:3]}))
cherry_picked.chmod(0o644)
with pytest.raises((ValueError, RuntimeError), match="four|restart|sha"):
v2.load_v11_e2_final_latents(cherry_picked, authority)
path.write_bytes(save_safetensors({"final_latents": expected + 1}))
with pytest.raises((ValueError, RuntimeError), match="sha|authority|size"):
v2.load_v11_e2_final_latents(path, authority)
def test_restart_ledger_is_monotone_and_breaks_objective_ties_by_index() -> None:
ledger = v2.RestartLedger(restart_count=4)
ledger.record((4.0, 3.0, 2.0, 1.0))
ledger.record((5.0, 2.0, 3.0, 1.0))
assert ledger.best_so_far == (4.0, 2.0, 2.0, 1.0)
assert ledger.select((1.0, 1.0, 2.0, 3.0)) == 0
with pytest.raises((ValueError, RuntimeError), match="regress|monotone"):
ledger.record_best_so_far((4.1, 2.0, 2.0, 1.0))
def test_evaluator_cannot_run_before_lock_or_change_locked_selection() -> None:
lock = v2.SelectionLock()
with pytest.raises((ValueError, RuntimeError), match="lock|select"):
lock.evaluate(lambda index: {"rank": index})
assert lock.lock((3.0, 1.0, 1.0, 2.0)) == 1
assert lock.evaluate(lambda index: {"rank": index}) == {"rank": 1}
with pytest.raises((ValueError, RuntimeError), match="locked|selection"):
lock.lock((0.0, 3.0, 3.0, 3.0))
def test_distributional_prior_has_no_oracle_distance_input() -> None:
latents = torch.tensor([[[0.0, 1.0, 9.0, -9.0]]], dtype=torch.float32)
prior = v2.distributional_prior(latents, mean=0.0, std=1.0, tail_threshold=3.0)
assert prior["mean_error"] == pytest.approx(0.25)
assert prior["mean_term"] == pytest.approx(0.25**2)
assert prior["tail_term"] == pytest.approx(18.0)
expected = prior["mean_term"] + prior["std_term"] + 0.1 * prior["tail_term"]
assert prior["prior"] == pytest.approx(expected)
assert "oracle" not in " ".join(prior.keys()).lower()
class _TinyFrozenDecoder(torch.nn.Module):
def __init__(self) -> None:
super().__init__()
self.projection = torch.nn.Conv1d(2, 2, 1, bias=False)
torch.nn.init.eye_(self.projection.weight[..., 0])
for parameter in self.parameters():
parameter.requires_grad_(False)
def forward(self, latents: torch.Tensor) -> torch.Tensor:
return self.projection(latents)
def test_frozen_decoder_keeps_weights_grad_free_but_latents_receive_gradient() -> None:
decoder = _TinyFrozenDecoder()
latents = torch.full((1, 2, 32), 0.1, requires_grad=True)
audit = v2.frozen_decoder_step(decoder, latents, torch.zeros_like(latents))
assert audit.weight_sha256_before == audit.weight_sha256_after
assert audit.finite_loss and audit.finite_latent_gradient and audit.nonzero_latent_gradient
assert all(parameter.grad is None for parameter in decoder.parameters())
def test_progress_never_substitutes_for_feasibility_or_high_fidelity() -> None:
failed = v2.quality_gate(progress_fraction=0.99, feasibility_metrics={"time_nmse": 2.0}, high_fidelity_metrics={"si_sdr_db": -10.0})
assert not failed.feasibility_pass
assert not failed.high_fidelity_pass
assert failed.quality_claim == "NO_QUALITY_CLAIM"
def test_authority_tamper_and_atomic_publication(tmp_path: Path) -> None:
staged = tmp_path / "staged"
staged.mkdir()
staged.chmod(0o755)
payload = b"v2 evidence"
(staged / "metrics.json").write_bytes(payload)
(staged / "metrics.json").chmod(0o644)
authority = {"metrics.json": hashlib.sha256(payload).hexdigest()}
published = tmp_path / "published"
v2.atomic_publish_verified(staged, published, authority)
assert (published / "metrics.json").read_bytes() == payload
assert not staged.exists()
(published / "metrics.json").write_bytes(b"tampered")
with pytest.raises((ValueError, RuntimeError), match="sha|authority|tamper"):
v2.verify_published_authority(published, authority)
replacement = tmp_path / "replacement"
replacement.mkdir()
replacement.chmod(0o755)
(replacement / "metrics.json").write_bytes(payload)
(replacement / "metrics.json").chmod(0o644)
with pytest.raises((ValueError, RuntimeError), match="authority|sha"):
v2.atomic_publish_verified(replacement, published, {"metrics.json": "0" * 64})
assert (published / "metrics.json").read_bytes() == b"tampered"