YOLO26 tutorial: train a safety gear detection model in 30 minutes on an RTX 5060 8 GB
on this page
Introduction
When people think of a GPU cloud, they usually picture expensive GPUs running large language models. But plenty of AI that’s put to work in the field only needs a single 8 GB GPU. A prime example is object detection, which finds objects in photos and video.
In this post, we train Ultralytics’ latest model, YOLO26, on a gcube RTX 5060 8 GB container to build a model that spots whether workers are wearing helmets, vests, gloves, safety boots and goggles in construction site photos.
By the end of this post, you’ll have
- your own model (
best.pt) that draws boxes around safety gear when you give it a photo, - learned how to read the training curves and accuracy metrics (mAP), and
- an ONNX file you can use on other servers or edge devices.
| Item | Details |
|---|---|
| Difficulty | Beginner (basic Python is all you need) |
| GPU | gcube RTX 5060 8 GB × 1 |
| Model | Ultralytics YOLO26n (optional: YOLO26s) |
| Data | Construction-PPE (1,416 images, 11 classes, downloads automatically) |
| Time required | About 30 minutes (including 7.5 minutes of YOLO26n training) |
1. Background
YOLO26
- The latest YOLO model, officially released by Ultralytics in January 2026.
- Earlier YOLO models needed a separate post-processing step (NMS) to remove overlapping boxes, but YOLO26 handles this inside the model with an NMS-free architecture, which makes deployment simpler.
- It comes in five sizes — n, s, m, l and x. Here we use n (default) and s (optional), which fit comfortably in 8 GB.
The Construction-PPE dataset
A construction site safety gear dataset released by Ultralytics. It contains 1,416 real site images (1,132 train / 143 validation / 141 test) labeled with 11 classes.
| Group | Classes |
|---|---|
| Gear worn (5) | helmet, gloves, vest, boots, goggles |
| Gear missing (4) | no_helmet, no_gloves, no_boots, no_goggle |
| Other (2) | Person, none |
Because “worn” and “missing” are trained as separate classes, you can go beyond simple detection to detecting safety violations. Just specify the dataset name in the training code and it downloads automatically.
2. Create a gcube workload
On gcube, you register a workload by entering the container image address and start command yourself. Use the settings below as is, and the workload starts with PyTorch and JupyterLab ready for the RTX 5060.
| Item | Value |
|---|---|
| GPU | RTX 5060 (8 GB) × 1 |
| Registry Type | Docker Hub |
| Container Image | pytorch/pytorch:2.9.1-cuda12.8-cudnn9-runtime |
| Container Port | 8888 |
| Minimum CUDA Version | 12.8 or later |
Container command
bash -c "apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y git wget libgl1 libglib2.0-0 && pip install jupyterlab && jupyter lab --ip=0.0.0.0 --port=8888 --no-browser --allow-root --ServerApp.token='' --ServerApp.password=''"
Why this image? The RTX 5060 is a Blackwell-generation GPU, so it needs PyTorch built with CUDA 12.8 or later. With an older image, the GPU may be detected but computations won’t work properly. Installing
libgl1up front also lets you proceed without the OpenCV error (libGL.so.1).
Once the workload is running, add /lab to the end of the service URL to open it, then open Notebook → Python 3 from the Launcher. This setup opens without a token, so don’t share the URL with anyone outside your team.
3. Check the GPU environment
In the first notebook cell, check that PyTorch recognizes the RTX 5060 properly.
import torch
print("PyTorch:", torch.__version__)
print("CUDA:", torch.version.cuda)
print("GPU available:", torch.cuda.is_available())
print("GPU name:", torch.cuda.get_device_name(0))
print("Compute capability:", torch.cuda.get_device_capability(0))
PyTorch: 2.9.1+cu128
CUDA: 12.8
GPU available: True
GPU name: NVIDIA GeForce RTX 5060
Compute capability: (12, 0)
You’re all set if CUDA is 12.8 or later and there’s no sm_120 is not compatible warning.
4. Install Ultralytics
!pip install -q ultralytics
import ultralytics
ultralytics.checks()
Ultralytics 8.4.178 🚀 Python-3.11.14 torch-2.9.1+cu128 CUDA:0 (NVIDIA GeForce RTX 5060, 8151MiB)
Setup complete ✅ (12 CPUs, 20.5 GB RAM, 60.8/75.6 GB disk)
When you see Setup complete ✅, you’re ready.
5. First run: detect right away with a pretrained model
Before training, check that the base model — which already knows 80 kinds of objects such as people, cars and buses — runs properly.
from ultralytics import YOLO
from ultralytics.utils import ASSETS
from IPython.display import Image, display
model = YOLO("yolo26n.pt") # downloaded automatically on first run
results = model.predict(ASSETS / "bus.jpg", save=True) # sample image bundled with the package
save_dir = results[0].save_dir
print("Results saved to:", save_dir)
display(Image(filename=f"{save_dir}/bus.jpg", width=600))
The actual output was 640x480 4 persons, 1 bus, 6.1ms. That works out to about 0.006 seconds to analyze one photo.
6. Train the safety gear detection model
6-1. Train YOLO26n (recommended)
import time, torch
from ultralytics import YOLO
torch.cuda.reset_peak_memory_stats()
t0 = time.time()
model = YOLO("yolo26n.pt")
results = model.train(
data="construction-ppe.yaml", # dataset downloads automatically
epochs=50,
imgsz=640,
batch=16,
device=0,
workers=4,
project="ppe",
name="y26n",
)
print(f"Training time: {(time.time()-t0)/60:.1f} min")
print(f"Peak VRAM: {torch.cuda.max_memory_allocated()/1024**3:.2f} GB")
When you run it, it downloads the dataset (170 MB) and starts training right away. If you check GPU_mem in the log, you’ll see it uses only about 3.2 GB of the 8 GB.
| Option | Meaning | 8 GB tip |
|---|---|---|
epochs | How many times to train over the full dataset | 50 is enough |
batch | Number of images processed at once | Lower it to 8 if you run out of memory |
workers | Number of data loading processes | 2 or 0 if you hit a shared memory error |
6-2. Higher accuracy with YOLO26s (optional)
If you run this in the same kernel right after 6-1, GPU memory left over from the previous training causes
CUDA error: out of memory. Restart the kernel from the menu with Kernel → Restart Kernel… → Restart before running it.
import time, torch
from ultralytics import YOLO
torch.cuda.reset_peak_memory_stats()
t0 = time.time()
model = YOLO("yolo26s.pt")
results = model.train(data="construction-ppe.yaml", epochs=100, imgsz=640, batch=16,
device=0, workers=4, project="ppe", name="y26s")
print(f"Training time: {(time.time()-t0)/60:.1f} min")
print(f"Peak VRAM: {torch.cuda.max_memory_allocated()/1024**3:.2f} GB")
7. Check the training results
from IPython.display import Image, display # re-import if you restarted the kernel
save_dir = model.trainer.save_dir # actual save location
print("Training results folder:", save_dir)
display(Image(filename=f"{save_dir}/results.png", width=900))
display(Image(filename=f"{save_dir}/val_batch0_pred.jpg", width=900))
results.png shows loss and accuracy curves per epoch, and val_batch0_pred.jpg shows example predictions on validation images. We also measure final performance on the test set, which the model never saw during training.
best = YOLO(f"{save_dir}/weights/best.pt")
metrics = best.val(data="construction-ppe.yaml", split="test")
print("mAP50:", round(metrics.box.map50, 3))
print("mAP50-95:", round(metrics.box.map, 3))
Measured results (RTX 5060 8 GB, batch 16)
| Model | Epochs | Training time | Peak VRAM | Test mAP50 | Test mAP50-95 |
|---|---|---|---|---|---|
| YOLO26n | 50 | 7.5 min | 2.6 GB | 0.535 | 0.267 |
| YOLO26s | 100 | 21.7 min | 4.6 GB | 0.562 | 0.273 |
- Both models trained comfortably, using around half of the 8 GB or less.
- s is slightly more accurate than n but takes about 3x as long. We recommend starting with n to learn the workflow.
- By class, the model finds gear being worn, like helmets and vests, well, but accuracy was lower for the “missing” classes, because there are fewer examples of missing gear in the training data.
- Training twice with the same image and settings produced exactly the same numbers, so if you follow along, you should get nearly the same results.
How to read mAP: A value between 0 and 1 that shows how accurately the model finds boxes. mAP50 counts a box as correct if it’s “roughly right,” while mAP50-95 requires “precise placement” to count.
8. Apply it to your own photos
Upload a site photo (for example, site.jpg) in the file panel on the left side of JupyterLab, then run:
from PIL import Image as PILImage
res = best.predict("site.jpg", conf=0.4, save=True)
print([(best.names[int(b.cls)], round(float(b.conf), 2)) for b in res[0].boxes])
display(PILImage.fromarray(res[0].plot()[..., ::-1])) # show the result with boxes drawn
Running it on a site photo from the test set gave [('helmet', 0.82), ('vest', 0.81), ('Person', 0.78), ('gloves', 0.51)]. It found a worker wearing a helmet, vest and gloves.
conf=0.4means only detections with 40% confidence or higher are shown. Raise it if you get too many false positives, and lower it if it misses too much.- You can process video the same way with
best.predict("site.mp4", save=True).
Picking out only missing gear — the basic form of a safety monitoring system.
VIOLATIONS = {"no_helmet", "no_gloves", "no_boots", "no_goggle"}
found = [best.names[int(b.cls)] for b in res[0].boxes if best.names[int(b.cls)] in VIOLATIONS]
print("Violations detected:", found if found else "none")
9. Export the model (ONNX)
To use the model on other servers or edge devices, convert it to ONNX format.
onnx_path = best.export(format="onnx")
print(onnx_path)
On the first run, the required packages install automatically and best.onnx is created within a few seconds. Even if you see a Restart runtime... warning partway through, it succeeded as long as Export complete appears. You can download it from the file panel with right-click → Download.
10. Troubleshooting
These are errors we actually ran into when using a different image or changing the order of steps.
| Symptom | Cause | Fix |
|---|---|---|
sm_120 is not compatible warning | PyTorch built for CUDA 12.4 or earlier | Use the image recommended in step 2, or run pip install --upgrade torch torchvision --index-url https://download.pytorch.org/whl/cu128 and restart the kernel |
ImportError: libGL.so.1 | The container lacks the libraries OpenCV needs | Include libgl1 in the step 2 command, or switch to opencv-python-headless and restart the kernel |
Download failure ... Connection reset by peer | Intermittent connection drops from the download server | Rerun the cell. Download the dataset directly with the code below |
CUDA error: out of memory | GPU memory from the previous training is still in use | Restart the kernel and run again; if it’s still not enough, use batch=8 |
If the automatic dataset download fails:
from ultralytics.utils import DATASETS_DIR
from ultralytics.utils.downloads import download
download("https://github.com/ultralytics/assets/releases/download/v0.0.0/construction-ppe.zip", dir=DATASETS_DIR)
Wrapping up
With a single 8 GB GPU, we built a model that detects construction site safety gear in 30 minutes. Training used only 2.6 GB of VRAM, so you can absolutely get started with vision AI like object detection without an expensive GPU.
What to try next
- Train on your own data: Create YOLO-format labels with Label Studio or CVAT, write a yaml file with the same structure, and you can train with the same code.
- Extend to other tasks: The same API also handles segmentation (
yolo26n-seg.pt) and pose estimation (yolo26n-pose.pt). - Larger models: If you need higher accuracy, try training the m or l models on a larger GPU on gcube.
License note: The Ultralytics YOLO code and the Construction-PPE dataset are licensed under AGPL-3.0. You can use them freely for learning and research, but deploying a commercial service that includes them triggers source-disclosure obligations, so look into an Ultralytics Enterprise License.