updated beam search parameter
Browse files
app.py
CHANGED
|
@@ -18,7 +18,7 @@ from transformers import (
|
|
| 18 |
CLIPModel, CLIPProcessor, BitsAndBytesConfig
|
| 19 |
)
|
| 20 |
|
| 21 |
-
app = FastAPI(title="XAI Auditor:
|
| 22 |
|
| 23 |
app.add_middleware(
|
| 24 |
CORSMiddleware,
|
|
@@ -56,7 +56,7 @@ async def startup_event():
|
|
| 56 |
"processor": BlipProcessor.from_pretrained("Salesforce/blip-image-captioning-large")
|
| 57 |
}
|
| 58 |
|
| 59 |
-
# 2. Load Compressed ViT Track
|
| 60 |
MODELS["vit"] = {
|
| 61 |
"model": AutoModelForCausalLM.from_pretrained(
|
| 62 |
os.path.join(local_dir, "vit"),
|
|
@@ -77,19 +77,19 @@ async def startup_event():
|
|
| 77 |
"processor": CLIPProcessor.from_pretrained(os.path.join(local_dir, "clip/clip_processor"))
|
| 78 |
}
|
| 79 |
|
| 80 |
-
print("All system weights safely pinned.
|
| 81 |
|
| 82 |
-
# ---
|
| 83 |
|
| 84 |
def _generate_balanced_4_track(image, max_len=15):
|
| 85 |
"""
|
| 86 |
-
Generates exactly 4 captions
|
| 87 |
-
|
| 88 |
"""
|
| 89 |
captions = []
|
| 90 |
|
| 91 |
with torch.inference_mode():
|
| 92 |
-
# Track A:
|
| 93 |
b_data = MODELS["blip"]
|
| 94 |
b_inputs = b_data["processor"](images=image, return_tensors="pt")
|
| 95 |
b_pixels = b_inputs.pixel_values.to(DEVICE)
|
|
@@ -98,15 +98,16 @@ def _generate_balanced_4_track(image, max_len=15):
|
|
| 98 |
b_ids = b_data["model"].generate(
|
| 99 |
pixel_values=batched_b_pixels,
|
| 100 |
max_new_tokens=max_len,
|
| 101 |
-
do_sample=False,
|
| 102 |
-
num_beams=
|
| 103 |
-
|
| 104 |
-
|
|
|
|
| 105 |
)
|
| 106 |
b_caps = b_data["processor"].batch_decode(b_ids, skip_special_tokens=True)
|
| 107 |
captions.extend([cap.strip() for cap in b_caps])
|
| 108 |
|
| 109 |
-
# Track B:
|
| 110 |
v_data = MODELS["vit"]
|
| 111 |
i_proc, t_proc = v_data["processor"]
|
| 112 |
v_inputs = i_proc(images=image, return_tensors="pt")
|
|
@@ -122,8 +123,9 @@ def _generate_balanced_4_track(image, max_len=15):
|
|
| 122 |
pixel_values=batched_v_pixels,
|
| 123 |
attention_mask=batched_mask,
|
| 124 |
max_new_tokens=max_len,
|
| 125 |
-
do_sample=False,
|
| 126 |
-
num_beams=
|
|
|
|
| 127 |
early_stopping=True,
|
| 128 |
use_cache=True
|
| 129 |
)
|
|
@@ -140,7 +142,7 @@ async def generate_captions(file: UploadFile = File(...)):
|
|
| 140 |
start_time = time.perf_counter()
|
| 141 |
image = Image.open(file.file).convert("RGB")
|
| 142 |
|
| 143 |
-
#
|
| 144 |
captions = await asyncio.to_thread(_generate_balanced_4_track, image, 15)
|
| 145 |
|
| 146 |
elapsed_time = time.perf_counter() - start_time
|
|
@@ -197,4 +199,36 @@ async def internal_debate_audit(file: UploadFile = File(...), user_prompt: str =
|
|
| 197 |
image_bytes = await file.read()
|
| 198 |
image = Image.open(io.BytesIO(image_bytes)).convert("RGB")
|
| 199 |
|
| 200 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
CLIPModel, CLIPProcessor, BitsAndBytesConfig
|
| 19 |
)
|
| 20 |
|
| 21 |
+
app = FastAPI(title="XAI Auditor: Pure Greedy Fast Ensemble")
|
| 22 |
|
| 23 |
app.add_middleware(
|
| 24 |
CORSMiddleware,
|
|
|
|
| 56 |
"processor": BlipProcessor.from_pretrained("Salesforce/blip-image-captioning-large")
|
| 57 |
}
|
| 58 |
|
| 59 |
+
# 2. Load Compressed ViT Track
|
| 60 |
MODELS["vit"] = {
|
| 61 |
"model": AutoModelForCausalLM.from_pretrained(
|
| 62 |
os.path.join(local_dir, "vit"),
|
|
|
|
| 77 |
"processor": CLIPProcessor.from_pretrained(os.path.join(local_dir, "clip/clip_processor"))
|
| 78 |
}
|
| 79 |
|
| 80 |
+
print("All system weights safely pinned. Pure greedy acceleration paths ready.")
|
| 81 |
|
| 82 |
+
# --- Ultra-Fast Pure Greedy Generation Engine ---
|
| 83 |
|
| 84 |
def _generate_balanced_4_track(image, max_len=15):
|
| 85 |
"""
|
| 86 |
+
Generates exactly 4 captions using clean, single-pass greedy tracks
|
| 87 |
+
with a repetition penalty to guarantee speed and output variation.
|
| 88 |
"""
|
| 89 |
captions = []
|
| 90 |
|
| 91 |
with torch.inference_mode():
|
| 92 |
+
# Track A: Fast Greedy BLIP Pass (2 parallel unique streams)
|
| 93 |
b_data = MODELS["blip"]
|
| 94 |
b_inputs = b_data["processor"](images=image, return_tensors="pt")
|
| 95 |
b_pixels = b_inputs.pixel_values.to(DEVICE)
|
|
|
|
| 98 |
b_ids = b_data["model"].generate(
|
| 99 |
pixel_values=batched_b_pixels,
|
| 100 |
max_new_tokens=max_len,
|
| 101 |
+
do_sample=False, # Pure deterministic greedy path
|
| 102 |
+
num_beams=1, # Completely eliminate branching tree overhead
|
| 103 |
+
repetition_penalty=1.2, # Forces variation across the two streams
|
| 104 |
+
early_stopping=True,
|
| 105 |
+
use_cache=True
|
| 106 |
)
|
| 107 |
b_caps = b_data["processor"].batch_decode(b_ids, skip_special_tokens=True)
|
| 108 |
captions.extend([cap.strip() for cap in b_caps])
|
| 109 |
|
| 110 |
+
# Track B: Fast Greedy ViT Pass (2 parallel unique streams)
|
| 111 |
v_data = MODELS["vit"]
|
| 112 |
i_proc, t_proc = v_data["processor"]
|
| 113 |
v_inputs = i_proc(images=image, return_tensors="pt")
|
|
|
|
| 123 |
pixel_values=batched_v_pixels,
|
| 124 |
attention_mask=batched_mask,
|
| 125 |
max_new_tokens=max_len,
|
| 126 |
+
do_sample=False, # Pure deterministic greedy path
|
| 127 |
+
num_beams=1, # Completely eliminate branching tree overhead
|
| 128 |
+
repetition_penalty=1.2, # Forces variation across the two streams
|
| 129 |
early_stopping=True,
|
| 130 |
use_cache=True
|
| 131 |
)
|
|
|
|
| 142 |
start_time = time.perf_counter()
|
| 143 |
image = Image.open(file.file).convert("RGB")
|
| 144 |
|
| 145 |
+
# Run the accelerated greedy pipeline
|
| 146 |
captions = await asyncio.to_thread(_generate_balanced_4_track, image, 15)
|
| 147 |
|
| 148 |
elapsed_time = time.perf_counter() - start_time
|
|
|
|
| 199 |
image_bytes = await file.read()
|
| 200 |
image = Image.open(io.BytesIO(image_bytes)).convert("RGB")
|
| 201 |
|
| 202 |
+
blip_caption = (await asyncio.to_thread(_generate_balanced_4_track, image, 15))[0]
|
| 203 |
+
|
| 204 |
+
clip_m = MODELS["clip"]["model"]
|
| 205 |
+
clip_p = MODELS["clip"]["processor"]
|
| 206 |
+
clip_dtype = torch.float16 if DEVICE == "cuda" else torch.float32
|
| 207 |
+
|
| 208 |
+
image_inputs = clip_p(images=image, return_tensors="pt")
|
| 209 |
+
text_inputs = clip_p(text=[user_prompt, blip_caption], return_tensors="pt", padding=True)
|
| 210 |
+
|
| 211 |
+
with torch.inference_mode():
|
| 212 |
+
img_pixels = image_inputs.pixel_values.to(device=DEVICE, dtype=clip_dtype)
|
| 213 |
+
txt_ids = text_inputs.input_ids.to(DEVICE)
|
| 214 |
+
txt_mask = text_inputs.attention_mask.to(DEVICE)
|
| 215 |
+
|
| 216 |
+
image_features = clip_m.get_image_features(pixel_values=img_pixels)
|
| 217 |
+
image_features = image_features / image_features.norm(dim=-1, keepdim=True)
|
| 218 |
+
|
| 219 |
+
text_features = clip_m.get_text_features(input_ids=txt_ids, attention_mask=txt_mask)
|
| 220 |
+
text_features = text_features / text_features.norm(dim=-1, keepdim=True)
|
| 221 |
+
|
| 222 |
+
logits_per_image = (image_features @ text_features.T) * clip_m.logit_scale.exp()
|
| 223 |
+
probs = F.softmax(logits_per_image, dim=-1).cpu().to(torch.float32).numpy()[0]
|
| 224 |
+
|
| 225 |
+
u_score, m_score = float(probs[0]), float(probs[1])
|
| 226 |
+
verdict = "Model Bias Detected." if abs(u_score - m_score) >= 0.15 else "Consensus: High Alignment."
|
| 227 |
+
if u_score < 0.35: verdict = "Perspective Divergence: Intent not grounded in image."
|
| 228 |
+
|
| 229 |
+
return {
|
| 230 |
+
"perspectives": {"user": user_prompt, "ai": blip_caption},
|
| 231 |
+
"audit_scores": {"intent_grounding": round(u_score, 4), "ai_grounding": round(m_score, 4)},
|
| 232 |
+
"verdict": verdict,
|
| 233 |
+
"metadata": {"processing_time_sec": round(time.perf_counter() - start_time, 4)}
|
| 234 |
+
}
|