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
| """cc12m_data.py — CC12M-resident data path for dist_bed (pod rung). | |
| Trains straight from the pixparse/cc12m-wds tars via a one-time offset | |
| index (no extraction: 1.18TB stays as 2,176 tars). Row order = the | |
| feature-bank concatenation order (features_0000..2175), so targets[idx] | |
| indexing works exactly like the COCO path. | |
| python tools/cc12m_data.py --build-index # one-time, parallel scan | |
| """ | |
| import glob | |
| import json | |
| import os | |
| import tarfile | |
| import numpy as np | |
| import torch | |
| from PIL import Image, ImageFile | |
| from torch.utils.data import Dataset | |
| ImageFile.LOAD_TRUNCATED_IMAGES = True | |
| DATA_ROOT = os.environ.get("DIST_DATA_ROOT", "./data") | |
| CC12M_TARS = os.environ.get("CC12M_TARS", | |
| os.path.join(DATA_ROOT, "cc12m")) | |
| CC12M_FEATS = os.environ.get("CC12M_FEATS", | |
| os.path.join(DATA_ROOT, "cc12m_feats", | |
| "clip_b16_laion2b")) | |
| INDEX = os.path.join(CC12M_TARS, "jpg_offset_index.npz") | |
| def _scan_shard(path): | |
| """-> (shard_name, {key: (offset, size)}) for .jpg members.""" | |
| out = {} | |
| with tarfile.open(path, "r") as tar: | |
| for m in tar: | |
| if m.isfile() and m.name.endswith(".jpg"): | |
| out[m.name[:-4]] = (m.offset_data, m.size) | |
| return os.path.basename(path), out | |
| def build_index(workers=32): | |
| from multiprocessing import Pool | |
| tars = sorted(glob.glob(os.path.join(CC12M_TARS, "*.tar"))) | |
| assert tars, f"no tars under {CC12M_TARS}" | |
| print(f"[index] scanning {len(tars)} tars with {workers} workers") | |
| shard_names, keys, shard_idx, offs, sizes = [], [], [], [], [] | |
| with Pool(workers) as pool: | |
| for name, d in pool.imap(_scan_shard, tars, chunksize=4): | |
| si = len(shard_names) | |
| shard_names.append(name) | |
| for k, (o, s) in d.items(): | |
| keys.append(k) | |
| shard_idx.append(si) | |
| offs.append(o) | |
| sizes.append(s) | |
| if si % 200 == 0: | |
| print(f" [{si}] {sum(map(len, [keys]))} keys", flush=True) | |
| np.savez(INDEX, shards=np.array(shard_names), | |
| keys=np.array(keys), shard_idx=np.array(shard_idx, np.int32), | |
| off=np.array(offs, np.int64), size=np.array(sizes, np.int64)) | |
| print(f"[index] {len(keys)} jpgs -> {INDEX}") | |
| def load_cc12m_tower(cfg): | |
| """-> (keys, fp16 UNNORMALIZED) for an extra tower bank | |
| (cc12m_feats_{cfg} under CC12M_FEATS_ROOT), concat-cached.""" | |
| root = os.path.join(os.environ.get("CC12M_FEATS_ROOT", "/data"), | |
| f"cc12m_feats_{cfg}") | |
| cache = os.path.join(root, "all_concat.pt") | |
| if os.path.isfile(cache): | |
| d = torch.load(cache, map_location="cpu", weights_only=True) | |
| return d["keys"], d["emb"] | |
| files = sorted(glob.glob(os.path.join(root, "features_*.pt"))) | |
| assert len(files) == 2176, f"{cfg} bank incomplete: {len(files)}/2176" | |
| keys, embs = [], [] | |
| for f in files: | |
| try: | |
| d = torch.load(f, map_location="cpu", weights_only=True) | |
| except Exception: | |
| # pod tower shards carry numpy.str_ keys (offset-index array | |
| # slices) which weights_only refuses; these are SELF-AUTHORED | |
| # files on our own disk — trusted load, keys coerced below. | |
| d = torch.load(f, map_location="cpu", weights_only=False) | |
| keys += [str(k) for k in d["keys"]] | |
| embs.append(d["emb"]) | |
| emb = torch.cat(embs) | |
| torch.save({"keys": keys, "emb": emb}, cache) | |
| return keys, emb | |
| def load_cc12m_gpa(): | |
| """-> (keys, fp16 GPA targets) built by cc12m_gpa.py.""" | |
| p = os.path.join(os.environ.get("CC12M_FEATS_ROOT", "/data"), | |
| "cc12m_gpa.pt") | |
| d = torch.load(p, map_location="cpu", weights_only=True) | |
| return d["keys"], d["emb"] | |
| def load_cc12m_targets(): | |
| """-> (keys list, fp16 targets (N,512) UNNORMALIZED) in bank file order. | |
| Caller normalizes (the bed normalizes per-batch).""" | |
| cache = os.path.join(os.path.dirname(CC12M_FEATS), "all_concat.pt") | |
| if os.path.isfile(cache): | |
| d = torch.load(cache, map_location="cpu", weights_only=True) | |
| return d["keys"], d["emb"] | |
| files = sorted(glob.glob(os.path.join(CC12M_FEATS, "features_*.pt"))) | |
| assert len(files) == 2176, f"bank incomplete: {len(files)}/2176" | |
| keys, embs = [], [] | |
| for f in files: | |
| d = torch.load(f, map_location="cpu", weights_only=True) | |
| keys += d["keys"] | |
| embs.append(d["emb"]) | |
| emb = torch.cat(embs) | |
| torch.save({"keys": keys, "emb": emb}, cache) | |
| return keys, emb | |
| class Cc12mImages(Dataset): | |
| """(row i) -> (STUDENT_TF tensor, i), rows in bank order. Per-worker | |
| persistent file handles; reads jpg bytes by offset from the tars.""" | |
| def __init__(self, keys, tf): | |
| z = np.load(INDEX, allow_pickle=False) | |
| pos = {k: i for i, k in enumerate(z["keys"].tolist())} | |
| sel = np.array([pos[k] for k in keys], dtype=np.int64) | |
| self.shards = [os.path.join(CC12M_TARS, s) | |
| for s in z["shards"].tolist()] | |
| self.shard_idx = z["shard_idx"][sel] | |
| self.off = z["off"][sel] | |
| self.size = z["size"][sel] | |
| self.tf = tf | |
| def __len__(self): | |
| return len(self.off) | |
| def _read(self, i): | |
| # open/seek/read/close per item: with 2,176 shards x N workers, | |
| # persistent handles exhaust the fd limit (learned the hard way, | |
| # wave 1). Syscall cost is noise next to jpg decode. | |
| with open(self.shards[int(self.shard_idx[i])], "rb") as fh: | |
| fh.seek(int(self.off[i])) | |
| return fh.read(int(self.size[i])) | |
| def __getitem__(self, i): | |
| import io | |
| im = Image.open(io.BytesIO(self._read(i))).convert("RGB") | |
| return self.tf(im), i | |
| if __name__ == "__main__": | |
| import argparse | |
| ap = argparse.ArgumentParser() | |
| ap.add_argument("--build-index", action="store_true") | |
| ap.add_argument("--workers", type=int, default=32) | |
| a = ap.parse_args() | |
| if a.build_index: | |
| build_index(a.workers) | |