Object detection / YOLO in practice

Train YOLOv8 on Your Own Dataset: NEU-DET Steel Surface Defect Detection

Many YOLO tutorials stop at the training command and show one results.png. This page runs the whole workflow on the NEU-DET dataset: label conversion, splitting, data.yaml, training four models, and reading mAP50, mAP50-95, the confusion matrix and error examples. Every number comes from one real run.

Short answer

Training YOLOv8 on your own data takes four steps. Convert annotations to YOLO format with one TXT file per image. Split by image into train, val and test. Write a data.yaml with paths and class names. Then run yolo detect train from official pretrained weights. On NEU-DET, YOLOv8n trained for 200 epochs in about 29 minutes on a T4 and reached 77.1% mAP50 and 42.1% mAP50-95 on the test set, in line with the 74.8%–78.4% reported in published papers.

About this page

Tutorial
What this page solves
You have a defect or object detection dataset. You want to train YOLOv8 or YOLO11 on it and judge whether the result is good enough to report.
Who it is for
Students using YOLO for a course project, thesis or first paper, and engineers working on industrial visual inspection. You should be comfortable with the command line and Python.
What you will have
A training workflow you can follow, plus complete test results for four models on NEU-DET to use as a baseline for your own experiments.
Covers
  • VOC XML to YOLO TXT conversion and directory layout
  • Stratified splitting and handling duplicate images
  • How to write data.yaml and use absolute paths on a server
  • Training settings and real results for YOLOv8n/s and YOLO11n/s under one setup
  • What mAP50 and mAP50-95 mean, and what is normal on NEU-DET
  • How to read the confusion matrix, PR curve, per-class AP and error examples
Does not cover
  • Annotation tool interfaces (LabelImg, Roboflow)
  • Architecture changes such as attention modules
  • Deployment and TensorRT acceleration

Main path: step by step

Dataset

Why this stepThe split and the metrics depend on these counts.

NEU-DET is the detection subset of the NEU surface defect database released by Kechen Song's group at Northeastern University (China). It contains 1,800 grayscale images of hot-rolled steel strip, each 200×200 pixels, with 300 images for each of six defect classes. Annotations are VOC XML.

Our audit counted 4,189 boxes. Three of them are exact duplicate rows inside the same image, which Ultralytics removes on load, so 4,186 boxes are used. Image count, box count and class count are three different numbers and should be reported separately.

Class IDNameDescriptionTest boxes
0crazingnetwork of fine cracks107
1inclusionembedded foreign material151
2patchesirregular surface patches120
3pitted_surfacesmall pits63
4rolled-in_scaleoxide scale pressed into the surface98
5scratcheslinear scratches86
Class IDs start at 0 and must use the same order in conversion, training and evaluation. The test set has 270 images and 625 boxes.

Step 1

Why this stepYOLO does not read XML. Each image needs a TXT file with the same name, one box per line.

A YOLO detection label has five columns: class_id x_center y_center width height. The last four are normalized to 0–1 by the image width and height. VOC bndbox stores pixel corners xmin, ymin, xmax, ymax, so they must be converted.

For example, a class 0 box (20, 40, 100, 120) in a 200×200 image becomes the line 0 0.30 0.40 0.40 0.40. An image with two defects has two lines.

Directory layout (images and labels mirror each other)text
neu_det_yolo/
├── data.yaml
└── data/
    ├── images/{train,val,test}/crazing_103.jpg
    └── labels/{train,val,test}/crazing_103.txt
VOC corners to YOLO center format (W, H = image size)text
x_center = (xmin + xmax) / (2W)
y_center = (ymin + ymax) / (2H)
width    = (xmax - xmin) / W
height   = (ymax - ymin) / H

Step 2

Why this stepTrain updates the weights, val selects the checkpoint and drives early stopping, and test is used only for the final report.

We stratified by image class with a fixed seed and split 70%/15%/15% into 1,260/270/270 images, or 210/45/45 per class. All four models used the same split list.

Compute a SHA256 hash for every image before splitting. Here patches_101.jpg and patches_105.jpg are byte-identical, so both were placed in the same split. If they land in train and test, the test score is inflated.

Do not use the test set to choose epochs, learning rate or augmentation. Changing the model after looking at test errors requires new held-out data.

RatioAdvantageCost
70/15/15 (this run)45 val and 45 test images per classLess training data than 80/10/10
80/10/10More training dataOnly 30 test images per class, so results vary more
Group by batch for industrial dataTests transfer to a new line or cameraRequires capture metadata

Step 3

Why this stepdata.yaml tells YOLO where each split's images are and what the classes are called.

train, val and test point to image folders. YOLO finds labels by replacing images with labels in the path. Ultralytics versions resolve a relative path differently, so regenerate data.yaml with an absolute path on the GPU server before training.

data.yamlyaml
path: /absolute/path/to/neu_det_yolo/data
train: images/train
val: images/val
test: images/test
names:
  0: crazing
  1: inclusion
  2: patches
  3: pitted_surface
  4: rolled-in_scale
  5: scratches

Step 4

Why this stepAll four models use identical settings so their results can be compared.

Check the GPU and environment firstbash
nvidia-smi
python -c "import torch, ultralytics; print(torch.__version__, torch.cuda.is_available(), ultralytics.__version__)"
Training command (settings used in this run)bash
yolo detect train data=data.yaml model=yolov8n.pt \
  epochs=200 patience=50 batch=16 imgsz=640 \
  optimizer=SGD lr0=0.01 seed=20261027 deterministic=True \
  workers=4 device=0
ParameterValueNote
epochs200Upper limit; early stopping can end sooner
patience50Stop after 50 epochs without validation improvement
batch16Fits in a 16 GB T4
imgsz640200×200 images are upscaled, which adds no detail
optimizerSGDSet explicitly; optimizer=auto ignores lr0
modelyolov8n/s.pt, yolo11n/s.ptAll start from official COCO pretrained weights
Environment: Ultralytics 8.4.190 on one Tesla T4.

Step 5

Why this stepCurves show convergence and overfitting. They are not the final score.

box_loss

Position error between predicted and true boxes. Lower is better, but values are not comparable across models.

cls_loss

Classification error. Falling training loss with steadily rising validation loss and falling validation mAP signals overfitting.

Large early swings

The NEU-DET validation set has only 270 images, so per-epoch mAP is noisy. Read the trend and the mean of the last 20 epochs, not a single peak.

Curve ends before epoch 200

This may be early stopping or an interruption. Check the log; do not fill in missing epochs.

YOLO11n validation mAP50 and mAP50-95 by epoch on NEU-DET
YOLO11n validation mAP. It swings widely for the first 75 epochs and settles near 75% mAP50 and 42% mAP50-95 after about 150 epochs.
YOLO11n training and validation box, cls and dfl loss curves
YOLO11n training (solid) and validation (dashed) loss. Validation loss flattens after about 100 epochs and does not keep rising. The sudden drop in training loss over the last 10 epochs comes from close_mosaic=10 turning off Mosaic augmentation.

Step 6

Why this stepTo answer whether your mAP is normal, compare against a baseline with the same dataset and evaluation method.

IoU is the intersection area of the predicted and true boxes divided by their union. mAP50 averages per-class AP at an IoU threshold of 0.5, so a box only needs to roughly overlap. mAP50-95 averages AP over ten thresholds from 0.50 to 0.95 in steps of 0.05, so boxes must fit tightly, and it is always lower than mAP50.

A common claim is that mAP50-95 above 0.7 is good. That claim ignores the dataset. NEU-DET defects have vague boundaries: all four models score 41%–43% mAP50-95, and five papers report YOLOv8n mAP50 between 74.8% and 78.4%. On this dataset, about 75% mAP50 and 42% mAP50-95 is a normal baseline.

ModelTest mAP50Test mAP50-95PrecisionRecall
YOLOv8n77.06%42.14%74.7%71.6%
YOLO11n76.60%42.82%75.2%69.3%
YOLO11s75.76%42.62%74.2%71.2%
YOLOv8s74.63%41.12%72.5%69.0%
NEU-DET test set, 270 images, Ultralytics val defaults (conf=0.001, NMS IoU=0.7), one random seed. The four models are within 2.5 percentage points; one seed is not enough to call any of them significantly better.

Step 7

Why this stepThe confusion matrix separates class mix-ups from missed and false detections.

Read the axes first. Here the horizontal axis is the true class and the vertical axis is the predicted class. The diagonal counts correct boxes.

The bottom background row counts misses: real boxes the model did not report. The crazing column has 53 misses against 54 correct, so half of the 107 crazing boxes were missed. The rightmost background column counts false positives: predicted boxes with no matching defect. The crazing row has 49 and the rolled-in_scale row has 47.

The six defect classes are almost never confused with each other; only one patches box was predicted as pitted_surface. On NEU-DET the main problem is separating defects from background.

YOLO11n confusion matrix on the NEU-DET test set, predicted class on the vertical axis and true class on the horizontal axis
YOLO11n test confusion matrix (counts). True class on the horizontal axis, predicted class on the vertical axis. Almost all off-diagonal counts are in the background row and column.

Step 8

Why this stepOverall mAP hides the weakest classes. Per-class AP shows where to work next.

Crazing is a fine network texture spread over the whole region, so box boundaries are hard to annotate consistently. Rolled-in scale looks similar to normal oxide texture. Their AP50-95 values are only 14.6% and 28.6%. To raise overall mAP, start with these two classes: check annotation consistency and study missed examples before changing the architecture.

ClassYOLO11n AP50YOLO11n AP50-95YOLOv8n AP50 in three papers
crazing43.7%14.6%38.8%–47.9%
inclusion85.1%41.1%82.0%–84.9%
patches93.9%64.4%88.9%–94.0%
pitted_surface85.3%57.7%83.3%–84.3%
rolled-in_scale62.7%28.6%55.9%–66.9%
scratches89.0%50.5%92.0%–97.1%
Paper range covers YOLO-SDS, DDI-YOLO and Regularized YOLO, the three papers that report all six class AP50 values. All four of our models share the same two weakest classes: crazing and rolled-in_scale.
Crazing example: green solid boxes are ground truth, red dashed boxes are predictions, one crazing region at lower left is missed
Missed crazing (crazing_103.jpg). Green solid boxes are ground truth and red dashed boxes are predictions; the thick box at lower left was not detected.
Rolled-in scale example: the model predicts a box where no defect is annotated
Rolled-in scale false positive. A region with defect-like texture is reported as a defect.

Concepts and judgment

Background

Why this stepThis explains a common reason your numbers do not match a paper or a colleague's.

Training used imgsz=640, but Ultralytics val uses rectangular inference by default (rect=True), and the 200×200 images were actually processed as 672×672 tensors. Saving predictions with predict at 640×640 and computing AP from them gives different numbers.

Under the 640 method, mAP50 is 74.29% for YOLO11n, 74.03% for YOLO11s, 70.52% for YOLOv8n and 69.53% for YOLOv8s. YOLOv8n ranks first under val defaults and YOLO11n ranks first under the 640 method. The weights are the same; only the evaluation changed.

An independent review found this mismatch, and the report lists both sets of results separately. When comparing with papers, align at least the split, input size, epochs, pretrained weights, software version, and whether results are on val or test.

PaperSplitYOLOv8n mAP50
FP-YOLOv8 (Sensors 2024)train/val 7:374.8%
DDI-YOLO (Applied Sciences 2024)1440/180/18075.9%
YOLO-SDS (Sensors 2024)9:1, 1620/18076.2%
DSL-YOLO (Sensors 2024)8:1:1, 1440/180/18076.4%
Regularized YOLO (Sensors 2024)train/val 8:278.4%
This page (val defaults)1260/270/270, test set77.1%
Splits, epochs and batch sizes differ, so these values are a reference range, not a ranking.

Choose by your situation

Choosing

Why this stepChoose a model by accuracy, speed and size.

On a small dataset like NEU-DET with 1,800 images, the s models were not more accurate than the n models, and they were 2–3 times slower on CPU. Start with an n model as the baseline when data is limited. YOLO11n has fewer parameters and slightly higher mAP50-95. Try s or larger when you have more data or smaller objects.

ModelParamsGFLOPsWeightsT4 per imageCPU per image
YOLO11n2.61M6.65.5 MB9.7 ms166 ms
YOLOv8n3.14M8.86.5 MB8.0 ms166 ms
YOLO11s9.43M21.719.2 MB10.8 ms382 ms
YOLOv8s11.14M28.722.5 MB11.0 ms480 ms
FP32, batch=1, 640 input, including image decoding, preprocessing, inference and NMS; mean of 100 timed runs after 10 warm-ups. CPU uses 2 threads.

Reference and appendix

Run record

Why this stepData source and run conditions, so you can check the numbers.

All numbers on this page come from one long research task on Scientify on 27 October 2026. After the user uploaded a task brief, Scientify listed five research requirements for confirmation. It then downloaded the data, checked for duplicate images, rented one T4 GPU, trained the four models in sequence, synced the results back to the workspace, released the GPU, and wrote a 35-page report in Chinese.

After the first report, an independent review flagged that validation and speed tests used different input sizes (672 and 640). Scientify recomputed everything under the 640 method and changed the conclusion from "YOLOv8n is best" to "the ranking depends on the evaluation method". The second review passed. The task took about 5 hours, about 3 of them on the GPU.

Scientify workspace showing research requirements R1 to R5 awaiting confirmation
The five research requirements confirmed before the run: data audit and split, four-model training, figures and error examples, literature baselines, and delivery with GPU release.
Scientify recomputing AP under the 640 method after independent review and correcting the conclusion
Repair after the independent review: AP recomputed under the 640 method, with both result sets labeled separately in the report.

Common errors and fixes

Ordered by how often they occur.

Dataset images not found / FileNotFoundError

Cause: The path in data.yaml is relative or points to your local machine, or case and extensions differ.

Fix: Regenerate data.yaml with an absolute path on the training machine and confirm that images/train and the other folders exist.

No labels found, or an unusually high background count

Cause: labels does not mirror images, or XML files were passed to YOLO directly.

Fix: Make sure every image has a non-empty TXT with the same name under labels. Convert VOC to YOLO first.

non-normalized or out of bounds coordinates

Cause: Pixel coordinates were written to TXT, or COCO xywh was treated as VOC xyxy.

Fix: Normalize by the original image size. Find the bad source annotations instead of clipping every box.

Label class exceeds dataset class count

Cause: Class IDs do not start at 0, or names order differs from the conversion.

Fix: Keep one class map and use it for both conversion and data.yaml.

Labels were fixed but counts are unchanged

Cause: YOLO cached the previous scan.

Fix: Delete the .cache file next to labels and train again.

CUDA out of memory

Cause: Batch is too large or another process holds GPU memory.

Fix: Check usage with nvidia-smi. If memory is still short, lower batch for every model in the comparison.

torch.cuda.is_available() returns False

Cause: A CPU-only PyTorch is installed, or a different Python is running.

Fix: Check with which python and pip show torch, then install a GPU build that matches the driver.

Loss is nan or mAP stays at 0

Cause: Wrong label coordinates or classes, pretrained weights not loaded, or learning rate too high.

Fix: Overlay labels on sample images, confirm model=*.pt, then check learning rate and AMP. More epochs will not fix this.

References

FAQ

How many epochs does YOLOv8 need on a custom dataset?

We used 200 epochs with patience 50 on NEU-DET. Validation mAP settled after about 150 epochs, and YOLOv8s stopped early at epoch 157. For small datasets, 200 epochs with early stopping is a reasonable start; use the validation curve flattening as the signal.

What is a good mAP50-95?

There is no cross-dataset standard. On NEU-DET all four models score 41%–43% mAP50-95 and about 75% mAP50, consistent with published papers. Judge your result against a baseline with the same dataset, split and evaluation method.

Is YOLOv8 or YOLO11 better?

On NEU-DET they differ by about one percentage point, and the ranking changes with the evaluation method. YOLO11n has fewer parameters (2.61M vs 3.14M) and slightly higher mAP50-95; YOLOv8n is slightly faster on a T4. One seed is not enough to call a significant difference.

Why is my mAP lower than in the paper?

Usually the split, input size, epochs, software version or evaluation method differ. On this page the same YOLOv8n weights score 77.1% mAP50 under one evaluation method and 70.5% under another. List these conditions in one table before comparing.

Which NEU-DET class is hardest to detect?

Crazing and rolled-in_scale. Across the four models crazing AP50 is about 43%–49% and rolled-in_scale about 56%–63%. The main errors are misses and background false positives, not confusion between classes.

Can I train without a GPU?

Training on CPU works but is slow. Here YOLOv8n trained for 200 epochs in about 29 minutes on a T4. Without a local GPU, rent an hourly cloud GPU and release it when training ends.

Let Scientify train on your dataset

Upload your data and a task description. Scientify prepares the format, rents a GPU for training, produces figures and a report, and releases the GPU when training ends.