Aliazimi00 commited on
Commit
74145db
·
verified ·
1 Parent(s): da438f1

Update core/train_eval.py

Browse files
Files changed (1) hide show
  1. core/train_eval.py +23 -12
core/train_eval.py CHANGED
@@ -30,7 +30,6 @@ def mean_absolute_scaled_error(y_true, y_pred, y_train):
30
  """Calculate MASE, using naive forecast as denominator."""
31
  y_true, y_pred = np.array(y_true), np.array(y_pred)
32
  errors = np.abs(y_true - y_pred)
33
- # Naive forecast: use previous value as prediction
34
  naive_errors = np.abs(y_train[1:] - y_train[:-1])
35
  mean_naive_error = np.mean(naive_errors) if len(naive_errors) > 0 else 1.0
36
  return np.mean(errors) / mean_naive_error if mean_naive_error != 0 else np.nan
@@ -62,6 +61,7 @@ def train_and_evaluate(
62
  dropout=0.2,
63
  window=30,
64
  test_split=0.2,
 
65
  device="cuda" if torch.cuda.is_available() else "cpu",
66
  verbose=True
67
  ):
@@ -83,6 +83,7 @@ def train_and_evaluate(
83
  print(f"X_val shape: {X_val.shape}, y_val shape: {y_val.shape}")
84
  print(f"X_test shape: {X_test.shape}, y_test shape: {y_test.shape}")
85
 
 
86
  X_train_tensor = torch.tensor(X_train, dtype=torch.float32)
87
  y_train_tensor = torch.tensor(y_train, dtype=torch.float32)
88
  X_val_tensor = torch.tensor(X_val, dtype=torch.float32)
@@ -90,15 +91,15 @@ def train_and_evaluate(
90
  X_test_tensor = torch.tensor(X_test, dtype=torch.float32)
91
  y_test_tensor = torch.tensor(y_test, dtype=torch.float32)
92
 
93
- train_loader = DataLoader(TensorDataset(X_train_tensor, y_train_tensor), batch_size=32, shuffle=True)
94
- val_loader = DataLoader(TensorDataset(X_val_tensor, y_val_tensor), batch_size=32, shuffle=False)
95
- test_loader = DataLoader(TensorDataset(X_test_tensor, y_test_tensor), batch_size=32, shuffle=False)
96
 
97
  input_dim = X_train.shape[2] if X_train.ndim == 3 else 1
98
  model = model_cls(input_size=input_dim, hidden_size=hidden, num_layers=layers, output_size=horizon, dropout=dropout).to(device)
99
  optimizer = torch.optim.AdamW(model.parameters(), lr=lr, betas=(beta1, beta2), weight_decay=weight_decay)
100
  loss_fn = nn.MSELoss()
101
- scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', patience=5, factor=0.5, threshold=1e-4)
102
 
103
  train_losses = []
104
  val_losses = []
@@ -186,13 +187,13 @@ def train_and_evaluate(
186
  mda = mean_directional_accuracy(targets_inv, preds_inv)
187
 
188
  result["metrics"] = {
189
- "R2": round(r2, 4),
190
- "Explained Variance": round(evs, 4),
191
- "MDA (%)": round(mda, 4) if not np.isnan(mda) else None,
192
- "RMSE": round(rmse, 4),
193
- "MAE": round(mae, 4),
194
- "MAPE (%)": round(mape, 4) if not np.isnan(mape) else None,
195
- "MASE": round(mase, 4) if not np.isnan(mase) else None
196
  }
197
 
198
  result["forecast"] = preds_inv
@@ -212,4 +213,14 @@ def train_and_evaluate(
212
  if not future_df.empty:
213
  result["future_actuals"] = future_df['value'].values.tolist()[:horizon]
214
 
 
 
 
 
 
 
 
 
 
 
215
  return result
 
30
  """Calculate MASE, using naive forecast as denominator."""
31
  y_true, y_pred = np.array(y_true), np.array(y_pred)
32
  errors = np.abs(y_true - y_pred)
 
33
  naive_errors = np.abs(y_train[1:] - y_train[:-1])
34
  mean_naive_error = np.mean(naive_errors) if len(naive_errors) > 0 else 1.0
35
  return np.mean(errors) / mean_naive_error if mean_naive_error != 0 else np.nan
 
61
  dropout=0.2,
62
  window=30,
63
  test_split=0.2,
64
+ scheduler_factor=0.5,
65
  device="cuda" if torch.cuda.is_available() else "cpu",
66
  verbose=True
67
  ):
 
83
  print(f"X_val shape: {X_val.shape}, y_val shape: {y_val.shape}")
84
  print(f"X_test shape: {X_test.shape}, y_test shape: {y_test.shape}")
85
 
86
+ batch_size = 32
87
  X_train_tensor = torch.tensor(X_train, dtype=torch.float32)
88
  y_train_tensor = torch.tensor(y_train, dtype=torch.float32)
89
  X_val_tensor = torch.tensor(X_val, dtype=torch.float32)
 
91
  X_test_tensor = torch.tensor(X_test, dtype=torch.float32)
92
  y_test_tensor = torch.tensor(y_test, dtype=torch.float32)
93
 
94
+ train_loader = DataLoader(TensorDataset(X_train_tensor, y_train_tensor), batch_size=batch_size, shuffle=True)
95
+ val_loader = DataLoader(TensorDataset(X_val_tensor, y_val_tensor), batch_size=batch_size, shuffle=False)
96
+ test_loader = DataLoader(TensorDataset(X_test_tensor, y_test_tensor), batch_size=batch_size, shuffle=False)
97
 
98
  input_dim = X_train.shape[2] if X_train.ndim == 3 else 1
99
  model = model_cls(input_size=input_dim, hidden_size=hidden, num_layers=layers, output_size=horizon, dropout=dropout).to(device)
100
  optimizer = torch.optim.AdamW(model.parameters(), lr=lr, betas=(beta1, beta2), weight_decay=weight_decay)
101
  loss_fn = nn.MSELoss()
102
+ scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', patience=5, factor=scheduler_factor, threshold=1e-4)
103
 
104
  train_losses = []
105
  val_losses = []
 
187
  mda = mean_directional_accuracy(targets_inv, preds_inv)
188
 
189
  result["metrics"] = {
190
+ "R² (%)": round(r2 * 100, 2),
191
+ "Explained Variance (%)": round(evs * 100, 2),
192
+ "MDA (%)": round(mda, 2) if not np.isnan(mda) else None,
193
+ "RMSE": round(rmse, 2),
194
+ "MAE": round(mae, 2),
195
+ "MAPE (%)": round(mape, 2) if not np.isnan(mape) else None,
196
+ "MASE": round(mase, 2) if not np.isnan(mase) else None
197
  }
198
 
199
  result["forecast"] = preds_inv
 
213
  if not future_df.empty:
214
  result["future_actuals"] = future_df['value'].values.tolist()[:horizon]
215
 
216
+ result["architecture"] = {
217
+ "model_name": model_cls.__name__,
218
+ "num_layers": layers,
219
+ "hidden_units": hidden,
220
+ "dropout": dropout,
221
+ "batch_size": batch_size,
222
+ "input_size": input_dim,
223
+ "output_size": horizon
224
+ }
225
+
226
  return result