JSONC: комментарии и висящие запятые #

jsonc
{
  // строчный комментарий
  "project": "test", /* блочный комментарий */
  "train": {
    "epochs": 40,   // допустима висящая запятая
  },
}

Кузня убирает комментарии и висящие запятые перед разбором — можно писать конфиги как обычный код.

Корень #

ПутьТипПо умолчаниюОписание
projectstring"untitled"Имя проекта. Показывается в Discord и заголовке рана.
run_namestring"auto""auto" — генерирует читаемое случайное имя, например yasnyy-gorn-k3f9.
taskenum"supervised"Тип задачи: supervised или rl.
seedint1337Seed для воспроизводимости (torch, numpy, random). Диапазон [0, 2³¹−1].
deviceenum"auto"Устройство: auto (выбирает CUDA > MPS > CPU), cpu, cuda, mps.

Раздел: model #

ПутьТипПо умолчаниюОписание
model.input_dimint ≥12Размерность входа. При загрузке CSV/NPZ автоматически исправляется под реальные данные.
model.output_dimint ≥13Размерность выхода (число классов для классификации, 1 для регрессии).
model.layerslayers[]2×linear(64)+reluСлои скрытой части. Последний linear-head добавляется автоматически.

Типы слоёв

ТипПараметрыПримечание
linearunits (обязательно), bias (bool, default true)Полносвязный слой. Последний head добавляется автоматически.
relu, gelu, tanh, sigmoid, siluАктивационные функции без параметров.
leaky_relunegative_slope (default 0.01)LeakyReLU с настраиваемым наклоном.
dropoutp (default 0.1, диапазон [0, 1))Случайное обнуление нейронов при обучении.
batchnormBatchNorm1d для линейных слоёв.
layernormLayerNorm. Нельзя использовать после conv2d.
flattenРазворачивает тензор. Нужен перед linear после conv2d.
conv2dchannels (обязательно), kernel_size (default 3), stride, paddingТребует python:-хука для загрузки изображений.
maxpool2d, avgpool2dТолько после conv2d.
lstm, gruhidden_size (default 64), num_layers (default 1), bidirectional (bool)Рекуррентные слои для последовательностей.
embeddingnum_embeddings (обязательно), embedding_dim (default 32)Таблица эмбеддингов.

Раздел: data #

ПутьТипПо умолчаниюОписание
data.sourcestring"builtin:spirals"Источник данных (см. форматы ниже).
data.n_samplesint ≥163000Число семплов для встроенных генераторов. Игнорируется для CSV/NPZ.
data.val_splitfloat [0, 0.9]0.2Доля валидационной выборки. 0 — без валидации.
data.batch_sizeint ≥164Размер батча. Автоматически уменьшается, если больше датасета.
data.normalizebooltrueНормализация по статистикам обучающей выборки.
data.noisefloat ≥00.08Уровень шума для встроенных генераторов.

Форматы data.source

ФорматПримерОписание
builtin:*builtin:spiralsВстроенные: spirals, moons, xor, blobs, sine.
Путь к CSVdata/iris.csvАвто-определение заголовка и разделителя. Последняя колонка — метка.
Путь к NPZdata/dataset.npzОжидает массивы X и y (или inputs/labels).
python:модуль:функцияpython:mydata:loadФункция возвращает кортеж (X, y).

Раздел: train #

ПутьТипПо умолчаниюОписание
train.epochsint ≥140Число эпох.
train.lossenum"cross_entropy"Функция потерь (см. таблицу ниже).
train.grad_clipfloat ≥01.0Clipping градиентов. 0 — выключить.
train.log_everyint ≥11Логировать каждые N эпох. Увеличьте до 5–10 при rate-limit Discord.

Подраздел: train.optimizer

ПутьТипПо умолчаниюОписание
train.optimizer.nameenum"adamw"Оптимизатор: adam, adamw, sgd, rmsprop, adagrad, nadam.
train.optimizer.lrfloat [1e-8, 10]0.003Learning rate.
train.optimizer.weight_decayfloat ≥00.01L2-регуляризация.
train.optimizer.momentumfloat [0, 1]0.9Momentum (только для SGD и RMSprop; игнорируется Adam-подобными).

Подраздел: train.scheduler

ПутьТипПо умолчаниюОписание
train.scheduler.nameenum"cosine"Планировщик: none, cosine, step, exponential, plateau, onecycle.
train.scheduler.warmup_epochsint ≥02Линейный прогрев LR. 0 — выключить. Сбрасывается в 0 если ≥ epochs.
train.scheduler.step_sizeint ≥110Шаг для step и half-patience для plateau.
train.scheduler.gammafloat [0, 1]0.5Множитель для step, exponential, plateau.

Подраздел: train.early_stop

ПутьТипПо умолчаниюОписание
train.early_stop.enabledbooltrueВключить early stopping.
train.early_stop.metricstring"val_loss"Метрика для слежения. Метрики с acc, return, r2 — max; остальные — min.
train.early_stop.patienceint ≥110Эпох без улучшения до остановки.
train.early_stop.min_deltafloat ≥00.0001Минимальное улучшение, которое считается прогрессом.

Подраздел: train.checkpoint

ПутьТипПо умолчаниюОписание
train.checkpoint.keep_bestbooltrueВсегда сохранять best.pt.
train.checkpoint.every_epochsint ≥00Сохранять чекпоинт каждые N эпох. 0 — только лучший.
train.checkpoint.metricstring"val_loss"Метрика для отбора лучшего чекпоинта.

Функции потерь #

ЗначениеPyTorchКогда использовать
cross_entropyCrossEntropyLossМногоклассовая классификация. Требует output_dim ≥ 2.
mseMSELossРегрессия (числовой выход).
maeL1LossРегрессия, устойчивая к выбросам.
bceBCELossБинарная классификация с sigmoid на выходе.
bce_logitsBCEWithLogitsLossБинарная классификация, включает sigmoid внутри.
huberHuberLossРегрессия: мягкое сочетание MSE и MAE.
nllNLLLossПосле log_softmax. Требует output_dim ≥ 2.

Раздел: simulation #

Используется только при task = "rl".

ПутьТипПо умолчаниюОписание
simulation.enabledboolfalseПри task=rl принудительно выставляется в true.
simulation.pathstring""Путь к .py-файлу среды.
simulation.inline_codecode""Код среды прямо в конфиге. Приоритетнее path.
simulation.entrystring"make_env"Имя фабрики или класса среды.
simulation.algoenum"ppo"Алгоритм: ppo, reinforce, dqn.
simulation.episodesint ≥1300Число эпизодов.
simulation.max_stepsint ≥1200Максимум шагов в эпизоде.
simulation.gammafloat [0, 1]0.99Discount factor.
simulation.gae_lambdafloat [0, 1]0.95GAE-λ (только PPO).
simulation.clip_epsfloat [0, 1]0.2PPO clip ε.
simulation.entropy_coeffloat ≥00.01Коэффициент энтропийного бонуса.
simulation.value_coeffloat ≥00.5Вес loss value-функции.
simulation.rollout_episodesint ≥18Эпизодов перед каждым обновлением политики.
simulation.update_epochsint ≥14Проходов по собранному батчу (PPO).
simulation.timeout_secondsfloat ≥030.0Таймаут одного шага/reset. >0 — изолировать в подпроцессе. 0 — in-process (быстрее, без изоляции).

Раздел: discord #

Подраздел: discord.presence

ПутьТипПо умолчаниюОписание
discord.presence.enabledboolfalseВключить Rich Presence.
discord.presence.client_idstring""Application ID из discord.com/developers. Без него presence отключается.
discord.presence.large_imagestring"kuznya"Ключ арта, загруженного в портал разработчика.
discord.presence.small_imagestring""Ключ малой иконки.
discord.presence.show_metricsbooltrueПоказывать текущую метрику в строке статуса.
discord.presence.buttonsbuttons[][]До 2 кнопок: [{"label": "...", "url": "https://..."}]. Метки ≤ 31 байт.

Подраздел: discord.webhook

ПутьТипПо умолчаниюОписание
discord.webhook.enabledboolfalseВключить вебхук.
discord.webhook.url_envstring"KUZNYA_WEBHOOK_URL"Имя переменной окружения с URL вебхука. Никогда не пишите URL напрямую в конфиг, который попадёт в git.
discord.webhook.urlsecret""URL напрямую. Редактируется в UI. Не хранится в экспорте.
discord.webhook.live_panelbooltrueОдно сообщение редактируется на месте (1 POST + N PATCH).
discord.webhook.notifylist["run_start","run_end","best","crash"]События для отправки.
discord.webhook.attach_curvesbooltrueПрикладывать PNG с графиком потерь к финальной карточке.

Раздел: output #

ПутьТипПо умолчаниюОписание
output.dirstring"runs"Корневая папка для артефактов ранов.
output.save_curvesbooltrueСохранять кривые в MetricStore.

Межполевые правила валидации #

Эти правила нельзя выразить в плоской схеме — они проверяются в config.validate():

УсловиеПоведение
train.loss in (cross_entropy, nll) и model.output_dim < 2Ошибка Используй mse для регрессии.
simulation.enabled = true без path и inline_codeОшибка Укажи код среды.
simulation.path и simulation.inline_code оба заданыПредупреждение Приоритет у inline_code.
simulation.enabled = true и task = supervisedПредупреждение task автоматически переключается в rl.
discord.presence.enabled = true без client_idПредупреждение Presence отключается.
discord.webhook.enabled = true без URLПредупреждение Webhook отключается.
train.scheduler.warmup_epochs ≥ train.epochsПредупреждение warmup_epochs сбрасывается в 0.
data.batch_size > data.n_samplesПредупреждение batch_size уменьшается до n_samples // 4.
data.val_split ≤ 0 и train.early_stop.enabled = trueПредупреждение early_stop.metric переключается на train_loss.
model.input_dim не совпадает с реальной размерностью данныхПредупреждение Исправляется автоматически.

Примеры конфигов #

1. Бинарная классификация (CSV)

json
{
  "project": "fraud-detection",
  "task": "supervised",
  "model": {
    "input_dim": 30,
    "output_dim": 2,
    "layers": [
      {"type": "linear", "units": 128}, {"type": "relu"},
      {"type": "dropout", "p": 0.3},
      {"type": "linear", "units": 64},  {"type": "relu"}
    ]
  },
  "data": {
    "source": "data/fraud.csv",
    "val_split": 0.15,
    "batch_size": 128,
    "normalize": true
  },
  "train": {
    "epochs": 50,
    "loss": "cross_entropy",
    "optimizer": {"name": "adamw", "lr": 0.001, "weight_decay": 0.01},
    "scheduler": {"name": "plateau"}
  }
}

2. Регрессия с LSTM

json
{
  "project": "time-series",
  "task": "supervised",
  "model": {
    "input_dim": 10,
    "output_dim": 1,
    "layers": [
      {"type": "lstm", "hidden_size": 64, "num_layers": 2},
      {"type": "dropout", "p": 0.2}
    ]
  },
  "data": {
    "source": "data/ts.npz",
    "batch_size": 32
  },
  "train": {
    "epochs": 100,
    "loss": "mse",
    "optimizer": {"name": "adam", "lr": 0.001},
    "scheduler": {"name": "cosine", "warmup_epochs": 5}
  }
}

3. RL: PPO на встроенном gridworld

json
{
  "project": "gridworld-ppo",
  "task": "rl",
  "model": {
    "layers": [
      {"type": "linear", "units": 64}, {"type": "tanh"},
      {"type": "linear", "units": 64}, {"type": "tanh"}
    ]
  },
  "simulation": {
    "enabled": true,
    "path": "sims/gridworld.py",
    "algo": "ppo",
    "episodes": 300,
    "max_steps": 200,
    "gamma": 0.99,
    "gae_lambda": 0.95,
    "clip_eps": 0.2,
    "timeout_seconds": 30.0
  },
  "train": {
    "optimizer": {"name": "adam", "lr": 0.0003},
    "grad_clip": 0.5
  }
}

4. Supervised + Discord webhook

json
{
  "project": "mnist-demo",
  "task": "supervised",
  "model": {
    "input_dim": 784,
    "output_dim": 10,
    "layers": [
      {"type": "linear", "units": 256}, {"type": "relu"},
      {"type": "linear", "units": 128}, {"type": "relu"}
    ]
  },
  "data": {
    "source": "python:mydata:load_mnist",
    "batch_size": 256
  },
  "train": {
    "epochs": 20,
    "loss": "cross_entropy",
    "optimizer": {"name": "adamw", "lr": 0.001}
  },
  "discord": {
    "webhook": {
      "enabled": true,
      "url_env": "KUZNYA_WEBHOOK_URL",
      "live_panel": true,
      "attach_curves": true
    }
  }
}

5. RL с inline кодом среды

json
{
  "project": "my-game",
  "task": "rl",
  "simulation": {
    "enabled": true,
    "inline_code": "class Env:\n    n_actions = 2\n    def reset(self):\n        self.x = 0\n        return [float(self.x)]\n    def step(self, a):\n        self.x += 1 if a else -1\n        done = abs(self.x) >= 5\n        return [float(self.x)], -0.1 if not done else 1.0, done, {}\ndef make_env(): return Env()",
    "algo": "ppo",
    "episodes": 200,
    "timeout_seconds": 0
  },
  "train": {
    "optimizer": {"name": "adam", "lr": 0.003}
  }
}