Workflow i CLI¶
Po ostatnim refaktorze Easy-RT-DETR ma juz jeden glowny workflow eksperymentow zamiast wielu rozlacznych skryptow.
Glowne elementy¶
Nowy stack sklada sie z:
- YAML configow w
configs/, - loadera configow i override'ow w
easy_rtdetr/configuration.py, - wspolnego solvera w
easy_rtdetr/engine/solver.py, - wspolnych builderow danych w
easy_rtdetr/data/, - builderow optimizera, schedulerow, warmupu i EMA w
easy_rtdetr/optim/, - glownego CLI w
easy_rtdetr/cli.py, - cienkich wrapperow w
scripts/.
To jest teraz preferowana sciezka uruchamiania projektu.
Glowne entrypointy¶
W repo pozostaly uniwersalne skrypty:
scripts/train.pyscripts/eval.pyscripts/visualize.pyscripts/benchmark_video.pyscripts/calibrate.pyscripts/prepare_dataset.pyscripts/run_remote.py
Skrypty dataset-specific zostaly usuniete z glownego workflow.
Trening¶
Przyklad treningu na VOC car:
.venv/bin/python scripts/train.py --config configs/voc_car/base.yaml
Przyklad treningu z override:
.venv/bin/python scripts/train.py \
--config configs/voc_car/base.yaml \
--set solver.epochs=5 \
--set model.backbone_name=hgnetv2_s
Przyklad gotowego configu dla HGNet-V2-S:
.venv/bin/python scripts/train.py --config configs/voc_car/hgnetv2_s.yaml
Mozna tez wymusic zapis finalnego checkpointu pod konkretna sciezka:
.venv/bin/python scripts/train.py \
--config configs/voc_car/base.yaml \
--output artifacts/voc_car_best.pt
Ewaluacja¶
Przyklad:
.venv/bin/python scripts/eval.py \
--config configs/voc_car/base.yaml \
--checkpoint runs/voc_car/.../checkpoints/best.pt
Wynik obejmuje miedzy innymi:
AP50AP75mAP@0.50:0.95avg_best_iou- proxy precision/recall
- duplikaty boxow
Wizualizacja¶
Przyklad:
.venv/bin/python scripts/visualize.py \
--config configs/voc_car/base.yaml \
--checkpoint runs/voc_car/.../checkpoints/best.pt \
--input car_on_street.avif \
--output-dir artifacts/inference_vis
Benchmark wideo¶
Do lokalnego pomiaru predkosci inferencji na CPU/GPU sluzy:
.venv/bin/python scripts/benchmark_video.py \
--config configs/bdd_vehicle3/resnet50_lr1e4.yaml \
--checkpoint artifacts/remote/custom/artifacts/bdd_vehicle3_resnet50_overfit64_512_200e.pt \
--input-video artifacts/videos/input.mp4 \
--device cpu \
--max-frames 100 \
--warmup-frames 5 \
--threads 4 \
--summary artifacts/video_benchmarks/run.json
Opcjonalnie mozna zapisac krotki podglad z bboxami:
.venv/bin/python scripts/benchmark_video.py \
--config configs/bdd_vehicle3/resnet50_lr1e4.yaml \
--checkpoint artifacts/remote/custom/artifacts/bdd_vehicle3_resnet50_overfit64_512_200e.pt \
--input-video artifacts/videos/input.mp4 \
--output-video artifacts/videos/preview.mp4 \
--device cpu \
--max-frames 30 \
--frame-stride 5 \
--set data.image_size=512
Skrypt wymaga lokalnych binarek ffmpeg i ffprobe. Nie wymaga opencv.
Filmy z YouTube nalezy pobierac tylko wtedy, gdy material mozna legalnie wykorzystac. Pomocniczo mozna uzyc lokalnie zainstalowanego yt-dlp:
.venv/bin/python -m yt_dlp -f "bv*[height<=480]+ba/b[height<=480]/best[height<=480]/worst" \
--merge-output-format mp4 \
-o "artifacts/videos/input.%(ext)s" \
"https://www.youtube.com/watch?v=..."
Benchmark TensorRT na Jetsonie¶
Do pomiaru surowej wydajnosci engine'a TensorRT na Jetsonie sluza:
scripts/jetson_tensorrt_benchmark.sh
scripts/benchmark_tensorrt_engine.py
Pierwszy skrypt uruchamia kontener z obrazem camera-worker, konwertuje ONNX przez trtexec, zapisuje .engine, log trtexec i odpala drugi skrypt. Drugi skrypt mierzy juz gotowy engine przez TensorRT Python API + CuPy.
Przyklad dla modelu openimages_traffic5_raw umieszczonego w /data/test_model na Jetsonie:
cd /data/test_model
IMAGE=10.10.0.1:5000/camera-worker:latest-jetson \
./scripts/jetson_tensorrt_benchmark.sh easy_rtdetr_openimages_traffic5_raw.onnx
Domyslne parametry:
- input tensor:
images - input shape:
1x3x640x640 - precyzja:
fp16 - warmup
trtexec:1000 ms - benchmark
trtexec:30 s - benchmark Python API:
50warmup iterations +500measured iterations
W przypadku ONNX z external data obok pliku .onnx musi lezec rowniez plik .onnx.data, np.:
easy_rtdetr_openimages_traffic5_raw.onnx
easy_rtdetr_openimages_traffic5_raw.onnx.data
Ten benchmark mierzy sam model/engine. Nie obejmuje RTSP, dekodowania, letterbox/resize, postprocessingu, rysowania bboxow ani WebRTC.
Przygotowanie datasetow¶
Do konwersji datasetow sluzy:
.venv/bin/python scripts/prepare_dataset.py --dataset vehicles3
Aktualnie istotny wariant to vehicles3, czyli Roboflow vehicles v2 release zmapowany do trzech klas:
carbustruck
Po konwersji root datasetu to:
data/vehicles3
Config treningowy:
configs/vehicles3/resnet50.yaml
Alternatywny, szerszy wariant dla generalizacji to openimages_traffic4, czyli podzbior Open Images z klasami:
personcarbustruck
Przyklad przygotowania limitowanego subsetu:
.venv/bin/python scripts/prepare_dataset.py \
--dataset openimages_traffic4 \
--raw-root data/openimages_raw \
--output-root data/openimages_traffic4 \
--max-train-samples-per-class 2000 \
--max-val-samples-per-class 500 \
--min-area-ratio 0.0005 \
--download-workers 16
Config treningowy:
configs/openimages_traffic4/hgnetv2_b0.yaml
Kalibracja score¶
Model zwraca surowe score po sigmoid, ale repo zawiera tez prosty etap kalibracji precision:
.venv/bin/python scripts/calibrate.py \
--config configs/voc_car/base.yaml \
--checkpoint runs/voc_car/.../checkpoints/best.pt \
--output artifacts/voc_calibration.json
To jest przydatne do wizualizacji typu:
raw=...p=...
gdzie p jest empiryczna precyzja oszacowana na zbiorze ewaluacyjnym.
Co robi solver¶
Wspolny solver obsluguje:
- train loop,
- eval loop,
- checkpointing
best/last, - AMP,
- DDP przy uruchomieniu przez
torchrun, - gradient clipping,
- scheduler learning rate,
- warmup,
- EMA wag modelu,
- logowanie i prosty profiling.
Przy AMP solver zapisuje w metrykach optimizer_steps. To jest wazne dla krotkich smoke testow: jesli optimizer_steps=0, pipeline mogl przejsc poprawnie, ale wagi nie zostaly zaktualizowane, bo GradScaler odrzucil kroki optymalizatora.
Gdy solver.use_ema=true, solver ewaluuje teraz dwa warianty modelu:
- EMA jako wariant glowny, zapisywany w metrykach bez prefiksu i uzywany do wyboru
best.pt, - raw model jako diagnostyka, zapisywany z prefiksem
raw_, np.raw_AP50.
Dzieki temu w krotkich i srednich treningach widac, czy EMA dogania raw model. Dla krotkich runow praktyczniejsze jest ema_decay=0.999; 0.9999 jest sensowne dopiero przy dluzszych treningach, bo EMA aktualizuje sie wtedy bardzo wolno.
Po poprawce DFL w auxiliary dense head dodano test regresyjny na broadcasting wag:
tests/test_engine_utils.py::test_auxiliary_dense_dfl_loss_does_not_broadcast_weights
Jesli po kolejnych zmianach training loss znowu zacznie byc nienaturalnie wysoki, ten test jest pierwszym miejscem do sprawdzenia.
Struktura wynikow¶
Kazdy run tworzy katalog z:
checkpoints/best.ptcheckpoints/last.ptmetrics.jsonconfig_resolved.yamltrain.log
To upraszcza porownywanie eksperymentow i integracje ze zdalnym runnerem.
Zdalny runner¶
scripts/run_remote.py nie powinien byc traktowany jako rsync calego repo. Domyslnie wysyla tylko minimalna allowliste potrzebna do treningu:
easy_rtdetr/configs/scripts/pyproject.tomlREADME.md
Przed startem zdalnego kodu wypisywane sa sync_files i sync_size_mb. Jezeli te wartosci sa duze, nalezy sprawdzic --sync-path i wykluczenia, zanim uruchomi sie dlugi trening.
Dwie karty GPU na Kaggle wlacza sie przez --nproc-per-node 2, co po stronie zdalnej uruchamia torchrun i powinno dac w logu distributed=True world_size=2.
Import wag backbone'u z Paddle¶
Repo zawiera tez utility do importu wag PPHGNetV2 z .pdparams. Wspierane warianty: S (wlasny duzy wariant) oraz B0 (kompatybilny z PaddleClas):
.venv/bin/python scripts/import_hgnetv2.py \
--source /path/to/PPHGNetV2_B0_ssld_stage1_pretrained.pdparams \
--output artifacts/hgnetv2_b0_pretrained.pt \
--arch B0
Tak zapisany checkpoint mozna potem podac przez:
model.backbone_name=hgnetv2_b0(lubhgnetv2_sdla wariantu duzego),model.backbone_pretrained_path=artifacts/hgnetv2_b0_pretrained.pt.
Pretrenowane wagi dla B0 sa dostepne publicznie na PaddleClas (Apache 2.0). Wariant S w naszym repo nie ma bezposrednio pasujacych wag - jego startup byl od zera.
Gradient accumulation¶
Solver przyjmuje solver.grad_accum_steps (default 1). Przy grad_accum_steps=N:
- forward + backward jest robiony co krok,
- optimizer step jest robiony co
Nkrokow lub na ostatnim batchu epoki, lossjest skalowany przez1/Nprzed backward, zeby zachowac semantyke wielkiego batcha,- przy DDP
model.no_sync()jest uzywane na niepelnych krokach zeby uniknac zbyt czestych all-reduce.
Uzywaj grad_accum_steps=2..4 gdy nie miescisz batcha w pamieci GPU. Przyklad - przy P2 na T4: batch_size: 2 + grad_accum_steps: 2 daje efektywny batch 4 per GPU.