Vision
image labeling
image tagging
vision classification

Image Classification

Assigning labels to images — single-label or multi-label. Foundational vision task; modern multimodal LLMs handle this competently in addition to specialized classifiers.

Capability notes

Local image classification splits into two approaches in 2026: specialized vision models (CLIP, SigLIP, DINOv2) and multimodal LLMs prompted to classify. Specialized models are 10–100× faster and more accurate for defined label sets. Multimodal LLMs handle open-vocabulary classification — "is this photo showing signs of water damage?" — without retraining but at 3–20× higher compute cost. CLIP ViT-L/14 (OpenAI, MIT-licensed) embeds images into a shared text–image space. Zero-shot classification: embed candidate labels, compute cosine similarity to image embedding, pick highest. Accuracy on ImageNet-1K zero-shot: 75.5% top-1. With prompt engineering ("a photo of a {label}") accuracy rises to 76.2%. OpenCLIP ViT-H/14 (LAION-2B trained) reaches 78.0% top-1 — the open-weight zero-shot ceiling. SigLIP (Google, more permissive license) trades some zero-shot flexibility for 2–3× faster inference with a sigmoid loss that produces better-calibrated probabilities. DINOv2 (Meta, Apache 2.0) produces visual features that excel at fine-grained classification — distinguishing bird species, car models, plant varieties where CLIP's coarse alignment fails. DINOv2 ViT-g/14 reaches 86.4% linear-probe accuracy on iNaturalist 2021 vs CLIP's 72.1%. Requires a small classifier head trained on ~500–5,000 labeled examples per class. Multimodal LLMs — [Llama 3.2 Vision](/models/llama-3-3-70b), Qwen2.5-VL, InternVL2 — can classify images from natural language descriptions. Accuracy on fine-grained tasks: 82–88% with 11B+ parameter VLMs. Tradeoff: 2–8 seconds per image on [RTX 4090](/hardware/rtx-4090) vs 2–20 ms for a specialized classifier. Use VLMs when your label set changes frequently or classification criteria are subjective. Use CLIP/DINOv2 when labels are stable and throughput matters.

If you just want to try this

Lowest-friction path to a working setup.

Start with [Ollama](/tools/ollama) running a VLM for zero-setup classification. Install Ollama, pull a vision model: ```bash ollama pull llama3.2-vision:11b-instruct-q4_K_M ``` Then classify images via Ollama's API. Python example using requests: ```python import requests, base64, json with open("photo.jpg", "rb") as f: img_b64 = base64.b64encode(f.read()).decode() resp = requests.post("http://localhost:11434/api/generate", json={ "model": "llama3.2-vision:11b-instruct-q4_K_M", "prompt": "Classify this image into one of: indoor, outdoor_nature, outdoor_urban, document.", "images": [img_b64], "stream": False }) print(resp.json()["response"]) ``` This runs on [RTX 3060 12GB](/hardware/rtx-3060-12gb), [RTX 4060 Ti 16GB](/hardware/rtx-4060-ti-16gb), or any 8 GB+ GPU. Classification time: 2–5 seconds per image on consumer hardware. For higher throughput (100+ images/second), switch to CLIP via [Hugging Face Transformers](/tools/transformers): ```python from transformers import pipeline classifier = pipeline("zero-shot-image-classification", model="openai/clip-vit-large-patch14") result = classifier("photo.jpg", candidate_labels=["indoor", "outdoor_nature", "outdoor_urban", "document"]) print(result[0]["label"], result[0]["score"]) ``` CLIP ViT-L uses 2.5 GB VRAM and classifies at 30–80 images/second on [RTX 4090](/hardware/rtx-4090). For fine-grained classification (species, products, defects), use DINOv2 with a linear probe — train on 500 labeled examples with scikit-learn's LogisticRegression on extracted features.

For production deployment

Operator-grade recommendation.

Production image classification pipelines prioritize throughput, accuracy, and latency based on use case. **Batch inference pipeline.** For 10K–1M images/day at <100 ms latency, use [ONNX Runtime](/tools/llama-cpp) with CLIP ViT-B/32 quantized to FP16. Preprocess images to 224×224 on CPU, run encoder on GPU. Throughput on [L4](/hardware/nvidia-l4) (24 GB): 600–900 images/second at batch=64. On [L40S](/hardware/nvidia-l40s) (48 GB): 1,200–1,800 images/second. **Fine-grained classification.** DINOv2 ViT-g + linear classifier head. Extract features once per image (cached to vector DB), classify via lightweight logistic regression. Retrieval: cosine similarity against labeled embeddings in [pgvector](/tools/pgvector) or [Qdrant](/tools/qdrant). 1M stored embeddings at 1536 dimensions = 6 GB storage. Retrieval + classification at 5,000–15,000 queries/second on CPU. **Accuracy targets.** General multi-class (ImageNet-style, 1000 classes): 75–82% top-1 for zero-shot CLIP/SigLIP; 85–90% for fine-tuned. Fine-grained (species, product SKU): 80–92% with DINOv2 + linear probe. Subjective classification (image quality, aesthetic rating): 65–78% — multimodal LLMs outperform specialized models on subjective tasks but at 50–100× higher compute. Benchmark on your data — ImageNet zero-shot accuracy does not predict domain-specific accuracy. **Multi-model ensemble.** Route easy samples (high CLIP confidence >0.9) through fast CLIP; route ambiguous samples to a VLM like [Llama 3.2 Vision](/models/llama-3-3-70b) via [vLLM](/tools/vllm). Typical split: 80% fast, 20% VLM. Reduces average latency from 3 seconds (all-VLM) to 150 ms while maintaining 92%+ accuracy on ambiguous 20%. **Label drift monitoring.** Production label distributions shift. Implement drift detection: compare daily class distribution against 30-day rolling average using KS test or PSI. Trigger retraining when PSI > 0.1. Embedding drift: track mean cosine similarity between daily and reference embeddings — alert when similarity drops below 0.95.

What breaks

Failure modes operators see in the wild.

**Zero-shot label mismatch.** Symptom: CLIP assigns high confidence to wrong labels. "A photo of a jaguar" applied to a car image returns 0.89 confidence for "jaguar" (animal). Cause: CLIP encodes both visual and textual semantics — ambiguous labels produce dual-domain matches. Mitigation: add context to labels ("a wildlife photo of a jaguar" vs "a photo of a Jaguar automobile"), use SigLIP for better-calibrated probabilities, maintain negative label set for disambiguation. **Fine-grained confusion.** Symptom: classifying bird species — CLIP assigns "American Robin" 0.67 vs "Varied Thrush" 0.64 (both correct-looking). Cause: CLIP's contrastive pretraining optimizes for coarse image–text alignment, not fine-grained visual differences. Mitigation: switch to DINOv2 with linear probe for fine-grained domains. DINOv2's self-supervised training learns per-patch features that capture species-level detail. **Open-vocabulary hallucination with VLMs.** Symptom: VLM classifies image of an empty desk as containing "a laptop, coffee cup, and notebook" when none are present. Cause: VLMs are generative — they predict plausible descriptions, not constrained to observable elements. Mitigation: prompt-engineer with "List ONLY items VISIBLE in the image. Do not infer or assume." Use structured output (JSON schema) forcing a boolean per candidate label. For critical classification, use CLIP + VLM agreement — require both agree for confidence. **Batch OOM on high-res inputs.** Symptom: 4K×3K photos at batch=32 exhaust 24 GB VRAM in preprocessing. Cause: image encoder processes full-resolution inputs before pooling — VRAM scales with (height × width × batch). Mitigation: resize to model's native resolution (224×224 for CLIP, 384×384 for ViT-L) before batching. Use a CPU-based preprocessing pipeline (Albumentations, torchvision) feeding GPU in streaming mode. **Label space explosion.** Symptom: zero-shot classification with 10,000+ candidate labels — 90+ seconds per image. Cause: classification runs dot product against every candidate — O(labels × embedding_dim). Mitigation: hierarchical classification — first-stage CLIP into broad category (20 classes), second-stage specialized model within category. Reduces compute from O(10K) to O(√10K + 20). Precompute text embeddings once and reuse.

Hardware guidance

**Hobbyist tier ($300–600).** [RTX 3060 12GB](/hardware/rtx-3060-12gb): CLIP ViT-L at 15–30 images/second, DINOv2 ViT-B at 25–45 images/second. Fits VLM classification (llama3.2-vision:11b Q4) at 3–8 seconds/image. [Intel Arc B580](/hardware/intel-arc-b580) at 12 GB: CLIP at 20–35 images/second via OpenVINO backend. [RX 7600 XT](/hardware/rx-7600-xt) at 16 GB: CLIP at 15–25 images/second — AMD ROCm support for Transformers is spotty; fallback to ONNX Runtime with DirectML. **Enthusiast tier ($1,500–2,500).** [RTX 4090](/hardware/rtx-4090) at 24 GB: CLIP ViT-L at 60–80 images/second batch=16, VLM classification at 2–3 seconds/image. Runs both CLIP pipeline + VLM fallback on same card. [RTX 5080](/hardware/rtx-5080) at 16 GB: CLIP at 50–70 images/second but VLM requires 16 GB — tight for 11B models. [RTX 5090](/hardware/rtx-5090) at 32 GB: same throughput as 4090 for classification but handles larger VLM batch sizes and 90B vision models. **SMB tier ($6,000–15,000).** [RTX 6000 Ada](/hardware/rtx-6000-ada) at 48 GB: CLIP at 80–110 images/second batch=64. Fits DINOv2 ViT-g (1.1B params) for fine-grained classification at 30–50 images/second. [L40S](/hardware/nvidia-l40s) at 48 GB: identical profile, datacenter form factor. **Enterprise tier ($25,000+).** [A100 80GB SXM](/hardware/nvidia-a100-80gb-sxm): DINOv2 ViT-g batch=128 at 80–120 images/second. Handles multi-model ensemble (CLIP + DINOv2 + VLM) in single GPU. [H100 PCIe](/hardware/nvidia-h100-pcie): provides no meaningful throughput gain for classification — encoders are memory-bandwidth-bound, not compute-bound. A100's 2.0 TB/s vs H100's 2.0 TB/s = identical. **CPU-only classification.** 16-core x86: CLIP ViT-B at 2–5 images/second via ONNX Runtime with OpenVINO optimizations. Acceptable for <1,000 images/day. [Apple M4 Pro](/hardware/apple-m4-pro): CLIP at 15–25 images/second via CoreML — best CPU inference. DINOv2 ViT-B: 8–12 images/second.

Runtime guidance

**Transformers vs ONNX vs vLLM — runtime selection by throughput requirement.** [Hugging Face Transformers](/tools/transformers) is the default: `pipeline("zero-shot-image-classification")` works out of the box. CLIP, SigLIP, DINOv2 all supported natively. Best for prototyping, research, and sub-1,000 images/day. Python API is consistent across model architectures. Tradeoff: ~20–40% lower throughput than optimized runtimes due to dynamic batching overhead and Python GIL. For production throughput, export models to ONNX and use ONNX Runtime with CUDA execution provider. A CLIP ViT-B ONNX model processes 3–5× more images/second than the equivalent Transformers pipeline, primarily from eliminating Python overhead on per-token operations and using fused CUDA kernels. Export script: `optimum-cli export onnx --model openai/clip-vit-base-patch32 clip_onnx/`. For Intel GPUs, use OpenVINO execution provider; for AMD, use ROCm or DirectML. [MLX-LM](/tools/mlx-lm) on Apple Silicon: CLIP ViT-L via MLX at 30–50 images/second on [M4 Max](/hardware/macbook-pro-16-m4-max). Native Metal acceleration without CUDA translation layer. MLX's unified memory model eliminates GPU→CPU transfers for preprocessing — load image via PIL, resize on CPU, MLX handles GPU transfer internally. For VLM-based classification at scale, [vLLM](/tools/vllm) with its continuous batching serves llama3.2-vision and Qwen2.5-VL at 15–30 concurrent requests on single [L40S](/hardware/nvidia-l40s). Each classification request (image + label prompt) processes in 2–5 seconds. vLLM's prefix caching reuses vision encoder outputs when same image receives multiple label queries — useful for multi-label classification where one image is queried against 20+ label sets. **Decision tree.** <1,000 images/day, changing labels: Transformers CLI + VLM. 1K–100K images/day, stable labels: ONNX Runtime + CLIP/SigLIP. >100K images/day: ONNX Runtime + custom C++ serving with gRPC. Fine-grained classification: DINOv2 feature extraction (Transformers) + [pgvector](/tools/pgvector) for similarity search. VLM fallback for ambiguous cases: [Ollama](/tools/ollama) for <100 ambiguous/day, [vLLM](/tools/vllm) for >100/day.

Setup walkthrough

  1. pip install transformers torch torchvision.
  2. Python script for zero-shot classification (no training needed):
from transformers import pipeline
classifier = pipeline("zero-shot-image-classification", model="openai/clip-vit-large-patch14")
result = classifier("photo.jpg", candidate_labels=["cat", "dog", "bird", "car"])
print(result)  # [{"label": "cat", "score": 0.95}, ...]
  1. First classification in <1 second on GPU, ~2-5 seconds on CPU.
  2. For custom classes with training: pip install timm → load a pre-trained ViT or ConvNeXt → fine-tune on your labeled images (50-200 images per class, ~5-30 minutes training on GPU).
  3. For production: use ONNX Runtime — export the model to ONNX format for 2-3× faster inference.
  4. For video classification: process frames with the same pipeline, aggregate predictions across frames.

The cheap setup

Image classification is extremely hardware-efficient. CLIP ViT-B/16 (300 MB) classifies images at 50-100 images/second on any laptop CPU. A $300 refurbished laptop handles 100K+ images/day classification. For fine-tuning: a used GTX 1060 6 GB ($60) trains a ResNet-50 on 1,000 images per class in 15-30 minutes. For real-time video classification (30 fps), add a used GTX 1660 Super 6 GB ($100). Classification is the cheapest AI task — even Raspberry Pi 5 does 5-10 classifications/second.

The serious setup

Any RTX GPU is overkill for classification. A used RTX 3060 12 GB (~$200-250, see /hardware/rtx-3060-12gb) runs ViT-Large at 500-1,000 images/second — 3M+ images/hour. Fine-tunes ViT on 10K images in ~5 minutes. For massive-scale classification (100M+ images): the bottleneck is storage I/O and data loading, not GPU compute. Pair with fast NVMe storage and a high-core-count CPU. Total: ~$800-1,000. Classification is almost never the compute bottleneck in a pipeline — spend your budget on storage and data preprocessing instead.

Common beginner mistake

The mistake: Using a multimodal LLM (GPT-4V, Qwen2-VL) for batch image classification when you have 100K images to process. Why it fails: VLMs generate text autoregressively — they read the image, then generate "cat" token-by-token. Each classification takes 2-5 seconds and costs ~1,000 tokens (vs. 0.01 seconds for a dedicated classifier). At 100K images, that's 50-250 hours and millions of tokens vs. 16 minutes with a classifier. The fix: Use VLMs for one-off tasks or ambiguous cases. For batch classification, use a dedicated classifier (CLIP, ViT, ConvNeXt). They produce a single forward pass → probability distribution in milliseconds. Use the VLM only for the 1% of images the classifier is uncertain about.

Recommended setup for image classification

Recommended runtimes

Browse all tools for runtimes that fit this workload.

Reality check

Local AI workloads have real hardware constraints that vary by task type. VRAM ceiling decides what model fits; bandwidth decides decode speed; compute decides prefill speed. Pick the GPU tier that fits your actual workload, not the spec sheet.

Common mistakes

  • Buying for spec-sheet VRAM without modeling KV cache + activation overhead
  • Underestimating quantization quality loss below Q4
  • Skipping flash-attention support (real perf gap on long context)
  • Ignoring sustained-load thermals (laptops thermal-throttle within 30 min)

What breaks first

The errors most operators hit when running image classification locally. Each links to a diagnose+fix walkthrough.

Before you buy

Verify your specific hardware can handle image classification before committing money.

Specialized buyer guides
Updated 2026 roundup