Перейти к содержимому

Конфигурация обучения моделей и маршруты

Каждый ключ блока model_training, как запуски ставятся в очередь, оцениваются и хранятся, админские и агентские маршруты, а также решения для частых ошибок запуска.

Новое в v2.14.0

Эта страница — справочник по блоку model_training конфигурации Potato и по тому, что происходит с запуском после его начала. Страница рассчитана на человека, который ведёт исследование и хочет ограничить запуски, отправить их на другую машину, показать разметчикам предсказания модели или начать обучение из скрипта. Каждый ключ, значение по умолчанию, маршрут и сообщение ниже сверены с кодом Potato. Для первого запуска начните с руководства Обучите свою первую модель. Тренеры и их параметры перечислены на странице Тренеры.

Полная конфигурация

Конфигурация ниже обучает классификатор тональности на отзывах о товарах. auto_retrain переобучает sklearn-text после каждых 25 новых аннотаций. С признаками TF-IDF по умолчанию sklearn-text обучается на процессоре и не требует ничего сверх обычной установки Potato. Поэтому частые автоматические запуски обходятся дёшево. Обратная запись показывает разметчикам каждое предсказание с уверенностью не ниже 0,8. С include_unlabeled запуск предсказывает также для отзывов, которые никто ещё не разметил. Значения hf-text-classification по умолчанию и бэкенд gpu-server обслуживают запуски, которые вручную начинают со страницы Training:

yaml
annotation_task_name: "Review sentiment with model training"
task_dir: "."
data_files:
  - "data/reviews.json"
item_properties:
  id_key: "id"
  text_key: "text"
output_annotation_dir: "annotation_output"
user_config:
  allow_all_users: true
 
annotation_schemes:
  - annotation_type: "radio"
    name: "sentiment"
    description: "Is this review positive or negative?"
    labels: ["positive", "negative"]
 
model_training:
  enabled: true
  split_seed: 0
  splits: {train: 0.7, val: 0.15, test: 0.15}
  aggregation: consensus
  retain_runs: 5
  queue_max: 10
  max_wall_seconds: 3600
  max_ram_mb: 8192
  num_threads: 4
  trainer_params:
    sklearn-text:
      classifier: sklearn.linear_model.LogisticRegression
      classifier_kwargs: {max_iter: 1000}
    hf-text-classification:
      model_name: answerdotai/ModernBERT-base
      epochs: 4
      lora: true
  auto_retrain:
    enabled: true
    trainer: sklearn-text
    schemas: [sentiment]
    min_interval_s: 600
    update_frequency: 25
  writeback:
    schemas: [sentiment]
    min_confidence: 0.8
    include_unlabeled: true
  backends:
    gpu-server:
      type: ssh
      host: gpu-server
      python: /opt/conda/bin/python3
      gpus: auto
      min_free_gpu_mb: 4000

Держите split_seed неизменным на всё время исследования. Новое начальное значение переназначает каждый объект, поэтому отложенные объекты попадают в обучение, и поздние оценки перестают быть сопоставимыми с ранними. Порог min_confidence 0,8 — только отправная точка, а подходящий порог зависит от первой оценки на отложенных объектах. Включайте include_unlabeled, когда эта оценка оправдывает показ предварительных меток, потому что предварительные метки привязывают разметчиков к ответу модели.

Ключи в model_training

Все ключи находятся под model_training:

КлючПо умолчаниюЗначение
enabledfalseРегистрирует страницу Training, маршруты под /admin/training и агентские маршруты под /api/training. Без enabled: true маршрутов не существует.
retain_runs5Сколько завершённых запусков хранится в журнале запусков. Более старый запуск уходит из журнала, если его предсказания не хранятся до сих пор. Каталоги запусков остаются на диске.
grace_seconds20Сколько секунд отменённому запуску даётся на выход, прежде чем Potato убьёт процесс. Значение 0 или больше, оно отправляется вместе с заданием бэкендам типов ssh, slurm и agent.
queue_max10Сколько запусков может ждать за выполняющимся запуском.
split_seed0Начальное значение для распределения объектов по выборкам train, val и test.
splits{train: 0.7, val: 0.15, test: 0.15}Доли выборок, нормированные так, чтобы сумма равнялась 1. Имена — train, val и test, и train обязательна.
aggregationconsensusКак метки нескольких разметчиков на объекте сводятся в одну. consensus подгоняет модель Dawid-Skene, если в исследовании больше одного разметчика, и переходит к большинству голосов, если подгонка не удалась. majority берёт большинство голосов.
max_wall_secondsне заданоЛимит времени одного запуска. Potato проверяет локальный запуск при каждом событии, о котором запуск сообщает, а запуск по ssh или через агента — каждую секунду.
max_ram_mbне заданоЛимит адресного пространства процесса обучения, устанавливаемый через setrlimit. На платформе без такого лимита запуск пишет предупреждение и продолжается.
deviceautoauto, cpu, cuda, cuda:N или mps. При auto сначала берётся CUDA, затем Metal от Apple, затем процессор.
num_threadsне заданоЗадаёт OMP_NUM_THREADS, MKL_NUM_THREADS и OPENBLAS_NUM_THREADS для запуска, если окружение ещё не задаёт эти переменные.
auto_retrainвыкл.Переобучение по мере поступления аннотаций. См. auto_retrain.
writebackнетПубликация предсказаний как предварительных меток. См. writeback.
backendlocalБэкенд для запусков, не называющих другого.
backendsнетИменованные бэкенды ssh, slurm и agent. См. Бэкенды.
max_predictions_mb512Наибольший predictions.jsonl, который может загрузить удалённый агент.
trainer_paramsнетЗначения параметров по умолчанию, по имени тренера.
tilingenabled: autoНарезка больших изображений на плитки для тренеров детекции и сегментации. См. tiling.

Собственные params запуска переопределяют trainer_params, а те переопределяют значения тренера по умолчанию. Имя параметра, которого тренер не принимает, отклоняется при запуске сервера, если имя стоит под trainer_params, а иначе при начале запуска. Страница Тренеры показывает порядок на примере.

auto_retrain

Автоматическое переобучение проверяет, нужен ли новый запуск, после каждого сохранения аннотации:

КлючПо умолчаниюЗначение
enabledfalseВключает проверку.
trainerнетИмя тренера. Обязателен.
schemasнетСхемы для обучения. Обязательны.
min_interval_s600Сколько секунд должно пройти с завершения последнего запуска, прежде чем начнётся следующий.
update_frequency25Сколько новых аннотаций должно прийти с последнего автоматического запуска, прежде чем начнётся следующий.
params{}Параметры тренера, как в params запуска через API.
backendmodel_training.backendБэкенд для автоматических запусков.
accept_licencefalseПодтверждает лицензию тренера, который просит подтверждение (ultralytics-detect, ultralytics-segment, layoutlmv3). Без подтверждения автоматические запуски этих тренеров пропускаются.

Когда проверка решает не запускать обучение, причина появляется в поле skip_reason ответа GET /admin/training/api/status, например "waiting for 3 more annotation(s)" или "a run is already in progress". Автоматические запуски никогда не встают в очередь запусков. Следующая аннотация, сохранённая после того, как очередь опустеет, снова запускает проверку, уже с большим числом аннотаций для обучения. Potato держит счётчики аннотаций в памяти, поэтому после перезапуска проект, который уже обучался, считает новые аннотации с момента перезапуска.

writeback

Обратная запись решает, какие предсказания видят разметчики:

КлючПо умолчаниюЗначение
schemas[]Схемы, предсказания которых видят разметчики. Пустой список не показывает ничего.
min_confidence0.0Предсказания ниже порога сохраняются и не показываются. Предсказание без уверенности проходит.
fieldpredictionsПоле объекта, в которое записываются предварительные метки.
include_unlabeledfalseПредсказывает также для объектов, которые никто не разметил, и ставит им предварительные метки. Без include_unlabeled запуск предсказывает только для собственных объектов val и test.

tiling

Тренеры детекции и сегментации уменьшают каждое изображение до нескольких сотен пикселей. При таком размере объекты на снимке целого слайда или на спутниковой сцене теряются. Поэтому для схемы image_annotation, microscopy или geo_annotation Potato режет каждое большое изображение на плитки при построении обучающих данных запуска. Выборка изображения определяется до нарезки, поэтому плитки одного слайда никогда не попадают в две выборки. Предсказания переносятся обратно на целое изображение, а оценки на отложенных объектах считаются на целых изображениях. Руководство по моделям для изображений разбирает слайды и карты на практике.

КлючПо умолчаниюЗначение
enabledautoauto режет форматы слайдов (.svs, .ndpi, .mrxs, .scn и другие) и изображения, у которых длинная сторона не меньше auto_min_side. true режет каждое изображение, а false — ни одно.
auto_min_side4096Длина длинной стороны в пикселях, с которой auto начинает резать изображение.
tile_size1024Сторона плитки в пикселях, которые видит тренер.
overlap128Сколько пикселей делят соседние плитки, не больше половины tile_size. Держите перекрытие не меньше объектов, иначе крупный объект находится по частям.
downsample1Сколько пикселей полного разрешения приходится на пиксель плитки.
mppнетМикроны на пиксель плитки. Переопределяет downsample для слайда, который записывает своё разрешение.
background0.25Сколько пустых плиток выбирается на плитку с объектом. Для слайдов, размеченных лишь частично, задайте background: 0.
max_predict_tiles2000Наибольшее число плиток, предсказываемых на изображение. Сохраняются плитки с наибольшим количеством ткани.
min_visible0.4Доля объекта, которая должна лежать внутри плитки, чтобы объект обучался на этой плитке.
tissue_threshold0.05Доля плитки слайда, которая должна быть тканью, чтобы модель предсказывала на этой плитке.

Слайды читаются через openslide, который ставится командой pip install "potato-annotation[wsi]", на машине, которая строит обучающие данные. Удалённый бэкенд скачивает плитки, но никогда не слайд.

Очередь запусков

Одновременно выполняется один запуск. Запуск, начатый со страницы Training или через API во время другого запуска, ждёт, а не отклоняется. Запрос на старт возвращает 202 с queued: true и position запуска, а таблица Runs показывает запуск как waiting #N с кнопкой Cancel run. Когда выполняющийся запуск заканчивается, начинается самый старый из ожидающих.

Ожидающие запуски — это записи в журнале запусков, поэтому очередь переживает перезапуск, и первый ожидающий запуск начинается, когда сервер возвращается. Запуск, который предыдущий сервер выполнял в тот момент, одновременно помечается как interrupted. Обучающие данные ожидающего запуска строятся, когда запуск начинается, поэтому запуск обучается на аннотациях, существующих в этот момент. Старт, который был бы отклонён, например старт с неизвестной схемой, отклоняется сразу, а не когда подходит очередь запуска. Запуск, у которого схема или тренер исчезли из конфигурации во время ожидания, завершается с invalid_when_dequeued, и начинается следующий запуск.

Отправьте "queue": false в теле запроса, чтобы получить 409 вместо места в очереди. Когда уже ждут queue_max запусков, новый старт получает 429. GET /admin/training/api/status перечисляет ожидающие запуски по порядку в поле queue.

Проверки перед запуском

potato validate сообщает обо всех проблемах в блоке model_training сразу, и сервер отказывается запускаться при тех же проблемах:

bash
potato validate config.yaml --strict

Проверки охватывают такие случаи:

  • splits с именем, отличным от train, val и test, доля меньше 0 или не число, доли с нулевой суммой или отсутствие train.
  • Ключ, которого нет у writeback или auto_retrain, запись в writeback.schemas, не являющаяся схемой, или min_confidence вне диапазона от 0 до 1. accept_license сообщается как опечатка в accept_licence.
  • Включённый блок pre_annotation, у которого field отличается от writeback.field. Под таким блоком предварительная метка обучения не показывалась бы.
  • При auto_retrain.enabled несуществующий тренер или схема, схема, которой тренер учиться не может, параметры, которых тренер не принимает или которые имеют неверный тип, backend, отсутствующий в backends, или decision-calibrate на бэкенде, отличном от local.
  • Параметр под trainer_params, которого тренер не принимает или который имеет неверный тип. Внутри dp проверка охватывает также каждый ключ и его диапазон.
  • Значение grace_seconds меньше 0 или не число, а также retain_runs или split_seed меньше 0 или не целое число.
  • Под backends отсутствующий или неизвестный type, ключ, которого у типа нет, бэкенд ssh без host, значение gpus, отличное от auto, none или индексов GPU, удалённый бэкенд с именем local или model_training.backend, который не определён.

potato training check проверяет один бэкенд до того, как запуск его использует. Для local команда печатает устройство, которое получил бы запуск, например local: this machine, Apple Metal (mps) на Mac с чипом Apple. Для бэкенда ssh команда сообщает версию Python, каждый GPU с его свободной памятью, GPU, который получил бы запуск, и обучающие пакеты, которых не хватает удалённому интерпретатору. Кнопка Check на странице Training выполняет ту же проверку, а --json печатает отчёт как JSON:

bash
potato training check local config.yaml
potato training check gpu-server config.yaml

Запуск, начатый со страницы Training или через API, проверяется ещё раз в момент начала. Коды состояния перечислены в разделе Маршруты.

Бэкенды

Запуск выполняется на бэкенде, и меню Runs on на странице Training перечисляет настроенные бэкенды. model_training.backend задаёт значение по умолчанию, а запуск через API или auto_retrain может назвать другой бэкенд через backend. В Potato четыре типа бэкенда:

ТипГде работает тренерКто запускает тренера
localЭта машина, в подпроцессе. Доступен всегда и используется по умолчанию.Potato
sshДругая машина, до которой Potato добирается по ssh, например GPU-сервер.Potato, по ssh
slurmВычислительный узел кластера, как пакетное задание.Potato, по ssh на головной узел и затем sbatch
agentМашина, до которой Potato не дотянуться, например рабочая станция за NAT.Человек, командой potato training agent

Бэкенд ssh использует аутентификацию по ключу с включённым BatchMode, поэтому запрос пароля приводит к ошибке, а не к зависанию. Бэкенд slurm использует только sbatch, squeue и scancel, а также scontrol на кластерах, где scontrol есть, и требует remote_dir на хранилище, общем для вычислительных узлов. Бэкенду agent не нужен входящий порт, потому что агент сам открывает все соединения. Имя local зарезервировано за этой машиной, а decision-calibrate работает только на local. Руководство Обучение на GPU-сервере, кластере SLURM или машине за NAT проводит все три удалённых типа вместе с их ключами.

Оценки на отложенных объектах

Каждый запуск оценивает собственные предсказания на объектах val и test относительно сведённых человеческих меток. В именах метрик указана выборка, как в val_macro_f1 или test_f1. Объект с меткой и без предсказания считается ошибкой, поэтому пропуск трудных объектов не может поднять оценку тренера. <split>_coverage сообщает долю объектов, получивших предсказание.

Главная оценка показывается в столбце Held-out score таблицы Runs, а выборка и метрика указаны во всплывающей подсказке. Главная оценка — это главная метрика первой схемы на первой из выборок val и test, в которой есть объекты. Когда тренер выбрал лучшую контрольную точку по оценке val, Potato сначала пробует test, потому что тренер уже видел оценку val. Дообучающие тренеры, которые сохраняют лучшую эпоху, например hf-text-classification, torchvision-detect и llm-sft, берут главную оценку с test. sklearn-text, setfit, rdkit-property, тренеры моделей решений и мосты к моделям ничего не выбирают по val, и запуск любого из этих тренеров берёт главную оценку с val, пока в val есть объекты. Запуск без объектов val и test показывается как "not scored".

Главная метрика зависит от типа разметки схемы, как показывает таблица ниже для распространённых типов:

Тип разметкиГлавная метрика
radio, select, likertmacro-F1 (также точность и средняя абсолютная ошибка для числовых меток likert)
multiselectmicro-F1 (также macro-F1 и точное совпадение)
spanF1 по фрагментам, совпадающим по началу, концу и метке
texttoken F1 (также точное совпадение)
pairwise в режиме binaryточность по объектам, ответ на которые не был ничьей
rankingтау Кендалла
image_annotation, microscopy, geo_annotationCOCO mAP при IoU 0,5 (map_50), также записывается map_50_95
audio_annotationF1 по сегментам с одинаковой меткой при IoU не ниже 0,5
speech_transcriptword_accuracy, 1 минус доля ошибочных слов
volume_annotationmean_dice

Token F1 засчитывает ответ, где нужные слова стоят в неправильном порядке, поэтому читайте token F1 вместе с точным совпадением. Главная метрика детекции использует IoU 0,5, а не среднее от 0,5 до 0,95, потому что рамки двух разметчиков для одного объекта редко пересекаются при IoU 0,9. Таблица оценок на отложенных объектах в upstream перечисляет метрики для каждого типа разметки.

Обратная запись

После успешного запуска Potato сохраняет предсказания запуска и записывает предсказания, прошедшие четыре проверки, в поле predictions каждого объекта или в поле, которое называет writeback.field. Проверки идут в таком порядке, и отчёт об обратной записи считает каждый пропуск:

  1. Объекты выборки train никогда не получают предварительных меток. Проверка охватывает выборку train каждого запуска, ещё находящегося в журнале, а предварительная метка, оставленная на объекте более ранним запуском, снимается, когда более поздний запуск обучается на этом объекте.
  2. Публикуются только схемы из writeback.schemas. По умолчанию список пуст, поэтому включение обучения ничего не меняет для разметчиков.
  3. Отклонённые пары пропускаются. Пара из объекта и схемы с вердиктом reject в проверке модели больше не показывается.
  4. Применяется порог уверенности. Предсказание ниже min_confidence сохраняется и не публикуется.

Обратная запись никогда не меняет человеческую метку, потому что предсказания попадают в данные объекта, а разметка живёт в состоянии каждого разметчика. Предварительная метка показывается как заранее заполненный ответ, который разметчик может править, например выбор как выбранный вариант, и свободный текстовый ответ в текстовом поле схемы, и блок pre_annotation не нужен. Предварительная метка становится ответом разметчика, только когда разметчик правит её или переходит к следующему объекту. Поэтому предварительная метка, которую никто не правил и мимо которой никто не перешёл, никогда не становится обучающей меткой. Пара из разметчика и объекта, которую ai_support.holdout относит к контрольной группе исследования без помощи, предварительной метки не показывает, а данные объекта, отправленные для этой пары, не содержат ни writeback.field, ни pre_annotation.field. Отчёт об обратной записи — это поле writeback ответа GET /admin/training/api/status, а summary отчёта объясняет, почему запуск ничего не опубликовал.

Potato хранит одно предсказание на объект и схему, и предсказание более нового запуска заменяет предсказание более старого. Когда новое предсказание сохранено, но не показано, потому что оно ниже min_confidence, пусто или отклонено, предварительная метка более старого запуска сразу снимается с объекта, и отчёт об обратной записи учитывает объект в n_superseded_cleared. Предварительные метки, поставленные вместе с данными, остаются нетронутыми. При запуске сохранённые предсказания для схем из writeback.schemas записываются обратно в данные объектов под теми же четырьмя проверками, поэтому предварительные метки переживают перезапуск. Чтобы отозвать предварительные метки запуска, отправьте DELETE /admin/training/api/runs/<run_id>/predictions. Запрос удаляет сохранённые предсказания и снимает предварительные метки с объектов.

Исправленные и закреплённые объекты всегда обучают

Два вида объектов попадают в выборку train каждого последующего запуска, независимо от места объекта в стабильном разбиении:

  • Объекты, которые исправил проверяющий. Вердикт correct в проверке модели означает, что человек исправил ответ модели. Исправления приходят с объектов, на которых модель ошибалась сильнее всего, поэтому исправленный объект в val или test оценивал бы модель на выборке её собственных ошибок. Вердикты accept и reject оставляют объект там, где он был.
  • Закреплённые объекты. Кнопка Train on these рядом со срезом на странице Catalog закрепляет объекты, которые подходят под срез, например встроенный срез model-found-nothing. Закреплённый объект обучает модель, как только кто-нибудь его разметит.

Запуск, который переместил отложенные объекты в train, пишет предупреждение с их числом. Оценка такого запуска на отложенных объектах вычисляется без этих объектов и непосредственно не сопоставима с оценкой более раннего запуска. Числа лежат в stats.forced_train в manifest.json обучающих данных.

Сохранение выборки как версии датасета

Кнопка Keep this split as a dataset на странице запуска сохраняет объекты val, test или train запуска вместе с их согласованными человеческими метками как новую версию датасета. Версия датасета после этого никогда не меняется, поэтому последующие модели и промпты LLM можно сравнивать ровно на этих объектах. Функции нужен datasets.enabled: true. Каждая сохранённая версия содержит одну выборку и начинается с нуля, а не дополняет последнюю версию датасета. Иначе объекты val запуска 2, добавленные к объектам запуска 1, включали бы объекты, на которых обучался запуск 2. В inputs каждого примера нет поля предварительных меток, поэтому оценка не может прочитать ответ модели.

Откуда взялась предварительная метка

GET /admin/model-review включает provenance для каждого объекта очереди проверки, предварительную метку которого записал запуск обучения. Для каждой схемы запись называет идентификатор запуска, тренера и оценку запуска на отложенных объектах. У предварительных меток, поставленных вместе с данными, записи нет.

Где хранятся запуски

У каждого запуска есть каталог <task_dir>/<output_annotation_dir>/training/runs/<run_id>/:

ПутьСодержимое
bundle/Обучающие данные: train.jsonl, val.jsonl, test.jsonl, unlabeled.jsonl при include_unlabeled, labels.json, manifest.json и media/.
artifacts/model_card.json, predictions.jsonl и модель, например model.pkl для sklearn-text или каталог model/ для трансформерных тренеров.
spec.jsonЧто запуску было поручено сделать.
events.jsonl, stdout.log, stderr.logСобытия хода запуска и его вывод.
agent.logСобственный вывод удалённого агента, на бэкендах ssh.
bundle.tar.gzОбучающие данные в том виде, в каком их скачал агент, вместе с медиа, на удалённых бэкендах.

Журнал запусков живёт в базе данных проекта, <task_dir>/project.sqlite, и записывает запуски, выборку каждого объекта по запускам, объекты, закреплённые за обучением, сохранённые предсказания, токены агентов и публикации на Hugging Face Hub. retain_runs обрезает журнал и никогда не обрезает запуск, предсказания которого ещё хранятся, поэтому любую предварительную метку можно проследить до запуска, который её записал. Обрезка оставляет каталоги запусков на диске.

Запуск LoRA сохраняет только адаптер, от нескольких до нескольких сотен мегабайт, и загружает базовую модель по model_name, когда запуск предсказывает. Полное дообучение сохраняет всю модель. Задайте переменную окружения POTATO_MODEL_CACHE как каталог, и процесс обучения использует этот каталог для HF_HOME, TRANSFORMERS_CACHE и SENTENCE_TRANSFORMERS_HOME, если эти переменные ещё не заданы. На машине без доступа в сеть заранее положите в этот каталог модели, которые называют тренеры.

Маршруты

Страница Training и её маршруты JSON находятся под /admin/training и требуют доступа администратора. Доступ администратора означает сессию администратора или заголовок X-API-Key. Запросы POST и DELETE из браузера должны быть same-origin. Спецификация OpenAPI Potato помечает все 26 операций обучения как x-potato-requires-config: model_training.enabled: true:

МаршрутНазначение
GET /admin/trainingСтраница Training с формой запуска, списком запусков и тренерами.
GET /admin/training/runs/<run_id>Страница одного запуска со статусом, метриками, событиями и выборкой каждого объекта.
GET /admin/training/api/trainersВсе тренеры с их видами, модальностями, лицензией и состоянием установки.
GET /admin/training/api/schemasСхемы исследования, вид каждой схемы и тренеры, подходящие к каждой схеме.
GET /admin/training/api/statusТекущий или последний запуск с состоянием, ходом, метриками, предупреждениями, skip_reason, writeback и queue.
GET /admin/training/api/runsИстория запусков. ?limit= по умолчанию 50, максимум 500.
POST /admin/training/api/runsНачинает запуск. 200, когда запуск начался, и 202 с queued: true и position, когда запуск ждёт.
GET /admin/training/api/runs/<run_id>Запись одного запуска, а также review — точность предсказаний запуска по вердиктам проверки.
GET /admin/training/api/runs/<run_id>/eventsЖурнал событий запуска. ?limit= по умолчанию 200.
POST /admin/training/api/runs/<run_id>/cancelОтменяет выполняющийся или ожидающий запуск. 400 для любого другого идентификатора запуска.
DELETE /admin/training/api/runs/<run_id>/predictionsОтзывает сохранённые предсказания и предварительные метки запуска.
POST /admin/training/api/runs/<run_id>/push-to-hubПубликует модель запуска на Hugging Face Hub. См. Публикация на Hugging Face Hub.
POST /admin/training/api/runs/<run_id>/pin-splitСохраняет выборку как версию датасета, с телом {"dataset": name, "split": "val"}.
GET /admin/training/api/backendsНастроенные бэкенды.
POST /admin/training/api/backends/<name>/checkПроверяет бэкенд, как это делает potato training check.
GET /admin/training/api/pinnedЗакреплённые объекты, сгруппированные по причине.
POST /admin/training/api/pinnedЗакрепляет объекты за train, с {"slice": name} или {"instance_ids": [...]}.
DELETE /admin/training/api/pinnedОткрепляет перечисленные instance_ids или каждый закреплённый объект, если тело ничего не перечисляет.

Запрос запуска принимает trainer, schemas (список или одно имя), params, backend, accept_licence и queue. Каждый тренер обучается только на первой названной схеме. Запрос ниже начинает запуск sklearn-text на схеме sentiment из примера:

bash
curl -X POST -H "X-API-Key: $KEY" -H "Content-Type: application/json" \
  http://localhost:8000/admin/training/api/runs \
  -d '{"trainer": "sklearn-text", "schemas": ["sentiment"]}'

Отклонённый старт даёт причину в error:

СтатусКогда
400В теле нет тренера или схемы, неизвестный тренер или схема, схема, которой тренер учиться не может, тренер, которого проект запустить не может, или тренер, лицензию которого нужно подтвердить, с needs_licence_ack: true, пока запрос не задаст accept_licence: true
409Параметр, которого тренер не принимает или который имеет неверный тип или диапазон, неизвестный бэкенд, decision-calibrate на бэкенде, отличном от local, или уже выполняющийся запуск при "queue": false
429Уже ждут queue_max запусков

Протокол агента

model_training.enabled регистрирует также маршруты, которые вызывает агент обучения, под /api/training. Агент отправляет свой токен как Authorization: Bearer <token>, а отсутствующий или недействительный токен получает 401. Регистрация бэкенда вместо этого требует админский ключ API. potato/training/protocol.py описывает протокол для тех, кто пишет нового агента, а potato/training/agent.py — эталонная реализация:

МаршрутНазначение
POST /api/training/backends/registerВыдаёт токен агента для имени бэкенда, с X-API-Key. Этот маршрут вызывает potato training register.
POST /api/training/backends/<name>/heartbeatПростаивающий агент сообщает, что он жив. 403 для токена, выданного другому бэкенду.
GET /api/training/jobs/next?wait=30Длинный опрос. 200 с задачей или 204, если задача не пришла за wait секунд.
GET /api/training/jobs/<run_id>Задача, её спецификация и признак отмены задачи.
GET /api/training/jobs/<run_id>/bundleОбучающие данные в tar.gz вместе с медиа. Маршрут отвечает на запросы Range, поэтому агент возобновляет оборванную загрузку, до пяти попыток. 410, когда пакета уже нет.
POST /api/training/jobs/<run_id>/progressСобытия хода. Отмена возвращается в ответе.
POST /api/training/jobs/<run_id>/predictionspredictions.jsonl. 413 при превышении max_predictions_mb.
POST /api/training/jobs/<run_id>/completeКод выхода и итоговые события.

QLoRA

llm-sft, llm-dpo, hf-text-classification, vlm-sft и reward-model принимают lora: {quantize: 4bit} — настройку QLoRA (Dettmers et al., 2023). Базовая модель загружается с 4-битными весами NF4 и двойным квантованием, а поверх неё обучается адаптер LoRA в bf16, если GPU поддерживает bf16. quantize: 8bit — промежуточный вариант, и предсказания загружают базовую модель так же.

yaml
model_training:
  trainer_params:
    llm-sft:
      model_name: Qwen/Qwen2.5-7B-Instruct
      lora: {quantize: 4bit}

В 4 битах базовые веса занимают четверть памяти, которую те же веса занимают в bf16, а активации, адаптер и состояние оптимизатора добавляются сверху. Potato ещё не измерял память запуска QLoRA на GPU, поэтому планируйте по строке "Peak GPU memory" самого запуска. Каждый запуск трансформера пишет эту строку в конце. QLoRA требует GPU с CUDA и сборку bitsandbytes под CUDA этой машины. Запуск проверяет оба условия до загрузки модели, квантуя несколько чисел на GPU, и когда версии не совпадают, ошибка называет обе версии. Руководство по дообучению LLM применяет QLoRA к запускам SFT и DPO.

Публикация на Hugging Face Hub

У успешного запуска, модель которого лежит на сервере Potato, на странице запуска есть форма Publish to the Hugging Face Hub. При отправке выгружаются модель и карточка модели README.md, составленная по запуску, где названы тренер, базовая модель и адаптер, схемы и метки, размеры выборок, оценка на отложенных объектах с выборкой, на которой её измерили, и идентификаторы запуска и пакета. Карточка запуска dp содержит также строку "Differential privacy" с потраченным эпсилон относительно целевого, дельтой и выборкой train, которую охватывает гарантия. Строка опускает целевое значение или дельту, если запуск не записал это значение.

Выгружается фиксированный список файлов, а не весь каталог artifacts/. В списке файлы весов, например .safetensors, .bin, .pt и .pkl, файлы конфигурации и токенизатора в сохранённом каталоге model/, model_card.json с локальными путями, заменёнными именами файлов, и calibration.json. Ответы модели на объекты проекта (predictions.jsonl и raw_answers.jsonl для моделей решений) остаются на сервере. Контрольные точки, состояние оптимизатора, копии обучающих данных, которые делают некоторые тренеры (yolo_data/, wev_data/, laya_data/), и любая символическая ссылка, указывающая за пределы artifacts/, тоже не выгружаются.

Форма защищает от случайной или публичной отправки несколькими способами:

  • Название репозитория вводится дважды, и отправка проходит, только если оба названия совпадают.
  • Флажок Private по умолчанию отмечен. Пока Private отмечен, Potato не отправляет в существующий публичный репозиторий, а API отвечает 409.
  • Форма называет переменную окружения на сервере, по умолчанию HF_TOKEN, в которой лежит токен записи Hugging Face. Сам токен на странице никогда не вводится. Имя переменной должно содержать TOKEN или начинаться с HF_, а значение должно начинаться с hf_, поэтому значение другой переменной не может попасть на Hub.
  • Когда Hub не может сказать, существует ли репозиторий, ничего не отправляется, а репозиторий, который создала отправка, снова удаляется, если выгрузка затем не удалась.
  • Лицензия карточки модели — это идентификатор лицензии Hub, который вы указываете, например apache-2.0. Если его нет, в карточке сказано, что действует лицензия базовой модели. Тренеру, лицензию которого нужно подтвердить, например ultralytics-detect (AGPL-3.0), для отправки нужно то же подтверждение.
  • Модель, оставленную на удалённом хосте с fetch_artifacts: false или обученную на бэкенде agent, с сервера опубликовать нельзя, и ошибка называет, где находится модель.

Каждая отправка — один коммит. Страница запуска перечисляет каждую отправку с репозиторием, видимостью и коммитом, а журнал записывает, кто отправил. Через API тело POST /admin/training/api/runs/<run_id>/push-to-hub принимает repo_id, confirm_repo_id, private (по умолчанию true), token_env (по умолчанию HF_TOKEN), licence и accept_licence. Маршрут возвращает 201 с коммитом, 400 при несовпадении, отсутствующей переменной токена, отсутствии файлов модели или неподтверждённой лицензии и 502, когда Hub отказывает.

Устранение неполадок

Записи ниже охватывают ошибки, наиболее вероятные при первой настройке. Список устранения неполадок в upstream охватывает драйверы GPU, сборки CUDA и сообщения отдельных тренеров.

  • /admin/training возвращает 404. model_training.enabled не равен true, а Potato регистрирует маршруты только когда ключ равен true.
  • "Only N items in the train split". Разметьте больше объектов или уменьшите min_instances в params запуска. По умолчанию выборка train содержит 70% размеченных объектов.
  • "Schema 'x' has 1 distinct label(s) in the data". Классификатору нужно как минимум две используемые метки.
  • "No resolved annotations to train on". Схема, названная в запуске, отличается от размечаемой схемы, или никто ещё ничего не разметил.
  • Запуск не опубликовал предварительных меток. Прочитайте отчёт writeback в GET /admin/training/api/status. "No predictions were published: write-back is not enabled for any schema" означает, что writeback.schemas пуст, а счётчики пропусков показывают, сколько предсказаний убрала каждая проверка.
  • <trainer> does not take <name>. Параметр в запуске или под trainer_params написан с опечаткой или относится к другому тренеру. Сообщение перечисляет имена, которые принимает тренер.
  • Запуск был убит после нехватки памяти на машине. Процесс завершился по SIGKILL, обычно из-за убийцы по нехватке памяти. Возьмите модель поменьше или меньше объектов либо задайте max_ram_mb, чтобы запуск завершился ошибкой в рамках своего лимита.
  • "Stopped: the run took longer than model_training.max_wall_seconds". Запуск достиг лимита времени. Увеличьте max_wall_seconds или обучайте на меньшем числе объектов.
  • "The GPU ran out of memory". Уменьшите batch_size и увеличьте gradient_accumulation, чтобы сохранить эффективный размер батча, задайте lora: true или lora: {quantize: 4bit}, а для llm-sft задайте gradient_checkpointing: true или выберите модель поменьше.
  • "ssh to host failed: Permission denied". Potato запускает ssh с BatchMode=yes, поэтому ssh <host> true должен выполняться из учётной записи сервера без запроса. Ключ с парольной фразой работает, когда его держит ssh-agent.
  • Запуск на бэкенде agent остаётся в очереди. Ни один агент с этим именем бэкенда не опрашивает сервер. Запустите агента командой potato training agent --backend <name> и проверьте токен кнопкой Check на странице Training.

Дополнительные материалы

Источники