mlfoundations/open_clip
An open source implementation of CLIP.
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)
⚠️ Main branch training stack notice
>mainnow uses the post-refactor training stack by default. Training is organized aroundTrainingTaskwrappers, dict-based batches, FSDP2 support, NaFlex image/audio pipelines, and multipletorch.compilestrategies. 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 thev3branch 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 (timmnaflexvit) 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 tower —text_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 text — text_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 tagdatacomp1b_s12_8b_b180k, or directly viahf-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 viamultimodal_cfg.text_arch="modern"(mammut2-moderntext_*)
- CoCa v2 configs —coca2_*: 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_*). Existingcoca_*configs and released weights are unchanged
- Text validity masks for generative models — CoCa/MaMMUTforward()/encode_text()accepttext_valid([B, L], True = real token); tokenizers can emit exact masks (tokenizer(texts, output_mask=True)), and caption labels are masked to-100from them. Fixes the SimpleTokenizer pad-collision class (id 0 is a real token,'!'merges likex!=yemit it mid-caption); absent a mask, behavior falls back to the historicaltext != pad_idderivation. Text towers keep the HF-styleattention_maskkwarg 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-lossstill requires--accum-freq 1.
> Breaking changes — training CLI:
- --horovod removed (Horovod support deleted; DDP/FSDP2 only)
---torchscriptand--traceremoved (torch.jitis being deprecated upstream)
- Default--precisionchanged fromamp→amp_bf16(silent behavior change; pass--precision ampexplicitly to keep fp16 AMP)
- SigLIP's--loss-dist-implnow defaults togather, as does standaloneSigLipLoss. Pass--loss-dist-impl bidirto keep bidirectional ring exchange;reduceandshiftremain available. Gather stores all ranks' text features on each rank.
---naflex-max-tokens-per-batchnow 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 previous16384default.
> New training CLI flags (opt-in):
---siglip-chunk-size— image rows per SigLIP logits chunk (0disables). For example,--siglip --siglip-chunk-size 1024enables 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;shardeduses DCP per-rank shards (faster, lower memory)
---torchcompile-strategy {task,model,step}— choose whethertorch.compilecaptures task forward/loss, the underlying model, or the full single-batch train step
---use-naflexand--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 lengthstorch.compilesees (text-axis analogue of--naflex-pad-multiple)
---text-attention-mask— emit a per-sample text validity mask (batch keytext_valid) from the tokenizer, consumed by CoCa/MaMMUT for attention/pooling and-100caption-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;modelpreserves the loss-logit dtype and ambient autocast policy while returned loss/component scalars remain fp32
> Breaking changes — Python API:
-trace_modelremoved from the top-levelopen_clipnamespace
-load_openai_model,list_openai_models, andbuild_model_from_openai_state_dictremoved. Original-OpenAI weights are still loadable through the standardcreate_model_from_pretrained(..., pretrained='openai')path, which now routes through HuggingFace Hub (timm/*_clip.openai) instead oftorch.jit.loadonopenaipublic.azureedge.netarchives. Removing the JIT path closes an arbitrary-code-execution surface (JIT archives can ship pickled code).
- Training pipeline wrapsmodel + lossin aTrainingTasksubclass (CLIPTask,SigLIPTask,CoCaTask,DistillCLIPTask,CLAPTask). Code that previously calledtrain_one_epoch(model, loss, ...)orevaluate(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 throughtask(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 ofcoca_model.pyand intoCoCaTask.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 addstext_validaftertextinencode_text,forward, andforward_intermediates. This shifts the older trailing positional arguments (normalize,image_latent,image_indices, and so on); pass those arguments by keyword. For example, replacemodel.encode_text(text, False)withmodel.encode_text(text, normalize=False).
-CLIPTextCfg.eos_idno longer defaults to2(that value is only correct for XLM-style vocabs). Configs usingpool_type="eos"must seteos_idexplicitly, andget_tokenizernow validateseos_id/pad_idagainst the resolved tokenizer, raising on mismatch instead of pooling/masking silently wrong positions.
-HFTokenizerno longer fabricatespad_token_id=0when 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 forcespadding_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-facingtokenizer(...)defaults toadd_special_tokens=True.decode()/batch_decode()default toskip_special_tokens=False, stop_at_eos=True; passstop_at_eos=Falseto 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 unlessskip_special_tokens=True.
- Model traits replace model-name sniffing. Every model carriesmodel.traits(open_clip.get_model_traits(model)): family, objectives, NaFlex/variable-text contracts. The training entrypoints derive NaFlex data, variable text, the--text-attention-maskdefault and the grad-accum / distill guards from the built model viaapply_model_traits, sohf-hub:and renamed configs no longer need a magic substring;args.genlip/args.genlap/args.naflexclapare gone and the data loaders (get_data,get_wds_dataset, ...) takemodel_traits.--use-naflexnow always setsforce_naflex_vision, which the factory treats as a no-op for NaFlex-native and audio models. GenLIP configs get NaFlex transforms from a plaincreate_model_and_transformscall.create_task()likewise selects the task from the built model. MaMMUT decoders now honormultimodal_cfg.variable_text(previously dropped), somammut2-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 apad_idargument —model.pad_idis derived from the text tower (the id it actually masks with:text_cfg.pad_idfor native towers, the transformers config pad for HF towers). MaMMUT follows the same pattern. This fixescoca_roberta-*, which previously masked with roberta's pad (1) in the tower while the loss ignored 0 — its config now declarespad_id: 1and the caption loss no longer trains on padding.
-CoCaTaskbuilds caption labels masked to-100;CoCaLoss's cross-entropy usesignore_index=-100. Itspad_idarg is retained for standalone callers passing raw labels (default0preserves the old value-based behavior; the task path passesNone). 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)orcreate_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 orpad_id=Nonefor 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 itscreate_loss(args, model=...)call throughopen_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-imagenow 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 itsinit_parameterswas never called andtext_projectionwas 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 derivespad/bos/eosids from the model/tower/HF config instead of hardcoding CLIP token ids (fixes generation for HF-tower CoCa), and shares one implementation inopen_clip.generation.
-get_tokenizervalidation is stricter for generative configs (CoCa/MaMMUT/GenLIP): an explicit nonzeropad_idwith a tokenizer that reserves no pad token raises, and an unsetpad_idagainst a reserved nonzero tokenizer pad warns (the pad-value fallback would train the caption loss on padding).
- WebDataset pipelines now assemble astokenize -> [length bucketing] -> decode -> transformso the bucket pool holds raw bytes instead of decoded images/waveforms (10-50x less dataloader-worker memory). The old decode-first assembly is preserved inopen_clip_train.legacy_data(no bucketing/NaFlex) and used bylegacy_main.
> Dependency bump: Minimumtorch>=2.6(was>=2.0). This is the version wheretorch.load(weights_only=True)became the default — all checkpoint loads in this repo now passweights_only=Trueexplicitly with noweights_only=Falsefallback. If you're resuming training with a custom optimizer that pickles non-allowlisted Python types, register them viatorch.serialization.add_safe_globals([...])before callingload_checkpoint.
> Checkpoint compatibility: Existing pretrained.ptcheckpoints load without changes. Training checkpoints saved onmaininclude astate_dictkey that's compatible with prior versions; EMA, optimizer state, and optional training counters are also preserved.0-Dvs1-Dscalar 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_mainremains available for older image/text training scripts that need the pre-task loop, and pairs with the frozen decode-first data pipelines inopen_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/steptorch.compileintegration), 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
|
|
|:--:|
| 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.