From 4847f0255793f8e82088b66d908ae5751455cece Mon Sep 17 00:00:00 2001 From: Julien Malik <julien.malik@c-s.fr> Date: Sun, 17 Oct 2010 19:34:32 +0200 Subject: [PATCH] ENH: fix memory management of generic kernel in the svm_parameter struct --- Code/Learning/otbChangeProfileKernelFunctor.h | 23 + .../Learning/otbMixturePolyRBFKernelFunctor.h | 23 + .../Learning/otbNonGaussianRBFKernelFunctor.h | 24 + Code/Learning/otbSVMKernels.h | 414 ++++++++++++-- Code/Learning/otbSVMModel.h | 8 +- Code/Learning/otbSVMModel.txx | 1 - Code/Learning/otbSpectralAngleKernelFunctor.h | 26 +- Utilities/otbsvm/svm.cpp | 369 ++++++++++--- Utilities/otbsvm/svm.h | 510 ++++++++---------- 9 files changed, 1001 insertions(+), 397 deletions(-) diff --git a/Code/Learning/otbChangeProfileKernelFunctor.h b/Code/Learning/otbChangeProfileKernelFunctor.h index af8dd7ae24..013ebc8c84 100644 --- a/Code/Learning/otbChangeProfileKernelFunctor.h +++ b/Code/Learning/otbChangeProfileKernelFunctor.h @@ -44,6 +44,14 @@ class ChangeProfileKernelFunctor : public GenericKernelFunctorBase { public: + typedef ChangeProfileKernelFunctor Self; + typedef GenericKernelFunctorBase Superclass; + + // Deep copy operator + virtual GenericKernelFunctorBase* Clone() const + { + return new Self(*this); + } double operator ()(const svm_node * x, const svm_node * y, const svm_parameter& param) const; @@ -55,6 +63,21 @@ public: * into specific variables to speed up kernel evaluations */ void Update(); +protected: + ChangeProfileKernelFunctor(const Self& copy) + : Superclass(copy) + { + *this = copy; + } + + ChangeProfileKernelFunctor& + operator=(const Self& copy) + { + Superclass::operator =(copy); + Update(); + return *this; + } + private: double m_Coef; double m_Degree; diff --git a/Code/Learning/otbMixturePolyRBFKernelFunctor.h b/Code/Learning/otbMixturePolyRBFKernelFunctor.h index 7dfd81f8b5..38a1287048 100644 --- a/Code/Learning/otbMixturePolyRBFKernelFunctor.h +++ b/Code/Learning/otbMixturePolyRBFKernelFunctor.h @@ -42,9 +42,18 @@ class MixturePolyRBFKernelFunctor : public GenericKernelFunctorBase { public: + typedef MixturePolyRBFKernelFunctor Self; + typedef GenericKernelFunctorBase Superclass; + double operator ()(const svm_node * x, const svm_node * y, const svm_parameter& param) const; + // Deep copy operator + virtual GenericKernelFunctorBase* Clone() const + { + return new Self(*this); + } + MixturePolyRBFKernelFunctor (); virtual ~MixturePolyRBFKernelFunctor () {} @@ -53,6 +62,20 @@ public: void Update(); protected: + MixturePolyRBFKernelFunctor(const Self& copy) + : Superclass(copy) + { + *this = copy; + } + + MixturePolyRBFKernelFunctor& + operator=(const Self& copy) + { + Superclass::operator =(copy); + Update(); + return *this; + } + double m_Mixture; double m_GammaPoly; double m_CoefPoly; diff --git a/Code/Learning/otbNonGaussianRBFKernelFunctor.h b/Code/Learning/otbNonGaussianRBFKernelFunctor.h index 22e25a141a..6504e29c23 100644 --- a/Code/Learning/otbNonGaussianRBFKernelFunctor.h +++ b/Code/Learning/otbNonGaussianRBFKernelFunctor.h @@ -41,6 +41,14 @@ class NonGaussianRBFKernelFunctor : public GenericKernelFunctorBase { public: + typedef NonGaussianRBFKernelFunctor Self; + typedef GenericKernelFunctorBase Superclass; + + // Deep copy operator + virtual GenericKernelFunctorBase* Clone() const + { + return new Self(*this); + } double operator ()(const svm_node * x, const svm_node * y, const svm_parameter& param) const; @@ -52,10 +60,26 @@ public: * into specific variables to speed up kernel evaluations */ void Update(); +protected: + NonGaussianRBFKernelFunctor(const Self& copy) + : Superclass(copy) + { + *this = copy; + } + + NonGaussianRBFKernelFunctor& + operator=(const Self& copy) + { + Superclass::operator =(copy); + Update(); + return *this; + } + protected: double m_Alpha; double m_Beta; double m_Gamma; + }; } // end of namespace otb diff --git a/Code/Learning/otbSVMKernels.h b/Code/Learning/otbSVMKernels.h index d80b68677e..c14b3b3a46 100644 --- a/Code/Learning/otbSVMKernels.h +++ b/Code/Learning/otbSVMKernels.h @@ -19,15 +19,18 @@ #define __otbSVMKernels_h #include "itkNumericTraits.h" -#include "itkImageRegionIterator.h" +#include "otbMath.h" // Existing kernels #include "otbSpectralAngleKernelFunctor.h" #include "otbChangeProfileKernelFunctor.h" #include "otbNonGaussianRBFKernelFunctor.h" +#include "otbMixturePolyRBFKernelFunctor.h" #include "svm.h" #include <vector> +#include <algorithm> // for std::find +#include <string.h> // for strpbrk namespace otb { @@ -37,16 +40,38 @@ namespace otb class CustomKernelFunctor : public GenericKernelFunctorBase { public: + typedef CustomKernelFunctor Self; + typedef GenericKernelFunctorBase Superclass; + CustomKernelFunctor() : GenericKernelFunctorBase() { this->SetName("custom"); } virtual ~CustomKernelFunctor() {} + // Deep copy operator + virtual GenericKernelFunctorBase* Clone() const + { + return new Self(*this); + } + virtual double operator ()(const svm_node *x, const svm_node *y, const svm_parameter& /*param*/) const { return (dot(x, x) - 2.0 * dot(x, y) + dot(y, y)); } + +protected: + CustomKernelFunctor(const Self& copy) + : Superclass(copy) + { + *this = copy; + } + + CustomKernelFunctor& operator=(const Self& copy) + { + Superclass::operator =(copy); + return *this; + } }; /** \class InvMultiQuadricKernelFunctor @@ -55,6 +80,9 @@ public: class InvMultiQuadricKernelFunctor : public GenericKernelFunctorBase { public: + typedef InvMultiQuadricKernelFunctor Self; + typedef GenericKernelFunctorBase Superclass; + InvMultiQuadricKernelFunctor() : GenericKernelFunctorBase() { this->SetName("invMultiQuadric"); @@ -62,16 +90,37 @@ public: } virtual ~InvMultiQuadricKernelFunctor() {} + // Deep copy operator + virtual GenericKernelFunctorBase* Clone() const + { + return new Self(*this); + } + virtual double operator ()(const svm_node *x, const svm_node *y, const svm_parameter& param) const { - CustomKernelFunctor custom; - double mq = this->GetValue<double>("const_coef") + custom(x, y, param); + double mq = this->GetValue<double>("const_coef") + m_Custom(x, y, param); if (mq == 0.0) { return itk::NumericTraits<double>::max(); } return 1.0 / sqrt(mq); } + +protected: + InvMultiQuadricKernelFunctor(const Self& copy) + : Superclass(copy) + { + *this = copy; + } + + InvMultiQuadricKernelFunctor& operator=(const Self& copy) + { + Superclass::operator =(copy); + return *this; + } + +private: + CustomKernelFunctor m_Custom; }; /** \class KModKernelFunctor @@ -80,6 +129,9 @@ public: class KModKernelFunctor : public GenericKernelFunctorBase { public: + typedef KModKernelFunctor Self; + typedef GenericKernelFunctorBase Superclass; + KModKernelFunctor() : GenericKernelFunctorBase() { this->SetName("KMod"); @@ -89,8 +141,7 @@ public: virtual double operator ()(const svm_node *x, const svm_node *y, const svm_parameter& param) const { - CustomKernelFunctor custom; - double mq = this->GetValue<double>("const_coef") + custom(x, y, param); + double mq = this->GetValue<double>("const_coef") + m_Custom(x, y, param); if (mq == 0.0) { @@ -98,6 +149,28 @@ public: } return exp(param.gamma / mq) - 1.0; } + + // Deep copy operator + virtual GenericKernelFunctorBase* Clone() const + { + return new Self(*this); + } + +protected: + KModKernelFunctor(const Self& copy) + : Superclass(copy) + { + *this = copy; + } + + KModKernelFunctor& operator=(const Self& copy) + { + Superclass::operator =(copy); + return *this; + } + +private: + CustomKernelFunctor m_Custom; }; /** \class SAMKernelFunctor @@ -106,6 +179,9 @@ public: class SAMKernelFunctor : public GenericKernelFunctorBase { public: + typedef SAMKernelFunctor Self; + typedef GenericKernelFunctorBase Superclass; + SAMKernelFunctor() : GenericKernelFunctorBase() { this->SetName("SAM"); @@ -122,6 +198,25 @@ public: double ss = dot(x, y); return vcl_acos(ss / vcl_sqrt(den)); } + + // Deep copy operator + virtual GenericKernelFunctorBase* Clone() const + { + return new Self(*this); + } + +protected: + SAMKernelFunctor(const Self& copy) + : Superclass(copy) + { + *this = copy; + } + + SAMKernelFunctor& operator=(const Self& copy) + { + Superclass::operator =(copy); + return *this; + } }; /** \class RadialSAMKernelFunctor @@ -130,6 +225,9 @@ public: class RadialSAMKernelFunctor : public GenericKernelFunctorBase { public: + typedef RadialSAMKernelFunctor Self; + typedef GenericKernelFunctorBase Superclass; + RadialSAMKernelFunctor() : GenericKernelFunctorBase() { this->SetName("RadialSAM"); @@ -138,9 +236,30 @@ public: virtual double operator ()(const svm_node *x, const svm_node *y, const svm_parameter& param) const { - SAMKernelFunctor sam; - return vcl_exp(-param.gamma * sam(x, y, param)); + return vcl_exp(-param.gamma * m_Sam(x, y, param)); + } + + // Deep copy operator + virtual GenericKernelFunctorBase* Clone() const + { + return new Self(*this); + } + +protected: + RadialSAMKernelFunctor(const Self& copy) + : Superclass(copy) + { + *this = copy; + } + + RadialSAMKernelFunctor& operator=(const Self& copy) + { + Superclass::operator =(copy); + return *this; } + +private: + SAMKernelFunctor m_Sam; }; /** \class InverseCosSAMKernelFunctor @@ -149,6 +268,9 @@ public: class InverseCosSAMKernelFunctor : public GenericKernelFunctorBase { public: + typedef InverseCosSAMKernelFunctor Self; + typedef GenericKernelFunctorBase Superclass; + InverseCosSAMKernelFunctor() : GenericKernelFunctorBase() { this->SetName("InverseCosSAM"); @@ -157,9 +279,30 @@ public: virtual double operator ()(const svm_node *x, const svm_node *y, const svm_parameter& param) const { - SAMKernelFunctor sam; - return 1.0 - vcl_cos(sam(x, y, param)); + return 1.0 - vcl_cos(m_Sam(x, y, param)); + } + + // Deep copy operator + virtual GenericKernelFunctorBase* Clone() const + { + return new Self(*this); } + +protected: + InverseCosSAMKernelFunctor(const Self& copy) + : Superclass(copy) + { + *this = copy; + } + + InverseCosSAMKernelFunctor& operator=(const Self& copy) + { + Superclass::operator =(copy); + return *this; + } + +private: + SAMKernelFunctor m_Sam; }; /** \class InvMultiQuadraticSAMKernelFunctor @@ -168,6 +311,9 @@ public: class InvMultiQuadraticSAMKernelFunctor : public GenericKernelFunctorBase { public: + typedef InvMultiQuadraticSAMKernelFunctor Self; + typedef GenericKernelFunctorBase Superclass; + InvMultiQuadraticSAMKernelFunctor() : GenericKernelFunctorBase() { this->SetName("invMultiQuadraticSAM"); @@ -175,10 +321,15 @@ public: } virtual ~InvMultiQuadraticSAMKernelFunctor() {} + // Deep copy operator + virtual GenericKernelFunctorBase* Clone() const + { + return new Self(*this); + } + virtual double operator ()(const svm_node *x, const svm_node *y, const svm_parameter& param) const { - SAMKernelFunctor sam; - double mq = this->GetValue<double>("const_coef") + sam(x, y, param); + double mq = this->GetValue<double>("const_coef") + m_Sam(x, y, param); if (mq == 0.) { @@ -186,6 +337,22 @@ public: } return 1. / sqrt(mq); } + +protected: + InvMultiQuadraticSAMKernelFunctor(const Self& copy) + : Superclass(copy) + { + *this = copy; + } + + InvMultiQuadraticSAMKernelFunctor& operator=(const Self& copy) + { + Superclass::operator =(copy); + return *this; + } + +private: + SAMKernelFunctor m_Sam; }; /** \class KModSAMKernelFunctor @@ -194,6 +361,9 @@ public: class KModSAMKernelFunctor : public GenericKernelFunctorBase { public: + typedef KModSAMKernelFunctor Self; + typedef GenericKernelFunctorBase Superclass; + KModSAMKernelFunctor() : GenericKernelFunctorBase() { this->SetName("KModSAM"); @@ -201,10 +371,15 @@ public: } virtual ~KModSAMKernelFunctor() {} + // Deep copy operator + virtual GenericKernelFunctorBase* Clone() const + { + return new Self(*this); + } + virtual double operator ()(const svm_node *x, const svm_node *y, const svm_parameter& param) const { - SAMKernelFunctor sam; - double mq = this->GetValue<double>("const_coef") + sam(x, y, param); + double mq = this->GetValue<double>("const_coef") + m_Sam(x, y, param); if (mq == 0.) { @@ -212,6 +387,22 @@ public: } return vcl_exp(param.gamma / mq) - 1.0; } + +protected: + KModSAMKernelFunctor(const Self& copy) + : Superclass(copy) + { + *this = copy; + } + + KModSAMKernelFunctor& operator=(const Self& copy) + { + Superclass::operator =(copy); + return *this; + } + +private: + SAMKernelFunctor m_Sam; }; /** \class RBFKernelFunctor @@ -220,6 +411,9 @@ public: class RBFKernelFunctor : public GenericKernelFunctorBase { public: + typedef RBFKernelFunctor Self; + typedef GenericKernelFunctorBase Superclass; + RBFKernelFunctor() : GenericKernelFunctorBase() { this->SetName("RBF"); @@ -227,11 +421,15 @@ public: } virtual ~RBFKernelFunctor() {} - virtual double operator ()(const svm_node *x, const svm_node *y, const svm_parameter& param) const + // Deep copy operator + virtual GenericKernelFunctorBase* Clone() const { - CustomKernelFunctor custom; - double res = this->GetValue<double>("gamma_coef") * custom(x, y, param); + return new Self(*this); + } + virtual double operator ()(const svm_node *x, const svm_node *y, const svm_parameter& param) const + { + double res = this->GetValue<double>("gamma_coef") * m_Custom(x, y, param); return vcl_exp(-res); } @@ -310,6 +508,21 @@ public: } +protected: + RBFKernelFunctor(const Self& copy) + : Superclass(copy) + { + *this = copy; + } + + RBFKernelFunctor& operator=(const Self& copy) + { + Superclass::operator =(copy); + return *this; + } + +private: + CustomKernelFunctor m_Custom; }; /** \class RBFRBFSAMKernelFunctor @@ -318,6 +531,9 @@ public: class RBFRBFSAMKernelFunctor : public GenericKernelFunctorBase { public: + typedef RBFRBFSAMKernelFunctor Self; + typedef GenericKernelFunctorBase Superclass; + RBFRBFSAMKernelFunctor() : GenericKernelFunctorBase() { this->SetName("RBFRBFSAM"); @@ -325,13 +541,34 @@ public: } virtual ~RBFRBFSAMKernelFunctor() {} + // Deep copy operator + virtual GenericKernelFunctorBase* Clone() const + { + return new Self(*this); + } + virtual double operator ()(const svm_node *x, const svm_node *y, const svm_parameter& param) const { - CustomKernelFunctor custom; - RadialSAMKernelFunctor radialSam; - return (this->GetValue<double>("lin_coef") * vcl_exp(-param.gamma * custom(x, y, param)) - + (1.0 - this->GetValue<double>("lin_coef")) * radialSam(x, y, param)); + return (this->GetValue<double>("lin_coef") * vcl_exp(-param.gamma * m_Custom(x, y, param)) + + (1.0 - this->GetValue<double>("lin_coef")) * m_RadialSam(x, y, param)); } + +protected: + RBFRBFSAMKernelFunctor(const Self& copy) + : Superclass(copy) + { + *this = copy; + } + + RBFRBFSAMKernelFunctor& operator=(const Self& copy) + { + Superclass::operator =(copy); + return *this; + } + +private: + CustomKernelFunctor m_Custom; + RadialSAMKernelFunctor m_RadialSam; }; /** \class PolyRBFSAMKernelFunctor @@ -340,6 +577,9 @@ public: class PolyRBFSAMKernelFunctor : public GenericKernelFunctorBase { public: + typedef PolyRBFSAMKernelFunctor Self; + typedef GenericKernelFunctorBase Superclass; + PolyRBFSAMKernelFunctor() : GenericKernelFunctorBase() { this->SetName("polyRBFSAM"); @@ -348,13 +588,34 @@ public: } virtual ~PolyRBFSAMKernelFunctor() {} + // Deep copy operator + virtual GenericKernelFunctorBase* Clone() const + { + return new Self(*this); + } + virtual double operator ()(const svm_node *x, const svm_node *y, const svm_parameter& param) const { - RadialSAMKernelFunctor radialSam; return this->GetValue<double>("const_lin") * vcl_pow(dot(x, y) + this->GetValue<double>("const_coef"), param.degree) + (1.0 - this->GetValue<double>("const_coef")) - * radialSam(x, y, param); + * m_RadialSam(x, y, param); + } + +protected: + PolyRBFSAMKernelFunctor(const Self& copy) + : Superclass(copy) + { + *this = copy; + } + + PolyRBFSAMKernelFunctor& operator=(const Self& copy) + { + Superclass::operator =(copy); + return *this; } + +private: + RadialSAMKernelFunctor m_RadialSam; }; /** \class RBFDiffKernelFunctor @@ -363,12 +624,21 @@ public: class RBFDiffKernelFunctor : public GenericKernelFunctorBase { public: + typedef RBFDiffKernelFunctor Self; + typedef GenericKernelFunctorBase Superclass; + RBFDiffKernelFunctor() : GenericKernelFunctorBase() { this->SetName("RBFDiff"); } virtual ~RBFDiffKernelFunctor() {} + // Deep copy operator + virtual GenericKernelFunctorBase* Clone() const + { + return new Self(*this); + } + virtual double operator ()(const svm_node *x, const svm_node *y, const svm_parameter& param) const { @@ -396,6 +666,20 @@ public: } return total; } + +protected: + RBFDiffKernelFunctor(const Self& copy) + : Superclass(copy) + { + *this = copy; + } + + RBFDiffKernelFunctor& operator=(const Self& copy) + { + Superclass::operator =(copy); + return *this; + } + }; /** \class CustomLinearKernelFunctor @@ -404,17 +688,41 @@ public: class CustomLinearKernelFunctor : public GenericKernelFunctorBase { public: + typedef CustomLinearKernelFunctor Self; + typedef GenericKernelFunctorBase Superclass; + CustomLinearKernelFunctor() : GenericKernelFunctorBase() { this->SetName("customLinear"); } virtual ~CustomLinearKernelFunctor() {} + // Deep copy operator + virtual GenericKernelFunctorBase* Clone() const + { + return new Self(*this); + } + virtual double operator ()(const svm_node *x, const svm_node *y, const svm_parameter& param) const { - CustomKernelFunctor custom; - return (vcl_exp(-param.gamma * custom(x, y, param))); + return (vcl_exp(-param.gamma * m_Custom(x, y, param))); } + +protected: + CustomLinearKernelFunctor(const Self& copy) + : Superclass(copy) + { + *this = copy; + } + + CustomLinearKernelFunctor& operator=(const Self& copy) + { + Superclass::operator =(copy); + return *this; + } + +private: + CustomKernelFunctor m_Custom; }; /** \class GroupedRBFKernelFunctor @@ -423,12 +731,21 @@ public: class GroupedRBFKernelFunctor : public GenericKernelFunctorBase { public: + typedef GroupedRBFKernelFunctor Self; + typedef GenericKernelFunctorBase Superclass; + GroupedRBFKernelFunctor() : GenericKernelFunctorBase() { this->SetName("groupedRBF"); } virtual ~GroupedRBFKernelFunctor() {} + // Deep copy operator + virtual GenericKernelFunctorBase* Clone() const + { + return new Self(*this); + } + virtual double operator ()(const svm_node *x, const svm_node *y, const svm_parameter& param) const { const char * parameters = param.custom; @@ -513,8 +830,7 @@ public: } // value can have different value according to j - CustomLinearKernelFunctor customLinear; - value = customLinear(xGroup, yGroup, param); + value = m_CustomLinear(xGroup, yGroup, param); total += value; } @@ -552,8 +868,7 @@ public: } // value can have different value according to j - CustomLinearKernelFunctor customLinear; - value = customLinear(xGroup, yGroup, param); + value = m_CustomLinear(xGroup, yGroup, param); total += value; } @@ -563,8 +878,7 @@ public: else { - CustomLinearKernelFunctor customLinear; - total = static_cast<double>(numberOfGroups) * customLinear(x, y, param); + total = static_cast<double>(numberOfGroups) * m_CustomLinear(x, y, param); } if (xTemp != NULL) delete xTemp; @@ -572,6 +886,22 @@ public: return total; } + +protected: + GroupedRBFKernelFunctor(const Self& copy) + : Superclass(copy) + { + *this = copy; + } + + GroupedRBFKernelFunctor& operator=(const Self& copy) + { + Superclass::operator =(copy); + return *this; + } + +private: + CustomLinearKernelFunctor m_CustomLinear; }; /** \class GroupingAdaptiveKernelFunctor @@ -580,6 +910,9 @@ public: class GroupingAdaptiveKernelFunctor : public GenericKernelFunctorBase { public: + typedef GroupingAdaptiveKernelFunctor Self; + typedef GenericKernelFunctorBase Superclass; + GroupingAdaptiveKernelFunctor() : GenericKernelFunctorBase() { this->SetName("groupingAdaptive"); @@ -588,6 +921,12 @@ public: } virtual ~GroupingAdaptiveKernelFunctor() {} + // Deep copy operator + virtual GenericKernelFunctorBase* Clone() const + { + return new Self(*this); + } + virtual double operator ()(const svm_node *x, const svm_node *y, const svm_parameter& param) const { const char * parameters = param.custom; @@ -730,6 +1069,21 @@ public: return total; } + + +protected: + GroupingAdaptiveKernelFunctor(const Self& copy) + : Superclass(copy) + { + *this = copy; + } + + GroupingAdaptiveKernelFunctor& operator=(const Self& copy) + { + Superclass::operator =(copy); + return *this; + } + }; } diff --git a/Code/Learning/otbSVMModel.h b/Code/Learning/otbSVMModel.h index 25c0f2828c..860677645d 100644 --- a/Code/Learning/otbSVMModel.h +++ b/Code/Learning/otbSVMModel.h @@ -299,13 +299,15 @@ public: } /** Get/Set methods for generic kernel functor */ - virtual GenericKernelFunctorBase * GetKernelFunctor(void) const + GenericKernelFunctorBase * GetKernelFunctor(void) const { return m_Parameters.kernel_generic; } - virtual void SetKernelFunctor(GenericKernelFunctorBase* pGenericKernelFunctor) + + void SetKernelFunctor(GenericKernelFunctorBase* pGenericKernelFunctor) { - m_Parameters.kernel_generic = pGenericKernelFunctor; + if (pGenericKernelFunctor != NULL) + m_Parameters.kernel_generic = pGenericKernelFunctor->Clone(); this->Modified(); } diff --git a/Code/Learning/otbSVMModel.txx b/Code/Learning/otbSVMModel.txx index 8c2cd7358e..56f3a8790b 100644 --- a/Code/Learning/otbSVMModel.txx +++ b/Code/Learning/otbSVMModel.txx @@ -70,7 +70,6 @@ SVMModel<TValue, TLabel>::Initialize() if (!m_Model) { m_Model = new struct svm_model; - m_Model->delete_composed = false; m_Model->l = 0; m_Model->nr_class = 0; m_Model->SV = NULL; diff --git a/Code/Learning/otbSpectralAngleKernelFunctor.h b/Code/Learning/otbSpectralAngleKernelFunctor.h index e183ae12c3..ea31df6c40 100644 --- a/Code/Learning/otbSpectralAngleKernelFunctor.h +++ b/Code/Learning/otbSpectralAngleKernelFunctor.h @@ -46,6 +46,14 @@ class SpectralAngleKernelFunctor : public GenericKernelFunctorBase { public: + typedef SpectralAngleKernelFunctor Self; + typedef GenericKernelFunctorBase Superclass; + + // Deep copy operator + virtual GenericKernelFunctorBase* Clone() const + { + return new Self(*this); + } double operator ()(const svm_node * x, const svm_node * y, const svm_parameter& param) const; @@ -58,7 +66,23 @@ public: void Update(); protected: - inline double SAM(const svm_node * x, const svm_node * y) const; + SpectralAngleKernelFunctor(const Self& copy) + : Superclass(copy) + { + *this = copy; + } + + SpectralAngleKernelFunctor& + operator=(const Self& copy) + { + Superclass::operator =(copy); + Update(); + return *this; + } + +private: + + double SAM(const svm_node * x, const svm_node * y) const; double m_Coef; }; diff --git a/Utilities/otbsvm/svm.cpp b/Utilities/otbsvm/svm.cpp index 8a52980f6c..1a3a023db7 100644 --- a/Utilities/otbsvm/svm.cpp +++ b/Utilities/otbsvm/svm.cpp @@ -42,6 +42,8 @@ static void print_string_stdout(const char *s) #ifdef OTB_SHOW_ALL_MSG_DEBUG fputs(s,stdout); fflush(stdout); +#else + s = 0; // keep compiler happy #endif /*** End OTB modification ***/ } @@ -236,7 +238,7 @@ private: static double dot(const svm_node *px, const svm_node *py); /*** OTB modification : add svm_parameter to the list of parameters ***/ - double kernel_linear(int i, int j, const svm_parameter& param) const + double kernel_linear(int i, int j, const svm_parameter&) const { return dot(x[i],x[j]); } @@ -2118,7 +2120,9 @@ static void svm_group_classes(const svm_problem *prob, int *nr_class_ret, int ** // svm_model *svm_train(const svm_problem *prob, const svm_parameter *param) { - svm_model *model = Malloc(svm_model,1); + /*** Begin OTB modification ***/ + svm_model *model = new svm_model; + /*** End OTB modification ***/ model->param = *param; model->free_sv = 0; // XXX @@ -2786,8 +2790,9 @@ svm_model *svm_load_model(const char *model_file_name, GenericKernelFunctorBase* if(fp==NULL) return NULL; // read parameters - - svm_model *model = Malloc(svm_model,1); + /*** Begin OTB modification ***/ + svm_model *model = new svm_model; + /*** End OTB modification ***/ svm_parameter& param = model->param; model->rho = NULL; model->probA = NULL; @@ -2818,7 +2823,7 @@ svm_model *svm_load_model(const char *model_file_name, GenericKernelFunctorBase* free(model->rho); free(model->label); free(model->nSV); - free(model); + delete model; return NULL; } } @@ -2840,7 +2845,7 @@ svm_model *svm_load_model(const char *model_file_name, GenericKernelFunctorBase* free(model->rho); free(model->label); free(model->nSV); - free(model); + delete model; return NULL; } } @@ -2905,10 +2910,10 @@ svm_model *svm_load_model(const char *model_file_name, GenericKernelFunctorBase* { if (generic_kernel_functor == NULL) { - fprintf(stderr, "generic kernel functor is not initialized\n", cmd); + fprintf(stderr, "generic kernel functor is not initialized\n"); return NULL; } - param.kernel_generic = generic_kernel_functor; + param.kernel_generic = generic_kernel_functor->Clone(); //Load generic parameters int cr = param.kernel_generic->load_parameters(&fp); if (cr != 0) @@ -2932,8 +2937,7 @@ svm_model *svm_load_model(const char *model_file_name, GenericKernelFunctorBase* param.kernel_composed = new ComposedKernelFunctor; int cr = param.kernel_composed->load_parameters(&fp); - model->delete_composed = true; - //int cr = param.kernel_generic->load_parameters(&fp); + if (cr != 0) { fprintf(stderr, "error while loading composed kernel parameters from the file %s.\n", model_file_name); @@ -3029,14 +3033,13 @@ svm_model *svm_copy_model( const svm_model *model ) const svm_parameter& param = model->param; // instanciated the copy - svm_model *modelCpy = Malloc(svm_model,1); + svm_model *modelCpy = new svm_model; svm_parameter& paramCpy = modelCpy->param; modelCpy->rho = NULL; modelCpy->probA = NULL; modelCpy->probB = NULL; modelCpy->label = NULL; modelCpy->nSV = NULL; - modelCpy->delete_composed = false; // SVM type copy paramCpy.svm_type = param.svm_type; @@ -3144,14 +3147,18 @@ svm_model *svm_copy_model( const svm_model *model ) // Generic kernel copy if (param.kernel_type == GENERIC) { - paramCpy.kernel_generic = new GenericKernelFunctorBase; - *paramCpy.kernel_generic = *param.kernel_generic; + if (param.kernel_generic != NULL) + paramCpy.kernel_generic = param.kernel_generic->Clone(); + else + paramCpy.kernel_generic = NULL; } // Composed kernel copy if (param.kernel_type == COMPOSED) { - paramCpy.kernel_composed = new ComposedKernelFunctor; - *paramCpy.kernel_generic = *param.kernel_generic; + if (param.kernel_composed != NULL) + paramCpy.kernel_composed = param.kernel_composed->Clone(); + else + paramCpy.kernel_composed = NULL; } return modelCpy; @@ -3181,7 +3188,7 @@ void svm_free_and_destroy_model(svm_model** model_ptr_ptr) if(model_ptr != NULL) { svm_free_model_content(model_ptr); - free(model_ptr); + delete model_ptr; } } @@ -3191,11 +3198,14 @@ void svm_destroy_model(svm_model* model_ptr) svm_free_and_destroy_model(&model_ptr); } -void svm_destroy_param(svm_parameter* param) +/*** Begin OTB modification ***/ +void svm_destroy_param(svm_parameter* /*param*/) { - free(param->weight_label); - free(param->weight); + // done in destructor now + //free(param->weight_label); + //free(param->weight); } +/*** End OTB modification ***/ const char *svm_check_parameter(const svm_problem *prob, const svm_parameter *param) { @@ -3341,19 +3351,51 @@ void svm_set_print_string_function(void (*print_func)(const char *)) /*** Begin OTB modification ***/ -GenericKernelFunctorBase::GenericKernelFunctorBase(const GenericKernelFunctorBase& copy) +GenericKernelFunctorBase::GenericKernelFunctorBase() + : m_Name("FunctorName") +{ +} + +GenericKernelFunctorBase::~GenericKernelFunctorBase() +{ +} + +GenericKernelFunctorBase::GenericKernelFunctorBase(const Self& copy) { *this = copy; } GenericKernelFunctorBase& -GenericKernelFunctorBase::operator=(const GenericKernelFunctorBase& copy) +GenericKernelFunctorBase::operator=(const Self& copy) { this->m_MapParameters = copy.m_MapParameters; this->m_Name = copy.m_Name; return *this; } +GenericKernelFunctorBase* GenericKernelFunctorBase::Clone() const +{ + return new Self(*this); +} + +double GenericKernelFunctorBase::operator()(const svm_node * /*x*/, const svm_node * /*y*/, const svm_parameter& /*param*/) const +{ + itkGenericExceptionMacro(<<"Kernel functor not definied (Null)"); + return static_cast<double> (0.); +} + +/** Used for Taylor classification*/ +// degree is the development degree +// index is the current value +// isAtEnd to indicate that it's the last possible derivation +// baseValue is the constant of the formula +double GenericKernelFunctorBase::derivative(const svm_node * /*x*/, const svm_node * /*y*/, const svm_parameter& /*param*/, + int /*degree*/, int /*index*/, bool /*isAtEnd*/, double /*constValue*/) const +{ + itkGenericExceptionMacro(<<"derivative method not definied (Null)"); + return 0.; +} + int GenericKernelFunctorBase:: load_parameters(FILE ** pfile) @@ -3375,6 +3417,7 @@ load_parameters(FILE ** pfile) } return 0; } + int GenericKernelFunctorBase:: save_parameters(FILE ** pfile, const char * generic_kernel_parameters_keyword)const @@ -3640,56 +3683,154 @@ add(const svm_node *px, const svm_node *py) const return(vec); } + +void GenericKernelFunctorBase::SetName(std::string name) +{ + m_Name = name; +} +std::string GenericKernelFunctorBase::GetName(void) const +{ + return m_Name; +} + +void GenericKernelFunctorBase::SetMapParameters(const MapType & map) +{ + m_MapParameters = map; +} + +const GenericKernelFunctorBase::MapType & GenericKernelFunctorBase::GetMapParameters() const +{ + return m_MapParameters; +} + +GenericKernelFunctorBase::MapType GenericKernelFunctorBase::GetMapParameters() +{ + return m_MapParameters; +} + +void GenericKernelFunctorBase::Update(void) +{ +} + // **************************************************************************************** // ************************ ComposedKernelFunctor methods ********************/ // **************************************************************************************** -ComposedKernelFunctor::ComposedKernelFunctor(const ComposedKernelFunctor& copy) +ComposedKernelFunctor::ComposedKernelFunctor() +{ + this->SetName("ComposedFunctorName"); + this->SetValue<bool> ("MultiplyKernelFunctor", false); +} + +ComposedKernelFunctor::~ComposedKernelFunctor() +{ + ClearFunctorList(); +} + +ComposedKernelFunctor::ComposedKernelFunctor(const Self& copy) : Superclass(copy) { *this = copy; } ComposedKernelFunctor& -ComposedKernelFunctor::operator=(const ComposedKernelFunctor& copy) +ComposedKernelFunctor::operator=(const Self& copy) { // Call Superclass::operator= Superclass::operator =(copy); // Copy Self attributes - this->m_KernelFunctorList = copy.m_KernelFunctorList; - this->m_HaveToBeDeletedList = copy.m_HaveToBeDeletedList; + SetKernelFunctorList(copy.m_KernelFunctorList); this->m_PonderationList = copy.m_PonderationList; return *this; } +ComposedKernelFunctor* ComposedKernelFunctor::Clone() const +{ + return new Self(*this); +} + +double ComposedKernelFunctor::operator()(const svm_node *x, const svm_node *y, const svm_parameter& param) const +{ + double out = 0.; + if (!m_KernelFunctorList.empty() && !m_PonderationList.empty() && m_KernelFunctorList.size() + == m_PonderationList.size()) + { + for (unsigned int i = 0; i < m_KernelFunctorList.size(); i++) + { + const GenericKernelFunctorBase& kernel = *m_KernelFunctorList[i]; + if (!this->GetValue<bool> ("MultiplyKernelFunctor")) + { + out += m_PonderationList[i] * kernel(x, y, param); + } + else + { + out *= kernel(x, y, param); + } + } + } + else + { + itkGenericExceptionMacro(<<"ComposedKernelFunctor::operator() : lists dimensions mismatch"); + } + return out; +} + +double ComposedKernelFunctor::derivative(const svm_node *x, const svm_node *y, const svm_parameter& param, int degree, int index, bool isAtEnd, double constValue) const +{ + double out = 0.; + if (m_KernelFunctorList.size() != 0 && m_PonderationList.size() != 0 && m_KernelFunctorList.size() + == m_PonderationList.size()) + { + for (unsigned int i = 0; i < m_KernelFunctorList.size(); i++) + { + if ((this->GetValue<bool> ("MultiplyKernelFunctor")) == false) + { + out += m_PonderationList[i] * (m_KernelFunctorList[i]->derivative(x, y, param, degree, index, isAtEnd, + constValue)); + } + else + { + itkGenericExceptionMacro(<<"derivative method not definied (Null)"); + } + } + } + else + { + itkGenericExceptionMacro(<<"ComposedKernelFunctor::operator() : lists dimensions mismatch"); + } + return out; +} + void ComposedKernelFunctor ::print_parameters(void)const { MapConstIterator iter = this->GetMapParameters().begin(); - std::cout << "Print composed kernel parameters: "<<this->GetName()<<", "<<this->GetMapParameters().size()<<std::endl; - while( iter != this->GetMapParameters().end() ) - { - std::cout << " "<<iter->first <<" "<<iter->second<<std::endl; - ++iter; - } - std::cout<<std::endl; - std::cout<<"Composition kernels:"<<std::endl; - if (m_KernelFunctorList.size() != 0 && m_PonderationList.size() != 0 && m_KernelFunctorList.size() == m_PonderationList.size()) - { - for (unsigned int i = 0; i<m_KernelFunctorList.size(); i++) - { - std::cout<<m_KernelFunctorList[i]->GetName()<<":"<<std::endl; - std::cout<<"Associated ponderation:"<<m_PonderationList[i]<<std::endl; - m_KernelFunctorList[i]->print_parameters(); - std::cout<<std::endl; - } - } - else - { - itkGenericExceptionMacro(<<"ComposedKernelFunctor::print_param() : lists dimensions mismatch"); - } + std::cout << "Print composed kernel parameters: " << this->GetName() << ", " << this->GetMapParameters().size() + << std::endl; + while (iter != this->GetMapParameters().end()) + { + std::cout << " " << iter->first << " " << iter->second << std::endl; + ++iter; + } + std::cout << std::endl; + std::cout << "Composition kernels:" << std::endl; + if (m_KernelFunctorList.size() != 0 && m_PonderationList.size() != 0 && m_KernelFunctorList.size() + == m_PonderationList.size()) + { + for (unsigned int i = 0; i < m_KernelFunctorList.size(); i++) + { + std::cout << m_KernelFunctorList[i]->GetName() << ":" << std::endl; + std::cout << "Associated ponderation:" << m_PonderationList[i] << std::endl; + m_KernelFunctorList[i]->print_parameters(); + std::cout << std::endl; + } + } + else + { + itkGenericExceptionMacro(<<"ComposedKernelFunctor::print_param() : lists dimensions mismatch"); + } } @@ -3702,47 +3843,46 @@ load_parameters(FILE ** pfile) char value[81]; // Read functor name - fscanf(*pfile,"%80s",keyword); + fscanf(*pfile, "%80s", keyword); this->SetName(std::string(keyword)); // Read number of parameters - fscanf(*pfile,"%d",&NbParams); + fscanf(*pfile, "%d", &NbParams); - for ( int cpt=0 ; cpt < NbParams ; cpt++) + for (int cpt = 0; cpt < NbParams; cpt++) { - fscanf(*pfile,"%80s",keyword); - fscanf(*pfile,"%80s",value); - this->SetValue<std::string>(keyword, value); + fscanf(*pfile, "%80s", keyword); + fscanf(*pfile, "%80s", value); + this->SetValue<std::string> (keyword, value); } - char tempChar[100]; fscanf(*pfile, "%80s", tempChar); - while( strcmp(tempChar,"Ponderation")==0 || strcmp(tempChar,"list:")==0 ) + while (strcmp(tempChar, "Ponderation") == 0 || strcmp(tempChar, "list:") == 0) { - fscanf(*pfile, "%80s", tempChar); + fscanf(*pfile, "%80s", tempChar); } unsigned int i = 0; - while( strcmp(tempChar,"Kernels")!=0 ) + while (strcmp(tempChar, "Kernels") != 0) { - m_PonderationList.push_back(::atof(tempChar)); - fscanf(*pfile, "%80s", tempChar); - i++; + m_PonderationList.push_back(::atof(tempChar)); + fscanf(*pfile, "%80s", tempChar); + i++; } - while( strcmp(tempChar,"Kernels")==0 || strcmp(tempChar,"list:")==0 || strcmp(tempChar,"Number")==0 || strcmp(tempChar,"of")==0 || strcmp(tempChar,"Kernels:")==0) + while (strcmp(tempChar, "Kernels") == 0 || strcmp(tempChar, "list:") == 0 || strcmp(tempChar, "Number") == 0 + || strcmp(tempChar, "of") == 0 || strcmp(tempChar, "Kernels:") == 0) { - fscanf(*pfile, "%80s", tempChar); + fscanf(*pfile, "%80s", tempChar); } int NbOfKernels = ::atoi(tempChar); - for(unsigned int j=0; j<static_cast<unsigned int>(NbOfKernels); j++) + for (unsigned int j = 0; j < static_cast<unsigned int> (NbOfKernels); j++) { - fscanf(*pfile, "%80s", tempChar); - GenericKernelFunctorBase * gen; - gen = new GenericKernelFunctorBase; - gen->load_parameters(pfile); - m_KernelFunctorList.push_back(gen); - // Add the pointer to the "Have to Deleted" pointer list - m_HaveToBeDeletedList.push_back(gen); + fscanf(*pfile, "%80s", tempChar); + GenericKernelFunctorBase * gen; + gen = new GenericKernelFunctorBase; + gen->load_parameters(pfile); + AddKernelFunctorModelToKernelList(gen); + delete gen; } return 0; @@ -3760,20 +3900,20 @@ save_parameters(FILE ** pfile, const char * composed_kernel_parameters_keyword)c flux << this->GetMapParameters().size(); flux >> strNbParams; line = line + " " + this->GetName() + " " + strNbParams; - while( iter != this->GetMapParameters().end() ) + while (iter != this->GetMapParameters().end()) { - line = line + " " + iter->first + " " + iter->second; - ++iter; + line = line + " " + iter->first + " " + iter->second; + ++iter; } line = line + "\n" + "Ponderation list:\n"; - for (unsigned int i = 0; i<m_PonderationList.size(); i++) + for (unsigned int i = 0; i < m_PonderationList.size(); i++) { - std::string ponde; - ::otb::StringStream flux; - flux << m_PonderationList[i]; - flux >> ponde; - line = line + " " + ponde; + std::string ponde; + ::otb::StringStream flux; + flux << m_PonderationList[i]; + flux >> ponde; + line = line + " " + ponde; } line = line + "\n" + "Kernels list:\nNumber of Kernels: "; std::string nbOfKernels; @@ -3782,14 +3922,75 @@ save_parameters(FILE ** pfile, const char * composed_kernel_parameters_keyword)c flux2 >> nbOfKernels; line = line + nbOfKernels + "\n"; - fprintf(*pfile,"%s", line.c_str()); - for (unsigned int i = 0; i<m_KernelFunctorList.size(); i++) + fprintf(*pfile, "%s", line.c_str()); + for (unsigned int i = 0; i < m_KernelFunctorList.size(); i++) { - m_KernelFunctorList[i]->save_parameters(pfile, "generic_kernel_parameters"); + m_KernelFunctorList[i]->save_parameters(pfile, "generic_kernel_parameters"); } return 0; } -/*** End OTB modification ***/ +/** Set/Get the SVM Model vector for the composed kernel */ +ComposedKernelFunctor::KernelListType& ComposedKernelFunctor::GetKernelFunctorList() +{ + return m_KernelFunctorList; +} + +void ComposedKernelFunctor::SetKernelFunctorList(const KernelListType& kernelFunctorList) +{ + ClearFunctorList(); + KernelListType::const_iterator it = kernelFunctorList.begin(); + for (; it != kernelFunctorList.end(); ++it) + { + m_KernelFunctorList.push_back( (*it)->Clone() ); + } +} + +// Add 1 element to the end of the list +void ComposedKernelFunctor::AddKernelFunctorModelToKernelList(const GenericKernelFunctorBase * kernelfunctor) +{ + m_KernelFunctorList.push_back( kernelfunctor->Clone() ); +} + +void ComposedKernelFunctor::ClearFunctorList() +{ + KernelListType::iterator it = m_KernelFunctorList.begin(); + for (; it != m_KernelFunctorList.end(); ++it) + { + delete *it; + } + m_KernelFunctorList.clear(); +} + + +/** Set/Get the ponderation list to apply to each svm_model of the composed kernel */ +std::vector<double> ComposedKernelFunctor::GetPonderationList() +{ + return m_PonderationList; +} + +void ComposedKernelFunctor::SetPonderationModelList(const std::vector<double> & list) +{ + m_PonderationList = list; +} + +// Add 1 element to the end of the list +void ComposedKernelFunctor::AddPonderationToPonderationList(const double & pond) +{ + m_PonderationList.push_back(pond); +} + +/** Set/Get the boolean to know which operation has to be done with the kernel functors. */ +void ComposedKernelFunctor::SetMultiplyKernelFunctor( bool val ) +{ + this->SetValue<bool>("MultiplyKernelFunctor", val); +} + +bool ComposedKernelFunctor::GetMultiplyKernelFunctor() +{ + return (this->GetValue<bool>("MultiplyKernelFunctor")); +} + +/*** End OTB modification ***/ diff --git a/Utilities/otbsvm/svm.h b/Utilities/otbsvm/svm.h index b6dfa23748..8de804303b 100644 --- a/Utilities/otbsvm/svm.h +++ b/Utilities/otbsvm/svm.h @@ -7,11 +7,163 @@ #include <map> #include <vector> #include "otbMacro.h" -class GenericKernelFunctorBase; -class ComposedKernelFunctor; -/*** End OTB modification ***/ +#include <string.h> + +struct svm_node; +struct svm_parameter; + +/** \class GenericKernelFunctorBase + * \brief Undocumented + */ +class GenericKernelFunctorBase +{ +public: + typedef GenericKernelFunctorBase Self; + + typedef std::map<std::string, std::string> MapType; + typedef MapType::iterator MapIterator; + typedef MapType::const_iterator MapConstIterator; + + GenericKernelFunctorBase(); + + virtual ~GenericKernelFunctorBase(); + + virtual GenericKernelFunctorBase* Clone() const; + + virtual double operator()(const svm_node * /*x*/, const svm_node * /*y*/, const svm_parameter& /*param*/) const; + + + virtual double derivative(const svm_node * /*x*/, const svm_node * /*y*/, const svm_parameter& /*param*/, + int /*degree*/, int /*index*/, bool /*isAtEnd*/, double /*constValue*/) const; + + virtual int load_parameters(FILE ** pfile); + + virtual int save_parameters(FILE ** pfile, const char * generic_kernel_parameters_keyword) const; + + virtual void print_parameters(void) const; + + virtual double dot(const svm_node *px, const svm_node *py) const; + + virtual svm_node * sub(const svm_node *px, const svm_node *py) const; + + virtual svm_node * add(const svm_node *px, const svm_node *py) const; + + virtual void SetName(std::string name); + virtual std::string GetName(void) const; + + virtual void SetMapParameters(const MapType & map); + virtual const MapType & GetMapParameters() const; + virtual MapType GetMapParameters(); + + template<class T> + T GetValue(const char *option) const + { + std::string Value = m_MapParameters.find(std::string(option))->second; + T lValeur; + ::otb::StringStream flux; + flux << Value; + flux >> lValeur; + return lValeur; + } + + template<class T> + void SetValue(const char *option, const T & value) + { + std::string lValeur; + ::otb::StringStream flux; + flux << value; + flux >> lValeur; + m_MapParameters[std::string(option)] = lValeur; + } + + // Override this method to to split m_MapParameters into specific variables to speed up kernel evaluations + virtual void Update(void); + +protected: + GenericKernelFunctorBase(const Self& copy); + + Self& operator=(const Self& copy); + +private: + /** Kernel functor parameters */ + MapType m_MapParameters; + + /** Functor label name (without space) */ + std::string m_Name; +}; + +/** \class ComposedKernelFunctor + * \brief Undocumented + */ +class ComposedKernelFunctor: public GenericKernelFunctorBase +{ +public: + typedef ComposedKernelFunctor Self; + typedef GenericKernelFunctorBase Superclass; + + ComposedKernelFunctor(); + + virtual ~ComposedKernelFunctor(); + + virtual ComposedKernelFunctor* Clone() const; + + typedef std::vector<GenericKernelFunctorBase *> KernelListType; + + virtual double operator()(const svm_node *x, const svm_node *y, const svm_parameter& param) const; + + /** Used for Taylor classification*/ + // degree is the developement degree + // index is the current value + // isAtEnd to indicate that it's the last possible derivation + // baseValue is the constant of the formula + virtual double derivative(const svm_node *x, const svm_node *y, const svm_parameter& param, int degree, int index, bool isAtEnd, double constValue) const; + + virtual int load_parameters(FILE ** pfile); + + virtual int save_parameters(FILE ** pfile, const char * composed_kernel_parameters_keyword) const; + + virtual void print_parameters(void)const; + + /** Get a reference to the internal kernel list */ + KernelListType& GetKernelFunctorList(); + + /** Set internal kernel list. A clone is made of each kernel when copying */ + void SetKernelFunctorList(const KernelListType& kernelFunctorList); + + // Add 1 element to the end of the list. A clone is made of the kernel + void AddKernelFunctorModelToKernelList(const GenericKernelFunctorBase * kernelfunctor); + + /** Set/Get the ponderation list to apply to each svm_model of the composed kernel */ + std::vector<double> GetPonderationList(); + void SetPonderationModelList(const std::vector<double> & list); + // Add 1 element to the end of the list + void AddPonderationToPonderationList(const double & pond); + + /** Set/Get the boolean to know which operation has to be done with the kernel functors. */ + void SetMultiplyKernelFunctor( bool val ); + bool GetMultiplyKernelFunctor(); + +protected: + /** Copy constructor */ + ComposedKernelFunctor(const Self& copy); + + /* Assignment operator */ + Self& operator=(const Self& copy); + +private: + + void ClearFunctorList(); + + typedef GenericKernelFunctorBase::MapType MapType; + typedef GenericKernelFunctorBase::MapIterator MapIterator; + typedef GenericKernelFunctorBase::MapConstIterator MapConstIterator; + + /** Generic kernel functors that composed kernel */ + KernelListType m_KernelFunctorList; + /** Ponderation list to apply to each svm_model of the composed kernel*/ + std::vector<double> m_PonderationList; +}; -/*** Begin OTB modification ***/ //#ifdef __cplusplus //extern "C" { //#endif @@ -37,7 +189,80 @@ enum { LINEAR, POLY, RBF, SIGMOID, PRECOMPUTED, GENERIC, COMPOSED }; /* kernel_t struct svm_parameter { - int svm_type; + /*** Begin OTB modification ***/ + svm_parameter() + : kernel_generic(NULL), + kernel_composed(NULL), + nr_weight(0), + weight_label(NULL), + weight(NULL) + { + } + + svm_parameter(const svm_parameter& copy) + : kernel_generic(NULL), + kernel_composed(NULL), + nr_weight(0), + weight_label(NULL), + weight(NULL) + { + *this = copy; + } + + ~svm_parameter() + { + delete kernel_generic; + delete kernel_composed; + free(weight_label); + free(weight); + } + + svm_parameter& operator=(const svm_parameter& copy) + { + svm_type = copy.svm_type; + kernel_type = copy.kernel_type; + degree = copy.degree; + gamma = copy.gamma; + coef0 = copy.coef0; + const_coef = copy.const_coef; + lin_coef = copy.lin_coef; + memcpy(custom, copy.custom, 500); + delete kernel_generic; + delete kernel_composed; + kernel_generic = copy.kernel_generic != NULL ? copy.kernel_generic->Clone() : NULL; + kernel_composed = copy.kernel_composed != NULL ? copy.kernel_composed->Clone() : NULL; + cache_size = copy.cache_size; + eps = copy.eps; + C = copy.C; + + if (nr_weight > 0) + { + free(weight_label); + free(weight); + } + + nr_weight = copy.nr_weight; + if (nr_weight > 0) + { + weight_label = (int *)malloc(nr_weight*sizeof(int)); + weight = (double *)malloc(nr_weight*sizeof(double)); + } + else + { + weight_label = NULL; + weight = NULL; + } + memcpy(weight_label, copy.weight_label, nr_weight); + memcpy(weight, copy.weight, nr_weight); + nu = copy.nu; + p = copy.p; + shrinking = copy.shrinking; + probability = copy.probability; + return *this; + } + /*** End OTB modification ***/ + + int svm_type; int kernel_type; int degree; /* for poly */ double gamma; /* for poly/rbf/sigmoid */ @@ -66,7 +291,7 @@ struct svm_parameter // // svm_model -// +// struct svm_model { struct svm_parameter param; /* parameter */ @@ -86,10 +311,6 @@ struct svm_model /* XXX */ int free_sv; /* 1 if svm_model is created by svm_load_model*/ /* 0 if svm_model is created by svm_train */ - - /*** Begin OTB modification ***/ - bool delete_composed; // to know if the composed functor was set using load method - /*** End OTB modification ***/ }; struct svm_model *svm_train(const struct svm_problem *prob, const struct svm_parameter *param); @@ -121,7 +342,7 @@ void svm_set_print_string_function(void (*print_func)(const char *)); // deprecated // this function will be removed in future release -void svm_destroy_model(struct svm_model *model_ptr); +void svm_destroy_model(struct svm_model *model_ptr); /*** Begin OTB modification ***/ //#ifdef __cplusplus @@ -129,271 +350,4 @@ void svm_destroy_model(struct svm_model *model_ptr); //#endif /*** End OTB modification ***/ -/*** Begin OTB modification ***/ - -/** \class GenericKernelFunctorBase - * \brief Undocumented - */ -class GenericKernelFunctorBase -{ -public: - GenericKernelFunctorBase() : - m_Name("FunctorName") - { - } - - /** Copy constructor */ - GenericKernelFunctorBase(const GenericKernelFunctorBase& copy); - - GenericKernelFunctorBase& operator=(const GenericKernelFunctorBase& copy); - - virtual ~GenericKernelFunctorBase() - { - } - - typedef GenericKernelFunctorBase Self; - typedef std::map<std::string, std::string> MapType; - typedef MapType::iterator MapIterator; - typedef MapType::const_iterator MapConstIterator; - - template<class T> - T GetValue(const char *option) const - { - std::string Value = m_MapParameters.find(std::string(option))->second; - T lValeur; - ::otb::StringStream flux; - flux << Value; - flux >> lValeur; - return lValeur; - } - - template<class T> - void SetValue(const char *option, const T & value) - { - std::string lValeur; - ::otb::StringStream flux; - flux << value; - flux >> lValeur; - m_MapParameters[std::string(option)] = lValeur; - } - - virtual double operator()(const svm_node * /*x*/, const svm_node * /*y*/, const svm_parameter& /*param*/) const - { - itkGenericExceptionMacro(<<"Kernel functor not definied (Null)"); - return static_cast<double> (0.); - } - - /** Used for Taylor classification*/ - // degree is the development degree - // index is the current value - // isAtEnd to indicate that it's the last possible derivation - // baseValue is the constant of the formula - virtual double derivative(const svm_node * /*x*/, const svm_node * /*y*/, const svm_parameter& /*param*/, - int /*degree*/, int /*index*/, bool /*isAtEnd*/, double /*constValue*/) const - { - itkGenericExceptionMacro(<<"derivative method not definied (Null)"); - return 0.; - } - - virtual int load_parameters(FILE ** pfile); - - virtual int save_parameters(FILE ** pfile, const char * generic_kernel_parameters_keyword) const; - - virtual void print_parameters(void) const; - - virtual double dot(const svm_node *px, const svm_node *py) const; - - virtual svm_node * sub(const svm_node *px, const svm_node *py) const; - - virtual svm_node * add(const svm_node *px, const svm_node *py) const; - - virtual void SetName(std::string name) - { - m_Name = name; - } - virtual std::string GetName(void) - { - return m_Name; - } - virtual const std::string GetName(void) const - { - return m_Name; - } - - virtual void SetMapParameters(const MapType & map) - { - m_MapParameters = map; - } - - virtual const MapType & GetMapParameters() const - { - return m_MapParameters; - } - - virtual MapType GetMapParameters() - { - return m_MapParameters; - } - - // Override this method to to split m_MapParameters into specific variables to speed up kernel evaluations - virtual void Update(void) - { - } - -private: - - /** Kernel functor parameters */ - MapType m_MapParameters; - - /** Functor label name (without space) */ - std::string m_Name; -}; - -/** \class ComposedKernelFunctor - * \brief Undocumented - */ -class ComposedKernelFunctor: public GenericKernelFunctorBase -{ -public: - typedef GenericKernelFunctorBase Superclass; - - ComposedKernelFunctor() - { - this->SetName("ComposedFunctorName"); - this->SetValue<bool> ("MultiplyKernelFunctor", false); - } - - virtual ~ComposedKernelFunctor() - { - for(unsigned int i=0; i < m_HaveToBeDeletedList.size(); i++) - { - for(unsigned int j=0; j<m_KernelFunctorList.size(); j++) - { - if(m_KernelFunctorList[j] == m_HaveToBeDeletedList[i]) - { - delete m_KernelFunctorList[j]; - m_HaveToBeDeletedList[i] = NULL; - } - } - } - } - - /** Copy constructor */ - ComposedKernelFunctor( const ComposedKernelFunctor& copy ); - - ComposedKernelFunctor& operator=(const ComposedKernelFunctor& copy); - - typedef std::vector<GenericKernelFunctorBase *> KernelListType; - - virtual double operator()(const svm_node *x, const svm_node *y, const svm_parameter& param) const - { - double out = 0.; - if (m_KernelFunctorList.size() != 0 && m_PonderationList.size() != 0 && m_KernelFunctorList.size() == m_PonderationList.size()) - { - for (unsigned int i = 0; i<m_KernelFunctorList.size(); i++) - { - if ((this->GetValue<bool>("MultiplyKernelFunctor")) == false) - { - out += m_PonderationList[i]*(*m_KernelFunctorList[i])(x, y, param); - } - else - { - out *= (*m_KernelFunctorList[i])(x, y, param); - } - } - } - else - { - itkGenericExceptionMacro(<<"ComposedKernelFunctor::operator() : lists dimensions mismatch"); - } - return out; - } - - /** Used for Taylor classification*/ - // degree is the developement degree - // index is the current value - // isAtEnd to indicate that it's the last possible derivation - // baseValue is the constant of the formula - virtual double derivative(const svm_node *x, const svm_node *y, const svm_parameter& param, int degree, int index, bool isAtEnd, double constValue)const - { - double out = 0.; - if (m_KernelFunctorList.size() != 0 && m_PonderationList.size() != 0 && m_KernelFunctorList.size() == m_PonderationList.size()) - { - for (unsigned int i = 0; i<m_KernelFunctorList.size(); i++) - { - if ((this->GetValue<bool>("MultiplyKernelFunctor")) == false) - { - out += m_PonderationList[i]*(m_KernelFunctorList[i]->derivative(x, y, param, degree, index, isAtEnd, constValue)); - } - else - { - itkGenericExceptionMacro(<<"derivative method not definied (Null)"); - } - } - } - else - { - itkGenericExceptionMacro(<<"ComposedKernelFunctor::operator() : lists dimensions mismatch"); - } - return out; - } - - virtual int load_parameters(FILE ** pfile); - - virtual int save_parameters(FILE ** pfile, const char * composed_kernel_parameters_keyword) const; - - virtual void print_parameters(void)const; - - /** Set/Get the SVM Model vector for the composed kernel */ - KernelListType GetKernelFunctorList() - {return m_KernelFunctorList;}; - - void SetKernelFunctorList(KernelListType kernelFunctorList) - {m_KernelFunctorList = kernelFunctorList;}; - - // Add 1 element to the end of the list - void AddKernelFunctorModelToKernelList(GenericKernelFunctorBase * kernelfunctor) - {m_KernelFunctorList.push_back(kernelfunctor);}; - - /** Generic kernel functors that have to be deleted. */ - KernelListType GetHaveToBeDeletedList() - {return m_HaveToBeDeletedList;}; - void SetHaveToBeDeletedList(KernelListType kernelFunctorList) - {m_HaveToBeDeletedList = kernelFunctorList;}; - // Add 1 element to the end of the list - void AddKernelFunctorModelToDeleteKernelList(GenericKernelFunctorBase * kernelfunctor) - {m_HaveToBeDeletedList.push_back(kernelfunctor);}; - - /** Set/Get the ponderation list to apply to each svm_model of the composed kernel */ - std::vector<double> GetPonderationList() - {return m_PonderationList;}; - void SetPonderationModelList(const std::vector<double> & list) - {m_PonderationList = list;}; - // Add 1 element to the end of the list - void AddPonderationToPonderationList(const double & pond) - {m_PonderationList.push_back(pond);}; - - /** Set/Get the boolean to know which operation has to be done with the kernel functors. */ - void SetMultiplyKernelFunctor( bool val ) - {this->SetValue<bool>("MultiplyKernelFunctor", val);}; - bool GetMultiplyKernelFunctor() - {return (this->GetValue<bool>("MultiplyKernelFunctor"));}; - -private: - typedef GenericKernelFunctorBase::MapType MapType; - typedef GenericKernelFunctorBase::MapIterator MapIterator; - typedef GenericKernelFunctorBase::MapConstIterator MapConstIterator; - - /** Generic kernel functors that composed kernel */ - KernelListType m_KernelFunctorList; - /** Generic kernel functors that have to be deleted. - * This list was made for the load_parameters methods where you set new functors using new. - * But, in other cases, functor can be added with reference. Thus, we need to know which ones have to be deleted. */ - KernelListType m_HaveToBeDeletedList; - /** Ponderation list to apply to each svm_model of the composed kernel*/ - std::vector<double> m_PonderationList; -}; - -/*** End OTB modification ***/ - #endif /* _LIBSVM_H */ -- GitLab