Skip to main content

Fused Triton kernels for memory-efficient SigLIP and SigLIP+ training

Project description

siglip-kernel

Fused Triton kernels for memory-efficient SigLIP training. The first public fused GPU kernel for the sigmoid contrastive loss: tile-by-tile computation that never materializes the B × B logit matrix, reducing peak loss memory from O(B²) to O(B · D) and enabling per-device batch sizes that the standard implementation cannot allocate.

On Hopper (GH200/H100) at B=65,536 in BF16 the kernel runs the full loss forward+backward in 48.8 ms versus the eager cuBLAS reference's 102.0 ms (2.1× faster) on 1.4 GB versus 33 GB; the minimum-memory configuration (chunk_size=1024) uses 640 MB (52× less) at 54.3 ms. It beats even a torch.compiled reference from B=32,768 up and reaches B=262,144 on 5.6 GB where both references OOM. An opt-in FP8 forward (backend="chunked_bf16_fp8") adds ~5% with gradient error below the BF16 floor. See the paper for full benchmarks and validation (3-epoch CC12M pre-training, 500-step LiT, parity tests).

Install

git clone https://github.com/avocardio/siglip-kernel.git
cd siglip-kernel
pip install -e .

Requires PyTorch ≥ 2.1 and Triton ≥ 3.0.

Usage

import torch
from siglip_kernel import fused_siglip_loss

img = torch.randn(8192, 768, device="cuda", dtype=torch.bfloat16)
txt = torch.randn(8192, 768, device="cuda", dtype=torch.bfloat16)
img = torch.nn.functional.normalize(img, dim=-1)
txt = torch.nn.functional.normalize(txt, dim=-1)
log_temp = torch.tensor(2.302, device="cuda", requires_grad=True)  # ln(10)
bias     = torch.tensor(-10.0, device="cuda", requires_grad=True)

loss = fused_siglip_loss(img, txt, log_temp, bias)
loss.backward()

A dtype-aware router selects the right backend automatically: chunked-BF16 (cuBLAS GEMM + Triton fused BCE with the temperature/bias affine folded in-kernel) for bfloat16/float16, fully-fused Triton for float32. Pass backend= to override ("chunked_bf16", "chunked_bf16_fp8", "chunked_epilogue", "fused", "hopper", "fused_v2", or "reference"). The chunk size is adaptive (speed-optimal c=4096 on SM90+); pass chunk_size=1024 to the loss functions directly for the minimum-memory configuration. The forward path is free of host syncs and CUDA-graph capturable.

SigLIP+ (multi-positive)

fused_siglip_plus_loss is the same chunked fused kernel applied to SigLIP+, the multi-positive formulation where all image-text pairs sharing a group identifier are positives and positive mass is normalized per anchor (1/k weighting, both directions averaged when symmetric). Logits may be rectangular (M captions for N images); with unique group ids it reduces to standard SigLIP.

from siglip_kernel import fused_siglip_plus_loss, SigLIPPlusLoss

# functional: pre-normalized features, group ids mark positives
loss = fused_siglip_plus_loss(img, txt, log_temp, bias, img_gid, txt_gid)

# or the drop-in module (own logit_scale/bias, reference-compatible dict output)
loss_fn = SigLIPPlusLoss(temperature=0.07)
out = loss_fn([img_raw, txt_raw], img_gid=img_gid, txt_gid=txt_gid)

Verified exact against the reference implementation (FP32 gradients to 2e-7) across symmetric/asymmetric, soft-label, rectangular shapes, and rows without positives. The eager reference materializes the logit, mask, and weight matrices; the fused path stays O(chunk · M).

For multi-GPU, DistributedSigLIPPlusLoss computes the true global-batch objective over the same overlapped P2P ring: group ids are all-gathered once per step (kilobytes, no gradients), per-anchor 1/k weights come from global counts, and every ring block receives its source rank's gid slice — so captions of an image living on other ranks are correctly treated as positives, never false negatives. Verified exact vs a single-process global reference (FP32 gradients to 2.5e-6, groups deliberately scattered) on 4, 8, and 16 GH200s across up to 4 nodes. Global 65,536 images × 262,144 captions: 196 ms on 1 GPU → 57 (4) → 42 (8) → 35 ms (16); global 131,072 × 524,288 (68B pairs): 87 ms on 16 GPUs at 2 GB/rank. The communication overlap contributes 5–34%, growing with node count.

Multi-GPU

DistributedSigLIPLoss is a drop-in for OpenCLIP's SigLipLoss signature (it receives the already-exponentiated logit_scale). The ring strategy exchanges text blocks peer-to-peer, runs every local_B × local_B block through the fused kernel, and propagates text gradients back around the ring in backward — with communication overlapped behind block compute in both passes (overlap=True, default):

from siglip_kernel.distributed import DistributedSigLIPLoss

loss_fn = DistributedSigLIPLoss(strategy="ring", rank=rank, world_size=world_size)
loss = loss_fn(image_features, text_features, logit_scale, logit_bias)

Verified exact against a single-process full-batch reference (FP32 gradients to 1.5e-6) on 4 and 8 GH200s. Loss step time (fwd+bwd, D=768, BF16):

global B 1 GPU 4 GPU (NVLink) 8 GPU (2 nodes)
65,536 46.9 ms 13.1 ms 10.1 ms
131,072 193.4 ms 31.5 ms

The comm/compute overlap is worth ~5% on NVLink and 13–21% across nodes. On Slurm/HPE-Slingshot clusters, load the aws-ofi-nccl plugin — without it NCCL falls back to TCP and multi-node ring steps run ~7× slower.

GPU support

Architecture SM Status
Ampere (A100) SM80 Tested, autotuned tiles
Ada (RTX 4090, L40) SM89 Tested, FP8 path available
Hopper (H100, H200) SM90 Tested, persistent kernel + TMA
Blackwell (B200) SM100 Tested via Triton 3.7, no code changes

OpenCLIP integration

For users on OpenCLIP, a no-dependency pure-PyTorch chunked variant of SigLipLoss is proposed upstream as PR #1145. That PR addresses the memory side only; for the speed-up too, install this package and use fused_siglip_loss directly.

Tests

pip install -e .[dev]
pytest tests/

119 tests cover correctness (forward + backward parity vs FP32 reference), gradient stability, diagonal-offset placement for distributed blocks, FP8/epilogue backends, and edge shapes (odd batches, uneven chunks, offsets crossing chunk boundaries). The multi-process NCCL paths are additionally validated against a full-batch reference on 4 and 8 GH200s.

Citation

Paper source at avocardio/fusedsiglip_paper; preprint forthcoming.

License

Apache-2.0.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

siglip_kernel-0.1.2.tar.gz (40.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

siglip_kernel-0.1.2-py3-none-any.whl (38.6 kB view details)

Uploaded Python 3

File details

Details for the file siglip_kernel-0.1.2.tar.gz.

File metadata

  • Download URL: siglip_kernel-0.1.2.tar.gz
  • Upload date:
  • Size: 40.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.13

File hashes

Hashes for siglip_kernel-0.1.2.tar.gz
Algorithm Hash digest
SHA256 3be331a71d1b3aeae19387c495b99fbd111e89f8dbacb5d2060880a93366d659
MD5 f7d8107cacfb5e0d0db661a087b83983
BLAKE2b-256 06a00571e094f72a4cdd9a5808e2b59db475f54e43e099c60f2c0eee1d6d2762

See more details on using hashes here.

File details

Details for the file siglip_kernel-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: siglip_kernel-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 38.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.13

File hashes

Hashes for siglip_kernel-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 b5fd273cae8136ac44cbeddbd3927dca803688dd2bf5116f8279756166e9efbf
MD5 bfee94c833dcfefbb50fa6c0c5590bed
BLAKE2b-256 0f8d5ffe3cc639d0f67fcc0eb3b2e2aba6431fc10d3d764b4db58b16a6fc8b34

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page