//=========================================================================== /*! * * * \brief abstract super class of all kernel functions * * * * \author T.Glasmachers, O. Krause, M. Tuma * \date 2010-2012 * * * \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_MODELS_KERNELS_ABSTRACTKERNELFUNCTION_H #define SHARK_MODELS_KERNELS_ABSTRACTKERNELFUNCTION_H #include #include #include #include namespace shark { #ifdef SHARK_COUNT_KERNEL_LOOKUPS #define INCREMENT_KERNEL_COUNTER( counter ) { counter++; } #else #define INCREMENT_KERNEL_COUNTER( counter ) { } #endif /// \brief Base class of all Kernel functions. /// /// \par /// A (Mercer) kernel is a symmetric positive definite /// function of two parameters. It is (currently) used /// in two contexts in Shark, namely for kernel methods /// such as support vector machines (SVMs), and for /// radial basis function networks. /// /// \par /// In Shark a kernel function class represents a parametric /// family of such kernel functions: The AbstractKernelFunction /// interface inherits the IParameterizable interface. /// template class AbstractKernelFunction : public AbstractMetric { private: typedef AbstractMetric base_type; typedef Batch Traits; public: /// \brief Input type of the Kernel. typedef typename base_type::InputType InputType; /// \brief batch input type of the kernel typedef typename base_type::BatchInputType BatchInputType; /// \brief Const references to InputType typedef typename base_type::ConstInputReference ConstInputReference; /// \brief Const references to BatchInputType typedef typename base_type::ConstBatchInputReference ConstBatchInputReference; AbstractKernelFunction() { } /// enumerations of kerneland metric features (flags) enum Feature { HAS_FIRST_PARAMETER_DERIVATIVE = 1, ///< is the kernel differentiable w.r.t. its parameters? HAS_FIRST_INPUT_DERIVATIVE = 2, ///< is the kernel differentiable w.r.t. its inputs? IS_NORMALIZED = 4 , ///< does k(x, x) = 1 hold for all inputs x? SUPPORTS_VARIABLE_INPUT_SIZE = 8 ///< Input arguments must have same size, but not the same size in different calls to eval }; /// This statement declares the member m_features. See Core/Flags.h for details. SHARK_FEATURE_INTERFACE; bool hasFirstParameterDerivative()const{ return m_features & HAS_FIRST_PARAMETER_DERIVATIVE; } bool hasFirstInputDerivative()const{ return m_features & HAS_FIRST_INPUT_DERIVATIVE; } bool isNormalized() const{ return m_features & IS_NORMALIZED; } bool supportsVariableInputSize() const{ return m_features & SUPPORTS_VARIABLE_INPUT_SIZE; } ///\brief Creates an internal state of the kernel. /// ///The state is needed when the derivatives are to be ///calculated. Eval can store a state which is then reused to speed up ///the calculations of the derivatives. This also allows eval to be ///evaluated in parallel! virtual boost::shared_ptr createState()const { SHARK_RUNTIME_CHECK(!hasFirstParameterDerivative() && !hasFirstInputDerivative(), "createState must be overridden by kernels with derivatives"); return boost::shared_ptr(new EmptyState()); } ///////////////////////////////////////////SINGLE ELEMENT INTERFACE/////////////////////////////////////////// // By default, this is mapped to the batch case. /// \brief Evaluates the kernel function. virtual double eval(ConstInputReference x1, ConstInputReference x2) const{ RealMatrix res; BatchInputType b1 = Traits::createBatch(x1,1); BatchInputType b2 = Traits::createBatch(x2,1); getBatchElement(b1,0) = x1; getBatchElement(b2,0) = x2; eval(b1, b2, res); return res(0, 0); } /// \brief Convenience operator which evaluates the kernel function. inline double operator () (ConstInputReference x1, ConstInputReference x2) const { return eval(x1, x2); } //////////////////////////////////////BATCH INTERFACE/////////////////////////////////////////// /// \brief Evaluates the subset of the KernelGram matrix which is defined by X1(rows) and X2 (columns). /// /// The result matrix is filled in with the values result(i,j) = kernel(x1[i], x2[j]); /// The State object is filled in with data used in subsequent derivative computations. virtual void eval(ConstBatchInputReference batchX1, ConstBatchInputReference batchX2, RealMatrix& result, State& state) const = 0; /// \brief Evaluates the subset of the KernelGram matrix which is defined by X1(rows) and X2 (columns). /// /// The result matrix is filled in with the values result(i,j) = kernel(x1[i], x2[j]); virtual void eval(ConstBatchInputReference batchX1, ConstBatchInputReference batchX2, RealMatrix& result) const { boost::shared_ptr state = createState(); eval(batchX1, batchX2, result, *state); } /// \brief Evaluates the subset of the KernelGram matrix which is defined by X1(rows) and X2 (columns). /// /// Convenience operator. /// The result matrix is filled in with the values result(i,j) = kernel(x1[i], x2[j]); inline RealMatrix operator () (ConstBatchInputReference batchX1, ConstBatchInputReference batchX2) const{ RealMatrix result; eval(batchX1, batchX2, result); return result; } /// \brief Computes the gradient of the parameters as a weighted sum over the gradient of all elements of the batch. /// /// The default implementation throws a "not implemented" exception. virtual void weightedParameterDerivative( ConstBatchInputReference batchX1, ConstBatchInputReference batchX2, RealMatrix const& coefficients, State const& state, RealVector& gradient ) const { SHARK_FEATURE_EXCEPTION(HAS_FIRST_PARAMETER_DERIVATIVE); } /// \brief Calculates the derivative of the inputs X1 (only x1!). /// /// The i-th row of the resulting matrix is a weighted sum of the form: /// c[i,0] * k'(x1[i], x2[0]) + c[i,1] * k'(x1[i], x2[1]) + ... + c[i,n] * k'(x1[i], x2[n]). /// /// The default implementation throws a "not implemented" exception. virtual void weightedInputDerivative( ConstBatchInputReference batchX1, ConstBatchInputReference batchX2, RealMatrix const& coefficientsX2, State const& state, BatchInputType& gradient ) const { SHARK_FEATURE_EXCEPTION(HAS_FIRST_INPUT_DERIVATIVE); } //////////////////////////////////NORMS AND DISTANCES///////////////////////////////// /// Computes the squared distance in the kernel induced feature space. virtual double featureDistanceSqr(ConstInputReference x1, ConstInputReference x2) const{ if (isNormalized()){ double k12 = eval(x1, x2); return (2.0 - 2.0 * k12); } else { double k11 = eval(x1, x1); double k12 = eval(x1, x2); double k22 = eval(x2, x2); return (k11 - 2.0 * k12 + k22); } } virtual RealMatrix featureDistanceSqr(ConstBatchInputReference batchX1,ConstBatchInputReference batchX2) const{ std::size_t sizeX1 = batchSize(batchX1); std::size_t sizeX2 = batchSize(batchX2); RealMatrix result=(*this)(batchX1,batchX2); result *= -2.0; if (isNormalized()){ noalias(result) += 2.0; } else { //compute self-product RealVector kx2(sizeX2); for(std::size_t i = 0; i != sizeX2;++i){ kx2(i)=eval(getBatchElement(batchX2,i),getBatchElement(batchX2,i)); } for(std::size_t j = 0; j != sizeX1;++j){ double kx1=eval(getBatchElement(batchX1,j),getBatchElement(batchX1,j)); noalias(row(result,j)) += kx1 + kx2; } } return result; } }; } #endif