SimpleDet Docs

Quickstart

This tutorial is the shortest path through the current repository. It explains not only what to run, but why the repo is split into a detector-definition step and a native-runtime execution step.

Use this page when you want one guided path from install to detector definition, training, and evaluation.

1. Install and run doctor

Install the CPU runtime extra first. It gives the quickstart the native PyTorch, Lightning, COCO metric, and image-loading dependencies used by training, testing, and inference.

python -m pip install 'simpledet[cpu]'
python -m simpledet doctor --workdir ./runs/quickstart

When working from a checkout, use python -m pip install -e '.[cpu]' instead. doctor reports missing optional extras as warnings unless you add --strict, so it is useful before deciding whether you need extras such as timm, geo, or plots.

2. Create a tiny local COCO fixture

This fixture exists only to verify the wiring. It creates two small RGB PNG files and three COCO-style annotation files under data/quickstart-coco, so the commands do not depend on private machine paths or external datasets.

python - <<'PY'
import json
import struct
import zlib
from pathlib import Path

root = Path("data/quickstart-coco")
(root / "imgs").mkdir(parents=True, exist_ok=True)
(root / "Annotations").mkdir(parents=True, exist_ok=True)

def chunk(kind, payload):
    return (
        struct.pack(">I", len(payload))
        + kind
        + payload
        + struct.pack(">I", zlib.crc32(kind + payload) & 0xFFFFFFFF)
    )

def write_png(path, width=64, height=64):
    row = b"\x00" + (b"\x40\x90\xe0" * width)
    raw = row * height
    path.write_bytes(
        b"\x89PNG\r\n\x1a\n"
        + chunk(b"IHDR", struct.pack(">IIBBBBB", width, height, 8, 2, 0, 0, 0))
        + chunk(b"IDAT", zlib.compress(raw))
        + chunk(b"IEND", b"")
    )

for name in ("sample_0001.png", "sample_0002.png"):
    write_png(root / "imgs" / name)

def payload(image_id, file_name):
    return {
        "images": [{"id": image_id, "file_name": file_name, "width": 64, "height": 64}],
        "annotations": [{
            "id": image_id,
            "image_id": image_id,
            "category_id": 1,
            "bbox": [12, 10, 28, 30],
            "area": 840,
            "iscrowd": 0,
        }],
        "categories": [{"id": 1, "name": "wake"}],
    }

splits = {
    "train_annotations.json": payload(1, "sample_0001.png"),
    "val_annotations.json": payload(2, "sample_0002.png"),
    "test_annotations.json": payload(2, "sample_0002.png"),
}
for filename, split_payload in splits.items():
    (root / "Annotations" / filename).write_text(json.dumps(split_payload, indent=2))
PY

3. Define a RetinaNet detector

A DetectorSpec is the high-level model description. The suite registry resolves the RetinaNet alias, the ResNet backbone, and the native head and neck wiring before training starts.

python - <<'PY'
from pprint import pprint
from simpledet.suite import build_detector, build_neck, compile_native_detector_plan

spec = build_detector(
    "retinanet",
    backbone="resnet18",
    neck=build_neck("FPN", out_channels=128, num_outs=4),
    num_classes=1,
    in_channels=3,
    pretrained=False,
)
plan = compile_native_detector_plan(spec)

print(spec.family)
pprint(plan.encoder)
pprint(plan.neck)
pprint(plan.head)
PY

Expected output shape:

dense
ComponentPlan(kind='encoder', type='resnet18', ...)
ComponentPlan(kind='neck', type='FPN', ...)
ComponentPlan(kind='head', type='RetinaHead', ...)

The quickstart disables pretrained weights so the first run does not download external checkpoints. For real experiments, keep the same shape and change the detector, backbone, class count, and dataset paths.

4. Write the dataset and runtime config

The config keeps the detector definition, dataset paths, runtime knobs, optimizer, checkpoint path, and export intent in one repeatable file.

cat > quickstart.toml <<'TOML'
stages = ["build", "train", "test"]
workdir = "runs/quickstart"
seed = 71

[detector]
name = "retinanet"
num_classes = 1
backbone = "resnet18"
pretrained = false

[detector.neck]
name = "FPN"
out_channels = 128
num_outs = 4

[dataset]
format = "coco"
root = "data/quickstart-coco"
train = "Annotations/train_annotations.json"
val = "Annotations/val_annotations.json"
test = "Annotations/test_annotations.json"
data_prefix = "imgs/"
classes = ["wake"]
in_channels = 3
tif_channels_to_load = [1, 2, 3]

[runtime]
resize = 128
batch_size = 1
max_epochs = 1
num_workers = 0
accelerator = "cpu"
devices = 1

[optimizer]
name = "AdamW"
learning_rate = 0.001

[scheduler]
name = "step"
step_size = 1
gamma = 0.5

[checkpoint]
path = "runs/quickstart/checkpoints/last.ckpt"
resume = false

[export]
formats = ["json"]
TOML

python -m simpledet --project-validate quickstart.toml

5. Train, test, and infer

These are the three operational commands for the quickstart. Run them in order: the test and inference stages load runs/quickstart/checkpoints/last.ckpt, which the train command writes.

python -m simpledet --project-run quickstart.toml --stages build train
python -m simpledet --project-run quickstart.toml --stages test
python -m simpledet --project-run quickstart.toml --stages infer

Expected artifacts:

  • runs/quickstart/checkpoints/last.ckpt
  • native-manifest.json
  • native-metrics.json
  • run-manifest.json
  • prediction records and metric summaries printed by the CLI

6. Swap in your dataset

Use the same config shape for a real dataset. The important contract is local and explicit: SimpleDet validates the root, image directory, and train, validation, and test annotation files before it creates the workdir or enters the native runtime.

dataset_root/
  imgs/
    image_0001.png
    image_0002.png
  Annotations/
    train_annotations.json
    val_annotations.json
    test_annotations.json

Replace data/quickstart-coco, classes, and num_classes together. Keep pretrained = false for fully offline smoke runs; choose a pretrained backbone only when the environment can download or already has the weights.