Views
No views yet
1conda create -n ssl-aasist python=3.10.14
2conda activate ssl-aasist
3pip install pip==23
4pip install omegaconf==2.0.6 pyarrow==19.0pip install torch datasets transformers librosa numpy scikit-learn huggingface_hubpip install git+https://github.com/facebookresearch/fairseq.git@920a548ca770fb1a951f7f4289b4d3a0c1bc226f1from transformers import AutoConfig, AutoModel
2import torch
3import librosa
4from datasets import load_dataset
5import numpy as np
6from torch import Tensor
7from sklearn.metrics import roc_auc_score
8
9config = AutoConfig.from_pretrained("ash56/ssl-aasist", trust_remote_code=True)
10device = 'cuda' if torch.cuda.is_available() else 'cpu'
11model = AutoModel.from_pretrained("ash56/ssl-aasist", config=config,trust_remote_code=True, force_download=True).to(device)
12
13#Load ShiftySpeech dataset
14spoof_data= load_dataset("ash56/ShiftySpeech", data_files={"data": "Vocoders/apnet2/apnet2_aishell_flac.tar.gz"})["data"]
15real_data = load_dataset("ash56/ShiftySpeech", data_files={"data": "real_data_flac/real_data_aishell_flac.tar.gz"})["data"]
16model.eval()
171def pad(x, max_len=64600):
2 x_len = x.shape[0]
3 if x_len >= max_len:
4 return x[:max_len]
5 # need to pad
6 num_repeats = int(max_len / x_len)+1
7 padded_x = np.tile(x, (1, num_repeats))[:, :max_len][0]
8 return padded_x 1output_file = "apnet2-aishell_scores.txt"
2
3#inference on spoof data
4with open(output_file, "a") as f:
5 # get scores of spoof audios
6 for sample in spoof_data:
7 fname = sample["__key__"]
8 audio = sample["flac"]["array"]
9 sampling_rate = sample["flac"]["sampling_rate"]
10 if sampling_rate != 16000:
11 audio = librosa.resample(audio, orig_sr=sampling_rate, target_sr=16000)
12 audio_padded = pad(audio,64600)
13 x_inp = Tensor(audio_padded).unsqueeze(0).to(device)
14 with torch.no_grad():
15 batch_out = model(x_inp)
16 batch_score = batch_out[:, 1].cpu().numpy().ravel()[0]
17 f.write(f"{fname} spoof {batch_score}\n")
18
19 #get scores of real audios
20 for sample in real_data:
21 print(real_data)
22 fname = sample["__key__"]
23 audio = sample["flac"]["array"]
24 sampling_rate = sample["flac"]["sampling_rate"]
25 if sampling_rate != 16000:
26 audio = librosa.resample(audio, orig_sr=sampling_rate, target_sr=16000)
27 audio_padded = pad(audio,64600)
28 x_inp = Tensor(audio_padded).unsqueeze(0).to(device)
29 with torch.no_grad():
30 batch_out = model(x_inp)
31 batch_score = batch_out[:, 1].cpu().numpy().ravel()[0]
32 f.write(f"{fname} bonafide {batch_score}\n")
33
34print(f"Scores saved in {output_file}")1# helper functions to calculate EER
2def compute_eer(target_scores, nontarget_scores):
3 """ Returns equal error rate (EER) and the corresponding threshold. """
4 frr, far, thresholds = compute_det_curve(target_scores, nontarget_scores)
5 abs_diffs = np.abs(frr - far)
6 min_index = np.argmin(abs_diffs)
7 eer = np.mean((frr[min_index], far[min_index]))
8 return eer, thresholds[min_index], frr, far
9
10def compute_det_curve(target_scores, nontarget_scores):
11
12 n_scores = target_scores.size + nontarget_scores.size
13 all_scores = np.concatenate((target_scores, nontarget_scores))
14 labels = np.concatenate(
15 (np.ones(target_scores.size), np.zeros(nontarget_scores.size)))
16
17 # Sort labels based on scores
18 indices = np.argsort(all_scores, kind='mergesort')
19 labels = labels[indices]
20
21 # Compute false rejection and false acceptance rates
22 tar_trial_sums = np.cumsum(labels)
23 nontarget_trial_sums = nontarget_scores.size - \
24 (np.arange(1, n_scores + 1) - tar_trial_sums)
25
26 # false rejection rates
27 frr = np.concatenate(
28 (np.atleast_1d(0), tar_trial_sums / target_scores.size))
29 far = np.concatenate((np.atleast_1d(1), nontarget_trial_sums /
30 nontarget_scores.size)) # false acceptance rates
31 # Thresholds are the sorted scores
32 thresholds = np.concatenate(
33 (np.atleast_1d(all_scores[indices[0]] - 0.001), all_scores[indices]))
34
35 return frr, far, thresholds
36
37# get EER
38def calculate_EER(cm_scores_file,
39 output_file,
40 printout=True):
41 # Load CM scores
42 cm_data = np.genfromtxt(cm_scores_file, dtype=str)
43 cm_utt_id = cm_data[:, 0]
44 cm_keys = cm_data[:, 1]
45 cm_scores = cm_data[:, 2].astype(float)
46 # Extract bona fide (real human) and spoof scores from the CM scores
47 bona_cm = cm_scores[cm_keys == 'bonafide']
48 spoof_cm = cm_scores[cm_keys == 'spoof']
49 all_scores = np.concatenate([bona_cm, spoof_cm])
50 all_true_labels = np.concatenate([np.ones_like(bona_cm), np.zeros_like(spoof_cm)])
51
52 auc = roc_auc_score(all_true_labels, all_scores, max_fpr=0.05)
53 eer_cm, eer_threshold, frr, far = compute_eer(bona_cm, spoof_cm)
54
55 if printout:
56 with open(output_file, "w") as f_res:
57 f_res.write('\nCM SYSTEM\n')
58 f_res.write('\tEER\t\t= {:8.9f} % '
59 '(Equal error rate for countermeasure)\n'.format(
60 eer_cm * 100))
61
62
63eval_eer = calculate_EER(
64 cm_scores_file=output_file,output_file="apnet2_aishell_eer.txt")
651@misc{garg2025syntheticspeechdetectionwild,
2 title={Less is More for Synthetic Speech Detection in the Wild},
3 author={Ashi Garg and Zexin Cai and Henry Li Xinyuan and Leibny Paola García-Perera and Kevin Duh and Sanjeev Khudanpur and Matthew Wiesner and Nicholas Andrews},
4 year={2025},
5 eprint={2502.05674},
6 archivePrefix={arXiv},
7 primaryClass={eess.AS},
8 url={https://arxiv.org/abs/2502.05674},
9}