Решения

Данные и хранение на GPU: чекпоинты, кэш и пайплайны

Задача страницы. Помочь выстроить поток данных под GPU‑задачи: где хранить датасеты и чекпоинты, как быстро переносить большие объёмы, чем кэшировать, как избежать простоя GPU из‑за I/O и не потерять прогресс при прерывании инстанса.

Принципы, которые экономят часы и деньги

  • Локальность и «горячие» данные. Датасеты и модели, которые активно читаются, держите на локальном NVMe (внутри инстанса). Всё остальное — в объектном хранилище.
  • Мало крупных файлов лучше, чем много мелких. Пакуйте датасеты в tar‑шарды/партиции; тысячам мелких файлов всегда проигрывать по IOPS.
  • Потоковый конвейер вместо «ждать пока скачается всё». Стриминг и префетч позволяют считать уже первые батчи, пока хвост догружается.
  • Идемпотентность и автосейвы. Любой шаг должен безопасно перезапускаться; чекпоинты и артефакты — с версионированием и атомарной записью.
  • Отделяйте вычисления от хранения. Инстанс можно удалить, данные — нет; чекпоинты и артефакты дублируйте в долговременное хранилище.

Быстрый выбор стратегии (по размеру и типу задачи)

  • До ~50 ГБ (прототип, инференс): копируйте прямо на NVMe инстанса; кэш моделей/эмбеддингов тоже туда.
  • 50–500 ГБ (тренировка, CV): храните в объектном хранилище, при старте — быстрая синхронизация «горячих» шардов на NVMe + фоновая докачка.
  • 500 ГБ–10 ТБ (LLM, видео): храните в объектном хранилище; используйте тар‑шарды/WebDataset, стриминг и агрессивный префетч; чекпоинты — сразу в удалённое хранилище.
  • Multi‑node: на каждый узел — локальный кэш под свой shard‑диапазон; не тяните одни и те же файлы по сети на все узлы одновременно.

Чекпоинты: никакой потери прогресса

Как часто?

  • Обучение: по времени (например, каждые 15–30 мин.) и по шагам/эпохам.
  • Инференс/батчи: по чанкам (N образцов/клипов/документов).

Структура и атомарность:

  • Пишите во временный файл и атомарно переименовывайте в целевое имя: checkpoint.tmp → checkpoint.pt.
  • Держите ротацию: …/ckpt-000100, …/ckpt-000200 и latest как симлинк/манифест.
  • Сразу после записи — дублирование в удалённое хранилище (объектное/S3‑совместимое).

Пример (PyTorch, атомарная запись + дублирование)

				
					import os, json, torch, fsspec, tempfile

def atomic_save(obj, path_local):
    d = os.path.dirname(path_local); os.makedirs(d, exist_ok=True)
    with tempfile.NamedTemporaryFile(dir=d, delete=False) as t:
        torch.save(obj, t.name)
        tmp = t.name
    os.replace(tmp, path_local)  # атомарно

def save_and_upload(state, local_path, remote_url):
    atomic_save(state, local_path)
    with fsspec.open(local_path, "rb") as fsrc, fsspec.open(remote_url, "wb") as fdst:
        fdst.write(fsrc.read())

# пример: save_and_upload(state, "/data/ckpts/ckpt-000200.pt", "s3://bucket/exp1/ckpt-000200.pt")

				
			

Перенос и подготовка датасетов

Быстрый параллельный HTTP/HTTPS:

				
					# urls.txt — список прямых ссылок; aria2 параллелит загрузку
aria2c -i urls.txt -x16 -s16 -j8 -d /data/datasets

				
			

Объектное хранилище / S3‑совместимое (пример rclone):

				
					# копируем с высокой параллельностью, проверками и резюме
rclone copy s3:mybucket/path /data/datasets/path \
  --transfers=32 --checkers=64 --fast-list --copy-links --progress

				
			

Синхронизация из другого сервера (rsync):

				
					rsync -ah --info=progress2 --partial --inplace --chmod=ugo=r \
  --exclude='*.tmp' source:/datasets/imagenet/ /data/datasets/imagenet/

				
			

Архивы и тар‑шарды:

  • Разбивайте датасет на шарды по 512 МБ–2 ГБ в формате tar (или parquet‑партиции) — это резко снижает накладные расходы при чтении.
  • Для картинок/видео используйте WebDataset (tar‑шарды + индекс).

Синхронизация из другого сервера (rsync):

				
					import webdataset as wds
dataset = (wds.WebDataset("/data/datasets/myset/{000000..000255}.tar")
           .decode("pil")
           .to_tuple("jpg;png", "json"))
loader = wds.WebLoader(dataset, batch_size=64, num_workers=8)

				
			

Кэширование: модели, датасеты, артефакты

Стандартизируйте пути к кэшу (переопределите их на NVMe инстанса):

				
					export HF_HOME=/data/.cache/hf
export TRANSFORMERS_CACHE=$HF_HOME/transformers
export HF_DATASETS_CACHE=$HF_HOME/datasets
export TORCH_HOME=/data/.cache/torch
mkdir -p $TRANSFORMERS_CACHE $HF_DATASETS_CACHE $TORCH_HOME

				
			

Предпрогрев (pre‑warm):

  • На этапе «подготовки» один раз скачайте веса/токенайзеры/вспомогательные артефакты в кэш, затем снимайте образ/шаблон или закрепляйте диск.
  • Для инференс‑сервисов держите отдельный слой кэша (например, общий том), чтобы деплои не перекачивали веса заново.

Дата‑пайплайны для обучения/инференса

Обучение:

  • Префетч и pinned memory в DataLoader.
  • Аугментации на GPU, где уместно, чтобы CPU не стал бутылочным горлышком.
  • Шардирование по эпохам — распределяйте список шардов между воркерами/узлами, чтобы избежать «драки» за одинаковые файлы.

Инференс/батчи:

  • Читайте из источника чанками (N документов/клипов), сохраняйте промежуточные результаты каждые M чанков.
  • Параллельно выгружайте результаты в хранилище; не накапливайте гигабайты в /tmp.

Видеопотоки/рендер:

  • Храните исходники на объектном хранилище; формируйте рабочие очереди ссылок и вытягивайте в локальный кэш непосредственно перед обработкой.
  • Используйте NVENC/AV1 профили и фиксированные пресеты (см. раздел рендеринга).

Multi‑node и распределённый I/O

  • Своя доля для каждого узла. Раздавайте каждому узлу собственный набор шардов; избегайте общей сетевой директории с «горячими» чтениями.
  • Локальный кэш → чистка по LRU. Ограничьте размер кэша; вычищайте неиспользуемые шарды по LRU, чтобы NVMe не забивался.
  • Параллельные менеджеры загрузки. Разделите пул «скачивателей» и «читателей», чтобы обучение не ждало сеть/диск.

Безопасность и управление доступом

  • Секреты только через переменные окружения/секрет‑менеджер. Не коммитьте токены в репозиторий; ограничьте объём выведенных логов.
  • Шифруйте архивы и чувствительные артефакты. При необходимости — шифрование на стороне клиента перед загрузкой в объектное хранилище.
  • Маскируйте пути/имена в публичных артефактах; для датасетов с PII используйте анонимизацию/псевдонимизацию.

Стоимость и жизненный цикл данных

  • Хранение тарифицируется даже у остановленных инстансов. Планируйте объёмы дисков и своевременную чистку.
  • Стейджинг‑диск ≠ архив. После завершения — выгрузка артефактов в долговременное хранилище, удаление инстанса/тома.
  • Сжимайте и дедуплицируйте. Zstd для больших логов/JSON; избегайте gzip для потокового чтения (zstd быстрее и эффективнее).

Траблшутинг

  • GPU простаивает (<70%): проверьте num_workers, pin_memory, префетч, скорость диска/сети, наличие шардов локально.
  • OOM на диске: включите LRU‑чистку кэша и ротацию временных файлов; не держите несколько копий одного и того же датасета.
  • Повреждённые файлы: проверяйте контрольные суммы; включите повторные попытки/резервные зеркала в загрузчиках.
  • Прерываемые инстансы: проверяйте, что чекпоинт пишется «часто и атомарно», и немедленно выгружается наружу.

Полезные сниппеты

PyTorch DataLoader (параметры I/O):

				
					loader = DataLoader(dataset,
    batch_size=64,
    shuffle=True,
    num_workers=8,
    pin_memory=True,
    persistent_workers=True,
    prefetch_factor=4)

				
			

Загрузка из объектного хранилища по списку ключей:

				
					import fsspec
fs = fsspec.filesystem("s3", anon=False)
for key in keys:
    with fs.open(f"s3://bucket/{key}", "rb") as fsrc, open(f"/data/{key}", "wb") as fdst:
        fdst.write(fsrc.read())