Install any skill in seconds. Free to start, no credit card required.
Get Started Free →This skill should be used when user asks to "improve my mAP", "why is my model overfitting", "my training is diverging", "read my results.csv", "interpret my training curves", "my AP50 is good but AP50-95 is bad", "my recall is low", "how do I pick learning rate", "which augmentations should I use", "should I use a bigger model", "tune hyperparameters", or asks how to train YOLO26 for detection, instance or semantic segmentation, pose, OBB, classification, or depth.
.claude/skills/fcakyon-yolo-training/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 30% | 0% |
| case-02 | ✗→✓ | ▲ Improved | -28% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 8% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 32% | 0% |
| case-20 | ✗→✓ | ▲ Improved | 19% | 0% |
Read the run before changing anything. The results.csv and confusion matrix usually name the problem already.
Ordered by cost to try, cheapest first, not by size of the potential win.
but time to rule out.
train and val curves sit close together. That is underfitting, and it is the only case a bigger model reliably fixes.
imgsz, so 640 to 1280 is roughly 4x thetraining budget, and pretrained weights transfer worse the further you move from the size they were fit at. Justify it with the object sizes in your data, not as a default first move.
package ships no dataset-analysis tooling, so any audit here is your own script plus looking at images. Worth it once the cheap knobs are spent.
pythonimport pandas as pd df = pd.read_csv("runs/detect/train/results.csv") df.columns = df.columns.str.strip() print(df.tail(10)[["epoch", "train/box_loss", "val/box_loss", "metrics/mAP50(B)", "metrics/mAP50-95(B)"]]) print("best epoch:", df["metrics/mAP50-95(B)"].idxmax(), "of", len(df))
Then read, in this order:
| Read | Question it answers | | ------------------------------------------ | ----------------------------------------- | | best epoch vs total epochs | undertrained, overtrained, or right | | train loss vs val loss trend | which side of the generalization gap | | mAP50 vs mAP50-95 | classification and recall vs localization | | P vs R at the operating point | over-suppression vs over-firing | | per-class AP spread | one broken class or a general weakness | | confusion matrix background row and column | false positives vs missed detections |
references/diagnostics.md maps each pattern to a cause and a knob, and lists what to rule out before turning that knob. Read it before recommending a change. references/task-notes.md covers detect, segment, semantic, pose, obb, classify, and depth specifics.
These produce "I changed X and nothing happened". All six are current defaults.
optimizer=auto ignores lr0 and momentum. It is the default. It picks MuSGD atlr 0.01 when ceil(len(dataset) / max(batch, nbs)) * epochs exceeds 10000, otherwise AdamW at 0.002 * 5 / (4 + nc), and forces warmup_bias_lr=0. Crossing that iteration count silently changes optimizer between two runs you meant to compare. Setting lr0 while leaving optimizer=auto does nothing. Set optimizer=AdamW or optimizer=SGD explicitly first.
nbs=64 normalizes the loss, so batch does not scale LR the way you assume. Below 64 thetrainer accumulates gradients to an effective 64. Dropping batch 64 to 16 changes almost nothing about the effective step.
close_mosaic=10 turns off mosaic for the last 10 epochs. The late jump in mAP is thatswitch, not convergence. On a 20-epoch run it is half the schedule, and on a 10-epoch run mosaic never runs at all.
[0, 0, 0, 1]. best.pt and patienceignore precision, recall, and mAP50 completely. Segment and pose sum both heads, classify uses (top1 + top5) / 2, semantic uses mIoU. A run whose precision is climbing while mAP50-95 is flat will still early-stop.
max_det=300 truncates validation on dense scenes. Above roughly 300 objects per imageyour recall ceiling is an artifact.
end2end models decode without NMS, so iou does nothing on them. agnostic_nmsstill applies, the predictor passes it into the head, so only the IoU threshold is dead.
Fine-tuning a pretrained checkpoint on a normal custom dataset:
bashyolo train model=yolo26s.pt data=my-data.yaml epochs=200 imgsz=640 batch=16 \ optimizer=AdamW lr0=0.001 lrf=0.01 cos_lr=True warmup_epochs=3 \ patience=50 close_mosaic=20
Deviate on evidence from the charts, one axis at a time. It differs from the shipped defaults because epochs=100 is short for a small dataset, patience=100 never fires inside 100 epochs, and close_mosaic=10 is too short a clean tail once epochs rise.
Change one thing per run and keep seed fixed. Run-to-run noise on a small dataset is often 0.5 to 1.0 mAP, so a 0.3 mAP "improvement" from a single run is not a result. Confirm anything under about 1 point across three seeds.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 19,690 | 20,759 | +5% | 1 | 1 | 0% | 3,241 | 4,212 | +30% | 0 | 0 | — |
case-02 | fail→pass | 20,493 | 8,743 | -57% | 1 | 1 | 0% | 2,875 | 2,079 | -28% | 0 | 0 | — |
case-03 | fail→fail | 19,421 | 5,601 | -71% | 1 | 1 | 0% | 2,557 | 2,485 | -3% | 0 | 0 | — |
case-04 | pass→fail | 20,758 | 12,076 | -42% | 1 | 1 | 0% | 2,530 | 3,078 | +22% | 0 | 0 | — |
case-05 | pass→pass | 19,321 | 12,597 | -35% | 1 | 1 | 0% | 2,825 | 2,630 | -7% | 0 | 0 | — |
case-06 | fail→pass | 19,826 | 12,586 | -37% | 1 | 1 | 0% | 2,534 | 2,741 | +8% | 0 | 0 | — |
case-07 | pass→pass | 12,659 | 10,252 | -19% | 1 | 1 | 0% | 2,219 | 2,353 | +6% | 0 | 0 | — |
case-08 | fail→pass | 11,475 | 11,743 | +2% | 1 | 1 | 0% | 2,061 | 2,723 | +32% | 0 | 0 | — |
case-09 | fail→fail | 17,035 | 11,016 | -35% | 1 | 1 | 0% | 2,006 | 2,441 | +22% | 0 | 0 | — |
case-20 | fail→pass | 18,936 | 14,851 | -22% | 1 | 1 | 0% | 2,729 | 3,235 | +19% | 0 | 0 | — |
case-10 | pass→pass | 10,203 | 8,326 | -18% | 1 | 1 | 0% | 1,877 | 2,008 | +7% | 0 | 0 | — |
case-11 | fail→pass | 18,331 | 12,741 | -30% | 1 | 1 | 0% | 2,092 | 2,474 | +18% | 0 | 0 | — |
case-12 | pass→pass | 16,487 | 21,123 | +28% | 1 | 1 | 0% | 1,813 | 3,535 | +95% | 0 | 0 | — |
case-13 | fail→pass | 19,457 | 12,213 | -37% | 1 | 1 | 0% | 2,023 | 2,786 | +38% | 0 | 0 | — |
case-14 | pass→pass | 14,418 | 22,701 | +57% | 1 | 1 | 0% | 3,218 | 5,328 | +66% | 0 | 0 | — |
case-15 | pass→pass | 23,175 | 20,748 | -10% | 1 | 1 | 0% | 3,823 | 4,723 | +24% | 0 | 0 | — |
case-16 | pass→pass | 23,905 | 19,605 | -18% | 1 | 1 | 0% | 4,561 | 4,676 | +3% | 0 | 0 | — |
case-17 | pass→pass | 19,122 | 18,997 | -1% | 1 | 1 | 0% | 2,628 | 3,621 | +38% | 0 | 0 | — |
case-18 | pass→pass | 18,111 | 13,831 | -24% | 1 | 1 | 0% | 2,361 | 2,691 | +14% | 0 | 0 | — |
case-19 | pass→pass | 16,942 | 12,385 | -27% | 1 | 1 | 0% | 1,974 | 2,632 | +33% | 0 | 0 | — |
case-21 | pass→pass | 19,652 | 9,644 | -51% | 1 | 1 | 0% | 2,694 | 2,289 | -15% | 0 | 0 | — |
case-22 | pass→pass | 12,512 | 7,904 | -37% | 1 | 1 | 0% | 1,093 | 1,953 | +79% | 0 | 0 | — |
case-23 | fail→pass | 19,468 | 11,842 | -39% | 1 | 1 | 0% | 2,233 | 2,426 | +9% | 0 | 0 | — |
case-24 | pass→pass | 12,630 | 11,089 | -12% | 1 | 1 | 0% | 1,624 | 2,622 | +61% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 24 cases were attempted. The headline lift of +29 percentage points is the difference between those two pass rates over the 24 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.