Collaboration · Supporting a final-year team of four
YOLO Object Detection (YOLO26)
Co-authored
AI
Supporting a four-person HKMU final-year team on how well vision models find objects underwater, in adverse weather, at small scale and under camouflage: the shared code, built with Claude Code, and the real-data baselines of all four plans.
A four-person HKMU final-year team is studying how well computer-vision models find objects underwater, in adverse weather, at small scale and under camouflage, in one shared repository with a four-tab demo app. My part, built with Claude Code, was the shared training, evaluation and results code and the first real-data baseline: YOLO26n on Brackish, 20 epochs, one seed, validation mAP50 0.584 and mAP50-95 0.345. Crab AP was 0.000 in that same run, and the cause is still unknown. I then ran the Phase 1 baselines of all four plans through a remote session on a teammate’s faster PC (PR #4, still open), seed 0 only: mAP50 0.635 on DAWN, 0.291 on VisDrone and S-measure 0.853 on COD10K. These are baselines: the team’s attention, distillation and edge methods have not yet been trained on real data.
§ 02
In motionInmotion
Each video clip goes into exactly one of train, validation and test, so no clip crosses; then the detector is tested underwater, in bad weather, on small objects and against camouflage.§ 03
My contributionsMycontributions
Shared framework (PR #1, with the run plots added in PR #2), written with Claude Code: a dataset manifest, one train, evaluate and log loop, a results CSV and run plots. Python on main, starter files included, totals 5,404 lines with 84 test functions, counted from the source rather than from a test run.
Drafted code for all four plans (PR #1): per-plan training scripts, custom attention and fusion layers, and a four-tab Gradio demo app. The real-data runs that followed are baselines: the custom layers have not been trained on real data, and the demo app was only checked to start and serve its four tabs.
Underwater baseline (PR #2): YOLO26n on Brackish, 20 epochs, one seed, validation mAP50 0.584 and mAP50-95 0.345. Crab AP was 0.000 in the same run. The best checkpoint was picked on validation, so both figures are slightly optimistic.
Phase 1 baselines of all four plans (PR #4, still open), through a remote session on a teammate’s RTX 5060 Ti PC: a scheduled runner trained five models overnight in about 3 h 40 min. Seed 0 only: Brackish mAP50 0.597 at 50 epochs, DAWN fold 0 student 0.635, VisDrone 0.291 with AP small 0.083, and S-measure 0.853 on COD10K and 0.854 on CAMO. The 50-epoch underwater run is newer but not clearly better: mAP50-95 went from 0.345 to 0.344 and precision from 0.754 to 0.580.
Dataset corrections (PR #1), with Claude Code: re-split Brackish by video clip and renumbered DAWN’s classes by name, checked against the PASCAL VOC names of its 1,027 images.
Project governance: plans, phase gates, stewards for shared files and the team’s workflow documents.
A training driver for all four plans and a guard against reusing a run of another epoch count (PR #3). That pull request was closed without merging, so none of this work reached main.
§ 04
How it worksHowitworks
1
Dataset manifest
One JSON file records each dataset’s source, licence notes and download instructions.
tells the scripts what to fetch
2
Preparation
Scripts prepare and check Brackish and DAWN, then write fixed split lists, with Brackish split by video clip.
fixed train and validation lists
3
Model definition
Ultralytics stays pinned at 8.4.175; generated YAML files and a layer map add custom layers without editing the library.
model source and trainer class
4
Shared training loop
Plans A, B and C train through one loop at 640 px with nms=False; Plan D keeps its own plain PyTorch loop.
evaluates the trained weights
5
Results log
Each run adds one CSV row with its metrics, head, GPU, commit, library versions and timestamp.
saves a figure of the run
6
Plots
A Matplotlib figure of each run shows losses, mAP and per-class scores; selected plots are committed beside the results.
§ 05
ExhibitsExhibits
Validation scores per class from the 20-epoch run with one seed. Crab is at 0.000 and shrimp at 0.080, while the headline mAP50 of 0.584 averages all six.Normalised confusion matrix from the same run. True crabs go to background at 1.00, and 0.54 of true shrimp are lost the same way.Validation mAP across the run. Epoch 16 is the best checkpoint at mAP50-95 0.345, and more epochs alone did little after about epoch 7.
§ 06
Engineering notesEngineeringnotes
Dispatch № 1
The split that leaked whole clips
The problem
The Roboflow copy of Brackish spread all 89 source clips across train, validation and test. Frames from one clip sat on both sides of the split, which flatters validation scores.
The decision
Keep every clip whole in one split. Try 500 clip orders and pick the one whose validation and test sets best match the class mix, without using model results.
The result
The 14,674 images became 11,612 train, 1,575 validation and 1,487 test, with no clip in two splits. Frames from different clips of the same fixed camera can still look alike.
Dispatch № 2
Measuring accuracy on the head that gets timed
The problem
The plans took YOLO26 inference to be NMS-free by default. Reading Ultralytics 8.4.175 showed that validation uses the one-to-many head with external NMS unless told otherwise, while the speed protocol times the one-to-one head.
The decision
Pass nms=False through the shared train, validation and predict code, and write the head used into the results rows.
The result
Both rows on main record head=one2one(nms=False). Speed has not been measured, so only the accuracy half of the pairing exists so far.
Dispatch № 3
The class the model never found
The problem
In the 20-epoch run crab scored AP 0.000, and the normalised confusion matrix sends true crabs to background at 1.00. Scarcity does not explain it: crab has the most training boxes, 9,706.
The decision
Report the failure in PR #2 beside the headline figure, and advise inspecting crab images and labels before comparing any attention variants.
The result
The cause has not been established. The mAP50 of 0.584 is an average over six classes, so it also hides shrimp at 0.080.
# Which YOLO26 head produces the reported accuracy. In Ultralytics 8.4.175, val, predict and the validation inside training use the
# one-to-many head with external NMS unless nms=False is passed (the default nms=None means external NMS). The speed protocol times
# the NMS-free one-to-one head, so accuracy is measured on that same head: every train, val and predict call passes these arguments.
# Models without a one-to-one head (YOLO11, YOLOv8 reference rows) ignore the setting and keep using NMS.
# This is a protocol decision for the whole team: change it only by agreement and record it in plans/decisions.md.
endToEndArguments = {"nms": False}
# Text added to the notes of every results row so the head used for a number is never ambiguous
endToEndNote = "head=one2one(nms=False)"
The setting lives in one place, and its note is written into the results rows, so a logged number says which head produced it.
§ 08
Development timelineDevelopmenttimeline
No recorded video for this project.
23 Oct 2026
Phase 1 baselines of all four plans recorded (PR #4, open)
Milestone
22 Oct 2026
Underwater baseline merged into main (PR #2)
Milestone
22 Oct 2026
All-plans training driver drafted; PR #3 closed unmerged
Milestone
18 Oct 2026
20-epoch underwater baseline: mAP50 0.584, one seed