Переглянути як Markdown

Навчання на орендованому 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 dataset
Підготувати на машині
import 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]"
Спочатку перевірити GPU
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 &
Кілька GPU з файлу Python
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.json
Зі скрипту
import 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"))
У браузері через тунель SSH
# На машині (типово прив'язується до 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 у репозиторії бібліотеки є робочим прикладом у кодовій базі, який можна скопіювати.

python
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 описує машини з кількома картами.

Перевірено з LibreYOLO v1.5.0.