Complete Guide to DETR: Object Detection with Transformers

# Panduan Lengkap DETR: Object Detection dengan Transformers DETR (DEtection TRansformer) adalah pendekatan revolusioner untuk object detection yang dikembangkan oleh Facebook AI Research. DETR mengg...

By Ruby Abdullah · · tutorial
PythonDETRObject DetectionTransformerComputer Vision

Complete Guide to DETR: Object Detection with Transformers

DETR (DEtection TRansformer) is a revolutionary approach to object detection developed by Facebook AI Research. DETR replaces complex traditional pipelines with an elegant end-to-end Transformer architecture.

In this tutorial, we'll learn DETR from basic concepts to practical implementation for object detection and segmentation.

Why DETR?

DETR Advantages:

  • End-to-End: No need for Non-Maximum Suppression (NMS) or anchor boxes
  • Simplicity: Inference requires only ~50 lines of PyTorch code
  • Performance: Matches Faster R-CNN with half the computation power
  • Versatile: Supports object detection and panoptic segmentation
  • Global Reasoning: Transformer enables global reasoning about object relationships
  • Parallel Prediction: Parallel predictions make DETR very fast
  • Comparison with Traditional Methods:

    | Aspect | Traditional (Faster R-CNN) | DETR |

    |--------|---------------------------|------|

    | Anchor Boxes | Yes | No |

    | NMS Post-processing | Yes | No |

    | Hand-crafted Components | Many | Minimal |

    | End-to-End Training | No | Yes |

    | Global Context | Limited | Full |

    DETR Architecture

    Main Components:

    Input Image → CNN Backbone → Transformer Encoder → Transformer Decoder → FFN → Predictions
    

    ↓ ↓ ↓

    Features Positional Object Queries

    Encoding (Learned)

    1. CNN Backbone

    # ResNet-50 or ResNet-101 as feature extractor
    

    Input: Image (3, H, W)

    Output: Feature map (2048, H/32, W/32)

    2. Transformer Encoder

    # Processes flattened feature map with self-attention
    

    Adds positional encoding

    Output: Encoded features with global context

    3. Transformer Decoder

    # Uses learned object queries (default: 100)
    

    Cross-attention with encoded features

    Self-attention between object queries

    Output: 100 embeddings for predictions

    4. Prediction Heads

    # FFN for class prediction
    

    FFN for bounding box prediction (centerx, centery, width, height)

    Special class: "no object" for queries that don't detect objects

    Installation

    Requirements

    # Clone repository
    

    git clone https://github.com/facebookresearch/detr.git

    cd detr

    Install dependencies

    conda create -n detr python=3.8

    conda activate detr

    PyTorch and Torchvision

    conda install pytorch torchvision cudatoolkit=11.3 -c pytorch

    Other dependencies

    conda install cython scipy

    pip install -U 'git+https://github.com/cocodataset/cocoapi.git#subdirectory=PythonAPI'

    For panoptic segmentation (optional)

    pip install git+https://github.com/cocodataset/panopticapi.git

    Verify Installation

    import torch
    

    import torchvision

    print(f"PyTorch version: {torch.version}")

    print(f"Torchvision version: {torchvision.version}")

    print(f"CUDA available: {torch.cuda.isavailable()}")

    Quick Start: Inference with Pretrained Model

    1. Load Model via PyTorch Hub

    import torch
    

    from PIL import Image

    import requests

    import matplotlib.pyplot as plt

    Load pretrained DETR model

    model = torch.hub.load('facebookresearch/detr:main', 'detrresnet50', pretrained=True)

    model.eval()

    COCO classes

    CLASSES = [

    'N/A', 'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus',

    'train', 'truck', 'boat', 'traffic light', 'fire hydrant', 'N/A',

    'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse',

    'sheep', 'cow', 'elephant', 'bear', 'zebra', 'giraffe', 'N/A', 'backpack',

    'umbrella', 'N/A', 'N/A', 'handbag', 'tie', 'suitcase', 'frisbee', 'skis',

    'snowboard', 'sports ball', 'kite', 'baseball bat', 'baseball glove',

    'skateboard', 'surfboard', 'tennis racket', 'bottle', 'N/A', 'wine glass',

    'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', 'sandwich',

    'orange', 'broccoli', 'carrot', 'hot dog', 'pizza', 'donut', 'cake',

    'chair', 'couch', 'potted plant', 'bed', 'N/A', 'dining table', 'N/A',

    'N/A', 'toilet', 'N/A', 'tv', 'laptop', 'mouse', 'remote', 'keyboard',

    'cell phone', 'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'N/A',

    'book', 'clock', 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'

    ]

    Colors for visualization

    COLORS = [[0.000, 0.447, 0.741], [0.850, 0.325, 0.098], [0.929, 0.694, 0.125],

    [0.494, 0.184, 0.556], [0.466, 0.674, 0.188], [0.301, 0.745, 0.933]]

    2. Preprocessing and Inference

    import torchvision.transforms as T
    
    

    Standard COCO transforms

    transform = T.Compose([

    T.Resize(800),

    T.ToTensor(),

    T.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])

    ])

    def detect(imagepath, model, transform, threshold=0.7):

    """

    Detect objects in an image using DETR.

    Args:

    imagepath: Path to image or URL

    model: DETR model

    transform: Image transforms

    threshold: Confidence threshold

    Returns:

    Detected objects with boxes and labels

    """

    # Load image

    if imagepath.startswith('http'):

    im = Image.open(requests.get(imagepath, stream=True).raw)

    else:

    im = Image.open(imagepath)

    # Transform

    img = transform(im).unsqueeze(0)

    # Inference

    with torch.nograd():

    outputs = model(img)

    # Post-process

    probas = outputs['predlogits'].softmax(-1)[0, :, :-1]

    keep = probas.max(-1).values > threshold

    # Convert boxes from [0, 1] to image coordinates

    bboxesscaled = rescalebboxes(outputs['predboxes'][0, keep], im.size)

    return probas[keep], bboxesscaled, im

    def rescalebboxes(outbbox, size):

    """Convert normalized boxes to image coordinates."""

    imgw, imgh = size

    b = boxcxcywhtoxyxy(outbbox)

    b = b torch.tensor([imgw, imgh, imgw, imgh], dtype=torch.float32)

    return b

    def boxcxcywhtoxyxy(x):

    """Convert boxes from center format to corner format."""

    xc, yc, w, h = x.unbind(-1)

    b = [(xc - 0.5 w), (yc - 0.5 h),

    (xc + 0.5 w), (yc + 0.5 h)]

    return torch.stack(b, dim=-1)

    3. Visualize Results

    def plotresults(pilimg, prob, boxes):
    

    """Visualize detection results."""

    plt.figure(figsize=(16, 10))

    plt.imshow(pilimg)

    ax = plt.gca()

    colors = COLORS 100

    for p, (xmin, ymin, xmax, ymax), c in zip(prob, boxes.tolist(), colors):

    ax.addpatch(plt.Rectangle(

    (xmin, ymin), xmax - xmin, ymax - ymin,

    fill=False, color=c, linewidth=3

    ))

    cl = p.argmax()

    text = f'{CLASSES[cl]}: {p[cl]:0.2f}'

    ax.text(xmin, ymin, text, fontsize=15,

    bbox=dict(facecolor='yellow', alpha=0.5))

    plt.axis('off')

    plt.tightlayout()

    plt.savefig('detectionresult.png', dpi=150, bboxinches='tight')

    plt.show()

    Run detection

    url = 'http://images.cocodataset.org/val2017/000000039769.jpg'

    probas, bboxes, image = detect(url, model, transform)

    plotresults(image, probas, bboxes)

    print(f"Detected {len(probas)} objects")

    for p, box in zip(probas, bboxes):

    cl = p.argmax()

    print(f" {CLASSES[cl]}: {p[cl]:.2f} at {box.tolist()}")

    Pretrained Models

    Available Models

    | Model | Backbone | Box AP | URL |

    |-------|----------|--------|-----|

    | DETR | ResNet-50 | 42.0 | detrresnet50 |

    | DETR-DC5 | ResNet-50 | 43.3 | detrresnet50dc5 |

    | DETR | ResNet-101 | 43.5 | detrresnet101 |

    | DETR-DC5 | ResNet-101 | 44.9 | detrresnet101dc5 |

    Load Different Models

    # ResNet-50 backbone
    

    modelr50 = torch.hub.load('facebookresearch/detr:main', 'detrresnet50', pretrained=True)

    ResNet-50 with dilated C5 stage

    modelr50dc5 = torch.hub.load('facebookresearch/detr:main', 'detrresnet50dc5', pretrained=True)

    ResNet-101 backbone

    modelr101 = torch.hub.load('facebookresearch/detr:main', 'detrresnet101', pretrained=True)

    ResNet-101 with dilated C5 stage

    modelr101dc5 = torch.hub.load('facebookresearch/detr:main', 'detrresnet101dc5', pretrained=True)

    Load from Checkpoint

    # Download checkpoint
    

    import urllib.request

    checkpointurl = 'https://dl.fbaipublicfiles.com/detr/detr-r50-e632da11.pth'

    urllib.request.urlretrieve(checkpointurl, 'detr-r50.pth')

    Load checkpoint

    checkpoint = torch.load('detr-r50.pth', maplocation='cpu')

    model.loadstatedict(checkpoint['model'])

    Training DETR

    1. Prepare COCO Dataset

    # Download COCO 2017
    

    mkdir -p data/coco

    cd data/coco

    Download images

    wget http://images.cocodataset.org/zips/train2017.zip

    wget http://images.cocodataset.org/zips/val2017.zip

    Download annotations

    wget http://images.cocodataset.org/annotations/annotationstrainval2017.zip

    Extract

    unzip train2017.zip

    unzip val2017.zip

    unzip annotationstrainval2017.zip

    Folder structure:

    data/
    

    └── coco/

    ├── train2017/

    ├── val2017/

    └── annotations/

    ├── instancestrain2017.json

    └── instancesval2017.json

    2. Training Command

    # Single GPU training
    

    python main.py --cocopath /path/to/coco

    Multi-GPU training (8 GPUs)

    python -m torch.distributed.launch \

    --nprocpernode=8 \

    --useenv main.py \

    --cocopath /path/to/coco

    Training with custom settings

    python main.py \

    --cocopath /path/to/coco \

    --batchsize 2 \

    --epochs 300 \

    --lr 1e-4 \

    --lrbackbone 1e-5 \

    --numqueries 100 \

    --outputdir outputs/detrcustom

    3. Training Configuration

    # Default hyperparameters (from paper)
    

    args = {

    # Optimizer

    'lr': 1e-4, # Learning rate for transformer

    'lrbackbone': 1e-5, # Learning rate for backbone

    'weightdecay': 1e-4, # Weight decay

    # Architecture

    'backbone': 'resnet50', # Backbone CNN

    'numqueries': 100, # Number of object queries

    'hiddendim': 256, # Transformer hidden dimension

    'nheads': 8, # Attention heads

    'enclayers': 6, # Encoder layers

    'declayers': 6, # Decoder layers

    'dimfeedforward': 2048, # FFN dimension

    'dropout': 0.1, # Dropout rate

    # Training

    'epochs': 300, # Total epochs

    'batchsize': 2, # Batch size per GPU

    'clipmaxnorm': 0.1, # Gradient clipping

    # Loss weights

    'setcostclass': 1, # Class cost for Hungarian matching

    'setcostbbox': 5, # L1 box cost

    'setcostgiou': 2, # GIoU cost

    'bboxlosscoef': 5, # Box L1 loss coefficient

    'gioulosscoef': 2, # GIoU loss coefficient

    'eoscoef': 0.1, # "No object" class weight

    }

    4. Custom Training Script

    import torch
    

    from torch.utils.data import DataLoader

    from detr.models import buildmodel

    from detr.datasets import builddataset

    from detr.engine import trainoneepoch, evaluate

    def traindetr(args):

    # Build model

    model, criterion, postprocessors = buildmodel(args)

    model.to(args.device)

    # Build dataset

    datasettrain = builddataset(imageset='train', args=args)

    datasetval = builddataset(imageset='val', args=args)

    # DataLoaders

    samplertrain = torch.utils.data.RandomSampler(datasettrain)

    samplerval = torch.utils.data.SequentialSampler(datasetval)

    dataloadertrain = DataLoader(

    datasettrain,

    batchsize=args.batchsize,

    sampler=samplertrain,

    collatefn=utils.collatefn,

    numworkers=args.numworkers

    )

    dataloaderval = DataLoader(

    datasetval,

    batchsize=args.batchsize,

    sampler=samplerval,

    collatefn=utils.collatefn,

    numworkers=args.numworkers

    )

    # Optimizer

    paramdicts = [

    {"params": [p for n, p in model.namedparameters()

    if "backbone" not in n and p.requiresgrad]},

    {"params": [p for n, p in model.namedparameters()

    if "backbone" in n and p.requiresgrad],

    "lr": args.lrbackbone},

    ]

    optimizer = torch.optim.AdamW(paramdicts, lr=args.lr, weightdecay=args.weightdecay)

    # LR Scheduler

    lrscheduler = torch.optim.lrscheduler.StepLR(optimizer, args.lrdrop)

    # Training loop

    for epoch in range(args.epochs):

    trainstats = trainoneepoch(

    model, criterion, dataloadertrain,

    optimizer, args.device, epoch, args.clipmaxnorm

    )

    lrscheduler.step()

    # Evaluate

    teststats, cocoevaluator = evaluate(

    model, criterion, postprocessors,

    dataloaderval, args.device

    )

    # Save checkpoint

    if (epoch + 1) % 10 == 0:

    torch.save({

    'model': model.statedict(),

    'optimizer': optimizer.statedict(),

    'lrscheduler': lrscheduler.statedict(),

    'epoch': epoch,

    }, f'checkpoint{epoch:04d}.pth')

    Evaluation

    1. Evaluate Pretrained Model

    python main.py \
    

    --batchsize 2 \

    --noauxloss \

    --eval \

    --resume https://dl.fbaipublicfiles.com/detr/detr-r50-e632da11.pth \

    --cocopath /path/to/coco

    2. Evaluation Script

    from detr.datasets.cocoeval import CocoEvaluator
    

    from detr.datasets.coco import makecocotransforms

    def evaluatemodel(model, dataloader, device):

    model.eval()

    cocoevaluator = CocoEvaluator(dataloader.dataset.coco, ['bbox'])

    for samples, targets in dataloader:

    samples = samples.to(device)

    targets = [{k: v.to(device) for k, v in t.items()} for t in targets]

    with torch.nograd():

    outputs = model(samples)

    # Post-process

    origtargetsizes = torch.stack([t["origsize"] for t in targets], dim=0)

    results = postprocessors'bbox'

    res = {target['imageid'].item(): output

    for target, output in zip(targets, results)}

    cocoevaluator.update(res)

    cocoevaluator.synchronizebetweenprocesses()

    cocoevaluator.accumulate()

    cocoevaluator.summarize()

    return cocoevaluator

    Run evaluation

    stats = evaluatemodel(model, dataloaderval, device)

    print(f"AP: {stats.cocoeval['bbox'].stats[0]:.3f}")

    print(f"AP50: {stats.cocoeval['bbox'].stats[1]:.3f}")

    print(f"AP75: {stats.cocoeval['bbox'].stats[2]:.3f}")

    Fine-tuning on Custom Dataset

    1. Prepare Custom Dataset

    import json
    

    from PIL import Image

    from torch.utils.data import Dataset

    class CustomCocoDataset(Dataset):

    """

    Custom dataset in COCO format.

    """

    def init(self, imgfolder, annfile, transforms=None):

    self.imgfolder = imgfolder

    self.transforms = transforms

    with open(annfile, 'r') as f:

    self.coco = json.load(f)

    self.ids = [img['id'] for img in self.coco['images']]

    # Build image id to annotations mapping

    self.imgtoanns = {}

    for ann in self.coco['annotations']:

    imgid = ann['imageid']

    if imgid not in self.imgtoanns:

    self.imgtoanns[imgid] = []

    self.imgtoanns[imgid].append(ann)

    def len(self):

    return len(self.ids)

    def getitem(self, idx):

    imgid = self.ids[idx]

    # Get image info

    imginfo = next(img for img in self.coco['images'] if img['id'] == imgid)

    imgpath = f"{self.imgfolder}/{imginfo['filename']}"

    img = Image.open(imgpath).convert('RGB')

    # Get annotations

    anns = self.imgtoanns.get(imgid, [])

    # Prepare target

    boxes = []

    labels = []

    for ann in anns:

    x, y, w, h = ann['bbox']

    boxes.append([x, y, x + w, y + h])

    labels.append(ann['categoryid'])

    target = {

    'boxes': torch.tensor(boxes, dtype=torch.float32),

    'labels': torch.tensor(labels, dtype=torch.int64),

    'imageid': torch.tensor([imgid]),

    'origsize': torch.tensor([img.height, img.width]),

    'size': torch.tensor([img.height, img.width]),

    }

    if self.transforms:

    img, target = self.transforms(img, target)

    return img, target

    2. COCO Annotation Format

    {
    

    "images": [

    {"id": 1, "filename": "image1.jpg", "width": 640, "height": 480},

    {"id": 2, "filename": "image2.jpg", "width": 800, "height": 600}

    ],

    "annotations": [

    {"id": 1, "imageid": 1, "categoryid": 1, "bbox": [100, 100, 200, 150]},

    {"id": 2, "imageid": 1, "categoryid": 2, "bbox": [300, 200, 100, 100]},

    {"id": 3, "imageid": 2, "categoryid": 1, "bbox": [50, 50, 300, 200]}

    ],

    "categories": [

    {"id": 1, "name": "cat"},

    {"id": 2, "name": "dog"}

    ]

    }

    3. Modify Model for Custom Classes

    def buildcustomdetr(numclasses):
    

    """

    Build DETR for custom number of classes.

    """

    # Load pretrained model

    model = torch.hub.load('facebookresearch/detr:main', 'detrresnet50', pretrained=True)

    # Modify class prediction head

    # Original: 91 COCO classes + 1 "no object" = 92

    # Custom: numclasses + 1 "no object"

    model.classembed = torch.nn.Linear(

    model.classembed.infeatures,

    numclasses + 1

    )

    # Reinitialize the new layer

    torch.nn.init.normal(model.classembed.weight, std=0.01)

    torch.nn.init.constant(model.classembed.bias, 0)

    # Set "no object" bias to higher value (makes model predict "no object" more often initially)

    model.classembed.bias.data[-1] = -2.0

    return model

    Example: 5 custom classes

    numclasses = 5

    model = buildcustomdetr(numclasses)

    print(f"Model output classes: {model.classembed.outfeatures}")

    4. Fine-tuning Script

    def finetunedetr(model, trainloader, valloader, numepochs=50):
    

    """

    Fine-tune DETR on custom dataset.

    """

    device = torch.device('cuda' if torch.cuda.isavailable() else 'cpu')

    model.to(device)

    # Freeze backbone for first few epochs

    for param in model.backbone.parameters():

    param.requiresgrad = False

    # Optimizer

    optimizer = torch.optim.AdamW([

    {'params': model.transformer.parameters(), 'lr': 1e-4},

    {'params': model.classembed.parameters(), 'lr': 1e-3},

    {'params': model.bboxembed.parameters(), 'lr': 1e-4},

    {'params': model.queryembed.parameters(), 'lr': 1e-4},

    ], weightdecay=1e-4)

    # Training loop

    for epoch in range(numepochs):

    model.train()

    totalloss = 0

    for batchidx, (images, targets) in enumerate(trainloader):

    images = images.to(device)

    targets = [{k: v.to(device) for k, v in t.items()} for t in targets]

    outputs = model(images)

    lossdict = criterion(outputs, targets)

    loss = sum(lossdict.values())

    optimizer.zerograd()

    loss.backward()

    torch.nn.utils.clipgradnorm(model.parameters(), 0.1)

    optimizer.step()

    totalloss += loss.item()

    # Unfreeze backbone after epoch 10

    if epoch == 10:

    for param in model.backbone.parameters():

    param.requiresgrad = True

    optimizer.addparamgroup({

    'params': model.backbone.parameters(),

    'lr': 1e-5

    })

    print(f"Epoch {epoch+1}/{numepochs}, Loss: {totalloss/len(trainloader):.4f}")

    return model

    Panoptic Segmentation

    1. Load Panoptic Model

    # Load DETR with panoptic head
    

    model = torch.hub.load(

    'facebookresearch/detr:main',

    'detrresnet50panoptic',

    pretrained=True,

    returnpostprocessor=True,

    numclasses=250 # COCO panoptic classes

    )

    detr, postprocessor = model

    detr.eval()

    2. Panoptic Inference

    def panopticinference(imagepath, model, postprocessor):
    

    """

    Run panoptic segmentation.

    """

    im = Image.open(imagepath)

    # Transform

    transform = T.Compose([

    T.Resize(800),

    T.ToTensor(),

    T.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])

    ])

    img = transform(im).unsqueeze(0)

    with torch.nograd():

    outputs = model(img)

    # Post-process

    result = postprocessor(outputs, torch.tensor([[im.height, im.width]]))[0]

    # result contains:

    # - 'segmentation': Segmentation mask (H, W) with segment IDs

    # - 'segmentsinfo': List of dicts with info for each segment

    return result

    Example

    result = panopticinference('image.jpg', detr, postprocessor)

    print(f"Number of segments: {len(result['segmentsinfo'])}")

    for seg in result['segmentsinfo']:

    print(f" ID: {seg['id']}, Category: {seg['categoryid']}, "

    f"Is Thing: {seg['isthing']}")

    3. Visualize Panoptic

    import numpy as np
    

    from panopticapi.utils import rgb2id

    def visualizepanoptic(image, result):

    """

    Visualize panoptic segmentation result.

    """

    # Get segmentation mask

    segmask = result['segmentation'].numpy()

    # Create color map

    np.random.seed(42)

    colors = np.random.randint(0, 255, (256, 3), dtype=np.uint8)

    # Apply colors

    coloredmask = colors[segmask % 256]

    # Blend with original image

    imagenp = np.array(image)

    blended = (0.5 imagenp + 0.5 coloredmask).astype(np.uint8)

    plt.figure(figsize=(16, 8))

    plt.subplot(1, 3, 1)

    plt.imshow(image)

    plt.title('Original')

    plt.axis('off')

    plt.subplot(1, 3, 2)

    plt.imshow(coloredmask)

    plt.title('Segmentation')

    plt.axis('off')

    plt.subplot(1, 3, 3)

    plt.imshow(blended)

    plt.title('Blended')

    plt.axis('off')

    plt.tightlayout()

    plt.savefig('panopticresult.png')

    plt.show()

    Best Practices

    1. Memory Optimization

    # Gradient checkpointing to reduce memory
    

    from torch.utils.checkpoint import checkpoint

    Mixed precision training

    from torch.cuda.amp import autocast, GradScaler

    scaler = GradScaler()

    for images, targets in trainloader:

    with autocast():

    outputs = model(images)

    loss = criterion(outputs, targets)

    scaler.scale(loss).backward()

    scaler.step(optimizer)

    scaler.update()

    2. Data Augmentation

    import albumentations as A
    

    from albumentations.pytorch import ToTensorV2

    traintransform = A.Compose([

    A.RandomResizedCrop(800, 800, scale=(0.5, 1.0)),

    A.HorizontalFlip(p=0.5),

    A.ColorJitter(brightness=0.4, contrast=0.4, saturation=0.4),

    A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),

    ToTensorV2(),

    ], bboxparams=A.BboxParams(format='coco', labelfields=['labels']))

    3. Inference Optimization

    # TorchScript for faster inference
    

    scriptedmodel = torch.jit.script(model)

    scriptedmodel.save('detrscripted.pt')

    ONNX export

    torch.onnx.export(

    model,

    dummyinput,

    'detr.onnx',

    inputnames=['image'],

    outputnames=['predlogits', 'predboxes'],

    dynamicaxes={'image': {0: 'batch', 2: 'height', 3: 'width'}}

    )

    4. Batch Inference

    def batchinference(imagepaths, model, transform, batchsize=8):
    

    """

    Efficient batch inference.

    """

    allresults = []

    for i in range(0, len(imagepaths), batchsize):

    batchpaths = imagepaths[i:i+batchsize]

    # Load and transform images

    images = []

    sizes = []

    for path in batchpaths:

    img = Image.open(path)

    sizes.append(img.size)

    images.append(transform(img))

    # Stack into batch

    batch = torch.stack(images)

    with torch.nograd():

    outputs = model(batch.to(device))

    # Process each image in batch

    for j, (prob, boxes) in enumerate(zip(

    outputs['predlogits'].softmax(-1),

    outputs['predboxes']

    )):

    # Filter by threshold

    keep = prob[:, :-1].max(-1).values > 0.7

    allresults.append({

    'path': batchpaths[j],

    'scores': prob[keep],

    'boxes': rescalebboxes(boxes[keep], sizes[j])

    })

    return allresults

    Troubleshooting

    1. Out of Memory

    # Reduce batch size
    

    args.batchsize = 1

    Use gradient accumulation

    accumulationsteps = 4

    for i, (images, targets) in enumerate(trainloader):

    loss = criterion(model(images), targets)

    loss = loss / accumulationsteps

    loss.backward()

    if (i + 1) % accumulationsteps == 0:

    optimizer.step()

    optimizer.zerograd()

    2. Training Not Converging

    # Check learning rate
    

    LR too high can cause divergence

    args.lr = 1e-5 # Start with smaller LR

    Make sure data augmentation isn't too aggressive

    Make sure normalization is correct

    3. Low AP on Custom Dataset

    # Make sure annotation format is correct
    

    Check class balance

    Consider more epochs

    Fine-tune from pretrained model

    Conclusion

    DETR is an innovative approach to object detection:

    Key Takeaways:

  • End-to-End: No need for NMS or anchor boxes
  • Transformer-based: Global reasoning for object detection
  • Simple: Elegant and easy-to-understand architecture
  • Versatile: Supports detection and segmentation
  • State-of-the-art: Competitive with traditional methods
  • When to Use DETR:

    Use DETR when:
    • Need end-to-end object detection
    • Dataset has objects with complex relationships
    • Want to avoid hand-crafted components
    • Need panoptic segmentation
    • Research or prototyping

    Consider alternatives when:
    • Real-time inference is required (DETR is slower than YOLO)
    • Dataset is very small (DETR needs lots of data)
    • Resources are limited (DETR is memory-intensive)

    Resources:

    • Paper: "End-to-End Object Detection with Transformers"
    • GitHub: https://github.com/facebookresearch/detr
    • Colab Notebooks available in repository

    Happy coding with DETR!

    Related Articles

    Florence-2: Microsoft's Multi-Task Vision Foundation Model

    Florence-2: Model Vision Multi-Task dari Microsoft Daftar Isi Pendahuluan Prasyarat Instalasi Memuat Model Florence-2

    Supervision: Computer Vision Toolkit by Roboflow

    Supervision: Toolkit Computer Vision dari Roboflow Dalam proyek computer vision, setelah model mendeteksi objek, Anda ma...

    Complete Ultralytics Tutorial: Object Detection with YOLO

    Tutorial Lengkap Ultralytics: Object Detection dengan YOLO Ultralytics adalah framework Python yang menyediakan implemen...

    Surya OCR Tutorial: Document AI for Text Detection, OCR, and Layout Analysis

    Tutorial Surya OCR: Document AI untuk Text Detection, OCR, dan Layout Analysis Surya adalah library Document AI open-sou...