BiliSakura commited on
Commit
f7038f8
·
verified ·
1 Parent(s): cd99f4e

Add files using upload-large-folder tool

Browse files
README.md CHANGED
@@ -9,6 +9,11 @@ tags:
9
  - latent-diffusion
10
  - custom-pipeline
11
  - arxiv:2411.16969
 
 
 
 
 
12
  ---
13
 
14
  # BiliSakura/ZoomLDM-brca
@@ -60,6 +65,20 @@ out = pipe(
60
  images = out.images
61
  ```
62
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  ## Limitations
64
 
65
  - Requires correctly precomputed BRCA conditioning features.
 
9
  - latent-diffusion
10
  - custom-pipeline
11
  - arxiv:2411.16969
12
+ widget:
13
+ - src: demo_images/input.jpeg
14
+ prompt: BRCA sample conditioned on demo SSL feature (mag=0)
15
+ output:
16
+ url: demo_images/output.jpeg
17
  ---
18
 
19
  # BiliSakura/ZoomLDM-brca
 
65
  images = out.images
66
  ```
67
 
68
+ ## Demo Generation (dataset-backed)
69
+
70
+ This repo includes `run_demo_inference.py`, which uses local repo assets only:
71
+
72
+ - image: `demo_images/input.jpeg`
73
+ - SSL feature: `demo_data/0_ssl_feat.npy`
74
+ - magnification label: `0`
75
+
76
+ Run:
77
+
78
+ ```bash
79
+ python run_demo_inference.py
80
+ ```
81
+
82
  ## Limitations
83
 
84
  - Requires correctly precomputed BRCA conditioning features.
__pycache__/pipeline_zoomldm.cpython-312.pyc CHANGED
Binary files a/__pycache__/pipeline_zoomldm.cpython-312.pyc and b/__pycache__/pipeline_zoomldm.cpython-312.pyc differ
 
demo_data/0_ssl_feat.npy ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a0ccbc75eb5c210505d2ded9e3e2745a975971c8a331bd76ae31fc4d5c08a44a
3
+ size 2176
demo_images/input.jpeg ADDED
demo_images/output.jpeg ADDED
pipeline_zoomldm.py CHANGED
@@ -44,6 +44,10 @@ def _ensure_local_ldm_on_path():
44
 
45
 
46
  _ensure_local_ldm_on_path()
 
 
 
 
47
 
48
 
49
  def _get_class(target: str):
@@ -299,6 +303,17 @@ class ZoomLDMPipeline(DiffusionPipeline):
299
  path = Path(snapshot_download(pretrained_model_name_or_path))
300
 
301
  path = path.resolve()
 
 
 
 
 
 
 
 
 
 
 
302
 
303
  def _is_diffusers_model_dir(candidate: Path) -> bool:
304
  required = [
@@ -333,8 +348,6 @@ class ZoomLDMPipeline(DiffusionPipeline):
333
  )
334
  model_dir = candidate_dirs[0]
335
 
336
- scheduler = DDIMScheduler.from_pretrained(model_dir / "scheduler")
337
-
338
  _TARGETS = {
339
  "unet": "ldm.modules.diffusionmodules.openaimodel.UNetModel",
340
  "vae": "ldm.models.autoencoder.VQModelInterface",
@@ -381,6 +394,12 @@ class ZoomLDMPipeline(DiffusionPipeline):
381
  component.eval()
382
  return component
383
 
 
 
 
 
 
 
384
  unet = load_custom_component("unet")
385
  vae = load_custom_component("vae")
386
  conditioning_encoder = load_custom_component("conditioning_encoder")
 
44
 
45
 
46
  _ensure_local_ldm_on_path()
47
+ # Register module alias so diffusers component loading can resolve
48
+ # model_index entries like "pipeline_zoomldm" even when this file is loaded
49
+ # under a dynamic module name (e.g. diffusers_modules.local.*).
50
+ sys.modules["pipeline_zoomldm"] = sys.modules[__name__]
51
 
52
 
53
  def _get_class(target: str):
 
303
  path = Path(snapshot_download(pretrained_model_name_or_path))
304
 
305
  path = path.resolve()
306
+ component_names = {"unet", "vae", "conditioning_encoder"}
307
+ # When diffusers loads components, it may call this class with a path like ".../unet".
308
+ requested_component = None
309
+ if path.name in component_names and (path / "config.json").exists():
310
+ requested_component = path.name
311
+ path = path.parent
312
+
313
+ # Also support explicit component requests via subfolder.
314
+ subfolder = kwargs.pop("subfolder", None)
315
+ if requested_component is None and subfolder in component_names:
316
+ requested_component = subfolder
317
 
318
  def _is_diffusers_model_dir(candidate: Path) -> bool:
319
  required = [
 
348
  )
349
  model_dir = candidate_dirs[0]
350
 
 
 
351
  _TARGETS = {
352
  "unet": "ldm.modules.diffusionmodules.openaimodel.UNetModel",
353
  "vae": "ldm.models.autoencoder.VQModelInterface",
 
394
  component.eval()
395
  return component
396
 
397
+ # Diffusers component-loading path: return a single module.
398
+ if requested_component is not None:
399
+ return load_custom_component(requested_component)
400
+
401
+ scheduler = DDIMScheduler.from_pretrained(model_dir / "scheduler")
402
+
403
  unet = load_custom_component("unet")
404
  vae = load_custom_component("vae")
405
  conditioning_encoder = load_custom_component("conditioning_encoder")
run_demo_inference.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Run ZoomLDM-BRCA demo inference using local demo assets."""
3
+
4
+ from pathlib import Path
5
+
6
+ import numpy as np
7
+ import torch
8
+ import torch.nn.functional as F
9
+ from diffusers import DiffusionPipeline
10
+
11
+
12
+ def preprocess_brca_ssl(npy_path: Path) -> torch.Tensor:
13
+ # Copied from dataset material:
14
+ # 1) cast to float32
15
+ # 2) normalize per-feature
16
+ # 3) reshape to (1024, h, h)
17
+ # 4) adaptive avg pool to max 8x8 if needed
18
+ feat = np.load(npy_path).astype(np.float32)
19
+ if feat.ndim == 1:
20
+ feat = feat[:, None]
21
+ mean = feat.mean(axis=0, keepdims=True)
22
+ std = feat.std(axis=0, keepdims=True)
23
+ feat = (feat - mean) / (std + 1e-8)
24
+ h = int(np.sqrt(feat.shape[1]))
25
+ feat = torch.tensor(feat.reshape((-1, h, h))).float() # (1024, h, h)
26
+ if h > 8:
27
+ feat = F.adaptive_avg_pool2d(feat, (8, 8))
28
+ return feat
29
+
30
+
31
+ def main() -> None:
32
+ repo = Path(__file__).resolve().parent
33
+ demo_dir = repo / "demo_images"
34
+ demo_data = repo / "demo_data"
35
+ demo_dir.mkdir(exist_ok=True)
36
+
37
+ # Use repo-local demo assets only.
38
+ src_img = demo_dir / "input.jpeg"
39
+ src_feat = demo_data / "0_ssl_feat.npy"
40
+ if not src_img.exists():
41
+ raise FileNotFoundError(f"Missing demo input image: {src_img}")
42
+ if not src_feat.exists():
43
+ raise FileNotFoundError(f"Missing demo SSL feature: {src_feat}")
44
+
45
+ ssl_feat = preprocess_brca_ssl(src_feat).unsqueeze(0).to("cuda") # (1, 1024, h, h)
46
+ magnification = torch.tensor([0], device="cuda", dtype=torch.long)
47
+
48
+ pipe = DiffusionPipeline.from_pretrained(
49
+ str(repo),
50
+ custom_pipeline=str(repo / "pipeline_zoomldm.py"),
51
+ trust_remote_code=True,
52
+ local_files_only=True,
53
+ ).to("cuda")
54
+
55
+ out = pipe(
56
+ ssl_features=ssl_feat,
57
+ magnification=magnification,
58
+ num_inference_steps=50,
59
+ guidance_scale=2.0,
60
+ generator=torch.Generator(device="cuda").manual_seed(42),
61
+ )
62
+ out.images[0].save(demo_dir / "output.jpeg")
63
+ print(f"Saved {demo_dir / 'input.jpeg'}")
64
+ print(f"Saved {demo_dir / 'output.jpeg'}")
65
+
66
+
67
+ if __name__ == "__main__":
68
+ main()