minhquang47 commited on
Commit
2c71cf5
·
verified ·
1 Parent(s): 4ec9203

Use original online structural extractors

Browse files
Files changed (1) hide show
  1. submission_task1.py +69 -15
submission_task1.py CHANGED
@@ -216,28 +216,82 @@ def load_model():
216
 
217
 
218
  def _pil_to_tensor(image: Image.Image) -> torch.Tensor:
219
- image = image.convert("RGB").resize(DEFAULT_IMAGE_SIZE, Image.BILINEAR)
220
- arr = np.asarray(image).astype(np.float32) / 255.0
 
 
 
221
  arr = np.transpose(arr, (2, 0, 1))
222
  return torch.from_numpy(arr).float().unsqueeze(0)
223
 
224
 
225
- def _default_structural_tensors(batch_size: int = 1) -> Dict[str, torch.Tensor]:
226
- """Fallback structural tensors for hidden validation without manifests.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
 
228
- The trained model expects prior/topological features. Official validation is
229
- likely image+question only, so this fallback keeps inference runnable. If a
230
- lightweight structural feature extractor is later added to the repo, replace
231
- this function with real per-image features.
232
  """
233
 
234
- grid_h, grid_w = DEFAULT_GRID_SIZE
235
- prior = torch.ones(batch_size, 1, grid_h, grid_w, dtype=torch.float32)
236
- prior = prior / prior.flatten(1).sum(dim=1).view(batch_size, 1, 1, 1).clamp_min(1e-6)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237
  return {
238
- "prior_mask": prior,
239
- "topo_features": torch.zeros(batch_size, DEFAULT_TOPO_FEATURE_DIM, dtype=torch.float32),
240
- "global_features": torch.zeros(batch_size, DEFAULT_GLOBAL_FEATURE_DIM, dtype=torch.float32),
241
  }
242
 
243
 
@@ -245,7 +299,7 @@ def predict_one(image: Image.Image, question: str, max_new_tokens: int = 48) ->
245
  model = load_model()
246
  device = _DEVICE or _select_device()
247
  image_tensor = _pil_to_tensor(image).to(device)
248
- structural = {key: value.to(device) for key, value in _default_structural_tensors(1).items()}
249
 
250
  with torch.inference_mode():
251
  prediction = model.generate(
 
216
 
217
 
218
  def _pil_to_tensor(image: Image.Image) -> torch.Tensor:
219
+ import cv2
220
+
221
+ image_rgb = np.asarray(image.convert("RGB")).astype(np.uint8)
222
+ image_rgb = cv2.resize(image_rgb, DEFAULT_IMAGE_SIZE[::-1], interpolation=cv2.INTER_AREA)
223
+ arr = image_rgb.astype(np.float32) / 255.0
224
  arr = np.transpose(arr, (2, 0, 1))
225
  return torch.from_numpy(arr).float().unsqueeze(0)
226
 
227
 
228
+ _STRUCTURAL_EXTRACTORS = None
229
+
230
+
231
+ def _get_structural_extractors():
232
+ """Create the same structural extractors used by offline precompute."""
233
+
234
+ global _STRUCTURAL_EXTRACTORS
235
+ if _STRUCTURAL_EXTRACTORS is not None:
236
+ return _STRUCTURAL_EXTRACTORS
237
+
238
+ from src.topology.lesion_prior import LesionPriorExtractor
239
+ from src.topology.tda_morphology import TopologicalExtractor as MorphologyTopologicalExtractor
240
+
241
+ prior_extractor = LesionPriorExtractor(
242
+ image_size=DEFAULT_IMAGE_SIZE,
243
+ grid_size=DEFAULT_GRID_SIZE,
244
+ use_morphology=False,
245
+ )
246
+ morpho_extractor = MorphologyTopologicalExtractor(
247
+ grid_size=DEFAULT_GRID_SIZE,
248
+ image_size=DEFAULT_IMAGE_SIZE,
249
+ )
250
+ _STRUCTURAL_EXTRACTORS = (prior_extractor, morpho_extractor)
251
+ return _STRUCTURAL_EXTRACTORS
252
+
253
+
254
+ def _extract_online_structural_tensors(image: Image.Image) -> Dict[str, torch.Tensor]:
255
+ """Compute structural features online with the original precompute logic.
256
+
257
+ This mirrors `scripts/precompute_structural_features.py`:
258
+ prior_output = LesionPriorExtractor.extract_prior(image_bgr)
259
+ morpho_output = MorphologyTopologicalExtractor.extract_features(image_bgr)
260
 
261
+ Shapes:
262
+ - prior_mask: [1, 14, 14]
263
+ - topo_features: [1, 14, 14, 12]
264
+ - global_features: [1, 8]
265
  """
266
 
267
+ import cv2
268
+
269
+ prior_extractor, morpho_extractor = _get_structural_extractors()
270
+
271
+ image_rgb = np.asarray(image.convert("RGB")).astype(np.uint8)
272
+ image_bgr = cv2.cvtColor(image_rgb, cv2.COLOR_RGB2BGR)
273
+
274
+ prior_output = prior_extractor.extract_prior(image_bgr)
275
+ morpho_output = morpho_extractor.extract_features(image_bgr)
276
+
277
+ prior_mask = prior_output["prior_mask"].astype(np.float32)
278
+ topo_features = morpho_output["topo_features"].astype(np.float32)
279
+ global_features = morpho_output["global_features"].astype(np.float32)
280
+
281
+ if prior_mask.shape != DEFAULT_GRID_SIZE:
282
+ raise ValueError(f"prior_mask shape {prior_mask.shape} != {DEFAULT_GRID_SIZE}")
283
+ expected_topo_shape = (*DEFAULT_GRID_SIZE, DEFAULT_TOPO_FEATURE_DIM)
284
+ if topo_features.shape != expected_topo_shape:
285
+ raise ValueError(f"topo_features shape {topo_features.shape} != {expected_topo_shape}")
286
+ if global_features.shape != (DEFAULT_GLOBAL_FEATURE_DIM,):
287
+ raise ValueError(
288
+ f"global_features shape {global_features.shape} != {(DEFAULT_GLOBAL_FEATURE_DIM,)}"
289
+ )
290
+
291
  return {
292
+ "prior_mask": torch.from_numpy(prior_mask).float().unsqueeze(0),
293
+ "topo_features": torch.from_numpy(topo_features).float().unsqueeze(0),
294
+ "global_features": torch.from_numpy(global_features).float().unsqueeze(0),
295
  }
296
 
297
 
 
299
  model = load_model()
300
  device = _DEVICE or _select_device()
301
  image_tensor = _pil_to_tensor(image).to(device)
302
+ structural = {key: value.to(device) for key, value in _extract_online_structural_tensors(image).items()}
303
 
304
  with torch.inference_mode():
305
  prediction = model.generate(