gpuhire 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gpuhire-0.2.0/.gitignore +64 -0
- gpuhire-0.2.0/CHANGELOG.md +156 -0
- gpuhire-0.2.0/LICENSE +21 -0
- gpuhire-0.2.0/PKG-INFO +247 -0
- gpuhire-0.2.0/README.md +182 -0
- gpuhire-0.2.0/docs/config/README.md +37 -0
- gpuhire-0.2.0/docs/config/r2.example.json +6 -0
- gpuhire-0.2.0/docs/contract.md +243 -0
- gpuhire-0.2.0/docs/nyshporka.md +125 -0
- gpuhire-0.2.0/examples/fetch_and_verify.py +95 -0
- gpuhire-0.2.0/examples/paddleocr_kaggle.py +96 -0
- gpuhire-0.2.0/examples/paddleocr_modal.py +107 -0
- gpuhire-0.2.0/examples/pull_volume.py +40 -0
- gpuhire-0.2.0/pyproject.toml +193 -0
- gpuhire-0.2.0/src/gpurunner/__init__.py +3 -0
- gpuhire-0.2.0/src/gpurunner/__main__.py +11 -0
- gpuhire-0.2.0/src/gpurunner/_embedded/__init__.py +0 -0
- gpuhire-0.2.0/src/gpurunner/_embedded/_common.py +71 -0
- gpuhire-0.2.0/src/gpurunner/_embedded/churro_runner.py +537 -0
- gpuhire-0.2.0/src/gpurunner/_embedded/dino_surname_verifier_runner.py +988 -0
- gpuhire-0.2.0/src/gpurunner/_embedded/htr_case_runner.py +2690 -0
- gpuhire-0.2.0/src/gpurunner/_embedded/htr_eval_runner.py +194 -0
- gpuhire-0.2.0/src/gpurunner/_embedded/htr_lines_eval_runner.py +299 -0
- gpuhire-0.2.0/src/gpurunner/_embedded/htr_page_bench_runner.py +169 -0
- gpuhire-0.2.0/src/gpurunner/_embedded/kraken_lines_runner.py +136 -0
- gpuhire-0.2.0/src/gpurunner/_embedded/kraken_train_runner.py +385 -0
- gpuhire-0.2.0/src/gpurunner/_embedded/paddle_page_bench_runner.py +98 -0
- gpuhire-0.2.0/src/gpurunner/_embedded/paddleocr_runner.py +343 -0
- gpuhire-0.2.0/src/gpurunner/_embedded/parseq_train_runner.py +1328 -0
- gpuhire-0.2.0/src/gpurunner/_embedded/rukopys_ocr_runner.py +574 -0
- gpuhire-0.2.0/src/gpurunner/_embedded/spotter_page_bench_runner.py +155 -0
- gpuhire-0.2.0/src/gpurunner/_embedded/trocr_lines_runner.py +177 -0
- gpuhire-0.2.0/src/gpurunner/_embedded/vit_classifier_modal_runner.py +412 -0
- gpuhire-0.2.0/src/gpurunner/_embedded/vit_classifier_runner.py +443 -0
- gpuhire-0.2.0/src/gpurunner/_embedded/yolo_spotter_modal_runner.py +1154 -0
- gpuhire-0.2.0/src/gpurunner/auth/__init__.py +5 -0
- gpuhire-0.2.0/src/gpurunner/auth/beam.py +171 -0
- gpuhire-0.2.0/src/gpurunner/auth/google.py +194 -0
- gpuhire-0.2.0/src/gpurunner/auth/kaggle.py +96 -0
- gpuhire-0.2.0/src/gpurunner/auth/lightning.py +227 -0
- gpuhire-0.2.0/src/gpurunner/auth/modal.py +27 -0
- gpuhire-0.2.0/src/gpurunner/auth/saturn.py +148 -0
- gpuhire-0.2.0/src/gpurunner/auth/vast.py +257 -0
- gpuhire-0.2.0/src/gpurunner/backends/__init__.py +49 -0
- gpuhire-0.2.0/src/gpurunner/backends/beam.py +1041 -0
- gpuhire-0.2.0/src/gpurunner/backends/colab.py +797 -0
- gpuhire-0.2.0/src/gpurunner/backends/kaggle.py +622 -0
- gpuhire-0.2.0/src/gpurunner/backends/lightning.py +805 -0
- gpuhire-0.2.0/src/gpurunner/backends/modal.py +652 -0
- gpuhire-0.2.0/src/gpurunner/backends/saturn.py +806 -0
- gpuhire-0.2.0/src/gpurunner/backends/vast.py +2313 -0
- gpuhire-0.2.0/src/gpurunner/cli.py +3153 -0
- gpuhire-0.2.0/src/gpurunner/config.py +74 -0
- gpuhire-0.2.0/src/gpurunner/core/__init__.py +16 -0
- gpuhire-0.2.0/src/gpurunner/core/backend.py +90 -0
- gpuhire-0.2.0/src/gpurunner/core/balances.py +359 -0
- gpuhire-0.2.0/src/gpurunner/core/boxes.py +712 -0
- gpuhire-0.2.0/src/gpurunner/core/budget.py +193 -0
- gpuhire-0.2.0/src/gpurunner/core/contract.py +81 -0
- gpuhire-0.2.0/src/gpurunner/core/gpu_equiv.py +226 -0
- gpuhire-0.2.0/src/gpurunner/core/htr_sizing.py +517 -0
- gpuhire-0.2.0/src/gpurunner/core/inputs.py +50 -0
- gpuhire-0.2.0/src/gpurunner/core/job.py +272 -0
- gpuhire-0.2.0/src/gpurunner/core/locks.py +214 -0
- gpuhire-0.2.0/src/gpurunner/core/manifest.py +380 -0
- gpuhire-0.2.0/src/gpurunner/core/models.py +109 -0
- gpuhire-0.2.0/src/gpurunner/core/offer_score.py +532 -0
- gpuhire-0.2.0/src/gpurunner/core/quota.py +583 -0
- gpuhire-0.2.0/src/gpurunner/core/usage.py +260 -0
- gpuhire-0.2.0/src/gpurunner/htr/__init__.py +11 -0
- gpuhire-0.2.0/src/gpurunner/htr/box_transport.py +204 -0
- gpuhire-0.2.0/src/gpurunner/htr/calibrate.py +219 -0
- gpuhire-0.2.0/src/gpurunner/htr/fetch_ckpt.py +254 -0
- gpuhire-0.2.0/src/gpurunner/htr/origin.py +217 -0
- gpuhire-0.2.0/src/gpurunner/htr/plan_build.py +568 -0
- gpuhire-0.2.0/src/gpurunner/htr/preflight.py +190 -0
- gpuhire-0.2.0/src/gpurunner/htr/r2.py +277 -0
- gpuhire-0.2.0/src/gpurunner/jobs/__init__.py +94 -0
- gpuhire-0.2.0/src/gpurunner/jobs/_net_probe.py +89 -0
- gpuhire-0.2.0/src/gpurunner/jobs/churro.py +94 -0
- gpuhire-0.2.0/src/gpurunner/jobs/crop_verifier.py +40 -0
- gpuhire-0.2.0/src/gpurunner/jobs/dino_surname_verifier.py +156 -0
- gpuhire-0.2.0/src/gpurunner/jobs/htr_case.py +426 -0
- gpuhire-0.2.0/src/gpurunner/jobs/htr_eval.py +115 -0
- gpuhire-0.2.0/src/gpurunner/jobs/htr_lines_eval.py +81 -0
- gpuhire-0.2.0/src/gpurunner/jobs/htr_page_bench.py +86 -0
- gpuhire-0.2.0/src/gpurunner/jobs/kraken_lines.py +70 -0
- gpuhire-0.2.0/src/gpurunner/jobs/kraken_train.py +170 -0
- gpuhire-0.2.0/src/gpurunner/jobs/paddle_page_bench.py +76 -0
- gpuhire-0.2.0/src/gpurunner/jobs/paddleocr.py +258 -0
- gpuhire-0.2.0/src/gpurunner/jobs/parseq_train.py +401 -0
- gpuhire-0.2.0/src/gpurunner/jobs/rukopys_ocr.py +78 -0
- gpuhire-0.2.0/src/gpurunner/jobs/spotter_page_bench.py +83 -0
- gpuhire-0.2.0/src/gpurunner/jobs/trocr_lines.py +77 -0
- gpuhire-0.2.0/src/gpurunner/jobs/vit_classifier.py +187 -0
- gpuhire-0.2.0/src/gpurunner/jobs/yolo_spotter.py +427 -0
- gpuhire-0.2.0/src/gpurunner/plugins/__init__.py +6 -0
- gpuhire-0.2.0/src/gpurunner/plugins/nyshporka_cloud.py +802 -0
- gpuhire-0.2.0/src/gpurunner/supervise/__init__.py +1 -0
- gpuhire-0.2.0/src/gpurunner/supervise/append.py +96 -0
- gpuhire-0.2.0/src/gpurunner/supervise/bg.py +181 -0
- gpuhire-0.2.0/src/gpurunner/supervise/decide.py +601 -0
- gpuhire-0.2.0/src/gpurunner/supervise/detach.py +312 -0
- gpuhire-0.2.0/src/gpurunner/supervise/gate.py +399 -0
- gpuhire-0.2.0/src/gpurunner/supervise/htr.py +3369 -0
- gpuhire-0.2.0/src/gpurunner/supervise/plan.py +404 -0
- gpuhire-0.2.0/src/gpurunner/supervise/state.py +437 -0
- gpuhire-0.2.0/src/gpurunner/supervise/verify.py +173 -0
- gpuhire-0.2.0/src/gpurunner/supervise/wrapup.py +65 -0
- gpuhire-0.2.0/src/gpurunner/web/__init__.py +15 -0
- gpuhire-0.2.0/src/gpurunner/web/app.py +305 -0
- gpuhire-0.2.0/src/gpurunner/web/static/index.html +809 -0
- gpuhire-0.2.0/tests/__init__.py +0 -0
- gpuhire-0.2.0/tests/conftest.py +116 -0
- gpuhire-0.2.0/tests/test_append_supervisor_side.py +159 -0
- gpuhire-0.2.0/tests/test_append_work_to_live_box.py +169 -0
- gpuhire-0.2.0/tests/test_balance.py +214 -0
- gpuhire-0.2.0/tests/test_beam_backend.py +553 -0
- gpuhire-0.2.0/tests/test_bg.py +92 -0
- gpuhire-0.2.0/tests/test_billing_visibility.py +68 -0
- gpuhire-0.2.0/tests/test_boot_progress.py +112 -0
- gpuhire-0.2.0/tests/test_boxes_registry.py +400 -0
- gpuhire-0.2.0/tests/test_cli_json_contract.py +103 -0
- gpuhire-0.2.0/tests/test_cli_squeeze.py +20 -0
- gpuhire-0.2.0/tests/test_colab_backend.py +487 -0
- gpuhire-0.2.0/tests/test_completeness_gate.py +248 -0
- gpuhire-0.2.0/tests/test_core.py +101 -0
- gpuhire-0.2.0/tests/test_double_start_and_honest_state.py +169 -0
- gpuhire-0.2.0/tests/test_dynamic_pages_reach_the_box.py +83 -0
- gpuhire-0.2.0/tests/test_fetch_layout.py +107 -0
- gpuhire-0.2.0/tests/test_fleet_regulator.py +468 -0
- gpuhire-0.2.0/tests/test_gpu_equiv.py +116 -0
- gpuhire-0.2.0/tests/test_htr_box_transport.py +493 -0
- gpuhire-0.2.0/tests/test_htr_calibrate.py +100 -0
- gpuhire-0.2.0/tests/test_htr_fetch_ckpt.py +172 -0
- gpuhire-0.2.0/tests/test_htr_origin.py +130 -0
- gpuhire-0.2.0/tests/test_htr_plan.py +350 -0
- gpuhire-0.2.0/tests/test_htr_r2.py +104 -0
- gpuhire-0.2.0/tests/test_htr_sizing.py +540 -0
- gpuhire-0.2.0/tests/test_htr_sizing_vram.py +122 -0
- gpuhire-0.2.0/tests/test_kaggle_backend.py +284 -0
- gpuhire-0.2.0/tests/test_kraken_train_job.py +89 -0
- gpuhire-0.2.0/tests/test_lightning_backend.py +387 -0
- gpuhire-0.2.0/tests/test_locks.py +122 -0
- gpuhire-0.2.0/tests/test_manifest_store.py +212 -0
- gpuhire-0.2.0/tests/test_material_travels_to_the_registry.py +108 -0
- gpuhire-0.2.0/tests/test_modal_backend.py +443 -0
- gpuhire-0.2.0/tests/test_no_self_killing_patterns.py +85 -0
- gpuhire-0.2.0/tests/test_nyshporka_plugin.py +485 -0
- gpuhire-0.2.0/tests/test_offer_score.py +456 -0
- gpuhire-0.2.0/tests/test_paddleocr_job.py +135 -0
- gpuhire-0.2.0/tests/test_parallel_sessions.py +353 -0
- gpuhire-0.2.0/tests/test_params_quoting.py +68 -0
- gpuhire-0.2.0/tests/test_parseq_train_job.py +164 -0
- gpuhire-0.2.0/tests/test_plan_loading.py +94 -0
- gpuhire-0.2.0/tests/test_post_fetch_and_dry_run_json.py +97 -0
- gpuhire-0.2.0/tests/test_probe_net_rc.py +29 -0
- gpuhire-0.2.0/tests/test_queue_isolation.py +148 -0
- gpuhire-0.2.0/tests/test_queue_prefetch.py +294 -0
- gpuhire-0.2.0/tests/test_quota.py +267 -0
- gpuhire-0.2.0/tests/test_release_notes.py +50 -0
- gpuhire-0.2.0/tests/test_render_all_jobs.py +141 -0
- gpuhire-0.2.0/tests/test_saturn_backend.py +374 -0
- gpuhire-0.2.0/tests/test_scan_private.py +184 -0
- gpuhire-0.2.0/tests/test_sizing_knows_the_material.py +137 -0
- gpuhire-0.2.0/tests/test_sizing_reads_our_quota_not_the_host.py +134 -0
- gpuhire-0.2.0/tests/test_stall_between_cases_and_wasted_rents.py +249 -0
- gpuhire-0.2.0/tests/test_supervise_decide.py +654 -0
- gpuhire-0.2.0/tests/test_supervise_detach.py +254 -0
- gpuhire-0.2.0/tests/test_supervise_flow.py +613 -0
- gpuhire-0.2.0/tests/test_supervise_gate.py +366 -0
- gpuhire-0.2.0/tests/test_supervise_state.py +209 -0
- gpuhire-0.2.0/tests/test_supervisor_honesty.py +549 -0
- gpuhire-0.2.0/tests/test_supervisor_queue_money_and_bans.py +155 -0
- gpuhire-0.2.0/tests/test_sweep.py +268 -0
- gpuhire-0.2.0/tests/test_usage.py +166 -0
- gpuhire-0.2.0/tests/test_vast_backend.py +542 -0
- gpuhire-0.2.0/tests/test_vast_rent_box.py +193 -0
- gpuhire-0.2.0/tests/test_vast_ssh_keygen.py +160 -0
- gpuhire-0.2.0/tests/test_voice_batch_reaches_the_box.py +32 -0
- gpuhire-0.2.0/tests/test_warm_box_and_cold_start.py +164 -0
- gpuhire-0.2.0/tests/test_web_api.py +200 -0
gpuhire-0.2.0/.gitignore
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.egg-info/
|
|
6
|
+
.pytest_cache/
|
|
7
|
+
.ruff_cache/
|
|
8
|
+
.mypy_cache/
|
|
9
|
+
|
|
10
|
+
# Virtualenv
|
|
11
|
+
.venv/
|
|
12
|
+
venv/
|
|
13
|
+
env/
|
|
14
|
+
|
|
15
|
+
# uv
|
|
16
|
+
.uv/
|
|
17
|
+
|
|
18
|
+
# Build
|
|
19
|
+
build/
|
|
20
|
+
dist/
|
|
21
|
+
*.whl
|
|
22
|
+
|
|
23
|
+
# IDE
|
|
24
|
+
.idea/
|
|
25
|
+
.vscode/
|
|
26
|
+
*.swp
|
|
27
|
+
|
|
28
|
+
# OS
|
|
29
|
+
.DS_Store
|
|
30
|
+
Thumbs.db
|
|
31
|
+
|
|
32
|
+
# Project: local scratch
|
|
33
|
+
/tmp/
|
|
34
|
+
/scratch/
|
|
35
|
+
/examples/_out/
|
|
36
|
+
/examples/*_out/
|
|
37
|
+
|
|
38
|
+
# Project: never commit credentials, even if accidentally dropped here
|
|
39
|
+
**/kaggle.json
|
|
40
|
+
**/access_token
|
|
41
|
+
.modal.toml
|
|
42
|
+
.env
|
|
43
|
+
.env.local
|
|
44
|
+
e2e_modal_out/
|
|
45
|
+
e2e_out/
|
|
46
|
+
|
|
47
|
+
# Артефакти прогонів (2026-07-29). `out/<job-id>/` — вивід fetch'а по кожному
|
|
48
|
+
# job'у, `.scratch/` — робочі теки датасетів; і те, й те відтворюване і росте
|
|
49
|
+
# без обмежень (1400+ файлів на момент правила). У git — тільки код.
|
|
50
|
+
/out/
|
|
51
|
+
/.scratch/
|
|
52
|
+
*.log
|
|
53
|
+
to_stop.txt
|
|
54
|
+
|
|
55
|
+
# 🔴 Логи прогонів у корені. Наглядач із 19.08 пише свій лог у data_dir(),
|
|
56
|
+
# але ручні запуски й далі лишають файли тут — а вони накопичуються роками
|
|
57
|
+
# (травневі sweep_v*.log дожили до вересня й не значили вже нічого).
|
|
58
|
+
*.log
|
|
59
|
+
*.err
|
|
60
|
+
/phase.txt
|
|
61
|
+
/to_stop.txt
|
|
62
|
+
|
|
63
|
+
# Реєстр боксів і калібрування — дані користувача, не пакета (див. config.registry_dir)
|
|
64
|
+
/data/
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Журнал змін
|
|
2
|
+
|
|
3
|
+
Формат — [Keep a Changelog](https://keepachangelog.com/uk/1.1.0/), версії —
|
|
4
|
+
[SemVer](https://semver.org/lang/uk/). До 1.0 мінорна версія може міняти
|
|
5
|
+
поведінку; те, що описано в [`docs/contract.md`](docs/contract.md), у межах
|
|
6
|
+
мінорної версії не міняється.
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.2.0] — 2026-09-21
|
|
11
|
+
|
|
12
|
+
Перший публічний випуск. Версія 0.1 жила приватним інструментом одного
|
|
13
|
+
дослідження; нижче — те, що змінилося на шляху до публікації.
|
|
14
|
+
|
|
15
|
+
### Додано
|
|
16
|
+
|
|
17
|
+
- **Доставка без бакета: `htr plan --transport box|auto`.** Хмарний прогін
|
|
18
|
+
доти вимагав свого S3 навіть від того, хто просто орендував машину на
|
|
19
|
+
годину: раннер уміє брати дані лише `curl` по посиланню, а видати таке
|
|
20
|
+
посилання вмів тільки бакет. Тепер його може видати сама машина — кадри й
|
|
21
|
+
ассети кладе туди системний `scp` (7.56 проти 0.48 МБ/с у SFTP paramiko,
|
|
22
|
+
заміряно на орендованому боксі), а на її петлі піднімається крихітний склад
|
|
23
|
+
(`htr/origin.py`, GET/PUT, лише `127.0.0.1`). Раннер не змінюється жодним
|
|
24
|
+
рядком. Доставка йде ПІСЛЯ воріт — інакше кожна забракована машина коштувала
|
|
25
|
+
б заливки; канал хоста до інтернету при цьому не міряється взагалі.
|
|
26
|
+
🔴 Чекпоінти на такій машині гинуть разом із нею, тож наглядач везе їх
|
|
27
|
+
додому кожні п'ять хвилин ПІД ЧАС роботи, а не в кінці. `auto` (дефолт)
|
|
28
|
+
бере бакет, коли він налаштований. Передполіт для `box` перевіряє диск, а не
|
|
29
|
+
мережу: посилань ще не існує, їх видасть машина, якої поки немає.
|
|
30
|
+
- **Машинний вивід `--json` у `run`, `status`, `fetch`.** Останній рядок stdout,
|
|
31
|
+
що починається з `{`, — один JSON-об'єкт зі `schema`; людське з `--json` іде в
|
|
32
|
+
stderr, код виходу той самий, відмова теж відповідає об'єктом. Стан прогону —
|
|
33
|
+
із закритого переліку `queued · running · completed · failed · cancelled ·
|
|
34
|
+
unknown`. Споживачі більше не мусять розбирати текст.
|
|
35
|
+
- **`docs/contract.md`** — на що мають право спиратись програми, які кличуть
|
|
36
|
+
gpurunner: команди й прапорці, форма відповідей, схема `plan.json`, змінні
|
|
37
|
+
оточення.
|
|
38
|
+
- **Плагін оренди для Нишпорки** — entry point `nyshporka.cloud`
|
|
39
|
+
(`gpurunner.plugins.nyshporka_cloud:VastRent`). gpurunner орендує й гасить бокс
|
|
40
|
+
на Vast.ai (скоринг офферів, реєстр боксів, перевірка балансу, незнімна стеля
|
|
41
|
+
ціни), а заливку, прогін і забір Нишпорка веде сама по SSH; R2 не потрібен.
|
|
42
|
+
Понад контракт — `status()`, `login(api_key)`, `estimate(need)`. Опис —
|
|
43
|
+
[`docs/nyshporka.md`](docs/nyshporka.md), форма — `docs/contract.md` §6.
|
|
44
|
+
- Vast: **оренда без job'а** — `VastBackend.rent_box / destroy_box / box_info /
|
|
45
|
+
live_instances`. onstart такого боксу — лише жорсткий таймер самознищення;
|
|
46
|
+
будь-який збій після створення інстансу (зокрема Ctrl+C) гасить його.
|
|
47
|
+
- **SSH-ключ без рук:** `auth.vast.ensure_ssh_key()` генерує пару ed25519 у
|
|
48
|
+
`<config>/vast_ssh/`, коли ключа немає ні в `GPURUNNER_VAST_SSH_KEY`, ні в
|
|
49
|
+
`~/.ssh`. Наявний ключ не перезаписується ніколи; свій має пріоритет.
|
|
50
|
+
- **`gpurunner auth vast --key <КЛЮЧ | ->`** зберігає ключ API у
|
|
51
|
+
`<config>/vast_api_key` (`-` — зі stdin); ключ ніде не друкується.
|
|
52
|
+
- Реєстр боксів: вирок **`slow_run`** (тиждень, бан із двох ударів) — машина
|
|
53
|
+
читала повільніше за прогноз за словами викликача, що орендував без наглядача.
|
|
54
|
+
- Job **`rukopys_ocr`** — сторінкове читання моделлю Rukopys-OCR-4B.
|
|
55
|
+
- Vast: параметр **`min_cuda`** (мінімальна CUDA драйвера хоста).
|
|
56
|
+
- **`tools/scan_private.py`** — ворота проти приватних даних, у pre-commit і CI.
|
|
57
|
+
- `LICENSE` (MIT), `CONTRIBUTING.md`, `SECURITY.md`, extra `all`.
|
|
58
|
+
- CI (Linux 3.11–3.13, Windows 3.12) і реліз за тегом через Trusted Publishing.
|
|
59
|
+
- Наглядач попереджає, коли стартує з порожнім реєстром боксів.
|
|
60
|
+
- `gpurunner htr calibrate` показує медіану окремо по старому й новому раннеру
|
|
61
|
+
та стелю за ядрами як вимір сітки. Саме розрив між раннерами був ранньою
|
|
62
|
+
ознакою того, що модель поїхала, — одне спільне число його ховало.
|
|
63
|
+
- Стан заходу зберігає `pages_this_run` і `wall_sec` кожної справи. Доти
|
|
64
|
+
`pages_done` включав підняте з чекпоінтів, а темп рахувався лише від
|
|
65
|
+
зробленого зараз — і відсіяти відновлені й догінні заходи з калібровки було
|
|
66
|
+
неможливо в принципі.
|
|
67
|
+
- Таблиця ринку показує «ядра» в колонці «що тисне», коли темп ріже саме CPU:
|
|
68
|
+
доти бокс із 20 шардами на 20 ядрах виглядав обмеженим шардами.
|
|
69
|
+
|
|
70
|
+
### Змінено
|
|
71
|
+
|
|
72
|
+
- **Реєстр боксів і калібрування шардів — дані користувача, а не пакета.**
|
|
73
|
+
Адресу дає `GPURUNNER_REPO_DATA_DIR`, без неї — `<тека даних>/registry`. Доти
|
|
74
|
+
реєстр жив у `data/` репозиторію й шукався відносно файла пакета — у
|
|
75
|
+
встановленому колесі ця адреса вказувала в `site-packages`.
|
|
76
|
+
- **Нейтральні імена за замовчуванням:** бакет R2 `gpurunner-htr`, томи Modal
|
|
77
|
+
`gpurunner-htr` і `gpurunner-spotter`. Свої задаються параметром
|
|
78
|
+
`modal_volume`, змінними `GPURUNNER_MODAL_VOLUME[_<JOB>]`, `R2_BUCKET`.
|
|
79
|
+
- `htr_eval`: параметр `target` обов'язковий.
|
|
80
|
+
- `htr fetch-ckpt`: гілка декоду визначається правилом `out` / `out-<тег>`, а
|
|
81
|
+
не зашитим переліком моделей.
|
|
82
|
+
- `requires-python >= 3.11` (було 3.12); версія пакета береться з одного місця.
|
|
83
|
+
- Бекенд Modal відмовляє ще до збирання образу, якщо локальний Python не збігається
|
|
84
|
+
з версією образу (3.12): Modal серіалізує обгортку між інтерпретаторами.
|
|
85
|
+
- Довідка CLI (`--help`) — українською цілком.
|
|
86
|
+
|
|
87
|
+
### Виправлено
|
|
88
|
+
|
|
89
|
+
- `htr plan`: архів кадрів заливався під іменем теки, а посилання вело на ім'я
|
|
90
|
+
прогону — перечитування справи іншою моделлю давало 404 у передпольоті.
|
|
91
|
+
- Після `--json` людський вивід консолі не «прилипає» до потоку попереднього
|
|
92
|
+
виклику.
|
|
93
|
+
- `htr supervise --detach` на macOS: умова вимагала бінарника `setsid`, якого
|
|
94
|
+
відчеплення не потребує (`start_new_session`). На POSIX вивід відчепленого
|
|
95
|
+
процесу тепер іде в `spawn.log`, як на Windows, а не в `/dev/null`.
|
|
96
|
+
- Колесо збирається: `force-include` дублював файли пакета, і `uv build` падав.
|
|
97
|
+
- `mypy src` чистий (було 69 зауважень).
|
|
98
|
+
- **Кошторис занижувався саме на тих машинах, які ми купуємо тепер.** Модель
|
|
99
|
+
темпу множила повний темп шарда на флот, який нема кому годувати: після того
|
|
100
|
+
як 06.09 шард дістав право жити на одному ядрі, заходи пішли по 14–20 шардів
|
|
101
|
+
на 19–23 ядрах — режиму, на якому калібрували, тоді не існувало. Спільна
|
|
102
|
+
медіана прогноз/факт виглядала майже пристойно (1.06), і за нею ховався
|
|
103
|
+
розрив **0.96 на старому раннері проти 1.27 на новому**. Лікує стеля за
|
|
104
|
+
ЯДРАМИ: шард виходить на повний темп приблизно з двох ядер
|
|
105
|
+
(`CORES_PER_SHARD_FULL_RATE = 1.8`), нижче — темп росте з ядрами, а не з
|
|
106
|
+
флотом. Саме число підібране за смугою, де ядер бракує: без стелі вона дає
|
|
107
|
+
1.27, при 1.5 — 1.11 (усе ще завищує), при 2.0 — 0.87 (карає дешеві
|
|
108
|
+
малоядерні бокси — рівно та вада, через яку ворота ціни їх колись
|
|
109
|
+
відкидали). ⚠ Не плутати з тим, скільки ядер шард ЗАЙМАЄ: там близько
|
|
110
|
+
одного, і на 1.5 ядра шард працює — просто дає ~0.8 повного темпу.
|
|
111
|
+
Замір: 113 заходів у смузі «ядер менше двох на шард» дають сталу величину
|
|
112
|
+
рядко-годин на ЯДРО (~20 000), а не на шард; на фіксованому флоті 13–16
|
|
113
|
+
шардів 15 ядер дали 261 536 рядко-год, 19 — 448 416, 27 — 562 297.
|
|
114
|
+
🔴 Це НЕ повернення стелі, знятої 05.09: та була зростаюча й завищувала
|
|
115
|
+
прогноз багатоядерним (525 проти 2000), ця — спадна й ніколи не піднімає
|
|
116
|
+
прогноз вище за флотовий доданок.
|
|
117
|
+
Разом із нею перекалібровано криву за матеріалом (`L0` 29 → 40,
|
|
118
|
+
`A` 33 700 → 36 000). Результат: медіана 0.94 на 457 чистих заходах, обидві
|
|
119
|
+
смуги («ядер менше двох на шард» і решта) сходяться на 0.94, вересневий зріз
|
|
120
|
+
1.19 → 0.95, частка завищень понад 25% — 38% → 28%. Невідомий матеріал прогнозується як і доти (220 стор/год на
|
|
121
|
+
шард), тож жоден старий приймач не зрушив.
|
|
122
|
+
- **Калібровка більше не рахує проби за заходи.** 59 записів із менш ніж 20
|
|
123
|
+
прочитаними сторінками (проби, догони, два записи з нулем сторінок при
|
|
124
|
+
додатному темпі) давали медіану 4.29 і тягли модель угору: вони міряють не
|
|
125
|
+
темп, а фіксовану ціну справи, яку модель рахує окремо.
|
|
126
|
+
|
|
127
|
+
- **Вісім тестів розкладки були зелені на Windows і червоні на Linux.** Вони
|
|
128
|
+
підставляли `os.cpu_count()`, а `_usable_cores()` бере ще й
|
|
129
|
+
`len(os.sched_getaffinity(0))` — виклик, якого на Windows немає взагалі, а в
|
|
130
|
+
CI він повертає справжні два ядра раннера й мовчки затирає підставлене
|
|
131
|
+
число. Спільна фікстура `host_cores` ставить обидва джерела разом і додає
|
|
132
|
+
`sched_getaffinity` там, де його в `os` нема, — тобто гілка прив'язки тепер
|
|
133
|
+
перевіряється й на машині розробника. Сам раннер не міняється: він читав
|
|
134
|
+
ядра правильно, брехали тести.
|
|
135
|
+
|
|
136
|
+
### Відоме про ім'я
|
|
137
|
+
|
|
138
|
+
- ⚠ **На PyPI пакет зветься `gpuhire`**, а команда, модуль і репозиторій —
|
|
139
|
+
`gpurunner`. Ім'я `gpurunner` майданчик не дав узяти: воно надто схоже на
|
|
140
|
+
наявний `gpu-runner` (0.0.7), і захист від typosquatting дивиться не на
|
|
141
|
+
точний збіг. Перейменовувати команду заради цього не стали — вона стоїть у
|
|
142
|
+
документації, у скілах Нишпорки й у змінній `NYSH_GPURUNNER`, а людина в
|
|
143
|
+
терміналі набирає команду, не ім'я колеса.
|
|
144
|
+
|
|
145
|
+
### Прибрано
|
|
146
|
+
|
|
147
|
+
- Залежність `jinja2` і порожній пакет `templates` — не використовувались.
|
|
148
|
+
|
|
149
|
+
### Відомі обмеження
|
|
150
|
+
|
|
151
|
+
- Бібліотечний код друкує через `print`, окремого логера ще немає.
|
|
152
|
+
- Бекенди, що емулюють файлову систему Kaggle, дублюють частину коду.
|
|
153
|
+
- Перелік job'ів ведеться у двох місцях `jobs/__init__.py`.
|
|
154
|
+
- Загальної команди перевірки оточення (`doctor`) немає — лише
|
|
155
|
+
`auth <бекенд> --verify` по одному.
|
|
156
|
+
|
gpuhire-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Serhii Dalishchynskyi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
gpuhire-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: gpuhire
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Один CLI для GPU-задач на Kaggle, Modal, Colab, Vast, Lightning, Beam і Saturn: подати, стежити, забрати, не переплатити
|
|
5
|
+
Project-URL: Homepage, https://github.com/SERGIUSH-UA/gpurunner
|
|
6
|
+
Project-URL: Source, https://github.com/SERGIUSH-UA/gpurunner
|
|
7
|
+
Project-URL: Issues, https://github.com/SERGIUSH-UA/gpurunner/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/SERGIUSH-UA/gpurunner/blob/main/CHANGELOG.md
|
|
9
|
+
Author: Serhii Dalishchynskyi
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: batch,colab,gpu,htr,kaggle,modal,ocr,rental,vast
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Intended Audience :: Science/Research
|
|
17
|
+
Classifier: Natural Language :: Ukrainian
|
|
18
|
+
Classifier: Operating System :: MacOS
|
|
19
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
20
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
24
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
25
|
+
Classifier: Topic :: System :: Distributed Computing
|
|
26
|
+
Requires-Python: >=3.11
|
|
27
|
+
Requires-Dist: httpx>=0.27
|
|
28
|
+
Requires-Dist: kaggle>=1.6
|
|
29
|
+
Requires-Dist: nbformat>=5.10
|
|
30
|
+
Requires-Dist: platformdirs>=4.2
|
|
31
|
+
Requires-Dist: psutil>=5.9
|
|
32
|
+
Requires-Dist: pydantic>=2.6
|
|
33
|
+
Requires-Dist: rich>=13.7
|
|
34
|
+
Requires-Dist: typer>=0.12
|
|
35
|
+
Provides-Extra: all
|
|
36
|
+
Requires-Dist: boto3>=1.34; extra == 'all'
|
|
37
|
+
Requires-Dist: fastapi>=0.115; extra == 'all'
|
|
38
|
+
Requires-Dist: google-api-python-client>=2.130; extra == 'all'
|
|
39
|
+
Requires-Dist: google-auth-oauthlib>=1.2; extra == 'all'
|
|
40
|
+
Requires-Dist: modal>=0.64; extra == 'all'
|
|
41
|
+
Requires-Dist: paramiko>=3.4; extra == 'all'
|
|
42
|
+
Requires-Dist: pillow>=10.0; extra == 'all'
|
|
43
|
+
Requires-Dist: uvicorn>=0.30; extra == 'all'
|
|
44
|
+
Provides-Extra: beam
|
|
45
|
+
Requires-Dist: beam-client>=0.2.200; extra == 'beam'
|
|
46
|
+
Provides-Extra: colab
|
|
47
|
+
Requires-Dist: google-api-python-client>=2.130; extra == 'colab'
|
|
48
|
+
Requires-Dist: google-auth-oauthlib>=1.2; extra == 'colab'
|
|
49
|
+
Provides-Extra: lightning
|
|
50
|
+
Requires-Dist: lightning-sdk>=2026.7; extra == 'lightning'
|
|
51
|
+
Provides-Extra: modal
|
|
52
|
+
Requires-Dist: modal>=0.64; extra == 'modal'
|
|
53
|
+
Provides-Extra: r2
|
|
54
|
+
Requires-Dist: boto3>=1.34; extra == 'r2'
|
|
55
|
+
Requires-Dist: pillow>=10.0; extra == 'r2'
|
|
56
|
+
Provides-Extra: saturn
|
|
57
|
+
Requires-Dist: saturn-client>=2026.2; extra == 'saturn'
|
|
58
|
+
Requires-Dist: saturnfs>=2024.3; extra == 'saturn'
|
|
59
|
+
Provides-Extra: vast
|
|
60
|
+
Requires-Dist: paramiko>=3.4; extra == 'vast'
|
|
61
|
+
Provides-Extra: web
|
|
62
|
+
Requires-Dist: fastapi>=0.115; extra == 'web'
|
|
63
|
+
Requires-Dist: uvicorn>=0.30; extra == 'web'
|
|
64
|
+
Description-Content-Type: text/markdown
|
|
65
|
+
|
|
66
|
+
# gpurunner
|
|
67
|
+
|
|
68
|
+
Один CLI для GPU-задач на чужому залізі: подати, стежити, забрати результат,
|
|
69
|
+
не переплатити. Сім бекендів за одним інтерфейсом — Kaggle, Modal, Google Colab,
|
|
70
|
+
Vast.ai, Lightning, Beam, Saturn Cloud.
|
|
71
|
+
|
|
72
|
+
> **In English.** `gpurunner` is a command-line tool that submits GPU jobs (OCR,
|
|
73
|
+
> handwriting recognition, model training) to Kaggle, Modal, Colab, Vast.ai,
|
|
74
|
+
> Lightning, Beam or Saturn Cloud through one interface, tracks them in a local
|
|
75
|
+
> manifest, fetches outputs and keeps an eye on spending. Documentation and CLI
|
|
76
|
+
> messages are in Ukrainian. It works on its own and also serves as the GPU
|
|
77
|
+
> rental module of [nyshporka](https://github.com/SERGIUSH-UA/nyshporka).
|
|
78
|
+
|
|
79
|
+
Статус: альфа (0.2). Команди й машинний вивід, на які спираються інші програми,
|
|
80
|
+
описано в [`docs/contract.md`](docs/contract.md) і в межах мінорної версії не
|
|
81
|
+
міняються; решта ще рухається.
|
|
82
|
+
|
|
83
|
+
## 1. Навіщо
|
|
84
|
+
|
|
85
|
+
- Той самий job іде на безкоштовну квоту Kaggle, на Modal із посекундним
|
|
86
|
+
білінгом або на орендований бокс Vast — міняється лише `-b`.
|
|
87
|
+
- Кожен прогін лишає запис у локальному маніфесті: що подано, куди, з якими
|
|
88
|
+
параметрами, чим закінчилось і чому впало.
|
|
89
|
+
- Гроші видно до старту: прорахунок вартості, стеля витрат, залишки по бекендах
|
|
90
|
+
(`gpurunner balance`), і що зараз тарифікується (`gpurunner burn`).
|
|
91
|
+
- Для довгих заходів на Vast є наглядач (`gpurunner htr supervise`): орендує
|
|
92
|
+
бокс, стежить за темпом, доганяє пропуски, звіряє повноту й гасить оренду сам.
|
|
93
|
+
- Бакет S3 для цього не обов'язковий: `htr plan --transport box` везе кадри й
|
|
94
|
+
ваги на саму машину по `scp` і піднімає на ній крихітний склад, з якого їх
|
|
95
|
+
бере робота. Чекпоінти наглядач забирає додому сам — машина може вмерти.
|
|
96
|
+
|
|
97
|
+
## 2. Установлення
|
|
98
|
+
|
|
99
|
+
Потрібен Python 3.11+.
|
|
100
|
+
|
|
101
|
+
⚠ На PyPI пакет зветься **`gpuhire`**, а команда в терміналі — `gpurunner`.
|
|
102
|
+
Ім'я `gpurunner` на PyPI зайняте схожим проєктом (`gpu-runner`), і майданчик
|
|
103
|
+
не дав його взяти; перейменовувати команду заради цього не стали.
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
pip install gpuhire # ядро + Kaggle
|
|
107
|
+
pip install "gpuhire[modal]" # + Modal
|
|
108
|
+
pip install "gpuhire[vast,r2]" # + Vast.ai і доставка даних через R2
|
|
109
|
+
pip install "gpuhire[all]" # modal, colab, vast, web, r2
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`lightning`, `beam`, `saturn` ставляться поіменно: їхні SDK важкі й потрібні
|
|
113
|
+
одиницям. Як модуль Нишпорки: `pip install "gpuhire[vast,r2]"` поруч із
|
|
114
|
+
нею — Нишпорка знайде плагін сама.
|
|
115
|
+
|
|
116
|
+
Поруч із Нишпоркою gpurunner стає її **бекендом оренди**: оголошує entry point
|
|
117
|
+
`nyshporka.cloud`, і `nysh cloud` сам орендує бокс на Vast.ai, читає справу по
|
|
118
|
+
SSH, забирає результат і гасить оренду. Від людини — лише ключ API
|
|
119
|
+
(`gpurunner auth vast --key <КЛЮЧ>`) і баланс; SSH-ключ генерується сам, R2 не
|
|
120
|
+
потрібен. Докладно — [`docs/nyshporka.md`](docs/nyshporka.md).
|
|
121
|
+
|
|
122
|
+
З вихідного коду:
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
git clone https://github.com/SERGIUSH-UA/gpurunner && cd gpurunner
|
|
126
|
+
uv sync --extra all
|
|
127
|
+
uv run gpurunner --version
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## 3. Перший прогін
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
gpurunner auth kaggle --verify # обліковка на місці?
|
|
134
|
+
gpurunner ls # які є job'и й бекенди
|
|
135
|
+
gpurunner run net-probe -b kaggle # найдешевша перевірка: чи є в кернелі мережа
|
|
136
|
+
gpurunner watch <handle> # чекати до кінця
|
|
137
|
+
gpurunner fetch <handle> -o out/ # забрати вихід
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
`--dry-run` перевіряє параметри й показує код, який поїде на бекенд, нічого не
|
|
141
|
+
подаючи. Параметри job'а — `-p ключ=значення` (значення розбирається як JSON,
|
|
142
|
+
якщо виходить).
|
|
143
|
+
|
|
144
|
+
🔴 **Vast тарифікує погодинно й не спиняється після завершення job'а.** Після
|
|
145
|
+
`fetch` обов'язково `gpurunner cancel <handle>`; що зараз горить, показує
|
|
146
|
+
`gpurunner burn`.
|
|
147
|
+
|
|
148
|
+
## 4. Бекенди
|
|
149
|
+
|
|
150
|
+
| бекенд | extra | обліковка | особливість |
|
|
151
|
+
|---|---|---|---|
|
|
152
|
+
| `kaggle` | — | `~/.kaggle/kaggle.json` або `KAGGLE_USERNAME` + `KAGGLE_KEY` | безкоштовна тижнева квота; вхід — Kaggle Dataset |
|
|
153
|
+
| `modal` | `modal` | `~/.modal.toml` (`modal token new`) | посекундний білінг; дані — у томі Modal; локальний Python має бути 3.12 — як в образі |
|
|
154
|
+
| `colab` | `colab` | OAuth-клієнт Google у теці конфігурації | нотбук треба запустити руками: Runtime → Run all |
|
|
155
|
+
| `vast` | `vast` | `VAST_API_KEY` або файл `vast_api_key` | оренда боксу по SSH; тарифікація до `cancel` |
|
|
156
|
+
| `lightning` | `lightning` | `LIGHTNING_USER_ID`, `LIGHTNING_API_KEY` | Studio + teamspace |
|
|
157
|
+
| `beam` | `beam` | `BEAM_TOKEN` або `~/.beam/config.ini` | стеля витрат на прогін і на місяць |
|
|
158
|
+
| `saturn` | `saturn` | `SATURN_TOKEN`, `SATURN_BASE_URL` | типи інстансів — `gpurunner saturn sizes` |
|
|
159
|
+
|
|
160
|
+
`gpurunner auth <бекенд>` показує, де шукається обліковка й чого бракує;
|
|
161
|
+
`--verify` робить пробний запит. Тека конфігурації — `%LOCALAPPDATA%\gpurunner`
|
|
162
|
+
(Windows) або `~/.config/gpurunner`; перекривається `GPURUNNER_CONFIG_DIR`.
|
|
163
|
+
Приклади файлів — у [`docs/config/`](docs/config/).
|
|
164
|
+
|
|
165
|
+
## 5. Job'и
|
|
166
|
+
|
|
167
|
+
Перелік з описами й бекендами — `gpurunner ls`; готові набори параметрів із
|
|
168
|
+
прорахунком вартості — `gpurunner recipes <job>`.
|
|
169
|
+
|
|
170
|
+
Загальні:
|
|
171
|
+
|
|
172
|
+
| job | що робить |
|
|
173
|
+
|---|---|
|
|
174
|
+
| `net-probe` | чи є у віддаленому кернелі мережа |
|
|
175
|
+
| `paddleocr` | PaddleOCR PP-OCRv5 по переліку PDF за посиланнями → txt і json по сторінках |
|
|
176
|
+
| `vit_classifier`, `crop_verifier`, `dino_surname_verifier` | дотренування бінарного класифікатора зображень (ViT / DINOv2) і скоринг |
|
|
177
|
+
| `yolo_spotter` | дотренування YOLO на пошук одного рукописного слова |
|
|
178
|
+
| `churro`, `rukopys_ocr` | сторінкове читання історичних документів VLM-моделями |
|
|
179
|
+
| `kraken_lines`, `trocr_lines` | сегментація сторінок на рядки й читання рядків |
|
|
180
|
+
| `kraken_train`, `parseq_train` | трен моделей читання рядків (kraken, PARSeq) |
|
|
181
|
+
| `htr_eval`, `htr_lines_eval`, `htr_page_bench`, `paddle_page_bench`, `spotter_page_bench` | бенчмарки читання рукопису |
|
|
182
|
+
|
|
183
|
+
Потребує пакета `nyshporka`:
|
|
184
|
+
|
|
185
|
+
| job | що робить |
|
|
186
|
+
|---|---|
|
|
187
|
+
| `htr_case` | прогін архівної справи раннером Нишпорки на орендованій карті; раннер і моделі приїжджають архівом ассетів, gpurunner доставляє їх на бокс і стежить |
|
|
188
|
+
|
|
189
|
+
Команди `gpurunner htr …` (план, передполіт, наглядач, забір чекпоінтів,
|
|
190
|
+
калібрування) обслуговують саме `htr_case`.
|
|
191
|
+
|
|
192
|
+
## 6. Команди
|
|
193
|
+
|
|
194
|
+
```
|
|
195
|
+
run · status · watch · logs · fetch · cancel · sweep життєвий цикл прогону
|
|
196
|
+
ls · recipes · balance · burn · reconcile · dash огляд, гроші, звірка
|
|
197
|
+
auth <бекенд> обліковки
|
|
198
|
+
dataset push|files Kaggle-датасети
|
|
199
|
+
drive push|files вхідні дані Colab у Google Drive
|
|
200
|
+
vast offers|instances · saturn sizes ринок і типи машин
|
|
201
|
+
boxes ls|explain|ban|star|prune|forget реєстр орендних боксів
|
|
202
|
+
bg start|status|stop довгі задачі у фоні
|
|
203
|
+
htr plan|preflight|supervise|state|stop|quiesce|fetch-ckpt|calibrate|append
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
`gpurunner <команда> --help` — повний перелік прапорців.
|
|
207
|
+
|
|
208
|
+
## 7. Реєстр боксів
|
|
209
|
+
|
|
210
|
+
Кожна оренда на Vast лишає рядок «обіцяне поруч із виміряним»: яке залізо
|
|
211
|
+
заявив хост і який темп воно дало. З цього складається вердикт машини, і
|
|
212
|
+
наступний пошук оферти погані машини оминає, а добрі шукає адресно.
|
|
213
|
+
|
|
214
|
+
Реєстр — дані користувача, а не пакета: у ньому ідентифікатори машин, ціни й
|
|
215
|
+
назви власних прогонів. Лежить у `GPURUNNER_REPO_DATA_DIR`, без змінної — у
|
|
216
|
+
`<тека даних>/registry`. Змінну варто спрямувати в теку власного
|
|
217
|
+
git-репозиторію: тоді в дифі видно, коли й чому бокс став поганим.
|
|
218
|
+
|
|
219
|
+
## 8. Для програм
|
|
220
|
+
|
|
221
|
+
Інші програми кличуть gpurunner окремим процесом і читають `--json`: останній
|
|
222
|
+
рядок stdout, що починається з `{`, — один об'єкт. Форма відповідей, перелік
|
|
223
|
+
стабільних команд, схема `plan.json` і змінні оточення —
|
|
224
|
+
[`docs/contract.md`](docs/contract.md).
|
|
225
|
+
|
|
226
|
+
Другий шлях — плагін у тому самому інтерпретаторі: клас
|
|
227
|
+
`gpurunner.plugins.nyshporka_cloud:VastRent` (entry point `nyshporka.cloud`)
|
|
228
|
+
орендує й гасить бокс для конвеєра Нишпорки. Методи, форма `Box.meta` і
|
|
229
|
+
необов'язкові `status / login / estimate` — [§6 контракту](docs/contract.md#6-плагін-nyshporkacloud).
|
|
230
|
+
|
|
231
|
+
## 9. Розробка
|
|
232
|
+
|
|
233
|
+
```
|
|
234
|
+
uv sync --extra all
|
|
235
|
+
uv run pytest
|
|
236
|
+
uv run ruff check .
|
|
237
|
+
uv run mypy src
|
|
238
|
+
python tools/scan_private.py # ворота проти приватних даних
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Тести не ходять у мережу й не потребують обліковок. Порядок внесення змін і
|
|
242
|
+
чекліст релізу — [`CONTRIBUTING.md`](CONTRIBUTING.md); про вразливості —
|
|
243
|
+
[`SECURITY.md`](SECURITY.md).
|
|
244
|
+
|
|
245
|
+
## 10. Ліцензія
|
|
246
|
+
|
|
247
|
+
MIT — див. [`LICENSE`](LICENSE).
|