Skip to content

MOBILECLIP2 · IMAGE CLASSIFICATION

MobileCLIP2: choose a model and classify an image

Compare S0, S2 and the larger variants, then run image–text matching with your own labels. MobileCLIP2 produces embeddings for classification and retrieval; use FastVLM when you need a written answer.

S0 / S2 site test: 24 images, CPU latency and memory →

Which MobileCLIP2 model?

Start with S0 for the smallest image encoder. S2 raises published ImageNet accuracy from 71.5% to 77.2%. Evaluate the larger models on your actual images before accepting their extra memory and compute costs.

ModelImage encoder (M)Text encoder (M)ImageNet top-1 (%)
S0 ↗11.463.471.5
S2 ↗35.763.477.2
B ↗86.363.479.4
S3 ↗125.1123.680.7
L-14 ↗304.3123.681.9
S4 ↗321.6123.681.9

Apple-published model-card values, checked September 12, 2026. Parameter counts are in millions; ImageNet zero-shot top-1 is accuracy on that benchmark, not a prediction for your images. Apple model card

Run your own image classification

  1. Create a Python environment and install the packages below.
  2. Download mobileclip2.py and save it next to your image.
  3. Run the command with at least two candidate labels. The first run downloads model weights.
  4. Inspect the JSON ranking. Change the labels to test whether the distinction is useful for your task.
Python · macOS / Linux
python -m venv .venv
source .venv/bin/activate
python -m pip install "open_clip_torch==3.3.0" "timm==1.0.29" torch pillow
curl -fLO https://fastvlm.net/examples/mobileclip2.py
python mobileclip2.py image.png --model S0 --labels "a receipt" "a chart" "a photograph"
Download Python example ↓
mobileclip2.py
"""Classify a local image against candidate labels with MobileCLIP2.

Install: python -m pip install "open_clip_torch==3.3.0" "timm==1.0.29" torch pillow
Run: python mobileclip2.py image.png --labels 'a receipt' 'a chart' 'a photograph'
Uses the timm/OpenCLIP adaptation of Apple's weights, downloaded on first run.
Source: https://huggingface.co/timm/MobileCLIP2-S0-OpenCLIP
"""
import argparse
import json
from pathlib import Path

import open_clip
import torch
from PIL import Image
from timm.utils import reparameterize_model


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument('image', type=Path)
    parser.add_argument('--model', choices=['S0', 'S2', 'B', 'S3', 'L-14', 'S4'], default='S0')
    parser.add_argument('--labels', nargs='+', required=True)
    args = parser.parse_args()
    if not args.image.is_file():
        parser.error('The image file does not exist.')
    if len(args.labels) < 2:
        parser.error('Provide at least two candidate labels.')
    name = 'MobileCLIP2-' + args.model
    device = 'cuda' if torch.cuda.is_available() else 'cpu'
    model, _, preprocess = open_clip.create_model_and_transforms(name, pretrained='dfndr2b')
    model = reparameterize_model(model.eval()).to(device)
    tokenizer = open_clip.get_tokenizer(name)
    image = preprocess(Image.open(args.image).convert('RGB')).unsqueeze(0).to(device)
    text = tokenizer(args.labels).to(device)
    with torch.inference_mode():
        image_features = model.encode_image(image)
        text_features = model.encode_text(text)
        image_features /= image_features.norm(dim=-1, keepdim=True)
        text_features /= text_features.norm(dim=-1, keepdim=True)
        scores = (100.0 * image_features @ text_features.T).softmax(dim=-1)[0].cpu().tolist()
    results = sorted(zip(args.labels, scores), key=lambda item: item[1], reverse=True)
    print(json.dumps({'model': name, 'scores': [{'label': label, 'score': score} for label, score in results],
        'note': 'Relative scores within the supplied labels, not calibrated probabilities.'}, indent=2))


if __name__ == '__main__':
    main()

Expected output: a JSON object with the model and labels sorted by score. Scores are relative to your candidate set; they are not calibrated probabilities. Try both relevant and unrelated labels.

This example uses the timm/OpenCLIP adaptation of Apple’s model. The original Apple checkpoint and the OpenCLIP-compatible files use different naming and loading paths.

MobileCLIP, MobileCLIP2, CLIP or FastVLM?

  • MobileCLIP → MobileCLIP2: compare the same size and preprocessing on your own labeled images. Version 2 changes the training recipe; do not apply first-generation speed claims to every v2 model.
  • CLIP / SigLIP alternatives: use the same image set, candidate labels and device. Compare accuracy, latency and memory together.
  • FastVLM: choose generative image question answering when a ranked list of labels cannot answer the question.
Try FastVLM image questions →

Troubleshooting

  • Unknown model: update open_clip_torch and timm; check that open_clip.list_models() includes MobileCLIP2-S0.
  • Incorrect results: keep the model in eval mode and use its own preprocess and tokenizer.
  • Download fails: check your connection to Hugging Face and available disk space.

Sources and downloads