S-Mithilesh commited on
Commit
36d0fcd
·
verified ·
1 Parent(s): 7a07c0b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +46 -132
app.py CHANGED
@@ -21,9 +21,6 @@ DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
21
  print("=" * 60)
22
  print("FORESIGHT - MODEL INITIALIZATION")
23
  print("=" * 60)
24
- print(f"Model repository : {MODEL_REPO}")
25
- print(f"Device : {DEVICE}")
26
- print(f"HF token present : {HF_TOKEN is not None}")
27
 
28
  processor = ViTImageProcessor(
29
  do_resize=True,
@@ -35,32 +32,15 @@ processor = ViTImageProcessor(
35
  image_std=[0.229, 0.224, 0.225],
36
  )
37
 
38
- print("Loading custom model code...")
 
39
 
40
- # Download configuration and modeling scripts from Hugging Face Hub
41
- config_path = hf_hub_download(
42
- repo_id=MODEL_REPO,
43
- filename="configuration_vit_refiner.py",
44
- token=HF_TOKEN,
45
- )
46
- model_path = hf_hub_download(
47
- repo_id=MODEL_REPO,
48
- filename="modeling_vit_refiner.py",
49
- token=HF_TOKEN,
50
- )
51
-
52
- # Dynamically import configuration_vit_refiner
53
- config_spec = importlib.util.spec_from_file_location(
54
- "configuration_vit_refiner", config_path
55
- )
56
  config_module = importlib.util.module_from_spec(config_spec)
57
  sys.modules["configuration_vit_refiner"] = config_module
58
  config_spec.loader.exec_module(config_module)
59
 
60
- # Dynamically import modeling_vit_refiner
61
- model_spec = importlib.util.spec_from_file_location(
62
- "modeling_vit_refiner", model_path
63
- )
64
  model_module = importlib.util.module_from_spec(model_spec)
65
  sys.modules["modeling_vit_refiner"] = model_module
66
  model_spec.loader.exec_module(model_module)
@@ -68,32 +48,18 @@ model_spec.loader.exec_module(model_module)
68
  ViTRefinerConfig = config_module.ViTRefinerConfig
69
  ViTRefinerModel = model_module.ViTRefinerModel
70
 
71
- # Instantiate model directly to prevent nested meta-context issues
72
  config = ViTRefinerConfig.from_pretrained(MODEL_REPO, token=HF_TOKEN)
73
  model = ViTRefinerModel(config)
74
 
75
- # Load weights safely from safetensors
76
- weights_path = hf_hub_download(
77
- repo_id=MODEL_REPO,
78
- filename="model.safetensors",
79
- token=HF_TOKEN,
80
- )
81
  state_dict = load_file(weights_path)
82
  model.load_state_dict(state_dict, strict=False)
83
 
84
  model.to(DEVICE)
85
  model.eval()
86
- print("Model initialized successfully.")
87
-
88
- # Override labels to REAL / FAKE
89
- model.config.id2label = {
90
- 0: "FAKE",
91
- 1: "REAL"
92
- }
93
- model.config.label2id = {
94
- "FAKE": 0,
95
- "REAL": 1
96
- }
97
 
98
  # -----------------------------
99
  # ATTENTION HOOK EXTRACTION
@@ -102,30 +68,37 @@ model.config.label2id = {
102
  captured_attentions = []
103
 
104
  def attention_hook(module, input, output):
105
- # Standard ViTSelfAttention outputs (context_layer, attention_probs)
106
- if isinstance(output, tuple) and len(output) > 1:
107
- captured_attentions.append(output[1].detach().cpu())
108
-
109
- # Attach hooks to all internal ViT self-attention layers
110
- for name, module in model.vit.vit.named_modules():
111
- if "attention.self" in name or name.endswith("self"):
 
 
 
112
  module.register_forward_hook(attention_hook)
113
 
114
  # -----------------------------
115
- # ATTENTION ROLLOUT (Exact from reference)
116
  # -----------------------------
117
 
118
  def compute_attention_rollout(attentions):
119
  if not attentions:
120
  return None
121
 
122
- # Shape: [layers, batch, heads, tokens, tokens]
123
- att_mat = torch.stack(attentions).squeeze(1)
 
 
 
 
124
  att_mat = att_mat.mean(dim=1)
125
 
126
  residual_att = torch.eye(att_mat.size(-1), device=att_mat.device)
127
  aug_att_mat = att_mat + residual_att
128
- aug_att_mat = aug_att_mat / aug_att_mat.sum(dim=-1).unsqueeze(-1)
129
 
130
  joint_attentions = torch.zeros_like(aug_att_mat)
131
  joint_attentions[0] = aug_att_mat[0]
@@ -151,11 +124,11 @@ def predict(image):
151
  inputs = processor(images=image, return_tensors="pt")
152
  inputs = {key: value.to(DEVICE) for key, value in inputs.items()}
153
 
154
- # Reset captured attentions before forward pass
155
  captured_attentions.clear()
156
 
157
  with torch.no_grad():
158
- outputs = model(**inputs)
 
159
  logits = outputs["logits"] if isinstance(outputs, dict) else outputs.logits
160
 
161
  probs = torch.nn.functional.softmax(logits, dim=-1)
@@ -164,30 +137,23 @@ def predict(image):
164
  prediction = model.config.id2label[predicted_class_idx.item()]
165
  confidence_pct = round(confidence.item() * 100, 2)
166
 
167
- # Attention rollout using captured attentions
168
  rollout = compute_attention_rollout(captured_attentions)
169
 
170
  if rollout is not None:
171
- mask = rollout[0, 1:]
172
  size = int(mask.shape[0] ** 0.5)
173
- mask = mask.reshape(size, size).cpu().numpy()
174
 
175
  mask = cv2.resize(mask, image.size)
176
  mask = (mask - mask.min()) / (mask.max() - mask.min() + 1e-8)
177
 
178
- heatmap = cv2.applyColorMap(
179
- np.uint8(255 * mask),
180
- cv2.COLORMAP_JET
181
- )
182
-
183
- overlay = cv2.addWeighted(
184
- np.array(image),
185
- 0.6,
186
- heatmap,
187
- 0.4,
188
- 0
189
- )
190
  else:
 
191
  overlay = np.array(image)
192
 
193
  return prediction, f"{confidence_pct}%", overlay
@@ -197,68 +163,16 @@ def predict(image):
197
  # -----------------------------
198
 
199
  custom_css = """
200
- /* Professional Adaptive Theme */
201
- :root {
202
- --primary-blue: #2563eb;
203
- --hero-text: #0f172a;
204
- }
205
- .dark {
206
- --hero-text: #f8fafc;
207
- }
208
- body {
209
- background-color: var(--background-fill-primary);
210
- }
211
- .hero {
212
- text-align: center;
213
- font-family: 'Inter', sans-serif;
214
- font-size: 48px;
215
- font-weight: 800;
216
- letter-spacing: -0.04em;
217
- margin-top: 50px;
218
- color: var(--hero-text) !important;
219
- }
220
- .sub {
221
- text-align: center;
222
- opacity: 0.7;
223
- font-size: 14px;
224
- font-weight: 600;
225
- letter-spacing: 0.1em;
226
- text-transform: uppercase;
227
- margin-bottom: 40px;
228
- color: var(--body-text-color);
229
- }
230
- .glass {
231
- background: var(--block-background-fill) !important;
232
- border: 1px solid var(--border-color-primary) !important;
233
- border-radius: 12px !important;
234
- padding: 24px !important;
235
- box-shadow: var(--block-shadow);
236
- transition: all 0.2s ease;
237
- }
238
- .glass:hover {
239
- border-color: var(--primary-blue) !important;
240
- box-shadow: 0 4px 20px rgba(37, 99, 235, 0.1);
241
- }
242
- button.primary {
243
- background: var(--primary-blue) !important;
244
- color: white !important;
245
- border: none !important;
246
- font-weight: 600 !important;
247
- padding: 12px 24px !important;
248
- border-radius: 8px !important;
249
- box-shadow: 0 4px 12px rgba(37, 99, 235, 0.2) !important;
250
- }
251
- button.primary:hover {
252
- background: #1d4ed8 !important;
253
- transform: translateY(-1px);
254
- box-shadow: 0 6px 16px rgba(37, 99, 235, 0.3) !important;
255
- }
256
- .gr-label {
257
- font-weight: 600 !important;
258
- font-size: 12px !important;
259
- text-transform: uppercase;
260
- color: var(--primary-blue) !important;
261
- }
262
  """
263
 
264
  with gr.Blocks(
 
21
  print("=" * 60)
22
  print("FORESIGHT - MODEL INITIALIZATION")
23
  print("=" * 60)
 
 
 
24
 
25
  processor = ViTImageProcessor(
26
  do_resize=True,
 
32
  image_std=[0.229, 0.224, 0.225],
33
  )
34
 
35
+ config_path = hf_hub_download(repo_id=MODEL_REPO, filename="configuration_vit_refiner.py", token=HF_TOKEN)
36
+ model_path = hf_hub_download(repo_id=MODEL_REPO, filename="modeling_vit_refiner.py", token=HF_TOKEN)
37
 
38
+ config_spec = importlib.util.spec_from_file_location("configuration_vit_refiner", config_path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  config_module = importlib.util.module_from_spec(config_spec)
40
  sys.modules["configuration_vit_refiner"] = config_module
41
  config_spec.loader.exec_module(config_module)
42
 
43
+ model_spec = importlib.util.spec_from_file_location("modeling_vit_refiner", model_path)
 
 
 
44
  model_module = importlib.util.module_from_spec(model_spec)
45
  sys.modules["modeling_vit_refiner"] = model_module
46
  model_spec.loader.exec_module(model_module)
 
48
  ViTRefinerConfig = config_module.ViTRefinerConfig
49
  ViTRefinerModel = model_module.ViTRefinerModel
50
 
 
51
  config = ViTRefinerConfig.from_pretrained(MODEL_REPO, token=HF_TOKEN)
52
  model = ViTRefinerModel(config)
53
 
54
+ weights_path = hf_hub_download(repo_id=MODEL_REPO, filename="model.safetensors", token=HF_TOKEN)
 
 
 
 
 
55
  state_dict = load_file(weights_path)
56
  model.load_state_dict(state_dict, strict=False)
57
 
58
  model.to(DEVICE)
59
  model.eval()
60
+
61
+ model.config.id2label = {0: "FAKE", 1: "REAL"}
62
+ model.config.label2id = {"FAKE": 0, "REAL": 1}
 
 
 
 
 
 
 
 
63
 
64
  # -----------------------------
65
  # ATTENTION HOOK EXTRACTION
 
68
  captured_attentions = []
69
 
70
  def attention_hook(module, input, output):
71
+ # If output is a tuple with attention probabilities, grab index 1
72
+ if isinstance(output, tuple):
73
+ if len(output) > 1 and output[1] is not None:
74
+ captured_attentions.append(output[1].detach().cpu())
75
+ elif isinstance(output[0], torch.Tensor) and output[0].ndim == 4: # [batch, heads, tokens, tokens]
76
+ captured_attentions.append(output[0].detach().cpu())
77
+
78
+ # Register hook on every self-attention block
79
+ for module in model.modules():
80
+ if module.__class__.__name__ == "ViTSelfAttention":
81
  module.register_forward_hook(attention_hook)
82
 
83
  # -----------------------------
84
+ # ATTENTION ROLLOUT
85
  # -----------------------------
86
 
87
  def compute_attention_rollout(attentions):
88
  if not attentions:
89
  return None
90
 
91
+ # Stack along layers dimension -> [layers, batch, heads, tokens, tokens]
92
+ att_mat = torch.stack(attentions)
93
+ if att_mat.dim() == 5:
94
+ att_mat = att_mat[:, 0] # Select batch item 0 -> [layers, heads, tokens, tokens]
95
+
96
+ # Mean over attention heads -> [layers, tokens, tokens]
97
  att_mat = att_mat.mean(dim=1)
98
 
99
  residual_att = torch.eye(att_mat.size(-1), device=att_mat.device)
100
  aug_att_mat = att_mat + residual_att
101
+ aug_att_mat = aug_att_mat / aug_att_mat.sum(dim=-1, keepdim=True)
102
 
103
  joint_attentions = torch.zeros_like(aug_att_mat)
104
  joint_attentions[0] = aug_att_mat[0]
 
124
  inputs = processor(images=image, return_tensors="pt")
125
  inputs = {key: value.to(DEVICE) for key, value in inputs.items()}
126
 
 
127
  captured_attentions.clear()
128
 
129
  with torch.no_grad():
130
+ # Passing output_attentions=True forces ViT layers to return attention matrices
131
+ outputs = model(**inputs, output_attentions=True)
132
  logits = outputs["logits"] if isinstance(outputs, dict) else outputs.logits
133
 
134
  probs = torch.nn.functional.softmax(logits, dim=-1)
 
137
  prediction = model.config.id2label[predicted_class_idx.item()]
138
  confidence_pct = round(confidence.item() * 100, 2)
139
 
140
+ # Compute rollout
141
  rollout = compute_attention_rollout(captured_attentions)
142
 
143
  if rollout is not None:
144
+ mask = rollout[0, 1:] # Token 0 is CLS token, rest are patch tokens
145
  size = int(mask.shape[0] ** 0.5)
146
+ mask = mask.reshape(size, size).numpy()
147
 
148
  mask = cv2.resize(mask, image.size)
149
  mask = (mask - mask.min()) / (mask.max() - mask.min() + 1e-8)
150
 
151
+ heatmap = cv2.applyColorMap(np.uint8(255 * mask), cv2.COLORMAP_JET)
152
+ heatmap = cv2.cvtColor(heatmap, cv2.COLOR_BGR2RGB)
153
+
154
+ overlay = cv2.addWeighted(np.array(image), 0.6, heatmap, 0.4, 0)
 
 
 
 
 
 
 
 
155
  else:
156
+ print("Warning: No attention matrices captured during forward pass.")
157
  overlay = np.array(image)
158
 
159
  return prediction, f"{confidence_pct}%", overlay
 
163
  # -----------------------------
164
 
165
  custom_css = """
166
+ :root { --primary-blue: #2563eb; --hero-text: #0f172a; }
167
+ .dark { --hero-text: #f8fafc; }
168
+ body { background-color: var(--background-fill-primary); }
169
+ .hero { text-align: center; font-family: 'Inter', sans-serif; font-size: 48px; font-weight: 800; letter-spacing: -0.04em; margin-top: 50px; color: var(--hero-text) !important; }
170
+ .sub { text-align: center; opacity: 0.7; font-size: 14px; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; margin-bottom: 40px; color: var(--body-text-color); }
171
+ .glass { background: var(--block-background-fill) !important; border: 1px solid var(--border-color-primary) !important; border-radius: 12px !important; padding: 24px !important; box-shadow: var(--block-shadow); transition: all 0.2s ease; }
172
+ .glass:hover { border-color: var(--primary-blue) !important; box-shadow: 0 4px 20px rgba(37, 99, 235, 0.1); }
173
+ button.primary { background: var(--primary-blue) !important; color: white !important; border: none !important; font-weight: 600 !important; padding: 12px 24px !important; border-radius: 8px !important; box-shadow: 0 4px 12px rgba(37, 99, 235, 0.2) !important; }
174
+ button.primary:hover { background: #1d4ed8 !important; transform: translateY(-1px); box-shadow: 0 6px 16px rgba(37, 99, 235, 0.3) !important; }
175
+ .gr-label { font-weight: 600 !important; font-size: 12px !important; text-transform: uppercase; color: var(--primary-blue) !important; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
  """
177
 
178
  with gr.Blocks(