aromidvar1355 commited on
Commit
5e3c87c
·
verified ·
1 Parent(s): 00dca38

Update core/train_eval.py

Browse files
Files changed (1) hide show
  1. core/train_eval.py +19 -15
core/train_eval.py CHANGED
@@ -17,6 +17,15 @@ def create_sequences(data, window_size, horizon=1):
17
  return np.array(X), np.array(y)
18
 
19
 
 
 
 
 
 
 
 
 
 
20
  def train_and_evaluate(
21
  df,
22
  model_cls,
@@ -25,6 +34,10 @@ def train_and_evaluate(
25
  layers=1,
26
  epochs=50,
27
  lr=0.001,
 
 
 
 
28
  window=30,
29
  test_split=0.2,
30
  device="cuda" if torch.cuda.is_available() else "cpu",
@@ -32,19 +45,15 @@ def train_and_evaluate(
32
  ):
33
  result = {}
34
 
35
- # Step 1: Keep original values for inverse mapping
36
  original_values = df['value'].values.astype(np.float32)
37
-
38
- # Step 2: Normalize data
39
  scaler = StandardScaler()
40
  scaled_data = scaler.fit_transform(original_values.reshape(-1, 1))
41
  X, y = create_sequences(scaled_data, window, horizon)
42
 
43
  print(f"X shape: {X.shape}, y shape: {y.shape}")
44
 
45
- # Step 3: Split into train, validation, and test
46
  split = int(len(X) * (1 - test_split))
47
- val_split = int(split * 0.9) # 90% train, 10% validation
48
  X_train, X_val, X_test = X[:val_split], X[val_split:split], X[split:]
49
  y_train, y_val, y_test = y[:val_split], y[val_split:split], y[split:]
50
 
@@ -63,10 +72,9 @@ def train_and_evaluate(
63
  val_loader = DataLoader(TensorDataset(X_val_tensor, y_val_tensor), batch_size=32, shuffle=False)
64
  test_loader = DataLoader(TensorDataset(X_test_tensor, y_test_tensor), batch_size=32, shuffle=False)
65
 
66
- # Step 4: Model
67
  input_dim = X_train.shape[2] if X_train.ndim == 3 else 1
68
- model = model_cls(input_size=input_dim, hidden_size=hidden, num_layers=layers, output_size=horizon).to(device)
69
- optimizer = torch.optim.AdamW(model.parameters(), lr=lr, betas=(0.9, 0.999), weight_decay=0.01)
70
  loss_fn = nn.MSELoss()
71
 
72
  train_losses = []
@@ -78,7 +86,6 @@ def train_and_evaluate(
78
 
79
  model.train()
80
  for epoch in range(epochs):
81
- # Training
82
  epoch_loss = 0.0
83
  for xb, yb in train_loader:
84
  xb, yb = xb.to(device), yb.to(device)
@@ -90,7 +97,6 @@ def train_and_evaluate(
90
  epoch_loss += loss.item()
91
  train_losses.append(epoch_loss / len(train_loader))
92
 
93
- # Validation
94
  model.eval()
95
  val_loss = 0.0
96
  with torch.no_grad():
@@ -105,7 +111,6 @@ def train_and_evaluate(
105
  if verbose and (epoch + 1) % 10 == 0:
106
  print(f"Epoch {epoch+1}/{epochs} - Train Loss: {train_losses[-1]:.4f}, Val Loss: {val_losses[-1]:.4f}")
107
 
108
- # Early stopping
109
  if val_loss < best_val_loss:
110
  best_val_loss = val_loss
111
  counter = 0
@@ -122,7 +127,6 @@ def train_and_evaluate(
122
  result["train_loss"] = train_losses
123
  result["val_loss"] = val_losses
124
 
125
- # Step 5: Evaluate
126
  model.eval()
127
  preds, targets = [], []
128
  with torch.no_grad():
@@ -137,7 +141,6 @@ def train_and_evaluate(
137
 
138
  print(f"Preds shape: {preds.shape}, Targets shape: {targets.shape}")
139
 
140
- # Reshape for inverse transform
141
  preds_reshaped = preds.reshape(-1, 1)
142
  targets_reshaped = targets.reshape(-1, 1)
143
  preds_inv = scaler.inverse_transform(preds_reshaped).reshape(preds.shape)
@@ -147,18 +150,19 @@ def train_and_evaluate(
147
  rmse = np.sqrt(mse)
148
  mae = mean_absolute_error(targets_inv, preds_inv)
149
  r2 = r2_score(targets_inv, preds_inv)
 
150
 
151
  result["metrics"] = {
152
  "R2": round(r2, 4),
153
  "RMSE": round(rmse, 4),
154
- "MAE": round(mae, 4)
 
155
  }
156
 
157
  result["forecast"] = preds_inv
158
  result["actual"] = targets_inv
159
  result["predicted"] = result["forecast"]
160
 
161
- # Step 6: Predict the next value(s)
162
  latest_window = scaled_data[-window:].reshape(1, window, 1)
163
  latest_input = torch.tensor(latest_window, dtype=torch.float32).to(device)
164
 
 
17
  return np.array(X), np.array(y)
18
 
19
 
20
+ def mean_absolute_percentage_error(y_true, y_pred):
21
+ """Calculate MAPE, avoiding division by zero."""
22
+ y_true, y_pred = np.array(y_true), np.array(y_pred)
23
+ non_zero = np.abs(y_true) > 0
24
+ if np.sum(non_zero) == 0:
25
+ return np.nan # Return NaN if all true values are zero
26
+ return np.mean(np.abs((y_true[non_zero] - y_pred[non_zero]) / y_true[non_zero])) * 100
27
+
28
+
29
  def train_and_evaluate(
30
  df,
31
  model_cls,
 
34
  layers=1,
35
  epochs=50,
36
  lr=0.001,
37
+ beta1=0.9, # Added
38
+ beta2=0.999, # Added
39
+ weight_decay=0.01, # Added
40
+ dropout=0.2, # Added
41
  window=30,
42
  test_split=0.2,
43
  device="cuda" if torch.cuda.is_available() else "cpu",
 
45
  ):
46
  result = {}
47
 
 
48
  original_values = df['value'].values.astype(np.float32)
 
 
49
  scaler = StandardScaler()
50
  scaled_data = scaler.fit_transform(original_values.reshape(-1, 1))
51
  X, y = create_sequences(scaled_data, window, horizon)
52
 
53
  print(f"X shape: {X.shape}, y shape: {y.shape}")
54
 
 
55
  split = int(len(X) * (1 - test_split))
56
+ val_split = int(split * 0.9)
57
  X_train, X_val, X_test = X[:val_split], X[val_split:split], X[split:]
58
  y_train, y_val, y_test = y[:val_split], y[val_split:split], y[split:]
59
 
 
72
  val_loader = DataLoader(TensorDataset(X_val_tensor, y_val_tensor), batch_size=32, shuffle=False)
73
  test_loader = DataLoader(TensorDataset(X_test_tensor, y_test_tensor), batch_size=32, shuffle=False)
74
 
 
75
  input_dim = X_train.shape[2] if X_train.ndim == 3 else 1
76
+ model = model_cls(input_size=input_dim, hidden_size=hidden, num_layers=layers, output_size=horizon, dropout=dropout).to(device)
77
+ optimizer = torch.optim.AdamW(model.parameters(), lr=lr, betas=(beta1, beta2), weight_decay=weight_decay)
78
  loss_fn = nn.MSELoss()
79
 
80
  train_losses = []
 
86
 
87
  model.train()
88
  for epoch in range(epochs):
 
89
  epoch_loss = 0.0
90
  for xb, yb in train_loader:
91
  xb, yb = xb.to(device), yb.to(device)
 
97
  epoch_loss += loss.item()
98
  train_losses.append(epoch_loss / len(train_loader))
99
 
 
100
  model.eval()
101
  val_loss = 0.0
102
  with torch.no_grad():
 
111
  if verbose and (epoch + 1) % 10 == 0:
112
  print(f"Epoch {epoch+1}/{epochs} - Train Loss: {train_losses[-1]:.4f}, Val Loss: {val_losses[-1]:.4f}")
113
 
 
114
  if val_loss < best_val_loss:
115
  best_val_loss = val_loss
116
  counter = 0
 
127
  result["train_loss"] = train_losses
128
  result["val_loss"] = val_losses
129
 
 
130
  model.eval()
131
  preds, targets = [], []
132
  with torch.no_grad():
 
141
 
142
  print(f"Preds shape: {preds.shape}, Targets shape: {targets.shape}")
143
 
 
144
  preds_reshaped = preds.reshape(-1, 1)
145
  targets_reshaped = targets.reshape(-1, 1)
146
  preds_inv = scaler.inverse_transform(preds_reshaped).reshape(preds.shape)
 
150
  rmse = np.sqrt(mse)
151
  mae = mean_absolute_error(targets_inv, preds_inv)
152
  r2 = r2_score(targets_inv, preds_inv)
153
+ mape = mean_absolute_percentage_error(targets_inv, preds_inv)
154
 
155
  result["metrics"] = {
156
  "R2": round(r2, 4),
157
  "RMSE": round(rmse, 4),
158
+ "MAE": round(mae, 4),
159
+ "MAPE": round(mape, 4) if not np.isnan(mape) else None
160
  }
161
 
162
  result["forecast"] = preds_inv
163
  result["actual"] = targets_inv
164
  result["predicted"] = result["forecast"]
165
 
 
166
  latest_window = scaled_data[-window:].reshape(1, window, 1)
167
  latest_input = torch.tensor(latest_window, dtype=torch.float32).to(device)
168