Spaces:
Sleeping
Sleeping
| """Training entrypoint (PRD §17, build-order step 5). | |
| python -m raaga_id.train [--datasets saraga_carnatic compmusic_raga] | |
| Floor (D16): a tonic-normalized pitch-class distribution (PCD) over each recording's | |
| predominant-melody pitch track, windowed (D7), classified by XGBoost. Split is BY | |
| TRACK (frozen benchmark, no window leakage). Pools any datasets that expose pitch + | |
| tonic (Saraga, IAMRRD). | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import numpy as np | |
| from . import data, features | |
| from .config import MODELS_DIR | |
| from .model import RaagaXGB | |
| def build_features(pclips, max_windows: int | None): | |
| """(X, y) of per-window model features (windowed TDMS, D28) labelled with track raaga.""" | |
| X, y = [], [] | |
| for pc in pclips: | |
| wins = features.model_windows(pc.times, pc.freqs, pc.tonic_hz, max_windows=max_windows) | |
| X.extend(wins) | |
| y.extend([pc.raaga] * len(wins)) | |
| if not X: | |
| raise SystemExit("No feature windows — is the dataset downloaded (pitch + tonic present)?") | |
| return np.vstack(X), np.array(y) | |
| def main() -> None: | |
| ap = argparse.ArgumentParser(description="Train the raaga floor (windowed TDMS + XGBoost, D28).") | |
| ap.add_argument("--out", default=str(MODELS_DIR / "raaga_xgb.json")) | |
| ap.add_argument("--datasets", nargs="+", default=["saraga_carnatic"]) | |
| ap.add_argument("--max-windows", type=int, default=None, help="cap windows/track (default: config)") | |
| ap.add_argument("--test-frac", type=float, default=0.25) | |
| args = ap.parse_args() | |
| pclips = list(data.iter_pitch_clips(only_vocab=True, datasets=tuple(args.datasets))) | |
| if not pclips: | |
| raise SystemExit("No labelled pitch clips — check datasets / raagas.json.") | |
| train_ids, test_ids = data.split_by_track(pclips, test_frac=args.test_frac) | |
| train_clips = [c for c in pclips if c.track_id in train_ids] | |
| print(f"{len(pclips)} clips {args.datasets} -> {len(train_clips)} train / {len(test_ids)} test " | |
| f"(frozen: {data.FROZEN_TEST_PATH})") | |
| X, y = build_features(train_clips, args.max_windows) | |
| classes = sorted(set(y)) | |
| idx = {c: i for i, c in enumerate(classes)} | |
| print(f"training on {len(X)} TDMS windows ({X.shape[1]}d) across {len(classes)} raagas: {classes}") | |
| model = RaagaXGB(classes).fit(X, np.array([idx[c] for c in y])) | |
| path = model.save(args.out) | |
| print(f"saved -> {path}\nnext: python -m raaga_id.evaluate --model {path}") | |
| if __name__ == "__main__": | |
| main() | |