Skip to content

Commit 1762b9a

Browse files
Revised loss function
1 parent 2a8f16c commit 1762b9a

6 files changed

Lines changed: 51 additions & 155 deletions

File tree

src/iplane/model_runner_nn.py

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ class ModelRunnerNN(ModelRunner):
4747

4848
def __init__(self, model: Optional[nn.Module]=None, num_epoch:int=3, learning_rate:float=1e-3,
4949
criterion:nn.Module=nn.MSELoss(), max_fractional_error: float=0.10,
50-
is_normalized:bool=False, is_report:bool=False):
50+
is_normalized:bool=True,
51+
noise_std: float=0.1, is_l1_regularization:bool=True, is_accuracy_regularization:bool=True,
52+
is_report:bool=False):
5153
"""
5254
Args:
5355
model (nn.Module): Model being run
@@ -56,6 +58,11 @@ def __init__(self, model: Optional[nn.Module]=None, num_epoch:int=3, learning_ra
5658
is_normalized (bool, optional): Whether to normalize the input data (divide by std).
5759
Defaults to False.
5860
max_fractional_error (float): Maximum error desired for each prediction
61+
noise_std (float, optional): Standard deviation of noise to add to inputs.
62+
is_l1_regularization (bool, optional): Whether to use L1 regularization.
63+
Defaults to True.
64+
is_accuracy_regularization (bool, optional): Whether to use accuracy regularization.
65+
Defaults to True.
5966
is_report (bool, optional): Print text for progress.
6067
Defaults to False.
6168
"""
@@ -66,6 +73,9 @@ def __init__(self, model: Optional[nn.Module]=None, num_epoch:int=3, learning_ra
6673
self.learning_rate = learning_rate
6774
self.is_normalized = is_normalized
6875
self.max_fractional_error = max_fractional_error
76+
self.noise_std = noise_std
77+
self.is_l1_regularization = is_l1_regularization
78+
self.is_accuracy_regularization = is_accuracy_regularization
6979
# Calculated state
7080
self.feature_std_tnsr = torch.tensor([np.nan])
7181
self.target_std_tnsr = torch.tensor([np.nan])
@@ -92,6 +102,27 @@ def _calculateAccuracy(self, feature_tnsr, target_tnsr)->float:
92102
accuracy = torch.sum(accurate_rows) / accurate_rows.shape[0]
93103
return accuracy
94104

105+
def _calculateSmothedInaccuracy(self, feature_tnsr, target_tnsr)->float:
106+
"""Calculates the mean absolute maximum fractional error for each sample.
107+
108+
Args:
109+
feature_tnsr (nn.Tensor): features
110+
target_tnsr (nn.Tensor): target
111+
112+
Returns:
113+
accuracy (float)
114+
"""
115+
prediction_tnsr = self.predict(feature_tnsr)
116+
prediction_arr = prediction_tnsr.cpu().numpy()
117+
target_arr = target_tnsr.cpu().numpy()
118+
# Find deiviations handling small and large predictions
119+
mae1_arr = np.max(np.abs(prediction_arr - target_arr) / target_arr, axis=1)
120+
mae2_arr = np.max(np.abs(prediction_arr - target_arr) / prediction_arr, axis=1)
121+
mae_arr = np.maximum(mae1_arr, mae2_arr)
122+
# Smooth the inaccuracy
123+
smoothed_inaccuracy = np.mean(mae_arr)
124+
return smoothed_inaccuracy
125+
95126
def fit(self, train_loader: DataLoader) -> RunnerResultPredict:
96127
"""
97128
Train the model. All calculations are on the accelerator device.
@@ -120,12 +151,11 @@ def calculate_std(is_feature: bool) -> torch.Tensor:
120151
self.feature_std_tnsr = calculate_std(is_feature=True).to(cn.DEVICE)
121152
self.target_std_tnsr = calculate_std(is_feature=False).to(cn.DEVICE)
122153
num_sample = full_feature_tnsr.size(0)
123-
reconstruction_loss_weight = 1/torch.std(self.target_std_tnsr)
124154
# Initialize for training
125155
optimizer = optim.Adam(self.model.parameters(), lr=self.learning_rate)
126156
self.model.train()
127157
losses = []
128-
avg_loss = 0.0
158+
avg_loss = 1e10
129159
epoch_loss = np.inf
130160
accuracies:list = []
131161
mi_hidden1_input_epochs:list = []
@@ -146,14 +176,25 @@ def calculate_std(is_feature: bool) -> torch.Tensor:
146176
idx_tnsr = permutation[iter*batch_size:(iter+1)*batch_size]
147177
feature_tnsr = full_feature_tnsr[idx_tnsr]/self.feature_std_tnsr
148178
target_tnsr = full_target_tnsr[idx_tnsr]/self.target_std_tnsr
179+
# Add noise to features for denoising autoencoder
180+
feature_tnsr = feature_tnsr + torch.randn_like(feature_tnsr) * self.noise_std
149181
# Forward pass with a regularization loss
150182
prediction_tnsr = self.model(feature_tnsr)
151183
reconstruction_loss = self.criterion(prediction_tnsr, target_tnsr)
152-
l1_loss = self._l1_regularization()
153-
accuracy = self._calculateAccuracy(full_feature_tnsr, full_target_tnsr)
154-
accuracy_loss = ACCURACY_WEIGHT*(1 - accuracy)
184+
if self.is_accuracy_regularization:
185+
accuracy_loss = self._calculateSmothedInaccuracy(full_feature_tnsr, full_target_tnsr)
186+
else:
187+
accuracy_loss = 0.0
188+
if self.is_l1_regularization:
189+
l1_loss = self._l1_regularization()
190+
else:
191+
l1_loss = 0.0
155192
# FIXME: May need to scale the losses.
156-
total_loss = reconstruction_loss_weight*reconstruction_loss + l1_loss + 0.1*accuracy_loss
193+
total_loss = reconstruction_loss + l1_loss + 0.01*accuracy_loss
194+
if False:
195+
print(f"epoch={epoch}, reconstruction_loss={reconstruction_loss.item():.4f}, "
196+
f"l1_loss={l1_loss:.4f}, accuracy_loss={accuracy_loss:.4f}",
197+
f"total_loss={total_loss.item():.4f}")
157198
# Backward pass
158199
optimizer.zero_grad()
159200
total_loss.backward()

src/training_visualizer.py

Lines changed: 0 additions & 79 deletions
This file was deleted.

tests/test_model_runner_nn.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
IGNORE_TESTS = True
1515
IS_PLOT = True
1616
NUM_EPOCH = 20000
17-
NUM_EPOCH = 5000
17+
NUM_EPOCH = 2000
1818

1919
TARGET_COLUMN = "target" # Assuming the target column is named 'target'
2020
NUM_DEPENDENT_FEATURE = 6

tests/test_model_runner_pca.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
from tests.utils_test import makeAutocoderData # type: ignore
55

66
import numpy as np # type: ignore
7-
import torch
87
from torch.utils.data import DataLoader
98
import pandas as pd # type: ignore
109
from typing import cast

tests/test_training_visualizer.py

Lines changed: 0 additions & 66 deletions
This file was deleted.

tests/utils_test.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,5 +96,6 @@ def makeAutocoderData(num_sample:int=NUM_SAMPLE,
9696
dependent_columns = [f"D_k_{''.join(str_idxs[i])}" for i in range(num_dependent_feature-num_mm)] # Consider MM
9797
columns = independent_columns + mm_columns + dependent_columns
9898
df = pd.DataFrame(feature_arr, columns=columns, dtype=np.float32)
99-
dataloader = DataLoader(DatasetCSV(csv_input=df, target_column=None), batch_size=10)
99+
batch_size = num_sample // 10
100+
dataloader = DataLoader(DatasetCSV(csv_input=df, target_column=None), batch_size=batch_size)
100101
return dataloader

0 commit comments

Comments
 (0)