MIC CLIP-integration (files_sha256 a7bce4f31eb6)
Browse files- README.md +26 -0
- integration.json +90 -0
- integrations/transformers/usage.md +83 -0
README.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
tags:
|
| 3 |
+
- mic
|
| 4 |
+
- test-artifact
|
| 5 |
+
base_model:
|
| 6 |
+
- openai/clip-vit-base-patch32
|
| 7 |
+
---
|
| 8 |
+
|
| 9 |
+
# MIC: CLIP zero-shot image classification
|
| 10 |
+
|
| 11 |
+
Model integration contract (MIC) for one usage path, across the checkpoints that share it. This repository holds the contract code and the manifest; each framework keeps its own expected results and pins this repository by revision. The model repositories are unchanged. It is a test artifact, not a model: exclude it from model search.
|
| 12 |
+
|
| 13 |
+
Usage path: CLIPProcessor + CLIPModel, image-caption matching, batched.
|
| 14 |
+
|
| 15 |
+
| File | What it is |
|
| 16 |
+
| --- | --- |
|
| 17 |
+
| [`integration.json`](integration.json) | Manifest: checkpoints, which fixture covers each, frameworks, entry points, variants, unsupported targets, comparison rules |
|
| 18 |
+
| [`integrations/transformers/usage.md`](integrations/transformers/usage.md) | Transformers contract, written as doc-builder runnable markdown: the same blocks are documentation and test |
|
| 19 |
+
|
| 20 |
+
| Checkpoint | Slim fixture (every framework PR) |
|
| 21 |
+
| --- | --- |
|
| 22 |
+
| [`openai/clip-vit-base-patch32`](https://huggingface.co/openai/clip-vit-base-patch32) | [`hf-internal-testing/proto-clip-vit-base-patch32-slim`](https://huggingface.co/hf-internal-testing/proto-clip-vit-base-patch32-slim) |
|
| 23 |
+
|
| 24 |
+
Checked outputs: `image_to_text`, `text_to_image`, `logits_per_image`, `text_kwargs_input_ids`, `image_processor_config_keys`, `training.loss`, `training.gradients`, `training.updated`.
|
| 25 |
+
|
| 26 |
+
A fixture pass and a real-checkpoint pass have different scopes; either establishes agreement on fixed inputs and a recorded runtime, not correctness on arbitrary inputs.
|
integration.json
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"mic": "0.3",
|
| 3 |
+
"name": "CLIP zero-shot image classification",
|
| 4 |
+
"usage": "CLIPProcessor + CLIPModel, image-caption matching, batched",
|
| 5 |
+
"architecture": "CLIPModel",
|
| 6 |
+
"checkpoints": {
|
| 7 |
+
"openai/clip-vit-base-patch32": {
|
| 8 |
+
"fixture": "hf-internal-testing/proto-clip-vit-base-patch32-slim"
|
| 9 |
+
}
|
| 10 |
+
},
|
| 11 |
+
"fixtures": {
|
| 12 |
+
"hf-internal-testing/proto-clip-vit-base-patch32-slim": {
|
| 13 |
+
"built_from": "openai/clip-vit-base-patch32",
|
| 14 |
+
"covers": [
|
| 15 |
+
"openai/clip-vit-base-patch32"
|
| 16 |
+
],
|
| 17 |
+
"build": {
|
| 18 |
+
"seed": 17
|
| 19 |
+
}
|
| 20 |
+
}
|
| 21 |
+
},
|
| 22 |
+
"integrations": {
|
| 23 |
+
"transformers": {
|
| 24 |
+
"entry_point": "integrations/transformers/usage.md",
|
| 25 |
+
"format": "runnable-markdown",
|
| 26 |
+
"requires": [
|
| 27 |
+
"transformers>=5",
|
| 28 |
+
"torch",
|
| 29 |
+
"Pillow"
|
| 30 |
+
],
|
| 31 |
+
"targets": [
|
| 32 |
+
"fixtures",
|
| 33 |
+
"checkpoints"
|
| 34 |
+
],
|
| 35 |
+
"variants": {
|
| 36 |
+
"default": {},
|
| 37 |
+
"eager": {
|
| 38 |
+
"attn_implementation": "eager"
|
| 39 |
+
},
|
| 40 |
+
"bfloat16": {
|
| 41 |
+
"dtype": "bfloat16"
|
| 42 |
+
}
|
| 43 |
+
},
|
| 44 |
+
"training": true,
|
| 45 |
+
"resources": {
|
| 46 |
+
"fixture": {
|
| 47 |
+
"memory_gb": 1,
|
| 48 |
+
"download_mb": 20
|
| 49 |
+
},
|
| 50 |
+
"openai/clip-vit-base-patch32": {
|
| 51 |
+
"memory_gb": 2,
|
| 52 |
+
"download_mb": 605
|
| 53 |
+
}
|
| 54 |
+
}
|
| 55 |
+
}
|
| 56 |
+
},
|
| 57 |
+
"outputs": {
|
| 58 |
+
"runtime": {
|
| 59 |
+
"compare": "exact"
|
| 60 |
+
},
|
| 61 |
+
"image_to_text": {
|
| 62 |
+
"compare": "exact"
|
| 63 |
+
},
|
| 64 |
+
"text_to_image": {
|
| 65 |
+
"compare": "exact"
|
| 66 |
+
},
|
| 67 |
+
"logits_per_image": {
|
| 68 |
+
"compare": "allclose",
|
| 69 |
+
"atol": 0.0001,
|
| 70 |
+
"rtol": 0.0001
|
| 71 |
+
},
|
| 72 |
+
"text_kwargs_input_ids": {
|
| 73 |
+
"compare": "exact"
|
| 74 |
+
},
|
| 75 |
+
"image_processor_config_keys": {
|
| 76 |
+
"compare": "exact"
|
| 77 |
+
},
|
| 78 |
+
"training.loss": {
|
| 79 |
+
"compare": "allclose",
|
| 80 |
+
"atol": 0.0001,
|
| 81 |
+
"rtol": 0.0001
|
| 82 |
+
},
|
| 83 |
+
"training.gradients": {
|
| 84 |
+
"compare": "all_true"
|
| 85 |
+
},
|
| 86 |
+
"training.updated": {
|
| 87 |
+
"compare": "true"
|
| 88 |
+
}
|
| 89 |
+
}
|
| 90 |
+
}
|
integrations/transformers/usage.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# CLIP: zero-shot image classification with Transformers
|
| 2 |
+
|
| 3 |
+
This page is the Transformers contract of the CLIP MIC and also a usage example. [doc-builder](https://github.com/huggingface/doc-builder/blob/main/docs/runnable-code-blocks.md) renders the `runnable` blocks below as documentation, and its pytest plugin runs them as written against `openai/clip-vit-base-patch32`. The MIC runner runs the same blocks against each slim fixture and each checkpoint in [`integration.json`](../../integration.json). Lines marked `# doc-builder: hide` only matter there: they swap in the pinned checkpoint or variant and print the result record.
|
| 4 |
+
|
| 5 |
+
## Match images to captions
|
| 6 |
+
|
| 7 |
+
```py runnable:clip
|
| 8 |
+
import torch
|
| 9 |
+
from PIL import Image
|
| 10 |
+
from transformers import CLIPModel, CLIPProcessor, set_seed
|
| 11 |
+
import json # doc-builder: hide
|
| 12 |
+
import os # doc-builder: hide
|
| 13 |
+
|
| 14 |
+
model_id = "openai/clip-vit-base-patch32"
|
| 15 |
+
model_id = os.environ.get("MIC_MODEL", model_id) # doc-builder: hide
|
| 16 |
+
variant = json.loads(os.environ.get("MIC_MODEL_KWARGS", "{}")) # doc-builder: hide
|
| 17 |
+
device = "cuda" if torch.cuda.is_available() else "cpu"
|
| 18 |
+
set_seed(0) # seeds torch, NumPy, and Python: loading, dropout, and data augmentation draw random numbers
|
| 19 |
+
|
| 20 |
+
processor = CLIPProcessor.from_pretrained(model_id)
|
| 21 |
+
model = CLIPModel.from_pretrained(model_id).to(device)
|
| 22 |
+
if variant: # doc-builder: hide
|
| 23 |
+
model = CLIPModel.from_pretrained(model_id, **variant).to(device)
|
| 24 |
+
|
| 25 |
+
colors = {"red": (255, 0, 0), "green": (0, 255, 0), "blue": (0, 0, 255), "yellow": (255, 255, 0)}
|
| 26 |
+
images = [Image.new("RGB", (256, 256), rgb) for rgb in colors.values()]
|
| 27 |
+
captions = [f"a photo of a {name} square" for name in colors]
|
| 28 |
+
inputs = processor(text=captions, images=images, return_tensors="pt", padding=True).to(device, model.dtype) # floating-point inputs follow the model's dtype
|
| 29 |
+
|
| 30 |
+
with torch.no_grad():
|
| 31 |
+
logits_per_image = model(**inputs).logits_per_image
|
| 32 |
+
best = logits_per_image.softmax(dim=1).argmax(dim=1)
|
| 33 |
+
for name, index in zip(colors, best.tolist()):
|
| 34 |
+
print(f"{name} image -> {captions[index]!r}")
|
| 35 |
+
```
|
| 36 |
+
|
| 37 |
+
## Pass options to one modality
|
| 38 |
+
|
| 39 |
+
A processor call can route options to one of its inputs, here padding to the text only. Integrations also read the preprocessing configuration without building a processor.
|
| 40 |
+
|
| 41 |
+
```py runnable:clip:3
|
| 42 |
+
from transformers.models.auto.image_processing_auto import get_image_processor_config
|
| 43 |
+
|
| 44 |
+
text_only = processor(text=captions, images=images, return_tensors="pt", text_kwargs={"padding": True})
|
| 45 |
+
print(text_only["input_ids"].shape)
|
| 46 |
+
|
| 47 |
+
image_config = get_image_processor_config(model_id)
|
| 48 |
+
print(sorted(image_config))
|
| 49 |
+
```
|
| 50 |
+
|
| 51 |
+
## One training step
|
| 52 |
+
|
| 53 |
+
```py runnable:clip:3
|
| 54 |
+
model.train()
|
| 55 |
+
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)
|
| 56 |
+
loss = model(**inputs, return_loss=True).loss
|
| 57 |
+
loss.backward()
|
| 58 |
+
before = {name: p.detach().clone() for name, p in model.named_parameters()} # doc-builder: hide
|
| 59 |
+
optimizer.step()
|
| 60 |
+
print(f"loss: {loss.item():.4f}")
|
| 61 |
+
|
| 62 |
+
if os.environ.get("MIC_RUNNER"): # doc-builder: hide
|
| 63 |
+
named = dict(model.named_parameters())
|
| 64 |
+
checked = ("visual_projection.weight", "text_projection.weight")
|
| 65 |
+
result = {
|
| 66 |
+
"runtime": {
|
| 67 |
+
"device": model.device.type,
|
| 68 |
+
"dtype": str(model.dtype).removeprefix("torch."),
|
| 69 |
+
"attn_implementation": model.config._attn_implementation,
|
| 70 |
+
},
|
| 71 |
+
"image_to_text": best.tolist(),
|
| 72 |
+
"text_to_image": logits_per_image.argmax(dim=0).tolist(),
|
| 73 |
+
"logits_per_image": logits_per_image.float().tolist(),
|
| 74 |
+
"text_kwargs_input_ids": text_only["input_ids"].tolist(),
|
| 75 |
+
"image_processor_config_keys": sorted(image_config),
|
| 76 |
+
"training": {
|
| 77 |
+
"loss": loss.item(),
|
| 78 |
+
"gradients": {n: bool(named[n].grad is not None and torch.count_nonzero(named[n].grad) > 0 and torch.isfinite(named[n].grad).all()) for n in checked},
|
| 79 |
+
"updated": any(not torch.equal(p, before[n]) for n, p in named.items()),
|
| 80 |
+
},
|
| 81 |
+
}
|
| 82 |
+
print(json.dumps(result))
|
| 83 |
+
```
|