Image Feature Extraction
Transformers
Safetensors
clip_vitb_mini
feature-extraction
clip
knowledge-distillation
consensus-distillation
vit
custom_code
Instructions to use AbstractPhil/clip-vitb-mini-distilled with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use AbstractPhil/clip-vitb-mini-distilled with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("image-feature-extraction", model="AbstractPhil/clip-vitb-mini-distilled", trust_remote_code=True)# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("AbstractPhil/clip-vitb-mini-distilled", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
| """Standalone loader for clip-vitb-mini-distilled (no repo imports). | |
| Usage: | |
| from loader import load_model, embed_images | |
| model = load_model("student.pt") # or a hf_hub_download path | |
| emb = embed_images(model, batch01) # (B,3,H,W) in [0,1] -> (B,512) | |
| The student is an 8.66M-parameter ViT (d=240, depth 12, heads 4, patch 16, | |
| img 160) distilled from CLIP ViT-B/16 (LAION-2B) pooled image features on | |
| COCO-2017 train (118,287 images, ~17 epochs). Outputs live in the teacher's | |
| 512-d projection space: compatible with the teacher's TEXT tower for | |
| zero-shot/retrieval. See the model card for measured capability and caveats. | |
| """ | |
| import torch | |
| import torch.nn as nn | |
| import torch.nn.functional as F | |
| CLIP_MEAN = (0.48145466, 0.4578275, 0.40821073) | |
| CLIP_STD = (0.26862954, 0.26130258, 0.27577711) | |
| class Block(nn.Module): | |
| def __init__(self, d, heads): | |
| super().__init__() | |
| self.n1 = nn.LayerNorm(d) | |
| self.qkv = nn.Linear(d, 3 * d) | |
| self.proj = nn.Linear(d, d) | |
| self.n2 = nn.LayerNorm(d) | |
| self.fc1 = nn.Linear(d, 4 * d) | |
| self.fc2 = nn.Linear(4 * d, d) | |
| self.heads = heads | |
| def forward(self, x): | |
| B, N, C = x.shape | |
| q, k, v = (self.qkv(self.n1(x)) | |
| .reshape(B, N, 3, self.heads, C // self.heads) | |
| .permute(2, 0, 3, 1, 4)) | |
| a = F.scaled_dot_product_attention(q, k, v) | |
| x = x + self.proj(a.transpose(1, 2).reshape(B, N, C)) | |
| return x + self.fc2(F.gelu(self.fc1(self.n2(x)))) | |
| class Student(nn.Module): | |
| """CLS-token readout, Linear head to the teacher's 512-d space.""" | |
| def __init__(self, out_dim=512, d=240, depth=12, heads=4, patch=16, | |
| img=160): | |
| super().__init__() | |
| self.patch = nn.Conv2d(3, d, patch, patch) | |
| self.cls = nn.Parameter(torch.zeros(1, 1, d)) | |
| self.pos = nn.Parameter(torch.zeros(1, (img // patch) ** 2 + 1, d)) | |
| self.blocks = nn.ModuleList(Block(d, heads) for _ in range(depth)) | |
| self.norm = nn.LayerNorm(d) | |
| self.head = nn.Linear(d, out_dim) | |
| def forward_features(self, x): | |
| x = self.patch(x).flatten(2).transpose(1, 2) | |
| x = torch.cat([self.cls.expand(x.shape[0], -1, -1), x], 1) + self.pos | |
| for b in self.blocks: | |
| x = b(x) | |
| return self.norm(x)[:, 0] | |
| def forward(self, x): | |
| return self.head(self.forward_features(x)) | |
| def load_model(path, device=None): | |
| device = device or ("cuda" if torch.cuda.is_available() else "cpu") | |
| ck = torch.load(path, map_location="cpu", weights_only=True) | |
| sd = ck["state_dict"] if "state_dict" in ck else ck | |
| model = Student(out_dim=sd["head.weight"].shape[0]) | |
| model.load_state_dict(sd, strict=True) | |
| return model.to(device).eval() | |
| def load_rotation(path): | |
| """Load a frame rotation shipped beside a consensus-distilled student. | |
| The rotation maps the student's consensus frame into the CLIP-B/16 | |
| (LAION-2B) deployment frame; it was fitted once, offline, on 2,500 | |
| COCO-val pairs (fp64 orthogonal Procrustes) and is FROZEN.""" | |
| d = torch.load(path, map_location="cpu", weights_only=True) | |
| return d["R"] if isinstance(d, dict) else d | |
| def embed_images(model, x01, batch=256, rotation=None): | |
| """x01: (B,3,H,W) float in [0,1]. Returns L2-normalized (B,512). | |
| Pass `rotation` (from load_rotation) with the consensus-distilled | |
| champion to place outputs in the LAION text tower's frame — required | |
| for zero-shot/retrieval against that tower, and how every headline | |
| number on the card was measured.""" | |
| dev = next(model.parameters()).device | |
| mean = torch.tensor(CLIP_MEAN).view(1, 3, 1, 1).to(dev) | |
| std = torch.tensor(CLIP_STD).view(1, 3, 1, 1).to(dev) | |
| out = [] | |
| for i in range(0, len(x01), batch): | |
| x = x01[i:i + batch].to(dev) | |
| x = F.interpolate(x, size=(160, 160), mode="bicubic", | |
| align_corners=False).clamp(0, 1) | |
| z = F.normalize(model((x - mean) / std), dim=-1) | |
| if rotation is not None: | |
| z = F.normalize(z.double() @ rotation.to(dev).double(), | |
| dim=-1).float() | |
| out.append(z.cpu()) | |
| return torch.cat(out) | |