Download inference.py from nishitanand/FIGMA: direct link, hf CLI and curl.
- Browser
- Download file 3.55 kB
-
https://huggingface.co/nishitanand/FIGMA/resolve/main/inference.py
- Command line
-
hf download hf://nishitanand/FIGMA/inference.py
-
curl -L -o inference.py https://huggingface.co/nishitanand/FIGMA/resolve/main/inference.py
3.55 kB
| #!/usr/bin/env python3 | |
| """ | |
| FIGMA inference: encode music and text into a shared space and retrieve. | |
| Examples | |
| -------- | |
| # Text -> Audio: rank a folder of .wav clips by a text query | |
| python inference.py --checkpoint figma.ckpt \ | |
| --audio_dir ./clips --query "a song in F minor at 120 BPM in 4/4 time" --topk 5 | |
| # Dump audio embeddings for a folder of clips | |
| python inference.py --checkpoint figma.ckpt --audio_dir ./clips --save_embeddings emb.pt | |
| """ | |
| import os | |
| import glob | |
| import argparse | |
| import torch | |
| import librosa | |
| from figma_model import Figma, get_tokenizer, SAMPLE_RATE, CLIP_SECONDS | |
| def load_audio_batch(paths, clip_seconds, sr=SAMPLE_RATE): | |
| fixed = int(sr * clip_seconds) | |
| out = torch.zeros(len(paths), 1, fixed) | |
| for i, p in enumerate(paths): | |
| wav, _ = librosa.load(p, sr=sr) | |
| wav = torch.tensor(wav, dtype=torch.float32) | |
| take = min(wav.numel(), fixed) | |
| out[i, 0, :take] = wav[:take] | |
| return out | |
| def embed_audios(model, paths, clip_seconds, device, batch_size=32): | |
| embs = [] | |
| for i in range(0, len(paths), batch_size): | |
| batch = load_audio_batch(paths[i:i + batch_size], clip_seconds).to(device) | |
| embs.append(model.encode_audio(batch).cpu()) | |
| return torch.cat(embs) if embs else torch.empty(0) | |
| def embed_texts(model, tokenizer, texts, device, max_len=128, batch_size=64): | |
| embs = [] | |
| for i in range(0, len(texts), batch_size): | |
| tok = tokenizer(texts[i:i + batch_size], return_tensors="pt", | |
| padding="max_length", truncation=True, max_length=max_len) | |
| tok = {k: v.to(device) for k, v in tok.items()} | |
| embs.append(model.encode_text(tok).cpu()) | |
| return torch.cat(embs) if embs else torch.empty(0) | |
| def main(): | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--checkpoint", required=True, help="Path to the FIGMA checkpoint (.ckpt)") | |
| ap.add_argument("--audio_dir", required=True, help="Folder of audio files") | |
| ap.add_argument("--audio_glob", default="*.wav") | |
| ap.add_argument("--query", help="Text query for text->audio retrieval") | |
| ap.add_argument("--topk", type=int, default=5) | |
| ap.add_argument("--save_embeddings", help="Path to save {paths, audio_emb} .pt") | |
| ap.add_argument("--clip_seconds", type=float, default=CLIP_SECONDS) | |
| ap.add_argument("--gpu", type=int, default=0) | |
| args = ap.parse_args() | |
| device = torch.device(f"cuda:{args.gpu}" if torch.cuda.is_available() else "cpu") | |
| model = Figma.from_checkpoint(args.checkpoint, device=device) | |
| tokenizer = get_tokenizer() | |
| paths = sorted(glob.glob(os.path.join(args.audio_dir, args.audio_glob))) | |
| if not paths: | |
| raise SystemExit(f"No audio matching {args.audio_glob} in {args.audio_dir}") | |
| print(f"Encoding {len(paths)} audio clips at {args.clip_seconds}s ...") | |
| audio_emb = embed_audios(model, paths, args.clip_seconds, device) | |
| if args.save_embeddings: | |
| torch.save({"paths": paths, "audio_emb": audio_emb}, args.save_embeddings) | |
| print(f"Saved embeddings -> {args.save_embeddings}") | |
| if args.query: | |
| q = embed_texts(model, tokenizer, [args.query], device)[0] | |
| scores = audio_emb @ q | |
| topk = scores.topk(min(args.topk, len(paths))) | |
| print(f"\nTop {topk.indices.numel()} matches for: {args.query!r}") | |
| for rank, (idx, sc) in enumerate(zip(topk.indices.tolist(), topk.values.tolist()), 1): | |
| print(f" {rank:>2}. {sc:.4f} {os.path.basename(paths[idx])}") | |
| if __name__ == "__main__": | |
| main() | |