deepsafe commited on
Commit
e16e208
Β·
verified Β·
1 Parent(s): 505afd3

feat: GPU enablement -- 3-tier CUDA Dockerfiles, TF32, health reporting (2026-04-02)

Browse files
audio/aasist3/Dockerfile CHANGED
@@ -1,32 +1,34 @@
1
- FROM python:3.10-slim
2
 
3
- # Install system dependencies (no git/build-essential needed)
4
- RUN apt-get update && apt-get install -y \
5
- ffmpeg \
6
- libsndfile1 \
 
 
7
  && rm -rf /var/lib/apt/lists/*
8
 
 
 
9
  WORKDIR /app
10
 
11
- # Install Python dependencies
 
 
 
 
12
  COPY requirements.txt .
13
  RUN pip install --no-cache-dir -r requirements.txt
14
 
15
- # Pre-cache wav2vec2 config (not weights, just the config JSON ~1KB)
16
  RUN python -c "from transformers import Wav2Vec2Config; Wav2Vec2Config.from_pretrained('facebook/wav2vec2-large-xlsr-53', cache_dir='/app/w2v_cache')"
17
 
18
- # Copy model code and API
19
  COPY model/ /app/model/
20
  COPY api.py .
21
-
22
- # Expected weight files in /app/weights/:
23
- # - model.safetensors (AASIST3 checkpoint)
24
- # - config.json (model configuration)
25
- # These are mounted from the host via docker-compose volumes.
26
 
27
  EXPOSE 8005
28
 
29
- # Drop root privileges
30
  RUN adduser --disabled-password --gecos '' appuser
31
  USER appuser
32
 
 
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
 
audio/aasist3/api.py CHANGED
@@ -75,6 +75,23 @@ def _get_device():
75
 
76
 
77
  DEVICE = _get_device()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
  SAMPLE_RATE = 16000
79
  TARGET_SAMPLES = 64600 # ~4.04 seconds at 16kHz
80
 
@@ -151,6 +168,19 @@ async def startup_event():
151
  load_model()
152
 
153
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
  @app.get("/health")
155
  async def health():
156
  """Health check endpoint."""
@@ -160,6 +190,7 @@ async def health():
160
  "model_id": MODEL_ID,
161
  "device": str(DEVICE),
162
  "weights_found": os.path.exists(os.path.join(WEIGHTS_DIR, "model.safetensors")),
 
163
  }
164
 
165
 
 
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_mem / 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
 
 
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_mem / 1024**2
179
+ ),
180
+ }
181
+ return {}
182
+
183
+
184
  @app.get("/health")
185
  async def health():
186
  """Health check endpoint."""
 
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
 
audio/aasist3/requirements.txt CHANGED
@@ -1,5 +1,5 @@
1
- torch==2.5.0
2
- torchaudio==2.5.0
3
  transformers>=4.40.0
4
  huggingface-hub>=0.20.0
5
  safetensors>=0.4.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
audio/nes2net/Dockerfile CHANGED
@@ -1,44 +1,40 @@
1
- FROM python:3.10-slim
2
-
3
- # Install system dependencies
4
- RUN apt-get update && apt-get install -y \
5
- git \
6
- ffmpeg \
7
- libsndfile1 \
8
- wget \
9
- build-essential \
10
- g++ \
11
  && rm -rf /var/lib/apt/lists/*
12
 
 
 
13
  WORKDIR /app
14
 
15
- # Install Python dependencies
 
 
 
 
16
  COPY requirements.txt .
17
  RUN pip install --no-cache-dir -r requirements.txt
18
 
19
- # Clone fairseq at the specific commit required by Nes2Net,
20
- # then patch setup.py to skip C extensions (not needed for
21
- # checkpoint_utils), and install as editable without deps.
22
  RUN git clone https://github.com/facebookresearch/fairseq.git /app/fairseq_repo && \
23
  cd /app/fairseq_repo && \
24
  git checkout a54021305d6b3c4c5959ac9395135f63202db8f1 && \
25
  sed -i 's/ext_modules=extensions/ext_modules=[]/' setup.py && \
26
  pip install --no-cache-dir --no-deps -e .
27
 
28
- # Copy model scripts
29
  COPY model_scripts /app/model_scripts
30
-
31
- # Copy API code
32
  COPY api.py .
33
-
34
- # Model weights are mounted from the host via docker-compose volumes.
35
- # Expected weight files in /app/weights/:
36
- # - nes2net_itw_valaug.pt (fine-tuned Nes2Net checkpoint)
37
- # - xlsr2_300m.pt (XLSR wav2vec 2.0 for architecture init)
38
 
39
  EXPOSE 8004
40
 
41
- # Drop root privileges
42
  RUN adduser --disabled-password --gecos '' appuser
43
  USER appuser
44
 
 
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
 
audio/nes2net/api.py CHANGED
@@ -88,6 +88,23 @@ def _get_device():
88
 
89
 
90
  DEVICE = _get_device()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  SAMPLE_RATE = 16000
92
  TARGET_SAMPLES = 64600 # ~4.04 seconds at 16kHz
93
 
@@ -174,6 +191,19 @@ async def startup_event():
174
  load_model()
175
 
176
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
  @app.get("/health")
178
  async def health():
179
  """Health check endpoint."""
@@ -183,6 +213,7 @@ async def health():
183
  "model_id": MODEL_ID,
184
  "device": str(DEVICE),
185
  "weights_found": os.path.exists(WEIGHTS_PATH),
 
186
  }
187
 
188
 
 
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_mem / 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
 
 
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_mem / 1024**2
202
+ ),
203
+ }
204
+ return {}
205
+
206
+
207
  @app.get("/health")
208
  async def health():
209
  """Health check endpoint."""
 
213
  "model_id": MODEL_ID,
214
  "device": str(DEVICE),
215
  "weights_found": os.path.exists(WEIGHTS_PATH),
216
+ **_gpu_health_info(),
217
  }
218
 
219
 
audio/nes2net/requirements.txt CHANGED
@@ -1,5 +1,5 @@
1
- torch==2.5.0
2
- torchaudio==2.5.0
3
  numpy==1.23.5
4
  librosa==0.9.1
5
  soundfile
 
1
+ torch==2.5.1
2
+ torchaudio==2.5.1
3
  numpy==1.23.5
4
  librosa==0.9.1
5
  soundfile
audio/safeear/Dockerfile CHANGED
@@ -1,24 +1,35 @@
1
- FROM python:3.9-slim
2
 
3
- RUN apt-get update && apt-get install -y \
4
- git \
5
- ffmpeg \
6
- libsndfile1 \
7
- wget \
 
8
  build-essential \
9
  && rm -rf /var/lib/apt/lists/*
10
 
 
 
11
  WORKDIR /app
12
 
 
 
 
 
 
13
  COPY requirements.txt .
14
  RUN pip install --no-cache-dir -r requirements.txt
15
 
16
  # Clone SafeEar repository (for model code imports)
17
  RUN git clone --depth 1 https://github.com/LetterLiGo/SafeEar.git /app/safeear_repo
18
 
19
- # Install the fairseq fork required by SafeEar's SpeechTokenizer
 
 
20
  WORKDIR /app/safeear_repo/fairseq_ours
21
- RUN pip install --no-cache-dir -e .
 
22
  WORKDIR /app
23
 
24
  # Download model weights from HuggingFace
@@ -32,7 +43,6 @@ COPY api.py .
32
 
33
  EXPOSE 8002
34
 
35
- # Drop root privileges
36
  RUN adduser --disabled-password --gecos '' appuser
37
  USER appuser
38
 
 
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
 
43
 
44
  EXPOSE 8002
45
 
 
46
  RUN adduser --disabled-password --gecos '' appuser
47
  USER appuser
48
 
audio/safeear/api.py CHANGED
@@ -72,6 +72,23 @@ WEIGHTS_DIR = os.environ.get(
72
  os.path.join(os.path.dirname(__file__), "weights"),
73
  )
74
  DEVICE = _get_device()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  SAMPLE_RATE = 16000
76
  MAX_AUDIO_LENGTH = 64600 # ~4 seconds at 16kHz (ASVspoof standard)
77
  SOFTMAX_TEMPERATURE = 5.0 # Calibration temperature for out-of-distribution data
@@ -210,6 +227,19 @@ async def startup_event():
210
  load_models()
211
 
212
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213
  @app.get("/health")
214
  async def health():
215
  """Return service health status and model availability."""
@@ -222,6 +252,7 @@ async def health():
222
  os.path.exists(os.path.join(WEIGHTS_DIR, "SpeechTokenizer.pt"))
223
  and os.path.exists(os.path.join(WEIGHTS_DIR, "model.ckpt"))
224
  ),
 
225
  }
226
 
227
 
 
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_mem / 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
 
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_mem / 1024**2
238
+ ),
239
+ }
240
+ return {}
241
+
242
+
243
  @app.get("/health")
244
  async def health():
245
  """Return service health status and model availability."""
 
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
 
audio/safeear/requirements.txt CHANGED
@@ -1,5 +1,5 @@
1
- torch>=1.13.0
2
- torchaudio>=0.13.0
3
  librosa>=0.10.0
4
  soundfile>=0.11.0
5
  numpy>=1.23.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
audio/shiftyspeech/Dockerfile CHANGED
@@ -1,52 +1,42 @@
1
- FROM python:3.10-slim
2
-
3
- # Install system dependencies
4
- RUN apt-get update && apt-get install -y \
5
- git \
6
- ffmpeg \
7
- libsndfile1 \
8
- wget \
9
- build-essential \
10
- g++ \
11
  && rm -rf /var/lib/apt/lists/*
12
 
 
 
13
  WORKDIR /app
14
 
15
- # Install Python dependencies
 
 
 
 
16
  COPY requirements.txt .
17
  RUN pip install --no-cache-dir -r requirements.txt
18
 
19
- # Clone fairseq at the specific commit required by ShiftySpeech,
20
- # then patch setup.py to skip C extensions (not needed for
21
- # checkpoint_utils), and install as editable without deps.
22
  RUN git clone https://github.com/facebookresearch/fairseq.git /app/fairseq_repo && \
23
  cd /app/fairseq_repo && \
24
  git checkout a54021305d6b3c4c5959ac9395135f63202db8f1 && \
25
  sed -i 's/ext_modules=extensions/ext_modules=[]/' setup.py && \
26
  pip install --no-cache-dir --no-deps -e .
27
 
28
- # Copy model code from the ShiftySpeech repo
29
  COPY synthetic_speech_detection /app/synthetic_speech_detection
30
-
31
- # Create models directory and symlink XLSR weights
32
- # (fairseq needs the checkpoint for architecture initialization;
33
- # the fine-tuned weights replace all parameters via load_state_dict)
34
  RUN mkdir -p /app/models
35
-
36
- # Copy API code
37
  COPY api.py .
38
-
39
- # Download weights at build time (or mount them as a volume)
40
- # Expected weight files in /app/weights/:
41
- # - hfg_aug_1_2.pt (augmented SSL-AASIST checkpoint, ~1.27GB)
42
- # - xlsr_53_56k.pt (XLSR wav2vec 2.0 for architecture init, ~3.5GB)
43
- # These are mounted from the host via docker-compose volumes.
44
- # Create symlink from models/xlsr2_300m.pt to the actual XLSR file.
45
  RUN ln -sf /app/weights/xlsr_53_56k.pt /app/models/xlsr2_300m.pt
46
 
47
  EXPOSE 8001
48
 
49
- # Drop root privileges
50
  RUN adduser --disabled-password --gecos '' appuser
51
  USER appuser
52
 
 
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 \
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
 
 
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 synthetic_speech_detection /app/synthetic_speech_detection
 
 
 
 
32
  RUN mkdir -p /app/models
 
 
33
  COPY api.py .
34
+ RUN mkdir -p /app/weights
35
+ COPY weights/ /app/weights/
 
 
 
 
 
36
  RUN ln -sf /app/weights/xlsr_53_56k.pt /app/models/xlsr2_300m.pt
37
 
38
  EXPOSE 8001
39
 
 
40
  RUN adduser --disabled-password --gecos '' appuser
41
  USER appuser
42
 
audio/shiftyspeech/api.py CHANGED
@@ -88,6 +88,23 @@ def _get_device():
88
 
89
 
90
  DEVICE = _get_device()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  SAMPLE_RATE = 16000
92
  TARGET_SAMPLES = 64600 # ~4.04 seconds at 16kHz
93
 
@@ -173,6 +190,19 @@ async def startup_event():
173
  load_model()
174
 
175
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
  @app.get("/health")
177
  async def health():
178
  """Health check endpoint."""
@@ -182,6 +212,7 @@ async def health():
182
  "model_id": MODEL_ID,
183
  "device": str(DEVICE),
184
  "weights_found": os.path.exists(WEIGHTS_PATH),
 
185
  }
186
 
187
 
 
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_mem / 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
 
 
190
  load_model()
191
 
192
 
193
+ def _gpu_health_info() -> dict:
194
+ """Return GPU metrics for the health endpoint."""
195
+ if torch.cuda.is_available() and DEVICE.type == "cuda":
196
+ return {
197
+ "gpu_name": torch.cuda.get_device_name(0),
198
+ "vram_used_mb": round(torch.cuda.memory_allocated(0) / 1024**2),
199
+ "vram_total_mb": round(
200
+ torch.cuda.get_device_properties(0).total_mem / 1024**2
201
+ ),
202
+ }
203
+ return {}
204
+
205
+
206
  @app.get("/health")
207
  async def health():
208
  """Health check endpoint."""
 
212
  "model_id": MODEL_ID,
213
  "device": str(DEVICE),
214
  "weights_found": os.path.exists(WEIGHTS_PATH),
215
+ **_gpu_health_info(),
216
  }
217
 
218
 
audio/shiftyspeech/requirements.txt CHANGED
@@ -1,8 +1,8 @@
1
  fastapi
2
  uvicorn
3
  python-multipart
4
- torch==2.5.0
5
- torchaudio==2.5.0
6
  numpy==1.23.5
7
  scipy
8
  librosa==0.9.1
 
1
  fastapi
2
  uvicorn
3
  python-multipart
4
+ torch==2.5.1
5
+ torchaudio==2.5.1
6
  numpy==1.23.5
7
  scipy
8
  librosa==0.9.1
audio/sonics/Dockerfile CHANGED
@@ -1,31 +1,33 @@
1
- FROM python:3.10-slim
2
-
3
- # Install system dependencies
4
- RUN apt-get update && apt-get install -y \
5
- git \
6
- ffmpeg \
7
- libsndfile1 \
8
- build-essential \
9
- g++ \
10
  && rm -rf /var/lib/apt/lists/*
11
 
 
 
12
  WORKDIR /app
13
 
14
- # Install Python dependencies
 
 
 
 
15
  COPY requirements.txt .
16
  RUN pip install --no-cache-dir -r requirements.txt
17
 
18
- # Copy API code
19
  COPY app.py .
20
 
21
- # Pre-download model weights at build time so startup is fast.
22
- # HFAudioClassifier.from_pretrained will cache in the default
23
- # huggingface_hub cache directory.
24
  RUN python -c "from sonics import HFAudioClassifier; HFAudioClassifier.from_pretrained('awsaf49/sonics-spectttra-alpha-120s')"
25
 
26
  EXPOSE 8003
27
 
28
- # Drop root privileges
29
  RUN adduser --disabled-password --gecos '' appuser
30
  USER appuser
31
 
 
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 \
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
  COPY app.py .
25
 
26
+ # Pre-download model weights
 
 
27
  RUN python -c "from sonics import HFAudioClassifier; HFAudioClassifier.from_pretrained('awsaf49/sonics-spectttra-alpha-120s')"
28
 
29
  EXPOSE 8003
30
 
 
31
  RUN adduser --disabled-password --gecos '' appuser
32
  USER appuser
33
 
audio/sonics/app.py CHANGED
@@ -70,6 +70,22 @@ def _get_device():
70
 
71
  DEVICE = _get_device()
72
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  # Global model instance
74
  model = None
75
 
@@ -142,6 +158,19 @@ async def root():
142
  }
143
 
144
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
  @app.get("/health")
146
  async def health():
147
  """Health check endpoint."""
@@ -149,6 +178,7 @@ async def health():
149
  "status": "healthy" if model is not None else "degraded",
150
  "model": MODEL_NAME,
151
  "device": str(DEVICE),
 
152
  }
153
 
154
 
 
70
 
71
  DEVICE = _get_device()
72
 
73
+ if DEVICE.type == "cuda":
74
+ torch.backends.cudnn.benchmark = True
75
+ torch.set_float32_matmul_precision("high")
76
+
77
+ if DEVICE.type == "cuda":
78
+ logger.info(
79
+ "Device: cuda (%s, %.1f GB VRAM)",
80
+ torch.cuda.get_device_name(0),
81
+ torch.cuda.get_device_properties(0).total_mem / 1024**3,
82
+ )
83
+ else:
84
+ logger.warning(
85
+ "Device: %s (no CUDA available -- check nvidia-container-toolkit)",
86
+ DEVICE,
87
+ )
88
+
89
  # Global model instance
90
  model = None
91
 
 
158
  }
159
 
160
 
161
+ def _gpu_health_info() -> dict:
162
+ """Return GPU metrics for the health endpoint."""
163
+ if torch.cuda.is_available() and DEVICE.type == "cuda":
164
+ return {
165
+ "gpu_name": torch.cuda.get_device_name(0),
166
+ "vram_used_mb": round(torch.cuda.memory_allocated(0) / 1024**2),
167
+ "vram_total_mb": round(
168
+ torch.cuda.get_device_properties(0).total_mem / 1024**2
169
+ ),
170
+ }
171
+ return {}
172
+
173
+
174
  @app.get("/health")
175
  async def health():
176
  """Health check endpoint."""
 
178
  "status": "healthy" if model is not None else "degraded",
179
  "model": MODEL_NAME,
180
  "device": str(DEVICE),
181
+ **_gpu_health_info(),
182
  }
183
 
184
 
image/aide/Dockerfile CHANGED
@@ -1,38 +1,35 @@
1
- FROM python:3.10-slim
 
 
 
2
 
3
  WORKDIR /app
4
 
5
  RUN apt-get update && \
6
- apt-get install -y git wget build-essential && \
7
- apt-get clean && \
 
8
  rm -rf /var/lib/apt/lists/*
9
 
10
- COPY requirements.txt .
11
 
12
  RUN pip install --no-cache-dir --upgrade pip "setuptools>=68" wheel
13
 
14
- # Install PyTorch β€” CPU-only build.
15
- # On arm64 (Apple Silicon / AWS Graviton) the default PyPI wheel is CPU-only.
16
- # On x86_64 we force the CPU wheel via the PyTorch index.
17
- RUN arch=$(uname -m) && \
18
- if [ "$arch" = "aarch64" ] || [ "$arch" = "arm64" ]; then \
19
- pip install --no-cache-dir torch==2.0.1 torchvision==0.15.2; \
20
- else \
21
- pip install --no-cache-dir \
22
- torch==2.0.1+cpu torchvision==0.15.2+cpu \
23
- --index-url https://download.pytorch.org/whl/cpu; \
24
- fi
25
 
 
26
  RUN pip install --no-cache-dir -r requirements.txt
27
 
28
- # Clone AIDE repo for model code and DCT module
29
  RUN git clone https://github.com/shilinyan99/AIDE.git model_code && \
30
  touch model_code/__init__.py && \
31
  touch model_code/models/__init__.py && \
32
  touch model_code/data/__init__.py
33
 
34
- # Weights and HF cache are provided via volume mounts at runtime
35
  RUN mkdir -p /app/weights /app/hf_cache
 
36
 
37
  COPY app.py .
38
 
@@ -44,7 +41,6 @@ ENV PYTHONPATH=/app/model_code:$PYTHONPATH
44
 
45
  EXPOSE ${MODEL_PORT}
46
 
47
- # Drop root privileges
48
  RUN adduser --disabled-password --gecos '' appuser
49
  USER appuser
50
 
 
1
+ FROM nvidia/cuda:12.1.1-cudnn8-runtime-ubuntu22.04
2
+
3
+ ENV DEBIAN_FRONTEND=noninteractive
4
+ ENV PYTHONUNBUFFERED=1
5
 
6
  WORKDIR /app
7
 
8
  RUN apt-get update && \
9
+ apt-get install -y --no-install-recommends \
10
+ python3 python3-pip python3-dev \
11
+ git wget build-essential && \
12
  rm -rf /var/lib/apt/lists/*
13
 
14
+ RUN ln -sf /usr/bin/python3 /usr/bin/python
15
 
16
  RUN pip install --no-cache-dir --upgrade pip "setuptools>=68" wheel
17
 
18
+ # Install PyTorch with CUDA 12.1 (replaces CPU-only arch-conditional install)
19
+ RUN pip install --no-cache-dir \
20
+ torch==2.5.1 torchvision==0.20.1 \
21
+ --index-url https://download.pytorch.org/whl/cu121
 
 
 
 
 
 
 
22
 
23
+ COPY requirements.txt .
24
  RUN pip install --no-cache-dir -r requirements.txt
25
 
 
26
  RUN git clone https://github.com/shilinyan99/AIDE.git model_code && \
27
  touch model_code/__init__.py && \
28
  touch model_code/models/__init__.py && \
29
  touch model_code/data/__init__.py
30
 
 
31
  RUN mkdir -p /app/weights /app/hf_cache
32
+ COPY weights/ /app/weights/
33
 
34
  COPY app.py .
35
 
 
41
 
42
  EXPOSE ${MODEL_PORT}
43
 
 
44
  RUN adduser --disabled-password --gecos '' appuser
45
  USER appuser
46
 
image/aide/app.py CHANGED
@@ -84,6 +84,20 @@ def _get_device():
84
 
85
 
86
  DEVICE = _get_device()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  PRELOAD_MODEL = os.environ.get("PRELOAD_MODEL", "false").lower() == "true"
88
  MODEL_TIMEOUT = int(os.environ.get("MODEL_TIMEOUT", "600"))
89
 
@@ -300,6 +314,19 @@ async def root():
300
  }
301
 
302
 
 
 
 
 
 
 
 
 
 
 
 
 
 
303
  @app.get("/health")
304
  async def health():
305
  """Health check endpoint."""
@@ -308,6 +335,7 @@ async def health():
308
  "model_name": MODEL_NAME,
309
  "device": str(DEVICE),
310
  "model_loaded": model is not None,
 
311
  }
312
 
313
 
 
84
 
85
 
86
  DEVICE = _get_device()
87
+ if DEVICE.type == "cuda":
88
+ torch.backends.cudnn.benchmark = True
89
+ torch.set_float32_matmul_precision("high")
90
+ if DEVICE.type == "cuda":
91
+ logger.info(
92
+ "Device: cuda (%s, %.1f GB VRAM)",
93
+ torch.cuda.get_device_name(0),
94
+ torch.cuda.get_device_properties(0).total_mem / 1024**3,
95
+ )
96
+ else:
97
+ logger.warning(
98
+ "Device: %s (no CUDA available -- check nvidia-container-toolkit)",
99
+ DEVICE,
100
+ )
101
  PRELOAD_MODEL = os.environ.get("PRELOAD_MODEL", "false").lower() == "true"
102
  MODEL_TIMEOUT = int(os.environ.get("MODEL_TIMEOUT", "600"))
103
 
 
314
  }
315
 
316
 
317
+ def _gpu_health_info() -> dict:
318
+ """Return GPU metrics for the health endpoint."""
319
+ if torch.cuda.is_available() and DEVICE.type == "cuda":
320
+ return {
321
+ "gpu_name": torch.cuda.get_device_name(0),
322
+ "vram_used_mb": round(torch.cuda.memory_allocated(0) / 1024**2),
323
+ "vram_total_mb": round(
324
+ torch.cuda.get_device_properties(0).total_mem / 1024**2
325
+ ),
326
+ }
327
+ return {}
328
+
329
+
330
  @app.get("/health")
331
  async def health():
332
  """Health check endpoint."""
 
335
  "model_name": MODEL_NAME,
336
  "device": str(DEVICE),
337
  "model_loaded": model is not None,
338
+ **_gpu_health_info(),
339
  }
340
 
341
 
image/cospy/Dockerfile CHANGED
@@ -1,26 +1,35 @@
1
- FROM python:3.10-slim
 
 
 
2
 
3
  WORKDIR /app
4
 
5
  RUN apt-get update && \
6
- apt-get install -y --no-install-recommends git build-essential && \
7
- apt-get clean && \
 
8
  rm -rf /var/lib/apt/lists/*
9
 
10
- COPY requirements.txt .
 
 
11
 
12
- RUN pip install --no-cache-dir --upgrade pip "setuptools>=68" wheel && \
13
- pip install --no-cache-dir -r requirements.txt
 
 
 
 
 
14
 
15
- # Clone the CO-SPY repo for model architecture code (detector modules).
16
- # Pinned to a specific commit for reproducibility.
17
  RUN git clone https://github.com/Megum1/CO-SPY.git model_code && \
18
  cd model_code && \
19
  git checkout 9fb781d && \
20
  cd ..
21
 
22
- # Weights and HF cache are provided via volume mounts / downloaded at runtime
23
  RUN mkdir -p /app/weights /app/hf_cache
 
24
 
25
  COPY app.py .
26
 
@@ -33,7 +42,6 @@ ENV PYTHONPATH=/app/model_code:$PYTHONPATH
33
 
34
  EXPOSE ${MODEL_PORT}
35
 
36
- # Drop root privileges -- chown hf_cache so appuser can write downloaded models
37
  RUN adduser --disabled-password --gecos '' appuser && \
38
  chown -R appuser:appuser /app/hf_cache
39
  USER appuser
 
1
+ FROM nvidia/cuda:12.1.1-cudnn8-runtime-ubuntu22.04
2
+
3
+ ENV DEBIAN_FRONTEND=noninteractive
4
+ ENV PYTHONUNBUFFERED=1
5
 
6
  WORKDIR /app
7
 
8
  RUN apt-get update && \
9
+ apt-get install -y --no-install-recommends \
10
+ python3 python3-pip python3-dev \
11
+ git build-essential && \
12
  rm -rf /var/lib/apt/lists/*
13
 
14
+ RUN ln -sf /usr/bin/python3 /usr/bin/python
15
+
16
+ RUN pip install --no-cache-dir --upgrade pip "setuptools>=68" wheel
17
 
18
+ # Install PyTorch with CUDA 12.1
19
+ RUN pip install --no-cache-dir \
20
+ torch==2.5.1 torchvision==0.20.1 \
21
+ --index-url https://download.pytorch.org/whl/cu121
22
+
23
+ COPY requirements.txt .
24
+ RUN pip install --no-cache-dir -r requirements.txt
25
 
 
 
26
  RUN git clone https://github.com/Megum1/CO-SPY.git model_code && \
27
  cd model_code && \
28
  git checkout 9fb781d && \
29
  cd ..
30
 
 
31
  RUN mkdir -p /app/weights /app/hf_cache
32
+ COPY weights/ /app/weights/
33
 
34
  COPY app.py .
35
 
 
42
 
43
  EXPOSE ${MODEL_PORT}
44
 
 
45
  RUN adduser --disabled-password --gecos '' appuser && \
46
  chown -R appuser:appuser /app/hf_cache
47
  USER appuser
image/cospy/app.py CHANGED
@@ -106,6 +106,22 @@ def _get_device():
106
 
107
 
108
  DEVICE = _get_device()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  PRELOAD_MODEL = os.environ.get("PRELOAD_MODEL", "false").lower() == "true"
110
  MODEL_TIMEOUT = int(os.environ.get("MODEL_TIMEOUT", "600"))
111
 
@@ -309,6 +325,19 @@ async def root():
309
  }
310
 
311
 
 
 
 
 
 
 
 
 
 
 
 
 
 
312
  @app.get("/health")
313
  async def health():
314
  """Health check endpoint."""
@@ -317,6 +346,7 @@ async def health():
317
  "model": MODEL_NAME,
318
  "device": str(DEVICE),
319
  "model_loaded": model is not None,
 
320
  }
321
 
322
 
 
106
 
107
 
108
  DEVICE = _get_device()
109
+ if DEVICE.type == "cuda":
110
+ torch.backends.cudnn.benchmark = True
111
+ torch.set_float32_matmul_precision("high")
112
+
113
+ if DEVICE.type == "cuda":
114
+ logger.info(
115
+ "Device: cuda (%s, %.1f GB VRAM)",
116
+ torch.cuda.get_device_name(0),
117
+ torch.cuda.get_device_properties(0).total_mem / 1024**3,
118
+ )
119
+ else:
120
+ logger.warning(
121
+ "Device: %s (no CUDA available -- check nvidia-container-toolkit)",
122
+ DEVICE,
123
+ )
124
+
125
  PRELOAD_MODEL = os.environ.get("PRELOAD_MODEL", "false").lower() == "true"
126
  MODEL_TIMEOUT = int(os.environ.get("MODEL_TIMEOUT", "600"))
127
 
 
325
  }
326
 
327
 
328
+ def _gpu_health_info() -> dict:
329
+ """Return GPU metrics for the health endpoint."""
330
+ if torch.cuda.is_available() and DEVICE.type == "cuda":
331
+ return {
332
+ "gpu_name": torch.cuda.get_device_name(0),
333
+ "vram_used_mb": round(torch.cuda.memory_allocated(0) / 1024**2),
334
+ "vram_total_mb": round(
335
+ torch.cuda.get_device_properties(0).total_mem / 1024**2
336
+ ),
337
+ }
338
+ return {}
339
+
340
+
341
  @app.get("/health")
342
  async def health():
343
  """Health check endpoint."""
 
346
  "model": MODEL_NAME,
347
  "device": str(DEVICE),
348
  "model_loaded": model is not None,
349
+ **_gpu_health_info(),
350
  }
351
 
352
 
image/effort/Dockerfile CHANGED
@@ -1,26 +1,35 @@
1
- FROM python:3.10-slim
 
 
 
2
 
3
  WORKDIR /app
4
 
5
  RUN apt-get update && \
6
- apt-get install -y --no-install-recommends git build-essential && \
7
- apt-get clean && \
 
8
  rm -rf /var/lib/apt/lists/*
9
 
10
- COPY requirements.txt .
 
 
11
 
12
- RUN pip install --no-cache-dir --upgrade pip "setuptools>=68" wheel && \
13
- pip install --no-cache-dir -r requirements.txt
 
 
 
 
 
14
 
15
- # Clone the Effort repo for model architecture code (detector + SVD modules).
16
- # Pinned to a specific commit for reproducibility.
17
  RUN git clone https://github.com/YZY-stack/Effort-AIGI-Detection.git model_code && \
18
  cd model_code && \
19
  git checkout 96f5dea2b534d400cfd7003f053c7e93c8e16461 && \
20
  cd ..
21
 
22
- # Weights and HF cache are provided via volume mounts at runtime
23
  RUN mkdir -p /app/weights /app/hf_cache
 
24
 
25
  COPY app.py .
26
 
@@ -34,7 +43,6 @@ ENV PYTHONPATH=/app/model_code/DeepfakeBench/training:/app/model_code/DeepfakeBe
34
 
35
  EXPOSE ${MODEL_PORT}
36
 
37
- # Drop root privileges β€” ensure appuser owns the HF cache dir
38
  RUN adduser --disabled-password --gecos '' appuser && \
39
  chown -R appuser:appuser /app/hf_cache
40
  USER appuser
 
1
+ FROM nvidia/cuda:12.1.1-cudnn8-runtime-ubuntu22.04
2
+
3
+ ENV DEBIAN_FRONTEND=noninteractive
4
+ ENV PYTHONUNBUFFERED=1
5
 
6
  WORKDIR /app
7
 
8
  RUN apt-get update && \
9
+ apt-get install -y --no-install-recommends \
10
+ python3 python3-pip python3-dev \
11
+ git build-essential && \
12
  rm -rf /var/lib/apt/lists/*
13
 
14
+ RUN ln -sf /usr/bin/python3 /usr/bin/python
15
+
16
+ RUN pip install --no-cache-dir --upgrade pip "setuptools>=68" wheel
17
 
18
+ # Install PyTorch with CUDA 12.1
19
+ RUN pip install --no-cache-dir \
20
+ torch==2.5.1 torchvision==0.20.1 \
21
+ --index-url https://download.pytorch.org/whl/cu121
22
+
23
+ COPY requirements.txt .
24
+ RUN pip install --no-cache-dir -r requirements.txt
25
 
 
 
26
  RUN git clone https://github.com/YZY-stack/Effort-AIGI-Detection.git model_code && \
27
  cd model_code && \
28
  git checkout 96f5dea2b534d400cfd7003f053c7e93c8e16461 && \
29
  cd ..
30
 
 
31
  RUN mkdir -p /app/weights /app/hf_cache
32
+ COPY weights/ /app/weights/
33
 
34
  COPY app.py .
35
 
 
43
 
44
  EXPOSE ${MODEL_PORT}
45
 
 
46
  RUN adduser --disabled-password --gecos '' appuser && \
47
  chown -R appuser:appuser /app/hf_cache
48
  USER appuser
image/effort/app.py CHANGED
@@ -107,6 +107,22 @@ def _get_device():
107
 
108
 
109
  DEVICE = _get_device()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
  PRELOAD_MODEL = os.environ.get("PRELOAD_MODEL", "false").lower() == "true"
111
  MODEL_TIMEOUT = int(os.environ.get("MODEL_TIMEOUT", "600"))
112
 
@@ -359,6 +375,19 @@ async def root():
359
  }
360
 
361
 
 
 
 
 
 
 
 
 
 
 
 
 
 
362
  @app.get("/health")
363
  async def health():
364
  """Health check endpoint."""
@@ -367,6 +396,7 @@ async def health():
367
  "model": MODEL_NAME,
368
  "device": str(DEVICE),
369
  "model_loaded": model is not None,
 
370
  }
371
 
372
 
 
107
 
108
 
109
  DEVICE = _get_device()
110
+ if DEVICE.type == "cuda":
111
+ torch.backends.cudnn.benchmark = True
112
+ torch.set_float32_matmul_precision("high")
113
+
114
+ if DEVICE.type == "cuda":
115
+ logger.info(
116
+ "Device: cuda (%s, %.1f GB VRAM)",
117
+ torch.cuda.get_device_name(0),
118
+ torch.cuda.get_device_properties(0).total_mem / 1024**3,
119
+ )
120
+ else:
121
+ logger.warning(
122
+ "Device: %s (no CUDA available -- check nvidia-container-toolkit)",
123
+ DEVICE,
124
+ )
125
+
126
  PRELOAD_MODEL = os.environ.get("PRELOAD_MODEL", "false").lower() == "true"
127
  MODEL_TIMEOUT = int(os.environ.get("MODEL_TIMEOUT", "600"))
128
 
 
375
  }
376
 
377
 
378
+ def _gpu_health_info() -> dict:
379
+ """Return GPU metrics for the health endpoint."""
380
+ if torch.cuda.is_available() and DEVICE.type == "cuda":
381
+ return {
382
+ "gpu_name": torch.cuda.get_device_name(0),
383
+ "vram_used_mb": round(torch.cuda.memory_allocated(0) / 1024**2),
384
+ "vram_total_mb": round(
385
+ torch.cuda.get_device_properties(0).total_mem / 1024**2
386
+ ),
387
+ }
388
+ return {}
389
+
390
+
391
  @app.get("/health")
392
  async def health():
393
  """Health check endpoint."""
 
396
  "model": MODEL_NAME,
397
  "device": str(DEVICE),
398
  "model_loaded": model is not None,
399
+ **_gpu_health_info(),
400
  }
401
 
402
 
image/fsd/Dockerfile CHANGED
@@ -1,23 +1,29 @@
1
- FROM python:3.12-slim
 
 
 
2
 
3
  WORKDIR /app
4
 
5
  RUN apt-get update && apt-get install -y --no-install-recommends \
 
6
  git wget \
7
- && apt-get clean && rm -rf /var/lib/apt/lists/*
 
 
8
 
9
- RUN pip install --no-cache-dir --upgrade pip setuptools wheel && pip install uv
10
 
11
- # Clone the FSD repo β€” this vendors the source code inside the image layer.
12
- # The code is frozen at the pinned commit; rebuild to pick up upstream changes.
13
  RUN git clone https://github.com/ductai199x/Forensic-Self-Descriptions-CVPR25.git model_code
14
 
15
- # Install CPU-only PyTorch first (must precede FSD install to avoid CUDA variant)
16
- RUN uv pip install --system torch --extra-index-url https://download.pytorch.org/whl/cpu
 
 
17
 
18
- # Install FSD inference dependencies manually, excluding heavy optional deps
19
- # (ray[serve] and gradio are listed in FSD's pyproject.toml but not needed here)
20
- RUN uv pip install --system --no-cache-dir \
21
  "scipy>=1.17.0" \
22
  "pillow>=12.1.0" \
23
  pillow-heif \
@@ -25,16 +31,17 @@ RUN uv pip install --system --no-cache-dir \
25
  tqdm \
26
  "scikit-learn>=1.6.0"
27
 
28
- # Install the FSD package itself without pulling its deps again
29
- RUN uv pip install --system --no-deps -e ./model_code
30
 
31
  # Install service-layer deps
32
  COPY requirements.txt .
33
- RUN uv pip install --system --no-cache-dir -r requirements.txt
34
 
35
  COPY app.py .
36
 
37
  RUN mkdir -p /app/weights
 
38
 
39
  ENV MODEL_PORT=5005
40
  ENV PRELOAD_MODEL=false
@@ -43,7 +50,6 @@ ENV WEIGHTS_DIR=/app/weights
43
 
44
  EXPOSE 5005
45
 
46
- # Drop root privileges
47
  RUN adduser --disabled-password --gecos '' appuser
48
  USER appuser
49
 
 
1
+ FROM nvidia/cuda:12.1.1-cudnn8-runtime-ubuntu22.04
2
+
3
+ ENV DEBIAN_FRONTEND=noninteractive
4
+ ENV PYTHONUNBUFFERED=1
5
 
6
  WORKDIR /app
7
 
8
  RUN apt-get update && apt-get install -y --no-install-recommends \
9
+ python3 python3-pip \
10
  git wget \
11
+ && rm -rf /var/lib/apt/lists/*
12
+
13
+ RUN ln -sf /usr/bin/python3 /usr/bin/python
14
 
15
+ RUN pip install --no-cache-dir --upgrade pip setuptools wheel
16
 
17
+ # Clone the FSD repo
 
18
  RUN git clone https://github.com/ductai199x/Forensic-Self-Descriptions-CVPR25.git model_code
19
 
20
+ # Install PyTorch with CUDA 12.1 (replaces CPU-only install)
21
+ RUN pip install --no-cache-dir \
22
+ torch==2.5.1 \
23
+ --index-url https://download.pytorch.org/whl/cu121
24
 
25
+ # Install FSD inference dependencies manually
26
+ RUN pip install --no-cache-dir \
 
27
  "scipy>=1.17.0" \
28
  "pillow>=12.1.0" \
29
  pillow-heif \
 
31
  tqdm \
32
  "scikit-learn>=1.6.0"
33
 
34
+ # Install FSD package without deps (bypasses upstream torch>=2.10.0 pin)
35
+ RUN pip install --no-deps -e ./model_code
36
 
37
  # Install service-layer deps
38
  COPY requirements.txt .
39
+ RUN pip install --no-cache-dir -r requirements.txt
40
 
41
  COPY app.py .
42
 
43
  RUN mkdir -p /app/weights
44
+ COPY weights/ /app/weights/
45
 
46
  ENV MODEL_PORT=5005
47
  ENV PRELOAD_MODEL=false
 
50
 
51
  EXPOSE 5005
52
 
 
53
  RUN adduser --disabled-password --gecos '' appuser
54
  USER appuser
55
 
image/fsd/app.py CHANGED
@@ -76,6 +76,21 @@ def _get_device():
76
 
77
 
78
  DEVICE = _get_device()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
 
80
  # Z-score conversion constants (see design spec Β§4)
81
  THRESHOLD_Z: float = -2.0 # FSD paper's default fake/real boundary
@@ -233,6 +248,19 @@ async def root():
233
  }
234
 
235
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
  @app.get("/health")
237
  async def health():
238
  """Health check endpoint."""
@@ -241,6 +269,7 @@ async def health():
241
  "model_name": MODEL_NAME,
242
  "device": DEVICE,
243
  "model_loaded": detector is not None,
 
244
  }
245
 
246
 
 
76
 
77
 
78
  DEVICE = _get_device()
79
+ if DEVICE == "cuda":
80
+ torch.backends.cudnn.benchmark = True
81
+ torch.set_float32_matmul_precision("high")
82
+
83
+ if DEVICE == "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_mem / 1024**3,
88
+ )
89
+ else:
90
+ logger.warning(
91
+ "Device: %s (no CUDA available -- check nvidia-container-toolkit)",
92
+ DEVICE,
93
+ )
94
 
95
  # Z-score conversion constants (see design spec Β§4)
96
  THRESHOLD_Z: float = -2.0 # FSD paper's default fake/real boundary
 
248
  }
249
 
250
 
251
+ def _gpu_health_info() -> dict:
252
+ """Return GPU metrics for the health endpoint."""
253
+ if torch.cuda.is_available() and DEVICE == "cuda":
254
+ return {
255
+ "gpu_name": torch.cuda.get_device_name(0),
256
+ "vram_used_mb": round(torch.cuda.memory_allocated(0) / 1024**2),
257
+ "vram_total_mb": round(
258
+ torch.cuda.get_device_properties(0).total_mem / 1024**2
259
+ ),
260
+ }
261
+ return {}
262
+
263
+
264
  @app.get("/health")
265
  async def health():
266
  """Health check endpoint."""
 
269
  "model_name": MODEL_NAME,
270
  "device": DEVICE,
271
  "model_loaded": detector is not None,
272
+ **_gpu_health_info(),
273
  }
274
 
275
 
image/npr/Dockerfile CHANGED
@@ -1,49 +1,40 @@
1
- FROM python:3.9-slim
2
 
3
- WORKDIR /app
 
4
 
5
- # Install git and wget
6
- RUN apt-get update && apt-get install -y --no-install-recommends git wget && apt-get clean && rm -rf /var/lib/apt/lists/*
7
 
8
- # Copy requirements file
9
- COPY requirements.txt .
 
 
10
 
11
- # Upgrade pip and install common build tools
12
- RUN pip install --no-cache-dir --upgrade pip setuptools wheel && pip install uv
13
 
14
- # Install NumPy first - use a common and stable version
15
- RUN uv pip install --system --no-cache-dir numpy==1.23.5
 
 
16
 
17
- # Install PyTorch CPU version (2.0.1 from requirements.txt) and other dependencies
18
- # Ensure torch and torchvision are for CPU
19
- RUN uv pip install --system torch==2.0.1 torchvision==0.15.2 --extra-index-url https://download.pytorch.org/whl/cpu
20
- # Install other dependencies from requirements.txt
21
- # Pip should skip torch/torchvision if already installed with the correct version.
22
- RUN uv pip install --system --no-cache-dir -r requirements.txt
23
 
24
- # Copy application code
25
  COPY app.py .
26
 
27
- # Clone the repository
28
  RUN git clone https://github.com/chuangchuangtan/NPR-DeepfakeDetection.git npr_deepfakedetection
29
 
30
- # Download model weights
31
  RUN mkdir -p npr_deepfakedetection/weights && \
32
  wget -O npr_deepfakedetection/weights/NPR.pth \
33
  https://github.com/chuangchuangtan/NPR-DeepfakeDetection/raw/main/model_epoch_last_3090.pth
34
 
35
- # Set environment variables
36
  ENV MODEL_PORT=5001
37
- ENV USE_GPU=false
38
  ENV PRELOAD_MODEL=false
39
  ENV MODEL_TIMEOUT=600
40
 
41
- # Expose port
42
  EXPOSE 5001
43
 
44
- # Drop root privileges
45
  RUN adduser --disabled-password --gecos '' appuser
46
  USER appuser
47
 
48
- # Run the application
49
- CMD ["python", "app.py"]
 
1
+ FROM nvidia/cuda:12.1.1-cudnn8-runtime-ubuntu22.04
2
 
3
+ ENV DEBIAN_FRONTEND=noninteractive
4
+ ENV PYTHONUNBUFFERED=1
5
 
6
+ WORKDIR /app
 
7
 
8
+ RUN apt-get update && apt-get install -y --no-install-recommends \
9
+ python3 python3-pip \
10
+ git wget \
11
+ && rm -rf /var/lib/apt/lists/*
12
 
13
+ RUN ln -sf /usr/bin/python3 /usr/bin/python
 
14
 
15
+ # Install PyTorch with CUDA 12.1 (replaces CPU-only install)
16
+ RUN pip install --no-cache-dir \
17
+ torch==2.5.1 torchvision==0.20.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
  COPY app.py .
24
 
 
25
  RUN git clone https://github.com/chuangchuangtan/NPR-DeepfakeDetection.git npr_deepfakedetection
26
 
 
27
  RUN mkdir -p npr_deepfakedetection/weights && \
28
  wget -O npr_deepfakedetection/weights/NPR.pth \
29
  https://github.com/chuangchuangtan/NPR-DeepfakeDetection/raw/main/model_epoch_last_3090.pth
30
 
 
31
  ENV MODEL_PORT=5001
 
32
  ENV PRELOAD_MODEL=false
33
  ENV MODEL_TIMEOUT=600
34
 
 
35
  EXPOSE 5001
36
 
 
37
  RUN adduser --disabled-password --gecos '' appuser
38
  USER appuser
39
 
40
+ CMD ["python", "app.py"]
 
image/npr/app.py CHANGED
@@ -76,15 +76,11 @@ MODEL_NAME = "npr_deepfakedetection"
76
  WEIGHTS_FILENAME = "NPR.pth"
77
  MODEL_FULL_PATH = os.path.join(model_code_path, "weights", WEIGHTS_FILENAME)
78
 
79
- USE_GPU_ENV = os.environ.get("USE_GPU", "false").lower() == "true"
80
-
81
 
82
  def _get_device():
83
  """Select optimal device: MPS (Apple) > CUDA (NVIDIA) > CPU."""
84
  import platform
85
 
86
- if not USE_GPU_ENV:
87
- return torch.device("cpu")
88
  override = os.environ.get("DEEPSAFE_DEVICE", "").strip().lower()
89
  if override == "cpu":
90
  return torch.device("cpu")
@@ -110,9 +106,19 @@ def _get_device():
110
 
111
 
112
  DEVICE = _get_device()
113
- if USE_GPU_ENV and DEVICE.type == "cpu":
 
 
 
 
 
 
 
 
 
114
  logger.warning(
115
- "USE_GPU is true but no accelerator is available. Falling back to CPU."
 
116
  )
117
  logger.info(f"Using device: {DEVICE}")
118
 
@@ -298,6 +304,19 @@ async def root_endpoint():
298
  }
299
 
300
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301
  @app.get("/health", tags=["System"])
302
  async def health_check_endpoint():
303
  model_file_exists = os.path.exists(MODEL_FULL_PATH)
@@ -316,6 +335,7 @@ async def health_check_endpoint():
316
  "model_definition_imported": "resnet50" in globals()
317
  and callable(globals()["resnet50"]),
318
  "model_loaded": model is not None,
 
319
  }
320
 
321
 
 
76
  WEIGHTS_FILENAME = "NPR.pth"
77
  MODEL_FULL_PATH = os.path.join(model_code_path, "weights", WEIGHTS_FILENAME)
78
 
 
 
79
 
80
  def _get_device():
81
  """Select optimal device: MPS (Apple) > CUDA (NVIDIA) > CPU."""
82
  import platform
83
 
 
 
84
  override = os.environ.get("DEEPSAFE_DEVICE", "").strip().lower()
85
  if override == "cpu":
86
  return torch.device("cpu")
 
106
 
107
 
108
  DEVICE = _get_device()
109
+ if DEVICE.type == "cuda":
110
+ torch.backends.cudnn.benchmark = True
111
+ torch.set_float32_matmul_precision("high")
112
+ if DEVICE.type == "cuda":
113
+ logger.info(
114
+ "Device: cuda (%s, %.1f GB VRAM)",
115
+ torch.cuda.get_device_name(0),
116
+ torch.cuda.get_device_properties(0).total_mem / 1024**3,
117
+ )
118
+ else:
119
  logger.warning(
120
+ "Device: %s (no CUDA available -- check nvidia-container-toolkit)",
121
+ DEVICE,
122
  )
123
  logger.info(f"Using device: {DEVICE}")
124
 
 
304
  }
305
 
306
 
307
+ def _gpu_health_info() -> dict:
308
+ """Return GPU metrics for the health endpoint."""
309
+ if torch.cuda.is_available() and DEVICE.type == "cuda":
310
+ return {
311
+ "gpu_name": torch.cuda.get_device_name(0),
312
+ "vram_used_mb": round(torch.cuda.memory_allocated(0) / 1024**2),
313
+ "vram_total_mb": round(
314
+ torch.cuda.get_device_properties(0).total_mem / 1024**2
315
+ ),
316
+ }
317
+ return {}
318
+
319
+
320
  @app.get("/health", tags=["System"])
321
  async def health_check_endpoint():
322
  model_file_exists = os.path.exists(MODEL_FULL_PATH)
 
335
  "model_definition_imported": "resnet50" in globals()
336
  and callable(globals()["resnet50"]),
337
  "model_loaded": model is not None,
338
+ **_gpu_health_info(),
339
  }
340
 
341
 
image/npr/requirements.txt CHANGED
@@ -1,8 +1,8 @@
1
  fastapi==0.103.1
2
  uvicorn==0.23.2
3
  pydantic==2.3.0
4
- torch==2.0.1
5
- torchvision==0.15.2
6
  pillow==10.0.1
7
  numpy==1.23.5
8
  scipy
 
1
  fastapi==0.103.1
2
  uvicorn==0.23.2
3
  pydantic==2.3.0
4
+ torch==2.5.1
5
+ torchvision==0.20.1
6
  pillow==10.0.1
7
  numpy==1.23.5
8
  scipy
image/universal/app.py CHANGED
@@ -68,6 +68,20 @@ def _get_device():
68
 
69
  DEVICE = _get_device()
70
  USE_GPU = DEVICE.type != "cpu"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  MODEL_PORT = int(os.environ.get("MODEL_PORT", 5003))
72
  PRELOAD_MODEL = os.environ.get("PRELOAD_MODEL", "false").lower() == "true"
73
  MODEL_TIMEOUT = int(
@@ -331,6 +345,19 @@ def read_root():
331
  }
332
 
333
 
 
 
 
 
 
 
 
 
 
 
 
 
 
334
  # Health check endpoint
335
  @app.get("/health")
336
  def health_check():
@@ -338,7 +365,12 @@ def health_check():
338
  model_file_exists = os.path.exists(weights_path)
339
 
340
  if model is not None:
341
- return {"status": "healthy", "device": str(DEVICE), "model_loaded": True}
 
 
 
 
 
342
  elif model_loading:
343
  return {
344
  "status": "loading",
 
68
 
69
  DEVICE = _get_device()
70
  USE_GPU = DEVICE.type != "cpu"
71
+ if DEVICE.type == "cuda":
72
+ torch.backends.cudnn.benchmark = True
73
+ torch.set_float32_matmul_precision("high")
74
+ if DEVICE.type == "cuda":
75
+ logger.info(
76
+ "Device: cuda (%s, %.1f GB VRAM)",
77
+ torch.cuda.get_device_name(0),
78
+ torch.cuda.get_device_properties(0).total_mem / 1024**3,
79
+ )
80
+ else:
81
+ logger.warning(
82
+ "Device: %s (no CUDA available -- check nvidia-container-toolkit)",
83
+ DEVICE,
84
+ )
85
  MODEL_PORT = int(os.environ.get("MODEL_PORT", 5003))
86
  PRELOAD_MODEL = os.environ.get("PRELOAD_MODEL", "false").lower() == "true"
87
  MODEL_TIMEOUT = int(
 
345
  }
346
 
347
 
348
+ def _gpu_health_info() -> dict:
349
+ """Return GPU metrics for the health endpoint."""
350
+ if torch.cuda.is_available() and DEVICE.type == "cuda":
351
+ return {
352
+ "gpu_name": torch.cuda.get_device_name(0),
353
+ "vram_used_mb": round(torch.cuda.memory_allocated(0) / 1024**2),
354
+ "vram_total_mb": round(
355
+ torch.cuda.get_device_properties(0).total_mem / 1024**2
356
+ ),
357
+ }
358
+ return {}
359
+
360
+
361
  # Health check endpoint
362
  @app.get("/health")
363
  def health_check():
 
365
  model_file_exists = os.path.exists(weights_path)
366
 
367
  if model is not None:
368
+ return {
369
+ "status": "healthy",
370
+ "device": str(DEVICE),
371
+ "model_loaded": True,
372
+ **_gpu_health_info(),
373
+ }
374
  elif model_loading:
375
  return {
376
  "status": "loading",
image/yermandy/Dockerfile CHANGED
@@ -1,42 +1,37 @@
1
- # Use a PyTorch base image
2
- FROM python:3.10-slim
3
 
4
- RUN pip install --no-cache-dir \
5
- torch==2.6.0 torchvision==0.21.0 \
6
- -f https://download.pytorch.org/whl/cpu/torch_stable.html
7
 
8
  WORKDIR /app
9
 
10
- # Install git and wget for cloning repo and downloading weights
11
- RUN apt-get update && \
12
- apt-get install -y git wget && \
13
- apt-get clean && \
14
- rm -rf /var/lib/apt/lists/*
15
 
16
- # Copy requirements file
17
- COPY requirements.txt .
 
 
 
 
18
 
19
- # Install Python dependencies
20
  RUN pip install --no-cache-dir -r requirements.txt
21
 
22
- # Clone the model repository
23
- # We'll name the cloned directory "model_code" to avoid conflicts
24
  RUN git clone https://github.com/yermandy/deepfake-detection.git model_code
25
 
26
- # Download model weights
27
  RUN mkdir -p model_code/weights && \
28
  wget https://huggingface.co/yermandy/deepfake-detection/resolve/main/model.ckpt -O model_code/weights/model.ckpt
29
 
30
- # Set Hugging Face home to cache pre-trained models inside the container
31
  ENV HF_HOME=/app/huggingface_cache
32
  ENV TRANSFORMERS_CACHE=/app/huggingface_cache
33
  ENV HF_HUB_CACHE=/app/huggingface_cache
34
  RUN mkdir -p $HF_HOME
35
 
36
- # Upgrade transformers for safetensors support (HuggingFace removed pytorch_model.bin)
37
  RUN pip install --no-cache-dir --upgrade transformers
38
 
39
- # Pre-download Hugging Face CLIP models to be self-sustaining
40
  RUN python -c "from transformers import CLIPProcessor, CLIPModel; \
41
  CLIPProcessor.from_pretrained('openai/clip-vit-base-patch16'); \
42
  CLIPProcessor.from_pretrained('openai/clip-vit-base-patch32'); \
@@ -44,27 +39,17 @@ RUN python -c "from transformers import CLIPProcessor, CLIPModel; \
44
  CLIPProcessor.from_pretrained('openai/clip-vit-large-patch14-336'); \
45
  CLIPModel.from_pretrained('openai/clip-vit-large-patch14')"
46
 
47
- # Copy the application file
48
  COPY app.py .
49
 
50
- # --- Environment Variables ---
51
- # MODEL_PORT will be set by docker-compose, defaulting here for clarity
52
  ENV MODEL_PORT=5002
53
  ENV MODEL_PATH=model_code/weights/model.ckpt
54
  ENV PRELOAD_MODEL="false"
55
- # MODEL_TIMEOUT: Seconds to keep model loaded if not preloaded
56
  ENV MODEL_TIMEOUT="600"
57
-
58
- # Add the cloned repository's root and src to PYTHONPATH
59
- # This allows app.py to import modules from the cloned model_code directory
60
  ENV PYTHONPATH=/app/model_code:/app/model_code/src:$PYTHONPATH
61
 
62
- # Expose the port the app runs on
63
  EXPOSE ${MODEL_PORT}
64
 
65
- # Drop root privileges
66
  RUN adduser --disabled-password --gecos '' appuser
67
  USER appuser
68
 
69
- # Command to run the application
70
- CMD ["python", "app.py"]
 
1
+ FROM nvidia/cuda:12.1.1-cudnn8-runtime-ubuntu22.04
 
2
 
3
+ ENV DEBIAN_FRONTEND=noninteractive
4
+ ENV PYTHONUNBUFFERED=1
 
5
 
6
  WORKDIR /app
7
 
8
+ RUN apt-get update && apt-get install -y --no-install-recommends \
9
+ python3 python3-pip \
10
+ git wget \
11
+ && rm -rf /var/lib/apt/lists/*
 
12
 
13
+ RUN ln -sf /usr/bin/python3 /usr/bin/python
14
+
15
+ # Install PyTorch with CUDA 12.1 (downgraded from 2.6.0 -- no cu121 wheels for 2.6+)
16
+ RUN pip install --no-cache-dir \
17
+ torch==2.5.1 torchvision==0.20.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 git clone https://github.com/yermandy/deepfake-detection.git model_code
24
 
 
25
  RUN mkdir -p model_code/weights && \
26
  wget https://huggingface.co/yermandy/deepfake-detection/resolve/main/model.ckpt -O model_code/weights/model.ckpt
27
 
 
28
  ENV HF_HOME=/app/huggingface_cache
29
  ENV TRANSFORMERS_CACHE=/app/huggingface_cache
30
  ENV HF_HUB_CACHE=/app/huggingface_cache
31
  RUN mkdir -p $HF_HOME
32
 
 
33
  RUN pip install --no-cache-dir --upgrade transformers
34
 
 
35
  RUN python -c "from transformers import CLIPProcessor, CLIPModel; \
36
  CLIPProcessor.from_pretrained('openai/clip-vit-base-patch16'); \
37
  CLIPProcessor.from_pretrained('openai/clip-vit-base-patch32'); \
 
39
  CLIPProcessor.from_pretrained('openai/clip-vit-large-patch14-336'); \
40
  CLIPModel.from_pretrained('openai/clip-vit-large-patch14')"
41
 
 
42
  COPY app.py .
43
 
 
 
44
  ENV MODEL_PORT=5002
45
  ENV MODEL_PATH=model_code/weights/model.ckpt
46
  ENV PRELOAD_MODEL="false"
 
47
  ENV MODEL_TIMEOUT="600"
 
 
 
48
  ENV PYTHONPATH=/app/model_code:/app/model_code/src:$PYTHONPATH
49
 
 
50
  EXPOSE ${MODEL_PORT}
51
 
 
52
  RUN adduser --disabled-password --gecos '' appuser
53
  USER appuser
54
 
55
+ CMD ["python", "app.py"]
 
image/yermandy/app.py CHANGED
@@ -147,13 +147,23 @@ def _get_device():
147
 
148
 
149
  DEVICE = _get_device()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
150
  PRELOAD_MODEL = os.environ.get("PRELOAD_MODEL", "false").lower() == "true"
151
  MODEL_TIMEOUT = int(os.environ.get("MODEL_TIMEOUT", "600")) # Default 10 minutes
152
 
153
- USE_GPU = (
154
- os.environ.get("USE_GPU", "false").lower() == "true" and torch.cuda.is_available()
155
- )
156
-
157
  # Global variables for the model and related components
158
  model: Optional[DeepfakeDetectionModel] = None
159
  preprocessing_fn: Optional[callable] = None
@@ -309,6 +319,19 @@ async def root():
309
  }
310
 
311
 
 
 
 
 
 
 
 
 
 
 
 
 
 
312
  @app.get("/health")
313
  async def health():
314
  model_file_exists = os.path.exists(MODEL_PATH)
@@ -323,6 +346,7 @@ async def health():
323
  "device": str(DEVICE),
324
  "model_weights_found": model_file_exists,
325
  "model_loaded": model is not None,
 
326
  }
327
 
328
 
 
147
 
148
 
149
  DEVICE = _get_device()
150
+ if DEVICE.type == "cuda":
151
+ torch.backends.cudnn.benchmark = True
152
+ torch.set_float32_matmul_precision("high")
153
+ if DEVICE.type == "cuda":
154
+ logger.info(
155
+ "Device: cuda (%s, %.1f GB VRAM)",
156
+ torch.cuda.get_device_name(0),
157
+ torch.cuda.get_device_properties(0).total_mem / 1024**3,
158
+ )
159
+ else:
160
+ logger.warning(
161
+ "Device: %s (no CUDA available -- check nvidia-container-toolkit)",
162
+ DEVICE,
163
+ )
164
  PRELOAD_MODEL = os.environ.get("PRELOAD_MODEL", "false").lower() == "true"
165
  MODEL_TIMEOUT = int(os.environ.get("MODEL_TIMEOUT", "600")) # Default 10 minutes
166
 
 
 
 
 
167
  # Global variables for the model and related components
168
  model: Optional[DeepfakeDetectionModel] = None
169
  preprocessing_fn: Optional[callable] = None
 
319
  }
320
 
321
 
322
+ def _gpu_health_info() -> dict:
323
+ """Return GPU metrics for the health endpoint."""
324
+ if torch.cuda.is_available() and DEVICE.type == "cuda":
325
+ return {
326
+ "gpu_name": torch.cuda.get_device_name(0),
327
+ "vram_used_mb": round(torch.cuda.memory_allocated(0) / 1024**2),
328
+ "vram_total_mb": round(
329
+ torch.cuda.get_device_properties(0).total_mem / 1024**2
330
+ ),
331
+ }
332
+ return {}
333
+
334
+
335
  @app.get("/health")
336
  async def health():
337
  model_file_exists = os.path.exists(MODEL_PATH)
 
346
  "device": str(DEVICE),
347
  "model_weights_found": model_file_exists,
348
  "model_loaded": model is not None,
349
+ **_gpu_health_info(),
350
  }
351
 
352
 
image/yermandy/requirements.txt CHANGED
@@ -5,9 +5,9 @@ Pillow>=9.0.0
5
  python-multipart
6
  numpy
7
 
8
- torch==2.6.0
9
- torchaudio==2.6.0
10
- torchvision==0.21.0
11
  lightning==2.5.0
12
  transformers==4.50.0
13
  tqdm==4.67.1 # progress bar
 
5
  python-multipart
6
  numpy
7
 
8
+ torch==2.5.1
9
+ torchaudio==2.5.1
10
+ torchvision==0.20.1
11
  lightning==2.5.0
12
  transformers==4.50.0
13
  tqdm==4.67.1 # progress bar
provenance/audioseal/Dockerfile CHANGED
@@ -1,12 +1,23 @@
1
- FROM python:3.10-slim
 
 
 
2
 
3
- # System deps: libsndfile for torchaudio, ffmpeg for format support
4
  RUN apt-get update && \
5
- apt-get install -y --no-install-recommends libsndfile1 ffmpeg && \
 
 
6
  rm -rf /var/lib/apt/lists/*
7
 
 
 
8
  WORKDIR /app
9
 
 
 
 
 
 
10
  COPY requirements.txt .
11
  RUN pip install --no-cache-dir -r requirements.txt
12
 
@@ -15,10 +26,8 @@ COPY app.py .
15
  ENV MODEL_PORT=9003
16
  ENV PRELOAD_MODEL=false
17
  ENV MODEL_TIMEOUT=600
18
- ENV USE_GPU=false
19
  EXPOSE 9003
20
 
21
- # Drop root privileges
22
  RUN adduser --disabled-password --gecos "" appuser
23
  USER appuser
24
 
 
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 && \
7
+ apt-get install -y --no-install-recommends \
8
+ python3 python3-pip \
9
+ libsndfile1 ffmpeg && \
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
 
 
26
  ENV MODEL_PORT=9003
27
  ENV PRELOAD_MODEL=false
28
  ENV MODEL_TIMEOUT=600
 
29
  EXPOSE 9003
30
 
 
31
  RUN adduser --disabled-password --gecos "" appuser
32
  USER appuser
33
 
provenance/audioseal/app.py CHANGED
@@ -73,6 +73,22 @@ def _get_device():
73
 
74
 
75
  DEVICE = _get_device()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  PRELOAD_MODEL = os.environ.get("PRELOAD_MODEL", "false").lower() == "true"
77
  MODEL_TIMEOUT = int(os.environ.get("MODEL_TIMEOUT", "600"))
78
 
@@ -204,6 +220,19 @@ async def root():
204
  }
205
 
206
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
  @app.get("/health")
208
  async def health():
209
  """Health check endpoint."""
@@ -214,6 +243,7 @@ async def health():
214
  "model_name": MODEL_NAME,
215
  "device": str(DEVICE),
216
  "model_loaded": detector is not None,
 
217
  }
218
 
219
 
 
73
 
74
 
75
  DEVICE = _get_device()
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_mem / 1024**3,
85
+ )
86
+ else:
87
+ logger.warning(
88
+ "Device: %s (no CUDA available -- check nvidia-container-toolkit)",
89
+ DEVICE,
90
+ )
91
+
92
  PRELOAD_MODEL = os.environ.get("PRELOAD_MODEL", "false").lower() == "true"
93
  MODEL_TIMEOUT = int(os.environ.get("MODEL_TIMEOUT", "600"))
94
 
 
220
  }
221
 
222
 
223
+ def _gpu_health_info() -> dict:
224
+ """Return GPU metrics for the health endpoint."""
225
+ if torch.cuda.is_available() and DEVICE.type == "cuda":
226
+ return {
227
+ "gpu_name": torch.cuda.get_device_name(0),
228
+ "vram_used_mb": round(torch.cuda.memory_allocated(0) / 1024**2),
229
+ "vram_total_mb": round(
230
+ torch.cuda.get_device_properties(0).total_mem / 1024**2
231
+ ),
232
+ }
233
+ return {}
234
+
235
+
236
  @app.get("/health")
237
  async def health():
238
  """Health check endpoint."""
 
243
  "model_name": MODEL_NAME,
244
  "device": str(DEVICE),
245
  "model_loaded": detector is not None,
246
+ **_gpu_health_info(),
247
  }
248
 
249
 
provenance/videoseal/Dockerfile CHANGED
@@ -1,18 +1,27 @@
1
- FROM python:3.11-slim
 
 
 
2
 
3
  # System deps: OpenCV headless needs libgl, ffmpeg for video decoding,
4
  # build-essential for pycocotools compilation
5
  RUN apt-get update && \
6
  apt-get install -y --no-install-recommends \
 
7
  libgl1 libglib2.0-0 ffmpeg build-essential && \
8
  rm -rf /var/lib/apt/lists/*
9
 
 
 
10
  WORKDIR /app
11
 
 
 
 
 
 
12
  COPY requirements.txt .
13
  # Install videoseal without deps to avoid decord (no ARM64 wheels).
14
- # We use OpenCV for video frame extraction instead.
15
- # Runtime deps are listed explicitly in requirements.txt.
16
  RUN pip install --no-cache-dir -r requirements.txt && \
17
  pip install --no-cache-dir --no-deps videoseal==1.0.1 && \
18
  apt-get purge -y --auto-remove build-essential && \
@@ -24,12 +33,12 @@ COPY configs/ configs/
24
  ENV MODEL_PORT=9004
25
  ENV PRELOAD_MODEL=false
26
  ENV MODEL_TIMEOUT=600
27
- ENV USE_GPU=false
28
  EXPOSE 9004
29
 
30
  # Pre-create cache dirs that videoseal needs (before dropping root)
31
- RUN mkdir -p /app/ckpts /app/.cache && \
32
- adduser --disabled-password --gecos "" appuser && \
 
33
  chown -R appuser:appuser /app/ckpts /app/.cache
34
  USER appuser
35
 
 
1
+ FROM nvidia/cuda:12.1.1-cudnn8-runtime-ubuntu22.04
2
+
3
+ ENV DEBIAN_FRONTEND=noninteractive
4
+ ENV PYTHONUNBUFFERED=1
5
 
6
  # System deps: OpenCV headless needs libgl, ffmpeg for video decoding,
7
  # build-essential for pycocotools compilation
8
  RUN apt-get update && \
9
  apt-get install -y --no-install-recommends \
10
+ python3 python3-pip python3-dev \
11
  libgl1 libglib2.0-0 ffmpeg build-essential && \
12
  rm -rf /var/lib/apt/lists/*
13
 
14
+ RUN ln -sf /usr/bin/python3 /usr/bin/python
15
+
16
  WORKDIR /app
17
 
18
+ # Install PyTorch with CUDA 12.1
19
+ RUN pip install --no-cache-dir \
20
+ torch==2.5.1 torchvision==0.20.1 \
21
+ --index-url https://download.pytorch.org/whl/cu121
22
+
23
  COPY requirements.txt .
24
  # Install videoseal without deps to avoid decord (no ARM64 wheels).
 
 
25
  RUN pip install --no-cache-dir -r requirements.txt && \
26
  pip install --no-cache-dir --no-deps videoseal==1.0.1 && \
27
  apt-get purge -y --auto-remove build-essential && \
 
33
  ENV MODEL_PORT=9004
34
  ENV PRELOAD_MODEL=false
35
  ENV MODEL_TIMEOUT=600
 
36
  EXPOSE 9004
37
 
38
  # Pre-create cache dirs that videoseal needs (before dropping root)
39
+ RUN mkdir -p /app/ckpts /app/.cache
40
+ COPY ckpts/ /app/ckpts/
41
+ RUN adduser --disabled-password --gecos "" appuser && \
42
  chown -R appuser:appuser /app/ckpts /app/.cache
43
  USER appuser
44
 
provenance/videoseal/app.py CHANGED
@@ -78,6 +78,22 @@ def _get_device():
78
 
79
 
80
  DEVICE = _get_device()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
  PRELOAD_MODEL = os.environ.get("PRELOAD_MODEL", "false").lower() == "true"
82
  MODEL_TIMEOUT = int(os.environ.get("MODEL_TIMEOUT", "600"))
83
 
@@ -340,6 +356,19 @@ async def root():
340
  }
341
 
342
 
 
 
 
 
 
 
 
 
 
 
 
 
 
343
  @app.get("/health")
344
  async def health():
345
  """Health check endpoint."""
@@ -350,6 +379,7 @@ async def health():
350
  "model_name": MODEL_NAME,
351
  "device": str(DEVICE),
352
  "model_loaded": model is not None,
 
353
  }
354
 
355
 
 
78
 
79
 
80
  DEVICE = _get_device()
81
+ if DEVICE.type == "cuda":
82
+ torch.backends.cudnn.benchmark = True
83
+ torch.set_float32_matmul_precision("high")
84
+
85
+ if DEVICE.type == "cuda":
86
+ logger.info(
87
+ "Device: cuda (%s, %.1f GB VRAM)",
88
+ torch.cuda.get_device_name(0),
89
+ torch.cuda.get_device_properties(0).total_mem / 1024**3,
90
+ )
91
+ else:
92
+ logger.warning(
93
+ "Device: %s (no CUDA available -- check nvidia-container-toolkit)",
94
+ DEVICE,
95
+ )
96
+
97
  PRELOAD_MODEL = os.environ.get("PRELOAD_MODEL", "false").lower() == "true"
98
  MODEL_TIMEOUT = int(os.environ.get("MODEL_TIMEOUT", "600"))
99
 
 
356
  }
357
 
358
 
359
+ def _gpu_health_info() -> dict:
360
+ """Return GPU metrics for the health endpoint."""
361
+ if torch.cuda.is_available() and DEVICE.type == "cuda":
362
+ return {
363
+ "gpu_name": torch.cuda.get_device_name(0),
364
+ "vram_used_mb": round(torch.cuda.memory_allocated(0) / 1024**2),
365
+ "vram_total_mb": round(
366
+ torch.cuda.get_device_properties(0).total_mem / 1024**2
367
+ ),
368
+ }
369
+ return {}
370
+
371
+
372
  @app.get("/health")
373
  async def health():
374
  """Health check endpoint."""
 
379
  "model_name": MODEL_NAME,
380
  "device": str(DEVICE),
381
  "model_loaded": model is not None,
382
+ **_gpu_health_info(),
383
  }
384
 
385
 
video/fake-stormer/Dockerfile CHANGED
@@ -1,4 +1,4 @@
1
- FROM python:3.9-slim
2
 
3
  WORKDIR /app
4
 
@@ -27,7 +27,6 @@ COPY app.py .
27
 
28
  # Environment variables
29
  ENV MODEL_PORT=7001
30
- ENV USE_GPU=false
31
  ENV PRELOAD_MODEL=false
32
 
33
  # Expose port
 
1
+ FROM pytorch/pytorch:1.8.0-cuda11.1-cudnn8-devel
2
 
3
  WORKDIR /app
4
 
 
27
 
28
  # Environment variables
29
  ENV MODEL_PORT=7001
 
30
  ENV PRELOAD_MODEL=false
31
 
32
  # Expose port
video/fake-stormer/app.py CHANGED
@@ -33,7 +33,6 @@ logging.basicConfig(level=logging.INFO)
33
  logger = logging.getLogger(__name__)
34
 
35
  MODEL_PORT = int(os.environ.get("MODEL_PORT", 7001))
36
- USE_GPU = os.environ.get("USE_GPU", "false").lower() == "true"
37
  PRELOAD_MODEL = os.environ.get("PRELOAD_MODEL", "false").lower() == "true"
38
  CONFIG_PATH = os.environ.get(
39
  "CONFIG_PATH", "model_code/configs/temporal/FakeSFormer_base_c23.yaml"
@@ -46,8 +45,6 @@ WEIGHTS_PATH = os.environ.get(
46
 
47
  def _get_device():
48
  """Select optimal device: MPS (Apple) > CUDA (NVIDIA) > CPU."""
49
- if not USE_GPU:
50
- return torch.device("cpu")
51
  override = os.environ.get("DEEPSAFE_DEVICE", "").strip().lower()
52
  if override == "cpu":
53
  return torch.device("cpu")
@@ -87,6 +84,23 @@ def _load_models():
87
  return
88
 
89
  _device = _get_device()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  logger.info(f"Loading FakeSTormer model on {_device}...")
91
 
92
  try:
@@ -160,12 +174,27 @@ def root():
160
  }
161
 
162
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
  @app.get("/health")
164
  def health():
165
  return {
166
  "status": "ok",
167
  "model_loaded": _is_model_loaded(),
168
  "weights_exist": os.path.exists(WEIGHTS_PATH),
 
 
169
  }
170
 
171
 
 
33
  logger = logging.getLogger(__name__)
34
 
35
  MODEL_PORT = int(os.environ.get("MODEL_PORT", 7001))
 
36
  PRELOAD_MODEL = os.environ.get("PRELOAD_MODEL", "false").lower() == "true"
37
  CONFIG_PATH = os.environ.get(
38
  "CONFIG_PATH", "model_code/configs/temporal/FakeSFormer_base_c23.yaml"
 
45
 
46
  def _get_device():
47
  """Select optimal device: MPS (Apple) > CUDA (NVIDIA) > CPU."""
 
 
48
  override = os.environ.get("DEEPSAFE_DEVICE", "").strip().lower()
49
  if override == "cpu":
50
  return torch.device("cpu")
 
84
  return
85
 
86
  _device = _get_device()
87
+
88
+ if _device.type == "cuda":
89
+ torch.backends.cudnn.benchmark = True
90
+ torch.set_float32_matmul_precision("high")
91
+
92
+ if _device.type == "cuda":
93
+ logger.info(
94
+ "Device: cuda (%s, %.1f GB VRAM)",
95
+ torch.cuda.get_device_name(0),
96
+ torch.cuda.get_device_properties(0).total_mem / 1024**3,
97
+ )
98
+ else:
99
+ logger.warning(
100
+ "Device: %s (no CUDA available -- check nvidia-container-toolkit)",
101
+ _device,
102
+ )
103
+
104
  logger.info(f"Loading FakeSTormer model on {_device}...")
105
 
106
  try:
 
174
  }
175
 
176
 
177
+ def _gpu_health_info() -> dict:
178
+ """Return GPU metrics for the health endpoint."""
179
+ if torch.cuda.is_available() and _device is not None and _device.type == "cuda":
180
+ return {
181
+ "gpu_name": torch.cuda.get_device_name(0),
182
+ "vram_used_mb": round(torch.cuda.memory_allocated(0) / 1024**2),
183
+ "vram_total_mb": round(
184
+ torch.cuda.get_device_properties(0).total_mem / 1024**2
185
+ ),
186
+ }
187
+ return {}
188
+
189
+
190
  @app.get("/health")
191
  def health():
192
  return {
193
  "status": "ok",
194
  "model_loaded": _is_model_loaded(),
195
  "weights_exist": os.path.exists(WEIGHTS_PATH),
196
+ "device": str(_device) if _device else "cpu",
197
+ **_gpu_health_info(),
198
  }
199
 
200
 
video/sbi/Dockerfile CHANGED
@@ -1,9 +1,13 @@
1
- FROM python:3.9-slim
 
 
 
2
 
3
  WORKDIR /app
4
 
5
- # Install system dependencies for OpenCV
6
- RUN apt-get update && apt-get install -y \
 
7
  libgl1 \
8
  libglib2.0-0 \
9
  libsm6 \
@@ -11,19 +15,27 @@ RUN apt-get update && apt-get install -y \
11
  libxrender-dev \
12
  && rm -rf /var/lib/apt/lists/*
13
 
14
- # Copy requirements and install
 
 
 
 
 
 
 
15
  COPY requirements.txt .
16
- RUN pip install --no-cache-dir -r requirements.txt
 
17
 
18
  # Create logs and weights directories
19
  RUN mkdir -p logs weights
 
20
 
21
  # Copy application code
22
  COPY app.py .
23
 
24
  # Environment variables
25
  ENV MODEL_PORT=7002
26
- ENV USE_GPU=false
27
  ENV PRELOAD_MODEL=false
28
  ENV MODEL_TIMEOUT=1800
29
  ENV WEIGHTS_PATH=/app/weights/FFc23.tar
 
1
+ FROM nvidia/cuda:12.1.1-cudnn8-runtime-ubuntu22.04
2
+
3
+ ENV DEBIAN_FRONTEND=noninteractive
4
+ ENV PYTHONUNBUFFERED=1
5
 
6
  WORKDIR /app
7
 
8
+ # Install Python 3.10 and system dependencies for OpenCV
9
+ RUN apt-get update && apt-get install -y --no-install-recommends \
10
+ python3 python3-pip \
11
  libgl1 \
12
  libglib2.0-0 \
13
  libsm6 \
 
15
  libxrender-dev \
16
  && rm -rf /var/lib/apt/lists/*
17
 
18
+ RUN ln -sf /usr/bin/python3 /usr/bin/python
19
+
20
+ # Install PyTorch with CUDA 12.1
21
+ RUN pip install --no-cache-dir \
22
+ torch==2.5.1 torchvision==0.20.1 \
23
+ --index-url https://download.pytorch.org/whl/cu121
24
+
25
+ # Copy requirements and install (facenet-pytorch needs --no-deps due to torch<2.3 pin)
26
  COPY requirements.txt .
27
+ RUN pip install --no-cache-dir --no-deps facenet-pytorch && \
28
+ pip install --no-cache-dir -r requirements.txt
29
 
30
  # Create logs and weights directories
31
  RUN mkdir -p logs weights
32
+ COPY weights/ /app/weights/
33
 
34
  # Copy application code
35
  COPY app.py .
36
 
37
  # Environment variables
38
  ENV MODEL_PORT=7002
 
39
  ENV PRELOAD_MODEL=false
40
  ENV MODEL_TIMEOUT=1800
41
  ENV WEIGHTS_PATH=/app/weights/FFc23.tar
video/sbi/app.py CHANGED
@@ -35,7 +35,6 @@ logging.basicConfig(level=logging.INFO)
35
  logger = logging.getLogger(__name__)
36
 
37
  MODEL_PORT = int(os.environ.get("MODEL_PORT", 7002))
38
- USE_GPU = os.environ.get("USE_GPU", "false").lower() == "true"
39
  PRELOAD_MODEL = os.environ.get("PRELOAD_MODEL", "false").lower() == "true"
40
  MODEL_TIMEOUT = int(os.environ.get("MODEL_TIMEOUT", 1800))
41
  WEIGHTS_PATH = os.environ.get("WEIGHTS_PATH", "/app/weights/FFc23.tar")
@@ -69,8 +68,6 @@ class Detector(nn.Module):
69
 
70
  def _get_device() -> torch.device:
71
  """Select optimal device: MPS (Apple) > CUDA (NVIDIA) > CPU."""
72
- if not USE_GPU:
73
- return torch.device("cpu")
74
  override = os.environ.get("DEEPSAFE_DEVICE", "").strip().lower()
75
  if override == "cpu":
76
  return torch.device("cpu")
@@ -114,6 +111,20 @@ def _load_models() -> None:
114
  return
115
 
116
  _device = _get_device()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  logger.info("Loading SBI model on %s ...", _device)
118
 
119
  # ── Face detector (MTCNN) ───────────────────────────────────────
@@ -193,6 +204,19 @@ def root():
193
  }
194
 
195
 
 
 
 
 
 
 
 
 
 
 
 
 
 
196
  @app.get("/health")
197
  def health():
198
  """Health check endpoint."""
@@ -202,6 +226,7 @@ def health():
202
  "device": str(_device) if _device else "cpu",
203
  "model_loaded": _is_model_loaded(),
204
  "weights_exist": os.path.exists(WEIGHTS_PATH),
 
205
  }
206
 
207
 
 
35
  logger = logging.getLogger(__name__)
36
 
37
  MODEL_PORT = int(os.environ.get("MODEL_PORT", 7002))
 
38
  PRELOAD_MODEL = os.environ.get("PRELOAD_MODEL", "false").lower() == "true"
39
  MODEL_TIMEOUT = int(os.environ.get("MODEL_TIMEOUT", 1800))
40
  WEIGHTS_PATH = os.environ.get("WEIGHTS_PATH", "/app/weights/FFc23.tar")
 
68
 
69
  def _get_device() -> torch.device:
70
  """Select optimal device: MPS (Apple) > CUDA (NVIDIA) > CPU."""
 
 
71
  override = os.environ.get("DEEPSAFE_DEVICE", "").strip().lower()
72
  if override == "cpu":
73
  return torch.device("cpu")
 
111
  return
112
 
113
  _device = _get_device()
114
+ if _device.type == "cuda":
115
+ torch.backends.cudnn.benchmark = True
116
+ torch.set_float32_matmul_precision("high")
117
+ if _device.type == "cuda":
118
+ logger.info(
119
+ "Device: cuda (%s, %.1f GB VRAM)",
120
+ torch.cuda.get_device_name(0),
121
+ torch.cuda.get_device_properties(0).total_mem / 1024**3,
122
+ )
123
+ else:
124
+ logger.warning(
125
+ "Device: %s (no CUDA available -- check nvidia-container-toolkit)",
126
+ _device,
127
+ )
128
  logger.info("Loading SBI model on %s ...", _device)
129
 
130
  # ── Face detector (MTCNN) ───────────────────────────────────────
 
204
  }
205
 
206
 
207
+ def _gpu_health_info() -> dict:
208
+ """Return GPU metrics for the health endpoint."""
209
+ if torch.cuda.is_available() and _device is not None and _device.type == "cuda":
210
+ return {
211
+ "gpu_name": torch.cuda.get_device_name(0),
212
+ "vram_used_mb": round(torch.cuda.memory_allocated(0) / 1024**2),
213
+ "vram_total_mb": round(
214
+ torch.cuda.get_device_properties(0).total_mem / 1024**2
215
+ ),
216
+ }
217
+ return {}
218
+
219
+
220
  @app.get("/health")
221
  def health():
222
  """Health check endpoint."""
 
226
  "device": str(_device) if _device else "cpu",
227
  "model_loaded": _is_model_loaded(),
228
  "weights_exist": os.path.exists(WEIGHTS_PATH),
229
+ **_gpu_health_info(),
230
  }
231
 
232