| """CPU contract for an in-domain captured-Music3 token-prediction experiment. |
| |
| This is deliberately not a native Music3 tokenizer and it makes no claim for |
| arbitrary external music. Its only eligible teachers are paired captured |
| Music3 waveforms, tokens, priming rows, and re-emitted waveforms. |
| """ |
| from __future__ import annotations |
|
|
| import pytest |
| import torch |
|
|
| from music3lab.codec import native_token_adapter as adapter |
|
|
|
|
| SAMPLES = 44_032 |
| FRAMES = 25 |
| SPLIT_SEEDS = { |
| "train": tuple(range(1000, 1064)), |
| "validation": tuple(range(2000, 2016)), |
| "heldout": tuple(range(3000, 3016)), |
| } |
|
|
|
|
| def _sidecar(split: str) -> adapter.TokenTeacherSidecar: |
| seeds = SPLIT_SEEDS[split] |
| count = len(seeds) |
| audio = torch.zeros(count, 2, SAMPLES) |
| audio[:, 0, 0] = torch.tensor(seeds, dtype=audio.dtype) |
| semantic = torch.arange(count * FRAMES, dtype=torch.int64).reshape(count, FRAMES) % 16_384 |
| residual = torch.arange(count * FRAMES * 7, dtype=torch.int64).reshape(count, FRAMES, 7) % 1_024 |
| priming = torch.arange(count * 8, dtype=torch.int64).reshape(count, 8) % 1_024 |
| return adapter.TokenTeacherSidecar( |
| split=split, |
| seeds=seeds, |
| audio=audio, |
| semantic=semantic, |
| residual=residual, |
| priming=priming, |
| reemitted_audio=audio.clone(), |
| source_domain="captured_music3", |
| ) |
|
|
|
|
| def test_teacher_sidecars_have_exact_64_16_16_seed_pairing_and_reemission() -> None: |
| sidecars = tuple(_sidecar(name) for name in ("train", "validation", "heldout")) |
| report = adapter.validate_token_teacher_sidecars(sidecars) |
| assert report.split_counts == {"train": 64, "validation": 16, "heldout": 16} |
| assert report.seed_sets == SPLIT_SEEDS |
| assert report.source_domain == "captured_music3_only" |
|
|
| missing = _sidecar("train") |
| missing.reemitted_audio = None |
| with pytest.raises(ValueError, match="reemitted_audio"): |
| adapter.validate_token_teacher_sidecars((missing,)) |
|
|
| mismatched = _sidecar("train") |
| mismatched.reemitted_audio[0, 0, 0] += 1 |
| with pytest.raises(ValueError, match="re-emitted audio"): |
| adapter.validate_token_teacher_sidecars((mismatched,)) |
|
|
|
|
| def test_waveform_adapter_emits_all_codebook_logits_and_per_code_cross_entropy() -> None: |
| batch = _sidecar("validation") |
| model = adapter.CapturedMusic3TokenAdapter(adapter.TokenAdapterConfig(hidden_channels=8)) |
| semantic_logits, residual_logits = model(batch.audio[:2]) |
| assert semantic_logits.shape == (2, FRAMES, 16_384) |
| assert residual_logits.shape == (2, FRAMES, 7, 1_024) |
|
|
| loss = adapter.token_cross_entropy( |
| semantic_logits, |
| residual_logits, |
| batch.semantic[:2], |
| batch.residual[:2], |
| ) |
| assert set(loss) == {"semantic", "residual", "total"} |
| assert loss["total"].isfinite() and loss["total"] > 0 |
| loss["total"].backward() |
| assert any(parameter.grad is not None for parameter in model.parameters()) |
|
|
|
|
| def test_modes_teacher_forcing_and_predicted_tokens_are_range_valid_and_renderable() -> None: |
| batch = _sidecar("validation") |
| modes = adapter.per_position_mode_tokens(batch.semantic, batch.residual) |
| assert modes.shape == (FRAMES, 8) |
| adapter.validate_predicted_tokens(modes.unsqueeze(0)) |
|
|
| backend = _TinyCapturedFuser() |
| captured_fused = backend.expected(batch.semantic[:1], batch.residual[:1], batch.priming[:1]) |
| replayed = adapter.teacher_force_captured_rows( |
| backend, batch.semantic[:1], batch.residual[:1], batch.priming[:1] |
| ) |
| assert torch.equal(replayed, captured_fused) |
| assert backend.sampling_rng is None |
|
|
| logits = torch.full((1, FRAMES, 16_384), -20.0) |
| logits[..., 7] = 20.0 |
| residual_logits = torch.full((1, FRAMES, 7, 1_024), -20.0) |
| residual_logits[..., 9] = 20.0 |
| predicted = adapter.predict_tokens(logits, residual_logits) |
| adapter.validate_predicted_tokens(predicted) |
| rendered = adapter.render_predicted_tokens(_TinyRenderer(), predicted) |
| assert rendered.shape == (1, 2, SAMPLES) |
|
|
| capability = adapter.describe_capability() |
| assert capability["native_tokenizer"] is False |
| assert capability["arbitrary_external_music"] is False |
| assert capability["domain"] == "captured_music3_only" |
|
|
|
|
| class _TinyCapturedFuser: |
| sampling_rng = "not-called" |
|
|
| @staticmethod |
| def expected(semantic: torch.Tensor, residual: torch.Tensor, priming: torch.Tensor) -> torch.Tensor: |
| rows = torch.cat((semantic.unsqueeze(-1), residual), dim=-1).to(torch.float32) |
| return rows.mean(dim=-1, keepdim=True).expand(-1, -1, 32_768).contiguous() |
|
|
| def teacher_force(self, semantic: torch.Tensor, residual: torch.Tensor, priming: torch.Tensor, *, sampling_rng=None) -> torch.Tensor: |
| self.sampling_rng = sampling_rng |
| return self.expected(semantic, residual, priming) |
|
|
|
|
| class _TinyRenderer: |
| def render(self, tokens: torch.Tensor) -> torch.Tensor: |
| assert tokens.shape[1:] == (FRAMES, 8) |
| return torch.zeros(tokens.shape[0], 2, SAMPLES) |
|
|
| def test_frozen_native_token_config_and_cli_are_cpu_safe() -> None: |
| import os |
| import subprocess |
| import sys |
| from pathlib import Path |
|
|
| loaded = adapter.load_native_token_config( |
| Path(__file__).parents[1] / "configs/native-token-adapter-v1.yaml" |
| ) |
| assert loaded.config.teacher.split_seeds() == SPLIT_SEEDS |
| assert loaded.config.native_tokenizer is False |
| result = subprocess.run( |
| [ |
| sys.executable, |
| "-B", |
| str(Path(__file__).parents[1] / "scripts/run_native_token_adapter.py"), |
| "--help", |
| ], |
| check=True, |
| capture_output=True, |
| text=True, |
| env={ |
| "PATH": os.environ["PATH"], |
| "PYTHONPATH": str(Path(__file__).parents[1] / "src"), |
| "CUDA_VISIBLE_DEVICES": "-1", |
| "PYTHONDONTWRITEBYTECODE": "1", |
| }, |
| ) |
| assert "not a native tokenizer" in " ".join(result.stdout.split()) |
|
|