implemented masked mae loss, added tensorflow writer, changed % logic
This commit is contained in:
parent
a8814d5d93
commit
5dd0f1dd3a
|
|
@ -3,9 +3,11 @@ import time
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import torch
|
import torch
|
||||||
|
from torch.utils.tensorboard import SummaryWriter
|
||||||
|
|
||||||
from lib import utils
|
from lib import utils
|
||||||
from model.pytorch.dcrnn_model import DCRNNModel
|
from model.pytorch.dcrnn_model import DCRNNModel
|
||||||
|
from model.pytorch.loss import masked_mae_loss
|
||||||
|
|
||||||
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
||||||
|
|
||||||
|
|
@ -21,6 +23,8 @@ class DCRNNSupervisor:
|
||||||
|
|
||||||
# logging.
|
# logging.
|
||||||
self._log_dir = self._get_log_dir(kwargs)
|
self._log_dir = self._get_log_dir(kwargs)
|
||||||
|
self._writer = SummaryWriter('runs/' + self._log_dir)
|
||||||
|
|
||||||
log_level = self._kwargs.get('log_level', 'INFO')
|
log_level = self._kwargs.get('log_level', 'INFO')
|
||||||
self._logger = utils.get_logger(self._log_dir, __name__, 'info.log', level=log_level)
|
self._logger = utils.get_logger(self._log_dir, __name__, 'info.log', level=log_level)
|
||||||
|
|
||||||
|
|
@ -91,7 +95,7 @@ class DCRNNSupervisor:
|
||||||
kwargs.update(self._train_kwargs)
|
kwargs.update(self._train_kwargs)
|
||||||
return self._train(**kwargs)
|
return self._train(**kwargs)
|
||||||
|
|
||||||
def evaluate(self, dataset='val'):
|
def evaluate(self, dataset='val', batches_seen=0):
|
||||||
"""
|
"""
|
||||||
Computes mean L1Loss
|
Computes mean L1Loss
|
||||||
:return: mean L1Loss
|
:return: mean L1Loss
|
||||||
|
|
@ -101,20 +105,22 @@ class DCRNNSupervisor:
|
||||||
|
|
||||||
val_iterator = self._data['{}_loader'.format(dataset)].get_iterator()
|
val_iterator = self._data['{}_loader'.format(dataset)].get_iterator()
|
||||||
losses = []
|
losses = []
|
||||||
criterion = torch.nn.L1Loss()
|
|
||||||
|
|
||||||
for _, (x, y) in enumerate(val_iterator):
|
for _, (x, y) in enumerate(val_iterator):
|
||||||
x, y = self._prepare_data(x, y)
|
x, y = self._prepare_data(x, y)
|
||||||
|
|
||||||
output = self.dcrnn_model(x)
|
output = self.dcrnn_model(x)
|
||||||
loss = self._compute_loss(y, output, criterion)
|
loss = self._compute_loss(y, output)
|
||||||
losses.append(loss.item())
|
losses.append(loss.item())
|
||||||
|
|
||||||
return np.mean(losses)
|
mean_loss = np.mean(losses)
|
||||||
|
|
||||||
|
self._writer.add_scalar('{} loss'.format(dataset), mean_loss, batches_seen)
|
||||||
|
|
||||||
|
return mean_loss
|
||||||
|
|
||||||
def _train(self, base_lr,
|
def _train(self, base_lr,
|
||||||
steps, patience=50, epochs=100,
|
steps, patience=50, epochs=100, lr_decay_ratio=0.1, log_every=10, save_model=1,
|
||||||
min_learning_rate=2e-6, lr_decay_ratio=0.1, log_every=10, save_model=1,
|
|
||||||
test_every_n_epochs=10, **kwargs):
|
test_every_n_epochs=10, **kwargs):
|
||||||
# steps is used in learning rate - will see if need to use it?
|
# steps is used in learning rate - will see if need to use it?
|
||||||
min_val_loss = float('inf')
|
min_val_loss = float('inf')
|
||||||
|
|
@ -124,7 +130,6 @@ class DCRNNSupervisor:
|
||||||
|
|
||||||
lr_scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=steps,
|
lr_scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, milestones=steps,
|
||||||
gamma=lr_decay_ratio)
|
gamma=lr_decay_ratio)
|
||||||
criterion = torch.nn.L1Loss() # mae loss
|
|
||||||
|
|
||||||
self.dcrnn_model = self.dcrnn_model.train()
|
self.dcrnn_model = self.dcrnn_model.train()
|
||||||
|
|
||||||
|
|
@ -142,7 +147,7 @@ class DCRNNSupervisor:
|
||||||
x, y = self._prepare_data(x, y)
|
x, y = self._prepare_data(x, y)
|
||||||
|
|
||||||
output = self.dcrnn_model(x, y, batches_seen)
|
output = self.dcrnn_model(x, y, batches_seen)
|
||||||
loss = self._compute_loss(y, output, criterion)
|
loss = self._compute_loss(y, output)
|
||||||
|
|
||||||
self._logger.debug(loss.item())
|
self._logger.debug(loss.item())
|
||||||
|
|
||||||
|
|
@ -158,17 +163,23 @@ class DCRNNSupervisor:
|
||||||
self._logger.info("epoch complete")
|
self._logger.info("epoch complete")
|
||||||
lr_scheduler.step()
|
lr_scheduler.step()
|
||||||
self._logger.info("evaluating now!")
|
self._logger.info("evaluating now!")
|
||||||
val_loss = self.evaluate(dataset='val')
|
|
||||||
|
val_loss = self.evaluate(dataset='val', batches_seen=batches_seen)
|
||||||
end_time = time.time()
|
end_time = time.time()
|
||||||
if epoch_num % log_every == 0:
|
|
||||||
|
self._writer.add_scalar('training loss',
|
||||||
|
np.mean(losses),
|
||||||
|
batches_seen)
|
||||||
|
|
||||||
|
if epoch_num % log_every == log_every - 1:
|
||||||
message = 'Epoch [{}/{}] ({}) train_mae: {:.4f}, val_mae: {:.4f}, lr: {:.6f}, ' \
|
message = 'Epoch [{}/{}] ({}) train_mae: {:.4f}, val_mae: {:.4f}, lr: {:.6f}, ' \
|
||||||
'{:.1f}s'.format(epoch_num, epochs, batches_seen,
|
'{:.1f}s'.format(epoch_num, epochs, batches_seen,
|
||||||
np.mean(losses), val_loss, lr_scheduler.get_lr()[0],
|
np.mean(losses), val_loss, lr_scheduler.get_lr()[0],
|
||||||
(end_time - start_time))
|
(end_time - start_time))
|
||||||
self._logger.info(message)
|
self._logger.info(message)
|
||||||
|
|
||||||
if epoch_num % test_every_n_epochs == 0:
|
if epoch_num % test_every_n_epochs == test_every_n_epochs - 1:
|
||||||
test_loss = self.evaluate(dataset='test')
|
test_loss = self.evaluate(dataset='test', batches_seen=batches_seen)
|
||||||
message = 'Epoch [{}/{}] ({}) train_mae: {:.4f}, test_mae: {:.4f}, lr: {:.6f}, ' \
|
message = 'Epoch [{}/{}] ({}) train_mae: {:.4f}, test_mae: {:.4f}, lr: {:.6f}, ' \
|
||||||
'{:.1f}s'.format(epoch_num, epochs, batches_seen,
|
'{:.1f}s'.format(epoch_num, epochs, batches_seen,
|
||||||
np.mean(losses), test_loss, lr_scheduler.get_lr()[0],
|
np.mean(losses), test_loss, lr_scheduler.get_lr()[0],
|
||||||
|
|
@ -223,9 +234,7 @@ class DCRNNSupervisor:
|
||||||
self.num_nodes * self.output_dim)
|
self.num_nodes * self.output_dim)
|
||||||
return x, y
|
return x, y
|
||||||
|
|
||||||
def _compute_loss(self, y_true, y_predicted, criterion):
|
def _compute_loss(self, y_true, y_predicted):
|
||||||
loss = 0
|
y_true = self.standard_scaler.inverse_transform(y_true)
|
||||||
for t in range(self.horizon):
|
y_predicted = self.standard_scaler.inverse_transform(y_predicted)
|
||||||
loss += criterion(self.standard_scaler.inverse_transform(y_predicted[t]),
|
return masked_mae_loss(y_predicted, y_true)
|
||||||
self.standard_scaler.inverse_transform(y_true[t]))
|
|
||||||
return loss
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
import torch
|
||||||
|
|
||||||
|
|
||||||
|
def masked_mae_loss(y_pred, y_true):
|
||||||
|
mask = (y_true != 0).float()
|
||||||
|
mask /= mask.mean()
|
||||||
|
loss = torch.abs(y_pred - y_true)
|
||||||
|
loss = loss * mask
|
||||||
|
return loss.mean()
|
||||||
Loading…
Reference in New Issue