Instructions to use StonyBrook-CVLab/BigCell with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Diffusers
How to use StonyBrook-CVLab/BigCell with Diffusers:
pip install -U diffusers transformers accelerate
import torch from diffusers import DiffusionPipeline # switch to "mps" for apple devices pipe = DiffusionPipeline.from_pretrained("StonyBrook-CVLab/BigCell", dtype=torch.bfloat16, device_map="cuda") prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k" image = pipe(prompt).images[0] - Notebooks
- Google Colab
- Kaggle
Add files using upload-large-folder tool
Browse files- README.md +141 -0
- bigcell-1024/model_index.json +19 -0
- bigcell-1024/pipeline.py +151 -0
- bigcell-1024/scheduler/scheduler_config.json +18 -0
- bigcell-1024/transformer/bigcell_transformer_2d.py +202 -0
- bigcell-1024/transformer/config.json +14 -0
- bigcell-1024/transformer/diffusion_pytorch_model.safetensors +3 -0
- bigcell-1024/vae/config.json +40 -0
- bigcell-2048/model_index.json +19 -0
- bigcell-2048/pipeline.py +151 -0
- bigcell-2048/scheduler/scheduler_config.json +18 -0
- bigcell-2048/transformer/bigcell_transformer_2d.py +202 -0
- bigcell-2048/transformer/config.json +14 -0
- bigcell-2048/transformer/diffusion_pytorch_model.safetensors +3 -0
- bigcell-2048/vae/config.json +40 -0
- bigcell-256/model_index.json +19 -0
- bigcell-256/pipeline.py +151 -0
- bigcell-256/scheduler/scheduler_config.json +18 -0
- bigcell-256/transformer/bigcell_transformer_2d.py +202 -0
- bigcell-256/transformer/config.json +14 -0
- bigcell-256/transformer/diffusion_pytorch_model.safetensors +3 -0
- bigcell-256/vae/config.json +40 -0
- cgm-8192/config.json +9 -0
- cgm-8192/model.safetensors +3 -0
- cgm-8192/normalization_stats.safetensors +3 -0
README.md
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: cc-by-nc-nd-4.0
|
| 3 |
+
library_name: diffusers
|
| 4 |
+
tags:
|
| 5 |
+
- histopathology
|
| 6 |
+
- whole-slide-image
|
| 7 |
+
- flow-matching
|
| 8 |
+
---
|
| 9 |
+
|
| 10 |
+
# BigCell: Generating Gigapixel Whole-Slide Images
|
| 11 |
+
|
| 12 |
+
[[📄 arXiv]](https://arxiv.org/abs/2610.14261) [[GitHub]](https://github.com/cvlab-stonybrook/BigCell) [[💾 Sample data]](https://huggingface.co/datasets/StonyBrook-CVLab/BigCell-sample-data)
|
| 13 |
+
|
| 14 |
+
BigCell is a flow-matching transformer (SiT-XL/2, 845M parameters) that generates histopathology images at 20×.
|
| 15 |
+
It is conditioned on a dense grid of [UNI-2h](https://huggingface.co/MahmoodLab/UNI2-h) embeddings, with one
|
| 16 |
+
1536-d token per 256×256 px. The model works in the latent space of the FLUX.2 VAE.
|
| 17 |
+
|
| 18 |
+
A native 2048×2048 tile generator, used with an inference-time sliding window, produces coherent images of up to
|
| 19 |
+
32,768×32,768 px. A separate conditioning generation model (CGM) samples the UNI-2 grid from a pathology report,
|
| 20 |
+
for text-to-image generation at 8192×8192.
|
| 21 |
+
|
| 22 |
+
| Folder | Content | Native tile | UNI-2 tokens / tile |
|
| 23 |
+
|---|---|---|---|
|
| 24 |
+
| `bigcell-256` | BigCell tile generator, progressive-training stage 1 | 256 px | 1 |
|
| 25 |
+
| `bigcell-1024` | stage 3 | 1024 px | 4×4 |
|
| 26 |
+
| `bigcell-2048` | **final model** (used in the paper) | 2048 px | 8×8 |
|
| 27 |
+
| `cgm-8192` | CGM (DiT-DH-B): TITAN text → 32×32×1536 UNI-2 grid of an 8192 px region | – | – |
|
| 28 |
+
|
| 29 |
+
Each `bigcell-*` folder is a diffusers pipeline (`BigCellPipeline`).
|
| 30 |
+
|
| 31 |
+
## Usage
|
| 32 |
+
|
| 33 |
+
The FLUX.2 VAE weights are not hosted here. Accept the licence of
|
| 34 |
+
[black-forest-labs/FLUX.2-dev](https://huggingface.co/black-forest-labs/FLUX.2-dev) and load the VAE from there.
|
| 35 |
+
Requires `diffusers>=0.36`.
|
| 36 |
+
|
| 37 |
+
```python
|
| 38 |
+
import torch
|
| 39 |
+
from diffusers import AutoencoderKLFlux2, DiffusionPipeline
|
| 40 |
+
from huggingface_hub import snapshot_download
|
| 41 |
+
|
| 42 |
+
name = "bigcell-2048"
|
| 43 |
+
path = f"{snapshot_download('StonyBrook-CVLab/BigCell', allow_patterns=f'{name}/*')}/{name}"
|
| 44 |
+
|
| 45 |
+
vae = AutoencoderKLFlux2.from_pretrained("black-forest-labs/FLUX.2-dev", subfolder="vae", torch_dtype=torch.bfloat16)
|
| 46 |
+
pipe = DiffusionPipeline.from_pretrained(path, vae=vae, custom_pipeline=path, trust_remote_code=True,
|
| 47 |
+
torch_dtype=torch.bfloat16).to("cuda")
|
| 48 |
+
```
|
| 49 |
+
|
| 50 |
+
### Generate from a UNI-2 grid
|
| 51 |
+
|
| 52 |
+
The pipeline takes a UNI-2 grid of shape `(B, Hg, Wg, 1536)` and returns a `(256·Hg) × (256·Wg)` image.
|
| 53 |
+
|
| 54 |
+
- A grid of exactly one native tile (8×8 for `bigcell-2048`) is denoised directly. Tokens of shape
|
| 55 |
+
`(B, T, 1536)` in raster order are also accepted.
|
| 56 |
+
- Larger grids are generated with the sliding-window procedure of the paper. Set `top_r < 1` for adaptive window
|
| 57 |
+
scheduling: only the fraction `top_r` of windows with the largest classifier-free-guidance magnitude is
|
| 58 |
+
recomputed after the first step.
|
| 59 |
+
|
| 60 |
+
```python
|
| 61 |
+
import numpy as np
|
| 62 |
+
from huggingface_hub import hf_hub_download
|
| 63 |
+
|
| 64 |
+
# 32×32 UNI-2 grid of a real 8192×8192 region from the sample data
|
| 65 |
+
f = hf_hub_download("StonyBrook-CVLab/BigCell-sample-data", repo_type="dataset",
|
| 66 |
+
filename="cptac/AML/C3L-00453-41_x0_y0/8192/0_uni.npy")
|
| 67 |
+
grid = torch.from_numpy(np.load(f)).float()[None] # (1, 32, 32, 1536)
|
| 68 |
+
|
| 69 |
+
image = pipe(grid, num_inference_steps=20, guidance_scale=2.0, top_r=0.25,
|
| 70 |
+
generator=torch.Generator("cuda").manual_seed(0)).images[0] # 8192×8192 PIL image
|
| 71 |
+
```
|
| 72 |
+
|
| 73 |
+
`pipe.get_unconditional_embedding(B)` returns the learned null condition, for unconditional samples.
|
| 74 |
+
|
| 75 |
+
### Extract a UNI-2 grid from your own image
|
| 76 |
+
|
| 77 |
+
```python
|
| 78 |
+
import timm, einops
|
| 79 |
+
from PIL import Image
|
| 80 |
+
from timm.data import resolve_data_config
|
| 81 |
+
from timm.data.transforms_factory import create_transform
|
| 82 |
+
|
| 83 |
+
timm_kwargs = dict(img_size=224, patch_size=14, depth=24, num_heads=24, init_values=1e-5, embed_dim=1536,
|
| 84 |
+
mlp_ratio=2.66667 * 2, num_classes=0, no_embed_class=True, mlp_layer=timm.layers.SwiGLUPacked,
|
| 85 |
+
act_layer=torch.nn.SiLU, reg_tokens=8, dynamic_img_size=True)
|
| 86 |
+
uni = timm.create_model("hf-hub:MahmoodLab/UNI2-h", pretrained=True, **timm_kwargs).eval().cuda()
|
| 87 |
+
transform = create_transform(**resolve_data_config(uni.pretrained_cfg, model=uni))
|
| 88 |
+
|
| 89 |
+
img = np.array(Image.open("region_20x.png").convert("RGB")) # H×W, multiples of 256, at 20×
|
| 90 |
+
hg, wg = img.shape[0] // 256, img.shape[1] // 256
|
| 91 |
+
patches = einops.rearrange(img, "(hg h) (wg w) c -> (hg wg) h w c", h=256, w=256)
|
| 92 |
+
with torch.inference_mode():
|
| 93 |
+
feats = torch.cat([uni(torch.stack([transform(Image.fromarray(p)) for p in patches[i:i + 256]]).cuda())
|
| 94 |
+
for i in range(0, len(patches), 256)])
|
| 95 |
+
grid = feats.reshape(1, hg, wg, 1536).float().cpu()
|
| 96 |
+
```
|
| 97 |
+
|
| 98 |
+
### Multi-GPU 32k generation and text-to-image
|
| 99 |
+
|
| 100 |
+
Gigapixel generation with windows sharded across GPUs, text-to-image with the CGM, and CGM-based data
|
| 101 |
+
augmentation are in the [GitHub repository](https://github.com/cvlab-stonybrook/BigCell):
|
| 102 |
+
|
| 103 |
+
```bash
|
| 104 |
+
torchrun --nproc_per_node 4 scripts/generate_from_grid.py --grid .../32768/0_uni.npy --top-r 0.25 --out 32k.jpg
|
| 105 |
+
python scripts/generate_from_text.py --prompt "Pancreatic ductal adenocarcinoma ..." --out out/
|
| 106 |
+
```
|
| 107 |
+
|
| 108 |
+
## Sampling settings used in the paper
|
| 109 |
+
|
| 110 |
+
- BigCell: 20 Euler steps, CFG 2.0, 2048 px windows with a 1024 px stride, and Gaussian window weighting.
|
| 111 |
+
- The time shift is stored in `transformer/config.json` (`alpha_shift`) and `scheduler/scheduler_config.json`
|
| 112 |
+
(`shift`). It is 3.0 for `bigcell-1024` / `bigcell-2048` and 1.0 for `bigcell-256`.
|
| 113 |
+
- CGM: 50-point Euler schedule with time shift √(32·32·1536/4096), CFG 2.0, and TITAN text tokens (unpooled,
|
| 114 |
+
127×768) as the condition.
|
| 115 |
+
|
| 116 |
+
## Citation
|
| 117 |
+
|
| 118 |
+
```bibtex
|
| 119 |
+
@misc{yellapragada2026bigcell,
|
| 120 |
+
title={BigCell: Generating Gigapixel Whole-Slide Images},
|
| 121 |
+
author={Srikar Yellapragada and Alexandros Graikos and Zilinghan Li and Kostas Triaridis and Tarak Nath Nandi and Ji Dong K Bai and Beatrice Knudsen and Tahsin Kurc and Prateek Prasanna and Rajarsi R. Gupta and Ravi K Madduri and Joel Saltz and Dimitris Samaras},
|
| 122 |
+
year={2026},
|
| 123 |
+
eprint={2610.14261},
|
| 124 |
+
archivePrefix={arXiv},
|
| 125 |
+
primaryClass={cs.CV},
|
| 126 |
+
url={https://arxiv.org/abs/2610.14261},
|
| 127 |
+
}
|
| 128 |
+
```
|
| 129 |
+
|
| 130 |
+
## License & Usage
|
| 131 |
+
|
| 132 |
+
**License**: Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International (CC BY-NC-ND 4.0)
|
| 133 |
+
|
| 134 |
+
**Notice**: These models are derivative works conditioned on embeddings from the
|
| 135 |
+
[UNI-2h](https://huggingface.co/MahmoodLab/UNI2-h) foundation model and, for the CGM, the
|
| 136 |
+
[TITAN](https://huggingface.co/MahmoodLab/TITAN) text encoder. They are subject to the original terms of those
|
| 137 |
+
licences. The FLUX.2 VAE is governed by its own licence.
|
| 138 |
+
|
| 139 |
+
- Academic and research use only: you may use these weights for non-commercial research purposes.
|
| 140 |
+
- No commercial use, including product development or commercial services.
|
| 141 |
+
- Generated images must not be used for clinical diagnosis.
|
bigcell-1024/model_index.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_class_name": [
|
| 3 |
+
"pipeline",
|
| 4 |
+
"BigCellPipeline"
|
| 5 |
+
],
|
| 6 |
+
"_diffusers_version": "0.37.1",
|
| 7 |
+
"transformer": [
|
| 8 |
+
"bigcell_transformer_2d",
|
| 9 |
+
"BigCellTransformer2DModel"
|
| 10 |
+
],
|
| 11 |
+
"vae": [
|
| 12 |
+
"diffusers",
|
| 13 |
+
"AutoencoderKLFlux2"
|
| 14 |
+
],
|
| 15 |
+
"scheduler": [
|
| 16 |
+
"diffusers",
|
| 17 |
+
"FlowMatchEulerDiscreteScheduler"
|
| 18 |
+
]
|
| 19 |
+
}
|
bigcell-1024/pipeline.py
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# BigCell pipeline. https://github.com/cvlab-stonybrook/BigCell
|
| 2 |
+
#
|
| 3 |
+
# Generates histopathology images from a grid of UNI-2 embeddings (one 1536-d token per 256x256 px at 20x).
|
| 4 |
+
# A grid that matches the model's native tile (e.g. 8x8 for BigCell-2048) is denoised directly; larger grids
|
| 5 |
+
# are generated with the sliding-window procedure of the paper (BigCell-large), optionally with adaptive
|
| 6 |
+
# window scheduling (``top_r < 1``). For multi-GPU generation of 16k-32k images use the GitHub scripts.
|
| 7 |
+
|
| 8 |
+
import math
|
| 9 |
+
from typing import List, Optional, Union
|
| 10 |
+
|
| 11 |
+
import numpy as np
|
| 12 |
+
import torch
|
| 13 |
+
from diffusers import DiffusionPipeline
|
| 14 |
+
from diffusers.image_processor import VaeImageProcessor
|
| 15 |
+
from diffusers.pipelines.pipeline_utils import ImagePipelineOutput
|
| 16 |
+
from diffusers.utils.torch_utils import randn_tensor
|
| 17 |
+
from PIL import Image
|
| 18 |
+
|
| 19 |
+
LATENTS_PER_TOKEN = 32 # one UNI-2 token covers 256 px = 32 Flux.2 latents
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def _gaussian_kernel(size, sigma, device):
|
| 23 |
+
x = torch.linspace(-1, 1, size)
|
| 24 |
+
x = torch.stack((x.tile(size, 1), x.tile(size, 1).T), dim=0)
|
| 25 |
+
k = torch.exp(-(torch.linalg.norm(x, dim=0) ** 2) / (2 * sigma**2))
|
| 26 |
+
return (k / k.max()).to(device)
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
class BigCellPipeline(DiffusionPipeline):
|
| 30 |
+
model_cpu_offload_seq = "transformer->vae"
|
| 31 |
+
|
| 32 |
+
def __init__(self, transformer, vae, scheduler):
|
| 33 |
+
super().__init__()
|
| 34 |
+
self.register_modules(transformer=transformer, vae=vae, scheduler=scheduler)
|
| 35 |
+
self.image_processor = VaeImageProcessor(vae_scale_factor=8)
|
| 36 |
+
|
| 37 |
+
@property
|
| 38 |
+
def tile_tokens(self):
|
| 39 |
+
"""Side of the UNI-2 grid covered by one native tile (1, 4 or 8)."""
|
| 40 |
+
return int(round(math.sqrt(self.transformer.config.num_caption_tokens)))
|
| 41 |
+
|
| 42 |
+
def get_unconditional_embedding(self, batch_size=1):
|
| 43 |
+
return self.transformer.unconditional_embedding.tile(batch_size, 1, 1)
|
| 44 |
+
|
| 45 |
+
def _velocity(self, x, t, y, guidance_scale):
|
| 46 |
+
"""Returns (cfg velocity, importance score |v_cond - v_uncond|)."""
|
| 47 |
+
null = self.get_unconditional_embedding(x.shape[0]).to(y.dtype)
|
| 48 |
+
v = self.transformer(torch.cat([x, x]), t.expand(2 * x.shape[0]), torch.cat([y, null])).float()
|
| 49 |
+
v_cond, v_uncond = v.chunk(2)
|
| 50 |
+
return v_uncond + guidance_scale * (v_cond - v_uncond), (v_cond - v_uncond).abs().mean().item()
|
| 51 |
+
|
| 52 |
+
def _sigmas(self, num_inference_steps, device):
|
| 53 |
+
self.scheduler.set_timesteps(sigmas=np.linspace(1.0, 0.0, num_inference_steps + 1)[:-1], device=device)
|
| 54 |
+
return self.scheduler.sigmas.to(device) # shifted, ends with 0
|
| 55 |
+
|
| 56 |
+
@torch.no_grad()
|
| 57 |
+
def _decode(self, latents, tile=256, sigma=0.5):
|
| 58 |
+
"""Tiled decode for large canvases (Gaussian-blended, accumulated on CPU)."""
|
| 59 |
+
_, _, h, w = latents.shape
|
| 60 |
+
dtype = self.vae.dtype
|
| 61 |
+
if h <= tile and w <= tile:
|
| 62 |
+
return self.vae.decode(latents.to(dtype)).sample.float().cpu()
|
| 63 |
+
out = torch.zeros(latents.shape[0], 3, h * 8, w * 8)
|
| 64 |
+
cnt = torch.zeros(1, 1, h * 8, w * 8)
|
| 65 |
+
kernel = _gaussian_kernel(tile * 8, sigma, "cpu")[None, None]
|
| 66 |
+
stride = tile // 2
|
| 67 |
+
for i in range(0, h - tile + 1, stride):
|
| 68 |
+
for j in range(0, w - tile + 1, stride):
|
| 69 |
+
dec = self.vae.decode(latents[:, :, i:i + tile, j:j + tile].to(dtype)).sample.float().cpu()
|
| 70 |
+
out[:, :, i * 8:(i + tile) * 8, j * 8:(j + tile) * 8] += dec * kernel
|
| 71 |
+
cnt[:, :, i * 8:(i + tile) * 8, j * 8:(j + tile) * 8] += kernel
|
| 72 |
+
return out / cnt.clamp(min=1e-6)
|
| 73 |
+
|
| 74 |
+
@torch.no_grad()
|
| 75 |
+
def __call__(
|
| 76 |
+
self,
|
| 77 |
+
uni_embeds: torch.Tensor,
|
| 78 |
+
num_inference_steps: int = 20,
|
| 79 |
+
guidance_scale: float = 2.0,
|
| 80 |
+
top_r: float = 1.0,
|
| 81 |
+
stride: Optional[int] = None,
|
| 82 |
+
window_sigma: float = 0.5,
|
| 83 |
+
generator: Optional[Union[torch.Generator, List[torch.Generator]]] = None,
|
| 84 |
+
latents: Optional[torch.Tensor] = None,
|
| 85 |
+
output_type: str = "pil",
|
| 86 |
+
return_dict: bool = True,
|
| 87 |
+
progress: bool = True,
|
| 88 |
+
):
|
| 89 |
+
"""
|
| 90 |
+
Args:
|
| 91 |
+
uni_embeds: UNI-2 grid of shape (B, Hg, Wg, 1536), or tokens of one native tile (B, T, 1536).
|
| 92 |
+
The output image is (256 * Hg) x (256 * Wg) pixels.
|
| 93 |
+
num_inference_steps: Euler steps (paper: 20).
|
| 94 |
+
guidance_scale: classifier-free guidance scale (paper: 2.0).
|
| 95 |
+
top_r: fraction of sliding windows recomputed at every step after the first (paper Sec. 3.3);
|
| 96 |
+
the rest reuse their cached velocity. 1.0 = full computation.
|
| 97 |
+
stride: window stride in latents (default: half a window, e.g. 128 = 1024 px for BigCell-2048).
|
| 98 |
+
window_sigma: width of the Gaussian window weighting.
|
| 99 |
+
output_type: "pil", "np" (uint8 HxWx3) or "latent".
|
| 100 |
+
"""
|
| 101 |
+
device = self._execution_device
|
| 102 |
+
dtype = self.transformer.dtype
|
| 103 |
+
tok = self.tile_tokens
|
| 104 |
+
if uni_embeds.ndim == 3: # (B, T, C) tokens of one tile -> grid
|
| 105 |
+
uni_embeds = uni_embeds.reshape(uni_embeds.shape[0], tok, tok, -1)
|
| 106 |
+
B, Hg, Wg, _ = uni_embeds.shape
|
| 107 |
+
if Hg < tok or Wg < tok:
|
| 108 |
+
raise ValueError(f"grid {Hg}x{Wg} is smaller than one tile ({tok}x{tok})")
|
| 109 |
+
uni_embeds = uni_embeds.to(device, dtype)
|
| 110 |
+
|
| 111 |
+
win = self.transformer.config.sample_size
|
| 112 |
+
H, W = Hg * LATENTS_PER_TOKEN, Wg * LATENTS_PER_TOKEN
|
| 113 |
+
stride = stride or win // 2
|
| 114 |
+
windows = [(h, w) for h in range(0, H - win + 1, stride) for w in range(0, W - win + 1, stride)]
|
| 115 |
+
kernel = _gaussian_kernel(win, window_sigma, device)
|
| 116 |
+
|
| 117 |
+
if latents is None:
|
| 118 |
+
latents = randn_tensor((B, self.transformer.config.in_channels, H, W), generator=generator,
|
| 119 |
+
device=device, dtype=torch.float32)
|
| 120 |
+
x = latents.to(device, torch.float32)
|
| 121 |
+
sigmas = self._sigmas(num_inference_steps, device)
|
| 122 |
+
|
| 123 |
+
n_select = len(windows) if top_r >= 1 else max(1, math.ceil(top_r * len(windows)))
|
| 124 |
+
importance = [dict() for _ in range(B)]
|
| 125 |
+
v_prev = torch.zeros_like(x)
|
| 126 |
+
with self.progress_bar(total=num_inference_steps) as pbar:
|
| 127 |
+
for step, (s_cur, s_next) in enumerate(zip(sigmas[:-1], sigmas[1:])):
|
| 128 |
+
t = s_cur.reshape(1).to(dtype)
|
| 129 |
+
v_new = v_prev.clone()
|
| 130 |
+
for b in range(B):
|
| 131 |
+
active = windows if step == 0 else sorted(windows, key=lambda w: -importance[b].get(w, 0.0))[:n_select]
|
| 132 |
+
v_sum = torch.zeros_like(x[b:b + 1])
|
| 133 |
+
w_sum = torch.zeros_like(x[b:b + 1])
|
| 134 |
+
for h, w in active:
|
| 135 |
+
y = uni_embeds[b:b + 1, h // 32:h // 32 + tok, w // 32:w // 32 + tok].reshape(1, tok * tok, -1)
|
| 136 |
+
v, score = self._velocity(x[b:b + 1, :, h:h + win, w:w + win].to(dtype), t, y, guidance_scale)
|
| 137 |
+
importance[b][(h, w)] = score
|
| 138 |
+
v_sum[:, :, h:h + win, w:w + win] += v * kernel
|
| 139 |
+
w_sum[:, :, h:h + win, w:w + win] += kernel
|
| 140 |
+
v_new[b:b + 1] = torch.where(w_sum > 0, v_sum / w_sum.clamp(min=1e-6), v_prev[b:b + 1])
|
| 141 |
+
v_prev = v_new
|
| 142 |
+
x = x + (s_next - s_cur) * v_new
|
| 143 |
+
if progress:
|
| 144 |
+
pbar.update()
|
| 145 |
+
|
| 146 |
+
if output_type == "latent":
|
| 147 |
+
return ImagePipelineOutput(images=x) if return_dict else (x,)
|
| 148 |
+
img = ((self._decode(x) + 1) / 2).clamp(0, 1)
|
| 149 |
+
img = (img.permute(0, 2, 3, 1) * 255).round().to(torch.uint8).numpy()
|
| 150 |
+
images = [Image.fromarray(i) for i in img] if output_type == "pil" else img
|
| 151 |
+
return ImagePipelineOutput(images=images) if return_dict else (images,)
|
bigcell-1024/scheduler/scheduler_config.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_class_name": "FlowMatchEulerDiscreteScheduler",
|
| 3 |
+
"_diffusers_version": "0.37.1",
|
| 4 |
+
"base_image_seq_len": 256,
|
| 5 |
+
"base_shift": 0.5,
|
| 6 |
+
"invert_sigmas": false,
|
| 7 |
+
"max_image_seq_len": 4096,
|
| 8 |
+
"max_shift": 1.15,
|
| 9 |
+
"num_train_timesteps": 1000,
|
| 10 |
+
"shift": 3.0,
|
| 11 |
+
"shift_terminal": null,
|
| 12 |
+
"stochastic_sampling": false,
|
| 13 |
+
"time_shift_type": "exponential",
|
| 14 |
+
"use_beta_sigmas": false,
|
| 15 |
+
"use_dynamic_shifting": false,
|
| 16 |
+
"use_exponential_sigmas": false,
|
| 17 |
+
"use_karras_sigmas": false
|
| 18 |
+
}
|
bigcell-1024/transformer/bigcell_transformer_2d.py
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# BigCell tile generator: a SiT flow-matching transformer conditioned on a grid of UNI-2 embeddings
|
| 2 |
+
# through cross-attention. https://github.com/cvlab-stonybrook/BigCell
|
| 3 |
+
#
|
| 4 |
+
# Adapted from SiT (https://github.com/willisma/SiT, MIT) and REPA-E (https://github.com/End2End-Diffusion/REPA-E, MIT).
|
| 5 |
+
|
| 6 |
+
import math
|
| 7 |
+
|
| 8 |
+
import numpy as np
|
| 9 |
+
import torch
|
| 10 |
+
import torch.nn as nn
|
| 11 |
+
import torch.nn.functional as F
|
| 12 |
+
from diffusers.configuration_utils import ConfigMixin, register_to_config
|
| 13 |
+
from diffusers.models.modeling_utils import ModelMixin
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def modulate(x, shift, scale):
|
| 17 |
+
return x * (1 + scale.unsqueeze(1)) + shift.unsqueeze(1)
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
class PatchEmbed(nn.Module):
|
| 21 |
+
def __init__(self, patch_size, in_channels, hidden_size):
|
| 22 |
+
super().__init__()
|
| 23 |
+
self.proj = nn.Conv2d(in_channels, hidden_size, kernel_size=patch_size, stride=patch_size, bias=True)
|
| 24 |
+
|
| 25 |
+
def forward(self, x):
|
| 26 |
+
return self.proj(x).flatten(2).transpose(1, 2)
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
class Mlp(nn.Module):
|
| 30 |
+
def __init__(self, in_features, hidden_features, out_features=None, approximate="none"):
|
| 31 |
+
super().__init__()
|
| 32 |
+
self.fc1 = nn.Linear(in_features, hidden_features)
|
| 33 |
+
self.act = nn.GELU(approximate=approximate)
|
| 34 |
+
self.fc2 = nn.Linear(hidden_features, out_features or in_features)
|
| 35 |
+
|
| 36 |
+
def forward(self, x):
|
| 37 |
+
return self.fc2(self.act(self.fc1(x)))
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
class Attention(nn.Module):
|
| 41 |
+
def __init__(self, dim, num_heads):
|
| 42 |
+
super().__init__()
|
| 43 |
+
self.num_heads = num_heads
|
| 44 |
+
self.qkv = nn.Linear(dim, dim * 3, bias=True)
|
| 45 |
+
self.proj = nn.Linear(dim, dim)
|
| 46 |
+
|
| 47 |
+
def forward(self, x):
|
| 48 |
+
B, N, C = x.shape
|
| 49 |
+
q, k, v = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4).unbind(0)
|
| 50 |
+
x = F.scaled_dot_product_attention(q, k, v)
|
| 51 |
+
return self.proj(x.transpose(1, 2).reshape(B, N, C))
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
class CrossAttention(nn.Module):
|
| 55 |
+
def __init__(self, dim, num_heads):
|
| 56 |
+
super().__init__()
|
| 57 |
+
self.num_heads = num_heads
|
| 58 |
+
self.q_linear = nn.Linear(dim, dim)
|
| 59 |
+
self.kv_linear = nn.Linear(dim, dim * 2)
|
| 60 |
+
self.proj = nn.Linear(dim, dim)
|
| 61 |
+
|
| 62 |
+
def forward(self, x, cond):
|
| 63 |
+
B, N, C = x.shape
|
| 64 |
+
h = self.num_heads
|
| 65 |
+
q = self.q_linear(x).reshape(B, N, h, C // h).transpose(1, 2)
|
| 66 |
+
k, v = self.kv_linear(cond).reshape(B, cond.shape[1], 2, h, C // h).permute(2, 0, 3, 1, 4).unbind(0)
|
| 67 |
+
x = F.scaled_dot_product_attention(q, k, v)
|
| 68 |
+
return self.proj(x.transpose(1, 2).reshape(B, N, C))
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
class TimestepEmbedder(nn.Module):
|
| 72 |
+
def __init__(self, hidden_size, frequency_embedding_size=256):
|
| 73 |
+
super().__init__()
|
| 74 |
+
self.mlp = nn.Sequential(
|
| 75 |
+
nn.Linear(frequency_embedding_size, hidden_size, bias=True),
|
| 76 |
+
nn.SiLU(),
|
| 77 |
+
nn.Linear(hidden_size, hidden_size, bias=True),
|
| 78 |
+
)
|
| 79 |
+
self.frequency_embedding_size = frequency_embedding_size
|
| 80 |
+
|
| 81 |
+
def forward(self, t):
|
| 82 |
+
half = self.frequency_embedding_size // 2
|
| 83 |
+
freqs = torch.exp(-math.log(10000) * torch.arange(half, dtype=torch.float32, device=t.device) / half)
|
| 84 |
+
args = t[:, None].float() * freqs[None]
|
| 85 |
+
return self.mlp(torch.cat([torch.cos(args), torch.sin(args)], dim=-1).to(t.dtype))
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
class CaptionEmbedder(nn.Module):
|
| 89 |
+
"""Projects UNI-2 tokens; ``y_embedding`` is the learned unconditional embedding used for CFG."""
|
| 90 |
+
|
| 91 |
+
def __init__(self, in_channels, hidden_size, token_num):
|
| 92 |
+
super().__init__()
|
| 93 |
+
self.y_proj = Mlp(in_channels, hidden_size, hidden_size, approximate="tanh")
|
| 94 |
+
self.register_buffer("y_embedding", torch.randn(token_num, in_channels) / in_channels**0.5)
|
| 95 |
+
|
| 96 |
+
def forward(self, caption):
|
| 97 |
+
return self.y_proj(caption)
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
class BigCellBlock(nn.Module):
|
| 101 |
+
def __init__(self, hidden_size, num_heads, mlp_ratio=4.0):
|
| 102 |
+
super().__init__()
|
| 103 |
+
self.norm1 = nn.LayerNorm(hidden_size, elementwise_affine=False, eps=1e-6)
|
| 104 |
+
self.attn = Attention(hidden_size, num_heads)
|
| 105 |
+
self.cross_attn = CrossAttention(hidden_size, num_heads)
|
| 106 |
+
self.norm2 = nn.LayerNorm(hidden_size, elementwise_affine=False, eps=1e-6)
|
| 107 |
+
self.mlp = Mlp(hidden_size, int(hidden_size * mlp_ratio), approximate="tanh")
|
| 108 |
+
self.adaLN_modulation = nn.Sequential(nn.SiLU(), nn.Linear(hidden_size, 6 * hidden_size, bias=True))
|
| 109 |
+
|
| 110 |
+
def forward(self, x, cond, t):
|
| 111 |
+
shift_msa, scale_msa, gate_msa, shift_mlp, scale_mlp, gate_mlp = self.adaLN_modulation(t).chunk(6, dim=-1)
|
| 112 |
+
x = x + gate_msa.unsqueeze(1) * self.attn(modulate(self.norm1(x), shift_msa, scale_msa))
|
| 113 |
+
x = x + self.cross_attn(x, cond)
|
| 114 |
+
x = x + gate_mlp.unsqueeze(1) * self.mlp(modulate(self.norm2(x), shift_mlp, scale_mlp))
|
| 115 |
+
return x
|
| 116 |
+
|
| 117 |
+
|
| 118 |
+
class FinalLayer(nn.Module):
|
| 119 |
+
def __init__(self, hidden_size, patch_size, out_channels):
|
| 120 |
+
super().__init__()
|
| 121 |
+
self.norm_final = nn.LayerNorm(hidden_size, elementwise_affine=False, eps=1e-6)
|
| 122 |
+
self.linear = nn.Linear(hidden_size, patch_size * patch_size * out_channels, bias=True)
|
| 123 |
+
self.adaLN_modulation = nn.Sequential(nn.SiLU(), nn.Linear(hidden_size, 2 * hidden_size, bias=True))
|
| 124 |
+
|
| 125 |
+
def forward(self, x, c):
|
| 126 |
+
shift, scale = self.adaLN_modulation(c).chunk(2, dim=-1)
|
| 127 |
+
return self.linear(modulate(self.norm_final(x), shift, scale))
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
class BigCellTransformer2DModel(ModelMixin, ConfigMixin):
|
| 131 |
+
"""SiT-XL/2 velocity predictor operating on Flux.2 VAE latents (32 channels, 8x downsampling).
|
| 132 |
+
|
| 133 |
+
Args:
|
| 134 |
+
sample_size: latent side length (tile resolution // 8).
|
| 135 |
+
num_caption_tokens: number of UNI-2 tokens per tile, (tile resolution // 256) ** 2.
|
| 136 |
+
alpha_shift: time shift used during training; the scheduler uses the same value.
|
| 137 |
+
"""
|
| 138 |
+
|
| 139 |
+
@register_to_config
|
| 140 |
+
def __init__(
|
| 141 |
+
self,
|
| 142 |
+
sample_size: int = 256,
|
| 143 |
+
patch_size: int = 2,
|
| 144 |
+
in_channels: int = 32,
|
| 145 |
+
hidden_size: int = 1152,
|
| 146 |
+
num_layers: int = 28,
|
| 147 |
+
num_attention_heads: int = 16,
|
| 148 |
+
mlp_ratio: float = 4.0,
|
| 149 |
+
caption_channels: int = 1536,
|
| 150 |
+
num_caption_tokens: int = 64,
|
| 151 |
+
alpha_shift: float = 1.0,
|
| 152 |
+
):
|
| 153 |
+
super().__init__()
|
| 154 |
+
self.x_embedder = PatchEmbed(patch_size, in_channels, hidden_size)
|
| 155 |
+
self.t_embedder = TimestepEmbedder(hidden_size)
|
| 156 |
+
self.y_embedder = CaptionEmbedder(caption_channels, hidden_size, num_caption_tokens)
|
| 157 |
+
num_patches = (sample_size // patch_size) ** 2
|
| 158 |
+
self.pos_embed = nn.Parameter(torch.zeros(1, num_patches, hidden_size), requires_grad=False)
|
| 159 |
+
grid = int(num_caption_tokens**0.5)
|
| 160 |
+
if num_caption_tokens > 1 and grid**2 == num_caption_tokens:
|
| 161 |
+
self.y_pos_embed = nn.Parameter(torch.zeros(1, num_caption_tokens, hidden_size), requires_grad=False)
|
| 162 |
+
else:
|
| 163 |
+
self.y_pos_embed = None
|
| 164 |
+
self.blocks = nn.ModuleList(
|
| 165 |
+
[BigCellBlock(hidden_size, num_attention_heads, mlp_ratio) for _ in range(num_layers)]
|
| 166 |
+
)
|
| 167 |
+
self.final_layer = FinalLayer(hidden_size, patch_size, in_channels)
|
| 168 |
+
pos = _sincos_2d(hidden_size, np.stack(np.meshgrid(np.arange(sample_size // patch_size),
|
| 169 |
+
np.arange(sample_size // patch_size)), 0).reshape(2, -1))
|
| 170 |
+
self.pos_embed.data.copy_(torch.from_numpy(pos).float()[None])
|
| 171 |
+
|
| 172 |
+
@property
|
| 173 |
+
def unconditional_embedding(self):
|
| 174 |
+
"""(1, T, 1536) learned null condition for classifier-free guidance."""
|
| 175 |
+
return self.y_embedder.y_embedding[None]
|
| 176 |
+
|
| 177 |
+
def unpatchify(self, x):
|
| 178 |
+
c, p = self.config.in_channels, self.config.patch_size
|
| 179 |
+
h = w = int(x.shape[1] ** 0.5)
|
| 180 |
+
x = torch.einsum("nhwpqc->nchpwq", x.reshape(x.shape[0], h, w, p, p, c))
|
| 181 |
+
return x.reshape(x.shape[0], c, h * p, w * p)
|
| 182 |
+
|
| 183 |
+
def forward(self, hidden_states, timestep, encoder_hidden_states):
|
| 184 |
+
"""hidden_states: (B, 32, H, W) noisy latent; timestep: (B,) in [0, 1] (1 = pure noise);
|
| 185 |
+
encoder_hidden_states: (B, T, 1536) UNI-2 tokens in raster order. Returns the velocity (noise - data)."""
|
| 186 |
+
x = self.x_embedder(hidden_states) + self.pos_embed
|
| 187 |
+
t = self.t_embedder(timestep)
|
| 188 |
+
y = self.y_embedder(encoder_hidden_states)
|
| 189 |
+
if self.y_pos_embed is not None:
|
| 190 |
+
y = y + self.y_pos_embed
|
| 191 |
+
for block in self.blocks:
|
| 192 |
+
x = block(x, y, t)
|
| 193 |
+
return self.unpatchify(self.final_layer(x, t))
|
| 194 |
+
|
| 195 |
+
|
| 196 |
+
def _sincos_2d(embed_dim, grid):
|
| 197 |
+
def one_d(dim, pos):
|
| 198 |
+
omega = 1.0 / 10000 ** (np.arange(dim // 2, dtype=np.float64) / (dim / 2.0))
|
| 199 |
+
out = np.einsum("m,d->md", pos.reshape(-1), omega)
|
| 200 |
+
return np.concatenate([np.sin(out), np.cos(out)], axis=1)
|
| 201 |
+
|
| 202 |
+
return np.concatenate([one_d(embed_dim // 2, grid[0]), one_d(embed_dim // 2, grid[1])], axis=1)
|
bigcell-1024/transformer/config.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_class_name": "BigCellTransformer2DModel",
|
| 3 |
+
"_diffusers_version": "0.37.1",
|
| 4 |
+
"alpha_shift": 3.0,
|
| 5 |
+
"caption_channels": 1536,
|
| 6 |
+
"hidden_size": 1152,
|
| 7 |
+
"in_channels": 32,
|
| 8 |
+
"mlp_ratio": 4.0,
|
| 9 |
+
"num_attention_heads": 16,
|
| 10 |
+
"num_caption_tokens": 16,
|
| 11 |
+
"num_layers": 28,
|
| 12 |
+
"patch_size": 2,
|
| 13 |
+
"sample_size": 128
|
| 14 |
+
}
|
bigcell-1024/transformer/diffusion_pytorch_model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:7e13cd2c48e9a4e7673e1cc9da626ee9842e5abbb22ba7b6036993d5015567b1
|
| 3 |
+
size 3322233744
|
bigcell-1024/vae/config.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_class_name": "AutoencoderKLFlux2",
|
| 3 |
+
"_diffusers_version": "0.36.0.dev0",
|
| 4 |
+
"act_fn": "silu",
|
| 5 |
+
"batch_norm_eps": 0.0001,
|
| 6 |
+
"batch_norm_momentum": 0.1,
|
| 7 |
+
"block_out_channels": [
|
| 8 |
+
128,
|
| 9 |
+
256,
|
| 10 |
+
512,
|
| 11 |
+
512
|
| 12 |
+
],
|
| 13 |
+
"down_block_types": [
|
| 14 |
+
"DownEncoderBlock2D",
|
| 15 |
+
"DownEncoderBlock2D",
|
| 16 |
+
"DownEncoderBlock2D",
|
| 17 |
+
"DownEncoderBlock2D"
|
| 18 |
+
],
|
| 19 |
+
"force_upcast": true,
|
| 20 |
+
"in_channels": 3,
|
| 21 |
+
"latent_channels": 32,
|
| 22 |
+
"layers_per_block": 2,
|
| 23 |
+
"mid_block_add_attention": true,
|
| 24 |
+
"norm_num_groups": 32,
|
| 25 |
+
"out_channels": 3,
|
| 26 |
+
"patch_size": [
|
| 27 |
+
2,
|
| 28 |
+
2
|
| 29 |
+
],
|
| 30 |
+
"sample_size": 1024,
|
| 31 |
+
"up_block_types": [
|
| 32 |
+
"UpDecoderBlock2D",
|
| 33 |
+
"UpDecoderBlock2D",
|
| 34 |
+
"UpDecoderBlock2D",
|
| 35 |
+
"UpDecoderBlock2D"
|
| 36 |
+
],
|
| 37 |
+
"use_post_quant_conv": true,
|
| 38 |
+
"use_quant_conv": true,
|
| 39 |
+
"_name_or_path": "black-forest-labs/FLUX.2-dev"
|
| 40 |
+
}
|
bigcell-2048/model_index.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_class_name": [
|
| 3 |
+
"pipeline",
|
| 4 |
+
"BigCellPipeline"
|
| 5 |
+
],
|
| 6 |
+
"_diffusers_version": "0.37.1",
|
| 7 |
+
"transformer": [
|
| 8 |
+
"bigcell_transformer_2d",
|
| 9 |
+
"BigCellTransformer2DModel"
|
| 10 |
+
],
|
| 11 |
+
"vae": [
|
| 12 |
+
"diffusers",
|
| 13 |
+
"AutoencoderKLFlux2"
|
| 14 |
+
],
|
| 15 |
+
"scheduler": [
|
| 16 |
+
"diffusers",
|
| 17 |
+
"FlowMatchEulerDiscreteScheduler"
|
| 18 |
+
]
|
| 19 |
+
}
|
bigcell-2048/pipeline.py
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# BigCell pipeline. https://github.com/cvlab-stonybrook/BigCell
|
| 2 |
+
#
|
| 3 |
+
# Generates histopathology images from a grid of UNI-2 embeddings (one 1536-d token per 256x256 px at 20x).
|
| 4 |
+
# A grid that matches the model's native tile (e.g. 8x8 for BigCell-2048) is denoised directly; larger grids
|
| 5 |
+
# are generated with the sliding-window procedure of the paper (BigCell-large), optionally with adaptive
|
| 6 |
+
# window scheduling (``top_r < 1``). For multi-GPU generation of 16k-32k images use the GitHub scripts.
|
| 7 |
+
|
| 8 |
+
import math
|
| 9 |
+
from typing import List, Optional, Union
|
| 10 |
+
|
| 11 |
+
import numpy as np
|
| 12 |
+
import torch
|
| 13 |
+
from diffusers import DiffusionPipeline
|
| 14 |
+
from diffusers.image_processor import VaeImageProcessor
|
| 15 |
+
from diffusers.pipelines.pipeline_utils import ImagePipelineOutput
|
| 16 |
+
from diffusers.utils.torch_utils import randn_tensor
|
| 17 |
+
from PIL import Image
|
| 18 |
+
|
| 19 |
+
LATENTS_PER_TOKEN = 32 # one UNI-2 token covers 256 px = 32 Flux.2 latents
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def _gaussian_kernel(size, sigma, device):
|
| 23 |
+
x = torch.linspace(-1, 1, size)
|
| 24 |
+
x = torch.stack((x.tile(size, 1), x.tile(size, 1).T), dim=0)
|
| 25 |
+
k = torch.exp(-(torch.linalg.norm(x, dim=0) ** 2) / (2 * sigma**2))
|
| 26 |
+
return (k / k.max()).to(device)
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
class BigCellPipeline(DiffusionPipeline):
|
| 30 |
+
model_cpu_offload_seq = "transformer->vae"
|
| 31 |
+
|
| 32 |
+
def __init__(self, transformer, vae, scheduler):
|
| 33 |
+
super().__init__()
|
| 34 |
+
self.register_modules(transformer=transformer, vae=vae, scheduler=scheduler)
|
| 35 |
+
self.image_processor = VaeImageProcessor(vae_scale_factor=8)
|
| 36 |
+
|
| 37 |
+
@property
|
| 38 |
+
def tile_tokens(self):
|
| 39 |
+
"""Side of the UNI-2 grid covered by one native tile (1, 4 or 8)."""
|
| 40 |
+
return int(round(math.sqrt(self.transformer.config.num_caption_tokens)))
|
| 41 |
+
|
| 42 |
+
def get_unconditional_embedding(self, batch_size=1):
|
| 43 |
+
return self.transformer.unconditional_embedding.tile(batch_size, 1, 1)
|
| 44 |
+
|
| 45 |
+
def _velocity(self, x, t, y, guidance_scale):
|
| 46 |
+
"""Returns (cfg velocity, importance score |v_cond - v_uncond|)."""
|
| 47 |
+
null = self.get_unconditional_embedding(x.shape[0]).to(y.dtype)
|
| 48 |
+
v = self.transformer(torch.cat([x, x]), t.expand(2 * x.shape[0]), torch.cat([y, null])).float()
|
| 49 |
+
v_cond, v_uncond = v.chunk(2)
|
| 50 |
+
return v_uncond + guidance_scale * (v_cond - v_uncond), (v_cond - v_uncond).abs().mean().item()
|
| 51 |
+
|
| 52 |
+
def _sigmas(self, num_inference_steps, device):
|
| 53 |
+
self.scheduler.set_timesteps(sigmas=np.linspace(1.0, 0.0, num_inference_steps + 1)[:-1], device=device)
|
| 54 |
+
return self.scheduler.sigmas.to(device) # shifted, ends with 0
|
| 55 |
+
|
| 56 |
+
@torch.no_grad()
|
| 57 |
+
def _decode(self, latents, tile=256, sigma=0.5):
|
| 58 |
+
"""Tiled decode for large canvases (Gaussian-blended, accumulated on CPU)."""
|
| 59 |
+
_, _, h, w = latents.shape
|
| 60 |
+
dtype = self.vae.dtype
|
| 61 |
+
if h <= tile and w <= tile:
|
| 62 |
+
return self.vae.decode(latents.to(dtype)).sample.float().cpu()
|
| 63 |
+
out = torch.zeros(latents.shape[0], 3, h * 8, w * 8)
|
| 64 |
+
cnt = torch.zeros(1, 1, h * 8, w * 8)
|
| 65 |
+
kernel = _gaussian_kernel(tile * 8, sigma, "cpu")[None, None]
|
| 66 |
+
stride = tile // 2
|
| 67 |
+
for i in range(0, h - tile + 1, stride):
|
| 68 |
+
for j in range(0, w - tile + 1, stride):
|
| 69 |
+
dec = self.vae.decode(latents[:, :, i:i + tile, j:j + tile].to(dtype)).sample.float().cpu()
|
| 70 |
+
out[:, :, i * 8:(i + tile) * 8, j * 8:(j + tile) * 8] += dec * kernel
|
| 71 |
+
cnt[:, :, i * 8:(i + tile) * 8, j * 8:(j + tile) * 8] += kernel
|
| 72 |
+
return out / cnt.clamp(min=1e-6)
|
| 73 |
+
|
| 74 |
+
@torch.no_grad()
|
| 75 |
+
def __call__(
|
| 76 |
+
self,
|
| 77 |
+
uni_embeds: torch.Tensor,
|
| 78 |
+
num_inference_steps: int = 20,
|
| 79 |
+
guidance_scale: float = 2.0,
|
| 80 |
+
top_r: float = 1.0,
|
| 81 |
+
stride: Optional[int] = None,
|
| 82 |
+
window_sigma: float = 0.5,
|
| 83 |
+
generator: Optional[Union[torch.Generator, List[torch.Generator]]] = None,
|
| 84 |
+
latents: Optional[torch.Tensor] = None,
|
| 85 |
+
output_type: str = "pil",
|
| 86 |
+
return_dict: bool = True,
|
| 87 |
+
progress: bool = True,
|
| 88 |
+
):
|
| 89 |
+
"""
|
| 90 |
+
Args:
|
| 91 |
+
uni_embeds: UNI-2 grid of shape (B, Hg, Wg, 1536), or tokens of one native tile (B, T, 1536).
|
| 92 |
+
The output image is (256 * Hg) x (256 * Wg) pixels.
|
| 93 |
+
num_inference_steps: Euler steps (paper: 20).
|
| 94 |
+
guidance_scale: classifier-free guidance scale (paper: 2.0).
|
| 95 |
+
top_r: fraction of sliding windows recomputed at every step after the first (paper Sec. 3.3);
|
| 96 |
+
the rest reuse their cached velocity. 1.0 = full computation.
|
| 97 |
+
stride: window stride in latents (default: half a window, e.g. 128 = 1024 px for BigCell-2048).
|
| 98 |
+
window_sigma: width of the Gaussian window weighting.
|
| 99 |
+
output_type: "pil", "np" (uint8 HxWx3) or "latent".
|
| 100 |
+
"""
|
| 101 |
+
device = self._execution_device
|
| 102 |
+
dtype = self.transformer.dtype
|
| 103 |
+
tok = self.tile_tokens
|
| 104 |
+
if uni_embeds.ndim == 3: # (B, T, C) tokens of one tile -> grid
|
| 105 |
+
uni_embeds = uni_embeds.reshape(uni_embeds.shape[0], tok, tok, -1)
|
| 106 |
+
B, Hg, Wg, _ = uni_embeds.shape
|
| 107 |
+
if Hg < tok or Wg < tok:
|
| 108 |
+
raise ValueError(f"grid {Hg}x{Wg} is smaller than one tile ({tok}x{tok})")
|
| 109 |
+
uni_embeds = uni_embeds.to(device, dtype)
|
| 110 |
+
|
| 111 |
+
win = self.transformer.config.sample_size
|
| 112 |
+
H, W = Hg * LATENTS_PER_TOKEN, Wg * LATENTS_PER_TOKEN
|
| 113 |
+
stride = stride or win // 2
|
| 114 |
+
windows = [(h, w) for h in range(0, H - win + 1, stride) for w in range(0, W - win + 1, stride)]
|
| 115 |
+
kernel = _gaussian_kernel(win, window_sigma, device)
|
| 116 |
+
|
| 117 |
+
if latents is None:
|
| 118 |
+
latents = randn_tensor((B, self.transformer.config.in_channels, H, W), generator=generator,
|
| 119 |
+
device=device, dtype=torch.float32)
|
| 120 |
+
x = latents.to(device, torch.float32)
|
| 121 |
+
sigmas = self._sigmas(num_inference_steps, device)
|
| 122 |
+
|
| 123 |
+
n_select = len(windows) if top_r >= 1 else max(1, math.ceil(top_r * len(windows)))
|
| 124 |
+
importance = [dict() for _ in range(B)]
|
| 125 |
+
v_prev = torch.zeros_like(x)
|
| 126 |
+
with self.progress_bar(total=num_inference_steps) as pbar:
|
| 127 |
+
for step, (s_cur, s_next) in enumerate(zip(sigmas[:-1], sigmas[1:])):
|
| 128 |
+
t = s_cur.reshape(1).to(dtype)
|
| 129 |
+
v_new = v_prev.clone()
|
| 130 |
+
for b in range(B):
|
| 131 |
+
active = windows if step == 0 else sorted(windows, key=lambda w: -importance[b].get(w, 0.0))[:n_select]
|
| 132 |
+
v_sum = torch.zeros_like(x[b:b + 1])
|
| 133 |
+
w_sum = torch.zeros_like(x[b:b + 1])
|
| 134 |
+
for h, w in active:
|
| 135 |
+
y = uni_embeds[b:b + 1, h // 32:h // 32 + tok, w // 32:w // 32 + tok].reshape(1, tok * tok, -1)
|
| 136 |
+
v, score = self._velocity(x[b:b + 1, :, h:h + win, w:w + win].to(dtype), t, y, guidance_scale)
|
| 137 |
+
importance[b][(h, w)] = score
|
| 138 |
+
v_sum[:, :, h:h + win, w:w + win] += v * kernel
|
| 139 |
+
w_sum[:, :, h:h + win, w:w + win] += kernel
|
| 140 |
+
v_new[b:b + 1] = torch.where(w_sum > 0, v_sum / w_sum.clamp(min=1e-6), v_prev[b:b + 1])
|
| 141 |
+
v_prev = v_new
|
| 142 |
+
x = x + (s_next - s_cur) * v_new
|
| 143 |
+
if progress:
|
| 144 |
+
pbar.update()
|
| 145 |
+
|
| 146 |
+
if output_type == "latent":
|
| 147 |
+
return ImagePipelineOutput(images=x) if return_dict else (x,)
|
| 148 |
+
img = ((self._decode(x) + 1) / 2).clamp(0, 1)
|
| 149 |
+
img = (img.permute(0, 2, 3, 1) * 255).round().to(torch.uint8).numpy()
|
| 150 |
+
images = [Image.fromarray(i) for i in img] if output_type == "pil" else img
|
| 151 |
+
return ImagePipelineOutput(images=images) if return_dict else (images,)
|
bigcell-2048/scheduler/scheduler_config.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_class_name": "FlowMatchEulerDiscreteScheduler",
|
| 3 |
+
"_diffusers_version": "0.37.1",
|
| 4 |
+
"base_image_seq_len": 256,
|
| 5 |
+
"base_shift": 0.5,
|
| 6 |
+
"invert_sigmas": false,
|
| 7 |
+
"max_image_seq_len": 4096,
|
| 8 |
+
"max_shift": 1.15,
|
| 9 |
+
"num_train_timesteps": 1000,
|
| 10 |
+
"shift": 3.0,
|
| 11 |
+
"shift_terminal": null,
|
| 12 |
+
"stochastic_sampling": false,
|
| 13 |
+
"time_shift_type": "exponential",
|
| 14 |
+
"use_beta_sigmas": false,
|
| 15 |
+
"use_dynamic_shifting": false,
|
| 16 |
+
"use_exponential_sigmas": false,
|
| 17 |
+
"use_karras_sigmas": false
|
| 18 |
+
}
|
bigcell-2048/transformer/bigcell_transformer_2d.py
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# BigCell tile generator: a SiT flow-matching transformer conditioned on a grid of UNI-2 embeddings
|
| 2 |
+
# through cross-attention. https://github.com/cvlab-stonybrook/BigCell
|
| 3 |
+
#
|
| 4 |
+
# Adapted from SiT (https://github.com/willisma/SiT, MIT) and REPA-E (https://github.com/End2End-Diffusion/REPA-E, MIT).
|
| 5 |
+
|
| 6 |
+
import math
|
| 7 |
+
|
| 8 |
+
import numpy as np
|
| 9 |
+
import torch
|
| 10 |
+
import torch.nn as nn
|
| 11 |
+
import torch.nn.functional as F
|
| 12 |
+
from diffusers.configuration_utils import ConfigMixin, register_to_config
|
| 13 |
+
from diffusers.models.modeling_utils import ModelMixin
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def modulate(x, shift, scale):
|
| 17 |
+
return x * (1 + scale.unsqueeze(1)) + shift.unsqueeze(1)
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
class PatchEmbed(nn.Module):
|
| 21 |
+
def __init__(self, patch_size, in_channels, hidden_size):
|
| 22 |
+
super().__init__()
|
| 23 |
+
self.proj = nn.Conv2d(in_channels, hidden_size, kernel_size=patch_size, stride=patch_size, bias=True)
|
| 24 |
+
|
| 25 |
+
def forward(self, x):
|
| 26 |
+
return self.proj(x).flatten(2).transpose(1, 2)
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
class Mlp(nn.Module):
|
| 30 |
+
def __init__(self, in_features, hidden_features, out_features=None, approximate="none"):
|
| 31 |
+
super().__init__()
|
| 32 |
+
self.fc1 = nn.Linear(in_features, hidden_features)
|
| 33 |
+
self.act = nn.GELU(approximate=approximate)
|
| 34 |
+
self.fc2 = nn.Linear(hidden_features, out_features or in_features)
|
| 35 |
+
|
| 36 |
+
def forward(self, x):
|
| 37 |
+
return self.fc2(self.act(self.fc1(x)))
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
class Attention(nn.Module):
|
| 41 |
+
def __init__(self, dim, num_heads):
|
| 42 |
+
super().__init__()
|
| 43 |
+
self.num_heads = num_heads
|
| 44 |
+
self.qkv = nn.Linear(dim, dim * 3, bias=True)
|
| 45 |
+
self.proj = nn.Linear(dim, dim)
|
| 46 |
+
|
| 47 |
+
def forward(self, x):
|
| 48 |
+
B, N, C = x.shape
|
| 49 |
+
q, k, v = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4).unbind(0)
|
| 50 |
+
x = F.scaled_dot_product_attention(q, k, v)
|
| 51 |
+
return self.proj(x.transpose(1, 2).reshape(B, N, C))
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
class CrossAttention(nn.Module):
|
| 55 |
+
def __init__(self, dim, num_heads):
|
| 56 |
+
super().__init__()
|
| 57 |
+
self.num_heads = num_heads
|
| 58 |
+
self.q_linear = nn.Linear(dim, dim)
|
| 59 |
+
self.kv_linear = nn.Linear(dim, dim * 2)
|
| 60 |
+
self.proj = nn.Linear(dim, dim)
|
| 61 |
+
|
| 62 |
+
def forward(self, x, cond):
|
| 63 |
+
B, N, C = x.shape
|
| 64 |
+
h = self.num_heads
|
| 65 |
+
q = self.q_linear(x).reshape(B, N, h, C // h).transpose(1, 2)
|
| 66 |
+
k, v = self.kv_linear(cond).reshape(B, cond.shape[1], 2, h, C // h).permute(2, 0, 3, 1, 4).unbind(0)
|
| 67 |
+
x = F.scaled_dot_product_attention(q, k, v)
|
| 68 |
+
return self.proj(x.transpose(1, 2).reshape(B, N, C))
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
class TimestepEmbedder(nn.Module):
|
| 72 |
+
def __init__(self, hidden_size, frequency_embedding_size=256):
|
| 73 |
+
super().__init__()
|
| 74 |
+
self.mlp = nn.Sequential(
|
| 75 |
+
nn.Linear(frequency_embedding_size, hidden_size, bias=True),
|
| 76 |
+
nn.SiLU(),
|
| 77 |
+
nn.Linear(hidden_size, hidden_size, bias=True),
|
| 78 |
+
)
|
| 79 |
+
self.frequency_embedding_size = frequency_embedding_size
|
| 80 |
+
|
| 81 |
+
def forward(self, t):
|
| 82 |
+
half = self.frequency_embedding_size // 2
|
| 83 |
+
freqs = torch.exp(-math.log(10000) * torch.arange(half, dtype=torch.float32, device=t.device) / half)
|
| 84 |
+
args = t[:, None].float() * freqs[None]
|
| 85 |
+
return self.mlp(torch.cat([torch.cos(args), torch.sin(args)], dim=-1).to(t.dtype))
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
class CaptionEmbedder(nn.Module):
|
| 89 |
+
"""Projects UNI-2 tokens; ``y_embedding`` is the learned unconditional embedding used for CFG."""
|
| 90 |
+
|
| 91 |
+
def __init__(self, in_channels, hidden_size, token_num):
|
| 92 |
+
super().__init__()
|
| 93 |
+
self.y_proj = Mlp(in_channels, hidden_size, hidden_size, approximate="tanh")
|
| 94 |
+
self.register_buffer("y_embedding", torch.randn(token_num, in_channels) / in_channels**0.5)
|
| 95 |
+
|
| 96 |
+
def forward(self, caption):
|
| 97 |
+
return self.y_proj(caption)
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
class BigCellBlock(nn.Module):
|
| 101 |
+
def __init__(self, hidden_size, num_heads, mlp_ratio=4.0):
|
| 102 |
+
super().__init__()
|
| 103 |
+
self.norm1 = nn.LayerNorm(hidden_size, elementwise_affine=False, eps=1e-6)
|
| 104 |
+
self.attn = Attention(hidden_size, num_heads)
|
| 105 |
+
self.cross_attn = CrossAttention(hidden_size, num_heads)
|
| 106 |
+
self.norm2 = nn.LayerNorm(hidden_size, elementwise_affine=False, eps=1e-6)
|
| 107 |
+
self.mlp = Mlp(hidden_size, int(hidden_size * mlp_ratio), approximate="tanh")
|
| 108 |
+
self.adaLN_modulation = nn.Sequential(nn.SiLU(), nn.Linear(hidden_size, 6 * hidden_size, bias=True))
|
| 109 |
+
|
| 110 |
+
def forward(self, x, cond, t):
|
| 111 |
+
shift_msa, scale_msa, gate_msa, shift_mlp, scale_mlp, gate_mlp = self.adaLN_modulation(t).chunk(6, dim=-1)
|
| 112 |
+
x = x + gate_msa.unsqueeze(1) * self.attn(modulate(self.norm1(x), shift_msa, scale_msa))
|
| 113 |
+
x = x + self.cross_attn(x, cond)
|
| 114 |
+
x = x + gate_mlp.unsqueeze(1) * self.mlp(modulate(self.norm2(x), shift_mlp, scale_mlp))
|
| 115 |
+
return x
|
| 116 |
+
|
| 117 |
+
|
| 118 |
+
class FinalLayer(nn.Module):
|
| 119 |
+
def __init__(self, hidden_size, patch_size, out_channels):
|
| 120 |
+
super().__init__()
|
| 121 |
+
self.norm_final = nn.LayerNorm(hidden_size, elementwise_affine=False, eps=1e-6)
|
| 122 |
+
self.linear = nn.Linear(hidden_size, patch_size * patch_size * out_channels, bias=True)
|
| 123 |
+
self.adaLN_modulation = nn.Sequential(nn.SiLU(), nn.Linear(hidden_size, 2 * hidden_size, bias=True))
|
| 124 |
+
|
| 125 |
+
def forward(self, x, c):
|
| 126 |
+
shift, scale = self.adaLN_modulation(c).chunk(2, dim=-1)
|
| 127 |
+
return self.linear(modulate(self.norm_final(x), shift, scale))
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
class BigCellTransformer2DModel(ModelMixin, ConfigMixin):
|
| 131 |
+
"""SiT-XL/2 velocity predictor operating on Flux.2 VAE latents (32 channels, 8x downsampling).
|
| 132 |
+
|
| 133 |
+
Args:
|
| 134 |
+
sample_size: latent side length (tile resolution // 8).
|
| 135 |
+
num_caption_tokens: number of UNI-2 tokens per tile, (tile resolution // 256) ** 2.
|
| 136 |
+
alpha_shift: time shift used during training; the scheduler uses the same value.
|
| 137 |
+
"""
|
| 138 |
+
|
| 139 |
+
@register_to_config
|
| 140 |
+
def __init__(
|
| 141 |
+
self,
|
| 142 |
+
sample_size: int = 256,
|
| 143 |
+
patch_size: int = 2,
|
| 144 |
+
in_channels: int = 32,
|
| 145 |
+
hidden_size: int = 1152,
|
| 146 |
+
num_layers: int = 28,
|
| 147 |
+
num_attention_heads: int = 16,
|
| 148 |
+
mlp_ratio: float = 4.0,
|
| 149 |
+
caption_channels: int = 1536,
|
| 150 |
+
num_caption_tokens: int = 64,
|
| 151 |
+
alpha_shift: float = 1.0,
|
| 152 |
+
):
|
| 153 |
+
super().__init__()
|
| 154 |
+
self.x_embedder = PatchEmbed(patch_size, in_channels, hidden_size)
|
| 155 |
+
self.t_embedder = TimestepEmbedder(hidden_size)
|
| 156 |
+
self.y_embedder = CaptionEmbedder(caption_channels, hidden_size, num_caption_tokens)
|
| 157 |
+
num_patches = (sample_size // patch_size) ** 2
|
| 158 |
+
self.pos_embed = nn.Parameter(torch.zeros(1, num_patches, hidden_size), requires_grad=False)
|
| 159 |
+
grid = int(num_caption_tokens**0.5)
|
| 160 |
+
if num_caption_tokens > 1 and grid**2 == num_caption_tokens:
|
| 161 |
+
self.y_pos_embed = nn.Parameter(torch.zeros(1, num_caption_tokens, hidden_size), requires_grad=False)
|
| 162 |
+
else:
|
| 163 |
+
self.y_pos_embed = None
|
| 164 |
+
self.blocks = nn.ModuleList(
|
| 165 |
+
[BigCellBlock(hidden_size, num_attention_heads, mlp_ratio) for _ in range(num_layers)]
|
| 166 |
+
)
|
| 167 |
+
self.final_layer = FinalLayer(hidden_size, patch_size, in_channels)
|
| 168 |
+
pos = _sincos_2d(hidden_size, np.stack(np.meshgrid(np.arange(sample_size // patch_size),
|
| 169 |
+
np.arange(sample_size // patch_size)), 0).reshape(2, -1))
|
| 170 |
+
self.pos_embed.data.copy_(torch.from_numpy(pos).float()[None])
|
| 171 |
+
|
| 172 |
+
@property
|
| 173 |
+
def unconditional_embedding(self):
|
| 174 |
+
"""(1, T, 1536) learned null condition for classifier-free guidance."""
|
| 175 |
+
return self.y_embedder.y_embedding[None]
|
| 176 |
+
|
| 177 |
+
def unpatchify(self, x):
|
| 178 |
+
c, p = self.config.in_channels, self.config.patch_size
|
| 179 |
+
h = w = int(x.shape[1] ** 0.5)
|
| 180 |
+
x = torch.einsum("nhwpqc->nchpwq", x.reshape(x.shape[0], h, w, p, p, c))
|
| 181 |
+
return x.reshape(x.shape[0], c, h * p, w * p)
|
| 182 |
+
|
| 183 |
+
def forward(self, hidden_states, timestep, encoder_hidden_states):
|
| 184 |
+
"""hidden_states: (B, 32, H, W) noisy latent; timestep: (B,) in [0, 1] (1 = pure noise);
|
| 185 |
+
encoder_hidden_states: (B, T, 1536) UNI-2 tokens in raster order. Returns the velocity (noise - data)."""
|
| 186 |
+
x = self.x_embedder(hidden_states) + self.pos_embed
|
| 187 |
+
t = self.t_embedder(timestep)
|
| 188 |
+
y = self.y_embedder(encoder_hidden_states)
|
| 189 |
+
if self.y_pos_embed is not None:
|
| 190 |
+
y = y + self.y_pos_embed
|
| 191 |
+
for block in self.blocks:
|
| 192 |
+
x = block(x, y, t)
|
| 193 |
+
return self.unpatchify(self.final_layer(x, t))
|
| 194 |
+
|
| 195 |
+
|
| 196 |
+
def _sincos_2d(embed_dim, grid):
|
| 197 |
+
def one_d(dim, pos):
|
| 198 |
+
omega = 1.0 / 10000 ** (np.arange(dim // 2, dtype=np.float64) / (dim / 2.0))
|
| 199 |
+
out = np.einsum("m,d->md", pos.reshape(-1), omega)
|
| 200 |
+
return np.concatenate([np.sin(out), np.cos(out)], axis=1)
|
| 201 |
+
|
| 202 |
+
return np.concatenate([one_d(embed_dim // 2, grid[0]), one_d(embed_dim // 2, grid[1])], axis=1)
|
bigcell-2048/transformer/config.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_class_name": "BigCellTransformer2DModel",
|
| 3 |
+
"_diffusers_version": "0.37.1",
|
| 4 |
+
"alpha_shift": 3.0,
|
| 5 |
+
"caption_channels": 1536,
|
| 6 |
+
"hidden_size": 1152,
|
| 7 |
+
"in_channels": 32,
|
| 8 |
+
"mlp_ratio": 4.0,
|
| 9 |
+
"num_attention_heads": 16,
|
| 10 |
+
"num_caption_tokens": 64,
|
| 11 |
+
"num_layers": 28,
|
| 12 |
+
"patch_size": 2,
|
| 13 |
+
"sample_size": 256
|
| 14 |
+
}
|
bigcell-2048/transformer/diffusion_pytorch_model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:17a3b7165206aa7d65140b685ae854a7c96098f2ebe98341371721d2855d030b
|
| 3 |
+
size 3379372944
|
bigcell-2048/vae/config.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_class_name": "AutoencoderKLFlux2",
|
| 3 |
+
"_diffusers_version": "0.36.0.dev0",
|
| 4 |
+
"act_fn": "silu",
|
| 5 |
+
"batch_norm_eps": 0.0001,
|
| 6 |
+
"batch_norm_momentum": 0.1,
|
| 7 |
+
"block_out_channels": [
|
| 8 |
+
128,
|
| 9 |
+
256,
|
| 10 |
+
512,
|
| 11 |
+
512
|
| 12 |
+
],
|
| 13 |
+
"down_block_types": [
|
| 14 |
+
"DownEncoderBlock2D",
|
| 15 |
+
"DownEncoderBlock2D",
|
| 16 |
+
"DownEncoderBlock2D",
|
| 17 |
+
"DownEncoderBlock2D"
|
| 18 |
+
],
|
| 19 |
+
"force_upcast": true,
|
| 20 |
+
"in_channels": 3,
|
| 21 |
+
"latent_channels": 32,
|
| 22 |
+
"layers_per_block": 2,
|
| 23 |
+
"mid_block_add_attention": true,
|
| 24 |
+
"norm_num_groups": 32,
|
| 25 |
+
"out_channels": 3,
|
| 26 |
+
"patch_size": [
|
| 27 |
+
2,
|
| 28 |
+
2
|
| 29 |
+
],
|
| 30 |
+
"sample_size": 1024,
|
| 31 |
+
"up_block_types": [
|
| 32 |
+
"UpDecoderBlock2D",
|
| 33 |
+
"UpDecoderBlock2D",
|
| 34 |
+
"UpDecoderBlock2D",
|
| 35 |
+
"UpDecoderBlock2D"
|
| 36 |
+
],
|
| 37 |
+
"use_post_quant_conv": true,
|
| 38 |
+
"use_quant_conv": true,
|
| 39 |
+
"_name_or_path": "black-forest-labs/FLUX.2-dev"
|
| 40 |
+
}
|
bigcell-256/model_index.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_class_name": [
|
| 3 |
+
"pipeline",
|
| 4 |
+
"BigCellPipeline"
|
| 5 |
+
],
|
| 6 |
+
"_diffusers_version": "0.37.1",
|
| 7 |
+
"transformer": [
|
| 8 |
+
"bigcell_transformer_2d",
|
| 9 |
+
"BigCellTransformer2DModel"
|
| 10 |
+
],
|
| 11 |
+
"vae": [
|
| 12 |
+
"diffusers",
|
| 13 |
+
"AutoencoderKLFlux2"
|
| 14 |
+
],
|
| 15 |
+
"scheduler": [
|
| 16 |
+
"diffusers",
|
| 17 |
+
"FlowMatchEulerDiscreteScheduler"
|
| 18 |
+
]
|
| 19 |
+
}
|
bigcell-256/pipeline.py
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# BigCell pipeline. https://github.com/cvlab-stonybrook/BigCell
|
| 2 |
+
#
|
| 3 |
+
# Generates histopathology images from a grid of UNI-2 embeddings (one 1536-d token per 256x256 px at 20x).
|
| 4 |
+
# A grid that matches the model's native tile (e.g. 8x8 for BigCell-2048) is denoised directly; larger grids
|
| 5 |
+
# are generated with the sliding-window procedure of the paper (BigCell-large), optionally with adaptive
|
| 6 |
+
# window scheduling (``top_r < 1``). For multi-GPU generation of 16k-32k images use the GitHub scripts.
|
| 7 |
+
|
| 8 |
+
import math
|
| 9 |
+
from typing import List, Optional, Union
|
| 10 |
+
|
| 11 |
+
import numpy as np
|
| 12 |
+
import torch
|
| 13 |
+
from diffusers import DiffusionPipeline
|
| 14 |
+
from diffusers.image_processor import VaeImageProcessor
|
| 15 |
+
from diffusers.pipelines.pipeline_utils import ImagePipelineOutput
|
| 16 |
+
from diffusers.utils.torch_utils import randn_tensor
|
| 17 |
+
from PIL import Image
|
| 18 |
+
|
| 19 |
+
LATENTS_PER_TOKEN = 32 # one UNI-2 token covers 256 px = 32 Flux.2 latents
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def _gaussian_kernel(size, sigma, device):
|
| 23 |
+
x = torch.linspace(-1, 1, size)
|
| 24 |
+
x = torch.stack((x.tile(size, 1), x.tile(size, 1).T), dim=0)
|
| 25 |
+
k = torch.exp(-(torch.linalg.norm(x, dim=0) ** 2) / (2 * sigma**2))
|
| 26 |
+
return (k / k.max()).to(device)
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
class BigCellPipeline(DiffusionPipeline):
|
| 30 |
+
model_cpu_offload_seq = "transformer->vae"
|
| 31 |
+
|
| 32 |
+
def __init__(self, transformer, vae, scheduler):
|
| 33 |
+
super().__init__()
|
| 34 |
+
self.register_modules(transformer=transformer, vae=vae, scheduler=scheduler)
|
| 35 |
+
self.image_processor = VaeImageProcessor(vae_scale_factor=8)
|
| 36 |
+
|
| 37 |
+
@property
|
| 38 |
+
def tile_tokens(self):
|
| 39 |
+
"""Side of the UNI-2 grid covered by one native tile (1, 4 or 8)."""
|
| 40 |
+
return int(round(math.sqrt(self.transformer.config.num_caption_tokens)))
|
| 41 |
+
|
| 42 |
+
def get_unconditional_embedding(self, batch_size=1):
|
| 43 |
+
return self.transformer.unconditional_embedding.tile(batch_size, 1, 1)
|
| 44 |
+
|
| 45 |
+
def _velocity(self, x, t, y, guidance_scale):
|
| 46 |
+
"""Returns (cfg velocity, importance score |v_cond - v_uncond|)."""
|
| 47 |
+
null = self.get_unconditional_embedding(x.shape[0]).to(y.dtype)
|
| 48 |
+
v = self.transformer(torch.cat([x, x]), t.expand(2 * x.shape[0]), torch.cat([y, null])).float()
|
| 49 |
+
v_cond, v_uncond = v.chunk(2)
|
| 50 |
+
return v_uncond + guidance_scale * (v_cond - v_uncond), (v_cond - v_uncond).abs().mean().item()
|
| 51 |
+
|
| 52 |
+
def _sigmas(self, num_inference_steps, device):
|
| 53 |
+
self.scheduler.set_timesteps(sigmas=np.linspace(1.0, 0.0, num_inference_steps + 1)[:-1], device=device)
|
| 54 |
+
return self.scheduler.sigmas.to(device) # shifted, ends with 0
|
| 55 |
+
|
| 56 |
+
@torch.no_grad()
|
| 57 |
+
def _decode(self, latents, tile=256, sigma=0.5):
|
| 58 |
+
"""Tiled decode for large canvases (Gaussian-blended, accumulated on CPU)."""
|
| 59 |
+
_, _, h, w = latents.shape
|
| 60 |
+
dtype = self.vae.dtype
|
| 61 |
+
if h <= tile and w <= tile:
|
| 62 |
+
return self.vae.decode(latents.to(dtype)).sample.float().cpu()
|
| 63 |
+
out = torch.zeros(latents.shape[0], 3, h * 8, w * 8)
|
| 64 |
+
cnt = torch.zeros(1, 1, h * 8, w * 8)
|
| 65 |
+
kernel = _gaussian_kernel(tile * 8, sigma, "cpu")[None, None]
|
| 66 |
+
stride = tile // 2
|
| 67 |
+
for i in range(0, h - tile + 1, stride):
|
| 68 |
+
for j in range(0, w - tile + 1, stride):
|
| 69 |
+
dec = self.vae.decode(latents[:, :, i:i + tile, j:j + tile].to(dtype)).sample.float().cpu()
|
| 70 |
+
out[:, :, i * 8:(i + tile) * 8, j * 8:(j + tile) * 8] += dec * kernel
|
| 71 |
+
cnt[:, :, i * 8:(i + tile) * 8, j * 8:(j + tile) * 8] += kernel
|
| 72 |
+
return out / cnt.clamp(min=1e-6)
|
| 73 |
+
|
| 74 |
+
@torch.no_grad()
|
| 75 |
+
def __call__(
|
| 76 |
+
self,
|
| 77 |
+
uni_embeds: torch.Tensor,
|
| 78 |
+
num_inference_steps: int = 20,
|
| 79 |
+
guidance_scale: float = 2.0,
|
| 80 |
+
top_r: float = 1.0,
|
| 81 |
+
stride: Optional[int] = None,
|
| 82 |
+
window_sigma: float = 0.5,
|
| 83 |
+
generator: Optional[Union[torch.Generator, List[torch.Generator]]] = None,
|
| 84 |
+
latents: Optional[torch.Tensor] = None,
|
| 85 |
+
output_type: str = "pil",
|
| 86 |
+
return_dict: bool = True,
|
| 87 |
+
progress: bool = True,
|
| 88 |
+
):
|
| 89 |
+
"""
|
| 90 |
+
Args:
|
| 91 |
+
uni_embeds: UNI-2 grid of shape (B, Hg, Wg, 1536), or tokens of one native tile (B, T, 1536).
|
| 92 |
+
The output image is (256 * Hg) x (256 * Wg) pixels.
|
| 93 |
+
num_inference_steps: Euler steps (paper: 20).
|
| 94 |
+
guidance_scale: classifier-free guidance scale (paper: 2.0).
|
| 95 |
+
top_r: fraction of sliding windows recomputed at every step after the first (paper Sec. 3.3);
|
| 96 |
+
the rest reuse their cached velocity. 1.0 = full computation.
|
| 97 |
+
stride: window stride in latents (default: half a window, e.g. 128 = 1024 px for BigCell-2048).
|
| 98 |
+
window_sigma: width of the Gaussian window weighting.
|
| 99 |
+
output_type: "pil", "np" (uint8 HxWx3) or "latent".
|
| 100 |
+
"""
|
| 101 |
+
device = self._execution_device
|
| 102 |
+
dtype = self.transformer.dtype
|
| 103 |
+
tok = self.tile_tokens
|
| 104 |
+
if uni_embeds.ndim == 3: # (B, T, C) tokens of one tile -> grid
|
| 105 |
+
uni_embeds = uni_embeds.reshape(uni_embeds.shape[0], tok, tok, -1)
|
| 106 |
+
B, Hg, Wg, _ = uni_embeds.shape
|
| 107 |
+
if Hg < tok or Wg < tok:
|
| 108 |
+
raise ValueError(f"grid {Hg}x{Wg} is smaller than one tile ({tok}x{tok})")
|
| 109 |
+
uni_embeds = uni_embeds.to(device, dtype)
|
| 110 |
+
|
| 111 |
+
win = self.transformer.config.sample_size
|
| 112 |
+
H, W = Hg * LATENTS_PER_TOKEN, Wg * LATENTS_PER_TOKEN
|
| 113 |
+
stride = stride or win // 2
|
| 114 |
+
windows = [(h, w) for h in range(0, H - win + 1, stride) for w in range(0, W - win + 1, stride)]
|
| 115 |
+
kernel = _gaussian_kernel(win, window_sigma, device)
|
| 116 |
+
|
| 117 |
+
if latents is None:
|
| 118 |
+
latents = randn_tensor((B, self.transformer.config.in_channels, H, W), generator=generator,
|
| 119 |
+
device=device, dtype=torch.float32)
|
| 120 |
+
x = latents.to(device, torch.float32)
|
| 121 |
+
sigmas = self._sigmas(num_inference_steps, device)
|
| 122 |
+
|
| 123 |
+
n_select = len(windows) if top_r >= 1 else max(1, math.ceil(top_r * len(windows)))
|
| 124 |
+
importance = [dict() for _ in range(B)]
|
| 125 |
+
v_prev = torch.zeros_like(x)
|
| 126 |
+
with self.progress_bar(total=num_inference_steps) as pbar:
|
| 127 |
+
for step, (s_cur, s_next) in enumerate(zip(sigmas[:-1], sigmas[1:])):
|
| 128 |
+
t = s_cur.reshape(1).to(dtype)
|
| 129 |
+
v_new = v_prev.clone()
|
| 130 |
+
for b in range(B):
|
| 131 |
+
active = windows if step == 0 else sorted(windows, key=lambda w: -importance[b].get(w, 0.0))[:n_select]
|
| 132 |
+
v_sum = torch.zeros_like(x[b:b + 1])
|
| 133 |
+
w_sum = torch.zeros_like(x[b:b + 1])
|
| 134 |
+
for h, w in active:
|
| 135 |
+
y = uni_embeds[b:b + 1, h // 32:h // 32 + tok, w // 32:w // 32 + tok].reshape(1, tok * tok, -1)
|
| 136 |
+
v, score = self._velocity(x[b:b + 1, :, h:h + win, w:w + win].to(dtype), t, y, guidance_scale)
|
| 137 |
+
importance[b][(h, w)] = score
|
| 138 |
+
v_sum[:, :, h:h + win, w:w + win] += v * kernel
|
| 139 |
+
w_sum[:, :, h:h + win, w:w + win] += kernel
|
| 140 |
+
v_new[b:b + 1] = torch.where(w_sum > 0, v_sum / w_sum.clamp(min=1e-6), v_prev[b:b + 1])
|
| 141 |
+
v_prev = v_new
|
| 142 |
+
x = x + (s_next - s_cur) * v_new
|
| 143 |
+
if progress:
|
| 144 |
+
pbar.update()
|
| 145 |
+
|
| 146 |
+
if output_type == "latent":
|
| 147 |
+
return ImagePipelineOutput(images=x) if return_dict else (x,)
|
| 148 |
+
img = ((self._decode(x) + 1) / 2).clamp(0, 1)
|
| 149 |
+
img = (img.permute(0, 2, 3, 1) * 255).round().to(torch.uint8).numpy()
|
| 150 |
+
images = [Image.fromarray(i) for i in img] if output_type == "pil" else img
|
| 151 |
+
return ImagePipelineOutput(images=images) if return_dict else (images,)
|
bigcell-256/scheduler/scheduler_config.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_class_name": "FlowMatchEulerDiscreteScheduler",
|
| 3 |
+
"_diffusers_version": "0.37.1",
|
| 4 |
+
"base_image_seq_len": 256,
|
| 5 |
+
"base_shift": 0.5,
|
| 6 |
+
"invert_sigmas": false,
|
| 7 |
+
"max_image_seq_len": 4096,
|
| 8 |
+
"max_shift": 1.15,
|
| 9 |
+
"num_train_timesteps": 1000,
|
| 10 |
+
"shift": 1.0,
|
| 11 |
+
"shift_terminal": null,
|
| 12 |
+
"stochastic_sampling": false,
|
| 13 |
+
"time_shift_type": "exponential",
|
| 14 |
+
"use_beta_sigmas": false,
|
| 15 |
+
"use_dynamic_shifting": false,
|
| 16 |
+
"use_exponential_sigmas": false,
|
| 17 |
+
"use_karras_sigmas": false
|
| 18 |
+
}
|
bigcell-256/transformer/bigcell_transformer_2d.py
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# BigCell tile generator: a SiT flow-matching transformer conditioned on a grid of UNI-2 embeddings
|
| 2 |
+
# through cross-attention. https://github.com/cvlab-stonybrook/BigCell
|
| 3 |
+
#
|
| 4 |
+
# Adapted from SiT (https://github.com/willisma/SiT, MIT) and REPA-E (https://github.com/End2End-Diffusion/REPA-E, MIT).
|
| 5 |
+
|
| 6 |
+
import math
|
| 7 |
+
|
| 8 |
+
import numpy as np
|
| 9 |
+
import torch
|
| 10 |
+
import torch.nn as nn
|
| 11 |
+
import torch.nn.functional as F
|
| 12 |
+
from diffusers.configuration_utils import ConfigMixin, register_to_config
|
| 13 |
+
from diffusers.models.modeling_utils import ModelMixin
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def modulate(x, shift, scale):
|
| 17 |
+
return x * (1 + scale.unsqueeze(1)) + shift.unsqueeze(1)
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
class PatchEmbed(nn.Module):
|
| 21 |
+
def __init__(self, patch_size, in_channels, hidden_size):
|
| 22 |
+
super().__init__()
|
| 23 |
+
self.proj = nn.Conv2d(in_channels, hidden_size, kernel_size=patch_size, stride=patch_size, bias=True)
|
| 24 |
+
|
| 25 |
+
def forward(self, x):
|
| 26 |
+
return self.proj(x).flatten(2).transpose(1, 2)
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
class Mlp(nn.Module):
|
| 30 |
+
def __init__(self, in_features, hidden_features, out_features=None, approximate="none"):
|
| 31 |
+
super().__init__()
|
| 32 |
+
self.fc1 = nn.Linear(in_features, hidden_features)
|
| 33 |
+
self.act = nn.GELU(approximate=approximate)
|
| 34 |
+
self.fc2 = nn.Linear(hidden_features, out_features or in_features)
|
| 35 |
+
|
| 36 |
+
def forward(self, x):
|
| 37 |
+
return self.fc2(self.act(self.fc1(x)))
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
class Attention(nn.Module):
|
| 41 |
+
def __init__(self, dim, num_heads):
|
| 42 |
+
super().__init__()
|
| 43 |
+
self.num_heads = num_heads
|
| 44 |
+
self.qkv = nn.Linear(dim, dim * 3, bias=True)
|
| 45 |
+
self.proj = nn.Linear(dim, dim)
|
| 46 |
+
|
| 47 |
+
def forward(self, x):
|
| 48 |
+
B, N, C = x.shape
|
| 49 |
+
q, k, v = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4).unbind(0)
|
| 50 |
+
x = F.scaled_dot_product_attention(q, k, v)
|
| 51 |
+
return self.proj(x.transpose(1, 2).reshape(B, N, C))
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
class CrossAttention(nn.Module):
|
| 55 |
+
def __init__(self, dim, num_heads):
|
| 56 |
+
super().__init__()
|
| 57 |
+
self.num_heads = num_heads
|
| 58 |
+
self.q_linear = nn.Linear(dim, dim)
|
| 59 |
+
self.kv_linear = nn.Linear(dim, dim * 2)
|
| 60 |
+
self.proj = nn.Linear(dim, dim)
|
| 61 |
+
|
| 62 |
+
def forward(self, x, cond):
|
| 63 |
+
B, N, C = x.shape
|
| 64 |
+
h = self.num_heads
|
| 65 |
+
q = self.q_linear(x).reshape(B, N, h, C // h).transpose(1, 2)
|
| 66 |
+
k, v = self.kv_linear(cond).reshape(B, cond.shape[1], 2, h, C // h).permute(2, 0, 3, 1, 4).unbind(0)
|
| 67 |
+
x = F.scaled_dot_product_attention(q, k, v)
|
| 68 |
+
return self.proj(x.transpose(1, 2).reshape(B, N, C))
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
class TimestepEmbedder(nn.Module):
|
| 72 |
+
def __init__(self, hidden_size, frequency_embedding_size=256):
|
| 73 |
+
super().__init__()
|
| 74 |
+
self.mlp = nn.Sequential(
|
| 75 |
+
nn.Linear(frequency_embedding_size, hidden_size, bias=True),
|
| 76 |
+
nn.SiLU(),
|
| 77 |
+
nn.Linear(hidden_size, hidden_size, bias=True),
|
| 78 |
+
)
|
| 79 |
+
self.frequency_embedding_size = frequency_embedding_size
|
| 80 |
+
|
| 81 |
+
def forward(self, t):
|
| 82 |
+
half = self.frequency_embedding_size // 2
|
| 83 |
+
freqs = torch.exp(-math.log(10000) * torch.arange(half, dtype=torch.float32, device=t.device) / half)
|
| 84 |
+
args = t[:, None].float() * freqs[None]
|
| 85 |
+
return self.mlp(torch.cat([torch.cos(args), torch.sin(args)], dim=-1).to(t.dtype))
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
class CaptionEmbedder(nn.Module):
|
| 89 |
+
"""Projects UNI-2 tokens; ``y_embedding`` is the learned unconditional embedding used for CFG."""
|
| 90 |
+
|
| 91 |
+
def __init__(self, in_channels, hidden_size, token_num):
|
| 92 |
+
super().__init__()
|
| 93 |
+
self.y_proj = Mlp(in_channels, hidden_size, hidden_size, approximate="tanh")
|
| 94 |
+
self.register_buffer("y_embedding", torch.randn(token_num, in_channels) / in_channels**0.5)
|
| 95 |
+
|
| 96 |
+
def forward(self, caption):
|
| 97 |
+
return self.y_proj(caption)
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
class BigCellBlock(nn.Module):
|
| 101 |
+
def __init__(self, hidden_size, num_heads, mlp_ratio=4.0):
|
| 102 |
+
super().__init__()
|
| 103 |
+
self.norm1 = nn.LayerNorm(hidden_size, elementwise_affine=False, eps=1e-6)
|
| 104 |
+
self.attn = Attention(hidden_size, num_heads)
|
| 105 |
+
self.cross_attn = CrossAttention(hidden_size, num_heads)
|
| 106 |
+
self.norm2 = nn.LayerNorm(hidden_size, elementwise_affine=False, eps=1e-6)
|
| 107 |
+
self.mlp = Mlp(hidden_size, int(hidden_size * mlp_ratio), approximate="tanh")
|
| 108 |
+
self.adaLN_modulation = nn.Sequential(nn.SiLU(), nn.Linear(hidden_size, 6 * hidden_size, bias=True))
|
| 109 |
+
|
| 110 |
+
def forward(self, x, cond, t):
|
| 111 |
+
shift_msa, scale_msa, gate_msa, shift_mlp, scale_mlp, gate_mlp = self.adaLN_modulation(t).chunk(6, dim=-1)
|
| 112 |
+
x = x + gate_msa.unsqueeze(1) * self.attn(modulate(self.norm1(x), shift_msa, scale_msa))
|
| 113 |
+
x = x + self.cross_attn(x, cond)
|
| 114 |
+
x = x + gate_mlp.unsqueeze(1) * self.mlp(modulate(self.norm2(x), shift_mlp, scale_mlp))
|
| 115 |
+
return x
|
| 116 |
+
|
| 117 |
+
|
| 118 |
+
class FinalLayer(nn.Module):
|
| 119 |
+
def __init__(self, hidden_size, patch_size, out_channels):
|
| 120 |
+
super().__init__()
|
| 121 |
+
self.norm_final = nn.LayerNorm(hidden_size, elementwise_affine=False, eps=1e-6)
|
| 122 |
+
self.linear = nn.Linear(hidden_size, patch_size * patch_size * out_channels, bias=True)
|
| 123 |
+
self.adaLN_modulation = nn.Sequential(nn.SiLU(), nn.Linear(hidden_size, 2 * hidden_size, bias=True))
|
| 124 |
+
|
| 125 |
+
def forward(self, x, c):
|
| 126 |
+
shift, scale = self.adaLN_modulation(c).chunk(2, dim=-1)
|
| 127 |
+
return self.linear(modulate(self.norm_final(x), shift, scale))
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
class BigCellTransformer2DModel(ModelMixin, ConfigMixin):
|
| 131 |
+
"""SiT-XL/2 velocity predictor operating on Flux.2 VAE latents (32 channels, 8x downsampling).
|
| 132 |
+
|
| 133 |
+
Args:
|
| 134 |
+
sample_size: latent side length (tile resolution // 8).
|
| 135 |
+
num_caption_tokens: number of UNI-2 tokens per tile, (tile resolution // 256) ** 2.
|
| 136 |
+
alpha_shift: time shift used during training; the scheduler uses the same value.
|
| 137 |
+
"""
|
| 138 |
+
|
| 139 |
+
@register_to_config
|
| 140 |
+
def __init__(
|
| 141 |
+
self,
|
| 142 |
+
sample_size: int = 256,
|
| 143 |
+
patch_size: int = 2,
|
| 144 |
+
in_channels: int = 32,
|
| 145 |
+
hidden_size: int = 1152,
|
| 146 |
+
num_layers: int = 28,
|
| 147 |
+
num_attention_heads: int = 16,
|
| 148 |
+
mlp_ratio: float = 4.0,
|
| 149 |
+
caption_channels: int = 1536,
|
| 150 |
+
num_caption_tokens: int = 64,
|
| 151 |
+
alpha_shift: float = 1.0,
|
| 152 |
+
):
|
| 153 |
+
super().__init__()
|
| 154 |
+
self.x_embedder = PatchEmbed(patch_size, in_channels, hidden_size)
|
| 155 |
+
self.t_embedder = TimestepEmbedder(hidden_size)
|
| 156 |
+
self.y_embedder = CaptionEmbedder(caption_channels, hidden_size, num_caption_tokens)
|
| 157 |
+
num_patches = (sample_size // patch_size) ** 2
|
| 158 |
+
self.pos_embed = nn.Parameter(torch.zeros(1, num_patches, hidden_size), requires_grad=False)
|
| 159 |
+
grid = int(num_caption_tokens**0.5)
|
| 160 |
+
if num_caption_tokens > 1 and grid**2 == num_caption_tokens:
|
| 161 |
+
self.y_pos_embed = nn.Parameter(torch.zeros(1, num_caption_tokens, hidden_size), requires_grad=False)
|
| 162 |
+
else:
|
| 163 |
+
self.y_pos_embed = None
|
| 164 |
+
self.blocks = nn.ModuleList(
|
| 165 |
+
[BigCellBlock(hidden_size, num_attention_heads, mlp_ratio) for _ in range(num_layers)]
|
| 166 |
+
)
|
| 167 |
+
self.final_layer = FinalLayer(hidden_size, patch_size, in_channels)
|
| 168 |
+
pos = _sincos_2d(hidden_size, np.stack(np.meshgrid(np.arange(sample_size // patch_size),
|
| 169 |
+
np.arange(sample_size // patch_size)), 0).reshape(2, -1))
|
| 170 |
+
self.pos_embed.data.copy_(torch.from_numpy(pos).float()[None])
|
| 171 |
+
|
| 172 |
+
@property
|
| 173 |
+
def unconditional_embedding(self):
|
| 174 |
+
"""(1, T, 1536) learned null condition for classifier-free guidance."""
|
| 175 |
+
return self.y_embedder.y_embedding[None]
|
| 176 |
+
|
| 177 |
+
def unpatchify(self, x):
|
| 178 |
+
c, p = self.config.in_channels, self.config.patch_size
|
| 179 |
+
h = w = int(x.shape[1] ** 0.5)
|
| 180 |
+
x = torch.einsum("nhwpqc->nchpwq", x.reshape(x.shape[0], h, w, p, p, c))
|
| 181 |
+
return x.reshape(x.shape[0], c, h * p, w * p)
|
| 182 |
+
|
| 183 |
+
def forward(self, hidden_states, timestep, encoder_hidden_states):
|
| 184 |
+
"""hidden_states: (B, 32, H, W) noisy latent; timestep: (B,) in [0, 1] (1 = pure noise);
|
| 185 |
+
encoder_hidden_states: (B, T, 1536) UNI-2 tokens in raster order. Returns the velocity (noise - data)."""
|
| 186 |
+
x = self.x_embedder(hidden_states) + self.pos_embed
|
| 187 |
+
t = self.t_embedder(timestep)
|
| 188 |
+
y = self.y_embedder(encoder_hidden_states)
|
| 189 |
+
if self.y_pos_embed is not None:
|
| 190 |
+
y = y + self.y_pos_embed
|
| 191 |
+
for block in self.blocks:
|
| 192 |
+
x = block(x, y, t)
|
| 193 |
+
return self.unpatchify(self.final_layer(x, t))
|
| 194 |
+
|
| 195 |
+
|
| 196 |
+
def _sincos_2d(embed_dim, grid):
|
| 197 |
+
def one_d(dim, pos):
|
| 198 |
+
omega = 1.0 / 10000 ** (np.arange(dim // 2, dtype=np.float64) / (dim / 2.0))
|
| 199 |
+
out = np.einsum("m,d->md", pos.reshape(-1), omega)
|
| 200 |
+
return np.concatenate([np.sin(out), np.cos(out)], axis=1)
|
| 201 |
+
|
| 202 |
+
return np.concatenate([one_d(embed_dim // 2, grid[0]), one_d(embed_dim // 2, grid[1])], axis=1)
|
bigcell-256/transformer/config.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_class_name": "BigCellTransformer2DModel",
|
| 3 |
+
"_diffusers_version": "0.37.1",
|
| 4 |
+
"alpha_shift": 1.0,
|
| 5 |
+
"caption_channels": 1536,
|
| 6 |
+
"hidden_size": 1152,
|
| 7 |
+
"in_channels": 32,
|
| 8 |
+
"mlp_ratio": 4.0,
|
| 9 |
+
"num_attention_heads": 16,
|
| 10 |
+
"num_caption_tokens": 1,
|
| 11 |
+
"num_layers": 28,
|
| 12 |
+
"patch_size": 2,
|
| 13 |
+
"sample_size": 32
|
| 14 |
+
}
|
bigcell-256/transformer/diffusion_pytorch_model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:091870c776997dd5314f8ccb69fdac97be13e54813eb8af2e56104cc437d0c78
|
| 3 |
+
size 3304373040
|
bigcell-256/vae/config.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_class_name": "AutoencoderKLFlux2",
|
| 3 |
+
"_diffusers_version": "0.36.0.dev0",
|
| 4 |
+
"act_fn": "silu",
|
| 5 |
+
"batch_norm_eps": 0.0001,
|
| 6 |
+
"batch_norm_momentum": 0.1,
|
| 7 |
+
"block_out_channels": [
|
| 8 |
+
128,
|
| 9 |
+
256,
|
| 10 |
+
512,
|
| 11 |
+
512
|
| 12 |
+
],
|
| 13 |
+
"down_block_types": [
|
| 14 |
+
"DownEncoderBlock2D",
|
| 15 |
+
"DownEncoderBlock2D",
|
| 16 |
+
"DownEncoderBlock2D",
|
| 17 |
+
"DownEncoderBlock2D"
|
| 18 |
+
],
|
| 19 |
+
"force_upcast": true,
|
| 20 |
+
"in_channels": 3,
|
| 21 |
+
"latent_channels": 32,
|
| 22 |
+
"layers_per_block": 2,
|
| 23 |
+
"mid_block_add_attention": true,
|
| 24 |
+
"norm_num_groups": 32,
|
| 25 |
+
"out_channels": 3,
|
| 26 |
+
"patch_size": [
|
| 27 |
+
2,
|
| 28 |
+
2
|
| 29 |
+
],
|
| 30 |
+
"sample_size": 1024,
|
| 31 |
+
"up_block_types": [
|
| 32 |
+
"UpDecoderBlock2D",
|
| 33 |
+
"UpDecoderBlock2D",
|
| 34 |
+
"UpDecoderBlock2D",
|
| 35 |
+
"UpDecoderBlock2D"
|
| 36 |
+
],
|
| 37 |
+
"use_post_quant_conv": true,
|
| 38 |
+
"use_quant_conv": true,
|
| 39 |
+
"_name_or_path": "black-forest-labs/FLUX.2-dev"
|
| 40 |
+
}
|
cgm-8192/config.json
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"model": "CGM-B",
|
| 3 |
+
"grid_size": 32,
|
| 4 |
+
"region_size": 8192,
|
| 5 |
+
"time_shift": 19.595917942265423,
|
| 6 |
+
"text_encoder": "MahmoodLab/TITAN",
|
| 7 |
+
"num_inference_steps": 50,
|
| 8 |
+
"guidance_scale": 2.0
|
| 9 |
+
}
|
cgm-8192/model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a3ae9348c830c1b0f8df002341ebd919e8ae76c03f5706d1971cafdcc7c22a78
|
| 3 |
+
size 1308806832
|
cgm-8192/normalization_stats.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:64d6310d55153ff074537018252b4809b80cfd3044354793fff554ad945137b9
|
| 3 |
+
size 12583072
|