1git clone https://github.com/ajd12342/paraspeechclap.git
2cd paraspeechclap
3pip install -r requirements.txt
1mkdir -p checkpoints
2huggingface-cli download ajd12342/paraspeechclap-situational paraspeechclap-situational.pth.tar --local-dir checkpoints
1# Compute similarity between audio and a text style description
2python scripts/inference.py \
3 --checkpoint_path ./checkpoints/paraspeechclap-situational.pth.tar \
4 --audio_path /path/to/audio.wav \
5 --text "A person is speaking in a whispered style."
6
7# Zero-shot classification across emotion/speaking-style candidates
8python scripts/inference.py \
9 --checkpoint_path ./checkpoints/paraspeechclap-situational.pth.tar \
10 --audio_path /path/to/audio.wav \
11 --candidates angry happy calm whispered enthusiastic saddened anxious
1import torch
2import torchaudio
3import torchaudio.transforms as T
4from paraspeechclap.model import CLAP
5from transformers import AutoTokenizer, Wav2Vec2FeatureExtractor
6
7SPEECH_MODEL = "microsoft/wavlm-large"
8TEXT_MODEL = "ibm-granite/granite-embedding-278m-multilingual"
9DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
10
11# Load ParaSpeechCLAP-Situational
12model = CLAP(
13 speech_name=SPEECH_MODEL,
14 text_name=TEXT_MODEL,
15 embedding_dim=768,
16)
17state_dict = torch.load("./checkpoints/paraspeechclap-situational.pth.tar", map_location=DEVICE)
18model.load_state_dict(state_dict, strict=False)
19model.to(DEVICE).eval()
20
21# Initialize preprocessors
22feature_extractor = Wav2Vec2FeatureExtractor.from_pretrained(SPEECH_MODEL)
23tokenizer = AutoTokenizer.from_pretrained(TEXT_MODEL)
24
25# Load and preprocess audio (resample to 16 kHz mono)
26waveform, sr = torchaudio.load("path/to/audio.wav")
27if sr != 16000:
28 waveform = T.Resample(sr, 16000)(waveform)
29if waveform.shape[0] > 1:
30 waveform = waveform.mean(dim=0, keepdim=True)
31audio = feature_extractor(
32 waveform.squeeze(0), sampling_rate=16000, return_tensors="pt"
33).input_values.to(DEVICE) # (1, num_samples)
34
35# Similarity with a free-form situational description
36text_tokens = tokenizer(
37 "A person is speaking in a whispered style.",
38 return_tensors="pt", padding=True, truncation=True, max_length=512
39)
40text_tokens = {k: v.to(DEVICE) for k, v in text_tokens.items()}
41
42with torch.no_grad():
43 audio_emb = model.get_audio_embedding(audio, normalize=True) # (1, 768)
44 text_emb = model.get_text_embedding(text_tokens, normalize=True) # (1, 768)
45 similarity = (audio_emb @ text_emb.T).item()
46 print(f"Similarity: {similarity:.4f}")
47
48# Zero-shot classification across situational candidate styles
49candidates = ["angry", "happy", "calm", "whispered", "enthusiastic", "saddened", "anxious"]
50prompts = [f"A person is speaking in a {s} style." for s in candidates]
51tokens = tokenizer(prompts, return_tensors="pt", padding=True, truncation=True, max_length=512)
52tokens = {k: v.to(DEVICE) for k, v in tokens.items()}
53
54with torch.no_grad():
55 text_embs = model.get_text_embedding(tokens, normalize=True) # (7, 768)
56 scores = (audio_emb @ text_embs.T).squeeze(0) # (7,)
57 pred = candidates[scores.argmax().item()]
58 print(f"Predicted style: {pred}")
The full set of 21 situational candidate styles used in the ParaSpeechCLAP-Situational evaluation is:
angry, guilt, scared, happy, loud, sarcastic, sympathetic, desirous, enthusiastic, saddened, anxious, sleepy, admiring, disgusted, awed, pained, fast, calm, whispered, enunciated, confused.
Use ParaSpeechCLAP-Situational as an inference-time reward model to select the best speech clip from N TTS candidates:
1python scripts/best_of_n.py \
2 checkpoint_path=./checkpoints/paraspeechclap-situational.pth.tar \
3 input_base_dir=/path/to/tts_outputs \
4 output_dir_name=best_of_N_paraspeechclap_situational
1# Retrieval (R@1, R@10, Median Rank)
2python scripts/evaluate_retrieval.py \
3 --config-name eval/retrieval \
4 checkpoint_path=./checkpoints/paraspeechclap-situational.pth.tar \
5 data.dataset_name=ajd12342/paraspeechclap-eval-situational \
6 data.audio_root=/path/to/audio_root \
7 meta.results=./results_retrieval/paraspeechclap-eval-situational/ajd12342-paraspeechclap-situational
8
9# Classification (UAR, Macro F1 — 21 situational classes)
10python scripts/evaluate_classification.py \
11 --config-name eval/classification/situational \
12 checkpoint_path=./checkpoints/paraspeechclap-situational.pth.tar \
13 data.audio_root=/path/to/audio_root \
14 meta.results=./results_classification/paraspeechclap-eval-situational/ajd12342-paraspeechclap-situational/
1@misc{diwan2026paraspeechclapdualencoderspeechtextmodel,
2 title={ParaSpeechCLAP: A Dual-Encoder Speech-Text Model for Rich Stylistic Language-Audio Pretraining},
3 author={Anuj Diwan and Eunsol Choi and David Harwath},
4 year={2026},
5 eprint={2603.28737},
6 archivePrefix={arXiv},
7 primaryClass={eess.AS},
8 url={https://arxiv.org/abs/2603.28737},
9}