Ismail Ben Alla

YOLO Object Detector

YOLOv1 from the Paper, in PyTorch

Computer vision · Sep 2023 · Completed

Give it an image and it draws a box around every object it knows, with its class, in one pass.

Built withPyTorchtorchvisionpytestMatplotlibNumPyKaggleGoogle Colab

YOLO Object Detector — overview

Overview

YOLOv1 turns object detection into one regression: the image is split into a 7 × 7 grid, and the cell that holds an object's centre predicts its class and two candidate boxes with a confidence. The network sees the whole image at once, so detection is a single forward pass. I wrote every part of it in PyTorch from the paper: the 24-layer network, the sum-squared-error loss, target encoding, decoding, non-max suppression and mAP, with no detection library and no pretrained weights.

The project started in 2023 as two notebooks trained on Mapillary traffic signs. When I rewrote it as a tested package I found that the test and validation CSVs were subsets of the training CSV, so every mAP had been measured on training images; that classes above 20 were never counted; that boxes were drawn from their centre as if it were a corner; and that the second box of each cell was never used at test time. The legacy folder keeps the notebooks and the full list of fixes.

To show the pipeline learns without ImageNet pretraining I added two datasets that run on a CPU: synthetic shapes and MNIST digits scattered on a canvas. A small 8.3M-parameter network reaches validation mAP@0.5 of 0.952 on the shapes and 0.921 on the digits in about 25 minutes each. PASCAL VOC and any YOLO-format folder are supported through the same command and a Kaggle / Colab notebook, but those GPU runs are not reported.

The question

Can a single-pass detector written without detection libraries or pretrained weights learn to find and classify objects, and how do I prove that the loss, decoding and mAP code is right?

Key features

How it works

  1. Encode the targets

    Each ground-truth box goes to the grid cell that contains its centre, as an offset inside the cell, a size relative to the image and a one-hot class, giving an S × S × (C + 5B) tensor.

  2. One forward pass

    Conv, batch-norm and leaky-ReLU blocks with four max-pools reduce the image to a 7 × 7 map; two fully connected layers output every box, confidence and class probability at once.

  3. Sum-squared-error loss

    For every object the box with the highest IoU is responsible and is pulled to the target coordinates and to confidence 1; every other predictor is pushed to confidence 0, weighted by λ_noobj; class probabilities are regressed in object cells.

  4. Decode and suppress

    Every box gets the score confidence × best class probability; boxes under the threshold are dropped and same-class boxes that overlap a kept box above the NMS IoU are removed.

  5. Measure mAP

    Per class, detections are sorted by score, matched to unmatched ground truth at IoU ≥ 0.5, and AP is the area under the precision envelope; mAP averages the classes that have ground truth.

Examples

Shapes validation images: ground truth on top, predictions after 20 epochs below. The small network reaches validation mAP@0.5 of 0.952 (circle 0.94, square 0.97, triangle 0.94).
Shapes validation images: ground truth on top, predictions after 20 epochs below. The small network reaches validation mAP@0.5 of 0.952 (circle 0.94, square 0.97, triangle 0.94).
MNIST digits scattered on a canvas: ground truth on top, predicted boxes with class and score below (display threshold 0.3). Validation mAP@0.5 is 0.921; the weakest classes are digit 1 at 0.75 and digit 8 at 0.88.
MNIST digits scattered on a canvas: ground truth on top, predicted boxes with class and score below (display threshold 0.3). Validation mAP@0.5 is 0.921; the weakest classes are digit 1 at 0.75 and digit 8 at 0.88.
The MNIST run over 12 epochs: train and validation loss, validation mAP@0.5 climbing to 0.92, and the four loss components (coordinates, object confidence, no-object confidence, class).
The MNIST run over 12 epochs: train and validation loss, validation mAP@0.5 climbing to 0.92, and the four loss components (coordinates, object confidence, no-object confidence, class).

Input

yolov1-train --dataset mnist --root data --image-size 112 --arch small --hidden 512 --dropout 0.3 --no-augment --train-size 10000 --val-size 500 --epochs 12 --batch-size 32 --lr 1e-3 --output-dir checkpoints/mnist

Output

checkpoints/mnist/: best.pt (highest validation mAP), last.pt, history.json, history.png, predictions.png, best_metrics.json — validation mAP@0.5 0.921 after 12 epochs, about 26 minutes on an 8-core CPU.

The MNIST recipe from the README. With only 3,000 training images the same network overfits (train loss 0.3, validation 1.6, mAP 0.55), which is why the run uses 10,000.

Tech stack

What I learned

Limitations

Keywords

YOLO · YOLOv1 · object detection · You Only Look Once · PyTorch · non-maximum suppression · NMS · mean average precision · mAP · PASCAL VOC · MNIST · Mapillary traffic signs · computer vision · deep learning