mlfoundations/open_clip

★ 14,143⑂ 0

An open source implementation of CLIP.

14,143Star
0Fork
0Watch
0Issue
PythonLanguage
-License
Created · last push · repository size 0 KB · default branch -

README

OpenCLIP

[[Paper]](https://arxiv.org/abs/2212.07143) [[Citations]](#citing) [[Clip Colab]](https://colab.research.google.com/github/mlfoundations/open_clip/blob/master/docs/Interacting_with_open_clip.ipynb) [[Coca Colab]](https://colab.research.google.com/github/mlfoundations/open_clip/blob/master/docs/Interacting_with_open_coca.ipynb) pypi

⚠️ Main branch training stack notice
> main now uses the post-refactor training stack by default. Training is organized around TrainingTask wrappers, dict-based batches, FSDP2 support, NaFlex image/audio pipelines, and multiple torch.compile strategies. The scope has grown well beyond the original refactor and now includes several new model families. For the older release-stable training API, pin to the v3 branch or the latest 3.x release on PyPI. Inference usage of pretrained image/text models is still intended to be compatible, but training scripts and downstream integrations should review the changes below before upgrading.
> New / experimental model families on main:
- NaFlex CLIP — variable-resolution/aspect image towers (timm naflexvit) with token-budget batching (--use-naflex, naflex_* configs)
- NaFlex CLAP — audio-text contrastive training with variable-duration audio (naflexclap_* configs)
- NaFlex GenLIP / GenLAP — generative image/audio captioning with prefix-LM attention and packed [media ; text] rows (naflexgenlip_*, naflexgenlap_* configs, tiktoken text)
- Modern text towertext_cfg.text_arch="modern": RoPE, SwiGLU/ReLU², RMSNorm, masked pooling (eos/mean/map), with optional qk-norm, gated attention, register tokens, sandwich norm, value residuals, and zero-init residual (moderntext-* configs)
- Variable-length texttext_cfg.variable_text=true pads captions to the per-batch max instead of a fixed context length (works with the modern tower and HF towers)
- Hugging Face ModernBERT text towers — e.g. gte-modernbert-base-ViT-B-32-256
- MaMMUT — single text decoder used in two passes per the paper: bi-directional without cross-attention for contrastive learning, causal with cross-attention for captioning (trains via the CoCa task/loss). Two config families, mirroring coca/coca2: mammut_* reproduces the original LAION-fork numerics exactly via legacy flags (pool_type="avg_all", use_pad_mask=false) and loads the released LAION openMaMMUT-ViT-L-14 weights (pretrained tag datacomp1b_s12_8b_b180k, or directly via hf-hub: — fork-format configs and state dicts are translated on load); mammut2_* uses the corrected defaults (masked-mean text pooling, pad masking). A modern-arch decoder variant is available via multimodal_cfg.text_arch="modern" (mammut2-moderntext_*)
- CoCa v2 configscoca2_*: paper-faithful attentional pooling (vision_cfg.attentional_pool="cascade", the paper's default — a separate single-query contrastive pooler, so the caption decoder now cross-attends over all 256 generative pooler tokens instead of 255, fixing #458) and the corrected CLS/pad attention mask (text_cfg.correct_cls_mask=true), per #554. A modern-text variant pairs the modern tower with a modern multimodal decoder (coca2-moderntext_*). Existing coca_* configs and released weights are unchanged
- Text validity masks for generative models — CoCa/MaMMUT forward()/encode_text() accept text_valid ([B, L], True = real token); tokenizers can emit exact masks (tokenizer(texts, output_mask=True)), and caption labels are masked to -100 from them. Fixes the SimpleTokenizer pad-collision class (id 0 is a real token, '!' merges like x!=y emit it mid-caption); absent a mask, behavior falls back to the historical text != pad_id derivation. Text towers keep the HF-style attention_mask kwarg at the tower boundary
- Variable text with gradient accumulation — CoCa/MaMMUT support different caption lengths across microbatches in both training entrypoints. Model forwards retain each microbatch's text length; caption logits and masked labels are padded when combining loss inputs, preserving the mean over all valid target tokens. This applies to the logits-based caption loss; --fused-caption-loss still requires --accum-freq 1.
> Breaking changes — training CLI:
- --horovod removed (Horovod support deleted; DDP/FSDP2 only)
- --torchscript and --trace removed (torch.jit is being deprecated upstream)
- Default --precision changed from ampamp_bf16 (silent behavior change; pass --precision amp explicitly to keep fp16 AMP)
- SigLIP's --loss-dist-impl now defaults to gather, as does standalone SigLipLoss. Pass --loss-dist-impl bidir to keep bidirectional ring exchange; reduce and shift remain available. Gather stores all ranks' text features on each rank.
- --naflex-max-tokens-per-batch now defaults to unset. The local token budget is inferred as --batch-size * max(--naflex-seq-lens); GenLIP/GenLAP also include their caption-token cap in the per-row cost. Pass an explicit token budget to preserve older runs that relied on the previous 16384 default.
> New training CLI flags (opt-in):
- --siglip-chunk-size — image rows per SigLIP logits chunk (0 disables). For example, --siglip --siglip-chunk-size 1024 enables chunking in both current and legacy training.
- --fsdp — use FSDP2 (fully_shard) instead of DDP
- --fsdp-no-reshard-after-forward, --fsdp-offload-cpu
- --fsdp-checkpoint {full,sharded} — full gathers to rank-0 as a single .pt; sharded uses DCP per-rank shards (faster, lower memory)
- --torchcompile-strategy {task,model,step} — choose whether torch.compile captures task forward/loss, the underlying model, or the full single-batch train step
- --use-naflex and --naflex-* flags — enable NaFlex variable-aspect image pipelines for compatible timm/OpenCLIP ViT-family models (token-budget batching via --naflex-seq-lens / --naflex-max-tokens-per-batch; the same machinery drives the NaFlex audio and generative models)
- --audio- and --audio-zeroshot- flags — enable CLAP audio preprocessing/training and Hugging Face audio zero-shot evaluation
- --length-bucketing, --bucket-pool, --bucket-chunk — reorder the train stream by sample length (caption and/or audio tokens) to tighten per-batch padding; the bucket pool holds raw, undecoded samples
- --text-pad-multiple — round per-batch variable-text length up to a multiple, bounding the distinct sequence lengths torch.compile sees (text-axis analogue of --naflex-pad-multiple)
- --text-attention-mask — emit a per-sample text validity mask (batch key text_valid) from the tokenizer, consumed by CoCa/MaMMUT for attention/pooling and -100 caption-label masking. Default auto-enables for CoCa/MaMMUT (except under --distill) and is rejected for tasks that don't consume it
- --caption-z-loss-weight, --caption-loss-compute-dtype {float32,model}, and --caption-loss-chunk-size — configure the next-token objective shared by CoCa/MaMMUT and GenLIP/GenLAP. Defaults preserve the existing fp32 CE with no z-loss; model preserves the loss-logit dtype and ambient autocast policy while returned loss/component scalars remain fp32
> Breaking changes — Python API:
- trace_model removed from the top-level open_clip namespace
- load_openai_model, list_openai_models, and build_model_from_openai_state_dict removed. Original-OpenAI weights are still loadable through the standard create_model_from_pretrained(..., pretrained='openai') path, which now routes through HuggingFace Hub (timm/*_clip.openai) instead of torch.jit.load on openaipublic.azureedge.net archives. Removing the JIT path closes an arbitrary-code-execution surface (JIT archives can ship pickled code).
- Training pipeline wraps model + loss in a TrainingTask subclass (CLIPTask, SigLIPTask, CoCaTask, DistillCLIPTask, CLAPTask). Code that previously called train_one_epoch(model, loss, ...) or evaluate(model, ...) directly should switch to passing a task. Tasks construct their own losses; create_loss("clip", ...) is available for standalone training loops (see below).
- Data pipelines emit dict batches instead of tuples. Image/text loaders use {"image": ..., "text": ...}; CLAP audio loaders use {"audio": ..., "text": ...}. Tuple-style image/text calls through task(images, texts) still work via a backward-compat path, but downstream code that iterates a dataloader directly should read the named keys.
- CoCa's autoregressive label shift moved out of coca_model.py and into CoCaTask. coca_model.forward() no longer performs the [:, :-1] / [:, 1:] slicing — callers that relied on that behavior outside training should handle labels themselves.
- CoCa's exact-mask API adds text_valid after text in encode_text, forward, and forward_intermediates. This shifts the older trailing positional arguments (normalize, image_latent, image_indices, and so on); pass those arguments by keyword. For example, replace model.encode_text(text, False) with model.encode_text(text, normalize=False).
- CLIPTextCfg.eos_id no longer defaults to 2 (that value is only correct for XLM-style vocabs). Configs using pool_type="eos" must set eos_id explicitly, and get_tokenizer now validates eos_id/pad_id against the resolved tokenizer, raising on mismatch instead of pooling/masking silently wrong positions.
- HFTokenizer no longer fabricates pad_token_id=0 when the underlying tokenizer has no pad token (id 0 is a real token in most BPE vocabs); variable-text setups fail fast instead. It also forces padding_side='right', which all OpenCLIP pooling/masking assumes.
- Tokenizer wrappers now share special-token controls: encode(..., add_special_tokens=False) remains body-only by default, while model-facing tokenizer(...) defaults to add_special_tokens=True. decode() / batch_decode() default to skip_special_tokens=False, stop_at_eos=True; pass stop_at_eos=False to inspect tokens after the first EOS. This intentionally changes legacy SimpleTokenizer decode output by hiding post-EOS id-0 fill (!) and makes TikToken decode render its reserved control tokens unless skip_special_tokens=True.
- Model traits replace model-name sniffing. Every model carries model.traits (open_clip.get_model_traits(model)): family, objectives, NaFlex/variable-text contracts. The training entrypoints derive NaFlex data, variable text, the --text-attention-mask default and the grad-accum / distill guards from the built model via apply_model_traits, so hf-hub: and renamed configs no longer need a magic substring; args.genlip / args.genlap / args.naflexclap are gone and the data loaders (get_data, get_wds_dataset, ...) take model_traits. --use-naflex now always sets force_naflex_vision, which the factory treats as a no-op for NaFlex-native and audio models. GenLIP configs get NaFlex transforms from a plain create_model_and_transforms call. create_task() likewise selects the task from the built model. MaMMUT decoders now honor multimodal_cfg.variable_text (previously dropped), so mammut2-moderntext_* configs train with per-batch padded text.
- MaxPooler (hf_pooler_type="max_pooler") mask polarity fixed — it previously max-pooled over the padding positions instead of the valid ones.
- CoCa.__init__ no longer takes a pad_id argument — model.pad_id is derived from the text tower (the id it actually masks with: text_cfg.pad_id for native towers, the transformers config pad for HF towers). MaMMUT follows the same pattern. This fixes coca_roberta-*, which previously masked with roberta's pad (1) in the tower while the loss ignored 0 — its config now declares pad_id: 1 and the caption loss no longer trains on padding.
- CoCaTask builds caption labels masked to -100; CoCaLoss's cross-entropy uses ignore_index=-100. Its pad_id arg is retained for standalone callers passing raw labels (default 0 preserves the old value-based behavior; the task path passes None). Validation generative-loss metrics are likewise mask/pad-aware and will report different (correct) values for nonzero-pad models.
- Standalone loss factory: create_loss(loss_type, *, ...) takes an explicit loss type ("clip", "distill_clip", "siglip", "coca", or "genlip") and flat keyword options, with no model, traits, or CLI namespace required. For example, create_loss("siglip", chunk_size=1024) or create_loss("coca", caption_loss_weight=2.0, clip_loss_weight=1.0, pad_id=1). CoCa/MaMMUT callers must explicitly pass a pad ID for raw labels or pad_id=None for labels already masked to -100; caption logits and labels must already be aligned for next-token prediction. Non-default options unsupported by the selected loss raise. The legacy trainer preserves its create_loss(args, model=...) call through open_clip_train.loss.create_loss_from_args, which resolves model traits, the actual pad ID, and compile-aware label caching. There is no model-name fallback.
- --lock-image now freezes vision attentional poolers (they were previously left trainable when locking CoCa-style towers, and were ungrouped under --image-layer-decay).
- MultimodalTransformer (the CoCa text decoder) now initializes its parameters — previously its init_parameters was never called and text_projection was uninitialized memory on fresh builds. New training runs won't bit-match runs started under older code; checkpoint loading is unaffected. generate() for CoCa/MaMMUT now derives pad/bos/eos ids from the model/tower/HF config instead of hardcoding CLIP token ids (fixes generation for HF-tower CoCa), and shares one implementation in open_clip.generation.
- get_tokenizer validation is stricter for generative configs (CoCa/MaMMUT/GenLIP): an explicit nonzero pad_id with a tokenizer that reserves no pad token raises, and an unset pad_id against a reserved nonzero tokenizer pad warns (the pad-value fallback would train the caption loss on padding).
- WebDataset pipelines now assemble as tokenize -> [length bucketing] -> decode -> transform so the bucket pool holds raw bytes instead of decoded images/waveforms (10-50x less dataloader-worker memory). The old decode-first assembly is preserved in open_clip_train.legacy_data (no bucketing/NaFlex) and used by legacy_main.
> Dependency bump: Minimum torch>=2.6 (was >=2.0). This is the version where torch.load(weights_only=True) became the default — all checkpoint loads in this repo now pass weights_only=True explicitly with no weights_only=False fallback. If you're resuming training with a custom optimizer that pickles non-allowlisted Python types, register them via torch.serialization.add_safe_globals([...]) before calling load_checkpoint.
> Checkpoint compatibility: Existing pretrained .pt checkpoints load without changes. Training checkpoints saved on main include a state_dict key that's compatible with prior versions; EMA, optimizer state, and optional training counters are also preserved. 0-D vs 1-D scalar reshape from the FSDP path is reconciled on load, so you can resume a DDP-trained checkpoint under FSDP2 and vice versa.
> Legacy training entry point: python -m open_clip_train.legacy_main remains available for older image/text training scripts that need the pre-task loop, and pairs with the frozen decode-first data pipelines in open_clip_train.legacy_data. It does not support the full task-era feature set (for example FSDP2, EMA, CLAP audio training, NaFlex, length bucketing, or the task/step torch.compile integration), and should be treated as a compatibility shim rather than the path for new training work.

Welcome to an open source implementation of OpenAI's CLIP (Contrastive Language-Image Pre-training).

Using this codebase, we have trained several models on a variety of data sources and compute budgets, ranging from small-scale experiments to larger runs including models trained on datasets such as LAION-400M, LAION-2B and DataComp-1B. Many of our models and their scaling properties are studied in detail in the paper reproducible scaling laws for contrastive language-image learning. Some of the best models we've trained and their zero-shot ImageNet-1k accuracy are shown below, along with the ViT-L model trained by OpenAI and other state-of-the-art open source alternatives (all can be loaded via OpenCLIP). We provide more details about our full collection of pretrained models here, and zero-shot results for 38 datasets here.

| Model | Training data | Resolution | # of samples seen | ImageNet zero-shot acc. | | -------- | ------- | ------- | ------- | ------- | | ConvNext-Base | LAION-2B | 256px | 13B | 71.5% | | ConvNext-Large | LAION-2B | 320px | 29B | 76.9% | | ConvNext-XXLarge | LAION-2B | 256px | 34B | 79.5% | | ViT-B-32-256 | DataComp-1B | 256px | 34B | 72.8% | | ViT-B-16 | DataComp-1B | 224px | 13B | 73.5% | | ViT-L-14 | LAION-2B | 224px | 32B | 75.3% | | ViT-H-14 | LAION-2B | 224px | 32B | 78.0% | | ViT-L-14 | DataComp-1B | 224px | 13B | 79.2% | | ViT-bigG-14 | LAION-2B | 224px | 34B | 80.1% | | | | | | | | ViT-L-14-quickgelu (Original CLIP) | WIT | 224px | 13B | 75.5% | | ViT-SO400M-14-SigLIP (SigLIP) | WebLI | 224px | 45B | 82.0% | | ViT-L-14 (DFN) | DFN-2B | 224px | 39B | 82.2% | | ViT-L-16-256 (SigLIP2) | WebLI (multi-lang) | 256px | 40B | 82.5% | | ViT-SO400M-14-SigLIP-384 (SigLIP) | WebLI | 384px | 45B | 83.1% | | ViT-H-14-quickgelu (DFN) | DFN-5B | 224px | 39B | 83.4% | | PE-Core-L-14-336 (PE) | MetaCLIP-5.4B | 336px | 58B | 83.5% | | ViT-SO400M-16-SigLIP2-384 (SigLIP2) | WebLI (multi-lang) | 384px | 40B | 84.1% | | ViT-H-14-378-quickgelu (DFN) | DFN-5B | 378px | 44B | 84.4% | | ViT-gopt-16-SigLIP2-384 (SigLIP2) | WebLI (multi-lang) | 384px | 40B | 85.0% | | PE-Core-bigG-14-448 (PE) | MetaCLIP-5.4B | 448px | 86B | 85.4% |

Model cards with additional model specific details can be found on the Hugging Face Hub under the OpenCLIP library tag: https://huggingface.co/models?library=open_clip.

If you found this repository useful, please consider citing. We welcome anyone to submit an issue or send an email if you have any other requests or suggestions.

Note that portions of src/open_clip/ modelling and tokenizer code are adaptations of OpenAI's official repository.

Approach

| CLIP | |:--:| | Image Credit: https://github.com/openai/CLIP |

Usage

pip install open_clip_torch
import torch
from PIL import Image
import open_clip

model, _, preprocess = open_clip.create_model_and_transforms('ViT-B-32', pretrained='laion2b_s34b_b79k') model.eval() # model in train mode by default, impacts some models with BatchNorm or stochastic depth active tokenizer = open_clip.get_tokenizer('ViT-B-32')

image = preprocess(Image.open("docs/CLIP.png")).unsqueeze(0) text = tokenizer(["a diagram", "a dog", "a cat"])

with torch.no_grad(), torch.autocast("cuda"): 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)

text_probs = (100.0 * image_features @ text_features.T).softmax(dim=-1)

print("Label probs:", text_probs) # prints: [[1., 0., 0.]]

If model uses timm image encoders (convnext, siglip, eva, etc) ensure the latest timm is installed. Upgrade timm if you see 'Unknown model' errors for the image encoder.

If model uses transformers tokenizers, ensure transformers is installed.

See also this [[Clip Colab]](https://colab.research.google.com/github/mlfoundations/open_clip/blob/master/docs/Interacting_with_open_clip.ipynb).

To compute billions of embeddings efficiently, you can use clip-retrieval which has openclip support.

Pretrained models

We offer a simple model interface to instantiate both pre-trained and untrained models. To see which pretrained models are available, use the following code snippet. More details about our pretrained models are available here.

>>> import open_clip
>> open_clip.list_pretrained()

You can find more about the models we support (e.g. number of parameters, FLOPs) in this table.

NOTE: Many existing checkpoints use the QuickGELU activation from the original OpenAI models. This activation is actually less efficient than native torch.nn.GELU in recent versions of PyTorch. The model defaults are now nn.GELU, so one should use model definitions with -quickgelu postfix for the OpenCLIP pretrained weights. All OpenAI pretrained weights will always default to QuickGELU. One can also use the non -quickgelu model definitions with pretrained weights using QuickGELU but there will be an accuracy drop, for fine-tune that will likely vanish for longer runs. Future trained models will use nn.GELU.

Loading models

Models can be loaded with open_clip.create_model_and_transforms, as shown in the example below. The model name and corresponding pretrained keys are compatible with the outputs of open_clip.list_pretrained().

The pretrained argument also accepts local paths, for example /path/to/my/b32.pt. You can also load checkpoints from huggingface this way. To do so, download the open_clip_pytorch_model.bin file (for example, https://huggingface.co/laion/CLIP-ViT-L-14-DataComp.XL-s13B-b90K/tree/main), and use pretrained=/path/to/open_clip_pytorch_model.bin.

# pretrained also accepts local paths
model, _, preprocess = open_clip.create_model_and_transforms('ViT-B-32', pretrained='laion2b_s34b_b79k') 

Fine-tuning on classification tasks

This repository is focused on training CLIP models. To fine-tune a trained zero-shot model on a downstream classification task such as ImageNet, please see our other repository: WiSE-FT. The WiSE-FT repository contains code for our paper on Robust Fine-tuning of Zero-shot Models, in which we introduce a technique for fine-tuning zero-shot models while preserving robustness under distribution shift.

Data

To download datasets as webdataset, we recommend img2dataset.

Conceptual Captions

See cc3m img2dataset example.

More Image Trending projects

1
2

Comfy-Org / ComfyUI

Python★ 133,239⑂ 0
3

opencv / opencv

C++★ 90,840⑂ 0
4
5

d2l-ai / d2l-zh

Python★ 80,681⑂ 0
6

unslothai / unsloth

Python★ 76,181⑂ 0