Variable Naming#

Hypster provides sensible defaults for naming your variables to keep your code DRY (Don’t Repeat Yourself)

Explicit Naming#

You can explicitly name your variables using the name parameter:

from hypster import HP, config


@config
def explicit_naming(hp: HP):
    var = hp.select(["o1", "o2"], name="my_explicit_variable")
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
Cell In[1], line 1
----> 1 from hypster import HP, config
      4 @config
      5 def explicit_naming(hp: HP):
      6     var = hp.select(["o1", "o2"], name="my_explicit_variable")

ModuleNotFoundError: No module named 'hypster'

Automatic Naming#

Hypster uses a name injection process to automatically name your hyperparameters. It’s important to understand how this works, especially if you have security concerns about code modification:

  1. Source Code Modification: Hypster analyzes your configuration function’s source code and injects name keyword arguments into the hyperparameter calls (hp.select(), hp.number(), etc.).

  2. AST Transformation: This process uses Python’s Abstract Syntax Tree (AST) to modify the source code without changing its functionality.

  3. Security Implications: While this process is designed to be safe, users with strict security requirements should be aware that it involves modifying and re-executing the source code.

  4. Disabling Name Injection: If you prefer to avoid automatic name injection, you can disable it by using @config(inject_names=False) or load(..., inject_names=False). When disabled, you must provide explicit names for all hyperparameters.

Example of how name injection modifies your code:

from hypster import HP, config


# Original code
@config
def my_config(hp: HP):
    model = hp.select(["cnn", "rnn"])


# Modified code (internal representation)
def my_config(hp: HP):
    model = hp.select(["cnn", "rnn"], name="model")

Automatic Naming Rules#

Hypster automatically infers variable names by utilizing the variable names, dictionary keys, and keyword arguments:

  1. Variable Names

    • Example: a = hp.select(['option1', 'option2'])

    • Result: ‘a’ will be the name of this parameter

  2. Dictionary Keys

    • Example: config = {'learning_rate': hp.number(0.001)}

    • Result: The dictionary key ‘learning_rate’ will be the name of this parameter

  3. Class and Function Keyword Arguments

    • Example: Model(hidden_size=hp.select([64, 128, 256]))

    • Result: The keyword argument ‘hidden_size’ will be the name of this parameter

For nested structures, Hypster uses dot notation (key.nested_key) to represent the hierarchy. For example:

model = Model(model_type=hp.select(['cnn', 'rnn']), # Automatically named 'model.model_type'
              model_kwargs={'lr' : hp.number(0.1)} # Automatically named 'model.model_kwargs.lr'
             )

Warning

  • Parameters are named based on the variable they’re assigned to, not the function or class name they’re associated with.

  • For example, result = some_func(a = hp.select(...)) will be accessible as result.a, not some_func.a.

Example Use-Cases:#

  1. Variable Assignment

@config
def automatic_naming(hp: HP):
    # This will be automatically named 'var'
    var = hp.select(["o1", "o2"])
    # This will be automatically named 'model_type'
    model_type = hp.select(["cnn", "rnn"])
  1. Dictionary Keys:

@config
def dict_naming(hp: HP):
    config = {
        "model_type": hp.select(["cnn", "rnn"]),  # Automatically named 'config.model_type'
        "learning_rate": hp.number(0.001),  # Automatically named 'config.learning_rate'
    }
  1. Class and function Keyword Arguments:

from hypster import HP, config


@config
def class_kwargs_naming(hp: HP):
    # Note new class definitions (or imports) need to be inside the config function
    class ModelConfig:
        def __init__(self, model_type, learning_rate):
            self.model_type = model_type
            self.learning_rate = learning_rate

    def func(param):
        return

    model = ModelConfig(
        model_type=hp.select(["cnn", "rnn"]),  # Automatically named 'model.model_type'
        learning_rate=hp.number(0.001),  # Automatically named 'model.learning_rate'
    )

    var = func(param=hp.select(["option1", "option2"]))  # Automatically named 'var.param'
results = class_kwargs_naming(selections={"model.model_type": "cnn", "var.param": "option1"})
print(results["model"].model_type)
print(results["model"].learning_rate)
cnn
0.001

Disabling Automatic Naming#

In case you want to disable automatic naming and rely solely on explicit naming, you can do so by setting inject_names=False:

from hypster import HP, config


@config(inject_names=False)
def class_kwargs_naming(hp: HP):
    # Note new class definitions (or imports) need to be inside the config function
    class ModelConfig:
        def __init__(self, model_type, learning_rate):
            self.model_type = model_type
            self.learning_rate = learning_rate

    def func(param):
        return

    model = ModelConfig(
        model_type=hp.select(["cnn", "rnn"], name="model_type"),
        learning_rate=hp.number(0.001, name="learning_rate"),
    )
    var = func(param=hp.select(["option1", "option2"], name="param"))

When automatic naming is disabled, you must provide explicit names for all hyperparameters. Failing to do so will result in an error:

@config(inject_names=False)
def no_injection_config(hp: HP):
    a = hp.select(["a", "b"])  # This will raise an error because no name is provided
import logging

# Disable logging to prevent verbose output
logging.disable(logging.CRITICAL)

try:
    no_injection_config()
    print("If you see this, the error didn't occur as expected.")
except ValueError as e:
    assert "`name` argument is missing" in str(e)
    print("ValueError occurred as expected: `name` argument is missing")
ValueError occurred as expected: `name` argument is missing

Disabling automatic naming can be useful in scenarios where you want full control over parameter names, when the automatic naming might lead to ambiguities in your configuration, or when you have security concerns about source code modification.