first commit
This commit is contained in:
89
utils/losses.py
Normal file
89
utils/losses.py
Normal file
@ -0,0 +1,89 @@
|
||||
# This source code is provided for the purposes of scientific reproducibility
|
||||
# under the following limited license from Element AI Inc. The code is an
|
||||
# implementation of the N-BEATS model (Oreshkin et al., N-BEATS: Neural basis
|
||||
# expansion analysis for interpretable time series forecasting,
|
||||
# https://arxiv.org/abs/1905.10437). The copyright to the source code is
|
||||
# licensed under the Creative Commons - Attribution-NonCommercial 4.0
|
||||
# International license (CC BY-NC 4.0):
|
||||
# https://creativecommons.org/licenses/by-nc/4.0/. Any commercial use (whether
|
||||
# for the benefit of third parties or internally in production) requires an
|
||||
# explicit license. The subject-matter of the N-BEATS model and associated
|
||||
# materials are the property of Element AI Inc. and may be subject to patent
|
||||
# protection. No license to patents is granted hereunder (whether express or
|
||||
# implied). Copyright © 2020 Element AI Inc. All rights reserved.
|
||||
|
||||
"""
|
||||
Loss functions for PyTorch.
|
||||
"""
|
||||
|
||||
import torch as t
|
||||
import torch.nn as nn
|
||||
import numpy as np
|
||||
import pdb
|
||||
|
||||
|
||||
def divide_no_nan(a, b):
|
||||
"""
|
||||
a/b where the resulted NaN or Inf are replaced by 0.
|
||||
"""
|
||||
result = a / b
|
||||
result[result != result] = .0
|
||||
result[result == np.inf] = .0
|
||||
return result
|
||||
|
||||
|
||||
class mape_loss(nn.Module):
|
||||
def __init__(self):
|
||||
super(mape_loss, self).__init__()
|
||||
|
||||
def forward(self, insample: t.Tensor, freq: int,
|
||||
forecast: t.Tensor, target: t.Tensor, mask: t.Tensor) -> t.float:
|
||||
"""
|
||||
MAPE loss as defined in: https://en.wikipedia.org/wiki/Mean_absolute_percentage_error
|
||||
|
||||
:param forecast: Forecast values. Shape: batch, time
|
||||
:param target: Target values. Shape: batch, time
|
||||
:param mask: 0/1 mask. Shape: batch, time
|
||||
:return: Loss value
|
||||
"""
|
||||
weights = divide_no_nan(mask, target)
|
||||
return t.mean(t.abs((forecast - target) * weights))
|
||||
|
||||
|
||||
class smape_loss(nn.Module):
|
||||
def __init__(self):
|
||||
super(smape_loss, self).__init__()
|
||||
|
||||
def forward(self, insample: t.Tensor, freq: int,
|
||||
forecast: t.Tensor, target: t.Tensor, mask: t.Tensor) -> t.float:
|
||||
"""
|
||||
sMAPE loss as defined in https://robjhyndman.com/hyndsight/smape/ (Makridakis 1993)
|
||||
|
||||
:param forecast: Forecast values. Shape: batch, time
|
||||
:param target: Target values. Shape: batch, time
|
||||
:param mask: 0/1 mask. Shape: batch, time
|
||||
:return: Loss value
|
||||
"""
|
||||
return 200 * t.mean(divide_no_nan(t.abs(forecast - target),
|
||||
t.abs(forecast.data) + t.abs(target.data)) * mask)
|
||||
|
||||
|
||||
class mase_loss(nn.Module):
|
||||
def __init__(self):
|
||||
super(mase_loss, self).__init__()
|
||||
|
||||
def forward(self, insample: t.Tensor, freq: int,
|
||||
forecast: t.Tensor, target: t.Tensor, mask: t.Tensor) -> t.float:
|
||||
"""
|
||||
MASE loss as defined in "Scaled Errors" https://robjhyndman.com/papers/mase.pdf
|
||||
|
||||
:param insample: Insample values. Shape: batch, time_i
|
||||
:param freq: Frequency value
|
||||
:param forecast: Forecast values. Shape: batch, time_o
|
||||
:param target: Target values. Shape: batch, time_o
|
||||
:param mask: 0/1 mask. Shape: batch, time_o
|
||||
:return: Loss value
|
||||
"""
|
||||
masep = t.mean(t.abs(insample[:, freq:] - insample[:, :-freq]), dim=1)
|
||||
masked_masep_inv = divide_no_nan(mask, masep[:, None])
|
||||
return t.mean(t.abs(target - forecast) * masked_masep_inv)
|
Reference in New Issue
Block a user