This commit is contained in:
Alex Blank
2025-05-19 13:59:16 +02:00
parent 426f4d6963
commit c6defa2065
196 changed files with 18625 additions and 1 deletions
View File
+127
View File
@@ -0,0 +1,127 @@
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,
)
]
}
+132
View File
@@ -0,0 +1,132 @@
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": 256,
"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,
},
},
{
"model_parameters": {
"cnn_channels": 64,
"kernel_size": 3,
"embed_dim": 64,
"num_enc_layers": 2,
"num_heads": 2,
},
},
{
"batch_size": 128,
"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,
},
},
]
)
}
+167
View File
@@ -0,0 +1,167 @@
import os
from functools import partial
import math
import torch
from torch import nn
import numpy as np
from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler
from torch.optim.lr_scheduler import OneCycleLR
from torch.optim import AdamW
from data_analysis.models.ov_detection.config import model_config
from utils.feature_functions import *
from utils.loss_functions import weighted_bce_loss_fn
from utils.training_utils import collate
from vsm_datascience_common import constants
feature_config = {
"feature_set_name": "full_feature_set",
"filter_criteria": {
"measurements.length": {
"$gt": constants.MEASUREMENTS_PER_DAY * 10,
"$lt": constants.MEASUREMENTS_PER_DAY * 150
},
"ends_at": {
"$exists": True,
"$ne": None
},
"$and": [
{"measurements.values": {"$not": {"$elemMatch": {"$lt": 35}}}},
{"measurements.values": {"$not": {"$elemMatch": {"$gt": 43}}}}
]
},
"augmentation": {
"use_augmentation": True,
"max_lookback": 4,
},
"feature_sets": [
"static_categorical_features",
"static_continuous_features",
"known_categorical_features",
"known_continuous_features",
"observed_categorical_features",
"observed_continuous_features",
"target_features"
],
"static_categorical_features": [
],
"static_continuous_features": [
{
"name": "average_cycle_length",
"fn": get_cycle_length_stats,
"scaler": RobustScaler
},
{
"name": "average_ovulation_day",
"fn": get_average_ovulation_day,
"scaler": RobustScaler
},
{
"name": "ovulation_std",
"fn": get_ovulation_std,
"scaler": StandardScaler
},
{
"name": "biphasic_fraction",
"fn": get_biphasic_fraction,
"scaler": MinMaxScaler
},
{
"name": "num_cycles",
"fn": get_num_cycles,
"scaler": RobustScaler
},
{
"name": "temperature_averages",
"fn": get_average_temperatures,
"scaler": StandardScaler
}
],
"known_categorical_features": [
],
"known_continuous_features": [
{
"name": "hours_from_start",
"fn": partial(get_hours_from_start, shift=0),
"scaler": MinMaxScaler,
"accumulation_fn": np.max
},
{
"name": "hour_of_day",
"fn": partial(get_hour_of_day_encoded, shift=0),
"scaler": None,
"accumulation_fn": np.max
},
{
"name": "day_of_week",
"fn": partial(get_day_of_week_encoded, shift=0),
"scaler": None,
"accumulation_fn": np.max
},
{
"name": "month_of_year",
"fn": partial(get_month_of_year_encoded, shift=0),
"scaler": None,
"accumulation_fn": np.max
}
],
"observed_categorical_features": [
],
"observed_continuous_features": [
{
"name": "temperature",
"fn": partial(get_temperature, shift=0),
"scaler": StandardScaler
},
{
"name": "rolling_average_temperature",
"fn": partial(get_rolling_average_with_padding, shift=0),
"scaler": StandardScaler
},
{
"name": "rolling_window_temperature_min",
"fn": partial(get_window_fn, window_size=constants.MEASUREMENTS_PER_DAY, fn=partial(np.min, axis=1)),
"scaler": StandardScaler
},
{
"name": "rolling_window_temperature_max",
"fn": partial(get_window_fn, window_size=constants.MEASUREMENTS_PER_DAY, fn=partial(np.max, axis=1)),
"scaler": StandardScaler
},
],
"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": "days_relative_to_ov",
"fn": get_days_relative_to_ov,
"scaler": RobustScaler,
"accumulation_fn": np.max
},
{
"name": "ov_day",
"fn": get_ov_day,
"scaler": RobustScaler,
"accumulation_fn": np.max
},
{
"name": "is_biphasic",
"fn": get_is_biphasic,
"scaler": MinMaxScaler,
"accumulation_fn": np.max
}
]
}
+127
View File
@@ -0,0 +1,127 @@
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
@@ -0,0 +1,109 @@
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,
}
}
]
}
+123
View File
@@ -0,0 +1,123 @@
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,
)
]
}