multimodalart's picture
multimodalart HF Staff
Upload folder using huggingface_hub
cbbf804 verified
Raw
History Blame Contribute Delete
4.39 kB
# backbones.py — image/text encoder adapters (OpenAI CLIP + SigLIP2) for the gradstep engine.
import torch
from torch import nn
import generate_fast as gf
from generate_fast import clip
OPENAI_MODELS = ("ViT-B/16", "ViT-B/32", "ViT-L/14")
SIGLIP_NORM = ([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
class SiglipVisual(nn.Module):
"""(B,3,S,S) pixel values -> pooled image embedding; mimics the CLIP visual interface."""
def __init__(self, vision_model, input_resolution, output_dim):
super().__init__()
self.vision_model = vision_model
self.input_resolution = input_resolution
self.output_dim = output_dim
def forward(self, x):
return self.vision_model(x).pooler_output
def load_backbone(name):
"""-> dict(kind, visual, cut_size, output_dim, encode_text(txt, device), text_module)."""
if name in OPENAI_MODELS:
p = clip.load(name, device="cpu", jit=False)[0].eval().requires_grad_(False)
# text tower in fp32 (GradStep casts the visual to bf16; CLIP's encode_text would
# otherwise cast text inputs by the visual dtype and mismatch the text weights)
p.transformer.float()
p.token_embedding.float()
p.ln_final.float()
p.positional_embedding.data = p.positional_embedding.data.float()
p.text_projection.data = p.text_projection.data.float()
def encode_text(txt, device):
t = clip.tokenize(txt).to(device)
x = p.token_embedding(t) + p.positional_embedding
x = p.transformer(x.permute(1, 0, 2)).permute(1, 0, 2)
x = p.ln_final(x)
return x[torch.arange(x.shape[0]), t.argmax(dim=-1)] @ p.text_projection
return {"kind": "openai", "visual": p.visual, "cut_size": p.visual.input_resolution,
"output_dim": p.visual.output_dim, "encode_text": encode_text, "text_module": p}
from transformers import AutoModel, AutoTokenizer
m = AutoModel.from_pretrained(name).eval().requires_grad_(False)
tok = AutoTokenizer.from_pretrained(name)
res = m.config.vision_config.image_size
dim = m.config.vision_config.hidden_size
visual = SiglipVisual(m.vision_model, res, dim)
def encode_text(txt, device):
ids = tok([txt], padding="max_length", max_length=64,
truncation=True, return_tensors="pt").input_ids.to(device)
return m.text_model(input_ids=ids).pooler_output # transformers-5-safe
return {"kind": "siglip", "visual": visual, "cut_size": res, "output_dim": dim,
"encode_text": encode_text, "text_module": m.text_model}
class _FP32LayerNorm(nn.LayerNorm):
"""CLIP-style LN: compute in fp32, cast back — cuts bf16 gradient noise."""
def forward(self, x):
return nn.functional.layer_norm(
x.float(), self.normalized_shape, self.weight, self.bias, self.eps).to(x.dtype)
def _fp32_layernorms(module):
for name, child in module.named_children():
if isinstance(child, nn.LayerNorm):
ln = _FP32LayerNorm(child.normalized_shape, eps=child.eps,
elementwise_affine=child.elementwise_affine)
if child.elementwise_affine:
ln.weight.data = child.weight.data.float()
if child.bias is not None:
ln.bias.data = child.bias.data.float()
ln.requires_grad_(False)
setattr(module, name, ln)
else:
_fp32_layernorms(child)
def _siglip_fixups(sm, backbone):
if backbone["kind"] == "siglip":
# HF siglip: bf16 everywhere except LNs in fp32 (mirrors the CLIP visual policy)
sm.visual.to(torch.bfloat16)
_fp32_layernorms(sm.visual)
mean, std = SIGLIP_NORM
sm.norm_mean.copy_(torch.tensor(mean).view(1, 3, 1, 1))
sm.norm_std.copy_(torch.tensor(std).view(1, 3, 1, 1))
return sm
def build_gradstep(vq, backbone, cutn, sideY, sideX):
sm = gf.GradStep(vq, backbone["visual"], cutn, backbone["cut_size"], sideY, sideX, 0.0).eval()
return _siglip_fixups(sm, backbone)
def build_fusedstep(unet, backbone, cutn, image_size):
import diffusion_fast as D # lazy: only the diffusion Spaces ship this module
sm = D.FusedStep(unet, backbone["visual"], cutn, backbone["cut_size"],
image_size, torch.bfloat16).eval()
return _siglip_fixups(sm, backbone)