gpuhire 0.2.0__py3-none-any.whl
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.dist-info/METADATA +247 -0
- gpuhire-0.2.0.dist-info/RECORD +103 -0
- gpuhire-0.2.0.dist-info/WHEEL +4 -0
- gpuhire-0.2.0.dist-info/entry_points.txt +5 -0
- gpuhire-0.2.0.dist-info/licenses/LICENSE +21 -0
- gpurunner/__init__.py +3 -0
- gpurunner/__main__.py +11 -0
- gpurunner/_embedded/__init__.py +0 -0
- gpurunner/_embedded/_common.py +71 -0
- gpurunner/_embedded/churro_runner.py +537 -0
- gpurunner/_embedded/dino_surname_verifier_runner.py +988 -0
- gpurunner/_embedded/htr_case_runner.py +2690 -0
- gpurunner/_embedded/htr_eval_runner.py +194 -0
- gpurunner/_embedded/htr_lines_eval_runner.py +299 -0
- gpurunner/_embedded/htr_page_bench_runner.py +169 -0
- gpurunner/_embedded/kraken_lines_runner.py +136 -0
- gpurunner/_embedded/kraken_train_runner.py +385 -0
- gpurunner/_embedded/paddle_page_bench_runner.py +98 -0
- gpurunner/_embedded/paddleocr_runner.py +343 -0
- gpurunner/_embedded/parseq_train_runner.py +1328 -0
- gpurunner/_embedded/rukopys_ocr_runner.py +574 -0
- gpurunner/_embedded/spotter_page_bench_runner.py +155 -0
- gpurunner/_embedded/trocr_lines_runner.py +177 -0
- gpurunner/_embedded/vit_classifier_modal_runner.py +412 -0
- gpurunner/_embedded/vit_classifier_runner.py +443 -0
- gpurunner/_embedded/yolo_spotter_modal_runner.py +1154 -0
- gpurunner/auth/__init__.py +5 -0
- gpurunner/auth/beam.py +171 -0
- gpurunner/auth/google.py +194 -0
- gpurunner/auth/kaggle.py +96 -0
- gpurunner/auth/lightning.py +227 -0
- gpurunner/auth/modal.py +27 -0
- gpurunner/auth/saturn.py +148 -0
- gpurunner/auth/vast.py +257 -0
- gpurunner/backends/__init__.py +49 -0
- gpurunner/backends/beam.py +1041 -0
- gpurunner/backends/colab.py +797 -0
- gpurunner/backends/kaggle.py +622 -0
- gpurunner/backends/lightning.py +805 -0
- gpurunner/backends/modal.py +652 -0
- gpurunner/backends/saturn.py +806 -0
- gpurunner/backends/vast.py +2313 -0
- gpurunner/cli.py +3153 -0
- gpurunner/config.py +74 -0
- gpurunner/core/__init__.py +16 -0
- gpurunner/core/backend.py +90 -0
- gpurunner/core/balances.py +359 -0
- gpurunner/core/boxes.py +712 -0
- gpurunner/core/budget.py +193 -0
- gpurunner/core/contract.py +81 -0
- gpurunner/core/gpu_equiv.py +226 -0
- gpurunner/core/htr_sizing.py +517 -0
- gpurunner/core/inputs.py +50 -0
- gpurunner/core/job.py +272 -0
- gpurunner/core/locks.py +214 -0
- gpurunner/core/manifest.py +380 -0
- gpurunner/core/models.py +109 -0
- gpurunner/core/offer_score.py +532 -0
- gpurunner/core/quota.py +583 -0
- gpurunner/core/usage.py +260 -0
- gpurunner/htr/__init__.py +11 -0
- gpurunner/htr/box_transport.py +204 -0
- gpurunner/htr/calibrate.py +219 -0
- gpurunner/htr/fetch_ckpt.py +254 -0
- gpurunner/htr/origin.py +217 -0
- gpurunner/htr/plan_build.py +568 -0
- gpurunner/htr/preflight.py +190 -0
- gpurunner/htr/r2.py +277 -0
- gpurunner/jobs/__init__.py +94 -0
- gpurunner/jobs/_net_probe.py +89 -0
- gpurunner/jobs/churro.py +94 -0
- gpurunner/jobs/crop_verifier.py +40 -0
- gpurunner/jobs/dino_surname_verifier.py +156 -0
- gpurunner/jobs/htr_case.py +426 -0
- gpurunner/jobs/htr_eval.py +115 -0
- gpurunner/jobs/htr_lines_eval.py +81 -0
- gpurunner/jobs/htr_page_bench.py +86 -0
- gpurunner/jobs/kraken_lines.py +70 -0
- gpurunner/jobs/kraken_train.py +170 -0
- gpurunner/jobs/paddle_page_bench.py +76 -0
- gpurunner/jobs/paddleocr.py +258 -0
- gpurunner/jobs/parseq_train.py +401 -0
- gpurunner/jobs/rukopys_ocr.py +78 -0
- gpurunner/jobs/spotter_page_bench.py +83 -0
- gpurunner/jobs/trocr_lines.py +77 -0
- gpurunner/jobs/vit_classifier.py +187 -0
- gpurunner/jobs/yolo_spotter.py +427 -0
- gpurunner/plugins/__init__.py +6 -0
- gpurunner/plugins/nyshporka_cloud.py +802 -0
- gpurunner/supervise/__init__.py +1 -0
- gpurunner/supervise/append.py +96 -0
- gpurunner/supervise/bg.py +181 -0
- gpurunner/supervise/decide.py +601 -0
- gpurunner/supervise/detach.py +312 -0
- gpurunner/supervise/gate.py +399 -0
- gpurunner/supervise/htr.py +3369 -0
- gpurunner/supervise/plan.py +404 -0
- gpurunner/supervise/state.py +437 -0
- gpurunner/supervise/verify.py +173 -0
- gpurunner/supervise/wrapup.py +65 -0
- gpurunner/web/__init__.py +15 -0
- gpurunner/web/app.py +305 -0
- gpurunner/web/static/index.html +809 -0
|
@@ -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).
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
gpurunner/__init__.py,sha256=QDbH_ktfuajY2_X5yXRyKpR-fsbFQXCq1rEBcc0S0aA,105
|
|
2
|
+
gpurunner/__main__.py,sha256=S-Ex1h2wwgrpw3R3jHJ__Nrgbn4Nrwf_yYGkxA0gxBI,514
|
|
3
|
+
gpurunner/cli.py,sha256=K35TY2AWEN2X4D8BCQeFJZGyJ-1_2NY7UOpaP4vvzLU,154558
|
|
4
|
+
gpurunner/config.py,sha256=iNgkZ5DqgRcbmBDq0dcBiYCT3Ci5jFxLaoPzLagwO5s,3382
|
|
5
|
+
gpurunner/_embedded/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
gpurunner/_embedded/_common.py,sha256=ltgW5rL8w3WuMe82HieOXunWVh8GtOgCTMPGH0ofUUc,4568
|
|
7
|
+
gpurunner/_embedded/churro_runner.py,sha256=66tF9iCJBj6-cKmpP1WLMi0tEIWSfMfvE2EdVc1qibM,29425
|
|
8
|
+
gpurunner/_embedded/dino_surname_verifier_runner.py,sha256=JinTHZjpFqsw-GYfWfvhoCPiP1hJIz4YWk0yhWJ63R0,38705
|
|
9
|
+
gpurunner/_embedded/htr_case_runner.py,sha256=NA4O7e8D3xsVd48se5Zho6ehMvZSDaAyjr3dKPH0LWA,152704
|
|
10
|
+
gpurunner/_embedded/htr_eval_runner.py,sha256=o-zunWFKiiOXr9-qHLFGIhwnV_i2sh7g5VP7upRxrZ8,8850
|
|
11
|
+
gpurunner/_embedded/htr_lines_eval_runner.py,sha256=Qgf6y9XRhAMcwVN1e8vT-PW5TgApwArTpbWnGQ6DNYo,12507
|
|
12
|
+
gpurunner/_embedded/htr_page_bench_runner.py,sha256=ejP-cnsnNhLKA39VQyD1NXvnfLOP-tss3FVmnuFnd84,7541
|
|
13
|
+
gpurunner/_embedded/kraken_lines_runner.py,sha256=CqLMJt2PzM4zQLVUeztz3igk4AZvv7mXdtUierJPQhc,5773
|
|
14
|
+
gpurunner/_embedded/kraken_train_runner.py,sha256=00eH0vCpV7MOZkWiFbNqfcCQ7H8QkIwuxBcvjxdUtNc,22981
|
|
15
|
+
gpurunner/_embedded/paddle_page_bench_runner.py,sha256=zFoiv3EQJ4-lXQ8fqYpvaoiV6NsfnRc3CkmxPhtKajI,4212
|
|
16
|
+
gpurunner/_embedded/paddleocr_runner.py,sha256=r4SatfLrFqsy43zp3IuCjVck44RoVY_crGKjk3vEtsw,12821
|
|
17
|
+
gpurunner/_embedded/parseq_train_runner.py,sha256=TAiVXheTcC5nv2_Om6Qe9jc_rrrUS6RVPSOjxAPD-9c,72502
|
|
18
|
+
gpurunner/_embedded/rukopys_ocr_runner.py,sha256=RPyQ2SlZv6A_OPTP8OO49Pe62HtAVklTvANOmliHeGQ,30501
|
|
19
|
+
gpurunner/_embedded/spotter_page_bench_runner.py,sha256=Ca6SYyLRS_5HQnTwcXbQEoPg68ExNJsqKFoWCftgb_M,7343
|
|
20
|
+
gpurunner/_embedded/trocr_lines_runner.py,sha256=WgaBr8-VaYt0mu9GA6toUiIP-jXxIXX63jupW6ws2Ng,7607
|
|
21
|
+
gpurunner/_embedded/vit_classifier_modal_runner.py,sha256=DjRqLd5l63C0j2igseAPQLIvWVQqjCIg8Mzc6ODo-sY,15143
|
|
22
|
+
gpurunner/_embedded/vit_classifier_runner.py,sha256=599fhKNpYiC1x8UzMorricCvpkDl-oJbXMXnP_eIs3I,15591
|
|
23
|
+
gpurunner/_embedded/yolo_spotter_modal_runner.py,sha256=3JhTmN-lOirbIWcCn0x7SJsoSNX1bVxH4dU1qnnOETU,47690
|
|
24
|
+
gpurunner/auth/__init__.py,sha256=DqDOcl2x1Vs-ItpKWDib6mVnool9dG8PS_4DHnbFVC4,167
|
|
25
|
+
gpurunner/auth/beam.py,sha256=YUtJmkLL-tnNMCLUcMxzgqtsIiQ9Kjb8allW90Cpp5Q,6090
|
|
26
|
+
gpurunner/auth/google.py,sha256=HH-J8alyBrF2p-XJDhsWrW9gLnl0m1LBTyAQJeHfFPU,7464
|
|
27
|
+
gpurunner/auth/kaggle.py,sha256=MOjK0KmkOL6GJS2o7Mmq75sfZmkqRRbpDPPw0RD01Ec,3270
|
|
28
|
+
gpurunner/auth/lightning.py,sha256=UTF8P14zPxTn9Drnw-dAaF7_xwLmZnUwkRW-lK-h1aQ,8417
|
|
29
|
+
gpurunner/auth/modal.py,sha256=dXISJgGpgwKE1OeUyFk5LJH-Y9JpomRlekLQ8rBTYgo,836
|
|
30
|
+
gpurunner/auth/saturn.py,sha256=Jc2NjSxNN0Go-x3iWhwzOmk2eacMVkHlPKh5a6NP2xw,5190
|
|
31
|
+
gpurunner/auth/vast.py,sha256=5ZomWE9YapcbbW6fDtMc4jeYfHVI-q1F_XIGOf_zUVk,11458
|
|
32
|
+
gpurunner/backends/__init__.py,sha256=abwuCtUCyc1l9IH6LinwdJIzJD7eoVWizSwdZzjSF3k,1353
|
|
33
|
+
gpurunner/backends/beam.py,sha256=42Iz6wjpilA7OpPZ-Ewfb7RB-CEj6iH9AQRf7iNYQBs,45260
|
|
34
|
+
gpurunner/backends/colab.py,sha256=FspAUYdEoD1lTrOc6Mf2_lR6IRWD-iMtdomhwyh9T1I,30505
|
|
35
|
+
gpurunner/backends/kaggle.py,sha256=nK9DPVqtyxHOKxZUcdlp4v_DeuZWoLMLkD2OGJUDJRU,29353
|
|
36
|
+
gpurunner/backends/lightning.py,sha256=5lAZJiUxcOMomDfwk9zspsHFVzziHkmtJCBko3IcbrQ,32847
|
|
37
|
+
gpurunner/backends/modal.py,sha256=Dz27b0Ktf70G0JhSUkEzviCuiKQHitLwlvPRngS-mmg,27311
|
|
38
|
+
gpurunner/backends/saturn.py,sha256=f5ImitChMKWrX9w_HpCGHbkvSUkQl7P_X6v1B6Gbm4M,31984
|
|
39
|
+
gpurunner/backends/vast.py,sha256=FqEdy0Pf4oNE1w3m-vaRRyq8R2tZ_rYbwkfVE8R9Rg4,131063
|
|
40
|
+
gpurunner/core/__init__.py,sha256=Gpd4z1tPhSAAC_d6b8eEm4Av1l2-urgSjaeng0fBIbM,401
|
|
41
|
+
gpurunner/core/backend.py,sha256=n724a1mmvkZHeDDxAM8R_GEkW7lmyAn8nMV_ImF2_s0,3714
|
|
42
|
+
gpurunner/core/balances.py,sha256=_6kVpdzzNRLu24czuISijWNTSJBdSlF9k5KZzIbZ3HY,17346
|
|
43
|
+
gpurunner/core/boxes.py,sha256=_2HdUjPrwZLvLFdEEJ_v0_MnTShzqAmlF2hr3Qo4Mv0,38053
|
|
44
|
+
gpurunner/core/budget.py,sha256=3lQk5EqNaNA3XM1OX_bAYHtVdzQqexo-xTYRrJJEiuk,6804
|
|
45
|
+
gpurunner/core/contract.py,sha256=x3hVnvK0gZxvhlKVJ6HKNZvcWf1OP5xB5x1Yi9JuC-A,4089
|
|
46
|
+
gpurunner/core/gpu_equiv.py,sha256=VjwVBdwnaWguN9VIashOrqkmUrDATIX1TDXMWVT6Iik,12885
|
|
47
|
+
gpurunner/core/htr_sizing.py,sha256=TSB5QG1P2wlfBnZPXYH9YIKqDGKd09TprNBh64L5sFU,36682
|
|
48
|
+
gpurunner/core/inputs.py,sha256=3dRGm50t3v-u02xlrZ8AUn833sKcP7P4gCxweZ6om2o,1882
|
|
49
|
+
gpurunner/core/job.py,sha256=qBChgvkkIyG1B7dQsTV1TA5Gwl_uZ7Mwo-rIryjqvfg,10779
|
|
50
|
+
gpurunner/core/locks.py,sha256=fCM5EJ7Msvr8_ljcc-rxYiwz2al2GER3oVuKYx8KNL8,9745
|
|
51
|
+
gpurunner/core/manifest.py,sha256=EAMvE1ixx8lchu6u1HDNSs2vw-9WMpVFFlSkEhtuqTc,15085
|
|
52
|
+
gpurunner/core/models.py,sha256=ZT0L93cxozpH35VsGXsgy6kfpGbB6wQobjxuuziJbSQ,4371
|
|
53
|
+
gpurunner/core/offer_score.py,sha256=wdjxyZOB0qFcmZExleq0yE3rmIwq0bw-U2MA9h0qyUU,29278
|
|
54
|
+
gpurunner/core/quota.py,sha256=F4d3Nfh9iCPPD0NtezE3b8QQxiLToCbjFsKjukuwPWQ,28360
|
|
55
|
+
gpurunner/core/usage.py,sha256=iNxsxwIM96w75jNm40EQ8DO61NbAgSyZH1qmLlpWHYg,14098
|
|
56
|
+
gpurunner/htr/__init__.py,sha256=S5IJh1Nbl1iQ9KKlDWE9-1MYmKpWj4gg8jfwF97Jwlg,1079
|
|
57
|
+
gpurunner/htr/box_transport.py,sha256=6d8MK-W1wqZnC-NNQ1cvjppn9OLo__my4MDn43zMixI,10839
|
|
58
|
+
gpurunner/htr/calibrate.py,sha256=2UH0s2NkJTOkRKW_9Qoj9fwuRHGoj8FwLspWrubuSO0,11064
|
|
59
|
+
gpurunner/htr/fetch_ckpt.py,sha256=pIH6LYabzt1fLYz0yH5WLN1iXf9c62Tbt_SlOcONAr8,13054
|
|
60
|
+
gpurunner/htr/origin.py,sha256=mkgPf1YADmyHnNmfSxau1gyd7fYRGKP_OdvM5GBegQc,10497
|
|
61
|
+
gpurunner/htr/plan_build.py,sha256=-eExZaRUhKEDZ71OEGbtKJDj1TF1z2OLOxws95sB_0c,33737
|
|
62
|
+
gpurunner/htr/preflight.py,sha256=k6iYuljeI_NE6RMNTTzVdNeyfQajB05yti4WiYG3SkY,11133
|
|
63
|
+
gpurunner/htr/r2.py,sha256=Mcb-4Z8E9YSDfetIWo0J-1l5zrfwzjVVpYUI9_z19GU,12644
|
|
64
|
+
gpurunner/jobs/__init__.py,sha256=q4DxOrtdOfQC1yTHYIwOGPNah1rmffF0bt89jjsgI3g,2989
|
|
65
|
+
gpurunner/jobs/_net_probe.py,sha256=v6zgHRk2oKX9Gg1jVDZpza-FsePSPyGBk8BASw77ulk,2555
|
|
66
|
+
gpurunner/jobs/churro.py,sha256=2Hirb-4B05VBhmSCep0QML7L_I3SIZ6m4jx2ea7n_tY,4547
|
|
67
|
+
gpurunner/jobs/crop_verifier.py,sha256=XNjOYxTHdcD1iub2ZrIn0Z5yT5LxoeMHKOCqpu-K2_8,1407
|
|
68
|
+
gpurunner/jobs/dino_surname_verifier.py,sha256=o0j3nr-aQWIO4rjFiiqsnkWbK5xXCNc2SAGBateVncU,6385
|
|
69
|
+
gpurunner/jobs/htr_case.py,sha256=FdpoC0FsKskk5xLn57CWLtjtX_rMpUvRnx8jueBLq6o,29969
|
|
70
|
+
gpurunner/jobs/htr_eval.py,sha256=PpB7tXVu8kQ98x6ASDA2GDMeceDDbizphySWihNQ1Hg,4666
|
|
71
|
+
gpurunner/jobs/htr_lines_eval.py,sha256=ntRJRtI-o72LugdWxxepjHNI5ShqgI7CGQfSO6U0WSs,3341
|
|
72
|
+
gpurunner/jobs/htr_page_bench.py,sha256=2bq35GC_26nt8y5sOF9_eZ9A1aj9rLUBATbUvrZ5jLw,3847
|
|
73
|
+
gpurunner/jobs/kraken_lines.py,sha256=zqRNUXXPTUyT02gKr0kIc3_KZPmxTUUdU-q4v8_Zszs,3049
|
|
74
|
+
gpurunner/jobs/kraken_train.py,sha256=8Luakris5cW2ecvQa1shFqU7VekzaVYG3bd83Ux5YXk,11233
|
|
75
|
+
gpurunner/jobs/paddle_page_bench.py,sha256=2CJIhpUgzzp3LV3sNwegTJriXmqpBujEp5T4uYWHJUs,3224
|
|
76
|
+
gpurunner/jobs/paddleocr.py,sha256=FzO7i9LL_OWn91Tdf_SjMvqxO8DXn3OVQiRpjIjhIys,10513
|
|
77
|
+
gpurunner/jobs/parseq_train.py,sha256=B2gwhJsMgVJT7jSmROdKPtBg-k35HIpLsvkCHEWRokw,27559
|
|
78
|
+
gpurunner/jobs/rukopys_ocr.py,sha256=1Q-xTr-sB86-yTGsQ0OvswVbWTDCOZwHZS0AJLH_j60,4078
|
|
79
|
+
gpurunner/jobs/spotter_page_bench.py,sha256=8FE6rhRX2ja4UzQblSdrL6Bu73HN9L4HgSA8oGORvws,3815
|
|
80
|
+
gpurunner/jobs/trocr_lines.py,sha256=ylyiB4wOwHfevcwvR9b4q6pBi_5HTjrrNbXYEsb3hjc,3339
|
|
81
|
+
gpurunner/jobs/vit_classifier.py,sha256=5OjzvOZrx_iLa1zs84b4TLWPXSPNjVynEbkQR8WmfJ8,7556
|
|
82
|
+
gpurunner/jobs/yolo_spotter.py,sha256=7wkEmpulBfNKzzUk4npmbyqdFZIv9SvnU8b1hqmxQT8,21827
|
|
83
|
+
gpurunner/plugins/__init__.py,sha256=Oyt6m2wwYaCzVcTmfosXTP5kpbiGt0KMfGMQHffeSBU,407
|
|
84
|
+
gpurunner/plugins/nyshporka_cloud.py,sha256=AcE705muEwKYV7qLJ-yB6RQymoEBOBzLfZExvCjfKG4,41365
|
|
85
|
+
gpurunner/supervise/__init__.py,sha256=yZ1pE32Upl-F5Gy9xos3k_s1FDzjl-b2vCjeU7dW-yo,126
|
|
86
|
+
gpurunner/supervise/append.py,sha256=xDVGMYdy64sTfahfERAv9znw8YBPWPCg4S6SStCHETY,5056
|
|
87
|
+
gpurunner/supervise/bg.py,sha256=ODKfGtUK4v1Zse3ePol5BhsKsjM44HeFngmGVyvfBVo,7775
|
|
88
|
+
gpurunner/supervise/decide.py,sha256=xOzlhgUGB0j6BZZ0uaM57SSp1z2GAQXCd_H2gksoj6s,44380
|
|
89
|
+
gpurunner/supervise/detach.py,sha256=rF5X__iefl3fypr3BG5i3XhSp-h411gijRJdyYh_ZpU,17314
|
|
90
|
+
gpurunner/supervise/gate.py,sha256=1Wh5X-wT4lb_naAnAWeeFt3Q_yyZTRA7dHvQnpcEpAU,25133
|
|
91
|
+
gpurunner/supervise/htr.py,sha256=sx8XnxrEireAFGt-_Qshpve-8_uU5tmXvrkajRmT2ZY,212986
|
|
92
|
+
gpurunner/supervise/plan.py,sha256=ah3-zTsrnIfMWifI29_p91Sh4s6Vr6Ris7hZaQZuEfQ,27996
|
|
93
|
+
gpurunner/supervise/state.py,sha256=I8Qaukq-pWZ_SKyxPAD44L4RyPbXdNI_Aps5N-5ntTo,23266
|
|
94
|
+
gpurunner/supervise/verify.py,sha256=-OlFL6aZvtyTAQdYj_z9xpFXNeSUeMhRQcsGgc869Cw,9707
|
|
95
|
+
gpurunner/supervise/wrapup.py,sha256=ecmtbF_gNSZVKmcUNPfJCC1KjLskgyBLNL3iUwlXvdU,3819
|
|
96
|
+
gpurunner/web/__init__.py,sha256=L_zFK82CxcXXxpEJdIsCOa0Hq0r7_A2vUcMMAX3lDSY,546
|
|
97
|
+
gpurunner/web/app.py,sha256=sGcfhmyQfPtBEIG8k3cCyov9EcIso7sXSwVZtSHF2BM,14834
|
|
98
|
+
gpurunner/web/static/index.html,sha256=JlArNRv5O7eG6-m9BgH9aOGC-F498-lPFuiEYnG4NOQ,41736
|
|
99
|
+
gpuhire-0.2.0.dist-info/METADATA,sha256=_CN8jIiXahpb04XDgIDzs8xV-tfHF9zWi1kte8RAcQU,14448
|
|
100
|
+
gpuhire-0.2.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
101
|
+
gpuhire-0.2.0.dist-info/entry_points.txt,sha256=I6QBdnQbrgzOXKI34zm-Fro9XhJptRkcw2z5cxxyp7s,117
|
|
102
|
+
gpuhire-0.2.0.dist-info/licenses/LICENSE,sha256=sPEhlEAJ1y1dh5hgVz46C0wnuR3AwVtWUptJrf5TGQc,1078
|
|
103
|
+
gpuhire-0.2.0.dist-info/RECORD,,
|
|
@@ -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.
|
gpurunner/__init__.py
ADDED
gpurunner/__main__.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""`python -m gpurunner` — останній запасний шлях відчеплених задач.
|
|
2
|
+
|
|
3
|
+
Задача планувальника не має PATH, і коли ні `gpurunner` у PATH, ні
|
|
4
|
+
`gpurunner.exe` поруч не знайдено, `detach.self_argv()` кличе саме так. Доти
|
|
5
|
+
цього модуля не було, і запасний шлях падав на «No module named gpurunner.__main__».
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from gpurunner.cli import app
|
|
9
|
+
|
|
10
|
+
if __name__ == "__main__":
|
|
11
|
+
app()
|
|
File without changes
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""Спільний пролог для embedded-ранерів; вклеюється рендером ПЕРЕД раннером.
|
|
2
|
+
|
|
3
|
+
Це не імпортований модуль (як і самі ранери) — ``Job.render_kaggle_code``
|
|
4
|
+
конкатенує цей файл із раннером в один текст, який їде на кернел. Звідси
|
|
5
|
+
обмеження ті самі: лише stdlib на верхньому рівні, жодних імпортів gpurunner,
|
|
6
|
+
без ``from __future__ import annotations``.
|
|
7
|
+
|
|
8
|
+
🔴 Порядок склеювання (спершу _common, потім раннер) навмисний: якщо раннер
|
|
9
|
+
визначає функцію з тим самим іменем, перемагає ЙОГО версія. Тому додавання
|
|
10
|
+
цього файлу нічого не ламає само по собі, а прибирати локальні копії можна
|
|
11
|
+
поступово, по одному раннеру.
|
|
12
|
+
|
|
13
|
+
Що сюди варто виносити: дрібні чисті функції, які вже скопійовані дослівно в
|
|
14
|
+
кілька ранерів і де розходження копій — це баг. Що НЕ варто: усе, що ранери
|
|
15
|
+
свідомо роблять по-різному (parseq розпаковує tgz системним ``tar``, решта —
|
|
16
|
+
``tarfile``), і все, що потрібне раннерам, які їздять ще й на Modal
|
|
17
|
+
(``paddleocr``, ``vit_classifier``, ``yolo_spotter``): Modal бере лише сам
|
|
18
|
+
модуль раннера, без цього прологу, тож їхні копії мусять лишатись при них.
|
|
19
|
+
"""
|
|
20
|
+
from datetime import datetime, timezone
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
KAGGLE_INPUT = Path("/kaggle/input")
|
|
24
|
+
KAGGLE_WORKING = Path("/kaggle/working")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _utc_iso() -> str:
|
|
28
|
+
return datetime.now(tz=timezone.utc).isoformat(timespec="seconds")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _dataset_root(slug: str, gt_file: str) -> Path:
|
|
32
|
+
"""Тека змонтованого датасету, знайдена за характерним файлом.
|
|
33
|
+
|
|
34
|
+
🔴 Точка монтування Kaggle не одна: буває ``/kaggle/input/<slug>``, буває
|
|
35
|
+
``/kaggle/input/<owner>-<slug>``, а з якогось моменту — ще й
|
|
36
|
+
``/kaggle/input/datasets/<owner>/<slug>/``. Через це job падав із «не
|
|
37
|
+
знайдено», хоча дані лежали поруч. Тому: спершу очевидні кандидати, далі
|
|
38
|
+
рекурсивний пошук, і аж тоді помилка — але з деревом того, що реально
|
|
39
|
+
змонтовано (найчастіша справжня причина — датасет ще не розпакувався).
|
|
40
|
+
"""
|
|
41
|
+
slug_short = slug.split("/")[-1]
|
|
42
|
+
candidates = [KAGGLE_INPUT / slug_short, KAGGLE_INPUT / slug.replace("/", "-")]
|
|
43
|
+
candidates += [d for d in KAGGLE_INPUT.iterdir() if d.is_dir()] if KAGGLE_INPUT.exists() else []
|
|
44
|
+
for c in candidates:
|
|
45
|
+
if (c / gt_file).exists():
|
|
46
|
+
return c
|
|
47
|
+
hits = sorted(KAGGLE_INPUT.glob(f"**/{gt_file}")) if KAGGLE_INPUT.exists() else []
|
|
48
|
+
if hits:
|
|
49
|
+
print(f"[diag] dataset root via rglob: {hits[0].parent}", flush=True)
|
|
50
|
+
return hits[0].parent
|
|
51
|
+
tree = []
|
|
52
|
+
if KAGGLE_INPUT.exists():
|
|
53
|
+
for d in sorted(KAGGLE_INPUT.iterdir()):
|
|
54
|
+
tree.append(str(d))
|
|
55
|
+
if d.is_dir():
|
|
56
|
+
tree += [f" {x.name}" for x in sorted(d.iterdir())[:8]]
|
|
57
|
+
raise RuntimeError(
|
|
58
|
+
f"dataset root with {gt_file} not found under {KAGGLE_INPUT}; mounted:\n"
|
|
59
|
+
+ ("\n".join(tree) or "<порожньо>"))
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _norm(s: str) -> str:
|
|
63
|
+
"""Нормалізація для нечіткого порівняння дореформеної кирилиці.
|
|
64
|
+
|
|
65
|
+
ѣ→е, і→и, ъ викидається — інакше та сама лексема в тексті XIX ст. і в
|
|
66
|
+
сучасному GT не збігається. Правило мусить бути одне на всі бенчмарки:
|
|
67
|
+
коли копій три, вони розходяться, і числа з різних job-ів перестають бути
|
|
68
|
+
порівнюваними — а вони існують саме заради порівняння.
|
|
69
|
+
"""
|
|
70
|
+
s = s.lower().replace("ё", "е").replace("ъ", "").replace("ѣ", "е").replace("і", "и")
|
|
71
|
+
return "".join(ch for ch in s if ch.isalpha() or ch == " ").strip()
|