Source code for cann.engine.training_config
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Tuple, List, Literal
[docs]
@dataclass
class TrainingConfig:
"""
Hyperparameters and settings for training the surrogate model.
Commonly adjusted fields are ``epochs``, ``batch_size``, ``learning_rate``,
``hidden_layers``, ``activation``, and ``train_val_test_split``.
"""
batch_size: int = 32768
epochs: int = 4800
dropout_rate: float = 0.0
batch_norm: bool = False
learning_rate: float = 1e-3
lr_decay_every_epochs: int | None = None
lr_decay_factor: float = 0.5
min_learning_rate: float = 0.0
optimizer: Literal["adam", "sgd"] = "adam"
loss: Literal["mse"] = "mse"
validation_every_epochs: int = 100
hidden_layers: List[int] = field(default_factory=lambda: [200, 200, 200, 200])
activation: Literal["relu", "tanh", "gelu"] = "relu"
weight_init: Literal["default", "uniform"] = "default"
weight_init_min: float = -0.05
weight_init_max: float = 0.05
bias_init: float | None = None
train_val_test_split: Tuple[float, float, float] = (0.8, 0.1, 0.1)
shuffle: bool = True
early_stopping: bool = False
device: Literal["cpu", "cuda"] = "cuda"
random_seed: int | None = 42
def __post_init__(self) -> None:
s = sum(self.train_val_test_split)
if not (0.99 <= s <= 1.01):
raise ValueError(f"train_val_test_split must sum to 1.0, got {s}")
if self.batch_size <= 0:
raise ValueError(f"batch_size must be positive, got {self.batch_size}")
if self.epochs <= 0:
raise ValueError(f"epochs must be positive, got {self.epochs}")
if self.learning_rate <= 0:
raise ValueError(
f"learning_rate must be positive, got {self.learning_rate}"
)
if self.lr_decay_every_epochs is not None and self.lr_decay_every_epochs <= 0:
raise ValueError(
"lr_decay_every_epochs must be positive when provided, "
f"got {self.lr_decay_every_epochs}"
)
if not (0 < self.lr_decay_factor <= 1):
raise ValueError(
f"lr_decay_factor must be in (0, 1], got {self.lr_decay_factor}"
)
if self.min_learning_rate < 0:
raise ValueError(
f"min_learning_rate must be non-negative, got {self.min_learning_rate}"
)
if self.min_learning_rate > self.learning_rate:
raise ValueError(
"min_learning_rate must not exceed learning_rate, "
f"got {self.min_learning_rate} > {self.learning_rate}"
)
if self.validation_every_epochs <= 0:
raise ValueError(
"validation_every_epochs must be positive, "
f"got {self.validation_every_epochs}"
)
if not self.hidden_layers or any(width <= 0 for width in self.hidden_layers):
raise ValueError(
f"hidden_layers must contain positive widths, got {self.hidden_layers}"
)
if self.weight_init not in ("default", "uniform"):
raise ValueError(f"Unsupported weight_init: {self.weight_init}")
if self.weight_init_min >= self.weight_init_max:
raise ValueError(
"weight_init_min must be smaller than weight_init_max, "
f"got {self.weight_init_min} >= {self.weight_init_max}"
)
[docs]
@classmethod
def from_dict(cls, cfg: dict) -> TrainingConfig:
"""
Create a TrainingConfig instance from a dictionary.
Args:
cfg (dict): Dictionary containing configuration parameters.
Returns:
TrainingConfig: Parsed training configuration.
Raises:
TypeError: If the dictionary contains keys not accepted by TrainingConfig.
"""
return cls(**cfg)