Meet YOLO26: next-gen vision AI.
Train your first YOLO model·Train·Lesson 8/10
Lessonbeginner

Resume and Iterate

Continue from where training stopped, fine-tune best.pt, and run experiments cheaply.

Real CV projects are a sequence of training runs, not a single epic one. Each round adds data — often guided by active learning — fixes a labeling bug, or tries a new image size. Knowing how to cheaply restart with fine-tuning instead of retraining from scratch is what makes that loop tight.

Outcome

Resume an interrupted training run, and start a new run from your previous best.pt instead of from a pretrained model.

Fast Track
If you already know your way around, here's the short version.
  1. yolo train resume=True model=runs/detect/.../weights/last.pt — continues exact training.

  2. YOLO('runs/.../best.pt').train(data=…) — new run, but starts from your weights.

  3. Tag runs with descriptive names: name=v2_added_pallets.

Hands-on

Link to this sectionResume an interrupted run#

Ultralytics Platform training charts and metrics

If a run was killed (power cut, disconnect, OOM at hour 8), resume training instead of starting over. Two options:

yolo train resume=True model=runs/detect/forklift_v1/weights/last.pt
from ultralytics import YOLO

model = YOLO("runs/detect/forklift_v1/weights/last.pt")
model.train(resume=True)

Resume picks up the exact optimizer state, learning-rate schedule, and epoch counter. It will not reset the schedule — it continues from where it stopped.

Resume vs new run

Resume only makes sense if the config hasn't changed. Different epoch count, image size, or data → it's a new run that starts from a checkpoint, not a resume. Use resume=False and pass the checkpoint as the model.

Link to this sectionIterate from your best.pt#

Most "next round" experiments aren't resumes — they're fresh runs that warm-start from your last good model. This is plain transfer learning inside your own project:

from ultralytics import YOLO

model = YOLO("runs/detect/forklift_v1/weights/best.pt")    # warm start

model.train(
    data="my_dataset/data.yaml",         # now with extra pallets
    epochs=50,                            # shorter — already pretrained on your data
    imgsz=640,
    name="forklift_v2_more_pallets",
    lr0=0.001,                            # lower LR — fine-tune, not retrain
)

Lower learning rate is the key knob: you want to nudge the model, not reset it. lr0=0.001 (vs the default 0.01) is a sane fine-tune starting point — the fine-tuning guide covers layer freezing and two-stage training when defaults aren't enough; the hyperparameter tuning guide covers sweeps and the genetic optimizer. Augmentation knobs live in the data augmentation guide.

Link to this sectionNaming runs#

Let your future self thank you: name every run after what changed.

BadGood
train2v2_added_pallets
exp_finalv3_imgsz1024_pallet_recall
backupv4_no_mosaic_aug
model.train(name="v2_added_pallets", ...)

A consistent naming scheme means you can compare results.csv across runs trivially. For richer experiment tracking, plug in the Comet or Weights & Biases integrations — both auto-log losses, metrics, and sample predictions per run.

Link to this sectionCompare runs side-by-side#

Ultralytics YOLO writes a results.csv per run. A small helper to compare:

import pandas as pd
import glob

rows = []
for path in sorted(glob.glob("runs/detect/*/results.csv")):
    df = pd.read_csv(path)
    rows.append({
        "run": path.split("/")[-2],
        "epochs": len(df),
        "best_mAP50_95": df["metrics/mAP50-95(B)"].max(),
        "final_box_loss": df["train/box_loss"].iloc[-1],
    })
print(pd.DataFrame(rows).to_string(index=False))

Link to this sectionWhen to start completely fresh#

Sometimes the dataset has changed enough — added a class, relabeled half the data — that warming from your old best.pt actually hurts. The old weights know "this background is forklift territory" with old labels; new labels disagree. In that case start from the pretrained YOLO again:

model = YOLO("yolo26n.pt")       # back to vanilla
model.train(data="my_dataset/data.yaml", epochs=100, name="v3_relabeled")
Try It

Take your trained model, add 20 more labeled images to the training set, and run a 30-epoch fine-tune with lr0=0.001. Compare mAP between v1 and v2 — the change should be small but in the right direction.

Done When
You've finished the lesson when all of these are true.
  • You've resumed an interrupted run at least once.

  • You've started a fresh run from your best.pt with a lower learning rate.

  • You've named your runs descriptively enough to compare them later.

What's next

Now let's apply the trained model to video — the format your real users probably care about.