added code

This commit is contained in:
2025-09-10 10:37:55 +02:00
parent 36901c736d
commit c78a68de80
199 changed files with 3561 additions and 22579 deletions
+279
View File
@@ -0,0 +1,279 @@
from functools import partial
from configs.config_utils import *
from configs.feature_config import feature_config
from experiment_setup import get_fertility_based_eval_functions
from utils.data_utils import *
from utils.training import *
from models.cnn_lstm import *
from models.utils import *
from models.collation import *
cnn_lstm_base_config = {
"model_name": "cnn_lstm",
"version": "1.0.0",
"model_class": CNNLSTM,
"feature_config": feature_config | {"ignored_features":
[
"fertility_probability",
"ov_over_probability",
# "days_relative_to_ov",
# "is_biphasic",
"ov_day",
]},
"batch_fn": produce_window_batches,
"collate_fn": simple_x_y_collate,
"model_creation_fn": simple_model_creation,
"model_save_fn": simple_model_save,
"model_load_fn": partial(simple_model_load, model_creation_fn=simple_model_creation),
"batch_loss_fn": get_model_loss,
"actual_fn": simple_get_y,
"predict_fn": simple_x_y_predict,
}
base_cnn_lstm_training_config = {
"batch_size": 128,
"learning_parameters": {
"max_lr": 1e-5,
"epochs": 30,
"patience": 5,
},
"loss_functions": [
nn.MSELoss(),
nn.BCEWithLogitsLoss(),
],
"max_grad_norm": 1.0,
"train_size": 0.7,
"val_size": 0.15,
"test_size": 0.15,
}
fertility_complexity_run = get_run_config(
run_name="cnn_lstm_complexity_run",
base_model_configuration=cnn_lstm_base_config | get_data_config_set(
values_per_day=288,
shift_in_hours=12,
input_window_length_in_days=40,
output_window_length=1,
output_window_offset=0
),
base_training_configuration=base_cnn_lstm_training_config,
model_config_kwargs_list=[
{
"model_parameters": {
"embed_dim": 32,
"lstm_hidden_size": 32,
"num_layers": 2,
},
},
{
"model_parameters": {
"embed_dim": 64,
"lstm_hidden_size": 64,
"num_layers": 2,
},
},
{
"model_parameters": {
"embed_dim": 128,
"lstm_hidden_size": 128,
"num_layers": 4,
},
},
]
)
model_input_run = get_run_config(
run_name="cnn_lstm_input_size_run",
base_model_configuration=cnn_lstm_base_config |
{
"model_parameters": {
"embed_dim": 128,
"lstm_hidden_size": 128,
"num_layers": 4,
},
},
base_training_configuration=base_cnn_lstm_training_config,
model_config_kwargs_list=input_run_kwargs_list,
)
fertility_input_run = get_run_config(
run_name="cnn_lstm_fertility_input_run",
base_model_configuration=cnn_lstm_base_config |
{
"feature_config": feature_config | {"ignored_features":
[
# "fertility_probability",
# "ov_over_probability",
"days_relative_to_ov",
"is_biphasic",
"ov_day",
]},
"model_parameters": {
"embed_dim": 128,
"lstm_hidden_size": 128,
"num_layers": 4,
},
},
base_training_configuration=base_cnn_lstm_training_config,
model_config_kwargs_list=[
get_data_config_set(
values_per_day=288,
shift_in_hours=12,
input_window_length_in_days=10,
output_window_length=1,
output_window_offset=0
),
get_data_config_set(
values_per_day=288,
shift_in_hours=12,
input_window_length_in_days=20,
output_window_length=1,
output_window_offset=0
),
get_data_config_set(
values_per_day=288,
shift_in_hours=12,
input_window_length_in_days=40,
output_window_length=1,
output_window_offset=0
),
get_data_config_set(
values_per_day=288,
shift_in_hours=12,
input_window_length_in_days=80,
output_window_length=1,
output_window_offset=0
),
get_data_config_set(
values_per_day=288,
shift_in_hours=12,
input_window_length_in_days=160,
output_window_length=1,
output_window_offset=0
)
],
evaluation_configuration={
"eval_functions_getter": get_fertility_based_eval_functions
},
)
fertility_complexity_run = get_run_config(
run_name="cnn_lstm_complexity_run",
base_model_configuration=cnn_lstm_base_config | get_data_config_set(
values_per_day=288,
shift_in_hours=12,
input_window_length_in_days=40,
output_window_length=1,
output_window_offset=0
) | {
"feature_config": feature_config | {"ignored_features":
[
# "fertility_probability",
# "ov_over_probability",
"days_relative_to_ov",
"is_biphasic",
"ov_day",
]},
},
base_training_configuration=base_cnn_lstm_training_config,
evaluation_configuration={
"eval_functions_getter": get_fertility_based_eval_functions
},
model_config_kwargs_list=[
{
"model_parameters": {
"embed_dim": 16,
"lstm_hidden_size": 16,
"num_layers": 1,
},
},
{
"model_parameters": {
"embed_dim": 32,
"lstm_hidden_size": 32,
"num_layers": 1,
},
},
{
"model_parameters": {
"embed_dim": 32,
"lstm_hidden_size": 32,
"num_layers": 2,
},
},
{
"model_parameters": {
"embed_dim": 64,
"lstm_hidden_size": 64,
"num_layers": 2,
},
},
{
"model_parameters": {
"embed_dim": 128,
"lstm_hidden_size": 128,
"num_layers": 2,
},
},
{
"model_parameters": {
"embed_dim": 128,
"lstm_hidden_size": 128,
"num_layers": 4,
},
},
{
"model_parameters": {
"embed_dim": 256,
"lstm_hidden_size": 256,
"num_layers": 4,
},
},
{
"model_parameters": {
"embed_dim": 512,
"lstm_hidden_size": 512,
"num_layers": 4,
},
},
]
)
best_config_run = get_run_config(
run_name="cnn_lstm_best_config_run",
base_model_configuration=cnn_lstm_base_config | get_data_config_set(
values_per_day=288,
shift_in_hours=12,
input_window_length_in_days=40,
output_window_length=1,
output_window_offset=0
) | {
"feature_config": feature_config | {"ignored_features":
[
# "fertility_probability",
# "ov_over_probability",
"days_relative_to_ov",
"is_biphasic",
"ov_day",
]},
"model_parameters": {
"embed_dim": 512,
"lstm_hidden_size": 512,
"num_layers": 4,
},
},
base_training_configuration=base_cnn_lstm_training_config | {
"learning_parameters": {
"max_lr": 1e-4,
# "learning_rate": base_lr * (batch_size / 4),
"epochs": 30,
"patience": 5,
},
},
model_config_kwargs_list=[],
evaluation_configuration={
"eval_functions_getter": get_fertility_based_eval_functions
},
)
-127
View File
@@ -1,127 +0,0 @@
from functools import partial
from configs.feature_config import feature_config
from models.cnn import CNNTransformer
from utils.data_utils import *
from utils.training import *
from models.lstm import *
from models.utils import *
from models.collation import *
take_every_nth = int(288 / 12)
shift_in_hours = 12
input_window_length = (288 // take_every_nth) * 80
# output_window_length = (288 // take_every_nth) * 1
output_window_length = 1
output_window_offset = input_window_length + (288 // take_every_nth) * 0
window_shift = int((288 // take_every_nth) / 24 * shift_in_hours)
min_input_length_fraction_for_padding = ((288 // take_every_nth) * 4) / input_window_length
max_lr = 1e-5
batch_size = 256
def get_cnn_run_config(
run_name: str,
run_description: str,
input_window_length: int,
output_window_length: int,
take_every_nth: int,
shift_in_hours: int,
output_window_offset: int,
batch_size: int,
model_parameters: dict,
max_lr: float,
num_epochs: int,
patience: int,
feature_config: dict):
"""
Get the configuration for the CNN model
Returns:
run_configuration: configuration for the CNN model
"""
base_model_config = {
"model_name": "cnn_regressor",
"version": "1.0.0",
"model_class": CNNTransformer,
"feature_config": feature_config | {"ignored_features":
[
"fertility_probability",
"ov_over_probability",
# "days_relative_to_ov",
# "is_biphasic",
"ov_day",
]},
"preprocessing": {
"window_shift": int((288 // take_every_nth) / 24 * shift_in_hours),
"take_every_nth": take_every_nth,
"min_input_length_fraction_for_padding": ((288 // take_every_nth) * 4) / input_window_length,
},
"batch_fn": produce_window_batches,
"collate_fn": simple_x_y_collate,
"model_creation_fn": simple_model_creation,
"model_save_fn": simple_model_save,
"model_load_fn": partial(simple_model_load, model_creation_fn=simple_model_creation),
"batch_loss_fn": get_model_loss,
"actual_fn": simple_get_y,
"predict_fn": simple_x_y_predict,
"model_parameters": {
**model_parameters | {"seq_len": input_window_length},
},
"input_window_length": input_window_length,
"output_window_length": output_window_length,
"output_window_offset": output_window_offset,
}
base_training_config = {
"batch_size": batch_size,
"model_class": CNNTransformer,
"learning_parameters": {
"learning_rate": max_lr * (batch_size / 4),
"epochs": num_epochs,
"patience": patience
},
"loss_functions": [
nn.MSELoss(),
nn.BCEWithLogitsLoss(),
],
"max_grad_norm": 1.0,
"train_size": 0.7,
"val_size": 0.15,
"test_size": 0.15,
}
return {
"name": run_name,
"description": run_description,
"model_configuration": base_model_config,
"training_configuration": base_training_config,
}
run_configuration = {
"runs": [
get_cnn_run_config(
run_name="cnn_ovulation_regression",
run_description="CNN model for ovulation regression",
input_window_length=input_window_length,
output_window_length=output_window_length,
take_every_nth=take_every_nth,
shift_in_hours=shift_in_hours,
output_window_offset=output_window_offset,
batch_size=batch_size,
model_parameters={
"cnn_channels": 64,
"kernel_size": 3,
"embed_dim": 64,
"num_enc_layers": 2,
"num_heads": 2,
},
max_lr=max_lr,
num_epochs=10,
patience=3,
feature_config=feature_config,
)
]
}
+321
View File
@@ -0,0 +1,321 @@
from functools import partial
from configs.config_utils import *
from configs.feature_config import feature_config
from experiment_setup import get_fertility_based_eval_functions
from models.cnn_transformer import CNNTransformer
from utils.data_utils import *
from utils.training import *
from models.utils import *
from models.collation import *
cnn_transformer_base_config = {
"model_name": "cnn_transformer",
"version": "1.0.0",
"model_class": CNNTransformer,
"feature_config": feature_config | {"ignored_features":
[
"fertility_probability",
"ov_over_probability",
# "days_relative_to_ov",
# "is_biphasic",
"ov_day",
]},
"batch_fn": produce_window_batches,
"collate_fn": simple_x_y_collate,
"model_creation_fn": simple_model_creation,
"model_save_fn": simple_model_save,
"model_load_fn": partial(simple_model_load, model_creation_fn=simple_model_creation),
"batch_loss_fn": get_model_loss,
"actual_fn": simple_get_y,
"predict_fn": simple_x_y_predict,
}
cnn_transformer_base_training_config = {
"batch_size": 128,
"model_class": CNNTransformer,
"learning_parameters": {
"max_lr": 1e-5,
"epochs": 30,
"patience": 5
},
"loss_functions": [
nn.MSELoss(),
nn.BCEWithLogitsLoss(),
],
"max_grad_norm": 1.0,
"train_size": 0.7,
"val_size": 0.15,
"test_size": 0.15,
}
fertility_complexity_run = get_run_config(
run_name="cnn_transformer_complexity_run",
base_model_configuration=cnn_transformer_base_config | get_data_config_set(
values_per_day=288,
shift_in_hours=12,
input_window_length_in_days=40,
output_window_length=1,
output_window_offset=0
),
base_training_configuration=cnn_transformer_base_training_config,
model_config_kwargs_list=[
{
"model_parameters": {
"embed_dim": 32,
"num_enc_layers": 2,
"num_heads": 2,
},
},
{
"model_parameters": {
"embed_dim": 64,
"num_enc_layers": 2,
"num_heads": 2,
},
},
{
"model_parameters": {
"embed_dim": 128,
"num_enc_layers": 4,
"num_heads": 4,
},
},
],
# add model config provider function to set seq_len in model parameters
additional_model_config_provider_fns={
"model_parameters": {
"seq_len": "eval(lambda x: x['input_window_length'])"
}
}
)
model_input_run = get_run_config(
run_name="cnn_transformer_input_size_run",
base_model_configuration=cnn_transformer_base_config |
{
"model_parameters": {
"embed_dim": 128,
"num_enc_layers": 4,
"num_heads": 4,
},
},
base_training_configuration=cnn_transformer_base_training_config,
model_config_kwargs_list=input_run_kwargs_list,
# add model config provider function to set seq_len in model parameters
additional_model_config_provider_fns={
"model_parameters": {
"seq_len": "eval(lambda x: x['input_window_length'])"
}
}
)
fertility_input_run = get_run_config(
run_name="cnn_transformer_fertility_input_run",
base_model_configuration=cnn_transformer_base_config |
{
"feature_config": feature_config | {"ignored_features":
[
# "fertility_probability",
# "ov_over_probability",
"days_relative_to_ov",
"is_biphasic",
"ov_day",
]},
"model_parameters": {
"embed_dim": 128,
"num_enc_layers": 4,
"num_heads": 4,
},
},
base_training_configuration=cnn_transformer_base_training_config,
model_config_kwargs_list=[
get_data_config_set(
values_per_day=288,
shift_in_hours=12,
input_window_length_in_days=10,
output_window_length=1,
output_window_offset=0
),
get_data_config_set(
values_per_day=288,
shift_in_hours=12,
input_window_length_in_days=20,
output_window_length=1,
output_window_offset=0
),
get_data_config_set(
values_per_day=288,
shift_in_hours=12,
input_window_length_in_days=40,
output_window_length=1,
output_window_offset=0
),
get_data_config_set(
values_per_day=288,
shift_in_hours=12,
input_window_length_in_days=80,
output_window_length=1,
output_window_offset=0
),
get_data_config_set(
values_per_day=288,
shift_in_hours=12,
input_window_length_in_days=160,
output_window_length=1,
output_window_offset=0
),
],
# add model config provider function to set seq_len in model parameters
additional_model_config_provider_fns={
"model_parameters": {
"seq_len": "eval(lambda x: x['input_window_length'])",
}
},
evaluation_configuration={
"eval_functions_getter": get_fertility_based_eval_functions
},
)
fertility_complexity_run = get_run_config(
run_name="cnn_transformer_complexity_run",
base_model_configuration=cnn_transformer_base_config | get_data_config_set(
values_per_day=288,
shift_in_hours=12,
input_window_length_in_days=40,
output_window_length=1,
output_window_offset=0
) | {
"feature_config": feature_config | {"ignored_features":
[
# "fertility_probability",
# "ov_over_probability",
"days_relative_to_ov",
"is_biphasic",
"ov_day",
]},
# "model_parameters": {
# "embed_dim": 256,
# "num_enc_layers": 2,
# "num_heads": 2,
# },
},
base_training_configuration=cnn_transformer_base_training_config,
evaluation_configuration={
"eval_functions_getter": get_fertility_based_eval_functions
},
model_config_kwargs_list=[
{
"model_parameters": {
"embed_dim": 16,
"num_enc_layers": 1,
"num_heads": 1,
},
},
{
"model_parameters": {
"embed_dim": 32,
"num_enc_layers": 1,
"num_heads": 1,
},
},
{
"model_parameters": {
"embed_dim": 64,
"num_enc_layers": 1,
"num_heads": 1,
},
},
{
"model_parameters": {
"embed_dim": 64,
"num_enc_layers": 2,
"num_heads": 2,
},
},
{
"model_parameters": {
"embed_dim": 128,
"num_enc_layers": 2,
"num_heads": 2,
},
},
{
"model_parameters": {
"embed_dim": 128,
"num_enc_layers": 4,
"num_heads": 4,
},
},
{
"model_parameters": {
"embed_dim": 256,
"num_enc_layers": 4,
"num_heads": 4,
},
},
{
"model_parameters": {
"embed_dim": 512,
"num_enc_layers": 4,
"num_heads": 4,
},
},
{
"model_parameters": {
"embed_dim": 512,
"num_enc_layers": 8,
"num_heads": 8,
},
},
],
# add model config provider function to set seq_len in model parameters
additional_model_config_provider_fns={
"model_parameters": {
"seq_len": "eval(lambda x: x['input_window_length'])"
}
}
)
best_config_run = get_run_config(
run_name="cnn_transformer_best_config_run",
base_model_configuration=cnn_transformer_base_config | get_data_config_set(
values_per_day=288,
shift_in_hours=12,
input_window_length_in_days=40,
output_window_length=1,
output_window_offset=0
) |
{
"feature_config": feature_config | {"ignored_features":
[
# "fertility_probability",
# "ov_over_probability",
"days_relative_to_ov",
"is_biphasic",
"ov_day",
]},
"model_parameters": {
"embed_dim": 512,
"num_enc_layers": 4,
"num_heads": 4,
},
},
base_training_configuration=cnn_transformer_base_training_config | {
"learning_parameters": {
"max_lr": 1e-4,
# "learning_rate": base_lr * (batch_size / 4),
"epochs": 30,
"patience": 5,
},
},
evaluation_configuration={
"eval_functions_getter": get_fertility_based_eval_functions
},
model_config_kwargs_list=[],
# add model config provider function to set seq_len in model parameters
additional_model_config_provider_fns={
"model_parameters": {
"seq_len": "eval(lambda x: x['input_window_length'])"
}
}
)
-133
View File
@@ -1,133 +0,0 @@
from typing import Callable
import configs
from configs.feature_config import feature_config
from configs.cnn_run_config import get_cnn_run_config
from configs.transformer_run_config import get_transformer_run_config
take_every_nth = int(288 / 12)
shift_in_hours = 12
input_window_length = (288 // take_every_nth) * 80
# output_window_length = (288 // take_every_nth) * 1
output_window_length = 1
output_window_offset = input_window_length + (288 // take_every_nth) * 0
window_shift = int((288 // take_every_nth) / 24 * shift_in_hours)
min_input_length_fraction_for_padding = ((288 // take_every_nth) * 4) / input_window_length
def config_generator(config_gen_fn: Callable,
fixed_params: dict,
variable_param_configs: list,
) -> list:
configs = list()
for variable_config in variable_param_configs:
config = fixed_params.copy()
for param_name, param_value in variable_config.items():
# update the config with the variable parameter, values can be None, if default should be used
if param_value is not None:
config[param_name] = param_value
configs.append(config_gen_fn(**config))
return configs
run_configuration = {
"name": "ovulation_regression",
"runs": config_generator(
get_cnn_run_config,
fixed_params={
"run_name": "cnn_ovulation_regression",
"run_description": "CNN model for ovulation regression",
"input_window_length": input_window_length,
"output_window_length": output_window_length,
"take_every_nth": take_every_nth,
"shift_in_hours": shift_in_hours,
"output_window_offset": output_window_offset,
"batch_size": 128,
"max_lr": 1e-5,
"num_epochs": 10,
"patience": 3,
"feature_config": feature_config,
},
variable_param_configs=[
{
"model_parameters": {
"cnn_channels": 32,
"kernel_size": 3,
"embed_dim": 32,
"num_enc_layers": 2,
"num_heads": 2,
},
},
{
"batch_size": 64,
"model_parameters": {
"cnn_channels": 64,
"kernel_size": 3,
"embed_dim": 64,
"num_enc_layers": 2,
"num_heads": 2,
},
},
{
"batch_size": 64,
"model_parameters": {
"cnn_channels": 128,
"kernel_size": 5,
"embed_dim": 128,
"num_enc_layers": 4,
"num_heads": 4,
},
},
]
) + config_generator(
get_transformer_run_config,
fixed_params={
"run_name": "transformer_ovulation_regression",
"run_description": "Transformer model for ovulation regression",
"input_window_length": input_window_length,
"output_window_length": output_window_length,
"take_every_nth": take_every_nth,
"shift_in_hours": shift_in_hours,
"output_window_offset": output_window_offset,
"batch_size": 128,
"max_lr": 1e-5,
"num_epochs": 10,
"patience": 3,
"feature_config": feature_config,
},
variable_param_configs=[
{
"model_parameters": {
"embed_dim": 64,
"num_enc_layers": 2,
"num_heads": 2,
},
},
{
"batch_size": 64,
"model_parameters": {
"embed_dim": 128,
"num_enc_layers": 4,
"num_heads": 4,
},
},
{
"batch_size": 64,
"model_parameters": {
"embed_dim": 256,
"num_enc_layers": 4,
"num_heads": 4,
},
},
{
"batch_size": 32,
"model_parameters": {
"embed_dim": 512,
"num_enc_layers": 4,
"num_heads": 4,
},
},
]
)
}
+356
View File
@@ -0,0 +1,356 @@
from copy import deepcopy
from typing import Callable
from vsm_datascience_common import constants
def recursive_dict_update(base_dict: dict, update_dict: dict) -> dict:
base_dict = deepcopy(base_dict)
for key, value in update_dict.items():
if isinstance(value, dict) and key in base_dict:
base_dict[key] = recursive_dict_update(base_dict[key], value)
else:
base_dict[key] = value
return base_dict
def recursive_provider_dict_update(base_dict: dict,
provider_fns: dict,
context: dict = None) -> dict:
"""
Recursively updates a base dictionary with values from provider functions.
Provider functions get intermediate dictionary as input and return a value.
Args:
base_dict: base dictionary to update.
provider_fns: provider functions to use for updating the dictionary.
context: base dict to use as context in recursive calls, defaults to None.
Returns:
A new dictionary with updated values from provider functions.
"""
if context is None:
base_dict = deepcopy(base_dict)
context = base_dict
for key, provider_fn in provider_fns.items():
if isinstance(provider_fn, dict):
# if the value is a dictionary, recursively update it
base_dict[key] = recursive_provider_dict_update(base_dict.get(key, {}), provider_fn, context)
elif callable(provider_fn):
# call the provider function with the current base_dict as input
base_dict[key] = provider_fn(context)
else:
# if value is string and starts with "eval(", evaluate it
if isinstance(provider_fn, str) and provider_fn.startswith("eval(") and provider_fn.endswith(")"):
# evaluate the string as a Python expression
eval_fn = eval(provider_fn[5:-1])
base_dict[key] = eval_fn(context)
else:
# if the value is not callable, just set it
base_dict[key] = provider_fn
return base_dict
def config_generator(config_gen_fn: Callable,
fixed_params: dict,
variable_param_configs: list,
) -> list:
configs = list()
for variable_config in variable_param_configs:
config = fixed_params.copy()
for param_name, param_value in variable_config.items():
# update the config with the variable parameter, values can be None, if default should be used
if param_value is not None:
config[param_name] = param_value
configs.append(config_gen_fn(**config))
return configs
def get_run_config(
run_name: str,
base_model_configuration: dict,
base_training_configuration: dict,
evaluation_configuration: dict = None,
model_config_kwargs_list: list = None,
training_config_kwargs_list: list = None,
*args, **kwargs) -> dict:
"""
Generates a list of training configurations for a given model and training setup.
Args and kwargs are forwarded to the `get_training_config` function.
Args:
run_name: name of the run.
base_model_configuration: base model configuration dictionary.
base_training_configuration: base training configuration dictionary.
evaluation_configuration: evaluation configuration dictionary, defaults to None.
model_config_kwargs_list: list of dictionaries containing additional keyword arguments for model configuration.
training_config_kwargs_list: list of dictionaries containing additional keyword arguments for training configuration.
Returns:
A dictionary containing the run configuration with a list of training configurations.
"""
if model_config_kwargs_list is None:
model_config_kwargs_list = list()
if training_config_kwargs_list is None:
training_config_kwargs_list = list()
training_configs = list()
num_trainings = max(len(model_config_kwargs_list), len(training_config_kwargs_list), 1)
num_model_kwargs = len(model_config_kwargs_list)
num_training_kwargs = len(training_config_kwargs_list)
# if num_model_kwargs == 0 and num_training_kwargs == 0:
# raise ValueError("Both model_config_kwargs_list and training_config_kwargs_list cannot be empty.")
for i in range(num_trainings):
# list length can either be equal, one, or zero
if num_model_kwargs == 0:
model_config_kwargs = {}
elif num_model_kwargs == 1:
model_config_kwargs = model_config_kwargs_list[0]
else:
model_config_kwargs = model_config_kwargs_list[i]
if num_training_kwargs == 0:
training_config_kwargs = {}
elif num_training_kwargs == 1:
training_config_kwargs = training_config_kwargs_list[0]
else:
training_config_kwargs = training_config_kwargs_list[i]
training_config = get_training_config(
training_name=f"{run_name}_{i}",
training_description=f"{run_name} training configuration {i}",
base_model_config=base_model_configuration,
model_config_kwargs=model_config_kwargs,
base_training_config=base_training_configuration,
training_config_kwargs=training_config_kwargs,
*args,
**kwargs,
)
training_configs.append(training_config)
return {
"name": run_name,
"runs": training_configs,
"evaluation_configuration": evaluation_configuration if evaluation_configuration is not None else {}
}
def get_training_config(
training_name: str,
training_description: str,
base_model_config: dict,
model_config_kwargs: dict,
base_training_config: dict,
training_config_kwargs: dict,
additional_model_config_provider_fns: dict = None,
additional_training_config_provider_fns: dict = None,
*args, **kwargs) -> dict:
"""
Generates a training configuration for a given model and training setup.
Args:
training_name: Name of the training.
training_description: Description of the training.
base_model_config: Base model configuration dictionary.
model_config_kwargs: Additional keyword arguments for model configuration.
base_training_config: Base training configuration dictionary.
training_config_kwargs: Additional keyword arguments for training configuration.
additional_model_config_provider_fns: Additional provider functions for parts of the config that depend on the config itself
such as input length as model parameter.
additional_training_config_provider_fns: Additional provider functions for parts of the config that depend on the config itself
such as input length as model parameter.
Returns:
A dictionary containing the training configuration with model and training parameters.
"""
# recursively merge the base model configuration with the provided kwargs
model_configuration = recursive_dict_update(base_model_config, model_config_kwargs)
# update based on provider functions
if additional_model_config_provider_fns:
model_configuration = recursive_provider_dict_update(model_configuration, additional_model_config_provider_fns)
required_model_configuration_keys = [
"model_name",
"version",
"model_class",
"feature_config",
"preprocessing",
"batch_fn",
"collate_fn",
"model_creation_fn",
"model_save_fn",
"model_load_fn",
"batch_loss_fn",
"actual_fn",
"predict_fn",
"model_parameters",
"input_window_length",
"output_window_length",
"output_window_offset"
]
if not all(key in model_configuration for key in required_model_configuration_keys):
missing_keys = [
key for key in required_model_configuration_keys if key not in base_model_config
]
raise ValueError(f"Missing required keys in model configuration: {', '.join(missing_keys)}")
training_configuration = recursive_dict_update(base_training_config, training_config_kwargs)
# update based on provider functions
if additional_training_config_provider_fns:
training_configuration = recursive_provider_dict_update(training_configuration,
additional_training_config_provider_fns)
# if "model_class" is not in training_configuration, set it to the model class from the model configuration
if "model_class" not in training_configuration:
training_configuration["model_class"] = base_model_config["model_class"]
required_training_configuration_keys = [
"model_class",
"batch_size",
"learning_parameters",
"max_grad_norm",
"train_size",
"val_size",
"test_size"
]
if not all(key in training_configuration for key in required_training_configuration_keys):
missing_keys = [
key for key in required_training_configuration_keys if key not in training_configuration
]
raise ValueError(f"Missing required keys in training configuration: {', '.join(missing_keys)}")
return {
"name": training_name,
"description": training_description,
"model_configuration": model_configuration,
"training_configuration": training_configuration,
}
def get_data_config_set(
values_per_day: int,
shift_in_hours: int,
input_window_length_in_days: int,
output_window_length: int,
output_window_offset: int,
) -> dict:
measurements_per_day = constants.MEASUREMENTS_PER_DAY
take_every_nth = int(measurements_per_day / values_per_day)
input_window_length = (measurements_per_day // take_every_nth) * input_window_length_in_days
return {
"input_window_length": input_window_length,
"output_window_length": output_window_length,
"output_window_offset": input_window_length + output_window_offset,
"preprocessing": {
"window_shift": max(int((measurements_per_day // take_every_nth) / 24 * shift_in_hours), 1),
"take_every_nth": take_every_nth,
"min_input_length_fraction_for_padding":
((measurements_per_day // take_every_nth) * 4) / input_window_length,
}
}
input_run_kwargs_list = [
get_data_config_set(
values_per_day=12,
shift_in_hours=12,
input_window_length_in_days=10,
output_window_length=1,
output_window_offset=0
),
get_data_config_set(
values_per_day=12,
shift_in_hours=12,
input_window_length_in_days=20,
output_window_length=1,
output_window_offset=0
),
get_data_config_set(
values_per_day=12,
shift_in_hours=12,
input_window_length_in_days=40,
output_window_length=1,
output_window_offset=0
),
get_data_config_set(
values_per_day=12,
shift_in_hours=12,
input_window_length_in_days=80,
output_window_length=1,
output_window_offset=0
),
get_data_config_set(
values_per_day=12,
shift_in_hours=12,
input_window_length_in_days=160,
output_window_length=1,
output_window_offset=0
),
get_data_config_set(
values_per_day=1,
shift_in_hours=12,
input_window_length_in_days=20,
output_window_length=1,
output_window_offset=0
),
get_data_config_set(
values_per_day=2,
shift_in_hours=12,
input_window_length_in_days=20,
output_window_length=1,
output_window_offset=0
),
get_data_config_set(
values_per_day=4,
shift_in_hours=12,
input_window_length_in_days=20,
output_window_length=1,
output_window_offset=0
),
get_data_config_set(
values_per_day=12,
shift_in_hours=12,
input_window_length_in_days=20,
output_window_length=1,
output_window_offset=0
),
get_data_config_set(
values_per_day=24,
shift_in_hours=12,
input_window_length_in_days=20,
output_window_length=1,
output_window_offset=0
),
get_data_config_set(
values_per_day=48,
shift_in_hours=12,
input_window_length_in_days=20,
output_window_length=1,
output_window_offset=0
),
get_data_config_set(
values_per_day=72,
shift_in_hours=12,
input_window_length_in_days=20,
output_window_length=1,
output_window_offset=0
),
get_data_config_set(
values_per_day=288,
shift_in_hours=12,
input_window_length_in_days=20,
output_window_length=1,
output_window_offset=0
)
]
+40 -15
View File
@@ -7,6 +7,7 @@ from torch import nn
import numpy as np
from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler
from torch.nn import BCEWithLogitsLoss, MSELoss
from torch.optim.lr_scheduler import OneCycleLR
from torch.optim import AdamW
@@ -24,6 +25,10 @@ feature_config = {
"$gt": constants.MEASUREMENTS_PER_DAY * 10,
"$lt": constants.MEASUREMENTS_PER_DAY * 150
},
"duration_in_days": {
"$gt": 10,
"$lt": 150,
},
"ends_at": {
"$exists": True,
"$ne": None
@@ -49,6 +54,21 @@ feature_config = {
"static_categorical_features": [
],
"static_continuous_features": [
{
"name": "user_age",
"fn": get_user_age,
"scaler": RobustScaler
},
{
"name": "user_age",
"fn": get_user_height,
"scaler": RobustScaler
},
{
"name": "user_weight",
"fn": get_user_weight,
"scaler": RobustScaler
},
{
"name": "average_cycle_length",
"fn": get_cycle_length_stats,
@@ -133,35 +153,40 @@ feature_config = {
},
],
"target_features": [
# {
# "name": "fertility_probability",
# "fn": partial(get_fertility_probability, shift=0),
# "scaler": MinMaxScaler,
# "accumulation_fn": np.max
# },
# {
# "name": "ov_over_probability",
# "fn": partial(get_ov_over_probability, shift=0),
# "scaler": MinMaxScaler,
# "accumulation_fn": np.max
# },
{
"name": "fertility_probability",
"fn": partial(get_fertility_probability, shift=0),
"scaler": MinMaxScaler,
"accumulation_fn": np.max,
"loss_fn": MSELoss,
},
{
"name": "ov_over_probability",
"fn": partial(get_ov_over_probability, shift=0),
"scaler": MinMaxScaler,
"accumulation_fn": np.max,
"loss_fn": BCEWithLogitsLoss,
},
{
"name": "days_relative_to_ov",
"fn": get_days_relative_to_ov,
"scaler": RobustScaler,
"accumulation_fn": np.max
"accumulation_fn": np.max,
"loss_fn": MSELoss,
},
{
"name": "ov_day",
"fn": get_ov_day,
"scaler": RobustScaler,
"accumulation_fn": np.max
"accumulation_fn": np.max,
"loss_fn": MSELoss,
},
{
"name": "is_biphasic",
"fn": get_is_biphasic,
"scaler": MinMaxScaler,
"accumulation_fn": np.max
"accumulation_fn": np.max,
"loss_fn": BCEWithLogitsLoss
}
]
}
+199
View File
@@ -0,0 +1,199 @@
from functools import partial
from configs.config_utils import *
from configs.feature_config import feature_config
from experiment_setup import get_fertility_based_eval_functions
from utils.data_utils import *
from utils.training import *
from models.lstm import *
from models.utils import *
from models.collation import *
lstm_base_config = {
"model_name": "lstm",
"version": "1.0.0",
"model_class": LSTM,
"feature_config": feature_config | {"ignored_features":
[
"fertility_probability",
"ov_over_probability",
# "days_relative_to_ov",
# "is_biphasic",
"ov_day",
]},
"batch_fn": produce_window_batches,
"collate_fn": simple_x_y_collate,
"model_creation_fn": simple_model_creation,
"model_save_fn": simple_model_save,
"model_load_fn": partial(simple_model_load, model_creation_fn=simple_model_creation),
"batch_loss_fn": get_model_loss,
"actual_fn": simple_get_y,
"predict_fn": simple_x_y_predict,
}
base_lstm_training_config = {
"batch_size": 256,
"model_class": LSTM,
"learning_parameters": {
"max_lr": 1e-4,
# "learning_rate": base_lr * (batch_size / 4),
"epochs": 30,
"patience": 5,
},
"max_grad_norm": 1.0,
"train_size": 0.7,
"val_size": 0.15,
"test_size": 0.15,
}
model_input_run = get_run_config(
run_name="lstm_input_size_run",
base_model_configuration=lstm_base_config |
{
"model_parameters": {
"lstm_hidden_size": 64,
"num_layers": 2,
},
},
base_training_configuration=base_lstm_training_config,
model_config_kwargs_list=input_run_kwargs_list
)
fertility_complexity_run = get_run_config(
run_name="lstm_fertility_complexity_run",
base_model_configuration=lstm_base_config | get_data_config_set(
values_per_day=12,
shift_in_hours=12,
input_window_length_in_days=160,
output_window_length=1,
output_window_offset=0
) | {
"feature_config": feature_config | {"ignored_features":
[
# "fertility_probability",
# "ov_over_probability",
"days_relative_to_ov",
"is_biphasic",
"ov_day",
]},
# "model_parameters": {
# "lstm_hidden_size": 128,
# "num_layers": 4,
# },
},
base_training_configuration=base_lstm_training_config,
model_config_kwargs_list=[
{
"model_parameters": {
"lstm_hidden_size": 16,
"num_layers": 1,
},
},
{
"model_parameters": {
"lstm_hidden_size": 32,
"num_layers": 1,
},
},
{
"model_parameters": {
"lstm_hidden_size": 32,
"num_layers": 2,
},
},
{
"model_parameters": {
"lstm_hidden_size": 64,
"num_layers": 2,
},
},
{
"model_parameters": {
"lstm_hidden_size": 128,
"num_layers": 2,
},
},
{
"model_parameters": {
"lstm_hidden_size": 128,
"num_layers": 4,
},
},
{
"model_parameters": {
"lstm_hidden_size": 256,
"num_layers": 4,
},
},
{
"model_parameters": {
"lstm_hidden_size": 512,
"num_layers": 4,
},
},
],
evaluation_configuration={
"eval_functions_getter": get_fertility_based_eval_functions
},
)
fertility_input_run = get_run_config(
run_name="lstm_fertility_input_size_run",
base_model_configuration=lstm_base_config |
{
"feature_config": feature_config | {"ignored_features":
[
# "fertility_probability",
# "ov_over_probability",
"days_relative_to_ov",
"is_biphasic",
"ov_day",
]},
"model_parameters": {
"lstm_hidden_size": 128,
"num_layers": 4,
},
},
base_training_configuration=base_lstm_training_config,
model_config_kwargs_list=input_run_kwargs_list,
evaluation_configuration={
"eval_functions_getter": get_fertility_based_eval_functions
},
)
best_config_run = get_run_config(
run_name="lstm_best_config_run",
base_model_configuration=lstm_base_config | get_data_config_set(
values_per_day=12,
shift_in_hours=12,
input_window_length_in_days=160,
output_window_length=1,
output_window_offset=0
) | {
"feature_config": feature_config | {"ignored_features":
[
# "fertility_probability",
# "ov_over_probability",
"days_relative_to_ov",
"is_biphasic",
"ov_day",
]},
"model_parameters": {
"lstm_hidden_size": 512,
"num_layers": 4,
},
},
base_training_configuration=base_lstm_training_config | {
"learning_parameters": {
"max_lr": 1e-4,
# "learning_rate": base_lr * (batch_size / 4),
"epochs": 50,
"patience": 7,
},
},
model_config_kwargs_list=[],
evaluation_configuration={
"eval_functions_getter": get_fertility_based_eval_functions
},
)
-127
View File
@@ -1,127 +0,0 @@
from functools import partial
from configs.feature_config import feature_config
from utils.data_utils import *
from utils.training import *
from models.lstm import *
from models.utils import *
from models.collation import *
take_every_nth = int(288 / 12)
shift_in_hours = 12
input_window_length = (288 // take_every_nth) * 80
# output_window_length = (288 // take_every_nth) * 1
output_window_length = 1
output_window_offset = input_window_length + (288 // take_every_nth) * 0
window_shift = int((288 // take_every_nth) / 24 * shift_in_hours)
min_input_length_fraction_for_padding = ((288 // take_every_nth) * 4) / input_window_length
max_lr = 1e-5
batch_size = 128
def get_lstm_run_config(
run_name: str,
run_description: str,
input_window_length: int,
output_window_length: int,
take_every_nth: int,
shift_in_hours: int,
output_window_offset: int,
batch_size: int,
model_parameters: dict,
max_lr: float,
num_epochs: int,
patience: int,
feature_config: dict):
"""
Get the configuration for the LSTM model
Returns:
run_configuration: configuration for the LSTM model
"""
base_model_config = {
"model_name": "lstm_regressor",
"version": "1.0.0",
"model_class": LSTMModel,
"feature_config": feature_config | {"ignored_features":
[
"fertility_probability",
"ov_over_probability",
# "days_relative_to_ov",
# "is_biphasic",
"ov_day",
]},
"preprocessing": {
"window_shift": int((288 // take_every_nth) / 24 * shift_in_hours),
"take_every_nth": take_every_nth,
"min_input_length_fraction_for_padding": ((288 // take_every_nth) * 4) / input_window_length,
},
"batch_fn": produce_window_batches,
"collate_fn": simple_x_y_collate,
"model_creation_fn": simple_model_creation,
"model_save_fn": simple_model_save,
"model_load_fn": partial(simple_model_load, model_creation_fn=simple_model_creation),
"batch_loss_fn": get_model_loss,
"actual_fn": simple_get_y,
"predict_fn": simple_x_y_predict,
"model_parameters": {
**model_parameters,
},
"input_window_length": input_window_length,
"output_window_length": output_window_length,
"output_window_offset": output_window_offset,
}
base_training_config = {
"batch_size": batch_size,
"model_class": LSTMModel,
"learning_parameters": {
"learning_rate": max_lr * (batch_size / 4),
# "learning_rate": base_lr * (batch_size / 4),
"epochs": num_epochs,
"patience": patience,
},
"loss_functions": [
nn.MSELoss(),
nn.BCEWithLogitsLoss(),
],
"max_grad_norm": 1.0,
"train_size": 0.7,
"val_size": 0.15,
"test_size": 0.15,
}
return {
"name": run_name,
"description": run_description,
"model_configuration": base_model_config,
"training_configuration": base_training_config,
}
run_configuration = {
"item_limit": 100,
"runs": [
get_lstm_run_config(
run_name="lstm_regressor",
run_description="LSTM regressor for fertility prediction",
input_window_length=input_window_length,
output_window_length=output_window_length,
take_every_nth=take_every_nth,
shift_in_hours=shift_in_hours,
output_window_offset=output_window_offset,
batch_size=batch_size,
model_parameters={
"cnn_channels": 64,
"cnn_kernel_size": 3,
"embed_dim": 128,
"lstm_hidden_size": 128,
"num_layers": 4,
},
max_lr=max_lr,
num_epochs=1000,
patience=50,
feature_config=feature_config
)
]
}
-109
View File
@@ -1,109 +0,0 @@
from functools import partial
from configs.feature_config import feature_config
from utils.data_utils import *
from utils.training import *
from models.third_party.patch_tst.models.PatchTST import Model as PatchTST
from models.utils import *
from models.collation import *
take_every_nth = int(288 / 12)
shift_in_hours = 12
input_window_length = (288 // take_every_nth) * 80
# output_window_length = (288 // take_every_nth) * 1
output_window_length = 1
output_window_offset = input_window_length + (288 // take_every_nth) * 0
window_shift = int((288 // take_every_nth) / 24 * shift_in_hours)
min_input_length_fraction_for_padding = ((288 // take_every_nth) * 4) / input_window_length
max_lr = 1e-5
batch_size = 64
run_configuration = {
"item_limit": 100,
"runs": [
{
"name": "lstm_ovulation_regression",
"description": "LSTM model for ovulation regression",
"model_configuration": {
"model_name": "patch_tst_regressor",
"version": "1.0.0",
"model_class": PatchTST,
"feature_config": feature_config | {"ignored_features":
[
"fertility_probability",
"ov_over_probability",
# "days_relative_to_ov",
# "is_biphasic",
"ov_day",
]},
"preprocessing": {
"window_shift": int((288 // take_every_nth) / 24 * shift_in_hours),
"take_every_nth": take_every_nth,
"min_input_length_fraction_for_padding": ((288 // take_every_nth) * 4) / input_window_length,
},
"batch_fn": produce_window_batches,
"collate_fn": simple_x_y_collate,
"model_creation_fn": simple_model_creation,
"model_save_fn": simple_model_save,
"model_load_fn": partial(simple_model_load, model_creation_fn=simple_model_creation),
"batch_loss_fn": get_model_loss,
"actual_fn": simple_get_y,
"predict_fn": simple_x_y_predict,
"model_parameters": {
"configs": {
# core
"seq_len": input_window_length,
"pred_len": output_window_length,
"seq_pred": False,
# model
"e_layers": 4,
"n_heads": 4,
"d_model": 128,
"d_ff": 128,
"dropout": 0.2,
"fc_dropout": 0.2,
"head_dropout": 0.0,
"individual": True,
# patch
# "patch_len": input_window_length,
"patch_len": int(288 / take_every_nth),
"stride": int(288 / take_every_nth / 2),
"padding_patch": 0,
# preprocessing
"revin": False,
"affine": False,
"subtract_last": False,
# decomp
"decomposition": True,
"kernel_size": 3,
}
},
"input_window_length": input_window_length,
"output_window_length": output_window_length,
"output_window_offset": output_window_offset,
},
"training_configuration": {
"batch_size": batch_size,
"model_class": PatchTST,
"learning_parameters": {
# "learning_rate": base_lr,
"learning_rate": max_lr * (batch_size / 4),
"epochs": 10,
"patience": 3,
},
"loss_functions": [
nn.MSELoss(),
nn.BCEWithLogitsLoss(),
],
"max_grad_norm": 1.0,
"train_size": 0.7,
"val_size": 0.15,
"test_size": 0.15,
}
}
]
}
+225
View File
@@ -0,0 +1,225 @@
from functools import partial
from configs.config_utils import *
from configs.feature_config import feature_config
from experiment_setup import get_fertility_based_eval_functions
from utils.data_utils import *
from utils.training import *
from models.transformer import *
from models.utils import *
from models.collation import *
base_transformer_model_config = {
"model_name": "transformer",
"version": "1.0.0",
"model_class": TransformerModel,
"feature_config": feature_config | {"ignored_features":
[
"fertility_probability",
"ov_over_probability",
# "days_relative_to_ov",
# "is_biphasic",
"ov_day",
]},
"batch_fn": produce_window_batches,
"model_creation_fn": simple_model_creation,
"collate_fn": simple_x_y_collate,
"model_save_fn": simple_model_save,
"model_load_fn": partial(simple_model_load, model_creation_fn=simple_model_creation),
"batch_loss_fn": get_model_loss,
"actual_fn": simple_get_y,
"predict_fn": simple_x_y_predict,
}
base_transformer_training_config = {
"batch_size": 128,
"model_class": TransformerModel,
"learning_parameters": {
"max_lr": 1e-5,
"epochs": 30,
"patience": 5,
},
"loss_functions": [
nn.MSELoss(),
nn.BCEWithLogitsLoss(),
],
"max_grad_norm": 1.0,
"train_size": 0.7,
"val_size": 0.15,
"test_size": 0.15,
}
fertility_complexity_run = get_run_config(
run_name="transformer_fertility_complexity_run",
base_model_configuration=base_transformer_model_config | get_data_config_set(
values_per_day=12,
shift_in_hours=12,
input_window_length_in_days=160,
output_window_length=1,
output_window_offset=0
) | {
"feature_config": feature_config | {"ignored_features":
[
# "fertility_probability",
# "ov_over_probability",
"days_relative_to_ov",
"is_biphasic",
"ov_day",
]},
# "model_parameters": {
# "embed_dim": 256,
# "num_enc_layers": 2,
# "num_heads": 2,
# },
},
base_training_configuration=base_transformer_training_config,
evaluation_configuration={
"eval_functions_getter": get_fertility_based_eval_functions
},
model_config_kwargs_list=[
{
"model_parameters": {
"embed_dim": 16,
"num_enc_layers": 1,
"num_heads": 1,
},
},
{
"model_parameters": {
"embed_dim": 32,
"num_enc_layers": 1,
"num_heads": 1,
},
},
{
"model_parameters": {
"embed_dim": 64,
"num_enc_layers": 1,
"num_heads": 1,
},
},
{
"model_parameters": {
"embed_dim": 64,
"num_enc_layers": 2,
"num_heads": 2,
},
},
{
"model_parameters": {
"embed_dim": 128,
"num_enc_layers": 2,
"num_heads": 2,
},
},
{
"model_parameters": {
"embed_dim": 128,
"num_enc_layers": 4,
"num_heads": 4,
},
},
{
"model_parameters": {
"embed_dim": 256,
"num_enc_layers": 4,
"num_heads": 4,
},
},
{
"model_parameters": {
"embed_dim": 512,
"num_enc_layers": 4,
"num_heads": 4,
},
},
{
"model_parameters": {
"embed_dim": 512,
"num_enc_layers": 8,
"num_heads": 8,
},
},
],
# add model config provider function to set seq_len in model parameters
additional_model_config_provider_fns={
"model_parameters": {
"seq_len": "eval(lambda x: x['input_window_length'])"
}
}
)
fertility_input_run = get_run_config(
run_name="transformer_fertility_input_run",
base_model_configuration=base_transformer_model_config | {
"feature_config": feature_config | {"ignored_features":
[
# "fertility_probability",
# "ov_over_probability",
"days_relative_to_ov",
"is_biphasic",
"ov_day",
]},
"model_parameters": {
"embed_dim": 256,
"num_enc_layers": 2,
"num_heads": 2,
},
},
base_training_configuration=base_transformer_training_config,
evaluation_configuration={
"eval_functions_getter": get_fertility_based_eval_functions
},
model_config_kwargs_list=input_run_kwargs_list,
# add model config provider function to set seq_len in model parameters
additional_model_config_provider_fns={
"model_parameters": {
"seq_len": "eval(lambda x: x['input_window_length'])"
}
}
)
best_config_run = get_run_config(
run_name="transformer_best_config_run",
base_model_configuration=base_transformer_model_config | get_data_config_set(
values_per_day=12,
shift_in_hours=12,
input_window_length_in_days=160,
output_window_length=1,
output_window_offset=0
) |
{
"feature_config": feature_config | {"ignored_features":
[
# "fertility_probability",
# "ov_over_probability",
"days_relative_to_ov",
"is_biphasic",
"ov_day",
]},
"model_parameters": {
"embed_dim": 512,
"num_enc_layers": 4,
"num_heads": 4,
},
},
base_training_configuration=base_transformer_training_config | {
"learning_parameters": {
"max_lr": 1e-4,
# "learning_rate": base_lr * (batch_size / 4),
"epochs": 30,
"patience": 5,
},
},
evaluation_configuration={
"eval_functions_getter": get_fertility_based_eval_functions
},
model_config_kwargs_list=[],
# add model config provider function to set seq_len in model parameters
additional_model_config_provider_fns={
"model_parameters": {
"seq_len": "eval(lambda x: x['input_window_length'])"
}
}
)
-123
View File
@@ -1,123 +0,0 @@
from functools import partial
from configs.feature_config import feature_config
from utils.data_utils import *
from utils.training import *
from models.transformer import *
from models.utils import *
from models.collation import *
take_every_nth = int(288 / 12)
shift_in_hours = 12
input_window_length = (288 // take_every_nth) * 80
# output_window_length = (288 // take_every_nth) * 1
output_window_length = 1
output_window_offset = input_window_length + (288 // take_every_nth) * 0
window_shift = int((288 // take_every_nth) / 24 * shift_in_hours)
min_input_length_fraction_for_padding = ((288 // take_every_nth) * 4) / input_window_length
transformer_batch_size = 128
def get_transformer_run_config(
run_name: str,
run_description: str,
input_window_length: int,
output_window_length: int,
take_every_nth: int,
shift_in_hours: int,
output_window_offset: int,
batch_size: int,
model_parameters: dict,
max_lr: float,
num_epochs: int,
patience: int,
feature_config: dict):
"""
Get the configuration for the Transformer model
Returns:
run_configuration: configuration for the Transformer model
"""
base_model_config = {
"model_name": "transformer_regressor",
"version": "1.0.0",
"model_class": TransformerModel,
"feature_config": feature_config | {"ignored_features":
[
"fertility_probability",
"ov_over_probability",
# "days_relative_to_ov",
# "is_biphasic",
"ov_day",
]},
"preprocessing": {
"window_shift": int((288 // take_every_nth) / 24 * shift_in_hours),
"take_every_nth": take_every_nth,
"min_input_length_fraction_for_padding": min_input_length_fraction_for_padding,
},
"batch_fn": produce_window_batches,
"model_creation_fn": simple_model_creation,
"collate_fn": simple_x_y_collate,
"model_save_fn": simple_model_save,
"model_load_fn": partial(simple_model_load, model_creation_fn=simple_model_creation),
"batch_loss_fn": get_model_loss,
"actual_fn": simple_get_y,
"predict_fn": simple_x_y_predict,
"model_parameters": {
**model_parameters | {"seq_len": input_window_length},
},
"input_window_length": input_window_length,
"output_window_length": output_window_length,
"output_window_offset": output_window_offset,
}
base_training_config = {
"batch_size": batch_size,
"model_class": TransformerModel,
"learning_parameters": {
"learning_rate": max_lr * (batch_size / 4),
# "learning_rate": base_lr * (batch_size / 4),
"epochs": num_epochs,
"patience": patience,
},
"loss_functions": [
nn.MSELoss(),
nn.BCEWithLogitsLoss(),
],
"max_grad_norm": 1.0,
"train_size": 0.7,
"val_size": 0.15,
"test_size": 0.15,
}
return {
"name": run_name,
"description": run_description,
"model_configuration": base_model_config,
"training_configuration": base_training_config
}
run_configuration = {
"runs": [
get_transformer_run_config(
run_name="transformer_ovulation_regression",
run_description="Transformer regressor for ovulation prediction",
input_window_length=input_window_length,
output_window_length=output_window_length,
take_every_nth=take_every_nth,
shift_in_hours=shift_in_hours,
output_window_offset=output_window_offset,
batch_size=transformer_batch_size,
model_parameters={
"embed_dim": 128,
"num_heads": 4,
"num_enc_layers": 4,
},
max_lr=1e-5,
num_epochs=20,
patience=3,
feature_config=feature_config,
)
]
}