deepsafe commited on
Commit
85261de
ยท
verified ยท
1 Parent(s): 11afb87

chore: remove non-weight files (batch 1)

Browse files
This view is limited to 50 files because it contains too many changes. ย  See raw diff
Files changed (50) hide show
  1. audio/aasist3/.gitignore +0 -1
  2. audio/aasist3/Dockerfile +0 -35
  3. audio/aasist3/api.py +0 -345
  4. audio/aasist3/model/__init__.py +0 -1
  5. audio/aasist3/model/branch.py +0 -34
  6. audio/aasist3/model/full_model.py +0 -139
  7. audio/aasist3/model/gat.py +0 -99
  8. audio/aasist3/model/hs_gal.py +0 -176
  9. audio/aasist3/model/kan.py +0 -213
  10. audio/aasist3/model/pool.py +0 -45
  11. audio/aasist3/model/residual.py +0 -56
  12. audio/aasist3/model/wav2vec.py +0 -82
  13. audio/aasist3/requirements.txt +0 -11
  14. audio/nes2net/.gitignore +0 -1
  15. audio/nes2net/Dockerfile +0 -41
  16. audio/nes2net/api.py +0 -315
  17. audio/nes2net/model_scripts/__init__.py +0 -0
  18. audio/nes2net/model_scripts/wav2vec2_Nes2Net_X.py +0 -317
  19. audio/nes2net/requirements.txt +0 -13
  20. audio/safeear/Dockerfile +0 -49
  21. audio/safeear/api.py +0 -321
  22. audio/safeear/download_weights.sh +0 -23
  23. audio/safeear/requirements.txt +0 -15
  24. audio/safeear/safeear_repo/.gitignore +0 -167
  25. audio/safeear/safeear_repo/LICENSE +0 -23
  26. audio/safeear/safeear_repo/README.md +0 -134
  27. audio/safeear/safeear_repo/assert/ASVSpoof-results.png +0 -3
  28. audio/safeear/safeear_repo/assert/Fig1.jpg +0 -3
  29. audio/safeear/safeear_repo/assert/SafeEar_logo.jpg +0 -3
  30. audio/safeear/safeear_repo/assert/exp1.png +0 -3
  31. audio/safeear/safeear_repo/assert/overall.gif +0 -3
  32. audio/safeear/safeear_repo/assert/overall.mp4 +0 -3
  33. audio/safeear/safeear_repo/assert/overall.png +0 -3
  34. audio/safeear/safeear_repo/assert/safe-space.png +0 -0
  35. audio/safeear/safeear_repo/config/train19.yaml +0 -87
  36. audio/safeear/safeear_repo/config/train21.yaml +0 -87
  37. audio/safeear/safeear_repo/datas/ASVSpoof2019/ASVspoof2019.LA.cm.dev.trl.txt +0 -0
  38. audio/safeear/safeear_repo/datas/ASVSpoof2019/ASVspoof2019.LA.cm.eval.trl.txt +0 -0
  39. audio/safeear/safeear_repo/datas/ASVSpoof2019/ASVspoof2019.LA.cm.train.trn.txt +0 -0
  40. audio/safeear/safeear_repo/datas/ASVSpoof2019/dev.tsv +0 -0
  41. audio/safeear/safeear_repo/datas/ASVSpoof2019/eval.tsv +0 -0
  42. audio/safeear/safeear_repo/datas/ASVSpoof2019/train.tsv +0 -0
  43. audio/safeear/safeear_repo/datas/ASVSpoof2021/ASVspoof2021.LA.cm.eval.trl.txt +0 -0
  44. audio/safeear/safeear_repo/datas/ASVSpoof2021/eval.tsv +0 -0
  45. audio/safeear/safeear_repo/datas/dump_hubert_avg_feature.py +0 -109
  46. audio/safeear/safeear_repo/datas/feature_utils.py +0 -65
  47. audio/safeear/safeear_repo/fairseq_ours/.circleci/config.yml +0 -171
  48. audio/safeear/safeear_repo/fairseq_ours/.github/CODEOWNERS +0 -18
  49. audio/safeear/safeear_repo/fairseq_ours/.github/ISSUE_TEMPLATE.md +0 -3
  50. audio/safeear/safeear_repo/fairseq_ours/.github/ISSUE_TEMPLATE/bug_report.md +0 -43
audio/aasist3/.gitignore DELETED
@@ -1 +0,0 @@
1
- weights/
 
 
audio/aasist3/Dockerfile DELETED
@@ -1,35 +0,0 @@
1
- FROM nvidia/cuda:12.1.1-cudnn8-runtime-ubuntu22.04
2
-
3
- ENV DEBIAN_FRONTEND=noninteractive
4
- ENV PYTHONUNBUFFERED=1
5
-
6
- RUN apt-get update && apt-get install -y --no-install-recommends \
7
- python3 python3-pip \
8
- ffmpeg libsndfile1 \
9
- && rm -rf /var/lib/apt/lists/*
10
-
11
- RUN ln -sf /usr/bin/python3 /usr/bin/python
12
-
13
- WORKDIR /app
14
-
15
- # Install PyTorch with CUDA 12.1
16
- RUN pip install --no-cache-dir \
17
- torch==2.5.1 torchaudio==2.5.1 \
18
- --index-url https://download.pytorch.org/whl/cu121
19
-
20
- COPY requirements.txt .
21
- RUN pip install --no-cache-dir -r requirements.txt
22
-
23
- RUN python -c "from transformers import Wav2Vec2Config; Wav2Vec2Config.from_pretrained('facebook/wav2vec2-large-xlsr-53', cache_dir='/app/w2v_cache')"
24
-
25
- COPY model/ /app/model/
26
- COPY api.py .
27
- RUN mkdir -p /app/weights
28
- COPY weights/ /app/weights/
29
-
30
- EXPOSE 8005
31
-
32
- RUN adduser --disabled-password --gecos '' appuser
33
- USER appuser
34
-
35
- CMD ["python", "api.py"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
audio/aasist3/api.py DELETED
@@ -1,345 +0,0 @@
1
- """AASIST3 Audio Deepfake Detection API.
2
-
3
- Detects synthetic speech using the AASIST3 model architecture:
4
- - Frontend: XLSR wav2vec 2.0 (HuggingFace Transformers)
5
- - Backend: AASIST with KAN (Kolmogorov-Arnold Network) linear
6
- layers and Graph Attention Networks
7
-
8
- Reference: https://github.com/AI4Bharat/AASIST3
9
- """
10
-
11
- import base64
12
- import io
13
- import logging
14
- import os
15
- import platform
16
- import time
17
- from typing import Optional
18
-
19
- import numpy as np
20
- import soundfile as sf
21
- import torch
22
- import torch.nn.functional as F
23
- import uvicorn
24
- from fastapi import FastAPI, HTTPException
25
- from pydantic import BaseModel, Field
26
-
27
- # Point transformers cache to pre-cached wav2vec2 config
28
- # (must be set before importing model code)
29
- os.environ["TRANSFORMERS_CACHE"] = "/app/w2v_cache"
30
-
31
- # Configure logging
32
- logging.basicConfig(
33
- level=logging.INFO,
34
- format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
35
- )
36
- logger = logging.getLogger("aasist3_api")
37
-
38
- # Import model class
39
- try:
40
- from model import aasist3 as AASIST3Model
41
- except ImportError as e:
42
- logger.error(f"Failed to import AASIST3 model: {e}")
43
- AASIST3Model = None
44
-
45
- # Constants
46
- MODEL_NAME = "aasist3"
47
- MODEL_ID = "aasist3_kan_mlaad"
48
- WEIGHTS_DIR = "/app/weights"
49
-
50
-
51
- def _get_device():
52
- """Select optimal device: MPS (Apple) > CUDA (NVIDIA) > CPU."""
53
- override = os.environ.get("DEEPSAFE_DEVICE", "").strip().lower()
54
- if override == "cpu":
55
- return torch.device("cpu")
56
- if override == "cuda" and torch.cuda.is_available():
57
- return torch.device("cuda")
58
- if (
59
- override == "mps"
60
- and hasattr(torch.backends, "mps")
61
- and torch.backends.mps.is_available()
62
- ):
63
- return torch.device("mps")
64
- if override:
65
- pass # Invalid override, fall through to auto-detect
66
- if (
67
- platform.system() == "Darwin"
68
- and hasattr(torch.backends, "mps")
69
- and torch.backends.mps.is_available()
70
- ):
71
- return torch.device("mps")
72
- if torch.cuda.is_available():
73
- return torch.device("cuda")
74
- return torch.device("cpu")
75
-
76
-
77
- DEVICE = _get_device()
78
-
79
- if DEVICE.type == "cuda":
80
- torch.backends.cudnn.benchmark = True
81
- torch.set_float32_matmul_precision("high")
82
-
83
- if DEVICE.type == "cuda":
84
- logger.info(
85
- "Device: cuda (%s, %.1f GB VRAM)",
86
- torch.cuda.get_device_name(0),
87
- torch.cuda.get_device_properties(0).total_memory / 1024**3,
88
- )
89
- else:
90
- logger.warning(
91
- "Device: %s (no CUDA available -- check nvidia-container-toolkit)",
92
- DEVICE,
93
- )
94
-
95
- SAMPLE_RATE = 16000
96
- TARGET_SAMPLES = 64600 # ~4.04 seconds at 16kHz
97
-
98
- # Global model instance
99
- model = None
100
-
101
-
102
- class AudioInput(BaseModel):
103
- """Request schema for audio deepfake detection."""
104
-
105
- audio_data: str = Field(
106
- ..., description="Base64 encoded audio string (WAV/MP3/etc)"
107
- )
108
- threshold: Optional[float] = Field(
109
- 0.5, ge=0.0, le=1.0, description="Classification threshold"
110
- )
111
-
112
-
113
- app = FastAPI(
114
- title="AASIST3 Audio Deepfake Detection API",
115
- description=(
116
- "Service for detecting synthetic speech using the "
117
- "AASIST3 model (HuggingFace wav2vec 2.0 + AASIST "
118
- "with KAN layers)."
119
- ),
120
- version="1.0.0",
121
- )
122
-
123
-
124
- def load_model():
125
- """Load the AASIST3 model from pretrained weights.
126
-
127
- Returns:
128
- The loaded model, or None if loading fails.
129
- """
130
- global model
131
- if model is not None:
132
- return model
133
-
134
- logger.info(f"Loading AASIST3 model onto {DEVICE}...")
135
-
136
- if AASIST3Model is None:
137
- logger.error("AASIST3 model class not available.")
138
- return None
139
-
140
- weights_safetensors = os.path.join(WEIGHTS_DIR, "model.safetensors")
141
- weights_config = os.path.join(WEIGHTS_DIR, "config.json")
142
-
143
- if not os.path.exists(weights_safetensors):
144
- logger.error(f"Model weights not found at {weights_safetensors}")
145
- return None
146
-
147
- if not os.path.exists(weights_config):
148
- logger.error(f"Model config not found at {weights_config}")
149
- return None
150
-
151
- try:
152
- model = AASIST3Model.from_pretrained(WEIGHTS_DIR)
153
- model.to(DEVICE)
154
- # Set model to inference mode (disables dropout, batchnorm)
155
- model.train(False)
156
-
157
- logger.info("AASIST3 model loaded successfully.")
158
- return model
159
- except Exception as e:
160
- logger.exception(f"Failed to load AASIST3 model: {e}")
161
- model = None
162
- return None
163
-
164
-
165
- @app.on_event("startup")
166
- async def startup_event():
167
- """Load model on service startup."""
168
- load_model()
169
-
170
-
171
- def _gpu_health_info() -> dict:
172
- """Return GPU metrics for the health endpoint."""
173
- if torch.cuda.is_available() and DEVICE.type == "cuda":
174
- return {
175
- "gpu_name": torch.cuda.get_device_name(0),
176
- "vram_used_mb": round(torch.cuda.memory_allocated(0) / 1024**2),
177
- "vram_total_mb": round(
178
- torch.cuda.get_device_properties(0).total_memory / 1024**2
179
- ),
180
- }
181
- return {}
182
-
183
-
184
- @app.get("/health")
185
- async def health():
186
- """Health check endpoint."""
187
- return {
188
- "status": "healthy" if model is not None else "degraded",
189
- "model": MODEL_NAME,
190
- "model_id": MODEL_ID,
191
- "device": str(DEVICE),
192
- "weights_found": os.path.exists(os.path.join(WEIGHTS_DIR, "model.safetensors")),
193
- **_gpu_health_info(),
194
- }
195
-
196
-
197
- def _load_audio_bytes(audio_bytes: bytes) -> tuple:
198
- """Load audio from raw bytes using soundfile with torchaudio fallback.
199
-
200
- Args:
201
- audio_bytes: Raw audio file bytes.
202
-
203
- Returns:
204
- Tuple of (audio_numpy_array, sample_rate).
205
-
206
- Raises:
207
- ValueError: If audio cannot be loaded by any backend.
208
- """
209
- # Try soundfile first (handles WAV, FLAC natively)
210
- sf_error = None
211
- try:
212
- audio, sr = sf.read(io.BytesIO(audio_bytes), dtype="float32")
213
- if audio.ndim > 1:
214
- audio = audio.mean(axis=1) # Convert to mono
215
- return audio, sr
216
- except Exception as sf_err:
217
- sf_error = sf_err
218
- logger.debug(f"soundfile failed, trying torchaudio: {sf_err}")
219
-
220
- # Fallback to torchaudio (handles MP3, compressed formats)
221
- try:
222
- import torchaudio
223
-
224
- buf = io.BytesIO(audio_bytes)
225
- waveform, sr = torchaudio.load(buf)
226
- if waveform.shape[0] > 1:
227
- waveform = waveform.mean(dim=0, keepdim=True)
228
- return waveform.squeeze(0).numpy(), sr
229
- except Exception as ta_err:
230
- raise ValueError(
231
- f"Failed to load audio with soundfile and torchaudio: "
232
- f"sf={sf_error}, ta={ta_err}"
233
- )
234
-
235
-
236
- def preprocess_audio(audio_bytes: bytes) -> torch.Tensor:
237
- """Preprocess audio for AASIST3 inference.
238
-
239
- Loads audio, resamples to 16kHz mono, and zero-pads or
240
- truncates to TARGET_SAMPLES.
241
-
242
- Args:
243
- audio_bytes: Raw audio file bytes.
244
-
245
- Returns:
246
- Audio tensor of shape (1, TARGET_SAMPLES).
247
-
248
- Raises:
249
- ValueError: If audio preprocessing fails.
250
- """
251
- try:
252
- logger.info("Starting audio preprocessing...")
253
- audio, sr = _load_audio_bytes(audio_bytes)
254
- logger.info(f"Audio loaded. Length: {len(audio)} samples at {sr}Hz")
255
-
256
- # Resample to 16kHz if needed
257
- if sr != SAMPLE_RATE:
258
- import torchaudio
259
-
260
- resampler = torchaudio.transforms.Resample(
261
- orig_freq=sr, new_freq=SAMPLE_RATE
262
- )
263
- audio_tensor = torch.FloatTensor(audio).unsqueeze(0)
264
- audio_tensor = resampler(audio_tensor).squeeze(0)
265
- audio = audio_tensor.numpy()
266
- logger.info(
267
- f"Resampled from {sr}Hz to {SAMPLE_RATE}Hz. "
268
- f"New length: {len(audio)} samples"
269
- )
270
-
271
- # Zero-pad or truncate to TARGET_SAMPLES
272
- if len(audio) >= TARGET_SAMPLES:
273
- audio = audio[:TARGET_SAMPLES]
274
- else:
275
- pad_length = TARGET_SAMPLES - len(audio)
276
- audio = np.pad(audio, (0, pad_length), mode="constant")
277
-
278
- logger.info(f"Audio padded/trimmed to {TARGET_SAMPLES} samples")
279
-
280
- audio_tensor = torch.FloatTensor(audio).unsqueeze(0).to(DEVICE)
281
- return audio_tensor
282
- except Exception as e:
283
- logger.error(f"Error preprocessing audio: {e}")
284
- raise ValueError(f"Audio preprocessing failed: {str(e)}")
285
-
286
-
287
- @app.post("/predict")
288
- async def predict(input_data: AudioInput):
289
- """Run deepfake detection on base64-encoded audio.
290
-
291
- The model outputs 2 logits: [bonafide_score, spoof_score].
292
- Class 0 = bonafide (real), Class 1 = spoof (fake).
293
- The returned probability is the spoof/fake probability.
294
- """
295
- if model is None:
296
- if load_model() is None:
297
- raise HTTPException(status_code=503, detail="Model not loaded")
298
-
299
- try:
300
- start_time = time.time()
301
- logger.info(
302
- f"Prediction request. Data size: " f"{len(input_data.audio_data)} chars"
303
- )
304
-
305
- # Decode base64 audio
306
- audio_bytes = base64.b64decode(input_data.audio_data)
307
-
308
- # Preprocess
309
- audio_tensor = preprocess_audio(audio_bytes)
310
-
311
- # Inference
312
- logger.info("Starting model inference...")
313
- with torch.no_grad():
314
- output = model(audio_tensor)
315
-
316
- # output shape: [batch, 2]
317
- # Index 0 = bonafide logit, Index 1 = spoof logit
318
- probs = torch.softmax(output, dim=1)
319
- prob_fake = probs[0, 1].item()
320
-
321
- prediction = 1 if prob_fake >= input_data.threshold else 0
322
- verdict = "fake" if prediction == 1 else "real"
323
- inference_time = time.time() - start_time
324
-
325
- logger.info(
326
- f"Prediction: {verdict} (prob_fake={prob_fake:.4f}, "
327
- f"time={inference_time:.3f}s)"
328
- )
329
-
330
- return {
331
- "model": MODEL_NAME,
332
- "probability": float(prob_fake),
333
- "prediction": int(prediction),
334
- "class": verdict,
335
- "inference_time": float(inference_time),
336
- }
337
-
338
- except Exception as e:
339
- logger.exception(f"Error during prediction: {e}")
340
- raise HTTPException(status_code=500, detail=str(e))
341
-
342
-
343
- if __name__ == "__main__":
344
- port = int(os.environ.get("MODEL_PORT", 8005))
345
- uvicorn.run(app, host="0.0.0.0", port=port)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
audio/aasist3/model/__init__.py DELETED
@@ -1 +0,0 @@
1
- from .full_model import aasist3
 
 
audio/aasist3/model/branch.py DELETED
@@ -1,34 +0,0 @@
1
- import torch.nn as nn
2
-
3
- from .hs_gal import HtrgGraphAttentionLayer
4
- from .pool import GraphPool
5
-
6
- class InferenceBranch(nn.Module):
7
- def __init__(self, gat_dims, temperature, pool_ratio, size):
8
- super().__init__()
9
- self.htrg_gat1 = HtrgGraphAttentionLayer(
10
- gat_dims[0], gat_dims[1], temperature=temperature, size=size
11
- )
12
- self.htrg_gat2 = HtrgGraphAttentionLayer(
13
- gat_dims[1], gat_dims[1], temperature=temperature, size=size
14
- )
15
-
16
- self.pool_hS = GraphPool(pool_ratio, gat_dims[1], 0.3, size=size)
17
- self.pool_hT = GraphPool(pool_ratio, gat_dims[1], 0.3, size=size)
18
-
19
- def forward(self, out_T, out_S, master):
20
- # ะŸะตั€ะฒะฐั ัั‚ะฐะดะธั
21
- out_T_res, out_S_res, master_res = self.htrg_gat1(out_T, out_S, master=master)
22
-
23
- # ะŸัƒะปะธะฝะณ
24
- out_S_res = self.pool_hS(out_S_res)
25
- out_T_res = self.pool_hT(out_T_res)
26
-
27
- # ะ’ั‚ะพั€ะฐั ัั‚ะฐะดะธั ั residual connection
28
- out_T_aug, out_S_aug, master_aug = self.htrg_gat2(out_T_res, out_S_res, master=master_res)
29
-
30
- out_T_final = out_T_res + out_T_aug
31
- out_S_final = out_S_res + out_S_aug
32
- master_final = master_res + master_aug
33
-
34
- return out_T_final, out_S_final, master_final
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
audio/aasist3/model/full_model.py DELETED
@@ -1,139 +0,0 @@
1
- #!/usr/bin/env python
2
-
3
- import torch
4
- import torch.nn.functional as F
5
- import torch.nn as nn
6
- from huggingface_hub import PyTorchModelHubMixin
7
-
8
- from .kan import KANLinear
9
- from .gat import GraphAttentionLayer
10
- from .pool import GraphPool
11
- from .branch import InferenceBranch
12
- from .residual import Residual_block
13
- from .wav2vec import Wav2Vec2Encoder
14
-
15
-
16
- class aasist3(nn.Module, PyTorchModelHubMixin):
17
- def __init__(self, d_args={
18
- "architecture": "AASIST",
19
- "nb_samp": 64600,
20
- "first_conv": 128,
21
- "filts": [70, [1, 32], [32, 32], [32, 64], [64, 64]],
22
- "gat_dims": [64, 32],
23
- "pool_ratios": [0.5, 0.7, 0.5, 0.5],
24
- "temperatures": [2.0, 2.0, 100.0, 100.0],
25
- }, size=200, w2v_cache_dir="weights/", load_pretrained=True):
26
- super().__init__()
27
-
28
- self.w2v_encoder = Wav2Vec2Encoder(cache_dir=w2v_cache_dir, load_pretrained=load_pretrained)
29
- self.bridge = KANLinear(1024, 128)
30
-
31
- self.d_args = d_args
32
- filts = d_args["filts"]
33
- gat_dims = d_args["gat_dims"]
34
- pool_ratios = d_args["pool_ratios"]
35
- temperatures = d_args["temperatures"]
36
-
37
- self.first_bn = nn.BatchNorm2d(num_features=1)
38
- self.selu = nn.SELU(inplace=True)
39
- self.drop = nn.Dropout(0.5, inplace=True)
40
- self.drop_way = nn.Dropout(0.2, inplace=True)
41
-
42
- self.encoder = nn.Sequential(
43
- nn.Sequential(Residual_block(nb_filts=filts[1], first=True)),
44
- nn.Sequential(Residual_block(nb_filts=filts[2])),
45
- nn.Sequential(Residual_block(nb_filts=filts[3])),
46
- nn.Sequential(Residual_block(nb_filts=filts[4])),
47
- nn.Sequential(Residual_block(nb_filts=filts[4])),
48
- nn.Sequential(Residual_block(nb_filts=filts[4])))
49
-
50
- self.pos_S = nn.Parameter(torch.randn(1, 42, filts[-1][-1]))
51
- self.pos_T = nn.Parameter(torch.randn(1, 67, filts[-1][-1]))
52
-
53
- self.GAT_layer_S = GraphAttentionLayer(filts[-1][-1], gat_dims[0], temperature=temperatures[0], size=size)
54
- self.GAT_layer_T = GraphAttentionLayer(filts[-1][-1], gat_dims[0], temperature=temperatures[1], size=size)
55
-
56
- self.pool_S = GraphPool(pool_ratios[0], gat_dims[0], 0.3, size=size)
57
- self.pool_T = GraphPool(pool_ratios[1], gat_dims[0], 0.3, size=size)
58
-
59
- self.master1 = nn.Parameter(torch.randn(1, 1, gat_dims[0]))
60
- self.master2 = nn.Parameter(torch.randn(1, 1, gat_dims[0]))
61
- self.master3 = nn.Parameter(torch.randn(1, 1, gat_dims[0]))
62
- self.master4 = nn.Parameter(torch.randn(1, 1, gat_dims[0]))
63
-
64
- self.inference_branch1 = InferenceBranch(
65
- gat_dims=gat_dims,
66
- temperature=temperatures[2],
67
- pool_ratio=pool_ratios[2],
68
- size=size
69
- )
70
- self.inference_branch2 = InferenceBranch(
71
- gat_dims=gat_dims,
72
- temperature=temperatures[2],
73
- pool_ratio=pool_ratios[2],
74
- size=size
75
- )
76
- self.inference_branch3 = InferenceBranch(
77
- gat_dims=gat_dims,
78
- temperature=temperatures[2],
79
- pool_ratio=pool_ratios[2],
80
- size=size
81
- )
82
- self.inference_branch4 = InferenceBranch(
83
- gat_dims=gat_dims,
84
- temperature=temperatures[2],
85
- pool_ratio=pool_ratios[2],
86
- size=size
87
- )
88
-
89
- self.out_layer = KANLinear(5 * gat_dims[1], 2)
90
-
91
- def forward(self, x, Freq_aug=False):
92
- x = self.w2v_encoder(x)
93
- x = self.bridge(x)
94
- x = x.transpose(1, 2)
95
- x = x.unsqueeze(dim=1)
96
- x = F.max_pool2d(torch.abs(x), (3, 3))
97
- x = self.first_bn(x)
98
- x = self.selu(x)
99
-
100
- e = self.encoder(x)
101
-
102
- # GAT-S
103
- e_S, _ = torch.max(torch.abs(e), dim=3)
104
- e_S = e_S.transpose(1, 2) + self.pos_S
105
- gat_S = self.GAT_layer_S(e_S)
106
- out_S = self.pool_S(gat_S)
107
-
108
- # GAT-T
109
- e_T, _ = torch.max(torch.abs(e), dim=2)
110
- e_T = e_T.transpose(1, 2) + self.pos_T
111
- gat_T = self.GAT_layer_T(e_T)
112
- out_T = self.pool_T(gat_T)
113
-
114
- out_T1, out_S1, master1 = self.inference_branch1(out_T, out_S, self.master1)
115
- out_T2, out_S2, master2 = self.inference_branch2(out_T, out_S, self.master2)
116
- out_T3, out_S3, master3 = self.inference_branch3(out_T, out_S, self.master3)
117
- out_T4, out_S4, master4 = self.inference_branch4(out_T, out_S, self.master4)
118
-
119
- out_T1, out_T2 = self.drop_way(out_T1), self.drop_way(out_T2)
120
- out_T3, out_T4 = self.drop_way(out_T3), self.drop_way(out_T4)
121
- out_S1, out_S2 = self.drop_way(out_S1), self.drop_way(out_S2)
122
- out_S3, out_S4 = self.drop_way(out_S3), self.drop_way(out_S4)
123
- master1, master2 = self.drop_way(master1), self.drop_way(master2)
124
- master3, master4 = self.drop_way(master3), self.drop_way(master4)
125
-
126
- out_T = torch.stack([out_T1, out_T2, out_T3, out_T4]).max(dim=0)[0]
127
- out_S = torch.stack([out_S1, out_S2, out_S3, out_S4]).max(dim=0)[0]
128
- master = torch.stack([master1, master2, master3, master4]).max(dim=0)[0]
129
-
130
- T_max, _ = torch.max(torch.abs(out_T), dim=1)
131
- T_avg = torch.mean(out_T, dim=1)
132
- S_max, _ = torch.max(torch.abs(out_S), dim=1)
133
- S_avg = torch.mean(out_S, dim=1)
134
-
135
- last_hidden = torch.cat([T_max, T_avg, S_max, S_avg, master.squeeze(1)], dim=1)
136
- last_hidden = self.drop(last_hidden)
137
- output = self.out_layer(last_hidden)
138
-
139
- return output
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
audio/aasist3/model/gat.py DELETED
@@ -1,99 +0,0 @@
1
- import torch, torch.nn as nn, torch.nn.functional as F
2
-
3
- from .kan import KANLinear
4
-
5
-
6
- class GraphAttentionLayer(nn.Module):
7
- def __init__(self, in_dim, out_dim, size, **kwargs):
8
- super().__init__()
9
-
10
- # attention map
11
- self.att_proj = KANLinear(in_dim, out_dim)
12
- self.att_weight = self._init_new_params(out_dim, 1)
13
-
14
- # project
15
- self.proj_with_att = KANLinear(in_dim, out_dim)
16
- self.proj_without_att = KANLinear(in_dim, out_dim)
17
-
18
- # batch norm
19
- self.bn = nn.BatchNorm1d(out_dim)
20
-
21
- # dropout for inputs
22
- self.input_drop = nn.Dropout(p=0.2)
23
-
24
- # activate
25
- self.act = nn.SELU(inplace=True)
26
-
27
- # temperature
28
- self.temp = 1.
29
- if "temperature" in kwargs:
30
- self.temp = kwargs["temperature"]
31
-
32
- def forward(self, x):
33
- '''
34
- x :(#bs, #node, #dim)
35
- '''
36
- # apply input dropout
37
- x = self.input_drop(x)
38
-
39
- # derive attention map
40
- att_map = self._derive_att_map(x)
41
-
42
- # projection
43
- x = self._project(x, att_map)
44
-
45
- # apply batch norm
46
- x = self._apply_BN(x)
47
- x = self.act(x)
48
- return x
49
-
50
- def _pairwise_mul_nodes(self, x):
51
- '''
52
- Calculates pairwise multiplication of nodes.
53
- - for attention map
54
- x :(#bs, #node, #dim)
55
- out_shape :(#bs, #node, #node, #dim)
56
- '''
57
-
58
- nb_nodes = x.size(1)
59
- x = x.unsqueeze(2).expand(-1, -1, nb_nodes, -1)
60
- x_mirror = x.transpose(1, 2)
61
-
62
- return x * x_mirror
63
-
64
- def _derive_att_map(self, x):
65
- '''
66
- x :(#bs, #node, #dim)
67
- out_shape :(#bs, #node, #node, 1)
68
- '''
69
- att_map = self._pairwise_mul_nodes(x)
70
- # size: (#bs, #node, #node, #dim_out)
71
- att_map = torch.tanh(self.att_proj(att_map))
72
- # size: (#bs, #node, #node, 1)
73
- att_map = torch.matmul(att_map, self.att_weight)
74
-
75
- # apply temperature
76
- att_map = att_map / self.temp
77
-
78
- att_map = F.softmax(att_map, dim=-2)
79
-
80
- return att_map
81
-
82
- def _project(self, x, att_map):
83
- x1 = self.proj_with_att(torch.matmul(att_map.squeeze(-1), x))
84
- x2 = self.proj_without_att(x)
85
-
86
- return x1 + x2
87
-
88
- def _apply_BN(self, x):
89
- org_size = x.size()
90
- x = x.view(-1, org_size[-1])
91
- x = self.bn(x)
92
- x = x.view(org_size)
93
-
94
- return x
95
-
96
- def _init_new_params(self, *size):
97
- out = nn.Parameter(torch.FloatTensor(*size))
98
- nn.init.xavier_normal_(out)
99
- return out
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
audio/aasist3/model/hs_gal.py DELETED
@@ -1,176 +0,0 @@
1
- import torch, torch.nn as nn, torch.nn.functional as F
2
-
3
- from .kan import KANLinear
4
-
5
-
6
- class HtrgGraphAttentionLayer(nn.Module):
7
- def __init__(self, in_dim, out_dim, size, **kwargs):
8
- super().__init__()
9
-
10
- self.proj_type1 = KANLinear(in_dim, in_dim)
11
- self.proj_type2 = KANLinear(in_dim, in_dim)
12
-
13
- # attention map
14
- self.att_proj = KANLinear(in_dim, out_dim)
15
- self.att_projM = KANLinear(in_dim, out_dim)
16
-
17
- self.att_weight11 = self._init_new_params(out_dim, 1)
18
- self.att_weight22 = self._init_new_params(out_dim, 1)
19
- self.att_weight12 = self._init_new_params(out_dim, 1)
20
- self.att_weightM = self._init_new_params(out_dim, 1)
21
-
22
- # project
23
- self.proj_with_att = KANLinear(in_dim, out_dim)
24
- self.proj_without_att = KANLinear(in_dim, out_dim)
25
-
26
- self.proj_with_attM = KANLinear(in_dim, out_dim)
27
- self.proj_without_attM = KANLinear(in_dim, out_dim)
28
-
29
- # batch norm
30
- self.bn = nn.BatchNorm1d(out_dim)
31
-
32
- # dropout for inputs
33
- self.input_drop = nn.Dropout(p=0.2)
34
-
35
- # activate
36
- self.act = nn.SELU(inplace=True)
37
-
38
- # temperature
39
- self.temp = 1.
40
- if "temperature" in kwargs:
41
- self.temp = kwargs["temperature"]
42
-
43
- def forward(self, x1, x2, master=None):
44
- '''
45
- x1 :(#bs, #node, #dim)
46
- x2 :(#bs, #node, #dim)
47
- '''
48
- num_type1 = x1.size(1)
49
- num_type2 = x2.size(1)
50
-
51
- x1 = self.proj_type1(x1)
52
- x2 = self.proj_type2(x2)
53
-
54
- x = torch.cat([x1, x2], dim=1)
55
-
56
- if master is None:
57
- master = torch.mean(x, dim=1, keepdim=True)
58
-
59
- # apply input dropout
60
- x = self.input_drop(x)
61
-
62
- # derive attention map
63
- att_map = self._derive_att_map(x, num_type1, num_type2)
64
-
65
- # directional edge for master node
66
- master = self._update_master(x, master)
67
-
68
- # projection
69
- x = self._project(x, att_map)
70
-
71
- # apply batch norm
72
- x = self._apply_BN(x)
73
- # x = self.act(x)
74
-
75
- x1 = x.narrow(1, 0, num_type1)
76
- x2 = x.narrow(1, num_type1, num_type2)
77
-
78
- return x1, x2, master
79
-
80
- def _update_master(self, x, master):
81
-
82
- att_map = self._derive_att_map_master(x, master)
83
- master = self._project_master(x, master, att_map)
84
-
85
- return master
86
-
87
- def _pairwise_mul_nodes(self, x):
88
- '''
89
- Calculates pairwise multiplication of nodes.
90
- - for attention map
91
- x :(#bs, #node, #dim)
92
- out_shape :(#bs, #node, #node, #dim)
93
- '''
94
-
95
- nb_nodes = x.size(1)
96
- x = x.unsqueeze(2).expand(-1, -1, nb_nodes, -1)
97
- x_mirror = x.transpose(1, 2)
98
-
99
- return x * x_mirror
100
-
101
- def _derive_att_map_master(self, x, master):
102
- '''
103
- x :(#bs, #node, #dim)
104
- out_shape :(#bs, #node, #node, 1)
105
- '''
106
- att_map = x * master
107
- att_map = torch.tanh(self.att_projM(att_map))
108
-
109
- att_map = torch.matmul(att_map, self.att_weightM)
110
-
111
- # apply temperature
112
- att_map = att_map / self.temp
113
-
114
- att_map = F.softmax(att_map, dim=-2)
115
-
116
- return att_map
117
-
118
- def _derive_att_map(self, x, num_type1, num_type2):
119
- '''
120
- x :(#bs, #node, #dim)
121
- out_shape :(#bs, #node, #node, 1)
122
- '''
123
- att_map = self._pairwise_mul_nodes(x)
124
- # size: (#bs, #node, #node, #dim_out)
125
- att_map = torch.tanh(self.att_proj(att_map))
126
- # size: (#bs, #node, #node, 1)
127
-
128
- att_board = torch.zeros_like(att_map[:, :, :, 0]).unsqueeze(-1)
129
-
130
- att_board[:, :num_type1, :num_type1, :] = torch.matmul(
131
- att_map[:, :num_type1, :num_type1, :], self.att_weight11)
132
- att_board[:, num_type1:, num_type1:, :] = torch.matmul(
133
- att_map[:, num_type1:, num_type1:, :], self.att_weight22)
134
- att_board[:, :num_type1, num_type1:, :] = torch.matmul(
135
- att_map[:, :num_type1, num_type1:, :], self.att_weight12)
136
- att_board[:, num_type1:, :num_type1, :] = torch.matmul(
137
- att_map[:, num_type1:, :num_type1, :], self.att_weight12)
138
-
139
- att_map = att_board
140
-
141
- # att_map = torch.matmul(att_map, self.att_weight12)
142
-
143
- # apply temperature
144
- att_map = att_map / self.temp
145
-
146
- att_map = F.softmax(att_map, dim=-2)
147
-
148
- return att_map
149
-
150
- def _project(self, x, att_map):
151
- x1 = self.proj_with_att(torch.matmul(att_map.squeeze(-1), x))
152
- x2 = self.proj_without_att(x)
153
-
154
- return x1 + x2
155
-
156
- def _project_master(self, x, master, att_map):
157
-
158
- x1 = self.proj_with_attM(torch.matmul(
159
- att_map.squeeze(-1).unsqueeze(1), x))
160
- x2 = self.proj_without_attM(master)
161
-
162
- return x1 + x2
163
-
164
- def _apply_BN(self, x):
165
- org_size = x.size()
166
- x = x.view(-1, org_size[-1])
167
- x = self.bn(x)
168
- x = x.view(org_size)
169
-
170
- return x
171
-
172
- def _init_new_params(self, *size):
173
- out = nn.Parameter(torch.FloatTensor(*size))
174
- nn.init.xavier_normal_(out)
175
- return out
176
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
audio/aasist3/model/kan.py DELETED
@@ -1,213 +0,0 @@
1
- import torch, math, torch.nn.functional as F
2
-
3
-
4
- class KANLinear(torch.nn.Module):
5
- def __init__(
6
- self,
7
- in_features,
8
- out_features,
9
- grid_size=16,
10
- spline_order=4,
11
- scale_noise=0.1,
12
- scale_base=1.0,
13
- scale_spline=1.0,
14
- enable_standalone_scale_spline=True,
15
- base_activation=torch.nn.PReLU,
16
- grid_eps=0.02,
17
- grid_range=[-1, 1],
18
- ):
19
- super(KANLinear, self).__init__()
20
- self.in_features = in_features
21
- self.out_features = out_features
22
- self.grid_size = grid_size
23
- self.spline_order = spline_order
24
-
25
- h = (grid_range[1] - grid_range[0]) / grid_size
26
- grid = (
27
- (
28
- torch.arange(-spline_order, grid_size + spline_order + 1) * h
29
- + grid_range[0]
30
- )
31
- .expand(in_features, -1)
32
- .contiguous()
33
- )
34
- self.register_buffer("grid", grid)
35
-
36
- self.base_weight = torch.nn.Parameter(torch.Tensor(out_features, in_features))
37
- self.spline_weight = torch.nn.Parameter(
38
- torch.Tensor(out_features, in_features, grid_size + spline_order)
39
- )
40
- if enable_standalone_scale_spline:
41
- self.spline_scaler = torch.nn.Parameter(
42
- torch.Tensor(out_features, in_features)
43
- )
44
-
45
- self.scale_noise = scale_noise
46
- self.scale_base = scale_base
47
- self.scale_spline = scale_spline
48
- self.enable_standalone_scale_spline = enable_standalone_scale_spline
49
- self.base_activation = base_activation()
50
- self.grid_eps = grid_eps
51
-
52
- self.reset_parameters()
53
-
54
- def reset_parameters(self):
55
- torch.nn.init.kaiming_uniform_(self.base_weight, a=math.sqrt(5) * self.scale_base)
56
- with torch.no_grad():
57
- noise = (
58
- (
59
- torch.rand(self.grid_size + 1, self.in_features, self.out_features)
60
- - 1 / 2
61
- )
62
- * self.scale_noise
63
- / self.grid_size
64
- )
65
- self.spline_weight.data.copy_(
66
- (self.scale_spline if not self.enable_standalone_scale_spline else 1.0)
67
- * self.curve2coeff(
68
- self.grid.T[self.spline_order : -self.spline_order],
69
- noise,
70
- )
71
- )
72
- if self.enable_standalone_scale_spline:
73
- # torch.nn.init.constant_(self.spline_scaler, self.scale_spline)
74
- torch.nn.init.kaiming_uniform_(self.spline_scaler, a=math.sqrt(5) * self.scale_spline)
75
-
76
- def b_splines(self, x: torch.Tensor):
77
- """
78
- Compute the B-spline bases for the given input tensor.
79
-
80
- Args:
81
- x (torch.Tensor): Input tensor of shape (batch_size, in_features).
82
-
83
- Returns:
84
- torch.Tensor: B-spline bases tensor of shape (batch_size, in_features, grid_size + spline_order).
85
- """
86
- assert x.dim() == 2 and x.size(1) == self.in_features
87
-
88
- grid: torch.Tensor = (
89
- self.grid
90
- ) # (in_features, grid_size + 2 * spline_order + 1)
91
- x = x.unsqueeze(-1)
92
- bases = ((x >= grid[:, :-1]) & (x < grid[:, 1:])).to(x.dtype)
93
- for k in range(1, self.spline_order + 1):
94
- bases = (
95
- (x - grid[:, : -(k + 1)])
96
- / (grid[:, k:-1] - grid[:, : -(k + 1)])
97
- * bases[:, :, :-1]
98
- ) + (
99
- (grid[:, k + 1 :] - x)
100
- / (grid[:, k + 1 :] - grid[:, 1:(-k)])
101
- * bases[:, :, 1:]
102
- )
103
-
104
- assert bases.size() == (
105
- x.size(0),
106
- self.in_features,
107
- self.grid_size + self.spline_order,
108
- )
109
- return bases.contiguous()
110
-
111
- def curve2coeff(self, x: torch.Tensor, y: torch.Tensor):
112
- """
113
- Compute the coefficients of the curve that interpolates the given points.
114
-
115
- Args:
116
- x (torch.Tensor): Input tensor of shape (batch_size, in_features).
117
- y (torch.Tensor): Output tensor of shape (batch_size, in_features, out_features).
118
-
119
- Returns:
120
- torch.Tensor: Coefficients tensor of shape (out_features, in_features, grid_size + spline_order).
121
- """
122
- assert x.dim() == 2 and x.size(1) == self.in_features
123
- assert y.size() == (x.size(0), self.in_features, self.out_features)
124
-
125
- A = self.b_splines(x).transpose(
126
- 0, 1
127
- ) # (in_features, batch_size, grid_size + spline_order)
128
- B = y.transpose(0, 1) # (in_features, batch_size, out_features)
129
- solution = torch.linalg.lstsq(
130
- A, B
131
- ).solution # (in_features, grid_size + spline_order, out_features)
132
- result = solution.permute(
133
- 2, 0, 1
134
- ) # (out_features, in_features, grid_size + spline_order)
135
-
136
- assert result.size() == (
137
- self.out_features,
138
- self.in_features,
139
- self.grid_size + self.spline_order,
140
- )
141
- return result.contiguous()
142
-
143
- @property
144
- def scaled_spline_weight(self):
145
- return self.spline_weight * (
146
- self.spline_scaler.unsqueeze(-1)
147
- if self.enable_standalone_scale_spline
148
- else 1.0
149
- )
150
-
151
- def forward(self, x: torch.Tensor):
152
- assert x.size(-1) == self.in_features
153
- original_shape = x.shape
154
- x = x.reshape(-1, self.in_features)
155
-
156
- base_output = F.linear(self.base_activation(x), self.base_weight)
157
- spline_output = F.linear(
158
- self.b_splines(x).view(x.size(0), -1),
159
- self.scaled_spline_weight.reshape(self.out_features, -1),
160
- )
161
- output = base_output + spline_output
162
- # print(*original_shape[:-1], output.shape)
163
- output = output.view(*original_shape[:-1], self.out_features)
164
- return output
165
-
166
- @torch.no_grad()
167
- def update_grid(self, x: torch.Tensor, margin=0.01):
168
- assert x.dim() == 2 and x.size(1) == self.in_features
169
- batch = x.size(0)
170
-
171
- splines = self.b_splines(x) # (batch, in, coeff)
172
- splines = splines.permute(1, 0, 2) # (in, batch, coeff)
173
- orig_coeff = self.scaled_spline_weight # (out, in, coeff)
174
- orig_coeff = orig_coeff.permute(1, 2, 0) # (in, coeff, out)
175
- unreduced_spline_output = torch.bmm(splines, orig_coeff) # (in, batch, out)
176
- unreduced_spline_output = unreduced_spline_output.permute(
177
- 1, 0, 2
178
- ) # (batch, in, out)
179
-
180
- # sort each channel individually to collect data distribution
181
- x_sorted = torch.sort(x, dim=0)[0]
182
- grid_adaptive = x_sorted[
183
- torch.linspace(
184
- 0, batch - 1, self.grid_size + 1, dtype=torch.int64, device=x.device
185
- )
186
- ]
187
-
188
- uniform_step = (x_sorted[-1] - x_sorted[0] + 2 * margin) / self.grid_size
189
- grid_uniform = (
190
- torch.arange(
191
- self.grid_size + 1, dtype=torch.float32, device=x.device
192
- ).unsqueeze(1)
193
- * uniform_step
194
- + x_sorted[0]
195
- - margin
196
- )
197
-
198
- grid = self.grid_eps * grid_uniform + (1 - self.grid_eps) * grid_adaptive
199
- grid = torch.concatenate(
200
- [
201
- grid[:1]
202
- - uniform_step
203
- * torch.arange(self.spline_order, 0, -1, device=x.device).unsqueeze(1),
204
- grid,
205
- grid[-1:]
206
- + uniform_step
207
- * torch.arange(1, self.spline_order + 1, device=x.device).unsqueeze(1),
208
- ],
209
- dim=0,
210
- )
211
-
212
- self.grid.copy_(grid.T)
213
- self.spline_weight.data.copy_(self.curve2coeff(x, unreduced_spline_output))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
audio/aasist3/model/pool.py DELETED
@@ -1,45 +0,0 @@
1
- import torch, torch.nn as nn
2
- from typing import Union
3
-
4
- from .kan import KANLinear
5
-
6
-
7
- class GraphPool(nn.Module):
8
- def __init__(self, k: float, in_dim: int, p: Union[float, int], size):
9
- super().__init__()
10
- self.k = k
11
- self.sigmoid = nn.Sigmoid()
12
- self.proj = KANLinear(in_dim, 1)
13
- self.drop = nn.Dropout(p=p) if p > 0 else nn.Identity()
14
- self.in_dim = in_dim
15
-
16
- def forward(self, h):
17
- Z = self.drop(h)
18
- weights = self.proj(Z)
19
- scores = self.sigmoid(weights)
20
- new_h = self.top_k_graph(scores, h, self.k)
21
-
22
- return new_h
23
-
24
- def top_k_graph(self, scores, h, k):
25
- """
26
- args
27
- =====
28
- scores: attention-based weights (#bs, #node, 1)
29
- h: graph data (#bs, #node, #dim)
30
- k: ratio of remaining nodes, (float)
31
-
32
- returns
33
- =====
34
- h: graph pool applied data (#bs, #node', #dim)
35
- """
36
- _, n_nodes, n_feat = h.size()
37
- n_nodes = max(int(n_nodes * k), 1)
38
- _, idx = torch.topk(scores, n_nodes, dim=1)
39
- idx = idx.expand(-1, -1, n_feat)
40
-
41
- h = h * scores
42
- h = torch.gather(h, 1, idx)
43
-
44
- return h
45
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
audio/aasist3/model/residual.py DELETED
@@ -1,56 +0,0 @@
1
- import torch.nn as nn
2
-
3
- class Residual_block(nn.Module):
4
- def __init__(self, nb_filts, first=False):
5
- super().__init__()
6
- self.first = first
7
-
8
- if not self.first:
9
- self.bn1 = nn.BatchNorm2d(num_features=nb_filts[0])
10
- self.conv1 = nn.Conv2d(in_channels=nb_filts[0],
11
- out_channels=nb_filts[1],
12
- kernel_size=(2, 3),
13
- padding=(1, 1),
14
- stride=1)
15
- self.selu = nn.SELU()
16
-
17
- self.bn2 = nn.BatchNorm2d(num_features=nb_filts[1])
18
- self.conv2 = nn.Conv2d(in_channels=nb_filts[1],
19
- out_channels=nb_filts[1],
20
- kernel_size=(2, 3),
21
- padding=(0, 1),
22
- stride=1)
23
-
24
- if nb_filts[0] != nb_filts[1]:
25
- self.downsample = True
26
- self.conv_downsample = nn.Conv2d(in_channels=nb_filts[0],
27
- out_channels=nb_filts[1],
28
- padding=(0, 1),
29
- kernel_size=(1, 3),
30
- stride=1)
31
-
32
- else:
33
- self.downsample = False
34
- # self.mp = nn.MaxPool2d((1, 3)) # self.mp = nn.MaxPool2d((1,4))
35
-
36
- def forward(self, x):
37
- identity = x
38
- if not self.first:
39
- out = self.bn1(x)
40
- out = self.selu(out)
41
- else:
42
- out = x
43
- out = self.conv1(x)
44
-
45
- # print('out',out.shape)
46
- out = self.bn2(out)
47
- out = self.selu(out)
48
- # print('out',out.shape)
49
- out = self.conv2(out)
50
- #print('conv2 out',out.shape)
51
- if self.downsample:
52
- identity = self.conv_downsample(identity)
53
-
54
- out += identity
55
- # out = self.mp(out)
56
- return out
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
audio/aasist3/model/wav2vec.py DELETED
@@ -1,82 +0,0 @@
1
- import torch, torch.nn as nn
2
- from transformers import Wav2Vec2Model, Wav2Vec2Config
3
-
4
-
5
- class Wav2Vec2Encoder(nn.Module):
6
- """SSL encoder based on Hugging Face's Wav2Vec2 model."""
7
-
8
- def __init__(self,
9
- model_name_or_path: str = "facebook/wav2vec2-large-xlsr-53",
10
- ssl_out_dim: int = 768,
11
- use_ssl_n_layers: int = None,
12
- freeze_ssl_n_layers: int = 0,
13
- output_attentions: bool = False,
14
- output_hidden_states: bool = False,
15
- normalize_waveform: bool = True,
16
- cache_dir: str = "weights",
17
- load_pretrained: bool = True):
18
- """Initialize the Wav2Vec2 encoder.
19
-
20
- Args:
21
- model_name_or_path: HuggingFace model name or path to local model.
22
- ssl_out_dim: Output dimension of the Wav2Vec2 encoder.
23
- use_ssl_n_layers: Number of Wav2Vec2 layers to use. If None, use all layers.
24
- freeze_ssl_n_layers: Number of Wav2Vec2 layers to freeze during training.
25
- output_attentions: Whether to output attentions.
26
- output_hidden_states: Whether to output hidden states.
27
- normalize_waveform: Whether to normalize the waveform input.
28
- cache_dir: Directory to cache pretrained models.
29
- load_pretrained: Whether to load pretrained weights. If False, initializes with random weights.
30
- """
31
- super().__init__()
32
-
33
- self.model_name_or_path = model_name_or_path
34
- self.ssl_out_dim = ssl_out_dim
35
- self.use_ssl_n_layers = use_ssl_n_layers
36
- self.freeze_ssl_n_layers = freeze_ssl_n_layers
37
- self.output_attentions = output_attentions
38
- self.output_hidden_states = output_hidden_states
39
- self.normalize_waveform = normalize_waveform
40
-
41
- if load_pretrained:
42
- self.model = Wav2Vec2Model.from_pretrained(model_name_or_path, cache_dir=cache_dir)
43
- else:
44
- config = Wav2Vec2Config.from_pretrained(
45
- model_name_or_path,
46
- cache_dir=cache_dir,
47
- local_files_only=False
48
- )
49
- self.model = Wav2Vec2Model(config)
50
- self.model.init_weights()
51
-
52
- def forward(self, x):
53
- """Forward pass through the Wav2Vec2 encoder.
54
-
55
- Args:
56
- x: Input tensor of shape (batch_size, sequence_length, channels)
57
-
58
- Returns:
59
- Extracted features of shape (batch_size, sequence_length, ssl_out_dim)
60
- """
61
- # Handle shape: convert (batch_size, sequence_length, channels) to (batch_size, sequence_length)
62
- if x.ndim == 3:
63
- x = x.squeeze(-1) # Remove channel dimension if present
64
-
65
- if self.normalize_waveform:
66
- x = x / (torch.max(torch.abs(x), dim=1, keepdim=True)[0] + 1e-8)
67
-
68
- outputs = self.model(
69
- x,
70
- output_attentions=self.output_attentions,
71
- output_hidden_states=self.output_hidden_states,
72
- return_dict=True
73
- )
74
-
75
- last_hidden_state = outputs.last_hidden_state
76
-
77
- if self.use_ssl_n_layers is not None and self.output_hidden_states and outputs.hidden_states is not None:
78
- selected = outputs.hidden_states[-self.use_ssl_n_layers:]
79
- last_hidden_state = torch.mean(torch.stack(selected, dim=0), dim=0)
80
- del outputs
81
-
82
- return last_hidden_state
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
audio/aasist3/requirements.txt DELETED
@@ -1,11 +0,0 @@
1
- torch==2.5.1
2
- torchaudio==2.5.1
3
- transformers>=4.40.0
4
- huggingface-hub>=0.20.0
5
- safetensors>=0.4.0
6
- numpy<2.0
7
- soundfile
8
- fastapi
9
- uvicorn[standard]
10
- pydantic
11
- python-multipart
 
 
 
 
 
 
 
 
 
 
 
 
audio/nes2net/.gitignore DELETED
@@ -1 +0,0 @@
1
- weights/
 
 
audio/nes2net/Dockerfile DELETED
@@ -1,41 +0,0 @@
1
- FROM nvidia/cuda:12.1.1-cudnn8-runtime-ubuntu22.04
2
-
3
- ENV DEBIAN_FRONTEND=noninteractive
4
- ENV PYTHONUNBUFFERED=1
5
-
6
- RUN apt-get update && apt-get install -y --no-install-recommends \
7
- python3 python3-pip python3-dev \
8
- git ffmpeg libsndfile1 wget \
9
- build-essential g++ \
10
- && rm -rf /var/lib/apt/lists/*
11
-
12
- RUN ln -sf /usr/bin/python3 /usr/bin/python
13
-
14
- WORKDIR /app
15
-
16
- # Install PyTorch with CUDA 12.1
17
- RUN pip install --no-cache-dir \
18
- torch==2.5.1 torchaudio==2.5.1 \
19
- --index-url https://download.pytorch.org/whl/cu121
20
-
21
- COPY requirements.txt .
22
- RUN pip install --no-cache-dir -r requirements.txt
23
-
24
- # Clone fairseq with patched C extensions (same as ShiftySpeech)
25
- RUN git clone https://github.com/facebookresearch/fairseq.git /app/fairseq_repo && \
26
- cd /app/fairseq_repo && \
27
- git checkout a54021305d6b3c4c5959ac9395135f63202db8f1 && \
28
- sed -i 's/ext_modules=extensions/ext_modules=[]/' setup.py && \
29
- pip install --no-cache-dir --no-deps -e .
30
-
31
- COPY model_scripts /app/model_scripts
32
- COPY api.py .
33
- RUN mkdir -p /app/weights
34
- COPY weights/ /app/weights/
35
-
36
- EXPOSE 8004
37
-
38
- RUN adduser --disabled-password --gecos '' appuser
39
- USER appuser
40
-
41
- CMD ["python", "api.py"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
audio/nes2net/api.py DELETED
@@ -1,315 +0,0 @@
1
- """Nes2Net (XLSR + Nested Res2Net TDNN) Audio Deepfake Detection API.
2
-
3
- Detects synthetic speech using the Nes2Net model architecture:
4
- - Frontend: XLSR wav2vec 2.0 (Self-Supervised Learning)
5
- - Backend: Nested Res2Net TDNN with SE modules
6
-
7
- Reference: https://github.com/TianchiLiu/Nes2Net
8
- """
9
-
10
- import argparse
11
- import base64
12
- import io
13
- import logging
14
- import os
15
- import platform
16
- import sys
17
- import time
18
- import warnings
19
- from typing import Optional
20
-
21
- import librosa
22
- import numpy as np
23
- import torch
24
- import uvicorn
25
- from fastapi import FastAPI, HTTPException
26
- from pydantic import BaseModel, Field
27
-
28
- # Suppress deprecation warnings from fairseq/omegaconf compatibility
29
- warnings.filterwarnings("ignore", category=DeprecationWarning)
30
-
31
- # Monkey-patch omegaconf for fairseq compatibility (older fairseq
32
- # expects is_primitive_type which was removed in newer omegaconf).
33
- import omegaconf._utils as _omegaconf_utils
34
-
35
- if not hasattr(_omegaconf_utils, "is_primitive_type"):
36
- _omegaconf_utils.is_primitive_type = lambda t: t in (int, float, bool, str, bytes)
37
-
38
- # Configure logging
39
- logging.basicConfig(
40
- level=logging.INFO,
41
- format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
42
- )
43
- logger = logging.getLogger("nes2net_api")
44
-
45
- # Add the model code to the path
46
- if "/app" not in sys.path:
47
- sys.path.insert(0, "/app")
48
-
49
- # Import model class (deferred to allow path setup)
50
- try:
51
- from model_scripts.wav2vec2_Nes2Net_X import (
52
- wav2vec2_Nes2Net_no_Res_w_allT as Nes2NetModel,
53
- )
54
- except ImportError as e:
55
- logger.error(f"Failed to import Nes2Net model: {e}")
56
- Nes2NetModel = None
57
-
58
- # Constants
59
- MODEL_NAME = "nes2net"
60
- MODEL_ID = "nes2net_xlsr_itw_valaug"
61
- WEIGHTS_PATH = "/app/weights/nes2net_itw_valaug.pt"
62
-
63
-
64
- def _get_device():
65
- """Select optimal device: MPS (Apple) > CUDA (NVIDIA) > CPU."""
66
- override = os.environ.get("DEEPSAFE_DEVICE", "").strip().lower()
67
- if override == "cpu":
68
- return torch.device("cpu")
69
- if override == "cuda" and torch.cuda.is_available():
70
- return torch.device("cuda")
71
- if (
72
- override == "mps"
73
- and hasattr(torch.backends, "mps")
74
- and torch.backends.mps.is_available()
75
- ):
76
- return torch.device("mps")
77
- if override:
78
- pass # Invalid override, fall through to auto-detect
79
- if (
80
- platform.system() == "Darwin"
81
- and hasattr(torch.backends, "mps")
82
- and torch.backends.mps.is_available()
83
- ):
84
- return torch.device("mps")
85
- if torch.cuda.is_available():
86
- return torch.device("cuda")
87
- return torch.device("cpu")
88
-
89
-
90
- DEVICE = _get_device()
91
-
92
- if DEVICE.type == "cuda":
93
- torch.backends.cudnn.benchmark = True
94
- torch.set_float32_matmul_precision("high")
95
-
96
- if DEVICE.type == "cuda":
97
- logger.info(
98
- "Device: cuda (%s, %.1f GB VRAM)",
99
- torch.cuda.get_device_name(0),
100
- torch.cuda.get_device_properties(0).total_memory / 1024**3,
101
- )
102
- else:
103
- logger.warning(
104
- "Device: %s (no CUDA available -- check nvidia-container-toolkit)",
105
- DEVICE,
106
- )
107
-
108
- SAMPLE_RATE = 16000
109
- TARGET_SAMPLES = 64600 # ~4.04 seconds at 16kHz
110
-
111
- # Global model instance
112
- model = None
113
-
114
-
115
- class AudioInput(BaseModel):
116
- """Request schema for audio deepfake detection."""
117
-
118
- audio_data: str = Field(
119
- ..., description="Base64 encoded audio string (WAV/MP3/etc)"
120
- )
121
- threshold: Optional[float] = Field(
122
- 0.5, ge=0.0, le=1.0, description="Classification threshold"
123
- )
124
-
125
-
126
- app = FastAPI(
127
- title="Nes2Net Audio Deepfake Detection API",
128
- description=(
129
- "Service for detecting synthetic speech using the "
130
- "Nes2Net model (XLSR wav2vec 2.0 + Nested Res2Net TDNN)."
131
- ),
132
- version="1.0.0",
133
- )
134
-
135
-
136
- def load_model():
137
- """Load the Nes2Net model with fine-tuned weights.
138
-
139
- Returns:
140
- The loaded model, or None if loading fails.
141
- """
142
- global model
143
- if model is not None:
144
- return model
145
-
146
- logger.info(f"Loading Nes2Net model onto {DEVICE}...")
147
-
148
- if Nes2NetModel is None:
149
- logger.error("Nes2Net model class not available.")
150
- return None
151
-
152
- if not os.path.exists(WEIGHTS_PATH):
153
- logger.error(f"Model weights not found at {WEIGHTS_PATH}")
154
- return None
155
-
156
- try:
157
- args = argparse.Namespace(
158
- n_output_logits=2,
159
- dilation=2,
160
- pool_func="mean",
161
- SE_ratio=[1],
162
- Nes_ratio=[8, 8],
163
- )
164
- model = Nes2NetModel(args, str(DEVICE))
165
-
166
- # Load fine-tuned weights
167
- try:
168
- state_dict = torch.load(
169
- WEIGHTS_PATH,
170
- map_location=DEVICE,
171
- weights_only=False,
172
- )
173
- except TypeError:
174
- state_dict = torch.load(WEIGHTS_PATH, map_location=DEVICE)
175
-
176
- model.load_state_dict(state_dict)
177
- model.to(DEVICE)
178
- model.eval()
179
-
180
- logger.info("Nes2Net model loaded successfully.")
181
- return model
182
- except Exception as e:
183
- logger.exception(f"Failed to load Nes2Net model: {e}")
184
- model = None
185
- return None
186
-
187
-
188
- @app.on_event("startup")
189
- async def startup_event():
190
- """Load model on service startup."""
191
- load_model()
192
-
193
-
194
- def _gpu_health_info() -> dict:
195
- """Return GPU metrics for the health endpoint."""
196
- if torch.cuda.is_available() and DEVICE.type == "cuda":
197
- return {
198
- "gpu_name": torch.cuda.get_device_name(0),
199
- "vram_used_mb": round(torch.cuda.memory_allocated(0) / 1024**2),
200
- "vram_total_mb": round(
201
- torch.cuda.get_device_properties(0).total_memory / 1024**2
202
- ),
203
- }
204
- return {}
205
-
206
-
207
- @app.get("/health")
208
- async def health():
209
- """Health check endpoint."""
210
- return {
211
- "status": "healthy" if model is not None else "degraded",
212
- "model": MODEL_NAME,
213
- "model_id": MODEL_ID,
214
- "device": str(DEVICE),
215
- "weights_found": os.path.exists(WEIGHTS_PATH),
216
- **_gpu_health_info(),
217
- }
218
-
219
-
220
- def preprocess_audio(audio_bytes: bytes) -> torch.Tensor:
221
- """Preprocess audio for Nes2Net inference.
222
-
223
- Loads audio, resamples to 16kHz mono, and pads/trims
224
- to TARGET_SAMPLES using tiling (matching original training
225
- preprocessing).
226
-
227
- Args:
228
- audio_bytes: Raw audio file bytes.
229
-
230
- Returns:
231
- Audio tensor of shape (1, TARGET_SAMPLES).
232
-
233
- Raises:
234
- ValueError: If audio preprocessing fails.
235
- """
236
- try:
237
- logger.info("Starting audio preprocessing...")
238
- audio, sr = librosa.load(io.BytesIO(audio_bytes), sr=SAMPLE_RATE, mono=True)
239
- logger.info(f"Audio loaded. Length: {len(audio)} samples at {sr}Hz")
240
-
241
- # Pad/trim to TARGET_SAMPLES using tiling
242
- if len(audio) >= TARGET_SAMPLES:
243
- audio = audio[:TARGET_SAMPLES]
244
- else:
245
- num_repeats = TARGET_SAMPLES // len(audio) + 1
246
- audio = np.tile(audio, num_repeats)[:TARGET_SAMPLES]
247
-
248
- logger.info(f"Audio padded/trimmed to {TARGET_SAMPLES} samples")
249
-
250
- audio_tensor = torch.FloatTensor(audio).unsqueeze(0).to(DEVICE)
251
- return audio_tensor
252
- except Exception as e:
253
- logger.error(f"Error preprocessing audio: {e}")
254
- raise ValueError(f"Audio preprocessing failed: {str(e)}")
255
-
256
-
257
- @app.post("/predict")
258
- async def predict(input_data: AudioInput):
259
- """Run deepfake detection on base64-encoded audio.
260
-
261
- The model outputs 2 logits: [spoof_score, bonafide_score].
262
- Class 0 = spoof (fake), Class 1 = bonafide (real).
263
- The returned probability is the spoof/fake probability.
264
- """
265
- if model is None:
266
- if load_model() is None:
267
- raise HTTPException(status_code=503, detail="Model not loaded")
268
-
269
- try:
270
- start_time = time.time()
271
- logger.info(
272
- f"Prediction request. Data size: " f"{len(input_data.audio_data)} chars"
273
- )
274
-
275
- # Decode base64 audio
276
- audio_bytes = base64.b64decode(input_data.audio_data)
277
-
278
- # Preprocess
279
- audio_tensor = preprocess_audio(audio_bytes)
280
-
281
- # Inference
282
- logger.info("Starting model inference...")
283
- with torch.no_grad():
284
- output = model(audio_tensor)
285
-
286
- # output shape: [batch, 2]
287
- # Index 0 = spoof logit, Index 1 = bonafide logit
288
- probs = torch.softmax(output, dim=1)
289
- prob_fake = probs[0, 0].item()
290
-
291
- prediction = 1 if prob_fake >= input_data.threshold else 0
292
- verdict = "fake" if prediction == 1 else "real"
293
- inference_time = time.time() - start_time
294
-
295
- logger.info(
296
- f"Prediction: {verdict} (prob_fake={prob_fake:.4f}, "
297
- f"time={inference_time:.3f}s)"
298
- )
299
-
300
- return {
301
- "model": MODEL_NAME,
302
- "probability": float(prob_fake),
303
- "prediction": int(prediction),
304
- "class": verdict,
305
- "inference_time": float(inference_time),
306
- }
307
-
308
- except Exception as e:
309
- logger.exception(f"Error during prediction: {e}")
310
- raise HTTPException(status_code=500, detail=str(e))
311
-
312
-
313
- if __name__ == "__main__":
314
- port = int(os.environ.get("MODEL_PORT", 8004))
315
- uvicorn.run(app, host="0.0.0.0", port=port)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
audio/nes2net/model_scripts/__init__.py DELETED
File without changes
audio/nes2net/model_scripts/wav2vec2_Nes2Net_X.py DELETED
@@ -1,317 +0,0 @@
1
- import math
2
-
3
- import fairseq
4
- import torch
5
- import torch.nn as nn
6
-
7
- ___author__ = "Tianchi Liu"
8
- __email__ = "tianchi_liu@u.nus.edu"
9
- # modified from the model script from Hemlata Tak
10
-
11
-
12
- class SSLModel(nn.Module):
13
- def __init__(self, device):
14
- super(SSLModel, self).__init__()
15
- cp_path = (
16
- "/app/weights/xlsr2_300m.pt" # Change the pre-trained XLSR model path.
17
- )
18
- model, cfg, task = fairseq.checkpoint_utils.load_model_ensemble_and_task(
19
- [cp_path]
20
- )
21
- self.model = model[0]
22
- self.device = device
23
- self.out_dim = 1024
24
- return
25
-
26
- def extract_feat(self, input_data):
27
- # put the model to GPU if it not there
28
- if (
29
- next(self.model.parameters()).device != input_data.device
30
- or next(self.model.parameters()).dtype != input_data.dtype
31
- ):
32
- self.model.to(input_data.device, dtype=input_data.dtype)
33
- self.model.train()
34
- if True:
35
- # input should be in shape (batch, length)
36
- if input_data.ndim == 3:
37
- input_tmp = input_data[:, :, 0]
38
- else:
39
- input_tmp = input_data
40
- # [batch, length, dim]
41
- emb = self.model(input_tmp, mask=False, features_only=True)["x"]
42
- return emb
43
-
44
-
45
- class SEModule(nn.Module):
46
- def __init__(self, channels, SE_ratio=8):
47
- super(SEModule, self).__init__()
48
- self.se = nn.Sequential(
49
- nn.AdaptiveAvgPool1d(1),
50
- nn.Conv1d(channels, channels // SE_ratio, kernel_size=1, padding=0),
51
- nn.ReLU(),
52
- nn.Conv1d(channels // SE_ratio, channels, kernel_size=1, padding=0),
53
- nn.Sigmoid(),
54
- )
55
-
56
- def forward(self, input):
57
- x = self.se(input)
58
- return input * x
59
-
60
-
61
- class Bottle2neck(nn.Module):
62
-
63
- def __init__(
64
- self, inplanes, planes, kernel_size=None, dilation=None, scale=8, SE_ratio=8
65
- ):
66
- super(Bottle2neck, self).__init__()
67
- width = int(math.floor(planes / scale))
68
- self.conv1 = nn.Conv1d(inplanes, width * scale, kernel_size=1)
69
- self.bn1 = nn.BatchNorm1d(width * scale)
70
- self.nums = scale - 1
71
- convs = []
72
- bns = []
73
- weighted_sum = []
74
- num_pad = math.floor(kernel_size / 2) * dilation
75
- for i in range(self.nums):
76
- convs.append(
77
- nn.Conv2d(
78
- width,
79
- width,
80
- kernel_size=(kernel_size, 1),
81
- dilation=(dilation, 1),
82
- padding=(num_pad, 0),
83
- )
84
- )
85
- bns.append(nn.BatchNorm2d(width))
86
- initial_value = torch.ones(1, 1, 1, i + 2) * (1 / (i + 2))
87
- weighted_sum.append(nn.Parameter(initial_value, requires_grad=True))
88
- self.weighted_sum = nn.ParameterList(weighted_sum)
89
- self.convs = nn.ModuleList(convs)
90
- self.bns = nn.ModuleList(bns)
91
- self.conv3 = nn.Conv1d(width * scale, planes, kernel_size=1)
92
- self.bn3 = nn.BatchNorm1d(planes)
93
- self.relu = nn.ReLU()
94
- self.width = width
95
- self.se = SEModule(planes, SE_ratio)
96
-
97
- def forward(self, x):
98
- residual = x
99
- out = self.conv1(x)
100
- out = self.relu(out)
101
- out = self.bn1(out).unsqueeze(-1) # bz c T 1
102
-
103
- spx = torch.split(out, self.width, 1)
104
- sp = spx[self.nums]
105
- for i in range(self.nums):
106
- sp = torch.cat((sp, spx[i]), -1)
107
-
108
- sp = self.bns[i](self.relu(self.convs[i](sp)))
109
- sp_s = sp * self.weighted_sum[i]
110
- sp_s = torch.sum(sp_s, dim=-1, keepdim=False)
111
-
112
- if i == 0:
113
- out = sp_s
114
- else:
115
- out = torch.cat((out, sp_s), 1)
116
- out = torch.cat((out, spx[self.nums].squeeze(-1)), 1)
117
- out = self.conv3(out)
118
- out = self.relu(out)
119
- out = self.bn3(out)
120
- out = self.se(out)
121
- out += residual
122
- return out
123
-
124
-
125
- class ASTP(nn.Module):
126
- """Attentive statistics pooling: Channel- and context-dependent
127
- statistics pooling, first used in ECAPA_TDNN.
128
- """
129
-
130
- def __init__(self, in_dim, bottleneck_dim=128, global_context_att=False):
131
- super(ASTP, self).__init__()
132
- self.global_context_att = global_context_att
133
-
134
- # Use Conv1d with stride == 1 rather than Linear, then we don't
135
- # need to transpose inputs.
136
- if global_context_att:
137
- self.linear1 = nn.Conv1d(
138
- in_dim * 3, bottleneck_dim, kernel_size=1
139
- ) # equals W and b in the paper
140
- else:
141
- self.linear1 = nn.Conv1d(
142
- in_dim, bottleneck_dim, kernel_size=1
143
- ) # equals W and b in the paper
144
- self.linear2 = nn.Conv1d(
145
- bottleneck_dim, in_dim, kernel_size=1
146
- ) # equals V and k in the paper
147
-
148
- def forward(self, x):
149
- """
150
- x: a 3-dimensional tensor in tdnn-based architecture (B,F,T)
151
- or a 4-dimensional tensor in resnet architecture (B,C,F,T)
152
- 0-dim: batch-dimension, last-dim: time-dimension (frame-dimension)
153
- """
154
- if len(x.shape) == 4:
155
- x = x.reshape(x.shape[0], x.shape[1] * x.shape[2], x.shape[3])
156
- assert len(x.shape) == 3
157
-
158
- if self.global_context_att:
159
- context_mean = torch.mean(x, dim=-1, keepdim=True).expand_as(x)
160
- context_std = torch.sqrt(
161
- torch.var(x, dim=-1, keepdim=True) + 1e-10
162
- ).expand_as(x)
163
- x_in = torch.cat((x, context_mean, context_std), dim=1)
164
- else:
165
- x_in = x
166
-
167
- # DON'T use ReLU here! ReLU may be hard to converge.
168
- alpha = torch.tanh(self.linear1(x_in)) # alpha = F.relu(self.linear1(x_in))
169
- alpha = torch.softmax(self.linear2(alpha), dim=2)
170
- mean = torch.sum(alpha * x, dim=2)
171
- var = torch.sum(alpha * (x**2), dim=2) - mean**2
172
- std = torch.sqrt(var.clamp(min=1e-10))
173
- return torch.cat([mean, std], dim=1)
174
-
175
-
176
- class Nested_Res2Net_TDNN(nn.Module):
177
-
178
- def __init__(
179
- self,
180
- Nes_ratio=[8, 8],
181
- input_channel=1024,
182
- n_output_logits=2,
183
- dilation=2,
184
- pool_func="mean",
185
- SE_ratio=[8],
186
- ):
187
-
188
- super(Nested_Res2Net_TDNN, self).__init__()
189
- self.Nes_ratio = Nes_ratio[0]
190
- assert input_channel % Nes_ratio[0] == 0
191
- C = input_channel // Nes_ratio[0]
192
- self.C = C
193
- Build_in_Res2Nets = []
194
- bns = []
195
- for i in range(Nes_ratio[0] - 1):
196
- Build_in_Res2Nets.append(
197
- Bottle2neck(
198
- C,
199
- C,
200
- kernel_size=3,
201
- dilation=dilation,
202
- scale=Nes_ratio[1],
203
- SE_ratio=SE_ratio[0],
204
- )
205
- )
206
- bns.append(nn.BatchNorm1d(C))
207
- self.Build_in_Res2Nets = nn.ModuleList(Build_in_Res2Nets)
208
- self.bns = nn.ModuleList(bns)
209
- self.bn = nn.BatchNorm1d(1024)
210
- self.relu = nn.ReLU()
211
- self.pool_func = pool_func
212
- if pool_func == "mean":
213
- self.fc = nn.Linear(1024, n_output_logits)
214
- elif pool_func == "ASTP":
215
- self.pooling = ASTP(
216
- in_dim=input_channel, bottleneck_dim=128, global_context_att=False
217
- )
218
- self.fc = nn.Linear(2048, n_output_logits)
219
-
220
- def forward(self, x):
221
- spx = torch.split(x, self.C, 1)
222
- for i in range(self.Nes_ratio - 1):
223
- if i == 0:
224
- sp = spx[i]
225
- else:
226
- sp = sp + spx[i]
227
- sp = self.Build_in_Res2Nets[i](sp)
228
- sp = self.relu(sp)
229
- sp = self.bns[i](sp)
230
- if i == 0:
231
- out = sp
232
- else:
233
- out = torch.cat((out, sp), 1)
234
- out = torch.cat((out, spx[-1]), 1)
235
- out = self.bn(out)
236
- out = self.relu(out)
237
- if self.pool_func == "mean":
238
- out = torch.mean(out, dim=-1)
239
- elif self.pool_func == "ASTP":
240
- out = self.pooling(out)
241
- out = self.fc(out)
242
- return out
243
-
244
-
245
- class wav2vec2_Nes2Net_no_Res_w_allT(nn.Module):
246
- def __init__(self, args, device):
247
- super().__init__()
248
- self.device = device
249
-
250
- self.n_output_logits = args.n_output_logits
251
-
252
- ####
253
- # create network wav2vec 2.0
254
- ####
255
- self.ssl_model = SSLModel(self.device)
256
- self.Nested_Res2Net_TDNN = Nested_Res2Net_TDNN(
257
- Nes_ratio=args.Nes_ratio,
258
- input_channel=1024,
259
- n_output_logits=self.n_output_logits,
260
- dilation=args.dilation,
261
- pool_func=args.pool_func,
262
- SE_ratio=args.SE_ratio,
263
- )
264
-
265
- def forward(self, x):
266
- # -------pre-trained Wav2vec model fine tunning ------------------------##
267
- x_ssl_feat = self.ssl_model.extract_feat(x.squeeze(-1))
268
- x_ssl_feat = x_ssl_feat.permute(0, 2, 1)
269
- output = self.Nested_Res2Net_TDNN(x_ssl_feat)
270
-
271
- return output
272
-
273
-
274
- if __name__ == "__main__":
275
- import argparse
276
-
277
- parser = argparse.ArgumentParser()
278
- parser.add_argument("--n_output_logits", type=int, default=2)
279
- parser.add_argument("--dilation", type=int, default=2) # not important
280
- parser.add_argument(
281
- "--pool_func",
282
- type=str,
283
- default="mean",
284
- choices=["mean", "ASTP"],
285
- help="pooling function, choose from mean and ASTP",
286
- )
287
- parser.add_argument(
288
- "--Nes_ratio",
289
- type=int,
290
- nargs="+",
291
- default=[8, 8],
292
- help="Nes_ratio, from outer to inner",
293
- )
294
- parser.add_argument(
295
- "--SE_ratio",
296
- type=int,
297
- nargs="+",
298
- default=[1],
299
- help="SE downsampling ratio in the bottleneck",
300
- )
301
- args = parser.parse_args()
302
-
303
- model = wav2vec2_Nes2Net_no_Res_w_allT(args=args, device="cpu")
304
- x = torch.rand((4, 32000)).to("cpu")
305
- model = model.to("cpu")
306
- y = model(x)
307
- print(y)
308
- trainable_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
309
- print("all:", trainable_params)
310
- trainable_params = sum(
311
- p.numel() for p in model.ssl_model.parameters() if p.requires_grad
312
- )
313
- print("SSL:", trainable_params)
314
- trainable_params = sum(
315
- p.numel() for p in model.Nested_Res2Net_TDNN.parameters() if p.requires_grad
316
- )
317
- print("Backend:", trainable_params)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
audio/nes2net/requirements.txt DELETED
@@ -1,13 +0,0 @@
1
- torch==2.5.1
2
- torchaudio==2.5.1
3
- numpy==1.23.5
4
- librosa==0.9.1
5
- soundfile
6
- scipy
7
- omegaconf
8
- hydra-core
9
- bitarray
10
- fastapi
11
- uvicorn[standard]
12
- pydantic
13
- python-multipart
 
 
 
 
 
 
 
 
 
 
 
 
 
 
audio/safeear/Dockerfile DELETED
@@ -1,49 +0,0 @@
1
- FROM nvidia/cuda:12.1.1-cudnn8-runtime-ubuntu22.04
2
-
3
- ENV DEBIAN_FRONTEND=noninteractive
4
- ENV PYTHONUNBUFFERED=1
5
-
6
- RUN apt-get update && apt-get install -y --no-install-recommends \
7
- python3 python3-pip python3-dev \
8
- git ffmpeg libsndfile1 wget \
9
- build-essential \
10
- && rm -rf /var/lib/apt/lists/*
11
-
12
- RUN ln -sf /usr/bin/python3 /usr/bin/python
13
-
14
- WORKDIR /app
15
-
16
- # Install PyTorch with CUDA 12.1
17
- RUN pip install --no-cache-dir \
18
- torch==2.5.1 torchaudio==2.5.1 \
19
- --index-url https://download.pytorch.org/whl/cu121
20
-
21
- COPY requirements.txt .
22
- RUN pip install --no-cache-dir -r requirements.txt
23
-
24
- # Clone SafeEar repository (for model code imports)
25
- RUN git clone --depth 1 https://github.com/LetterLiGo/SafeEar.git /app/safeear_repo
26
-
27
- # Install the fairseq fork with C extensions PATCHED OUT
28
- # (same proven patch used by ShiftySpeech and Nes2Net --
29
- # C extensions are not needed for checkpoint loading)
30
- WORKDIR /app/safeear_repo/fairseq_ours
31
- RUN sed -i 's/ext_modules=extensions/ext_modules=[]/' setup.py && \
32
- pip install --no-cache-dir --no-deps -e .
33
- WORKDIR /app
34
-
35
- # Download model weights from HuggingFace
36
- RUN mkdir -p /app/weights && \
37
- wget -q -O /app/weights/SpeechTokenizer.pt \
38
- "https://huggingface.co/TEC2004/SafeEar-ASV19-spoof-detection/resolve/main/SpeechTokenizer.pt" && \
39
- wget -q -O /app/weights/model.ckpt \
40
- "https://huggingface.co/TEC2004/SafeEar-ASV19-spoof-detection/resolve/main/model.ckpt"
41
-
42
- COPY api.py .
43
-
44
- EXPOSE 8002
45
-
46
- RUN adduser --disabled-password --gecos '' appuser
47
- USER appuser
48
-
49
- CMD ["python", "api.py"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
audio/safeear/api.py DELETED
@@ -1,321 +0,0 @@
1
- """SafeEar audio deepfake detection API service.
2
-
3
- Uses the SafeEar content privacy-preserving model (CCS 2024) to detect
4
- synthetic speech. Two-stage pipeline:
5
- 1. SpeechTokenizer (neural audio codec) decouples acoustic features
6
- 2. SafeEar1s (transformer classifier) detects spoofing from acoustic tokens
7
-
8
- Weights: HuggingFace TEC2004/SafeEar-ASV19-spoof-detection
9
- """
10
-
11
- import base64
12
- import logging
13
- import os
14
- import sys
15
- import tempfile
16
- import time
17
- from typing import Optional
18
-
19
- import uvicorn
20
- from fastapi import FastAPI, HTTPException
21
- from pydantic import BaseModel, Field
22
-
23
- logging.basicConfig(
24
- level=logging.INFO,
25
- format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
26
- )
27
- logger = logging.getLogger("safeear_api")
28
-
29
- import platform
30
-
31
- import librosa
32
- import numpy as np
33
- import torch
34
-
35
- # Add SafeEar repo to path for model imports
36
- SAFEEAR_REPO_PATH = os.environ.get(
37
- "SAFEEAR_REPO_PATH",
38
- os.path.join(os.path.dirname(__file__), "safeear_repo"),
39
- )
40
- if SAFEEAR_REPO_PATH not in sys.path:
41
- sys.path.insert(0, SAFEEAR_REPO_PATH)
42
-
43
-
44
- def _get_device():
45
- """Select optimal device: MPS (Apple) > CUDA (NVIDIA) > CPU."""
46
- override = os.environ.get("DEEPSAFE_DEVICE", "").strip().lower()
47
- if override == "cpu":
48
- return torch.device("cpu")
49
- if override == "cuda" and torch.cuda.is_available():
50
- return torch.device("cuda")
51
- if (
52
- override == "mps"
53
- and hasattr(torch.backends, "mps")
54
- and torch.backends.mps.is_available()
55
- ):
56
- return torch.device("mps")
57
- if (
58
- platform.system() == "Darwin"
59
- and hasattr(torch.backends, "mps")
60
- and torch.backends.mps.is_available()
61
- ):
62
- return torch.device("mps")
63
- if torch.cuda.is_available():
64
- return torch.device("cuda")
65
- return torch.device("cpu")
66
-
67
-
68
- # Constants
69
- MODEL_NAME = "safeear"
70
- WEIGHTS_DIR = os.environ.get(
71
- "WEIGHTS_DIR",
72
- os.path.join(os.path.dirname(__file__), "weights"),
73
- )
74
- DEVICE = _get_device()
75
-
76
- if DEVICE.type == "cuda":
77
- torch.backends.cudnn.benchmark = True
78
- torch.set_float32_matmul_precision("high")
79
-
80
- if DEVICE.type == "cuda":
81
- logger.info(
82
- "Device: cuda (%s, %.1f GB VRAM)",
83
- torch.cuda.get_device_name(0),
84
- torch.cuda.get_device_properties(0).total_memory / 1024**3,
85
- )
86
- else:
87
- logger.warning(
88
- "Device: %s (no CUDA available -- check nvidia-container-toolkit)",
89
- DEVICE,
90
- )
91
-
92
- SAMPLE_RATE = 16000
93
- MAX_AUDIO_LENGTH = 64600 # ~4 seconds at 16kHz (ASVspoof standard)
94
- SOFTMAX_TEMPERATURE = 5.0 # Calibration temperature for out-of-distribution data
95
- NUM_INFERENCE_PASSES = 5 # Monte Carlo passes for stable predictions
96
-
97
- # Global model instances
98
- decouple_model = None
99
- detect_model = None
100
-
101
-
102
- class AudioInput(BaseModel):
103
- """Schema for audio prediction requests."""
104
-
105
- audio_data: str = Field(
106
- ..., description="Base64 encoded audio string (WAV/MP3/etc)"
107
- )
108
- threshold: Optional[float] = Field(
109
- 0.5, ge=0.0, le=1.0, description="Classification threshold"
110
- )
111
-
112
-
113
- app = FastAPI(
114
- title="SafeEar Audio Deepfake Detection API",
115
- description="Content privacy-preserving deepfake detection using SafeEar.",
116
- version="1.0.0",
117
- )
118
-
119
-
120
- def load_models():
121
- """Load both the decouple model (SpeechTokenizer) and detect model."""
122
- global decouple_model, detect_model
123
-
124
- if decouple_model is not None and detect_model is not None:
125
- return True
126
-
127
- speech_tokenizer_path = os.path.join(WEIGHTS_DIR, "SpeechTokenizer.pt")
128
- checkpoint_path = os.path.join(WEIGHTS_DIR, "model.ckpt")
129
-
130
- if not os.path.exists(speech_tokenizer_path):
131
- logger.error(f"SpeechTokenizer weights not found: {speech_tokenizer_path}")
132
- return False
133
- if not os.path.exists(checkpoint_path):
134
- logger.error(f"Model checkpoint not found: {checkpoint_path}")
135
- return False
136
-
137
- try:
138
- # --- Load SpeechTokenizer (decouple model) ---
139
- from safeear.models.decouple import SpeechTokenizer
140
-
141
- logger.info("Loading SpeechTokenizer...")
142
- decouple_model = SpeechTokenizer(
143
- n_filters=64,
144
- strides=[8, 5, 4, 2],
145
- dimension=1024,
146
- semantic_dimension=768,
147
- bidirectional=True,
148
- dilation_base=2,
149
- residual_kernel_size=3,
150
- n_residual_layers=1,
151
- lstm_layers=2,
152
- activation="ELU",
153
- codebook_size=1024,
154
- n_q=8,
155
- sample_rate=16000,
156
- )
157
- st_state = torch.load(speech_tokenizer_path, map_location="cpu")
158
- decouple_model.load_state_dict(st_state)
159
- decouple_model.to(DEVICE)
160
- decouple_model.eval()
161
- logger.info("SpeechTokenizer loaded.")
162
-
163
- # --- Load SafeEar1s (detect model) from Lightning checkpoint ---
164
- from safeear.models.safeear import SafeEar1s, SE_Rawformer_front
165
-
166
- logger.info("Loading SafeEar1s detect model...")
167
- detect_model = SafeEar1s(
168
- front=SE_Rawformer_front(),
169
- embedding_dim=1024,
170
- dropout_rate=0.1,
171
- attention_dropout=0.1,
172
- stochastic_depth=0.1,
173
- num_layers=2,
174
- num_heads=8,
175
- num_classes=2,
176
- positional_embedding="sine",
177
- mlp_ratio=1.0,
178
- )
179
-
180
- # The .ckpt is a PyTorch Lightning checkpoint
181
- ckpt = torch.load(checkpoint_path, map_location="cpu")
182
- state_dict = ckpt.get("state_dict", ckpt)
183
-
184
- # Lightning prefixes keys with "detect_model."
185
- detect_state = {}
186
- for k, v in state_dict.items():
187
- if k.startswith("detect_model."):
188
- detect_state[k.replace("detect_model.", "", 1)] = v
189
-
190
- detect_model.load_state_dict(detect_state)
191
- detect_model.to(DEVICE)
192
- detect_model.eval()
193
- logger.info("SafeEar1s detect model loaded.")
194
- return True
195
-
196
- except Exception as e:
197
- logger.exception(f"Failed to load SafeEar models: {e}")
198
- decouple_model = None
199
- detect_model = None
200
- return False
201
-
202
-
203
- def preprocess_audio(audio_bytes: bytes) -> torch.Tensor:
204
- """Load audio bytes, resample to 16kHz mono, pad/trim."""
205
- with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp:
206
- tmp.write(audio_bytes)
207
- tmp_path = tmp.name
208
-
209
- try:
210
- waveform, _ = librosa.load(tmp_path, sr=SAMPLE_RATE, mono=True)
211
- finally:
212
- os.unlink(tmp_path)
213
-
214
- if len(waveform) < MAX_AUDIO_LENGTH:
215
- waveform = np.pad(waveform, (0, MAX_AUDIO_LENGTH - len(waveform)))
216
- else:
217
- waveform = waveform[:MAX_AUDIO_LENGTH]
218
-
219
- # Shape: (1, 1, samples) -- batch=1, channels=1, time
220
- tensor = torch.FloatTensor(waveform).unsqueeze(0).unsqueeze(0).to(DEVICE)
221
- return tensor
222
-
223
-
224
- @app.on_event("startup")
225
- async def startup_event():
226
- """Attempt to load models at startup."""
227
- load_models()
228
-
229
-
230
- def _gpu_health_info() -> dict:
231
- """Return GPU metrics for the health endpoint."""
232
- if torch.cuda.is_available() and DEVICE.type == "cuda":
233
- return {
234
- "gpu_name": torch.cuda.get_device_name(0),
235
- "vram_used_mb": round(torch.cuda.memory_allocated(0) / 1024**2),
236
- "vram_total_mb": round(
237
- torch.cuda.get_device_properties(0).total_memory / 1024**2
238
- ),
239
- }
240
- return {}
241
-
242
-
243
- @app.get("/health")
244
- async def health():
245
- """Return service health status and model availability."""
246
- models_loaded = decouple_model is not None and detect_model is not None
247
- return {
248
- "status": "healthy" if models_loaded else "degraded",
249
- "model": MODEL_NAME,
250
- "device": str(DEVICE),
251
- "weights_found": (
252
- os.path.exists(os.path.join(WEIGHTS_DIR, "SpeechTokenizer.pt"))
253
- and os.path.exists(os.path.join(WEIGHTS_DIR, "model.ckpt"))
254
- ),
255
- **_gpu_health_info(),
256
- }
257
-
258
-
259
- @app.post("/predict")
260
- async def predict(input_data: AudioInput):
261
- """Run SafeEar inference on base64-encoded audio data."""
262
- if decouple_model is None or detect_model is None:
263
- if not load_models():
264
- raise HTTPException(status_code=503, detail="Models not loaded")
265
-
266
- try:
267
- start_time = time.time()
268
- logger.info(
269
- "Received prediction request. "
270
- f"Data size: {len(input_data.audio_data)} chars"
271
- )
272
-
273
- audio_bytes = base64.b64decode(input_data.audio_data)
274
- x_wav = preprocess_audio(audio_bytes)
275
-
276
- with torch.no_grad():
277
- # Step 1: Extract acoustic tokens via SpeechTokenizer
278
- # forward() returns:
279
- # (reconstructed, commit_loss, semantic_feature, acoustic_tokens)
280
- # layers=[0,1,2,3,4,5,6,7] means layer 0 goes to
281
- # semantic_feature; layers 1-7 go to acoustic_tokens list
282
- _, _, _, acoustic_tokens = decouple_model(
283
- x_wav, layers=[0, 1, 2, 3, 4, 5, 6, 7]
284
- )
285
-
286
- # Step 2: Run detection model with Monte Carlo averaging
287
- # SafeEar1s uses torch.randperm() in forward, so we average
288
- # multiple passes for stable predictions
289
- logit_sum = torch.zeros(1, 2, device=DEVICE)
290
- for _ in range(NUM_INFERENCE_PASSES):
291
- raw_logits, _ = detect_model(acoustic_tokens)
292
- logit_sum += raw_logits
293
- avg_logits = logit_sum / NUM_INFERENCE_PASSES
294
-
295
- # Step 3: Get fake probability with temperature-scaled softmax
296
- # The model produces extreme logits that saturate standard
297
- # softmax. Temperature scaling preserves discrimination while
298
- # giving more interpretable probabilities.
299
- probs = torch.softmax(avg_logits / SOFTMAX_TEMPERATURE, dim=-1)
300
- prob_fake = probs[0, 1].item()
301
-
302
- prediction = 1 if prob_fake >= input_data.threshold else 0
303
- verdict = "fake" if prediction == 1 else "real"
304
- inference_time = time.time() - start_time
305
-
306
- return {
307
- "model": MODEL_NAME,
308
- "probability": float(prob_fake),
309
- "prediction": int(prediction),
310
- "class": verdict,
311
- "inference_time": float(inference_time),
312
- }
313
-
314
- except Exception as e:
315
- logger.exception(f"Error during prediction: {e}")
316
- raise HTTPException(status_code=500, detail=str(e))
317
-
318
-
319
- if __name__ == "__main__":
320
- port = int(os.environ.get("MODEL_PORT", 8002))
321
- uvicorn.run(app, host="0.0.0.0", port=port)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
audio/safeear/download_weights.sh DELETED
@@ -1,23 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- WEIGHTS_DIR="${WEIGHTS_DIR:-/app/weights}"
5
- REPO_DIR="${REPO_DIR:-/app/safeear_repo}"
6
-
7
- mkdir -p "$WEIGHTS_DIR"
8
-
9
- echo "==> Cloning SafeEar source repository..."
10
- if [ ! -d "$REPO_DIR/.git" ]; then
11
- git clone --depth 1 https://github.com/LetterLiGo/SafeEar.git "$REPO_DIR"
12
- fi
13
-
14
- echo "==> Downloading SpeechTokenizer.pt from HuggingFace..."
15
- wget -q --show-progress -O "$WEIGHTS_DIR/SpeechTokenizer.pt" \
16
- "https://huggingface.co/TEC2004/SafeEar-ASV19-spoof-detection/resolve/main/SpeechTokenizer.pt"
17
-
18
- echo "==> Downloading model.ckpt from HuggingFace..."
19
- wget -q --show-progress -O "$WEIGHTS_DIR/model.ckpt" \
20
- "https://huggingface.co/TEC2004/SafeEar-ASV19-spoof-detection/resolve/main/model.ckpt"
21
-
22
- echo "==> Weights downloaded to $WEIGHTS_DIR"
23
- ls -lh "$WEIGHTS_DIR"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
audio/safeear/requirements.txt DELETED
@@ -1,15 +0,0 @@
1
- torch==2.5.1
2
- torchaudio==2.5.1
3
- librosa>=0.10.0
4
- soundfile>=0.11.0
5
- numpy>=1.23.0
6
- einops>=0.7.0
7
- timm>=0.9.0
8
- hydra-core>=1.0.7
9
- omegaconf>=2.1.0
10
- pytorch-lightning>=1.6.0
11
- scipy>=1.11.0
12
- fastapi>=0.100.0
13
- uvicorn[standard]>=0.20.0
14
- python-multipart>=0.0.5
15
- pydantic>=2.0.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
audio/safeear/safeear_repo/.gitignore DELETED
@@ -1,167 +0,0 @@
1
- # Byte-compiled / optimized / DLL files
2
- __pycache__/
3
- *.py[cod]
4
- *$py.class
5
-
6
- # C extensions
7
- *.so
8
-
9
- # Distribution / packaging
10
- .Python
11
- build/
12
- develop-eggs/
13
- dist/
14
- downloads/
15
- eggs/
16
- .eggs/
17
- lib/
18
- lib64/
19
- parts/
20
- sdist/
21
- var/
22
- wheels/
23
- share/python-wheels/
24
- *.egg-info/
25
- .installed.cfg
26
- *.egg
27
- MANIFEST
28
-
29
- # PyInstaller
30
- # Usually these files are written by a python script from a template
31
- # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
- *.manifest
33
- *.spec
34
-
35
- # Installer logs
36
- pip-log.txt
37
- pip-delete-this-directory.txt
38
-
39
- # Unit test / coverage reports
40
- htmlcov/
41
- .tox/
42
- .nox/
43
- .coverage
44
- .coverage.*
45
- .cache
46
- nosetests.xml
47
- coverage.xml
48
- *.cover
49
- *.py,cover
50
- .hypothesis/
51
- .pytest_cache/
52
- cover/
53
-
54
- # Translations
55
- *.mo
56
- *.pot
57
-
58
- # Django stuff:
59
- *.log
60
- local_settings.py
61
- db.sqlite3
62
- db.sqlite3-journal
63
-
64
- # Flask stuff:
65
- instance/
66
- .webassets-cache
67
-
68
- # Scrapy stuff:
69
- .scrapy
70
-
71
- # Sphinx documentation
72
- docs/_build/
73
-
74
- # PyBuilder
75
- .pybuilder/
76
- target/
77
-
78
- # Jupyter Notebook
79
- .ipynb_checkpoints
80
-
81
- # IPython
82
- profile_default/
83
- ipython_config.py
84
-
85
- # pyenv
86
- # For a library or package, you might want to ignore these files since the code is
87
- # intended to run in multiple environments; otherwise, check them in:
88
- # .python-version
89
-
90
- # pipenv
91
- # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
- # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
- # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
- # install all needed dependencies.
95
- #Pipfile.lock
96
-
97
- # poetry
98
- # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99
- # This is especially recommended for binary packages to ensure reproducibility, and is more
100
- # commonly ignored for libraries.
101
- # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102
- #poetry.lock
103
-
104
- # pdm
105
- # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106
- #pdm.lock
107
- # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108
- # in version control.
109
- # https://pdm.fming.dev/#use-with-ide
110
- .pdm.toml
111
-
112
- # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113
- __pypackages__/
114
-
115
- # Celery stuff
116
- celerybeat-schedule
117
- celerybeat.pid
118
-
119
- # SageMath parsed files
120
- *.sage.py
121
-
122
- # Environments
123
- .env
124
- .venv
125
- env/
126
- venv/
127
- ENV/
128
- env.bak/
129
- venv.bak/
130
-
131
- # Spyder project settings
132
- .spyderproject
133
- .spyproject
134
-
135
- # Rope project settings
136
- .ropeproject
137
-
138
- # mkdocs documentation
139
- /site
140
-
141
- # mypy
142
- .mypy_cache/
143
- .dmypy.json
144
- dmypy.json
145
-
146
- # Pyre type checker
147
- .pyre/
148
-
149
- # pytype static type analyzer
150
- .pytype/
151
-
152
- # Cython debug symbols
153
- cython_debug/
154
-
155
- # PyCharm
156
- # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157
- # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
158
- # and can be added to the global gitignore or merged into this file. For a more nuclear
159
- # option (not recommended) you can uncomment the following to ignore the entire idea folder.
160
- #.idea/
161
- model_zoos/*
162
- Exps/*
163
- datas/datasets
164
- datas/ASVSpoof2019/LA
165
- datas/ASVSpoof2021/ASVspoof2021_LA_eval
166
- datas/ASVSpoof2021/keys
167
- create_tsv.py
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
audio/safeear/safeear_repo/LICENSE DELETED
@@ -1,23 +0,0 @@
1
- # Creative Commons Attribution 4.0 International License
2
-
3
- ## License
4
-
5
- You are free to:
6
-
7
- - Share โ€” copy and redistribute the material in any medium or format
8
- - Adapt โ€” remix, transform, and build upon the material for any purpose, even commercially.
9
-
10
- Under the following terms:
11
-
12
- 1. **Attribution** โ€” You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
13
-
14
- 2. **No additional restrictions** โ€” You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits.
15
-
16
- ## Other Terms
17
-
18
- - This license applies to all types of works, including but not limited to text, images, audio, video, etc.
19
- - This license does not apply to any third-party materials included in the work, for which you must obtain permission separately.
20
-
21
- ## Disclaimer
22
-
23
- This work is provided on an "as is" basis, without any warranties or conditions of any kind, either express or implied, including but not limited to implied warranties of merchantability, fitness for a particular purpose, or non-infringement.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
audio/safeear/safeear_repo/README.md DELETED
@@ -1,134 +0,0 @@
1
- # <font color=E7595C>Safe</font><font color=F6C446>Ear</font><img src="assert/SafeEar_logo.jpg" alt="icon" style="width: 2em; height: 1.5em; vertical-align: middle;">: <font color=E7595C>Content Privacy-Preserving</font> <font color=F6C446>Audio Deepfake Detection</font>
2
-
3
- [![arXiv](https://img.shields.io/badge/arXiv-2409.09272-b31b1b.svg)](https://arxiv.org/abs/2409.09272)
4
- [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://makeapullrequest.com)
5
- [![CC BY 4.0](https://img.shields.io/badge/license-CC%20BY%204.0-blue.svg)](https://creativecommons.org/licenses/by/4.0/)
6
- ![GitHub stars](https://img.shields.io/github/stars/LetterLiGo/SafeEar)
7
- ![GitHub forks](https://img.shields.io/github/forks/LetterLiGo/SafeEar)
8
- ![Website](https://img.shields.io/website?url=https://safeearweb.github.io/Project/)
9
-
10
-
11
- By [1] Zhejiang University, [2] Tsinghua University.
12
- * [Xinfeng Li](https://letterligo.github.io)* [1], [Kai Li](https://cslikai.cn)* [2], Yifan Zheng [1], Chen Yanโ€  [1], Xiaoyu Ji [1], Wenyuan Xu [1].
13
-
14
- This repository is an official implementation of the SafeEar accepted to **ACM CCS 2024** (Core-A*, CCF-A, Big4) .
15
-
16
- Please also visit our <a href="https://safeearweb.github.io/Project/">(1) Project Website</a>, <a href="https://zenodo.org/records/14062964">(2) Full CVoiceFake Dataset</a>, and <a href="https://zenodo.org/records/11124319">(3) Sampled CVoiceFake Dataset</a>.
17
-
18
- ## ๐Ÿ”ฅNews
19
-
20
- [2025-03-18]: Supported the batch testing for ASVspoof 2019 and 2021, fixed some bugs for datasets and trainer.
21
-
22
- [2024-12-10]: Fixed all the bugs for training and test, and uploaded the files for data generation `datas/`.
23
-
24
- [2024-12-01]: Uploaded the checkpoint for data generation `datas/`.
25
-
26
- ## โœจKey Highlights:
27
-
28
- In this paper, we propose SafeEar, a novel framework that aims to detect deepfake audios without relying on accessing the speech content within. Our key idea is to devise a neural audio codec into a novel decoupling model that well separates the semantic and acoustic information from audio samples, and only use the acoustic information (e.g., prosody and timbre) for deepfake detection. In this way, no semantic content will be exposed to the detector. To overcome the challenge of identifying diverse deepfake audio without semantic clues, we enhance our deepfake detector with multi-head self-attention and codec augmentation. Extensive experiments conducted on four benchmark datasets demonstrate SafeEarโ€™s effectiveness in detecting various deepfake techniques with an equal error rate (EER) down to 2.02%. Simultaneously, it shields five-language speech content from being deciphered by both machine and human auditory analysis, demonstrated by word error rates (WERs) all above 93.93% and our user study. Furthermore, our benchmark constructed for anti-deepfake and anti-content recovery evaluation helps provide a basis for future research in the realms of audio privacy preservation and deepfake detection.
29
-
30
- ## ๐Ÿš€Overall Pipeline
31
-
32
- ![pipeline](assert/overall.gif)
33
-
34
- ## ๐Ÿ”งInstallation
35
-
36
- 1. Clone the repository:
37
-
38
- ```shell
39
- git clone git@github.com:LetterLiGo/SafeEar.git
40
- cd SafeEar/
41
- ```
42
-
43
- 2. Create and activate the conda environment:
44
-
45
- ```shell
46
- conda create -n safeear python=3.9
47
- conda activate safeear
48
- ```
49
-
50
- 3. Install PyTorch and torchvision following the [official instructions](https://pytorch.org). The code requires `python=3.9`, `pytorch=1.13`, `torchvision=0.14`.
51
-
52
-
53
- ```shell
54
- pip install torch==1.13.1+cu116 torchvision==0.14.1+cu116 torchaudio==0.13.1 --extra-index-url https://download.pytorch.org/whl/cu116
55
-
56
- ```
57
- 4. Install other dependencies:
58
-
59
- ```shell
60
- pip install pip==24.0
61
- pip install -r requirements.txt
62
- ```
63
-
64
- ## ๐Ÿ“ŠModel Performance
65
- ### ASVspoof 2019 & 2021
66
- ![](assert/ASVSpoof-results.png)
67
- ### Speech Recognition Performance
68
- ![](assert/exp1.png)
69
-
70
- ## Data preparation
71
-
72
- ### AVSpoof 2019 & 2021
73
-
74
- Please download the [ASVspoof 2019](https://datashare.is.ed.ac.uk/handle/10283/3336) and [ASVspoof 2021](https://www.asvspoof.org/index2021.html) datasets and extract them to the `datas/datasets` directory.
75
-
76
- ```shell
77
- datas/datasets/ASVspoof2019
78
- datas/datasets/ASVspoof2021
79
- ```
80
-
81
- #### Generate the Hubert L9 feature files
82
-
83
- ```shell
84
- mkdir model_zoos
85
- cd model_zoos
86
- wget https://dl.fbaipublicfiles.com/hubert/hubert_base_ls960.pt
87
- wget https://cloud.tsinghua.edu.cn/f/413a0cd2e6f749eea956/?dl=1 -O SpeechTokenizer.pt
88
- cd ../datas
89
- # Generate the Hubert L9 feature files for ASVspoof 2019
90
- python dump_hubert_avg_feature.py datasets/ASVSpoof2019 datasets/ASVSpoof2019_Hubert_L9
91
- # Generate the Hubert L9 feature files for ASVspoof 2021
92
- python dump_hubert_avg_feature.py datasets/ASVSpoof2021 datasets/ASVSpoof2021_Hubert_L9
93
- ```
94
-
95
- ## ๐Ÿ“šTraining
96
-
97
- Before starting training, please modify the parameter configurations in [`configs`](configs).
98
-
99
- Use the following commands to start training:
100
-
101
- ```shell
102
- python train.py --conf_dir config/train19.yaml
103
- python train.py --conf_dir config/train21.yaml
104
- ```
105
-
106
- ## ๐Ÿ“ˆTesting/Inference
107
-
108
- To evaluate a model on one or more GPUs, specify the `CUDA_VISIBLE_DEVICES`, `dataset`, `model` and `checkpoint`:
109
-
110
- ```shell
111
- python test.py --conf_dir Exps/ASVspoof19/config.yaml
112
- python test.py --conf_dir Exps/ASVspoof21/config.yaml
113
- ```
114
-
115
- ## Bugs and Issues
116
-
117
- If you meet `RuntimeError: Failed to load audio from <_io.BytesIO object at 0x7f45cb978f90>`, please use the following command to fix it:
118
-
119
- ```shell
120
- conda install -c anaconda 'ffmpeg<4.4'
121
- ```
122
-
123
- ## ๐Ÿ“œCitation
124
-
125
- If you find our work/code/dataset helpful, please consider citing:
126
-
127
- ```
128
- @inproceedings{li2024safeear,
129
- author = {Li, Xinfeng and Li, Kai and Zheng, Yifan and Yan, Chen and Ji, Xiaoyu, and Xu, Wenyuan},
130
- title = {{SafeEar: Content Privacy-Preserving Audio Deepfake Detection}},
131
- booktitle = {Proceedings of the 2024 {ACM} {SIGSAC} Conference on Computer and Communications Security (CCS)}
132
- year = {2024},
133
- }
134
- ```
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
audio/safeear/safeear_repo/assert/ASVSpoof-results.png DELETED

Git LFS Details

  • SHA256: 0697de878b12c7b96ad4609569ddc20388027764ca441575b9c66dc6696d53d2
  • Pointer size: 131 Bytes
  • Size of remote file: 684 kB
audio/safeear/safeear_repo/assert/Fig1.jpg DELETED

Git LFS Details

  • SHA256: 433d57f7a1496c0b3ad6c6c06434261ba2b98901a2fccbd821326a8637fc8135
  • Pointer size: 131 Bytes
  • Size of remote file: 236 kB
audio/safeear/safeear_repo/assert/SafeEar_logo.jpg DELETED

Git LFS Details

  • SHA256: e9ab20f08e487b0454686259bf9c52a4b79d35144e56a40f3f8abd94ce0e637f
  • Pointer size: 131 Bytes
  • Size of remote file: 258 kB
audio/safeear/safeear_repo/assert/exp1.png DELETED

Git LFS Details

  • SHA256: 5f6468a63356b243039324d80e928936d5eaac34b668e4410090b8418f5d0918
  • Pointer size: 132 Bytes
  • Size of remote file: 1.64 MB
audio/safeear/safeear_repo/assert/overall.gif DELETED

Git LFS Details

  • SHA256: a946cf1f760f5f94cdf8907ff2ac70f38ea211964c9df6c1e9a2f1237be6aed0
  • Pointer size: 131 Bytes
  • Size of remote file: 114 kB
audio/safeear/safeear_repo/assert/overall.mp4 DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:d34cf40c912995aeb9070d168bc41663e365b5e64544538e8cb7e36770233afc
3
- size 2170657
 
 
 
 
audio/safeear/safeear_repo/assert/overall.png DELETED

Git LFS Details

  • SHA256: f0271961e7957d83622d2b24a0f6f791bd131a1a493a72abc1142fd8b4a48e1a
  • Pointer size: 131 Bytes
  • Size of remote file: 121 kB
audio/safeear/safeear_repo/assert/safe-space.png DELETED
Binary file (36.3 kB)
 
audio/safeear/safeear_repo/config/train19.yaml DELETED
@@ -1,87 +0,0 @@
1
- datamodule:
2
- _target_: safeear.datas.asvspoof19.DataModule
3
- batch_size: 2
4
- num_workers: 8
5
- pin_memory: true
6
- DataClass_dict:
7
- _target_: safeear.datas.asvspoof19.DataClass
8
- train_path: ["datas/ASVSpoof2019/train.tsv", "datas/ASVSpoof2019/ASVspoof2019.LA.cm.train.trn.txt", "datas/datasets/ASVSpoof2019_Hubert_L9/ASVspoof2019_LA_train/flac"]
9
- val_path: ["datas/ASVSpoof2019/dev.tsv", "datas/ASVSpoof2019/ASVspoof2019.LA.cm.dev.trl.txt", "datas/datasets/ASVSpoof2019_Hubert_L9/ASVspoof2019_LA_dev/flac"]
10
- test_path: ["datas/ASVSpoof2019/eval.tsv", "datas/ASVSpoof2019/ASVspoof2019.LA.cm.eval.trl.txt", "datas/datasets/ASVSpoof2019_Hubert_L9/ASVspoof2019_LA_eval/flac"]
11
- max_len: 64600
12
-
13
- decouple_model:
14
- _target_: safeear.models.decouple.SpeechTokenizer
15
- n_filters: 64
16
- strides: [8,5,4,2]
17
- dimension: 1024
18
- semantic_dimension: 768
19
- bidirectional: true
20
- dilation_base: 2
21
- residual_kernel_size: 3
22
- n_residual_layers: 1
23
- lstm_layers: 2
24
- activation: ELU
25
- codebook_size: 1024
26
- n_q: 8
27
- sample_rate: 16000
28
-
29
- speechtokenizer_path: model_zoos/SpeechTokenizer.pt
30
-
31
- detect_model:
32
- _target_: safeear.models.safeear.SafeEar1s
33
- front:
34
- _target_: safeear.models.safeear.SE_Rawformer_front
35
- embedding_dim: 1024
36
- dropout_rate: 0.1
37
- attention_dropout: 0.1
38
- stochastic_depth: 0.1
39
- num_layers: 2
40
- num_heads: 8
41
- num_classes: 2
42
- positional_embedding: 'sine'
43
- mlp_ratio: 1.0
44
-
45
- system:
46
- _target_: safeear.trainer.safeear_trainer.SafeEarTrainer
47
- lr_raw_former: 3.0e-4
48
- save_score_path: ${exp.dir}/${exp.name}
49
-
50
- exp:
51
- dir: Exps/ # ไฟฎๆ”น
52
- name: ASVspoof19 # ไฟฎๆ”น
53
-
54
- early_stopping:
55
- _target_: pytorch_lightning.callbacks.EarlyStopping
56
- monitor: val_eer # ไฟฎๆ”น
57
- mode: min
58
- patience: 40
59
- verbose: true
60
-
61
- checkpoint:
62
- _target_: pytorch_lightning.callbacks.ModelCheckpoint
63
- dirpath: ${exp.dir}/${exp.name}/checkpoints
64
- monitor: val_eer # ไฟฎๆ”น
65
- mode: min
66
- verbose: true
67
- save_top_k: 1
68
- save_last: true
69
- filename: '{epoch}-{val_eer:.4f}' # ไฟฎๆ”น
70
-
71
- logger:
72
- _target_: pytorch_lightning.loggers.WandbLogger
73
- name: ${exp.name}
74
- save_dir: ${exp.dir}/${exp.name}/logs
75
- offline: true
76
- project: SafeEar
77
-
78
- trainer:
79
- _target_: pytorch_lightning.Trainer
80
- devices: [0]
81
- max_epochs: 500
82
- sync_batchnorm: true
83
- default_root_dir: ${exp.dir}/${exp.name}/
84
- accelerator: gpu
85
- limit_train_batches: 1.0
86
- limit_val_batches: 1.0
87
- fast_dev_run: false
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
audio/safeear/safeear_repo/config/train21.yaml DELETED
@@ -1,87 +0,0 @@
1
- datamodule:
2
- _target_: safeear.datas.asvspoof21.DataModule
3
- batch_size: 2
4
- num_workers: 8
5
- pin_memory: true
6
- DataClass_dict:
7
- _target_: safeear.datas.asvspoof21.DataClass
8
- train_path: ["datas/ASVSpoof2019/train.tsv", "datas/ASVSpoof2019/ASVspoof2019.LA.cm.train.trn.txt", "datas/datasets/ASVSpoof2019_Hubert_L9/ASVspoof2019_LA_train/flac"]
9
- val_path: ["datas/ASVSpoof2019/dev.tsv", "datas/ASVSpoof2019/ASVspoof2019.LA.cm.dev.trl.txt", "datas/datasets/ASVSpoof2019_Hubert_L9/ASVspoof2019_LA_dev/flac"]
10
- test_path: ["datas/ASVSpoof2021/eval.tsv", "datas/ASVSpoof2021/ASVspoof2021.LA.cm.eval.trl.txt", "datas/datasets/ASVSpoof2021_Hubert_L9"]
11
- max_len: 64600
12
-
13
- decouple_model:
14
- _target_: safeear.models.decouple.SpeechTokenizer
15
- n_filters: 64
16
- strides: [8,5,4,2]
17
- dimension: 1024
18
- semantic_dimension: 768
19
- bidirectional: true
20
- dilation_base: 2
21
- residual_kernel_size: 3
22
- n_residual_layers: 1
23
- lstm_layers: 2
24
- activation: ELU
25
- codebook_size: 1024
26
- n_q: 8
27
- sample_rate: 16000
28
-
29
- speechtokenizer_path: model_zoos/SpeechTokenizer.pt
30
-
31
- detect_model:
32
- _target_: safeear.models.safeear.SafeEar1s
33
- front:
34
- _target_: safeear.models.safeear.SE_Rawformer_front
35
- embedding_dim: 1024
36
- dropout_rate: 0.1
37
- attention_dropout: 0.1
38
- stochastic_depth: 0.1
39
- num_layers: 2
40
- num_heads: 8
41
- num_classes: 2
42
- positional_embedding: 'sine'
43
- mlp_ratio: 1.0
44
-
45
- system:
46
- _target_: safeear.trainer.safeear_trainer.SafeEarTrainer
47
- lr_raw_former: 3.0e-4
48
- save_score_path: ${exp.dir}/${exp.name}
49
-
50
- exp:
51
- dir: Exps/ # ไฟฎๆ”น
52
- name: ASVspoof21 # ไฟฎๆ”น
53
-
54
- early_stopping:
55
- _target_: pytorch_lightning.callbacks.EarlyStopping
56
- monitor: val_eer # ไฟฎๆ”น
57
- mode: min
58
- patience: 40
59
- verbose: true
60
-
61
- checkpoint:
62
- _target_: pytorch_lightning.callbacks.ModelCheckpoint
63
- dirpath: ${exp.dir}/${exp.name}/checkpoints
64
- monitor: val_eer # ไฟฎๆ”น
65
- mode: min
66
- verbose: true
67
- save_top_k: 1
68
- save_last: true
69
- filename: '{epoch}-{val_eer:.4f}' # ไฟฎๆ”น
70
-
71
- logger:
72
- _target_: pytorch_lightning.loggers.WandbLogger
73
- name: ${exp.name}
74
- save_dir: ${exp.dir}/${exp.name}/logs
75
- offline: true
76
- project: SafeEar
77
-
78
- trainer:
79
- _target_: pytorch_lightning.Trainer
80
- devices: [0]
81
- max_epochs: 40
82
- sync_batchnorm: true
83
- default_root_dir: ${exp.dir}/${exp.name}/
84
- accelerator: gpu
85
- limit_train_batches: 1.0
86
- limit_val_batches: 1.0
87
- fast_dev_run: false
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
audio/safeear/safeear_repo/datas/ASVSpoof2019/ASVspoof2019.LA.cm.dev.trl.txt DELETED
The diff for this file is too large to render. See raw diff
 
audio/safeear/safeear_repo/datas/ASVSpoof2019/ASVspoof2019.LA.cm.eval.trl.txt DELETED
The diff for this file is too large to render. See raw diff
 
audio/safeear/safeear_repo/datas/ASVSpoof2019/ASVspoof2019.LA.cm.train.trn.txt DELETED
The diff for this file is too large to render. See raw diff
 
audio/safeear/safeear_repo/datas/ASVSpoof2019/dev.tsv DELETED
The diff for this file is too large to render. See raw diff
 
audio/safeear/safeear_repo/datas/ASVSpoof2019/eval.tsv DELETED
The diff for this file is too large to render. See raw diff
 
audio/safeear/safeear_repo/datas/ASVSpoof2019/train.tsv DELETED
The diff for this file is too large to render. See raw diff
 
audio/safeear/safeear_repo/datas/ASVSpoof2021/ASVspoof2021.LA.cm.eval.trl.txt DELETED
The diff for this file is too large to render. See raw diff
 
audio/safeear/safeear_repo/datas/ASVSpoof2021/eval.tsv DELETED
The diff for this file is too large to render. See raw diff
 
audio/safeear/safeear_repo/datas/dump_hubert_avg_feature.py DELETED
@@ -1,109 +0,0 @@
1
- # Copyright (c) Facebook, Inc. and its affiliates.
2
- #
3
- # This source code is licensed under the MIT license found in the
4
- # LICENSE file in the root directory of this source tree.
5
-
6
- import logging
7
- import os
8
- import sys
9
- import warnings
10
-
11
- warnings.filterwarnings('ignore')
12
- from pathlib import Path
13
-
14
- import fairseq
15
- import librosa
16
- import soundfile as sf
17
- import torch
18
- import torch.nn.functional as F
19
- import tqdm
20
- from feature_utils import dump_feature, get_path_iterator
21
- from npy_append_array import NpyAppendArray
22
-
23
- logging.basicConfig(
24
- format="%(asctime)s | %(levelname)s | %(name)s | %(message)s",
25
- datefmt="%Y-%m-%d %H:%M:%S",
26
- level=os.environ.get("LOGLEVEL", "INFO").upper(),
27
- stream=sys.stdout,
28
- )
29
- logger = logging.getLogger("dump_hubert_feature")
30
-
31
-
32
- class HubertFeatureReader(object):
33
- def __init__(self, ckpt_path, layer, max_chunk=1600000):
34
- (
35
- model,
36
- cfg,
37
- task,
38
- ) = fairseq.checkpoint_utils.load_model_ensemble_and_task([ckpt_path])
39
- self.model = model[0].eval().cuda()
40
- self.task = task
41
- self.layer = layer
42
- self.max_chunk = max_chunk
43
- logger.info(f"TASK CONFIG:\n{self.task.cfg}")
44
- logger.info(f" max_chunk = {self.max_chunk}")
45
-
46
- def read_audio(self, path, ref_len=None):
47
- wav, sr = librosa.load(path, sr=None)
48
- assert sr == self.task.cfg.sample_rate, sr
49
- if wav.ndim == 2:
50
- wav = wav.mean(-1)
51
- assert wav.ndim == 1, wav.ndim
52
- if ref_len is not None and abs(ref_len - len(wav)) > 160:
53
- logging.warning(f"ref {ref_len} != read {len(wav)} ({path})")
54
- return wav
55
-
56
- def get_feats(self, path, ref_len=None):
57
- x = self.read_audio(path, ref_len)
58
- with torch.no_grad():
59
- x = torch.from_numpy(x).float().cuda()
60
- if self.task.cfg.normalize:
61
- x = F.layer_norm(x, x.shape)
62
- x = x.view(1, -1)
63
-
64
- avg_feat = []
65
- for start in range(0, x.size(1), self.max_chunk):
66
- x_chunk = x[:, start: start + self.max_chunk]
67
- feat_chunk, _, avg_feat_chunk = self.model.extract_features(
68
- source=x_chunk,
69
- padding_mask=None,
70
- mask=False,
71
- output_layer=self.layer,
72
- )
73
- avg_feat.append(avg_feat_chunk)
74
- return torch.cat(avg_feat, 1).squeeze(0)
75
-
76
- def dump_feature(reader,audio_dir,save_dir):
77
- save_dir = Path(save_dir)
78
- audio_dir = Path(audio_dir)
79
-
80
- audio_files = list(audio_dir.glob("**/*.flac"))
81
- for audio_file in tqdm.tqdm(audio_files):
82
- releative_path = audio_file.relative_to(audio_dir).with_suffix(".npy")
83
- save_path = save_dir / releative_path
84
- if not save_path.parent.exists():
85
- save_path.parent.mkdir(parents=True)
86
-
87
- feat_f = NpyAppendArray(save_path)
88
- feat = reader.get_feats(audio_file)
89
- feat_f.append(feat.cpu().numpy())
90
- logger.info("finished successfully")
91
-
92
- def main(audio_dir, save_dir, ckpt_path, layer, max_chunk):
93
- reader = HubertFeatureReader(ckpt_path, layer, max_chunk)
94
- dump_feature(reader, audio_dir, save_dir)
95
-
96
-
97
- if __name__ == "__main__":
98
- import argparse
99
-
100
- parser = argparse.ArgumentParser()
101
- parser.add_argument("audio_dir", nargs="?", default="datasets/ASVSpoof2019", help="Directory containing audio files")
102
- parser.add_argument("save_dir", nargs="?", default="datasets/ASVSpoof2019_Hubert_L9", help="Directory to save extracted features")
103
- parser.add_argument("ckpt_path", nargs="?", default="../model_zoos/hubert_base_ls960.pt", help="Path to the checkpoint file")
104
- parser.add_argument("layer", nargs="?", type=int, default=9, help="Layer number to extract features from")
105
- parser.add_argument("--max_chunk", type=int, default=1600000, help="Maximum chunk size for processing")
106
- args = parser.parse_args()
107
- logger.info(args)
108
-
109
- main(**vars(args))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
audio/safeear/safeear_repo/datas/feature_utils.py DELETED
@@ -1,65 +0,0 @@
1
- # Copyright (c) Facebook, Inc. and its affiliates.
2
- #
3
- # This source code is licensed under the MIT license found in the
4
- # LICENSE file in the root directory of this source tree.
5
-
6
- import logging
7
- import os
8
- import sys
9
-
10
- import tqdm
11
- from npy_append_array import NpyAppendArray
12
-
13
- logging.basicConfig(
14
- format="%(asctime)s | %(levelname)s | %(name)s | %(message)s",
15
- datefmt="%Y-%m-%d %H:%M:%S",
16
- level=os.environ.get("LOGLEVEL", "INFO").upper(),
17
- stream=sys.stdout,
18
- )
19
- logger = logging.getLogger("feature_utils")
20
-
21
-
22
- def get_shard_range(tot, nshard, rank):
23
- assert rank < nshard and rank >= 0, f"invaid rank/nshard {rank}/{nshard}"
24
- start = round(tot / nshard * rank)
25
- end = round(tot / nshard * (rank + 1))
26
- assert start < end, f"start={start}, end={end}"
27
- logger.info(
28
- f"rank {rank} of {nshard}, process {end-start} "
29
- f"({start}-{end}) out of {tot}"
30
- )
31
- return start, end
32
-
33
-
34
- def get_path_iterator(tsv, nshard, rank):
35
- with open(tsv, "r") as f:
36
- root = f.readline().rstrip()
37
- lines = [line.rstrip() for line in f]
38
- start, end = get_shard_range(len(lines), nshard, rank)
39
- lines = lines[start:end]
40
- def iterate():
41
- for line in lines:
42
- subpath, nsample = line.split("\t")
43
- yield f"{root}/{subpath}", int(nsample)
44
- return iterate, len(lines)
45
-
46
-
47
- def dump_feature(reader, generator, num, split, nshard, rank, feat_dir):
48
- iterator = generator()
49
-
50
- feat_path = f"{feat_dir}/{split}_{rank}_{nshard}.npy"
51
- leng_path = f"{feat_dir}/{split}_{rank}_{nshard}.len"
52
-
53
- os.makedirs(feat_dir, exist_ok=True)
54
- if os.path.exists(feat_path):
55
- os.remove(feat_path)
56
-
57
- feat_f = NpyAppendArray(feat_path)
58
- with open(leng_path, "w") as leng_f:
59
- for path, nsample in tqdm.tqdm(iterator, total=num):
60
- feat = reader.get_feats(path, nsample)
61
- feat_f.append(feat.cpu().numpy())
62
- leng_f.write(f"{len(feat)}\n")
63
- logger.info("finished successfully")
64
-
65
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
audio/safeear/safeear_repo/fairseq_ours/.circleci/config.yml DELETED
@@ -1,171 +0,0 @@
1
- # Use 2.1 for orbs
2
- version: 2.1
3
-
4
- # -------------------------------------------------------------------------------------
5
- # Environments to run the jobs in
6
- # -------------------------------------------------------------------------------------
7
- gpu: &gpu
8
- environment:
9
- CUDA_VERSION: "11.2"
10
- machine:
11
- image: ubuntu-2004-cuda-11.2:202103-01
12
- resource_class: gpu.nvidia.medium.multi
13
-
14
-
15
- # -------------------------------------------------------------------------------------
16
- # Re-usable commands
17
- # -------------------------------------------------------------------------------------
18
- cache_key: &cache_key cache-key-{{ .Environment.CIRCLE_JOB }}-{{ checksum ".circleci/config.yml" }}-{{ checksum "setup.py"}}
19
-
20
- install_dep_common: &install_dep_common
21
- - run:
22
- name: Install Common Dependencies
23
- command: |
24
- source activate fairseq
25
- pip install --upgrade setuptools
26
- pip install bitarray boto3 deepspeed editdistance fastBPE iopath ipdb ipython pyarrow pytest sacremoses sentencepiece subword-nmt hydra-core==1.0.7 omegaconf==2.0.6
27
- pip install --progress-bar off pytest
28
- pip install --progress-bar off fairscale
29
- pip install -i https://test.pypi.org/simple/ bitsandbytes-cuda111 -U
30
- python -c 'import torch; print("Torch version:", torch.__version__)'
31
- python -m torch.utils.collect_env
32
-
33
- install_dep_fused_ops: &install_dep_fused_ops
34
- - run:
35
- name: Install Megatron/Apex Dependencies
36
- working_directory: ~/
37
- command: |
38
- source activate fairseq
39
- git clone https://github.com/NVIDIA/apex
40
- cd apex
41
- git checkout e2083df5eb96643c61613b9df48dd4eea6b07690
42
- sed -i '101,107 s/^/#/' setup.py
43
- pip install -v --no-cache-dir --global-option="--cpp_ext" --global-option="--cuda_ext" --global-option="--deprecated_fused_adam" --global-option="--xentropy" --global-option="--fast_multihead_attn" ./
44
- cd ~/
45
- git clone --depth=1 --branch v2.4 https://github.com/NVIDIA/Megatron-LM.git
46
- cd Megatron-LM
47
- pip install -e .
48
-
49
- install_dep_xformers: &install_dep_xformers
50
- - run:
51
- name: Install xFormers Dependencies
52
- working_directory: ~/
53
- command: |
54
- source activate fairseq
55
- git clone https://github.com/facebookresearch/xformers.git
56
- cd xformers
57
- pip install -r requirements.txt
58
- pip install -e .
59
-
60
- install_dep_pt19: &install_dep_pt19
61
- - run:
62
- name: Install Pytorch Dependencies
63
- command: |
64
- source activate fairseq
65
- pip install --upgrade setuptools
66
- pip install torch==1.9.1+cu111 torchvision==0.10.1+cu111 torchaudio==0.9.1 -f https://download.pytorch.org/whl/torch_stable.html
67
- python -c 'import torch; print("Torch version:", torch.__version__)'
68
-
69
- install_dep_pt18: &install_dep_pt18
70
- - run:
71
- name: Install Pytorch Dependencies
72
- command: |
73
- source activate fairseq
74
- pip install --upgrade setuptools
75
- pip install torch==1.8.1+cu111 torchvision==0.9.1+cu111 torchaudio==0.8.1 -f https://download.pytorch.org/whl/torch_stable.html
76
- python -c 'import torch; print("Torch version:", torch.__version__)'
77
-
78
- install_repo: &install_repo
79
- - run:
80
- name: Install Repository
81
- command: |
82
- source activate fairseq
83
- pip install .
84
- python setup.py build_ext --inplace
85
-
86
- run_unittests: &run_unittests
87
- - run:
88
- name: Run Unit Tests
89
- command: |
90
- source activate fairseq
91
- pytest tests/gpu/test_binaries_gpu.py
92
-
93
- check_nvidia_driver: &check_nvidia_driver
94
- - run:
95
- name: Check NVIDIA Driver
96
- working_directory: ~/
97
- command: |
98
- pyenv versions
99
- nvidia-smi
100
-
101
- create_conda_env: &create_conda_env
102
- - run:
103
- name: Install and Create Conda Environment
104
- command: |
105
- curl -o ~/miniconda.sh -O https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
106
- chmod +x ~/miniconda.sh
107
- ~/miniconda.sh -b -p $HOME/miniconda
108
- rm ~/miniconda.sh
109
- echo 'export PATH=$HOME/miniconda/bin:$PATH' >> $BASH_ENV
110
- source $BASH_ENV
111
- if [ ! -d ~/miniconda/envs/fairseq ]
112
- then
113
- conda create -y -n fairseq python=3.8
114
- fi
115
- source activate fairseq
116
- python --version
117
- pip install --upgrade pip
118
- # -------------------------------------------------------------------------------------
119
- # Jobs to run
120
- # -------------------------------------------------------------------------------------
121
-
122
- jobs:
123
-
124
- gpu_tests_pt19:
125
- <<: *gpu
126
-
127
- working_directory: ~/fairseq-py
128
-
129
- steps:
130
- - checkout
131
- - <<: *check_nvidia_driver
132
- - <<: *create_conda_env
133
- - restore_cache:
134
- key: *cache_key
135
- - <<: *install_dep_pt19
136
- - <<: *install_dep_common
137
- - <<: *install_dep_fused_ops
138
- - save_cache:
139
- paths:
140
- - ~/miniconda/
141
- key: *cache_key
142
- - <<: *install_repo
143
- - <<: *run_unittests
144
-
145
- gpu_tests_pt18:
146
- <<: *gpu
147
-
148
- working_directory: ~/fairseq-py
149
-
150
- steps:
151
- - checkout
152
- - <<: *check_nvidia_driver
153
- - <<: *create_conda_env
154
- - restore_cache:
155
- key: *cache_key
156
- - <<: *install_dep_pt18
157
- - <<: *install_dep_common
158
- - <<: *install_dep_fused_ops
159
- - save_cache:
160
- paths:
161
- - ~/miniconda/
162
- key: *cache_key
163
- - <<: *install_repo
164
- - <<: *run_unittests
165
-
166
- workflows:
167
- version: 2
168
- build:
169
- jobs:
170
- - gpu_tests_pt18
171
- - gpu_tests_pt19
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
audio/safeear/safeear_repo/fairseq_ours/.github/CODEOWNERS DELETED
@@ -1,18 +0,0 @@
1
- # Setting up CODEOWNERS for UST related codebase
2
- # Documentation for open sourced models relevant to UST
3
- examples/speech_to_text @kahne @sravyapopuri388 @jmp84
4
- examples/speech_to_speech @an918tw @sravyapopuri388 @jmp84
5
- examples/speech_synthesis @kahne @jmp84
6
- examples/simultaneous_translation @kahne @jmp84
7
- examples/speech_text_joint_to_text @yuntang @jmp84
8
-
9
- # Speech related models relevant to UST
10
- fairseq/models/speech_to_speech @sravyapopuri388 @jmp84
11
- fairseq/models/speech_to_text @kahne @sravyapopuri388 @jmp84
12
- fairseq/models/text_to_speech @kahne @jmp84
13
-
14
- # CONFORMER IMPLEMENTATION
15
- fairseq/modules/conformer_layer.py @sravyapopuri388 @jmp84
16
- fairseq/modules/espnet_multihead_attention.py @sravyapopuri388 @jmp84
17
- fairseq/modules/rotary_positional_embedding.py @sravyapopuri388 @jmp84
18
- fairseq/modules/positional_encoding.py @sravyapopuri388 @jmp84
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
audio/safeear/safeear_repo/fairseq_ours/.github/ISSUE_TEMPLATE.md DELETED
@@ -1,3 +0,0 @@
1
- ## ๐Ÿ‘‰ [Please follow one of these issue templates](https://github.com/pytorch/fairseq/issues/new/choose) ๐Ÿ‘ˆ
2
-
3
- Note: to keep the backlog clean and actionable, issues may be immediately closed if they do not follow one of the above issue templates.
 
 
 
 
audio/safeear/safeear_repo/fairseq_ours/.github/ISSUE_TEMPLATE/bug_report.md DELETED
@@ -1,43 +0,0 @@
1
- ---
2
- name: ๐Ÿ› Bug Report
3
- about: Submit a bug report to help us improve
4
- labels: 'bug, needs triage'
5
- ---
6
-
7
- ## ๐Ÿ› Bug
8
-
9
- <!-- A clear and concise description of what the bug is. -->
10
-
11
- ### To Reproduce
12
-
13
- Steps to reproduce the behavior (**always include the command you ran**):
14
-
15
- 1. Run cmd '....'
16
- 2. See error
17
-
18
- <!-- If you have a code sample, error messages, stack traces, please provide it here as well -->
19
-
20
-
21
- #### Code sample
22
- <!-- Ideally attach a minimal code sample to reproduce the decried issue.
23
- Minimal means having the shortest code but still preserving the bug. -->
24
-
25
- ### Expected behavior
26
-
27
- <!-- A clear and concise description of what you expected to happen. -->
28
-
29
- ### Environment
30
-
31
- - fairseq Version (e.g., 1.0 or main):
32
- - PyTorch Version (e.g., 1.0)
33
- - OS (e.g., Linux):
34
- - How you installed fairseq (`pip`, source):
35
- - Build command you used (if compiling from source):
36
- - Python version:
37
- - CUDA/cuDNN version:
38
- - GPU models and configuration:
39
- - Any other relevant information:
40
-
41
- ### Additional context
42
-
43
- <!-- Add any other context about the problem here. -->