Skip to content

Commit fd4248f

Browse files
0.15.14
new pytorch models (opt. scheduler for lr)
1 parent eda3087 commit fd4248f

5 files changed

Lines changed: 343 additions & 20 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
77

88
[project]
99
name = "spotpython"
10-
version = "0.15.13"
10+
version = "0.15.14"
1111
authors = [
1212
{ name="T. Bartz-Beielstein", email="tbb@bartzundbartz.de" }
1313
]

src/spotpython/hyperdict/light_hyper_dict.json

Lines changed: 110 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -349,11 +349,17 @@
349349
},
350350
"optimizer": {
351351
"levels": [
352+
"Adadelta",
353+
"Adagrad",
352354
"Adam",
353355
"AdamW",
356+
"SparseAdam",
354357
"Adamax",
358+
"ASGD",
355359
"NAdam",
356360
"RAdam",
361+
"RMSprop",
362+
"Rprop",
357363
"SGD"
358364
],
359365
"type": "factor",
@@ -362,8 +368,107 @@
362368
"class_name": "torch.optim",
363369
"core_model_parameter_type": "str",
364370
"lower": 0,
371+
"upper": 11
372+
},
373+
"dropout_prob": {
374+
"type": "float",
375+
"default": 0.01,
376+
"transform": "None",
377+
"lower": 0.0,
378+
"upper": 0.25
379+
},
380+
"lr_mult": {
381+
"type": "float",
382+
"default": 1.0,
383+
"transform": "None",
384+
"lower": 0.1,
385+
"upper": 10.0
386+
},
387+
"patience": {
388+
"type": "int",
389+
"default": 2,
390+
"transform": "transform_power_2_int",
391+
"lower": 2,
392+
"upper": 6
393+
},
394+
"initialization": {
395+
"levels": [
396+
"Default",
397+
"kaiming_uniform",
398+
"kaiming_normal",
399+
"xavier_uniform",
400+
"xavier_normal"
401+
],
402+
"type": "factor",
403+
"default": "Default",
404+
"transform": "None",
405+
"core_model_parameter_type": "str",
406+
"lower": 0,
407+
"upper": 4
408+
}
409+
},
410+
"NNResNetRegressor": {
411+
"l1": {
412+
"type": "int",
413+
"default": 3,
414+
"transform": "transform_power_2_int",
415+
"lower": 3,
416+
"upper": 10
417+
},
418+
"epochs": {
419+
"type": "int",
420+
"default": 4,
421+
"transform": "transform_power_2_int",
422+
"lower": 4,
423+
"upper": 9
424+
},
425+
"batch_size": {
426+
"type": "int",
427+
"default": 4,
428+
"transform": "transform_power_2_int",
429+
"lower": 1,
430+
"upper": 6
431+
},
432+
"act_fn": {
433+
"levels": [
434+
"Sigmoid",
435+
"Tanh",
436+
"ReLU",
437+
"LeakyReLU",
438+
"ELU",
439+
"Swish"
440+
],
441+
"type": "factor",
442+
"default": "ReLU",
443+
"transform": "None",
444+
"class_name": "spotpython.torch.activation",
445+
"core_model_parameter_type": "instance()",
446+
"lower": 0,
365447
"upper": 5
366448
},
449+
"optimizer": {
450+
"levels": [
451+
"Adadelta",
452+
"Adagrad",
453+
"Adam",
454+
"AdamW",
455+
"SparseAdam",
456+
"Adamax",
457+
"ASGD",
458+
"NAdam",
459+
"RAdam",
460+
"RMSprop",
461+
"Rprop",
462+
"SGD"
463+
],
464+
"type": "factor",
465+
"default": "SGD",
466+
"transform": "None",
467+
"class_name": "torch.optim",
468+
"core_model_parameter_type": "str",
469+
"lower": 0,
470+
"upper": 11
471+
},
367472
"dropout_prob": {
368473
"type": "float",
369474
"default": 0.01,
@@ -388,15 +493,17 @@
388493
"initialization": {
389494
"levels": [
390495
"Default",
391-
"Kaiming",
392-
"Xavier"
496+
"kaiming_uniform",
497+
"kaiming_normal",
498+
"xavier_uniform",
499+
"xavier_normal"
393500
],
394501
"type": "factor",
395502
"default": "Default",
396503
"transform": "None",
397504
"core_model_parameter_type": "str",
398505
"lower": 0,
399-
"upper": 2
506+
"upper": 4
400507
}
401508
}
402509
}

src/spotpython/light/regression/nn_linear_regressor.py

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from torch import nn
44
from spotpython.hyperparameters.optimizer import optimizer_handler
55
import torchmetrics.functional.regression
6-
from spotpython.utils.math import generate_div2_list
6+
import torch.optim as optim
77

88

99
class NNLinearRegressor(L.LightningModule):
@@ -166,32 +166,57 @@ def __init__(
166166
if self.hparams.l1 < 4:
167167
raise ValueError("l1 must be at least 4")
168168
hidden_sizes = self._get_hidden_sizes()
169+
169170
# Create the network based on the specified hidden sizes
170171
layers = []
171172
layer_sizes = [self._L_in] + hidden_sizes
172-
layer_size_last = layer_sizes[0]
173-
for layer_size in layer_sizes[1:]:
173+
for i in range(len(layer_sizes) - 1):
174+
current_layer_size = layer_sizes[i]
175+
next_layer_size = layer_sizes[i + 1]
174176
layers += [
175-
nn.Linear(layer_size_last, layer_size),
177+
nn.Linear(current_layer_size, next_layer_size),
178+
nn.BatchNorm1d(next_layer_size), # Add Batch Normalization here
176179
self.hparams.act_fn,
177180
nn.Dropout(self.hparams.dropout_prob),
178181
]
179-
layer_size_last = layer_size
180182
layers += [nn.Linear(layer_sizes[-1], self._L_out)]
181-
# nn.Sequential summarizes a list of modules into a single module, applying them in sequence
182-
self.layers = nn.Sequential(*layers)
183183

184-
def _get_hidden_sizes(self):
185-
"""
186-
Generate the hidden layer sizes for the network.
184+
# Wrap the layers into a sequential container
185+
self.layers = nn.Sequential(*layers)
187186

188-
Returns:
189-
list: A list of hidden layer sizes.
187+
# Initialization (Xavier, Kaiming, or Default)
188+
self.apply(self._init_weights)
189+
190+
def _init_weights(self, module):
191+
if isinstance(module, nn.Linear):
192+
if self.hparams.initialization == "xavier_uniform":
193+
nn.init.xavier_uniform_(module.weight)
194+
elif self.hparams.initialization == "xavier_normal":
195+
nn.init.xavier_normal_(module.weight)
196+
elif self.hparams.initialization == "kaiming_uniform":
197+
nn.init.kaiming_uniform_(module.weight)
198+
elif self.hparams.initialization == "kaiming_normal":
199+
nn.init.kaiming_normal_(module.weight)
200+
else: # "Default"
201+
nn.init.uniform_(module.weight)
202+
if module.bias is not None:
203+
nn.init.zeros_(module.bias)
204+
205+
def _generate_div2_list(self, n, n_min) -> list:
206+
result = []
207+
current = n
208+
repeats = 1
209+
max_repeats = 4
210+
while current >= n_min:
211+
result.extend([current] * min(repeats, max_repeats))
212+
current = current // 2
213+
repeats = repeats + 1
214+
return result
190215

191-
"""
216+
def _get_hidden_sizes(self):
192217
n_low = self._L_in // 4
193218
n_high = max(self.hparams.l1, 2 * n_low)
194-
hidden_sizes = generate_div2_list(n_high, n_low)
219+
hidden_sizes = self._generate_div2_list(n_high, n_low)
195220
return hidden_sizes
196221

197222
def forward(self, x: torch.Tensor) -> torch.Tensor:
@@ -326,4 +351,18 @@ def configure_optimizers(self) -> torch.optim.Optimizer:
326351
optimizer = optimizer_handler(
327352
optimizer_name=self.hparams.optimizer, params=self.parameters(), lr_mult=self.hparams.lr_mult
328353
)
329-
return optimizer
354+
355+
num_milestones = 3 # Number of milestones to divide the epochs
356+
milestones = [int(self.hparams.epochs / (num_milestones + 1) * (i + 1)) for i in range(num_milestones)]
357+
358+
print(f"Milestones: {milestones}")
359+
360+
scheduler = optim.lr_scheduler.MultiStepLR(optimizer, milestones=milestones, gamma=0.1) # Decay factor
361+
362+
lr_scheduler_config = {
363+
"scheduler": scheduler,
364+
"interval": "epoch",
365+
"frequency": 1,
366+
}
367+
368+
return {"optimizer": optimizer, "lr_scheduler": lr_scheduler_config}

0 commit comments

Comments
 (0)