Instructions to use madtune/pixeldit-controlnet with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Diffusers
How to use madtune/pixeldit-controlnet with Diffusers:
pip install -U diffusers transformers accelerate
from diffusers import ControlNetModel, StableDiffusionControlNetPipeline controlnet = ControlNetModel.from_pretrained("madtune/pixeldit-controlnet") pipe = StableDiffusionControlNetPipeline.from_pretrained( "madtune/pixeldit-diffusers", controlnet=controlnet ) - Notebooks
- Google Colab
- Kaggle
| """ | |
| Precompute SigLIP + Gemma embeddings for all training images. | |
| Run precompute_wd_tags.py first to produce WD_TAGS_JSON. | |
| Output files in EMBEDDINGS_DIR: | |
| index.json {image_path: row_index} | |
| siglip_pools.npy float16 [N, 256, 1152] SigLIP patch features (pre-projection) | |
| gemma_embs.npy float16 [N, 300, 2304] Gemma text embeddings | |
| progress.json {last_completed: int} restartable | |
| These files are memory-mapped at training time by train.py. | |
| """ | |
| import json | |
| import os | |
| from pathlib import Path | |
| import numpy as np | |
| import torch | |
| import torch.nn.functional as F | |
| from PIL import Image | |
| from tqdm import tqdm | |
| from transformers import AutoImageProcessor, AutoModelForCausalLM, AutoTokenizer, SiglipVisionModel | |
| from transformers import logging as hf_logging | |
| hf_logging.set_verbosity_error() | |
| # Settings -------------------------------------------------------------------- | |
| IMAGE_DIR = "/home/nobus/Raid0/DataSet/Images1" | |
| WD_TAGS_JSON = "/home/nobus/Raid0/DataSet/embeddings/wd_tags.json" | |
| EMBEDDINGS_DIR = "/home/nobus/Raid0/DataSet/embeddings" | |
| SIGLIP_DEVICE = "cuda:0" | |
| GEMMA_DEVICE = "cuda:0" | |
| SIGLIP_BATCH = 64 | |
| GEMMA_BATCH = 16 | |
| # ----------------------------------------------------------------------------- | |
| _SIGLIP_ID = "google/siglip-so400m-patch14-384" | |
| _GEMMA_ID = "Efficient-Large-Model/gemma-2-2b-it" | |
| _N_IP = 256 | |
| _SIGLIP_DIM = 1152 | |
| _N_TEXT = 300 | |
| _GEMMA_DIM = 2304 | |
| _CHI_PROMPT = "\n".join([ | |
| 'Given a user prompt, generate an "Enhanced prompt" that provides detailed visual descriptions suitable for image generation. Evaluate the level of detail in the user prompt:', | |
| "- If the prompt is simple, focus on adding specifics about colors, shapes, sizes, textures, and spatial relationships to create vivid and concrete scenes.", | |
| "- If the prompt is already detailed, refine and enhance the existing details slightly without overcomplicating.", | |
| "Here are examples of how to transform or refine prompts:", | |
| "- User Prompt: A cat sleeping -> Enhanced: A small, fluffy white cat curled up in a round shape, sleeping peacefully on a warm sunny windowsill, surrounded by pots of blooming red flowers.", | |
| "- User Prompt: A busy city street -> Enhanced: A bustling city street scene at dusk, featuring glowing street lamps, a diverse crowd of people in colorful clothing, and a double-decker bus passing by towering glass skyscrapers.", | |
| "Please generate only the enhanced description for the prompt below and avoid including any additional commentary or evaluations:", | |
| "User Prompt: ", | |
| ]) | |
| _IMAGE_EXTS = {".jpg", ".jpeg", ".png", ".webp"} | |
| def _find_images(root): | |
| return sorted(p for p in Path(root).rglob("*") if p.is_file() and p.suffix.lower() in _IMAGE_EXTS) | |
| def _open_or_create_memmap(path, shape, dtype="float16"): | |
| if os.path.exists(path): | |
| mm = np.lib.format.open_memmap(path, mode="r+") | |
| assert mm.shape == shape and mm.dtype == np.dtype(dtype), \ | |
| f"Existing {path} shape/dtype mismatch: {mm.shape} vs {shape}" | |
| return mm | |
| return np.lib.format.open_memmap(path, mode="w+", dtype=dtype, shape=shape) | |
| def main(): | |
| os.makedirs(EMBEDDINGS_DIR, exist_ok=True) | |
| paths = _find_images(IMAGE_DIR) | |
| N = len(paths) | |
| print(f"Found {N} images in {IMAGE_DIR}") | |
| with open(WD_TAGS_JSON, encoding="utf-8") as fh: | |
| wd_tags = json.load(fh) | |
| print(f"Loaded WD tags: {len(wd_tags)} entries") | |
| # ββ index βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| index_path = os.path.join(EMBEDDINGS_DIR, "index.json") | |
| if os.path.exists(index_path): | |
| with open(index_path) as fh: | |
| index = json.load(fh) | |
| assert len(index) == N, f"Index has {len(index)} entries but found {N} images. Delete index.json to rebuild." | |
| print(f"Loaded existing index ({len(index)} entries)") | |
| else: | |
| index = {str(p): i for i, p in enumerate(paths)} | |
| with open(index_path, "w") as fh: | |
| json.dump(index, fh, indent=2) | |
| print(f"Built index β {index_path}") | |
| # ββ progress βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| progress_path = os.path.join(EMBEDDINGS_DIR, "progress.json") | |
| start_from = 0 | |
| if os.path.exists(progress_path): | |
| with open(progress_path) as fh: | |
| start_from = json.load(fh).get("last_completed", -1) + 1 | |
| print(f"Resuming from image {start_from}/{N}") | |
| if start_from >= N: | |
| print("All images already computed.") | |
| return | |
| # ββ memmap files βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| siglip_mm = _open_or_create_memmap( | |
| os.path.join(EMBEDDINGS_DIR, "siglip_pools.npy"), (N, _N_IP, _SIGLIP_DIM) | |
| ) | |
| gemma_mm = _open_or_create_memmap( | |
| os.path.join(EMBEDDINGS_DIR, "gemma_embs.npy"), (N, _N_TEXT, _GEMMA_DIM) | |
| ) | |
| print(f"siglip_pools.npy {siglip_mm.nbytes / 1e9:.1f} GB") | |
| print(f"gemma_embs.npy {gemma_mm.nbytes / 1e9:.1f} GB") | |
| remaining = paths[start_from:] | |
| # ββ SigLIP βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| print(f"\nLoading SigLIP on {SIGLIP_DEVICE}...") | |
| proc = AutoImageProcessor.from_pretrained(_SIGLIP_ID) | |
| siglip = SiglipVisionModel.from_pretrained(_SIGLIP_ID, torch_dtype=torch.float16).eval().to(SIGLIP_DEVICE) | |
| for bi in tqdm(range(0, len(remaining), SIGLIP_BATCH), desc="SigLIP"): | |
| batch_paths = remaining[bi: bi + SIGLIP_BATCH] | |
| imgs, valid = [], [] | |
| for j, p in enumerate(batch_paths): | |
| try: | |
| imgs.append(Image.open(p).convert("RGB")) | |
| valid.append(j) | |
| except Exception as e: | |
| print(f" skip {p}: {e}") | |
| if not imgs: | |
| continue | |
| inputs = proc(images=imgs, return_tensors="pt").to(SIGLIP_DEVICE) | |
| with torch.no_grad(): | |
| patches = siglip(**inputs).last_hidden_state # [B, 729, 1152] | |
| pooled = ( | |
| F.adaptive_avg_pool1d(patches.float().permute(0, 2, 1), _N_IP) | |
| .permute(0, 2, 1).to(torch.float16).cpu().numpy() # [B, 256, 1152] | |
| ) | |
| for arr, j in zip(pooled, valid): | |
| siglip_mm[start_from + bi + j] = arr | |
| siglip_mm.flush() | |
| del siglip | |
| torch.cuda.empty_cache() | |
| # ββ Gemma ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| print(f"\nLoading Gemma on {GEMMA_DEVICE}...") | |
| tokenizer = AutoTokenizer.from_pretrained(_GEMMA_ID) | |
| tokenizer.padding_side = "right" | |
| gemma = ( | |
| AutoModelForCausalLM.from_pretrained(_GEMMA_ID, torch_dtype=torch.float16) | |
| .get_decoder().eval().to(GEMMA_DEVICE) | |
| ) | |
| num_chi = len(tokenizer.encode(_CHI_PROMPT)) | |
| max_len = num_chi + _N_TEXT - 2 | |
| select = [0] + list(range(-(_N_TEXT - 1), 0)) | |
| for bi in tqdm(range(0, len(remaining), GEMMA_BATCH), desc="Gemma"): | |
| batch_paths = remaining[bi: bi + GEMMA_BATCH] | |
| texts = [_CHI_PROMPT + wd_tags.get(str(p.resolve()), "") for p in batch_paths] | |
| tok = tokenizer(texts, max_length=max_len, padding="max_length", | |
| truncation=True, return_tensors="pt").to(GEMMA_DEVICE) | |
| with torch.no_grad(): | |
| emb = gemma(input_ids=tok.input_ids, attention_mask=tok.attention_mask).last_hidden_state | |
| emb = emb[:, select, :].to(torch.float16).cpu().numpy() # [B, 300, 2304] | |
| for j in range(len(batch_paths)): | |
| gemma_mm[start_from + bi + j] = emb[j] | |
| gemma_mm.flush() | |
| with open(progress_path, "w") as fh: | |
| json.dump({"last_completed": start_from + bi + len(batch_paths) - 1}, fh) | |
| del gemma | |
| print(f"\nDone!") | |
| print(f" {EMBEDDINGS_DIR}/siglip_pools.npy") | |
| print(f" {EMBEDDINGS_DIR}/gemma_embs.npy") | |
| print(f" {EMBEDDINGS_DIR}/index.json") | |
| if __name__ == "__main__": | |
| main() | |