AD-Copilot: A Vision-Language Assistant for Industrial Anomaly Detection via Visual In-context Comparison

April 25, 2026 · View on GitHub

arXiv Model Demo License

Xi Jiang, Yue Guo, Jian Li, Yong Liu, Bin-Bin Gao, Hanqiu Deng, Jun Liu, Heng Zhao, Chengjie Wang, Feng Zheng

Southern University of Science and Technology  |  Tencent YouTu Lab  |  Macau University of Science and Technology  |  A*STAR

Abstract

Multimodal Large Language Models (MLLMs) have achieved impressive success in natural visual understanding, yet they consistently underperform in industrial anomaly detection (IAD). This is because MLLMs trained mostly on general web data differ significantly from industrial images. Moreover, they encode each image independently and can only compare images in the language space, making them insensitive to subtle visual differences that are key to IAD. To tackle these issues, we present AD-Copilot, an interactive MLLM specialized for IAD via visual in-context comparison. We first design a novel data curation pipeline to mine inspection knowledge from sparsely labeled industrial images, yielding a large-scale multimodal dataset Chat-AD (620k+ samples, 327 categories). AD-Copilot incorporates a novel Comparison Encoder that employs cross-attention between paired image features to enhance multi-image fine-grained perception, and is trained with a multi-stage strategy that incorporates domain knowledge and gradually enhances IAD skills. We also introduce MMAD-BBox, an extended benchmark for anomaly localization with bounding-box evaluation.

AD-Copilot achieves 82.3% accuracy on the MMAD benchmark, outperforming all proprietary and open-source models (including GPT-4o, Gemini 1.5 Pro) without any data leakage, and surpasses ordinary human performance on several IAD tasks.

News

  • [2026-04] Online demo available: HuggingFace Space
  • [2026-03] Paper released on arXiv: arXiv:2603.13779
  • [2026-03] Model weights released on HuggingFace
  • [Coming Soon] Chat-AD dataset and MMAD-BBox benchmark

Architecture

The Comparison Encoder performs cross-attention between paired image features to generate comparison tokens, enabling visual in-context comparison at the encoding stage. This design preserves original image representations while producing compact comparison tokens for downstream reasoning.

Models

ModelSizeBackboneDescriptionLink
AD-Copilot7BQwen2.5-VL-7BBase model for anomaly detectionjiang-cc/AD-Copilot
AD-Copilot-Thinking7BQwen2.5-VL-7BThinking variant with chain-of-thought reasoningjiang-cc/AD-Copilot-Thinking

Results

MMAD Benchmark (1-shot)

ModelScaleAnomaly Disc.Defect Cls.Defect Loc.Defect Desc.Defect Ana.Object Cls.Object Ana.Average
Human (expert)-95.2475.0092.3183.3394.2086.1180.3786.65
GPT-4o-68.6365.8055.6273.2183.4194.9882.8074.92
Qwen2.5-VL7B71.1056.0260.6964.1378.2691.4983.6772.19
AD-Copilot7B73.6467.8964.0880.6085.9191.0687.7878.71
AD-Copilot-Thinking7B73.9574.2976.4084.9286.9391.8687.6782.29

MMAD-BBox Benchmark (1-shot)

ModelScalemIoU (%)ACC@IoU 0.1ACC@IoU 0.3ACC@IoU 0.5
Qwen2.5-VL7B10.4728.3918.8313.39
AD-Copilot7B24.4655.6643.7734.78
AD-Copilot-Thinking7B25.3055.2244.7635.88

Installation

# Clone the repository
git clone https://github.com/jam-cc/AD-Copilot.git
cd AD-Copilot

# Create conda environment
conda create -n ad-copilot python=3.10 -y
conda activate ad-copilot

# Install dependencies
pip install -r requirements.txt

Quick Start

Inference

import torch
from transformers import AutoModelForImageTextToText, AutoProcessor
from qwen_vl_utils import process_vision_info
from PIL import Image

model_path = "jiang-cc/AD-Copilot"

processor = AutoProcessor.from_pretrained(
    model_path,
    min_pixels=64 * 28 * 28,
    max_pixels=1280 * 28 * 28,
    trust_remote_code=True,
)

model = AutoModelForImageTextToText.from_pretrained(
    model_path,
    torch_dtype=torch.bfloat16,
    attn_implementation="flash_attention_2",
    device_map="auto",
    trust_remote_code=True,
).eval()

# Load images
good_image = Image.open("path/to/good_image.png")
test_image = Image.open("path/to/test_image.png")

# Build messages
messages = [
    {
        "role": "user",
        "content": [
            {"type": "image", "image": good_image},
            {"type": "image", "image": test_image},
            {"type": "text", "text": "The first image is a normal sample. "
             "Is there any anomaly in the second image? A. Yes B. No. "
             "Please answer the letter only."},
        ],
    }
]

# Run inference
text = processor.apply_chat_template(
    messages, tokenize=False, add_generation_prompt=True
)
image_inputs, video_inputs = process_vision_info(messages)
inputs = processor(
    text=[text], images=image_inputs, videos=video_inputs,
    padding=True, return_tensors="pt",
).to(model.device)

generated_ids = model.generate(**inputs, max_new_tokens=128, do_sample=False)
generated_ids_trimmed = [
    out[len(inp):] for inp, out in zip(inputs.input_ids, generated_ids)
]
output = processor.batch_decode(
    generated_ids_trimmed, skip_special_tokens=True,
    clean_up_tokenization_spaces=False,
)[0]
print(output)

Command-Line Inference

# Basic inference
python scripts/inference.py \
    --model_path jiang-cc/AD-Copilot \
    --good_image path/to/good.png \
    --bad_image path/to/test.png

# With custom prompt
python scripts/inference.py \
    --model_path jiang-cc/AD-Copilot \
    --good_image path/to/good.png \
    --bad_image path/to/test.png \
    --prompt "The first image is a normal sample. Please describe the anomaly in the second image." \
    --max_new_tokens 256

# Benchmark mode (latency + throughput)
python scripts/inference.py \
    --model_path jiang-cc/AD-Copilot \
    --good_image path/to/good.png \
    --bad_image path/to/test.png \
    --benchmark

Supported Tasks

TaskExample Prompt
Anomaly DiscriminationThe first image is a normal sample. Is there any anomaly in the second image? A. Yes B. No.
Defect ClassificationThe first image is a normal sample. What is the type of defect? A. Contamination B. Broken C. Scratch D. No defect.
Defect DescriptionThe first image is a normal sample. Please describe the anomaly in the second image in detail.
Defect LocalizationThe first image is a normal sample. Please locate the defects within the second image with bounding box in JSON format.

Evaluation

# Run evaluation on MMAD benchmark
python scripts/evaluate_mmad.py \
    --model_path jiang-cc/AD-Copilot \
    --data_root /path/to/MMAD/dataset \
    --output_dir results/

See scripts/ for more details.

Environment

Key dependencies (see requirements.txt for full list):

PackageVersion
torch>= 2.4.0
transformers== 4.57.3
flash-attn>= 2.7.0 (recommended)
accelerate>= 0.30.0
qwen_vl_utilslatest

Note: flash-attn significantly speeds up inference but requires CUDA dev tools to compile. If unavailable, the model falls back to SDPA attention automatically.

Demo

Try AD-Copilot online: HuggingFace Space

The demo supports:

  • Comparison-based anomaly detection (reference + test image)
  • Single-image tasks (object counting, OCR)
  • Automatic bounding box visualization

License

This project is released under the Apache 2.0 License.

Citation

If you find this work useful, please cite our paper:

@article{jiang2026adcopilot,
  title   = {AD-Copilot: A Vision-Language Assistant for Industrial Anomaly
             Detection via Visual In-context Comparison},
  author  = {Jiang, Xi and Guo, Yue and Li, Jian and Liu, Yong and
             Gao, Bin-Bin and Deng, Hanqiu and Liu, Jun and Zhao, Heng
             and Wang, Chengjie and Zheng, Feng},
  journal = {arXiv preprint arXiv:2603.13779},
  year    = {2026}
}

Acknowledgements

AD-Copilot is built upon Qwen2.5-VL. We thank the Qwen team for their excellent foundation model.