AutoTuner API#
The panther.tuner module provides automatic hyperparameter optimization for sketching parameters using Optuna, a modern hyperparameter optimization framework.
Optional Dependencies#
Package |
Install Command |
Required For |
|---|---|---|
pandas |
|
|
Tip
For tuning result visualization, use Optuna’s built-in plots on tuner.search_algorithm.study.
See the external-tools section for examples.
Public Exports#
All recommended imports are available directly from panther.tuner:
from panther.tuner import (
# Core tuner
SKAutoTuner,
# Configuration
LayerConfig,
TuningConfigs,
# Parameter specification types
Categorical,
Int,
Float,
# Search algorithms
SearchAlgorithm,
OptunaSearch,
# Visualization (optional)
ModelVisualizer,
)
For advanced/internal APIs not re-exported at the top level, use:
from panther.tuner.SkAutoTuner.Configs import LayerNameResolver, ParamsResolver
SKAutoTuner Class#
- class panther.tuner.SKAutoTuner(model, configs, accuracy_eval_func, search_algorithm=None, verbose=False, accuracy_threshold=None, optimization_eval_func=None, num_runs_per_param=1)#
Auto-tuner for sketched neural network layers.
- Parameters:
model – The neural network model to tune (
nn.Module)configs – Configuration for the layers to tune (
TuningConfigs)accuracy_eval_func – Evaluation function that takes a model and returns an accuracy score (higher is better)
search_algorithm – Search algorithm to use (default:
OptunaSearch())verbose – Whether to print progress during tuning
accuracy_threshold – Minimum acceptable accuracy. If set along with
optimization_eval_func, the tuner maximizes speed while maintaining accuracy ≥ thresholdoptimization_eval_func – Function to maximize (e.g., throughput) after reaching the accuracy threshold
num_runs_per_param – Number of runs per parameter combination (for averaging noisy evaluations)
Tuning Workflow Methods#
- SKAutoTuner.tune() Dict[str, Dict[str, Any]]#
Run the tuning process for all configured layer groups.
- Returns:
Dictionary mapping layer names to their best parameters
- SKAutoTuner.apply_best_params() nn.Module#
Apply the best found parameters to the model, replacing layers with their sketched versions.
- Returns:
The model with optimized sketched layers
- SKAutoTuner.replace_without_tuning() nn.Module#
Replace layers with sketched versions using the first parameter value from each specification, without running any tuning trials. Useful for quick testing.
- Returns:
The model with layers replaced
Results and Analysis Methods#
- SKAutoTuner.get_best_params() Dict[str, Dict[str, Any]]#
Get the best parameters found for each layer.
- Returns:
Dictionary mapping layer names to their best parameter configurations
- SKAutoTuner.get_results_dataframe() pandas.DataFrame#
Get all tuning results as a pandas DataFrame.
- Returns:
DataFrame with columns:
layer_name, parameter columns,score,accuracy,speed- Raises:
ImportError – If pandas is not installed
results_df = tuner.get_results_dataframe() print(results_df[["layer_name", "num_terms", "low_rank", "accuracy", "speed", "score"]])
Persistence Methods#
- SKAutoTuner.save_tuning_results(file_path: str)#
Save tuning results to a pickle file.
- Parameters:
file_path – Path to save the results
- SKAutoTuner.load_tuning_results(file_path: str)#
Load tuning results from a pickle file.
- Parameters:
file_path – Path to load results from
- Raises:
FileNotFoundError – If the file does not exist
ValueError – If the file contains invalid data
Configuration Accessors#
- SKAutoTuner.getResolver() LayerNameResolver#
Get the layer name resolver for advanced layer inspection.
- SKAutoTuner.getConfigs() TuningConfigs#
Get the current (resolved) tuning configurations.
- SKAutoTuner.setConfigs(configs: TuningConfigs)#
Set new tuning configurations. Automatically resolves layer names and parameters.
Configuration Classes#
LayerConfig#
- class panther.tuner.LayerConfig(layer_names, params, separate=True, copy_weights=True)#
Configuration for a single layer or group of layers to tune.
- Parameters:
layer_names – Layer selector (see Layer Selectors)
params – Dictionary of parameter specifications (see Parameter Specification Types)
separate – If
True, tune each layer independently. IfFalse, tune all layers jointly with shared parameterscopy_weights – Whether to copy weights from original layers when creating sketched versions
from panther.tuner import LayerConfig, Categorical, Int # Tune fc1 and fc2 separately with the same parameter space config = LayerConfig( layer_names=["fc1", "fc2"], params={ "num_terms": Categorical([1, 2, 3]), "low_rank": Int(16, 128, step=16) }, separate=True, copy_weights=True )
TuningConfigs#
- class panther.tuner.TuningConfigs(configs: List[LayerConfig])#
Collection of
LayerConfigobjects for tuning multiple layer groups.- Parameters:
configs – List of
LayerConfigobjects
Container Methods:
__len__()- Number of configs__getitem__(index)- Get config by index__iter__()- Iterate over configsadd(config)- Add a config (returns newTuningConfigs)remove(index)- Remove config at index (returns newTuningConfigs)replace(index, config)- Replace config at index (returns newTuningConfigs)clone()- Deep copymerge(other)- Combine with anotherTuningConfigsfilter(predicate)- Filter configs by predicate functionmap(transform)- Transform each config
from panther.tuner import TuningConfigs, LayerConfig, Categorical configs = TuningConfigs([ LayerConfig( layer_names=["encoder.*"], params={"num_terms": Categorical([1, 2, 3])}, ), LayerConfig( layer_names=["decoder.*"], params={"num_terms": Categorical([2, 4, 8])}, ), ]) # Access individual configs print(len(configs)) # 2 print(configs[0]) # First LayerConfig
Layer Selectors#
The layer_names parameter in LayerConfig supports multiple selector formats for flexible layer targeting.
String Pattern#
A single string is interpreted as a regex pattern or substring:
# Match all layers containing "encoder"
LayerConfig(layer_names="encoder", ...)
# Match layers like "encoder.layer0.attention", "encoder.layer1.attention"
LayerConfig(layer_names="encoder.*attention", ...)
List of Patterns#
A list of strings matches multiple patterns:
# Match layers containing "encoder" OR "decoder"
LayerConfig(layer_names=["encoder", "decoder"], ...)
# Match specific layer names exactly
LayerConfig(layer_names=["fc1", "fc2", "fc3"], ...)
Dictionary Selector#
A dictionary enables advanced selection with multiple criteria:
# Select by regex pattern
LayerConfig(
layer_names={"pattern": "encoder\\.layer[0-5]\\..*"},
...
)
# Select by layer type
LayerConfig(
layer_names={"type": "Linear"}, # All nn.Linear layers
...
)
# Multiple types
LayerConfig(
layer_names={"type": ["Conv2d", "ConvTranspose2d"]},
...
)
# Select by substring
LayerConfig(
layer_names={"contains": "attention"},
...
)
# Select specific indices from matched layers
LayerConfig(
layer_names={
"pattern": "encoder.*",
"indices": [0, 2, 4] # First, third, and fifth matched layers
},
...
)
# Select a range of layers
LayerConfig(
layer_names={
"type": "Linear",
"range": [0, 6] # First 6 matched Linear layers
},
...
)
# Range with step
LayerConfig(
layer_names={
"type": "Linear",
"range": [0, 12, 2] # Every other layer from first 12
},
...
)
# Combine multiple criteria (intersection)
LayerConfig(
layer_names={
"pattern": "encoder.*",
"type": "Linear",
"indices": [0, 1, 2]
},
...
)
Selector Keys:
Key |
Type |
Description |
|---|---|---|
|
|
Regex patterns to match layer names |
|
|
Layer type names (e.g., |
|
|
Substrings that layer names must contain |
|
|
Specific indices from matched layers |
|
|
Range of indices (exclusive end) |
Note
indices and range cannot be used together. Multiple criteria (pattern, type, contains) are combined with AND logic (intersection).
Parameter Specification Types#
Modern first-class parameter specifications for expressing search spaces:
Categorical#
- class panther.tuner.Categorical(choices: Sequence[Any])#
A categorical parameter that takes values from a fixed set of choices.
- Parameters:
choices – Sequence of possible values (any type)
- Raises:
ValueError – If choices is empty
from panther.tuner import Categorical # Integer choices Categorical([1, 2, 3, 4]) # String choices Categorical(["relu", "gelu", "silu"]) # Boolean choices Categorical([True, False])
Int#
- class panther.tuner.Int(low: int, high: int, step: int = 1, log: bool = False)#
An integer parameter within a range
[low, high].- Parameters:
low – Lower bound (inclusive)
high – Upper bound (inclusive)
step – Step size for discrete values (default: 1)
log – Whether to sample in log scale
- Raises:
ValueError – If low > high, step < 1, or log=True with low ≤ 0
from panther.tuner import Int # Integer from 1 to 100 Int(1, 100) # Multiples of 8 from 8 to 512 Int(8, 512, step=8) # Log-scale integer sampling Int(1, 1000, log=True)
Float#
- class panther.tuner.Float(low: float, high: float, step: float = None, log: bool = False)#
A floating-point parameter within a range
[low, high].- Parameters:
low – Lower bound (inclusive)
high – Upper bound (inclusive)
step – Step size for discrete values (
Nonefor continuous)log – Whether to sample in log scale
- Raises:
ValueError – If low > high, step ≤ 0, or log=True with low ≤ 0
from panther.tuner import Float # Continuous float from 0 to 1 Float(0.0, 1.0) # Log-scale float (e.g., learning rate) Float(1e-5, 1e-1, log=True) # Discrete float values Float(0.1, 1.0, step=0.1)
Legacy List Format#
For backward compatibility, plain lists are also supported and are interpreted as Categorical:
# Legacy format (still works)
params = {
"num_terms": [1, 2, 3],
"low_rank": [8, 16, 32, 64],
}
# Equivalent modern format
params = {
"num_terms": Categorical([1, 2, 3]),
"low_rank": Categorical([8, 16, 32, 64]),
}
Automatic Parameter Generation#
The special value "auto" for the params field enables automatic parameter space generation based on layer dimensions:
from panther.tuner import LayerConfig, TuningConfigs
config = LayerConfig(
layer_names={"type": "Linear"},
params="auto", # Automatically determine parameter ranges
separate=True
)
How “auto” Works#
When params="auto" is specified, the tuner intelligently analyzes your model and generates optimal parameter search spaces:
Smart Grouping: Layers are automatically grouped by type, shape, and size to enable efficient tuning
Efficiency-Aware: Parameter ranges are computed using layer-specific efficiency equations that consider the mathematical properties of each layer type
Adaptive Ranges: The generated Parameter values are tailored to each layer’s dimensions to ensure only efficient configurations are explored
Layer-Specific Logic: Different layer types (Linear, Conv2d, etc.) use their own specialized parameter generation strategies
The automatic parameter generation considers:
Layer type and its specific implementation details
Input/output dimensions and their relationships
Theoretical efficiency bounds for sketched approximations
Practical constraints to avoid degenerate configurations
# Let the tuner figure out the best parameter ranges
config = LayerConfig(
layer_names={"type": "Linear"},
params="auto",
separate=True
)
# The tuner will:
# 1. Analyze each layer's dimensions
# 2. Group similar layers together
# 3. Generate efficient parameter ranges for each group
# 4. Create appropriate LayerConfigs automatically
Note
"auto" currently supports nn.Linear and nn.Conv2d layers. Unsupported layer types are skipped with a warning if verbose=True.
Search Algorithms#
SearchAlgorithm Interface#
- class panther.tuner.SearchAlgorithm#
Abstract base class for search algorithms. Implement this interface to create custom search strategies.
Required Methods:
- reset()#
Reset to initial state.
Optional Methods:
- get_resource() Any#
Return a resource value for resource-aware algorithms (e.g., Hyperband). The
SKAutoTunerwill pass this to evaluation functions if present.
OptunaSearch#
- class panther.tuner.OptunaSearch(n_trials=100, sampler=None, direction='maximize', study_name=None, storage=None, load_if_exists=False, seed=None)#
Optuna-backed search algorithm with state-of-the-art samplers.
- Parameters:
n_trials – Maximum number of trials (default: 100)
sampler – Optuna sampler (default:
TPESampler)direction –
"maximize"or"minimize"(default:"maximize")study_name – Name for the Optuna study (useful for persistence)
storage – Optuna storage URL (e.g.,
"sqlite:///study.db") for persistenceload_if_exists – Whether to resume an existing study from storage
seed – Random seed for reproducibility
Properties:
- study#
Access the underlying
optuna.Studyfor advanced operations.
Additional Methods:
- get_trials_dataframe() pandas.DataFrame#
Get a DataFrame of all trials (requires pandas).
Search Sampler Examples#
TPE Sampler (Default)
Tree-structured Parzen Estimator - excellent for most use cases:
from panther.tuner import SKAutoTuner, OptunaSearch
tuner = SKAutoTuner(
model=model,
configs=tuning_configs,
accuracy_eval_func=accuracy_eval_func,
search_algorithm=OptunaSearch(n_trials=100, seed=42),
)
Random Search
Simple random sampling:
from panther.tuner import SKAutoTuner, OptunaSearch
from optuna.samplers import RandomSampler
tuner = SKAutoTuner(
model=model,
configs=tuning_configs,
accuracy_eval_func=accuracy_eval_func,
search_algorithm=OptunaSearch(
n_trials=50,
sampler=RandomSampler(seed=42)
),
)
Grid Search
Exhaustive search over all combinations (use for small parameter spaces):
from panther.tuner import SKAutoTuner, OptunaSearch
from optuna.samplers import GridSampler
# Define the full search space for GridSampler
search_space = {
"num_terms": [1, 2, 3],
"low_rank": [8, 16, 32, 64],
}
tuner = SKAutoTuner(
model=model,
configs=tuning_configs,
accuracy_eval_func=accuracy_eval_func,
search_algorithm=OptunaSearch(
sampler=GridSampler(search_space)
),
)
CMA-ES
Covariance Matrix Adaptation Evolution Strategy - excellent for continuous parameters:
from panther.tuner import SKAutoTuner, OptunaSearch
from optuna.samplers import CmaEsSampler
tuner = SKAutoTuner(
model=model,
configs=tuning_configs,
accuracy_eval_func=accuracy_eval_func,
search_algorithm=OptunaSearch(
n_trials=200,
sampler=CmaEsSampler(seed=42)
),
)
ModelVisualizer#
- class panther.tuner.ModelVisualizer#
Utility class for discovering layer names in PyTorch models. Use this to craft correct layer selectors for
LayerConfig. All methods are static.
- static ModelVisualizer.print_module_tree(model: nn.Module, root_name: str = 'model')#
Print the module hierarchy as an ASCII tree with layer types.
- Parameters:
model – The PyTorch model to inspect
root_name – Display name for the root module
from panther.tuner import ModelVisualizer ModelVisualizer.print_module_tree(model) # Output: # model (MyModel)/ # └─ encoder (Encoder)/ # ├─ layer0 (TransformerLayer)/ # │ ├─ attention (MultiheadAttention)/ # │ └─ fc (Linear)/ # └─ layer1 (TransformerLayer)/ # ...
Use the printed layer names directly in your
LayerConfig:config = LayerConfig( layer_names=["encoder.layer0.fc", "encoder.layer1.fc"], params={...} )