SaniaE commited on
Commit
ace7c16
·
verified ·
1 Parent(s): cf0f372

added timing checks

Browse files
Files changed (1) hide show
  1. app.py +43 -10
app.py CHANGED
@@ -1,5 +1,6 @@
1
  import os
2
  import io
 
3
  import asyncio
4
  import random
5
  import numpy as np
@@ -8,7 +9,8 @@ import torch.nn.functional as F
8
  import matplotlib.pyplot as plt
9
  from PIL import Image, ImageFilter
10
  from fastapi import FastAPI, UploadFile, File, Query
11
- from fastapi.responses import StreamingResponse
 
12
  from huggingface_hub import snapshot_download, login
13
 
14
  from transformers import (
@@ -19,12 +21,21 @@ from transformers import (
19
 
20
  app = FastAPI(title="XAI Auditor Ensemble with CLIP Jury")
21
 
 
 
 
 
 
 
 
 
 
 
22
  # --- Configuration & Paths ---
23
  REPO_ID = "SaniaE/Image_Captioning_Ensemble"
24
  DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
25
  MODELS = {}
26
 
27
- # Metadata for loading
28
  MODEL_CONFIGS = {
29
  "blip": {
30
  "subfolder": "blip",
@@ -103,19 +114,30 @@ async def generate_captions(
103
  top_k: int = Query(50),
104
  top_p: float = Query(0.9)
105
  ):
106
- """Generates 5 diverse captions using the model ensemble."""
107
  image = Image.open(file.file).convert("RGB")
108
  architectures = ["blip", "vit"]
109
  selection = random.choices(architectures, k=5)
110
 
 
111
  tasks = [asyncio.to_thread(_generate_sync, m, image, temp, top_k, top_p) for m in selection]
112
  captions = await asyncio.gather(*tasks)
113
 
114
- return {"captions": captions, "metadata": {"models_used": selection, "temp": temp}}
 
 
 
 
 
 
 
 
 
 
115
 
116
  @app.post("/saliency")
117
  async def get_vision_saliency(file: UploadFile = File(...)):
118
- """Objective Saliency: Shows what the Vision Encoder focuses on (Self-Attention)."""
119
  image_bytes = await file.read()
120
  orig_img = Image.open(io.BytesIO(image_bytes)).convert("RGB")
121
 
@@ -124,8 +146,7 @@ async def get_vision_saliency(file: UploadFile = File(...)):
124
 
125
  with torch.no_grad():
126
  outputs = blip["model"].vision_model(inputs.pixel_values, output_attentions=True)
127
- attentions = outputs.attentions[-1] # Last layer
128
- # Average heads, look at CLS token attention to patches
129
  mask_1d = attentions[0, :, 0, 1:].mean(dim=0)
130
  grid_size = int(np.sqrt(mask_1d.shape[-1]))
131
  mask = mask_1d.view(grid_size, grid_size).cpu().numpy()
@@ -141,11 +162,19 @@ async def get_vision_saliency(file: UploadFile = File(...)):
141
  buf = io.BytesIO()
142
  blended.save(buf, format="PNG")
143
  buf.seek(0)
144
- return StreamingResponse(buf, media_type="image/png")
 
 
 
 
 
 
 
 
145
 
146
  @app.post("/audit")
147
  async def internal_debate_audit(file: UploadFile = File(...), user_prompt: str = Query(...)):
148
- """The CLIP-Powered Jury: Compares User Intent vs. Model Perception."""
149
  image_bytes = await file.read()
150
  image = Image.open(io.BytesIO(image_bytes)).convert("RGB")
151
 
@@ -172,8 +201,12 @@ async def internal_debate_audit(file: UploadFile = File(...), user_prompt: str =
172
  else:
173
  verdict = "Model Bias Detected."
174
 
 
 
 
175
  return {
176
  "perspectives": {"user": user_prompt, "ai": blip_caption},
177
  "audit_scores": {"intent_grounding": round(u_score, 4), "ai_grounding": round(m_score, 4)},
178
- "verdict": verdict
 
179
  }
 
1
  import os
2
  import io
3
+ import time
4
  import asyncio
5
  import random
6
  import numpy as np
 
9
  import matplotlib.pyplot as plt
10
  from PIL import Image, ImageFilter
11
  from fastapi import FastAPI, UploadFile, File, Query
12
+ from fastapi.middleware.cors import CORSMiddleware
13
+ from fastapi.responses import StreamingResponse, Response
14
  from huggingface_hub import snapshot_download, login
15
 
16
  from transformers import (
 
21
 
22
  app = FastAPI(title="XAI Auditor Ensemble with CLIP Jury")
23
 
24
+ # Enable smooth frontend cross-origin header interceptions for performance metrics
25
+ app.add_middleware(
26
+ CORSMiddleware,
27
+ allow_origins=["*"],
28
+ allow_credentials=True,
29
+ allow_methods=["*"],
30
+ allow_headers=["*"],
31
+ expose_headers=["X-Processing-Time", "X-Audit-Time", "X-Grounding-Verdict"]
32
+ )
33
+
34
  # --- Configuration & Paths ---
35
  REPO_ID = "SaniaE/Image_Captioning_Ensemble"
36
  DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
37
  MODELS = {}
38
 
 
39
  MODEL_CONFIGS = {
40
  "blip": {
41
  "subfolder": "blip",
 
114
  top_k: int = Query(50),
115
  top_p: float = Query(0.9)
116
  ):
117
+ start_time = time.perf_counter()
118
  image = Image.open(file.file).convert("RGB")
119
  architectures = ["blip", "vit"]
120
  selection = random.choices(architectures, k=5)
121
 
122
+ # Offload generative sampling loop to a worker thread pool
123
  tasks = [asyncio.to_thread(_generate_sync, m, image, temp, top_k, top_p) for m in selection]
124
  captions = await asyncio.gather(*tasks)
125
 
126
+ elapsed_time = time.perf_counter() - start_time
127
+ print(f"[BENCHMARK] /generate ensemble turnaround: {elapsed_time:.4f}s")
128
+
129
+ return {
130
+ "captions": captions,
131
+ "metadata": {
132
+ "models_used": selection,
133
+ "temp": temp,
134
+ "processing_time_sec": round(elapsed_time, 4)
135
+ }
136
+ }
137
 
138
  @app.post("/saliency")
139
  async def get_vision_saliency(file: UploadFile = File(...)):
140
+ start_time = time.perf_counter()
141
  image_bytes = await file.read()
142
  orig_img = Image.open(io.BytesIO(image_bytes)).convert("RGB")
143
 
 
146
 
147
  with torch.no_grad():
148
  outputs = blip["model"].vision_model(inputs.pixel_values, output_attentions=True)
149
+ attentions = outputs.attentions[-1]
 
150
  mask_1d = attentions[0, :, 0, 1:].mean(dim=0)
151
  grid_size = int(np.sqrt(mask_1d.shape[-1]))
152
  mask = mask_1d.view(grid_size, grid_size).cpu().numpy()
 
162
  buf = io.BytesIO()
163
  blended.save(buf, format="PNG")
164
  buf.seek(0)
165
+
166
+ elapsed_time = time.perf_counter() - start_time
167
+ print(f"[BENCHMARK] /saliency last-layer map turnaround: {elapsed_time:.4f}s")
168
+
169
+ return StreamingResponse(
170
+ buf,
171
+ media_type="image/png",
172
+ headers={"X-Processing-Time": f"{elapsed_time:.4f}"}
173
+ )
174
 
175
  @app.post("/audit")
176
  async def internal_debate_audit(file: UploadFile = File(...), user_prompt: str = Query(...)):
177
+ start_time = time.perf_counter()
178
  image_bytes = await file.read()
179
  image = Image.open(io.BytesIO(image_bytes)).convert("RGB")
180
 
 
201
  else:
202
  verdict = "Model Bias Detected."
203
 
204
+ elapsed_time = time.perf_counter() - start_time
205
+ print(f"[BENCHMARK] /audit multimodal jury turnaround: {elapsed_time:.4f}s | Verdict: {verdict}")
206
+
207
  return {
208
  "perspectives": {"user": user_prompt, "ai": blip_caption},
209
  "audit_scores": {"intent_grounding": round(u_score, 4), "ai_grounding": round(m_score, 4)},
210
+ "verdict": verdict,
211
+ "metadata": {"processing_time_sec": round(elapsed_time, 4)}
212
  }