/*! * * \brief Implements the Huber loss function for robust regression * * * \author Oswin Krause * \date 2014 * * * \par Copyright 1995-2017 Shark Development Team * *

* This file is part of Shark. * * * Shark is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Shark is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Shark. If not, see . * */ #ifndef SHARK_OBJECTIVEFUNCTIONS_LOSS_HUBERLOSS_H #define SHARK_OBJECTIVEFUNCTIONS_LOSS_HUBERLOSS_H #include namespace shark { /// \brief Huber-loss for for robust regression /// /// The Huber loss is a function that is quadratic if\f$ ||f(x)-y||_2 \leq \delta \f$. /// Outside this region, whn the error is larger, it is defined as a linear continuation. The function is once /// but not twice differentiable. This loss is important for regression as it weights outliers lower than /// ordinary least squares regression while still preserving a convex shape of the loss function. /// /// Please not that, due to its nature, the error function is not scale invariant. thus rescaling the dataset /// changes the behaviour. This function has the hyper parameter delta which marks thee region where /// the function changes from quadratic to linear. class HuberLoss : public AbstractLoss { public: /// constructor HuberLoss(double delta = 1.0):m_delta(delta){ m_features |= base_type::HAS_FIRST_DERIVATIVE; } /// \brief Returns class name "HuberLoss" std::string name() const { return "HuberLoss"; } ///\brief calculates the sum of all double eval(BatchLabelType const& labels, BatchOutputType const& predictions) const{ SIZE_CHECK(labels.size1() == predictions.size1()); SIZE_CHECK(labels.size2() == predictions.size2()); std::size_t numInputs = labels.size1(); double error = 0; for(std::size_t i = 0; i != numInputs;++i){ double norm2 = norm_sqr(row(predictions,i)-row(labels,i)); //check whether we are in the quadratic area if(norm2 <= sqr(m_delta)){ error += 0.5*norm2; } else{ error += m_delta*std::sqrt(norm2)-0.5*sqr(m_delta); } } return error; } double evalDerivative(BatchLabelType const& labels, BatchOutputType const& predictions, BatchOutputType& gradient)const{ SIZE_CHECK(labels.size1() == predictions.size1()); SIZE_CHECK(labels.size2() == predictions.size2()); std::size_t numInputs = predictions.size1(); std::size_t outputDim = predictions.size2(); gradient.resize(numInputs,outputDim); double error = 0; for(std::size_t i = 0; i != numInputs;++i){ double norm2 = norm_sqr(row(predictions,i)-row(labels,i)); //check whether we are in the quadratic area if(norm2 <= sqr(m_delta)){ error += 0.5*norm2; noalias(row(gradient,i)) = row(predictions,i)-row(labels,i); } else{ double norm = std::sqrt(norm2); error += m_delta*norm-0.5*sqr(m_delta); noalias(row(gradient,i)) = m_delta/norm*(row(predictions,i)-row(labels,i)); } } return error; } private: double m_delta; }; } #endif