Навчання на орендованому GPU
Орендований GPU перетворює запуск навчання на завдання з початком, завершенням і рахунком. Робота залишається такою самою, як під час локального навчання; відрізняються передавання даних, зовнішнє спостереження, отримання ваг і вимкнення машини.
Перед орендою
Два рішення згодом коштують більше, ніж зараз.
Спочатку розмістіть датасет у CDN. Упакування в один tar у репозиторії датасету
Hugging Face однаково працює в усіх постачальників, забезпечує швидке передавання
до кожного з них і потребує лише HF_TOKEN у середовищі завдання, якщо репозиторій
приватний. Копіювання датасету з домашнього з'єднання або отримання його на машині
з повільного джерела витрачає оплачуваний час GPU на очікування.
tar cf my-dataset.tar my-dataset/huggingface-cli upload my-org/my-dataset my-dataset.tar --repo-type datasetimport tarfile from huggingface_hub import hf_hub_download path = hf_hub_download( "my-org/my-dataset", "my-dataset.tar", repo_type="dataset")with tarfile.open(path) as archive: archive.extractall("/root/data")Потім визначте розмір диска. Постачальники, які тарифікують сховище, стягують плату за виділену, а не використану місткість, і після створення диск не можна зменшити. Додайте обсяг підготовлених даних і контрольних точок, залиште близько 30 відсотків запасу та зупиніться на цьому.
Встановлення на машині
pip install libreyolo # Додавайте лише потрібні для запуску доповнення: rfdetr для навчання RF-DETR,# lora для параметрично ефективного донавчання, onnx для подальшого експорту.pip install "libreyolo[rfdetr,lora]"import torch print(torch.__version__, torch.cuda.is_available())print(torch.cuda.get_device_name(0)) # Колесо, зібране для іншої архітектури, повідомляє True, а потім зазнає помилки# на першому справжньому ядрі, тому запустіть одне.x = torch.rand(2000, 2000, device="cuda")print(float((x @ x).sum()))Якщо образ ще не містить збірки CUDA для цієї карти, спочатку встановіть PyTorch,
а потім LibreYOLO, щоб pip не вибрав власну версію torch лише для CPU. Другий фрагмент
не є необов'язковою формальністю: колесо, зібране для неправильної архітектури GPU,
повідомляє torch.cuda.is_available() == True, а потім завершується на першій
справжній операції з помилкою CUDA error: no kernel image is available for execution on the device. Одне множення матриць виявляє це раніше, ніж година налаштування.
Якщо постачальник надає том, спрямовуйте HF_HOME до постійного сховища, щоб
завантажені контрольні точки й датасети зберігалися між запусками.
Запуск
Запускайте завдання від'єднаним. Якщо інтерактивний сеанс завершується через розрив мережевого з'єднання, навчання також припиняється.
nohup libreyolo train \ model=LibreYOLO9s.pt \ data=/root/data/my-dataset/data.yaml \ epochs=100 batch=-1 imgsz=640 \ project=/root/runs name=run1 \ > /root/train.log 2>&1 &from libreyolo import LibreYOLO if __name__ == "__main__": model = LibreYOLO("LibreYOLO9s.pt") model.train( data="/root/data/my-dataset/data.yaml", epochs=100, batch=64, # глобальний батч для всіх GPU device="0,1,2,3", project="/root/runs", name="run1", )Саме тут варто використовувати batch=-1, бо зазвичай навчання виконується на карті,
яку ви ще не використовували. Параметр тестує модель у режимі навчання зі справжнім
зворотним проходом і вибирає найбільший степінь двійки, що вміщується в пам'ять.
Це швидше, ніж з'ясувати межу через помилку нестачі пам'яті через двадцять хвилин.
Див. розділ Гіперпараметри.
На машині з кількома GPU параметр device="0,1,2,3" сам запускає по одному робочому
процесу на GPU, а batch залишається глобальним батчем для всіх них. Захисна умова
__main__ обов'язкова, оскільки кожен робочий процес повторно імпортує скрипт.
Цю та інші особливості розподіленого виконання описано в розділі
Навчання на кількох GPU.
Зовнішнє спостереження
Кожен запуск записує status.json до свого каталогу й атомарно перезаписує файл
після кожної епохи. Це дешеве читання кількох сотень байтів зі станом, поточною епохою,
оцінкою часу до завершення та останніми метриками без розбору логу.
cat /root/runs/run1/status.jsonimport json with open("/root/runs/run1/status.json") as handle: status = json.load(handle) print(status["state"], status["current_epoch"], status["eta_seconds"])print(status.get("metrics"))# На машині (типово прив'язується до 127.0.0.1:8420):libreyolo monitor /root/runs/run1 --no-browser # На своїй машині, потім локально відкрийте http://localhost:8420:# ssh -L 8420:localhost:8420 <user>@<host>Розташований поруч metrics.jsonl містить повну історію за епохами, а train.log
містить консольний вивід. Команда libreyolo monitor обслуговує браузерну панель
для всіх трьох файлів лише засобами стандартної бібліотеки, тому на машині не потрібно
встановлювати нічого, крім LibreYOLO. Відкривайте її через перенаправлення порту SSH.
Жоден із цих засобів не взаємодіє з процесом навчання, тому ними можна під'єднатися до активного запуску, повторно відкрити завершений запуск або дослідити аварійний.
Отримання ваг до припинення оплати
Машина є одноразовою. Надсилайте контрольні точки на проміжних етапах, а не лише наприкінці, бо інакше збій, витіснення чи вичерпання коштів знищить увесь результат.
huggingface-cli upload my-org/my-run \ /root/runs/run1/weights/best.pt best.ptФайли weights/best.pt і weights/last.pt записуються після кожної епохи та кожного
покращення. Параметр save_period=N додатково створює знімки weights/epoch_<N>.pt,
завдяки чому проміжне передавання потребує мало ресурсів. Варто також забрати невеликі
файли summary.json і results.csv, якщо сімейство записує їх.
Зворотний виклик on_train_epoch_end є зручним способом автоматизувати передавання.
Див. розділ Логери експериментів, де розміщені сервіси також
надають метрики без прямої взаємодії з машиною.
Припинення оплати
Помилка на цьому етапі коштує реальних грошей, а правило залежить від моделі постачальника.
На маркетплейсі з орендою фізичної машини тарифікація триває за реальним часом, доки екземпляр не знищено. Бездіяльний GPU коштує стільки само, як завантажений, тому саме завершення процесу навчання нічого не заощаджує. Для зупиненого екземпляра й далі нараховується плата за диск.
На безсерверній платформі, де завдання є декорованою функцією, контейнер масштабується до нуля після повернення з функції, тому ризик забути машину значно менший. Зависле завдання без обмеження часу й далі тарифікується, тому завжди встановлюйте тайм-аут.
Зупинка замість знищення є справжнім засобом заощадження, але водночас і пасткою. Вимірювання на орендованій машині з 8x RTX 4090 та диском 250 GB станом на 2026-07-31 дали такі результати: робота коштувала $3.4828 за годину, зупинка коштувала $0.0694 за годину лише за диск, а знищення не коштувало нічого. Зупинка заощаджує 98 відсотків, водночас зберігаючи середовище, підготовлені дані й контрольні точки.
Тариф зупиненого екземпляра можна обчислити перед орендою:
stopped $/hr = allocated_GB * storage_cost_per_GB_per_month / 730
= 250 * 0.20 / 730 = $0.0694/hrПорівняйте його з вартістю повторного налаштування: нової оренди, отримання образу, встановлення й повторної підготовки даних. На тій самій машині повторне налаштування потребувало близько 15 хвилин і 43 GB вхідного трафіку, загалом близько $1.00. За тарифу $0.0694 на годину повернення протягом приблизно 14 годин робить зупинку вигіднішою, а за довшої перерви вигідніше знищити екземпляр і відтворити його з підготовленої копії.
Для дефіцитного обладнання є один ризик, який робить зупинку небезпечною: зупинка звільняє GPU. Їх ніщо не резервує, тому повторний запуск вдасться, лише якщо вони досі вільні на хості. Диск збережеться, але GPU не гарантовано.
Безсерверний запуск як функція
Якщо керувати машиною не потрібно, Modal і Beam запускають декоровану функцію Python
на GPU та масштабуються до нуля після її повернення. Власний нічний набір тестів
LibreYOLO виконується на Modal, а tools/ci/modal_nightly.py у репозиторії бібліотеки
є робочим прикладом у кодовій базі, який можна скопіювати.
import modal
image = (
modal.Image.debian_slim(python_version="3.11")
.apt_install("git", "libgl1", "libglib2.0-0") # Системні бібліотеки OpenCV
.pip_install("libreyolo[rfdetr]")
)
app = modal.App("libreyolo-train")
cache = modal.Volume.from_name("libreyolo-cache", create_if_missing=True)
@app.function(gpu="A100", timeout=6 * 60 * 60, volumes={"/cache": cache})
def train():
import os
os.environ["HF_HOME"] = "/cache/hf" # кешування ваг між запусками
from libreyolo import LibreYOLO
model = LibreYOLO("LibreYOLO9s.pt")
model.train(data="coco8.yaml", epochs=100, project="/cache/runs")
cache.commit() # збереження тому
@app.local_entrypoint()
def main():
train.remote()Запустіть код командою modal run modal_train.py. Файлова система контейнера
тимчасова, тому все, що потрібно зберегти, має бути в томі або передаватися назовні.
Задавайте timeout= явно; лише він відділяє завислий запуск від необмеженого рахунку.
Beam використовує ту саму структуру з декоратором @function, об'єктом Volume
і викликом train.remote() з __main__.
Правильний вибір розміру за вартістю завдання
$/hr не є правильним показником для оптимізації. Мала модель використовує велику
карту лише частково, тому дешевший і повільніший GPU часто коштує менше на епоху.
Перш ніж запускати тривале навчання, виконайте профілювання на орендованій карті
протягом кількох кроків: якщо вердиктом є dataloader або host / launch, швидший
GPU нічого не дасть, а додаткові робочі процеси чи більший батч дадуть значний ефект.
Див. розділ Продуктивність навчання.
Пов'язані матеріали
- Датасети описують структуру підготовленого архіву та команду doctor, яка виявляє проблеми до початку тарифікації GPU.
- Навчання на кількох GPU описує машини з кількома картами.