System designTroubleshooting

Trained YOLO model has no detections: fix labels first

Trained YOLO model, no detections even on training images? The fault is in the label files. Check class indices, coordinate normalization and class order.

LumaSpec Vision10 min read Share on LinkedIn

On this page 10 sections
  1. 01Why does zero detections on training images rule out overfitting?
  2. 02Is every label line a class index plus four normalized numbers?
  3. 03Do class count and class order match from annotation to inference?
  4. 04How do you see the labels the trainer actually reads?
  5. 05What should a two-image sanity train prove?
  6. 06Do unmodified pretrained weights clear your inference code?
  7. 07When is the model itself really at fault?
  8. 08How do you keep label faults out of the next dataset?
  9. 09What hardware runs the checked model on the line?
  10. 10Questions

You trained a custom YOLO model, the loss fell nicely, and the test run draws zero bounding boxes - not weak boxes, nothing at all. When the very images the model trained on come back empty too, overfitting is ruled out and a data-pipeline fault becomes the prime suspect. The usual faults, in the order they strike: class indices outside the configured class count, coordinates exported in pixels instead of the normalized 0-1 center format, and a class list at inference that no longer matches training. Work through the checks below - open the label files, overlay the boxes, run a two-image sanity train, then test unmodified pretrained weights - and you will isolate the fault in under an hour, before touching anchors, hyperparameters or training length.

Why does zero detections on training images rule out overfitting?

An overfit model still fires on the images it memorized, usually with confidence above 0.5. A model that draws no boxes on its own training set never produced decodable output at all, so the fault sits in the label files or the decode path, not in the training schedule.

Overfitting means the model memorized its training set. A memorized person produces a box; memorization cannot produce silence. So the symptom pattern - training converges, test images empty, training images also empty - describes a pipeline that never delivered valid boxes to the loss, or never decoded them back out.

Broken labels also train without complaint. An empty or unreadable label file marks the image as background, and the trainer learns "nothing here" just as faithfully; trainers treat a frame with no readable boxes as a background sample. The loss still falls, sometimes to values that look healthy. A falling loss proves the optimizer runs, nothing more.

Is every label line a class index plus four normalized numbers?

A YOLO label line is class_index x_center y_center width height with all four coordinates normalized to 0-1 against image width and height, so a 1920 × 1080 image with a box from (480, 270) to (960, 810) must read 0 0.375 0.500 0.250 0.500.

Convert corner exports with:

x_center = (x_min + x_max) / 2 / image_width y_center = (y_min + y_max) / 2 / image_height width = (x_max - x_min) / image_width height = (y_max - y_min) / image_height

The four silent failures, in how often they appear:

  • Corner coordinates fed through unchanged: the line reads 0 480 270 960 810, every value sits beyond 1, and the decoded box covers nonsense.
  • One-based class numbering from the annotation tool while the trainer counts from zero, so person becomes index 1.
  • Reversed corners, x_min greater than x_max, which turns width negative.
  • Boxes that touch or cross the frame edge without clamping every coordinate into [0, 1].

Most desktop annotation tools export Pascal VOC XML or CSV with corner coordinates, not YOLO text, so a conversion step always exists. The CSV-to-YOLO conversion guide and the JSON annotation conversion guide list the index and scaling mistakes that break converted files.

Do class count and class order match from annotation to inference?

The class index in each label line is a row number into your class list, and trainer and inference code must read the same list in the same order. With one class every line starts with 0, and index 1 against nc = 1 is out of range.

Three copies of the class list usually exist - the converter's mapping, the training config, and the inference decode - and they drift apart when someone adds a class, re-sorts alphabetically, or rebuilds the converter. The trainer then fails loudly: an index beyond the declared class count raises a list-index error mid-training. Quieter variants remap labels wholesale, or inference code filters by class id and discards every box.

One check closes the whole group. With nc = 1, print the first field of every line in the label files, collect the unique values over the dataset, and the result must be exactly 0. Any 1, 2 or higher is a converter or config bug, not a model problem.

How do you see the labels the trainer actually reads?

Load every label file and draw its boxes on the image with a ten-line script before you retrain anything. If the overlay is empty or lands in the wrong place on even one image, no amount of training will repair it.

Draw at the resolution the trainer feeds the network. A letterbox resize to a square input changes geometry, and boxes drawn with raw-file coordinates on a resized canvas are the classic look-alike fault; the non-square training size explainer and the letterbox offset fix cover the two ways that mapping drifts.

Two counts catch the rest. Non-empty label files must equal annotated images: 500 annotated frames should give 500 files with at least one line. And every image needs one line per object: 3 people in the frame, 3 lines in the file. Run both counts over the train and validation splits, not just train.

What should a two-image sanity train prove?

Copy two images with their repaired labels, train for about 100 iterations at your usual settings, and expect the loss to approach zero while boxes appear on those images with confidence above 0.9. A model that cannot overfit two clean images has a pipeline fault, not a capacity problem.

The run takes minutes on any GPU and reads back decisively. Loss near zero with tight boxes: the pipeline works, move on to the full set. Loss falling but boxes absent or wandering: the loader reads something other than what you edited, usually a label path or file-name mismatch - images/frame_0001.jpg must pair with labels/frame_0001.txt, and one missing file silently becomes background. Loss stuck high: class indices or coordinate format are still wrong, and the checks in the sections above find them.

Do unmodified pretrained weights clear your inference code?

Run the original COCO-pretrained weights on a daylight photo that plainly contains a person, at the same confidence threshold you used before. Boxes appear and your inference path is proven, so the fault stays in your labels; still nothing and the decode path is the fault.

This test splits the problem in half in five minutes. It needs the same preprocessing your custom run used - identical letterbox size, normalization and channel order - or it proves nothing. The usual silent killers on the decode side: a channel-order swap between training and inference, pixel values left at 0-255 where the trainer expects 0-1, and a confidence threshold set far above the common 0.25 default. Debug at 0.05, judge at 0.25. The input normalization checks walk the preprocessing chain end to end.

When is the model itself really at fault?

Once the overlay is clean, the two-image train converges and pretrained weights fire, the model side is at fault. The usual three are too few annotated boxes per class, anchor sizes far from your object sizes, or too little training for imagery far from daylight RGB.

Dataset size first: a workable floor is roughly 1,500 annotated instances per class, with fewer surviving only for distinctive objects on clean backgrounds; the dataset size guide works through the counting. Rare classes die quietly - the single-class failure guide shows how to rescue the class that never fires.

Anchors second. YOLOv3's default anchors describe COCO-sized objects. If your targets are long, thin or small by comparison, recompute the anchors with the k-means routine that ships with the trainer, run on your own boxes.

Thermal and near-infrared imagery third: pretrained features transfer, but weaker, so expect longer training and lower starting confidence. The label rules never change - infrared person detection fails on the same file faults as daylight.

How do you keep label faults out of the next dataset?

Keep one class-list file that the converter, the trainer and the inference script all read, version the label files with the images in the same commit, and gate any new dataset on the overlay test - three habits that stop this fault from returning.

Expand each into a step that runs on its own:

  • One shared class file: converter output, training config and decode names all derive from it, so a class addition updates everywhere at once.
  • Counts in the pipeline: objects annotated = label lines written = boxes drawn, checked automatically after every conversion.
  • Assertions in the converter: indices below the class count, all four coordinates within [0, 1], no negative widths.
  • The overlay render saved alongside the weights, so anyone can see what the model was taught.

What hardware runs the checked model on the line?

Once the pipeline passes on your desktop, a smart camera with an x86 platform runs the same inference script on the device, so the checks you pass on the PC carry straight to the camera; vision sensors in these families instead run their own on-device inspection software.

If the rig keeps a PC in the loop, area scan cameras feed frames over GigE or USB3 while the model runs there; when inspection must happen at the sensor, a smart camera does capture and inference in one housing. Export and runtime tuning on embedded inference targets is its own discipline - this YOLO export and runtime performance walkthrough for edge hardware covers the export path on a compact AI module.

Smart cameras & vision sensorsSC / SC smart camera (X86 platform), 8.8 MP, USB3, Color/Mono, global shutter (LS-SMC-0017)LS-SMC-0017
Interface
USB 2.0
Resolution
6-10 MP
Sensor format
1"
Shutter
Global
$1,359.00View part

The LS-SMC-0017 pairs an x86 platform with an 8.8 MP, 1" global-shutter sensor on a C-mount, so the inference script you just validated runs at the camera without a separate PC.

Smart cameras & vision sensorsHikrobot MV-SC3050XC-16M-ATN-H 5 MP color vision sensorMV-SC3050XC-16M-ATN-H
Interface
Fast Ethernet
Resolution
5 MP
$1,809.00View part
Smart cameras & vision sensorsHikrobot MV-SC6050C-08M-XBN SC6000 Series Smart Camera, 5 MP, Color, 8 mm focal length, M12-mount, Multi-color light sourceMV-SC6050C-08M-XBN
Interface
GigE
Resolution
5 MP
$3,449.00 · quotedView and quote

Both example vision sensors are 5 MP color models with a 1/1.45" global-shutter sensor behind an M12 mount. The MV-SC6050C-08M-XBN adds a GigE interface and an integrated multi-color light source, and the MV-SC3050XC-16M-ATN-H runs over Fast Ethernet.

To narrow the field by resolution, interface and mount, use the camera finder or start the camera configurator. The systems topic page collects the neighboring training and deployment notes, and support comes with every order - talk to the team when the capture side needs a second opinion.

Questions

Can daylight-pretrained weights still find people in infrared images?

Often yes. The features a COCO-pretrained backbone learned about edges, blobs and human proportions transfer to thermal and near-infrared imagery, which is why thermal person detection works in practice. Transfer is weaker, so expect longer training and lower starting confidence, but the failure rule is unchanged: if even the training images return no boxes, the fault is labels or decode order, not the imagery type.

Do images with no annotated objects break training?

No. An empty or missing label file marks the frame as background, and a small share of background frames - roughly one in ten - teaches the model what not to fire on and cuts false positives. The dangerous variant is different: when annotated boxes exist but the loader finds no files, the whole set becomes background and the model still trains, toward detecting nothing.

What confidence threshold should I debug with?

Debug at 0.05, judge at the 0.25 most tools default to. If boxes appear only below 0.1, the model learned something real but weak - usually inconsistent labels or too few examples - so repair the data and retrain rather than shipping a 0.05 threshold that floods the line with false positives.

Can I feed my annotation tool's XML or CSV export straight to the trainer?

No. Most desktop tools export Pascal VOC XML or CSV corner coordinates, while YOLO trainers read plain text files of class-index and normalized center-format lines. Convert first, then open a few output files and run the overlay render; index shifts and unnormalized pixels are the two mistakes conversions make most often.

Should I just retrain longer or add more images?

Not until the pipeline checks pass. A model trained on broken labels reproduces the same empty result no matter how many frames you add, because the trainer faithfully learns the broken targets. Dataset size, anchors and training length only pay off after the overlay, the two-image train and the pretrained-weight test all come back clean.