Zdalny Trening GPU¶
Projekt ma gotowy przeplyw uruchamiania skryptow na zdalnym Jupyter/Kaggle GPU przez pyrun-jupyter.
Aktualny mechanizm¶
Wykorzystywane sa:
pyrun-jupyterdo wykonywania kodu na zdalnym kernelu Jupyter,scripts/run_remote.pyjako lokalny runner,scripts/remote_dispatch.pyjako entrypoint po stronie zdalnej,scripts/train.pyi YAML configi jako glowny workflow treningowy,- opcjonalnie MinIO jako storage bridge dla datasetow i artefaktow.
Runner nie wysyla calego repo. Domyslny upload jest allowlista:
easy_rtdetr/configs/scripts/pyproject.tomlREADME.md
Celowo pomijane sa katalogi robocze i duze dane:
.venv/data/artifacts/runs/.cache/.exp/site/.git/
Przed wlasciwym uruchomieniem runner wypisuje:
sync_paths=...sync_files=...sync_size_mb=...sync_uploaded=...
To jest najprostszy sanity-check. Dla normalnego treningu kodu projektu upload powinien byc maly. Ostatni smoke dla HGNet-V2-S wysylal 50 plikow i okolo 0.24 MB.
Przy dodaniu nowych configow liczba plikow moze minimalnie wzrosnac. Bieg BDD vehicle-3 + HGNet-V2-S wysylal 51 plikow i nadal okolo 0.24 MB.
Kaggle z dwiema kartami T4¶
Kaggle potrafi udostepnic dwie karty Tesla T4. Zwykly trening --device cuda uzywa jednego procesu, czyli praktycznie jednej karty. Aby uzyc obu kart, uruchom runner z:
.venv/bin/python scripts/run_remote.py custom \
--device cuda \
--nproc-per-node 2 \
--script scripts/train.py \
-- --config configs/synthetic/hgnetv2_s.yaml
--nproc-per-node 2 powoduje, ze scripts/remote_dispatch.py uruchamia zdalnie:
torchrun --standalone --nproc_per_node=2 scripts/train.py ...
Po poprawnym starcie log treningu powinien zawierac:
distributed=True world_size=2
To oznacza, ze trening idzie przez DDP na dwoch procesach. Przy CUDA kazdy proces dostaje swoj LOCAL_RANK i odpowiednia karte.
Przyklad smoke na Kaggle¶
Minimalny test HGNet-V2-S na synthetic dataset:
.venv/bin/python scripts/run_remote.py custom \
--device cuda \
--nproc-per-node 2 \
--upload-chunk-kb 512 \
--artifact artifacts/synthetic_hgnetv2_s_ddp_remote.pt \
--script scripts/train.py \
-- \
--config configs/synthetic/hgnetv2_s.yaml \
--output artifacts/synthetic_hgnetv2_s_ddp_remote.pt \
--set solver.epochs=1 \
--set data.train_samples=8 \
--set data.eval_samples=2 \
--set solver.batch_size=2 \
--set runtime.amp=true \
--set runtime.output_dir=runs/synthetic_hgnetv2_s_ddp_remote
Oczekiwane sygnaly poprawnego smoke:
sync_size_mbjest male, rzedu pojedynczych MB lub mniej,- log pokazuje
distributed=True world_size=2, - log pokazuje
checkpoint_saved=..., - lokalnie pojawia sie pobrany checkpoint w
artifacts/remote/..., optimizer_stepsjest wieksze od0, jezeli test ma potwierdzic realna aktualizacje wag.
Jesli optimizer_steps=0, to sam pipeline mogl przejsc, ale AMP GradScaler odrzucil wszystkie kroki optymalizatora. Dla prawdziwego treningu trzeba wtedy zmniejszyc runtime.amp_init_scale, wylaczyc AMP albo sprawdzic stabilnosc lossow.
MinIO dla datasetow i artefaktow¶
Przy wiekszych datasetach synchronizacja przez websocket jest niepraktyczna:
- wolna,
- podatna na zrywanie transferu,
- zbyt ciezka dla calych katalogow datasetow.
Dlatego duze datasety powinny isc przez MinIO:
- lokalny dataset jest stage'owany do MinIO,
- generowany jest presigned URL,
- zdalny kernel pobiera archive bezposrednio do
data/, - po treningu checkpoint moze wrocic przez MinIO lub przez standardowy download artefaktow.
Przyklad:
.venv/bin/python scripts/run_remote.py train-voc-car \
--device cuda \
--minio-endpoint http://188.245.77.217:9000 \
--minio-access-key admin \
--minio-secret-key '***' \
-- --set solver.epochs=5 --set solver.batch_size=4
Ustawienia MinIO mozna trzymac w scripts/.env:
MINIO_ENDPOINTMINIO_ACCESS_KEYMINIO_SECRET_KEYMINIO_BUCKET
URL do Kaggle/Jupyter tez moze byc w scripts/.env jako:
KAGGLE_PROXY_URLPYRUN_JUPYTER_URL
Aktualnie aktywny dataset roboczy w MinIO to vehicles3:
datasets/vehicles3/roboflow-v2-release/vehicles3-roboflow-v2-release.tar.gz
Jest to przetworzony Roboflow vehicles v2 release z klasami:
carbustruck
Oczekiwany root po rozpakowaniu:
data/vehicles3
SHA256 archiwum:
df67861809359786237779affa2fe3f0334ab48f855494922199c9c3a065be56
Przy uzyciu gotowego obiektu MinIO trzeba podac oczekiwany root po rozpakowaniu. Bez --dataset-expected-root runner inferuje root z nazwy archiwum, co przy nazwach wersjonowanych moze dac zly path.
Przyklad treningu vehicles3 na dwoch T4:
.venv/bin/python scripts/run_remote.py custom \
--device cuda \
--nproc-per-node 2 \
--timeout 7200 \
--dataset-source .exp/cache/datasets/vehicles3-roboflow-v2-release.tar.gz \
--dataset-object-name datasets/vehicles3/roboflow-v2-release/vehicles3-roboflow-v2-release.tar.gz \
--dataset-expected-root data/vehicles3 \
--artifact artifacts/vehicles3_resnet50.pt \
--script scripts/train.py \
-- \
--config configs/vehicles3/resnet50.yaml \
--output artifacts/vehicles3_resnet50.pt \
--set solver.epochs=5 \
--set runtime.output_dir=runs/vehicles3_resnet50
Wazna obserwacja praktyczna: MinIO pozwala nie wysylac datasetu przez websocket, ale Kaggle nie zawsze zachowuje lokalny katalog data/ miedzy sesjami. To znaczy, ze ten sam obiekt MinIO jest reuse'owany jako zrodlo, ale zdalny kernel moze pobrac i rozpakowac archiwum ponownie w nowej sesji.
Historyczny dataset BDD vehicle-3 byl trzymany pod:
datasets/bdd100k_vehicle3/trainval90-seed0/bdd100k_vehicle3-trainval90-seed0.tar.gz
Historyczny subset COCO traffic-5 byl trzymany pod:
datasets/coco_traffic5/5k1k-seed0-area0002/coco_traffic5-5k1k-seed0-area0002.tar.gz
Te dwa obiekty zostaly usuniete z MinIO 2026-05-10, zeby zwolnic miejsce. Ich configi i historia eksperymentow zostaja w repo jako dokumentacja, ale nie nalezy zakladac, ze dane nadal sa dostepne w storage.
Dostepne presety¶
Runner ma przygotowane presety:
train-pennfudantrain-syntheticeval-pennfudanvisualize-pennfudantrain-voc-careval-voc-carvisualize-voc-carcustom --script path/to/script.py
Presety sa cienka warstwa nad wspolnymi wrapperami:
scripts/train.pyscripts/eval.pyscripts/visualize.py
Inputy poza datasetem (--remote-input-object)¶
Czasami trening wymaga dodatkowych plikow oprocz datasetu - np. pretrenowane wagi backbone'u. Runner ma do tego flag --remote-input-object OBJECT=DEST:
--remote-input-object pretrained/hgnetv2_b0_ssld_stage1.pt=artifacts/hgnetv2_b0_pretrained.pt
Format: OBJECT_NAME_W_MINIO=DEST_PATH_NA_KAGGLE. Plik musi byc juz wgrany do MinIO przed uruchomieniem. Mozna podac flag wielokrotnie.
Konwencja: artifacts/ jest excludowane z domyslnego sync, wiec wszystko wieksze powinno isc przez MinIO + --remote-input-object, a nie przez websocket upload.
Fragmentacja pamieci GPU¶
scripts/remote_dispatch.py ustawia teraz domyslnie:
os.environ.setdefault("PYTORCH_CUDA_ALLOC_CONF", "expandable_segments:True")
To pomaga gdy PyTorch ma duzo reserved-but-unallocated pamieci przez fragmentacje (typowy objaw przy zmiennych ksztaltach lub mocnych zmianach memory pressure miedzy stepami). Nigdy nie szkodzi, czasem ratuje przed OOM bez zmiany batcha.
Typowe ostrzezenia¶
Nie kazde ostrzezenie z Kaggle oznacza blad treningu:
hostname of the client socket cannot be retrievedzwykle jest ostrzezeniem srodowiska Kaggle/c10d i nie blokuje DDP.padding='same'... zero-padded copypochodzi z konwolucji i jest ostrzezeniem wydajnosciowym.Grad strides do not match bucket view stridesmoze obnizac wydajnosc DDP, ale nie jest bledem funkcjonalnym.scheduler_step_skipped=no_optimizer_stepoznacza, ze w danej epoce nie bylo realnego kroku optymalizatora, najczesciej przez AMP overflow w bardzo krotkim smoke tescie.
Co wymaga dyscypliny¶
- Nie dodawac przez
--sync-pathduzych katalogow typu.venv,data,artifacts,runs. - Dla duzych danych uzywac MinIO, a nie websocket uploadu przez kernel.
- Po duzej zmianie architektury traktowac stare checkpointy jako niekompatybilne.
- Przy dluzszych biegach ustawic kontrolowany
runtime.output_diri--artifact-dir. - Dla treningu na dwoch T4 sprawdzac w logu
world_size=2, a nie tylkodevice=cuda.