{
  "$id": "https://schema.rtemis.org/hyperparameters/mlp/v1/schema.json",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "rtemis MLPHyperparameters",
  "description": "Multilayer perceptron (torch). See `setup_MLP`.",
  "type": "object",
  "properties": {
    "hidden_units": {
      "description": "Units in each hidden layer, one value per layer, so the length is the depth. NULL generates the widths from the shape settings.",
      "oneOf": [
        {
          "type": "null"
        },
        {
          "type": "array",
          "items": {
            "type": "integer",
            "minimum": 1
          },
          "minItems": 1
        },
        {
          "type": "object",
          "properties": {
            "candidates": {
              "description": "Values to tune over; the tuner selects one.",
              "type": "array",
              "items": {
                "type": "array",
                "items": {
                  "type": "integer",
                  "minimum": 1
                },
                "minItems": 1
              },
              "minItems": 2
            }
          },
          "required": ["candidates"],
          "additionalProperties": false
        }
      ],
      "x-rtemis": {
        "type": "integer",
        "container": "array",
        "tunable": true
      }
    },
    "shape": {
      "description": "Profile of the generated hidden layer widths. Ignored when hidden_units is set.",
      "oneOf": [
        {
          "type": "null"
        },
        {
          "type": "string",
          "enum": ["funnel", "constant", "triangle", "long_funnel", "diamond", "hexagon", "stairs"]
        },
        {
          "type": "object",
          "properties": {
            "candidates": {
              "description": "Values to tune over; the tuner selects one.",
              "type": "array",
              "items": {
                "type": "string",
                "enum": ["funnel", "constant", "triangle", "long_funnel", "diamond", "hexagon", "stairs"]
              },
              "minItems": 2
            }
          },
          "required": ["candidates"],
          "additionalProperties": false
        }
      ],
      "x-rtemis": {
        "type": "string",
        "tunable": true
      }
    },
    "shape_layers": {
      "description": "Number of hidden layers to generate. Ignored when hidden_units is set.",
      "oneOf": [
        {
          "type": "null"
        },
        {
          "type": "integer",
          "minimum": 1
        },
        {
          "type": "object",
          "properties": {
            "candidates": {
              "description": "Values to tune over; the tuner selects one.",
              "type": "array",
              "items": {
                "type": "integer",
                "minimum": 1
              },
              "minItems": 2
            }
          },
          "required": ["candidates"],
          "additionalProperties": false
        }
      ],
      "x-rtemis": {
        "type": "integer",
        "tunable": true
      }
    },
    "shape_max_units": {
      "description": "Widest generated hidden layer. NULL derives it from the encoded input width. Ignored when hidden_units is set.",
      "oneOf": [
        {
          "type": "null"
        },
        {
          "type": "integer",
          "minimum": 1
        },
        {
          "type": "object",
          "properties": {
            "candidates": {
              "description": "Values to tune over; the tuner selects one.",
              "type": "array",
              "items": {
                "type": "integer",
                "minimum": 1
              },
              "minItems": 2
            }
          },
          "required": ["candidates"],
          "additionalProperties": false
        }
      ],
      "x-rtemis": {
        "type": "integer",
        "tunable": true
      }
    },
    "activation": {
      "description": "Activation applied after every hidden layer.",
      "oneOf": [
        {
          "type": "string",
          "enum": ["relu", "gelu", "silu", "elu", "selu", "leaky_relu", "tanh"]
        },
        {
          "type": "object",
          "properties": {
            "candidates": {
              "description": "Values to tune over; the tuner selects one.",
              "type": "array",
              "items": {
                "type": "string",
                "enum": ["relu", "gelu", "silu", "elu", "selu", "leaky_relu", "tanh"]
              },
              "minItems": 2
            }
          },
          "required": ["candidates"],
          "additionalProperties": false
        }
      ],
      "x-rtemis": {
        "type": "string",
        "tunable": true
      }
    },
    "norm": {
      "description": "Normalization applied in every hidden layer. NULL applies none.",
      "oneOf": [
        {
          "type": "null"
        },
        {
          "type": "string",
          "enum": ["batch_norm", "layer_norm"]
        },
        {
          "type": "object",
          "properties": {
            "candidates": {
              "description": "Values to tune over; the tuner selects one.",
              "type": "array",
              "items": {
                "type": "string",
                "enum": ["batch_norm", "layer_norm"]
              },
              "minItems": 2
            }
          },
          "required": ["candidates"],
          "additionalProperties": false
        }
      ],
      "x-rtemis": {
        "type": "string",
        "tunable": true
      }
    },
    "norm_first": {
      "description": "Normalize before the activation rather than after it.",
      "type": "boolean",
      "x-rtemis": {
        "type": "boolean"
      }
    },
    "bias": {
      "description": "Give every hidden layer and the output layer a bias term.",
      "type": "boolean",
      "x-rtemis": {
        "type": "boolean"
      }
    },
    "residual": {
      "description": "Add a residual connection around every hidden layer, projected when the layer changes width.",
      "oneOf": [
        {
          "type": "boolean"
        },
        {
          "type": "object",
          "properties": {
            "candidates": {
              "description": "Values to tune over; the tuner selects one.",
              "type": "array",
              "items": {
                "type": "boolean"
              },
              "minItems": 2
            }
          },
          "required": ["candidates"],
          "additionalProperties": false
        }
      ],
      "x-rtemis": {
        "type": "boolean",
        "tunable": true
      }
    },
    "dropout": {
      "description": "Dropout probability applied after every hidden layer.",
      "oneOf": [
        {
          "type": "number",
          "minimum": 0,
          "exclusiveMaximum": 1
        },
        {
          "type": "object",
          "properties": {
            "candidates": {
              "description": "Values to tune over; the tuner selects one.",
              "type": "array",
              "items": {
                "type": "number",
                "minimum": 0,
                "exclusiveMaximum": 1
              },
              "minItems": 2
            }
          },
          "required": ["candidates"],
          "additionalProperties": false
        }
      ],
      "x-rtemis": {
        "type": "number",
        "tunable": true
      }
    },
    "input_dropout": {
      "description": "Dropout probability applied to the encoded input.",
      "oneOf": [
        {
          "type": "number",
          "minimum": 0,
          "exclusiveMaximum": 1
        },
        {
          "type": "object",
          "properties": {
            "candidates": {
              "description": "Values to tune over; the tuner selects one.",
              "type": "array",
              "items": {
                "type": "number",
                "minimum": 0,
                "exclusiveMaximum": 1
              },
              "minItems": 2
            }
          },
          "required": ["candidates"],
          "additionalProperties": false
        }
      ],
      "x-rtemis": {
        "type": "number",
        "tunable": true
      }
    },
    "weight_decay": {
      "description": "L2 penalty, decoupled from the gradient under the adamw optimizer.",
      "oneOf": [
        {
          "type": "number",
          "minimum": 0
        },
        {
          "type": "object",
          "properties": {
            "candidates": {
              "description": "Values to tune over; the tuner selects one.",
              "type": "array",
              "items": {
                "type": "number",
                "minimum": 0
              },
              "minItems": 2
            }
          },
          "required": ["candidates"],
          "additionalProperties": false
        }
      ],
      "x-rtemis": {
        "type": "number",
        "tunable": true
      }
    },
    "l1_penalty": {
      "description": "L1 penalty on the linear weights, added to the loss. Not interchangeable with weight_decay, which is L2.",
      "oneOf": [
        {
          "type": "number",
          "minimum": 0
        },
        {
          "type": "object",
          "properties": {
            "candidates": {
              "description": "Values to tune over; the tuner selects one.",
              "type": "array",
              "items": {
                "type": "number",
                "minimum": 0
              },
              "minItems": 2
            }
          },
          "required": ["candidates"],
          "additionalProperties": false
        }
      ],
      "x-rtemis": {
        "type": "number",
        "tunable": true
      }
    },
    "embeddings": {
      "description": "Represent each categorical feature by a learned embedding. FALSE one-hot encodes them instead.",
      "type": "boolean",
      "x-rtemis": {
        "type": "boolean"
      }
    },
    "embedding_dim": {
      "description": "Width of every embedding. NULL sizes each from its feature's cardinality.",
      "oneOf": [
        {
          "type": "null"
        },
        {
          "type": "integer",
          "minimum": 1
        },
        {
          "type": "object",
          "properties": {
            "candidates": {
              "description": "Values to tune over; the tuner selects one.",
              "type": "array",
              "items": {
                "type": "integer",
                "minimum": 1
              },
              "minItems": 2
            }
          },
          "required": ["candidates"],
          "additionalProperties": false
        }
      ],
      "x-rtemis": {
        "type": "integer",
        "tunable": true
      }
    },
    "embedding_dropout": {
      "description": "Dropout probability applied to the concatenated embeddings.",
      "oneOf": [
        {
          "type": "number",
          "minimum": 0,
          "exclusiveMaximum": 1
        },
        {
          "type": "object",
          "properties": {
            "candidates": {
              "description": "Values to tune over; the tuner selects one.",
              "type": "array",
              "items": {
                "type": "number",
                "minimum": 0,
                "exclusiveMaximum": 1
              },
              "minItems": 2
            }
          },
          "required": ["candidates"],
          "additionalProperties": false
        }
      ],
      "x-rtemis": {
        "type": "number",
        "tunable": true
      }
    },
    "optimizer": {
      "description": "Optimization algorithm.",
      "oneOf": [
        {
          "type": "string",
          "enum": ["adamw", "adam", "sgd", "rmsprop"]
        },
        {
          "type": "object",
          "properties": {
            "candidates": {
              "description": "Values to tune over; the tuner selects one.",
              "type": "array",
              "items": {
                "type": "string",
                "enum": ["adamw", "adam", "sgd", "rmsprop"]
              },
              "minItems": 2
            }
          },
          "required": ["candidates"],
          "additionalProperties": false
        }
      ],
      "x-rtemis": {
        "type": "string",
        "tunable": true
      }
    },
    "lr": {
      "description": "Learning rate.",
      "oneOf": [
        {
          "type": "number",
          "exclusiveMinimum": 0
        },
        {
          "type": "object",
          "properties": {
            "candidates": {
              "description": "Values to tune over; the tuner selects one.",
              "type": "array",
              "items": {
                "type": "number",
                "exclusiveMinimum": 0
              },
              "minItems": 2
            }
          },
          "required": ["candidates"],
          "additionalProperties": false
        }
      ],
      "x-rtemis": {
        "type": "number",
        "tunable": true
      }
    },
    "beta1": {
      "description": "Exponential decay rate of the first moment estimate. NULL leaves the torch default. Applies only when optimizer is adamw or adam.",
      "type": ["number", "null"],
      "minimum": 0,
      "exclusiveMaximum": 1,
      "x-rtemis": {
        "type": "number",
        "applies_when": {
          "optimizer": ["adamw", "adam"]
        }
      }
    },
    "beta2": {
      "description": "Exponential decay rate of the second moment estimate. NULL leaves the torch default. Applies only when optimizer is adamw or adam.",
      "type": ["number", "null"],
      "minimum": 0,
      "exclusiveMaximum": 1,
      "x-rtemis": {
        "type": "number",
        "applies_when": {
          "optimizer": ["adamw", "adam"]
        }
      }
    },
    "eps": {
      "description": "Term added to the denominator for numerical stability. NULL leaves the torch default. Applies only when optimizer is adamw, adam or rmsprop.",
      "type": ["number", "null"],
      "exclusiveMinimum": 0,
      "x-rtemis": {
        "type": "number",
        "applies_when": {
          "optimizer": ["adamw", "adam", "rmsprop"]
        }
      }
    },
    "momentum": {
      "description": "Momentum factor. NULL leaves the torch default. Applies only when optimizer is sgd or rmsprop.",
      "type": ["number", "null"],
      "minimum": 0,
      "x-rtemis": {
        "type": "number",
        "applies_when": {
          "optimizer": ["sgd", "rmsprop"]
        }
      }
    },
    "lr_scheduler": {
      "description": "Learning-rate schedule, configured from the epoch budget. NULL holds the learning rate fixed.",
      "type": ["string", "null"],
      "enum": [
        "step",
        "cosine_annealing",
        "one_cycle",
        "reduce_on_plateau",
        null
      ],
      "x-rtemis": {
        "type": "string"
      }
    },
    "batch_size": {
      "description": "Cases per optimization step.",
      "oneOf": [
        {
          "type": "integer",
          "minimum": 1
        },
        {
          "type": "object",
          "properties": {
            "candidates": {
              "description": "Values to tune over; the tuner selects one.",
              "type": "array",
              "items": {
                "type": "integer",
                "minimum": 1
              },
              "minItems": 2
            }
          },
          "required": ["candidates"],
          "additionalProperties": false
        }
      ],
      "x-rtemis": {
        "type": "integer",
        "tunable": true
      }
    },
    "max_epochs": {
      "description": "Largest number of passes over the training set.",
      "oneOf": [
        {
          "type": "integer",
          "minimum": 1
        },
        {
          "type": "object",
          "properties": {
            "candidates": {
              "description": "Values to tune over; the tuner selects one.",
              "type": "array",
              "items": {
                "type": "integer",
                "minimum": 1
              },
              "minItems": 2
            }
          },
          "required": ["candidates"],
          "additionalProperties": false
        }
      ],
      "x-rtemis": {
        "type": "integer",
        "tunable": true
      }
    },
    "patience": {
      "description": "Epochs without validation improvement before stopping early. Requires validation data; without it the fit runs the full epoch budget.",
      "type": "integer",
      "minimum": 1,
      "x-rtemis": {
        "type": "integer"
      }
    },
    "max_grad_norm": {
      "description": "Clip the gradient norm to this value before each step. NULL does not clip.",
      "oneOf": [
        {
          "type": "null"
        },
        {
          "type": "number",
          "exclusiveMinimum": 0
        },
        {
          "type": "object",
          "properties": {
            "candidates": {
              "description": "Values to tune over; the tuner selects one.",
              "type": "array",
              "items": {
                "type": "number",
                "exclusiveMinimum": 0
              },
              "minItems": 2
            }
          },
          "required": ["candidates"],
          "additionalProperties": false
        }
      ],
      "x-rtemis": {
        "type": "number",
        "tunable": true
      }
    },
    "loss": {
      "description": "Training objective. NULL = set from outcome type.",
      "type": ["string", "null"],
      "enum": [
        "mse",
        "l1",
        "smooth_l1",
        "cross_entropy",
        null
      ],
      "x-rtemis": {
        "type": "string",
        "default_on_null": true
      }
    },
    "device": {
      "description": "Compute device. On mps a seed does not reach dropout, so a fit using it is not reproducible; the run says so.",
      "type": ["string", "null"],
      "enum": [
        "cpu",
        "cuda",
        "mps",
        null
      ],
      "x-rtemis": {
        "type": "string"
      }
    },
    "seed": {
      "description": "Random seed for weight initialization, dropout and batch shuffling. NULL leaves them drawn from the ambient RNG.",
      "type": ["integer", "null"],
      "x-rtemis": {
        "type": "integer"
      }
    },
    "num_workers": {
      "description": "Subprocesses used to load batches. 0 loads them in the main process.",
      "type": "integer",
      "minimum": 0,
      "x-rtemis": {
        "type": "integer"
      }
    },
    "drop_last": {
      "description": "Drop the last incomplete batch of each training epoch.",
      "type": "boolean",
      "x-rtemis": {
        "type": "boolean"
      }
    },
    "ifw": {
      "description": "Inverse Frequency Weighting in classification.",
      "oneOf": [
        {
          "type": "boolean"
        },
        {
          "type": "object",
          "properties": {
            "candidates": {
              "description": "Values to tune over; the tuner selects one.",
              "type": "array",
              "items": {
                "type": "boolean"
              },
              "minItems": 2
            }
          },
          "required": ["candidates"],
          "additionalProperties": false
        }
      ],
      "x-rtemis": {
        "type": "boolean",
        "tunable": true
      }
    }
  },
  "additionalProperties": false
}
