Official implementation of AdaScope — an asynchronous coarse-to-fine framework designed for arbitrary-distribution infrared small target detection (IRSTD). AdaScope decouples target localization from context allocation via a divide-and-conquer strategy, reformulating coarse localization as a spatial existence classification problem and learning distribution-adaptive observation windows through reinforcement learning.
AdaScope is an asynchronous coarse-to-fine detector for arbitrary-distribution infrared small target detection: GEDM performs coarse localization by classifying spatial existence on a semantic grid (instead of fitting unstable cluster boundaries), and ARFR uses reinforcement learning (GRPO) to adaptively refine the observation window of each candidate, with the downstream detector's performance gain as the reward. Global and local predictions are fused by NMS.
git clone git@github.com:GrokCV/AdaScope.git
cd AdaScopeAll commands below must be run from the repository root.
conda create --name deepir python=3.9 -y
conda activate deepirInstall PyTorch with CUDA 11.8 (or a version matching your driver):
conda install pytorch torchvision torchaudio pytorch-cuda=11.8 \
-c pytorch \
-c nvidiapip install -U openmim
mim install mmengine
mim install "mmcv>=2.0.0"
mim install "mmdet>=3.0.0"python setup.py develop
# or
pip install -e .AdaScope is developed on the DenseSIRST infrared small-target dataset.
Download the dataset and place it under data/ so that the layout is:
data/DenseSIRST/SIRSTdevkit/
├── PNGImages/ # infrared images (*.png)
├── Splits/
│ ├── trainval_v2.txt # training split
│ └── test_v2.txt # testing split
└── SIRST/
├── BBox/ # single-instance annotations (*.xml)
└── Cluster_relabel_graph_v2/ # cluster annotations (*_with_clusters.xml)
If your data lives elsewhere, override DATA_ROOT in
configs/detection/_base_/datasets/adascope_densesirst.py.
AdaScope trains its cluster head and refiner against cluster-level annotations (a box that encloses a group of small targets). Generate them from the single-instance XMLs with the provided tools — run the first, then the second:
# (1) Graph-based clustering of the test split → Cluster_relabel_graph_v1
python tools/relabel_test_clusters_graph.py
# (2) Supplement Cluster_relabel_graph_v1 with singleton clusters so that every
# instance is covered → Cluster_relabel_graph_v2
python tools/build_cluster2_from_cluster1.pyThese two tools reproduce the
Cluster_relabel_graph_v2directory referenced by the training config. See the header of each script for its arguments.
AdaScope is trained in three stages automatically via the
SynWarmupSupGRPOStageHook:
| Stage | Epochs | What is trained |
|---|---|---|
| Pretrain | 1–12 | backbone / neck / GEDM cluster head / global head |
| Center offset SFT | 13–16 | ARFR (center alignment, supervised) |
| RL postraining4Scope | 17–28 | ARFR (context allocation, Scope Adjustment) |
CUDA_VISIBLE_DEVICES=0 python tools/train_det.py configs/detection/cluster/AdaScope.pyCUDA_VISIBLE_DEVICES=0,1,2,3 \
torchrun --nproc_per_node=4 \
tools/train_det.py configs/detection/cluster/AdaScope.pyCheckpoints are saved to work_dirs/adascope_fcos_densesirst/, with the best one
tracked by merged_voc/mAP.
The ARFR policy optimizer is pluggable. All variants share the same
coarse-to-fine pipeline (GEDM + ARFR + local FCOS) through the common base
detector AdaScopeRLDetector — only the detector/refiner classes and the
policy-stage name differ:
| Config | Policy optimizer |
|---|---|
AdaScope.py |
GRPO |
AdaScope_ppo.py |
PPO |
AdaScope_sac.py |
SAC |
AdaScope_trpo.py |
TRPO |
Train any variant with the same entry point:
CUDA_VISIBLE_DEVICES=0 python tools/train_det.py configs/detection/cluster/AdaScope.pyAdaScope_TOOD.py uses the same AdaScope detector/refiner and cluster head as
AdaScope.py, replacing the global FCOS head with a TOOD head. Its default
schedule is 20 epochs, matching the TOOD experiments reported in the paper.
Test with the corresponding config and checkpoint:
CUDA_VISIBLE_DEVICES=0 python tools/test_det.py \
configs/detection/cluster/AdaScope_ppo.py \
work_dirs/adascope_ppo_densesirst/best_merged_voc_mAP_epoch_XX.pthIf the cluster GT XML files are not found at training time, the refiner receives no valid proposals and all policy / refiner losses become zero. The symptom is easy to spot:
refiner_sup_num_validstays at 0 (or very low) in the training log- GPU memory usage is ~650 MiB instead of the normal ~1450 MiB
The base config configs/detection/_base_/datasets/adascope_densesirst.py
ships with a placeholder absolute path that does not exist on your machine:
DATA_ROOT = '/path/to/your/DenseSIRST/SIRSTdevkit'This is intentional — training will fail immediately with a FileNotFoundError
instead of silently loading empty cluster GT data. Edit DATA_ROOT to point
to your local DenseSIRST directory.
Diagnose
# Check whether cluster GT is loaded (memory should be ~1450 MiB)
grep "memory:" work_dirs/adascope_fcos_densesirst/train.log | head -5CUDA_VISIBLE_DEVICES=0 python tools/test_det.py \
configs/detection/cluster/AdaScope.py \
/path/to/best_merged_voc_mAP_epoch_XX.pthBy default the evaluator reports the merged metric (global + local fusion,
mAP @ IoU=0.5, 11-point VOC), which is also used for best-checkpoint selection.
To additionally report per-branch metrics (global / raw_cluster / refined_cluster
/ local), set SHOW_ALL_METRICS = True in
configs/detection/cluster/AdaScope.py.
Comparison with state-of-the-art methods on DenseSIRST (mAP and Recall under the VOC 11-point protocol at IoU=0.5; PR / F1 / F2 at a confidence threshold):
| Method | Backbone | FLOPs ↓ | Params ↓ | mAP50 ↑ | Recall50 ↑ | PR ↑ | F1 ↑ | F2 ↑ |
|---|---|---|---|---|---|---|---|---|
| One-stage | ||||||||
| FCOS | ResNet50 | 50.291G | 32.113M | 0.257 | 0.315 | 0.1571 | 0.2023 | 0.2445 |
| VFNet | ResNet50 | 48.317G | 32.709M | 0.253 | 0.336 | 0.1820 | 0.2251 | 0.2624 |
| YOLOX | — | 8.578G | 8.968M | 0.210 | 0.341 | 0.1450 | 0.1882 | 0.2291 |
| TOOD | ResNet50 | 50.456G | 32.018M | 0.256 | 0.355 | 0.1750 | 0.2224 | 0.2655 |
| DyHead | ResNet50 | 27.866G | 38.890M | 0.249 | 0.335 | 0.1650 | 0.2090 | 0.2488 |
| DDOD | ResNet50 | 46.514G | 32.378M | 0.253 | 0.335 | 0.1620 | 0.2079 | 0.2504 |
| GFL | ResNet50 | 52.296G | 32.258M | 0.264 | 0.367 | 0.1850 | 0.2331 | 0.2762 |
| Two-stage | ||||||||
| Cascade R-CNN | ResNet50 | 90.978G | 69.152M | 0.136 | 0.188 | 0.1150 | 0.1338 | 0.1484 |
| SABL | ResNet50 | 0.125T | 42.213M | 0.124 | 0.104 | 0.1050 | 0.0969 | 0.0926 |
| Dynamic R-CNN | ResNet50 | 63.179G | 41.348M | 0.184 | 0.235 | 0.1420 | 0.1678 | 0.1883 |
| End2End | ||||||||
| Sparse R-CNN | ResNet50 | 45.274G | 0.106G | 0.183 | 0.572 | 0.0850 | 0.1444 | 0.2488 |
| DAB-DETR | ResNet50 | 28.939G | 43.702M | 0.005 | 0.054 | 0.0100 | 0.0160 | 0.0250 |
| DQ-DETR | — | 783.57G | 58.68M | 0.0149 | 0.154 | 0.0200 | 0.0345 | 0.0610 |
| EFLNet | — | 65.49G | 38.335M | 0.152 | 0.1349 | 0.1400 | 0.1263 | 0.1193 |
| PConv | — | 65.32G | 37.136M | 0.164 | 0.179 | 0.1500 | 0.1525 | 0.1540 |
| Coarse2Fine | ||||||||
| DMNet | ResNet50 | 144.45G | 63.18M | 0.2239 | 0.1259 | 0.2400 | 0.1412 | 0.1132 |
| AdaZoom | ResNet50 | 49.96G | 31.887M | 0.052 | 0.348 | 0.0360 | 0.0554 | 0.0819 |
| YOLC | HRNet | 121.59G | 67.55M | 0.335 | 0.477 | 0.3416 | 0.3527 | 0.3597 |
| BAFE-Net | ResNet50 | 71.639G | 35.626M | 0.283 | 0.335 | 0.4275 | 0.3302 | 0.2905 |
| YOLD | HRNet | 122.62G | 67.61M | 0.171 | 0.371 | 0.3312 | 0.2172 | 0.1800 |
| SSCFNet | — | 76.29G | 19.24M | 0.3086 | 0.4351 | 0.9420 | 0.5704 | 0.4613 |
| HFMNet | — | 11.19G | 7.38M | 0.4117 | 0.5096 | 0.7629 | 0.6003 | 0.5322 |
| AdaScope (Ours) | ResNet50 | 44.95G | 30.05M | 0.602 | 0.732 | 0.6538 | 0.6291 | 0.6157 |
| Method | SIRST mAP50 | SIRST Recall | SIRST Params(M) | SIRST FLOPs(G) | SIRST FPS | IRSTD-1K mAP50 | IRSTD-1K Recall | IRSTD-1K Params(M) | IRSTD-1K FLOPs(G) | IRSTD-1K FPS |
|---|---|---|---|---|---|---|---|---|---|---|
| AdaScope | 82.93 | 81.65 | 30.05 | 44.95 | 31.87 | 59.04 | 63.64 | 30.05 | 44.95 | 31.87 |
| DNANet | 78.00 | 86.24 | 4.70 | 57.04 | 8.35 | 57.35 | 74.75 | 4.70 | 57.04 | 8.35 |
| ResUNet | 67.12 | 87.16 | 0.90 | 15.32 | 167.94 | 55.66 | 76.77 | 0.90 | 15.32 | 167.94 |
| ISNet | 0.00 | 0.00 | 1.09 | 122.47 | 35.28 | 0.67 | 8.75 | 1.09 | 122.47 | 35.28 |
| UIU-Net | 70.14 | 87.16 | 50.54 | 217.70 | 27.59 | 58.40 | 75.08 | 50.54 | 217.70 | 27.59 |
| ACM | 0.00 | 0.00 | 0.40 | 1.61 | 170.97 | 0.00 | 0.00 | 0.40 | 1.61 | 170.97 |
| ALCNet | 9.84 | 4.59 | 0.52 | 1.51 | 188.51 | 0.68 | 8.75 | 0.52 | 1.51 | 188.51 |
| SSCFNet | 23.96 | 80.73 | 19.24 | 76.29 | 13.33 | 25.35 | 85.86 | 19.24 | 76.29 | 13.33 |
| HFMNet | 39.40 | 79.91 | 7.38 | 11.19 | 33.25 | 49.33 | 86.87 | 7.38 | 11.19 | 33.25 |
AdaScope/
├── configs/
│ └── detection/
│ ├── _base_/
│ │ ├── datasets/adascope_densesirst.py # dataset + pipelines
│ │ ├── schedules/schedule_1x.py # LR schedule
│ │ └── default_runtime.py # runtime defaults
│ └── cluster/
│ ├── AdaScope.py # main experiment config (GRPO)
│ ├── AdaScope_ppo.py # PPO variant config
│ ├── AdaScope_sac.py # SAC variant config
│ ├── AdaScope_trpo.py # TRPO variant config
│ └── adascope_fcos_local.py # external local FCOS
├── deepir/
│ ├── models/
│ │ ├── detectors/
│ │ │ ├── adascope_detector.py # FixedFlatSyncGRPODetector (GRPO)
│ │ │ ├── adascope_rl_detector.py # AdaScopeRLDetector (shared base)
│ │ │ ├── adascope_ppo_detector.py # AdaScopePPODetector
│ │ │ ├── adascope_sac_detector.py # AdaScopeSACDetector
│ │ │ └── adascope_trpo_detector.py # AdaScopeTRPODetector
│ │ ├── refine/
│ │ │ ├── adascope_refiner.py # ARFR (GRPO refiner)
│ │ │ └── adascope_{ppo,sac,trpo}_refiner.py# RL variant refiners
│ │ └── cluster_heads/adascope_cluster_head.py# GEDM (C5 existence classifier)
│ ├── datasets/
│ │ ├── sirst_voc_det.py # DenseSIRST dataset
│ │ └── transforms/adascope_cluster_targets.py# cluster GT generation
│ ├── engine/hooks/adascope_stage_hook.py # shared 3-stage RL training hook
│ └── evaluation/metrics/selective_voc_metric.py# per-branch VOC metrics
├── tools/
│ ├── train_det.py / test_det.py # training & testing entry
│ ├── relabel_test_clusters_graph.py # cluster generation (v1)
│ └── build_cluster2_from_cluster1.py # cluster generation (v2)
└── docs/
├── pipeline.png
└── ARFR.png
If you find this work useful, please consider citing:
@article{adascope,
title={Beyond the Sparsity Assumption: Arbitrary-Distribution Infrared Small Target Detection},
author={Jingtang Chen, ZhuLiu, Mingjian Fu,Yimian Dai*},
journal={},
year={2026}
}This project is released under the Apache 2.0 license.
