How to Define a Complete Configuration Space with Hyperparameter Specifications in Hypster

You define a complete configuration space in Hypster by writing a Python function that uses the HP object to declare parameters with types, bounds, and optional HPO metadata, then calling instantiate() to validate and materialize concrete values.

The Hypster library (gilad-rubin/hypster) provides a declarative API for building configuration spaces that bridge the gap between static configuration files and hyperparameter optimization frameworks like Optuna. By leveraging Python functions and the HP class, you can encode complex parameter relationships, validation rules, and search space definitions in a single, readable structure.

The Core Architecture of Hypster Configuration Spaces

Hypster's architecture consists of several coordinated layers that transform a user-defined configuration function into a validated, optionally optimizable parameter space.

The instantiate Entry Point

The primary entry point in [src/hypster/core.py](https://github.com/gilad-rubin/hypster/blob/master/src/hypster/core.py#L17) orchestrates the configuration flow. The instantiate(config_func, values=...) function:

  1. Validates the signature of your configuration function
  2. Creates an HP instance populated with supplied values
  3. Executes the function to build the configuration space
  4. Checks for unknown parameters via _handle_unknown_parameters (lines 73-106)

This final validation step can warn, raise, or ignore unused keys and even suggests similar names using suggest_similar_names from [src/hypster/utils.py](https://github.com/gilad-rubin/hypster/blob/master/src/hypster/utils.py).

The HP Class API

The HP class in src/hypster/hp.py provides the public interface for parameter declaration. Key methods include:

  • int – Integer parameters with optional min/max bounds
  • float – Floating-point values with precision control
  • select – Single choice from a list of options
  • multi_int, multi_float, multi_text, multi_bool – Multi-value parameters
  • text – String parameters
  • bool – Boolean flags
  • nest – Nested configuration spaces

Each method delegates to specification objects (SingleValueSpec, MultiValueSpec, SelectSingleSpec, SelectMultiSpec) and low-level handlers that manage parameter registration.

Validation and Type Safety

The validators in [src/hypster/hp_calls.py](https://github.com/gilad-rubin/hypster/blob/master/src/hypster/hp_calls.py) enforce constraints at definition time:

  • IntValidator and FloatValidator perform bounds checking via validate_bounds to ensure values satisfy min/max constraints
  • SelectValidator validates categorical choices against available options
  • MultiValidator handles multi-value parameter validation

The optional strict flag prevents silent type down-casting, while name validation ensures the name= parameter is supplied when using value overrides.

HPO Metadata Definitions

For hyperparameter optimization, src/hypster/hpo/types.py defines data classes that extend parameters with search space metadata:

  • HpoInt – Configures step sizes, logarithmic scaling (scale="log"), and inclusive-max flags
  • HpoFloat – Supports step quantization, scaling modes, and distributions like loguniform
  • HpoCategorical – Enables ordered categorical flags and optional weight vectors for sampling bias

Pass these as the hpo_spec= argument to any HP method to enable Optuna integration.

Optuna Integration via _HPProxy

When optimizing, the _HPProxy class in src/hypster/hpo/optuna.py mirrors the HP API but forwards each call to trial.suggest_*. The proxy records suggested values in a collector dictionary, allowing you to retrieve the exact sampled configuration after the trial completes.

Namespace Handling with Nested Configurations

The nest method creates hierarchical parameter spaces by instantiating a new HP object with an extended namespace (parent.child.param). This mechanism:

  • Tracks nested calls to prevent name collisions
  • Propagates parameter access information upward
  • Enables conditional configuration blocks

Use nesting to create modular, reusable configuration components that merge into a unified space.

Step-by-Step: Building a Configuration Function

Define your configuration space by writing a function that accepts an HP instance and declares parameters using the methods above:


# file: my_config.py

from hypster import HP
from hypster.hpo.types import HpoInt, HpoFloat, HpoCategorical

def model_cfg(hp: HP):
    # Integer with bounds and HPO step specification

    batch_size = hp.int(
        32,
        name="batch_size",
        min=8,
        max=256,
        hpo_spec=HpoInt(step=8, scale="log")
    )

    # Float with log-uniform distribution for optimization

    lr = hp.float(
        0.001,
        name="learning_rate",
        min=1e-5,
        max=1e-1,
        hpo_spec=HpoFloat(scale="log", distribution="loguniform")
    )

    # Categorical selection with sampling weights

    optimizer = hp.select(
        ["adam", "sgd", "rmsprop"],
        name="optimizer",
        default="adam",
        hpo_spec=HpoCategorical(weights=[0.6, 0.3, 0.1])
    )

    # Multi-boolean flags

    flags = hp.multi_bool([True, False], name="flags")

    # Conditional nesting: only expose dropout for Adam optimizer

    def dropout_cfg(hp):
        return hp.float(0.5, name="dropout", min=0.0, max=1.0)

    if optimizer == "adam":
        hp.nest(dropout_cfg, name="dropout_cfg")

    return {
        "batch_size": batch_size,
        "lr": lr,
        "optimizer": optimizer,
        "flags": flags,
    }

This example demonstrates type declaration, bounds enforcement, HPO metadata injection, and conditional parameter exposure through nesting.

Instantiating Configurations with Concrete Values

To materialize a configuration with specific values, use the instantiate function from src/hypster/core.py:

from hypster import instantiate
from my_config import model_cfg

values = {
    "batch_size": 64,
    "learning_rate": 0.01,
    "optimizer": "sgd",
    "flags": [True, True],
}

cfg = instantiate(model_cfg, values=values)
print(cfg)

# Output: {'batch_size': 64, 'lr': 0.01, 'optimizer': 'sgd', 'flags': [True, True]}

The instantiate call validates the supplied dictionary against your declarations, raises ValueError for missing or invalid keys, and returns the configuration dictionary produced by your function.

Integrating with Optuna for Hyperparameter Optimization

To sample from the complete search space defined in your configuration, use the Optuna integration:

import optuna
from hypster.hpo.optuna import suggest_values
from my_config import model_cfg

def objective(trial):
    # Sample values according to HPO specifications

    sampled = suggest_values(trial, config=model_cfg)
    
    # Build and evaluate your model using sampled parameters

    # Returns a scalar loss for minimization

    return (sampled["lr"] - 0.01) ** 2 + (sampled["batch_size"] - 64) ** 2

study = optuna.create_study(direction="minimize")
study.optimize(objective, n_trials=30)

print("Best hyperparameters:", study.best_params)

The suggest_values function (lines 39-51 in src/hypster/hpo/optuna.py) uses the _HPProxy to translate your HP calls into Optuna's trial.suggest_* methods, automatically respecting the HpoInt, HpoFloat, and HpoCategorical specifications.

Error Handling and Validation

Hypster provides robust error handling through the validation layers in hp_calls.py. When instantiate detects parameters supplied in the values dictionary that were never accessed during configuration execution, it invokes _handle_unknown_parameters with configurable behavior:

  • Strict mode: Raises an error for any unknown key
  • Warning mode: Logs suggestions for similar valid names using suggest_similar_names
  • Ignore mode: Silently drops unused parameters

This prevents silent failures from typos in parameter names and ensures configuration integrity across refactoring.

Summary

  • Define parameter spaces using Python functions that accept an HP object and call methods like int(), float(), select(), and multi_bool().
  • Enforce constraints through the min, max, strict, and name parameters, validated by classes in src/hypster/hp_calls.py.
  • Enable optimization by passing hpo_spec objects (HpoInt, HpoFloat, HpoCategorical) to integrate with Optuna via src/hypster/hpo/optuna.py.
  • Materialize configurations using instantiate() from src/hypster/core.py, which validates inputs and handles unknown parameter detection.
  • Nest configurations using hp.nest() to create modular, hierarchical spaces with automatic namespace management.

Frequently Asked Questions

How do I create conditional parameters that only appear under certain values?

Use the nest method to conditionally expose parameter sub-spaces. Define a child configuration function and wrap it in an if statement based on the parent parameter value. For example, only expose dropout_rate when optimizer == "adam" by nesting the dropout configuration inside a conditional block. The HP class tracks namespace extensions automatically, ensuring child parameters are properly scoped.

What validation errors can Hypster catch during instantiation?

Hypster validates parameter types, bounds (min/max constraints), categorical choices, and required names through the validator classes in src/hypster/hpo/hp_calls.py. The instantiate function in src/hypster/core.py also detects unknown parameters—values supplied but never accessed—and can suggest similar valid names using fuzzy matching via suggest_similar_names.

How do I specify logarithmic scaling for hyperparameter optimization?

Pass an HpoInt or HpoFloat instance to the hpo_spec= argument of the corresponding HP method. Set scale="log" to enable logarithmic scaling, or use distribution="loguniform" for HpoFloat to sample from a log-uniform distribution. These specifications are interpreted by the _HPProxy class when using Optuna integration.

Can I define multi-valued parameters like lists of integers or booleans?

Yes. Use the multi_int, multi_float, multi_text, or multi_bool methods on the HP object. These create MultiValueSpec instances validated by MultiValidator, allowing you to specify lists of values with optional element-wise constraints and defaults.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →