9 #if defined(_MSC_VER) && (_MSC_VER >= 1400) 11 #pragma warning(disable:4100) 12 #pragma warning(disable:4512) 16 #include <boost/numeric/ublas/vector.hpp> 17 #include <boost/numeric/ublas/io.hpp> 18 #include <boost/random/mersenne_twister.hpp> 19 #include <boost/random/uniform_int_distribution.hpp> 25 #include <boost/serialization/nvp.hpp> 26 #include <boost/serialization/split_member.hpp> 27 #include <boost/serialization/vector.hpp> 28 #include <boost/serialization/utility.hpp> 30 #include "../Value.hpp" 31 #include "../Point.hpp" 32 #include "../utils/Random.hpp" 39 template <
typename Val,
typename DomainVal>
47 template<
class Archive>
48 void serialize( Archive &ar,
const unsigned int file_version ){
49 boost::serialization::split_member(ar, *
this, file_version);
52 template<
class Archive>
53 void save(Archive & ar,
const unsigned int )
const {
54 ar & boost::serialization::make_nvp(
"Dimension", dimension );
55 ar & boost::serialization::make_nvp(
"TrainingExamples", trainingExamples );
56 ar & boost::serialization::make_nvp(
"Smo", smo );
57 ar & boost::serialization::make_nvp(
"Categories", categories);
61 template<
class Archive>
62 void load(Archive & ar,
const unsigned int ) {
63 ar >> boost::serialization::make_nvp(
"Dimension", dimension );
64 ar >> boost::serialization::make_nvp(
"TrainingExamples", trainingExamples );
65 ar >> boost::serialization::make_nvp(
"Smo", smo );
66 ar >> boost::serialization::make_nvp(
"Categories", categories);
79 typedef typename Belief<DomainVal>::Beliefs
Beliefs;
92 typedef typename boost::numeric::ublas::vector<Val> ClassifyExampleSmo;
95 typedef typename std::pair < int, ClassifyExampleSmo > TrainExampleSmo;
102 hyperbolic_tangent_type
110 friend class boost::serialization::access;
113 template<
class Archive>
114 void serialize( Archive &ar,
const unsigned int file_version ){
115 boost::serialization::split_member(ar, *
this, file_version);
119 template<
class Archive>
120 void save(Archive & ar,
const unsigned int )
const {
121 ar & boost::serialization::make_nvp(
"C", C );
122 ar & boost::serialization::make_nvp(
"margin", margin );
123 ar & boost::serialization::make_nvp(
"epsilon", epsilon );
124 ar & boost::serialization::make_nvp(
"b", b );
125 ar & boost::serialization::make_nvp(
"delta_b", delta_b );
126 ar & boost::serialization::make_nvp(
"gaussParameter", gaussParameter );
127 ar & boost::serialization::make_nvp(
"polynomialInhomogeneousParameter", polynomialInhomogeneousParameter );
128 ar & boost::serialization::make_nvp(
"polynomialDegree", polynomialDegree );
129 ar & boost::serialization::make_nvp(
"tangentFrequency", tangentFrequency );
130 ar & boost::serialization::make_nvp(
"tangentShift", tangentShift );
131 ar & boost::serialization::make_nvp(
"sigmoidScaleFactor", sigmoidScaleFactor );
132 ar & boost::serialization::make_nvp(
"finiteStopCondition", finiteStopCondition );
133 ar & boost::serialization::make_nvp(
"stepsStopCondition", stepsStopCondition );
134 ar & boost::serialization::make_nvp(
"alpha", alpha );
135 ar & boost::serialization::make_nvp(
"error_cache", error_cache );
136 ar & boost::serialization::make_nvp(
"trainingExamples", trainingExamples );
137 ar & boost::serialization::make_nvp(
"kernelType", kernel_type );
141 template<
class Archive>
142 void load(Archive & ar,
const unsigned int ) {
143 ar >> boost::serialization::make_nvp(
"C", C );
144 ar >> boost::serialization::make_nvp(
"margin", margin );
145 ar >> boost::serialization::make_nvp(
"epsilon", epsilon );
146 ar >> boost::serialization::make_nvp(
"b", b );
147 ar >> boost::serialization::make_nvp(
"delta_b", delta_b );
148 ar >> boost::serialization::make_nvp(
"gaussParameter", gaussParameter );
149 ar >> boost::serialization::make_nvp(
"polynomialInhomogeneousParameter", polynomialInhomogeneousParameter );
150 ar >> boost::serialization::make_nvp(
"polynomialDegree", polynomialDegree );
151 ar >> boost::serialization::make_nvp(
"tangentFrequency", tangentFrequency );
152 ar >> boost::serialization::make_nvp(
"tangentShift", tangentShift );
153 ar >> boost::serialization::make_nvp(
"sigmoidScaleFactor", sigmoidScaleFactor );
154 ar >> boost::serialization::make_nvp(
"finiteStopCondition", finiteStopCondition );
155 ar >> boost::serialization::make_nvp(
"stepsStopCondition", stepsStopCondition );
156 ar >> boost::serialization::make_nvp(
"alpha", alpha );
157 ar >> boost::serialization::make_nvp(
"error_cache", error_cache );
158 ar >> boost::serialization::make_nvp(
"trainingExamples", trainingExamples );
159 ar >> boost::serialization::make_nvp(
"kernelType", kernel_type );
160 setKernel(kernel_type);
164 Val kernel_gauss(
const ClassifyExampleSmo& vec1,
const ClassifyExampleSmo& vec2);
167 Val kernel_linear(
const ClassifyExampleSmo& vec1,
const ClassifyExampleSmo& vec2);
170 Val kernel_polynomial(
const ClassifyExampleSmo& vec1,
const ClassifyExampleSmo& vec2);
173 Val kernel_hyperbolic_tangent(
const ClassifyExampleSmo& vec1,
const ClassifyExampleSmo& vec2);
179 Kernel_type kernel_type;
182 void setKernel(Kernel_type);
185 Val sigmoid_function(Val);
188 std::vector<Val> alpha;
209 Val polynomialInhomogeneousParameter;
212 Val polynomialDegree;
215 Val tangentFrequency;
221 bool finiteStopCondition;
222 double stepsStopCondition;
225 Val sigmoidScaleFactor;
228 std::vector<Val> error_cache;
231 std::vector< TrainExampleSmo > trainingExamples;
234 Val learned_func(
size_t i);
237 size_t optimizeTwoAlphas(
size_t i1,
size_t i2);
240 size_t examineKKTViolation(
size_t i1);
243 SmoAlgorithm(
const SmoAlgorithm& smo);
244 const SmoAlgorithm& operator=(
const SmoAlgorithm& smo);
247 SmoAlgorithm(Kernel_type _kernel_type = default_type) : kernel_type(_kernel_type), b(0.0), C(2.0), margin(0.001), epsilon(0.000000000001), gaussParameter(1.0), polynomialInhomogeneousParameter(0.0), polynomialDegree(2.0), tangentFrequency(1.0), tangentShift(0.0), finiteStopCondition(
true), stepsStopCondition(1.0), sigmoidScaleFactor(0.1) {
249 setKernel(kernel_type);
253 void train(std::vector<typename SmoAlgorithm::TrainExampleSmo> _trainingExamples);
256 Val classify(
const ClassifyExampleSmo& vec);
297 AttrDomain categories;
303 std::vector< typename SmoAlgorithm::TrainExampleSmo > trainingExamples;
310 Val classify(
const ClassifyExample& vec);
313 typename SmoAlgorithm::ClassifyExampleSmo convertVectorToUblas(
const ClassifyExample&);
321 SvmClassifier(
size_t dimension_,
const AttrDomain& category_domain) : dimension(dimension_) {
323 if(category_domain.getSize()==2)
324 categories = category_domain;
326 throw std::domain_error(
"For SVM classifier category domain should have exactly 2 classes");
330 void addExample(
const ClassifyExample& example,
const AttrValue& category);
406 template <
typename Val,
typename DomainVal>
408 typename SmoAlgorithm::ClassifyExampleSmo toRet(vec.size());
409 for(
size_t i=0; i<vec.size(); ++i)
414 template <
typename Val,
typename DomainVal>
417 return smo.classify( convertVectorToUblas( vec ) );
420 template <
typename Val,
typename DomainVal>
424 categories.find(category);
425 if(example.size() == this->dimension){
429 if(category==categories.begin()->get())
430 this->trainingExamples.push_back(std::make_pair(1, convertVectorToUblas(example) ));
432 this->trainingExamples.push_back(std::make_pair(-1, convertVectorToUblas(example) ));
436 throw std::domain_error(
"Train example's category: "+category+
" is not in classifier's domain.");
440 template <
typename Val,
typename DomainVal>
445 auto classify_value = this->classify(vec);
450 auto it = categories.begin();
451 toRet.push_back(
typename Beliefs::value_type(it->getDomain()->getValueId(it), classify_value));
455 toRet.push_back(
typename Beliefs::value_type(it->getDomain()->getValueId(it), 1.0-classify_value));
458 std::sort( toRet.begin(), toRet.end() );
462 template <
typename Val,
typename DomainVal>
467 template <
typename Val,
typename DomainVal>
470 template <
typename Val,
typename DomainVal>
473 template <
typename Val,
typename DomainVal>
476 template <
typename Val,
typename DomainVal>
479 template <
typename Val,
typename DomainVal>
482 template <
typename Val,
typename DomainVal>
485 template <
typename Val,
typename DomainVal>
488 template <
typename Val,
typename DomainVal>
491 template <
typename Val,
typename DomainVal>
494 template <
typename Val,
typename DomainVal>
497 template <
typename Val,
typename DomainVal>
500 template <
typename Val,
typename DomainVal>
503 template <
typename Val,
typename DomainVal>
506 template <
typename Val,
typename DomainVal>
509 template <
typename Val,
typename DomainVal>
512 template <
typename Val,
typename DomainVal>
515 template <
typename Val,
typename DomainVal>
518 template <
typename Val,
typename DomainVal>
520 smo.setKernel(SmoAlgorithm::Kernel_type::gauss_type);
523 template <
typename Val,
typename DomainVal>
525 smo.setKernel(SmoAlgorithm::Kernel_type::polynomial_type);
528 template <
typename Val,
typename DomainVal>
530 smo.setKernel(SmoAlgorithm::Kernel_type::hyperbolic_tangent_type);
539 template <
typename Val,
typename DomainVal>
541 assert(vec1.size() == vec2.size());
542 Val squared_euclidean_distance = boost::numeric::ublas::sum(boost::numeric::ublas::element_prod(vec1-vec2, vec1-vec2));
543 return exp(-gaussParameter*squared_euclidean_distance);
546 template <
typename Val,
typename DomainVal>
548 assert(vec1.size() == vec2.size());
549 return boost::numeric::ublas::sum(boost::numeric::ublas::element_prod(vec1, vec2));
552 template <
typename Val,
typename DomainVal>
554 assert(vec1.size() == vec2.size());
555 return pow(kernel_linear(vec1, vec2) + this->polynomialInhomogeneousParameter, this->polynomialDegree);
558 template <
typename Val,
typename DomainVal>
560 assert(vec1.size() == vec2.size());
561 return tanh(this->tangentFrequency * kernel_linear(vec1, vec2) - this->tangentShift);
564 template <
typename Val,
typename DomainVal>
566 return 1.0 / (1.0 + exp( (-this->sigmoidScaleFactor) * x) );
569 template <
typename Val,
typename DomainVal>
572 size_t numExamples = trainingExamples.size();
573 for(
size_t j = 0; j<numExamples; ++j)
575 result += alpha[i]*trainingExamples[i].first*((this->*kernel)(trainingExamples[i].second, trainingExamples[j].second));
580 template <
typename Val,
typename DomainVal>
582 this->kernel_type = kernel_type_in;
590 case polynomial_type:
593 case hyperbolic_tangent_type:
602 template <
typename Val,
typename DomainVal>
608 Val alpha1_old = alpha[i1];
609 int y1 = this->trainingExamples[i1].first;
611 if(alpha1_old > 0 && alpha1_old < this->C)
612 E1 = this->error_cache[i1];
614 E1 = learned_func(i1) - y1;
616 Val alpha2_old = this->alpha[i2];
617 int y2 = this->trainingExamples[i2].first;
619 if(alpha2_old > 0 && alpha2_old < this->C)
620 E2 = this->error_cache[i2];
622 E2 = learned_func(i2) - y2;
629 Val gamma = alpha1_old + alpha2_old;
640 Val gamma = alpha1_old - alpha2_old;
656 if(kernel_type==gauss_type || kernel_type==default_type){
660 k11 = (this->*kernel)(this->trainingExamples[i1].second, this->trainingExamples[i1].second);
661 k22 = (this->*kernel)(this->trainingExamples[i2].second, this->trainingExamples[i2].second);
663 Val k12 = (this->*kernel)(this->trainingExamples[i1].second, this->trainingExamples[i2].second);
664 Val eta = 2*k12 - k11 - k22;
668 alpha2_new = alpha2_old + y2 * (E2 - E1) / eta;
671 else if(alpha2_new > H)
676 Lobj = (eta/2) * L * L + L * ( y2 * (E1-E2) - eta * alpha2_old);
677 Hobj = (eta/2) * H * H + H * ( y2 * (E1-E2) - eta * alpha2_old);
679 if(Lobj > Hobj + epsilon)
681 else if(Lobj < Hobj - epsilon)
684 alpha2_new = alpha2_old;
687 if( ( (alpha2_new > alpha2_old) ? (alpha2_new - alpha2_old) : ( alpha2_old - alpha2_new ) ) < epsilon * (epsilon + alpha2_new + alpha2_old) )
690 Val alpha1_new = alpha1_old -s * (alpha2_new - alpha2_old);
692 alpha2_new += s * alpha1_new;
695 else if(alpha1_new > this->C){
696 alpha2_new += s * (alpha1_new - this->C);
697 alpha1_new = this->C;
703 if(alpha1_new > 0 && alpha1_new < this->C)
704 bnew = b + E1 + y1 * (alpha1_new - alpha1_old) * k11 + y2 * (alpha2_new - alpha2_old) * k12;
706 if(alpha2_new > 0 && alpha2_new < this->C)
707 bnew = b + E2 + y1 * (alpha1_new - alpha1_old) * k12 + y2 * (alpha2_new - alpha2_old) * k22;
709 Val b1 = b + E1 + y1 * (alpha1_new - alpha1_old) * k11 + y2 * (alpha2_new - alpha2_old) * k12;
710 Val b2 = b + E2 + y1 * (alpha1_new - alpha1_old) * k12 + y2 * (alpha2_new - alpha2_old) * k22;
714 this->delta_b = bnew - this->b;
720 Val t1 = y1 * (alpha1_new - alpha1_old);
721 Val t2 = y2 * (alpha2_new - alpha2_old);
722 size_t numExamples = trainingExamples.size();
723 for(
size_t i=0; i<numExamples; ++i)
724 if( alpha[i] > 0 && alpha[i] < this->C)
725 this->error_cache[i] += t1 * (this->*kernel)(trainingExamples[i1].second, trainingExamples[i].second) + t2 * (this->*kernel)(trainingExamples[i2].second, trainingExamples[i].second) - this->delta_b;
726 this->error_cache[i1] = 0.0;
727 this->error_cache[i2] = 0.0;
730 alpha[i1] = alpha1_new;
731 alpha[i2] = alpha2_new;
735 template <
typename Val,
typename DomainVal>
737 Val y1 = this->trainingExamples[i1].first;
738 Val alpha1 = alpha[i1];
739 Val E1 = (alpha1 > 0 && alpha1 < this->C) ? (this->error_cache[i1]) : (learned_func(i1) - y1);
741 size_t numExamples = trainingExamples.size();
742 if((r1 < -(this->margin) && alpha1 < (this->C)) || (r1 > this->margin && alpha1 > 0)){
747 for(
size_t k = 0; k < numExamples; ++k)
748 if(alpha[k] > 0 && alpha[k] < C){
749 Val E2 = error_cache[k];
750 Val temp = (E1>E2) ? (E1-E2) : (E2-E1);
757 if(optimizeTwoAlphas(i1, i2))
761 RandomInt rnd(0, static_cast<int>(numExamples)-1);
764 size_t j0 =
static_cast<size_t>(rnd());
765 for(
size_t j=j0; j < numExamples+j0; ++j){
766 size_t i2 = j%numExamples;
767 if(alpha[i2] > 0 && alpha[i2] < this->C)
768 if(optimizeTwoAlphas(i1, i2))
773 j0 =
static_cast<size_t>(rnd());
774 for(
size_t j=j0; j < numExamples+j0; ++j){
775 size_t i2 = j%numExamples;
776 if(optimizeTwoAlphas(i1, i2))
784 template <
typename Val,
typename DomainVal>
786 for(
const auto& example : _trainingExamples)
787 trainingExamples.push_back(example);
789 size_t numExamples = trainingExamples.size();
793 size_t alphasImproved = 0;
794 bool checkAllExamples =
true;
795 alpha.resize(numExamples, 0.);
796 error_cache.resize(numExamples, 0.);
798 size_t numSteps =
static_cast<size_t>(numExamples*this->stepsStopCondition);
800 while( (alphasImproved > 0 || checkAllExamples) && ( !(this->finiteStopCondition) || ((numSteps--) > 0 ) ) ){
802 if(checkAllExamples){
803 for(
size_t i=0; i<numExamples; ++i)
804 alphasImproved += examineKKTViolation(i);
807 for(
size_t i=0; i<numExamples; ++i)
808 if((alpha[i] > C+margin || alpha[i] < C-margin) && (alpha[i] > margin || alpha[i] < -(margin) ))
809 alphasImproved += examineKKTViolation(i);
812 checkAllExamples =
false;
813 else if(alphasImproved == 0)
814 checkAllExamples =
true;
818 std::vector<size_t> index_to_delete;
819 for(
size_t i = 0; i < alpha.size(); ++i)
822 index_to_delete.push_back(i-index_to_delete.size());
824 for(
const auto& i : index_to_delete) {
825 alpha.erase(alpha.begin() + i);
826 error_cache.erase(error_cache.begin() + i);
827 trainingExamples.erase(trainingExamples.begin() + i);
831 template <
typename Val,
typename DomainVal>
834 if(alpha.size() == 0)
837 size_t numExamples = trainingExamples.size();
838 for(
size_t i=0; i<numExamples; ++i)
839 result += alpha[i] * trainingExamples[i].first * ( (this->*kernel)(trainingExamples[i].second, vec) );
840 return sigmoid_function(result-b);
843 template <
typename Val,
typename DomainVal>
845 trainingExamples.clear();
852 template <
typename Val,
typename DomainVal>
856 else throw std::invalid_argument(
"SVM's parameter 'C' should be > 0");
859 template <
typename Val,
typename DomainVal>
862 this->margin = margin_in;
863 else throw std::invalid_argument(
"SVM's parameter 'margin' should be > 0");
866 template <
typename Val,
typename DomainVal>
869 this->epsilon = epsilon_in;
870 else throw std::invalid_argument(
"SVM's parameter 'epsilon' should be > 0");
873 template <
typename Val,
typename DomainVal>
875 if( gaussParameter_in > 0 )
876 this->gaussParameter = gaussParameter_in;
877 else throw std::invalid_argument(
"SVM's parameter 'gaussParameter' should be > 0");
880 template <
typename Val,
typename DomainVal>
882 this->polynomialInhomogeneousParameter = polynomialInhomogeneousParameter_in;
885 template <
typename Val,
typename DomainVal>
887 this->polynomialDegree = polynomialDegree_in;
890 template <
typename Val,
typename DomainVal>
892 if( tangentFrequency_in > 0 )
893 this->tangentFrequency = tangentFrequency_in;
894 else throw std::invalid_argument(
"SVM's parameter 'tangentFrequency' should be > 0");
897 template <
typename Val,
typename DomainVal>
899 if( tangentShift_in >= 0 )
900 this->tangentShift = tangentShift_in;
901 else throw std::invalid_argument(
"SVM's parameter 'tangentShift' should be >= 0");
904 template <
typename Val,
typename DomainVal>
907 this->stepsStopCondition = stop;
908 this->finiteStopCondition =
true;
910 else throw std::invalid_argument(
"SVM's parameter 'stepsStopCondition' should be > 0");
913 template <
typename Val,
typename DomainVal>
915 this->finiteStopCondition =
false;
918 template <
typename Val,
typename DomainVal>
920 if( sigmoidScaleFactor_in > 0 )
921 this->sigmoidScaleFactor = sigmoidScaleFactor_in;
922 else throw std::invalid_argument(
"SVM's parameter 'sigmoidScaleFactor' should be > 0");
927 #endif //FAIF_SVM_HPP_ DomainVal::DomainType AttrDomain
Definition: Svm.hpp:73
SvmClassifier()
Definition: Svm.hpp:318
void setPolynomialInhomogeneousParameter(Val polynomialInhomogeneousParameter)
Definition: Svm.hpp:495
void setTangentShift(Val tangentShift)
Definition: Svm.hpp:504
Beliefs getCategories(const ClassifyExample &vec)
Definition: Svm.hpp:441
size_t countTrainExamples()
Definition: Svm.hpp:474
void setSigmoidScaleFactor(Val sigmoidScaleFactor)
Definition: Svm.hpp:513
void unsetFiniteStepsStopCondition()
Definition: Svm.hpp:510
Belief< DomainVal > getCategory(const ClassifyExample &vec)
Definition: Svm.hpp:463
void setHyperbolicTangentKernel()
Definition: Svm.hpp:529
void setC(Val C)
Definition: Svm.hpp:483
void setEpsilon(Val epsilon)
Definition: Svm.hpp:489
void setMargin(Val margin)
Definition: Svm.hpp:486
void setFiniteStepsStopCondition(double stop)
Definition: Svm.hpp:507
void setTangentFrequency(Val tangentFrequency)
Definition: Svm.hpp:501
void setGaussParameter(Val gaussParameter)
Definition: Svm.hpp:492
std::vector< Val > ClassifyExample
Definition: Svm.hpp:70
void resetAndChangeDimension(size_t)
Definition: Svm.hpp:480
void setPolynomialDegree(Val polynomialDegree)
Definition: Svm.hpp:498
the uniform distribution for int, in range <min,max>, uses RandomSingleton
Definition: Random.hpp:107
SvmClassifier(size_t dimension_, const AttrDomain &category_domain)
Definition: Svm.hpp:321
void setPolynomialKernel()
Definition: Svm.hpp:524
void addExample(const ClassifyExample &example, const AttrValue &category)
Definition: Svm.hpp:421
DomainVal::Value AttrValue
Definition: Svm.hpp:76
void setLinearKernel()
Definition: Svm.hpp:516
void setGaussKernel()
Definition: Svm.hpp:519
Belief< DomainVal >::Beliefs Beliefs
Definition: Svm.hpp:79
friend class boost::serialization::access
serialization using boost::serialization
Definition: Svm.hpp:45
void reset()
Definition: Svm.hpp:477
belief is value id with probability
Definition: Belief.hpp:41
size_t getDimension()
Definition: Svm.hpp:471
void train()
Definition: Svm.hpp:468
the exception thrown when the value for given attribute is not found
Definition: ExceptionsFaif.hpp:32