svm.c
Go to the documentation of this file.
00001 
00008 /*
00009 Copyright (C) 2013 Milan Sulc.
00010 Copyright (C) 2012 Daniele Perrone.
00011 Copyright (C) 2011-13 Andrea Vedaldi.
00012 
00013 All rights reserved.
00014 
00015 This file is part of the VLFeat library and is made available under
00016 the terms of the BSD license (see the COPYING file).
00017 */
00018 
00806 /*
00807 
00808 <!-- ------------------------------------------------------------ --->
00809 @section svm-pegasos PEGASOS
00810 <!-- ------------------------------------------------------------ --->
00811 
00812 <!-- ------------------------------------------------------------ --->
00813 @subsection svm-pegasos-algorithm Algorithm
00814 <!-- ------------------------------------------------------------ --->
00815 
00816 PEGASOS @cite{shalev-shwartz07pegasos} is a stochastic subgradient
00817 optimizer. At the <em>t</em>-th iteration the algorithm:
00818 
00819 - Samples uniformly at random as subset @f$ A_t @f$ of <em>k</em> of
00820 training pairs @f$(x,y)@f$ from the <em>m</em> pairs provided for
00821 training (this subset is called mini batch).
00822 - Computes a subgradient @f$ \nabla_t @f$ of the function @f$ E_t(w) =
00823 \frac{1}{2}\|w\|^2 + \frac{1}{k} \sum_{(x,y) \in A_t} \ell(w;(x,y))
00824 @f$ (this is the SVM objective function restricted to the
00825 minibatch).
00826 - Compute an intermediate weight vector @f$ w_{t+1/2} @f$ by doing a
00827 step @f$ w_{t+1/2} = w_t - \alpha_t \nabla_t @f$ with learning rate
00828 @f$ \alpha_t = 1/(\eta t) @f$ along the subgradient. Note that the
00829 learning rate is inversely proportional to the iteration number.
00830 - Back projects the weight vector @f$ w_{t+1/2} @f$ on the
00831 hypersphere of radius @f$ \sqrt{\lambda} @f$ to obtain the next
00832 model estimate @f$ w_{t+1} @f$:
00833 @f[
00834 w_t = \min\{1, \sqrt{\lambda}/\|w\|\} w_{t+1/2}.
00835 @f]
00836 The hypersphere is guaranteed to contain the optimal weight vector
00837 @f$ w^* @f$.
00838 
00839 VLFeat implementation fixes to one the size of the mini batches @f$ k
00840 @f$.
00841 
00842 
00843 <!-- ------------------------------------------------------------ --->
00844 @subsection svm-pegasos-permutation Permutation
00845 <!-- ------------------------------------------------------------ --->
00846 
00847 VLFeat PEGASOS can use a user-defined permutation to decide the order
00848 in which data points are visited (instead of using random
00849 sampling). By specifying a permutation the algorithm is guaranteed to
00850 visit each data point exactly once in each loop. The permutation needs
00851 not to be bijective. This can be used to visit certain data samples
00852 more or less often than others, implicitly reweighting their relative
00853 importance in the SVM objective function. This can be used to balance
00854 the data.
00855 
00856 <!-- ------------------------------------------------------------ --->
00857 @subsection svm-pegasos-kernels Non-linear kernels
00858 <!-- ------------------------------------------------------------ --->
00859 
00860 PEGASOS can be extended to non-linear kernels, but the algorithm is
00861 not particularly efficient in this setting [1]. When possible, it may
00862 be preferable to work with explicit feature maps.
00863 
00864 Let @f$ k(x,y) @f$ be a positive definite kernel. A <em>feature
00865 map</em> is a function @f$ \Psi(x) @f$ such that @f$ k(x,y) = \langle
00866 \Psi(x), \Psi(y) \rangle @f$. Using this representation the non-linear
00867 SVM learning objective function writes:
00868 
00869 @f[
00870 \min_{w} \frac{\lambda}{2} \|w\|^2 + \frac{1}{m} \sum_{i=1}^n
00871 \ell(w; (\Psi(x)_i,y_i)).
00872 @f]
00873 
00874 Thus the only difference with the linear case is that the feature @f$
00875 \Psi(x) @f$ is used in place of the data @f$ x @f$.
00876 
00877 @f$ \Psi(x) @f$ can be learned off-line, for instance by using the
00878 incomplete Cholesky decomposition @f$ V^\top V @f$ of the Gram matrix
00879 @f$ K = [k(x_i,x_j)] @f$ (in this case @f$ \Psi(x_i) @f$ is the
00880 <em>i</em>-th columns of <em>V</em>). Alternatively, for additive
00881 kernels (e.g. intersection, Chi2) the explicit feature map computed by
00882 @ref homkermap.h can be used.
00883 
00884 For additive kernels it is also possible to perform the feature
00885 expansion online inside the solver, setting the specific feature map
00886 via ::vl_svmdataset_set_map. This is particular useful to keep the
00887 size of the training data small, when the number of the samples is big
00888 or the memory is limited.
00889 */
00890 
00891 #include "svm.h"
00892 #include "mathop.h"
00893 #include <string.h>
00894 
00895 struct VlSvm_ {
00896   VlSvmSolverType solver ;      
00898   vl_size dimension ;           
00899   double * model ;              
00900   double bias ;                 
00901   double biasMultiplier ;       
00903   /* valid during a run */
00904   double lambda ;               
00905   void const * data ;
00906   vl_size numData ;
00907   double const * labels ;       
00908   double const * weights ;      
00910   VlSvmDataset * ownDataset ;   
00912   VlSvmDiagnosticFunction diagnosticFn ;
00913   void * diagnosticFnData ;
00914   vl_size diagnosticFrequency ; 
00916   VlSvmLossFunction lossFn ;
00917   VlSvmLossFunction conjugateLossFn ;
00918   VlSvmLossFunction lossDerivativeFn ;
00919   VlSvmDcaUpdateFunction dcaUpdateFn ;
00920   VlSvmInnerProductFunction innerProductFn ;
00921   VlSvmAccumulateFunction accumulateFn ;
00922 
00923   vl_size iteration ;           
00924   vl_size maxNumIterations ;    
00925   double epsilon ;              
00927   /* Book keeping */
00928   VlSvmStatistics statistics ;  
00929   double * scores ;
00930 
00931   /* SGD specific */
00932   double  biasLearningRate ;    
00934   /* SDCA specific */
00935   double * alpha ;              
00936 } ;
00937 
00938 /* ---------------------------------------------------------------- */
00939 
00956 VlSvm *
00957 vl_svm_new (VlSvmSolverType type,
00958             double const * data,
00959             vl_size dimension,
00960             vl_size numData,
00961             double const * labels,
00962             double lambda)
00963 {
00964   VlSvmDataset * dataset = vl_svmdataset_new(VL_TYPE_DOUBLE, (void*)data, dimension, numData) ;
00965   VlSvm * self = vl_svm_new_with_dataset (type, dataset, labels, lambda) ;
00966   self->ownDataset = dataset ;
00967   return self ;
00968 }
00969 
00979 VlSvm *
00980 vl_svm_new_with_dataset (VlSvmSolverType solver,
00981                          VlSvmDataset * dataset,
00982                          double const * labels,
00983                          double lambda)
00984 {
00985   VlSvm * self = vl_svm_new_with_abstract_data (solver,
00986                                              dataset,
00987                                              vl_svmdataset_get_dimension(dataset),
00988                                              vl_svmdataset_get_num_data(dataset),
00989                                              labels,
00990                                              lambda) ;
00991   vl_svm_set_data_functions (self,
00992                              vl_svmdataset_get_inner_product_function(dataset),
00993                              vl_svmdataset_get_accumulate_function(dataset)) ;
00994   return self ;
00995 }
00996 
01013 VlSvm *
01014 vl_svm_new_with_abstract_data (VlSvmSolverType solver,
01015                                void * data,
01016                                vl_size dimension,
01017                                vl_size numData,
01018                                double const * labels,
01019                                double lambda)
01020 {
01021   VlSvm * self = vl_calloc(1,sizeof(VlSvm)) ;
01022 
01023   assert(dimension >= 1) ;
01024   assert(numData >= 1) ;
01025   assert(labels) ;
01026 
01027   self->solver = solver ;
01028 
01029   self->dimension = dimension ;
01030   self->model = 0 ;
01031   self->bias = 0 ;
01032   self->biasMultiplier = 1.0 ;
01033 
01034   self->lambda = lambda ;
01035   self->data = data ;
01036   self->numData = numData ;
01037   self->labels = labels ;
01038 
01039   self->diagnosticFrequency = numData ;
01040   self->diagnosticFn = 0 ;
01041   self->diagnosticFnData = 0 ;
01042 
01043   self->lossFn = vl_svm_hinge_loss ;
01044   self->conjugateLossFn = vl_svm_hinge_conjugate_loss ;
01045   self->lossDerivativeFn = vl_svm_hinge_loss_derivative ;
01046   self->dcaUpdateFn = vl_svm_hinge_dca_update ;
01047 
01048   self->innerProductFn = 0 ;
01049   self->accumulateFn = 0 ;
01050 
01051   self->iteration = 0 ;
01052   self->maxNumIterations = VL_MAX((double)numData, vl_ceil_f(10.0 / lambda)) ;
01053   self->epsilon = 1e-2 ;
01054 
01055   /* SGD */
01056   self->biasLearningRate = 0.01 ;
01057 
01058   /* SDCA */
01059   self->alpha = 0 ;
01060 
01061   /* allocations */
01062   self->model = vl_calloc(dimension, sizeof(double)) ;
01063   if (self->model == NULL) goto err_alloc ;
01064 
01065   if (self->solver == VlSvmSolverSdca) {
01066     self->alpha = vl_calloc(self->numData, sizeof(double)) ;
01067     if (self->alpha == NULL) goto err_alloc ;
01068   }
01069 
01070   self->scores = vl_calloc(numData, sizeof(double)) ;
01071   if (self->scores == NULL) goto err_alloc ;
01072 
01073   return self ;
01074 
01075 err_alloc:
01076   if (self->scores) {
01077     vl_free (self->scores) ;
01078     self->scores = 0 ;
01079   }
01080   if (self->model) {
01081     vl_free (self->model) ;
01082     self->model = 0 ;
01083   }
01084   if (self->alpha) {
01085     vl_free (self->alpha) ;
01086     self->alpha = 0 ;
01087   }
01088   return 0 ;
01089 }
01090 
01096 void
01097 vl_svm_delete (VlSvm * self)
01098 {
01099   if (self->model) {
01100     vl_free (self->model) ;
01101     self->model = 0 ;
01102   }
01103   if (self->alpha) {
01104     vl_free (self->alpha) ;
01105     self->alpha = 0 ;
01106   }
01107   if (self->ownDataset) {
01108     vl_svmdataset_delete(self->ownDataset) ;
01109     self->ownDataset = 0 ;
01110   }
01111   vl_free (self) ;
01112 }
01113 
01114 /* ---------------------------------------------------------------- */
01115 /*                                              Setters and getters */
01116 /* ---------------------------------------------------------------- */
01117 
01123 void vl_svm_set_epsilon (VlSvm *self, double epsilon)
01124 {
01125   assert(self) ;
01126   assert(epsilon >= 0) ;
01127   self->epsilon = epsilon ;
01128 }
01129 
01135 double vl_svm_get_epsilon (VlSvm const *self)
01136 {
01137   assert(self) ;
01138   return self->epsilon ;
01139 }
01140 
01148 void vl_svm_set_bias_learning_rate (VlSvm *self, double rate)
01149 {
01150   assert(self) ;
01151   assert(rate > 0) ;
01152   self->biasLearningRate = rate ;
01153 }
01154 
01160 double vl_svm_get_bias_learning_rate (VlSvm const *self)
01161 {
01162   assert(self) ;
01163   return self->biasLearningRate ;
01164 }
01165 
01174 void vl_svm_set_bias_multiplier (VlSvm * self, double b)
01175 {
01176   assert(self) ;
01177   assert(b >= 0) ;
01178   self->biasMultiplier = b ;
01179 }
01180 
01186 double vl_svm_get_bias_multiplier (VlSvm const * self)
01187 {
01188   assert(self) ;
01189   return self->biasMultiplier ;
01190 }
01191 
01201 void vl_svm_set_iteration_number (VlSvm *self, vl_uindex n)
01202 {
01203   assert(self) ;
01204   self->iteration = n ;
01205 }
01206 
01212 vl_size vl_svm_get_iteration_number (VlSvm const *self)
01213 {
01214   assert(self) ;
01215   return self->iteration ;
01216 }
01217 
01223 void vl_svm_set_max_num_iterations (VlSvm *self, vl_size n)
01224 {
01225   assert(self) ;
01226   self->maxNumIterations = n ;
01227 }
01228 
01234 vl_size vl_svm_get_max_num_iterations (VlSvm const *self)
01235 {
01236   assert(self) ;
01237   return self->maxNumIterations ;
01238 }
01239 
01248 void vl_svm_set_diagnostic_frequency (VlSvm *self, vl_size f)
01249 {
01250   assert(self) ;
01251   assert(f > 0) ;
01252   self->diagnosticFrequency = f ;
01253 }
01254 
01260 vl_size vl_svm_get_diagnostic_frequency (VlSvm const *self)
01261 {
01262   assert(self) ;
01263   return self->diagnosticFrequency ;
01264 }
01265 
01271 VlSvmSolverType vl_svm_get_solver (VlSvm const * self)
01272 {
01273   assert(self) ;
01274   return self->solver ;
01275 }
01276 
01288 void vl_svm_set_lambda (VlSvm * self, double lambda)
01289 {
01290   assert(self) ;
01291   assert(lambda >= 0) ;
01292   self->lambda = lambda ;
01293 }
01294 
01300 double vl_svm_get_lambda (VlSvm const * self)
01301 {
01302   assert(self) ;
01303   return self->lambda ;
01304 }
01305 
01320 void vl_svm_set_weights (VlSvm * self, double const *weights)
01321 {
01322   assert(self) ;
01323   self->weights = weights ;
01324 }
01325 
01331 double const *vl_svm_get_weights (VlSvm const * self)
01332 {
01333   assert(self) ;
01334   return self->weights ;
01335 }
01336 
01337 /* ---------------------------------------------------------------- */
01338 /*                                                         Get data */
01339 /* ---------------------------------------------------------------- */
01340 
01348 vl_size vl_svm_get_dimension (VlSvm *self)
01349 {
01350   assert(self) ;
01351   return self->dimension ;
01352 }
01353 
01361 vl_size vl_svm_get_num_data (VlSvm *self)
01362 {
01363   assert(self) ;
01364   return self->numData ;
01365 }
01366 
01374 double const * vl_svm_get_model (VlSvm const *self)
01375 {
01376   assert(self) ;
01377   return self->model ;
01378 }
01379 
01389 void vl_svm_set_model (VlSvm *self, double const *model)
01390 {
01391   assert(self) ;
01392   assert(model) ;
01393   memcpy(self->model, model, sizeof(double) * vl_svm_get_dimension(self)) ;
01394 }
01395 
01406 void vl_svm_set_bias (VlSvm *self, double b)
01407 {
01408   assert(self);
01409   if (self->biasMultiplier) {
01410     self->bias = b / self->biasMultiplier ;
01411   }
01412 }
01413 
01422 double vl_svm_get_bias (VlSvm const *self)
01423 {
01424   assert(self) ;
01425   return self->bias * self->biasMultiplier ;
01426 }
01427 
01433 VlSvmStatistics const * vl_svm_get_statistics (VlSvm const *self)
01434 {
01435   assert(self) ;
01436   return &self->statistics ;
01437 }
01438 
01448 double const * vl_svm_get_scores (VlSvm const *self)
01449 {
01450   return self->scores ;
01451 }
01452 
01453 /* ---------------------------------------------------------------- */
01454 /*                                                        Callbacks */
01455 /* ---------------------------------------------------------------- */
01456 
01478 void
01479 vl_svm_set_diagnostic_function (VlSvm *self, VlSvmDiagnosticFunction f, void *data) {
01480   self->diagnosticFn = f ;
01481   self->diagnosticFnData = data ;
01482 }
01483 
01492 void vl_svm_set_data_functions (VlSvm *self, VlSvmInnerProductFunction inner, VlSvmAccumulateFunction acc)
01493 {
01494   assert(self) ;
01495   assert(inner) ;
01496   assert(acc) ;
01497   self->innerProductFn = inner ;
01498   self->accumulateFn = acc ;
01499 }
01500 
01509 void vl_svm_set_loss_function (VlSvm *self, VlSvmLossFunction f)
01510 {
01511   assert(self) ;
01512   self->lossFn = f ;
01513 }
01514 
01519 void vl_svm_set_loss_derivative_function (VlSvm *self, VlSvmLossFunction f)
01520 {
01521   assert(self) ;
01522   self->lossDerivativeFn = f ;
01523 }
01524 
01529 void vl_svm_set_conjugate_loss_function (VlSvm *self, VlSvmLossFunction f)
01530 {
01531   assert(self) ;
01532   self->conjugateLossFn = f ;
01533 }
01534 
01539 void vl_svm_set_dca_update_function (VlSvm *self, VlSvmDcaUpdateFunction f)
01540 {
01541   assert(self) ;
01542   self->dcaUpdateFn = f ;
01543 }
01544 
01551 void
01552 vl_svm_set_loss (VlSvm *self, VlSvmLossType loss)
01553 {
01554 #define SETLOSS(x,y) \
01555 case VlSvmLoss ## x: \
01556   vl_svm_set_loss_function(self, vl_svm_ ## y ## _loss) ; \
01557   vl_svm_set_loss_derivative_function(self, vl_svm_ ## y ## _loss_derivative) ; \
01558   vl_svm_set_conjugate_loss_function(self, vl_svm_ ## y ## _conjugate_loss) ; \
01559   vl_svm_set_dca_update_function(self, vl_svm_ ## y ## _dca_update) ; \
01560   break;
01561 
01562   switch (loss) {
01563       SETLOSS(Hinge, hinge) ;
01564       SETLOSS(Hinge2, hinge2) ;
01565       SETLOSS(L1, l1) ;
01566       SETLOSS(L2, l2) ;
01567       SETLOSS(Logistic, logistic) ;
01568     default:
01569       assert(0) ;
01570   }
01571 }
01572 
01573 /* ---------------------------------------------------------------- */
01574 /*                                               Pre-defined losses */
01575 /* ---------------------------------------------------------------- */
01576 
01602 double
01603 vl_svm_hinge_loss (double inner, double label)
01604 {
01605   return VL_MAX(1 - label * inner, 0.0);
01606 }
01607 
01610 double
01611 vl_svm_hinge_loss_derivative (double inner, double label)
01612 {
01613   if (label * inner < 1.0) {
01614     return - label ;
01615   } else {
01616     return 0.0 ;
01617   }
01618 }
01619 
01625 double
01626 vl_svm_hinge_conjugate_loss (double u, double label) {
01627   double z = label * u ;
01628   if (-1 <= z && z <= 0) {
01629     return label * u ;
01630   } else {
01631     return VL_INFINITY_D ;
01632   }
01633 }
01634 
01637 double
01638 vl_svm_hinge_dca_update (double alpha, double inner, double norm2, double label) {
01639   double palpha = (label - inner) / norm2 + alpha ;
01640   return label * VL_MAX(0, VL_MIN(1, label * palpha)) - alpha ;
01641 }
01642 
01645 double
01646 vl_svm_hinge2_loss (double inner,double label)
01647 {
01648   double z = VL_MAX(1 - label * inner, 0.0) ;
01649   return z*z ;
01650 }
01651 
01654 double
01655 vl_svm_hinge2_loss_derivative (double inner, double label)
01656 {
01657   if (label * inner < 1.0) {
01658     return 2 * (inner - label) ;
01659   } else {
01660     return 0 ;
01661   }
01662 }
01663 
01666 double
01667 vl_svm_hinge2_conjugate_loss (double u, double label) {
01668   if (label * u <= 0) {
01669     return (label + u/4) * u ;
01670   } else {
01671     return VL_INFINITY_D ;
01672   }
01673 }
01674 
01677 double
01678 vl_svm_hinge2_dca_update (double alpha, double inner, double norm2, double label) {
01679   double palpha = (label - inner - 0.5*alpha) / (norm2 + 0.5) + alpha ;
01680   return label * VL_MAX(0, label * palpha) - alpha ;
01681 }
01682 
01685 double
01686 vl_svm_l1_loss (double inner,double label)
01687 {
01688   return vl_abs_d(label - inner) ;
01689 }
01690 
01693 double
01694 vl_svm_l1_loss_derivative (double inner, double label)
01695 {
01696   if (label > inner) {
01697     return - 1.0 ;
01698   } else {
01699     return + 1.0 ;
01700   }
01701 }
01702 
01705 double
01706 vl_svm_l1_conjugate_loss (double u, double label) {
01707   if (vl_abs_d(u) <= 1) {
01708     return label*u ;
01709   } else {
01710     return VL_INFINITY_D ;
01711   }
01712 }
01713 
01716 double
01717 vl_svm_l1_dca_update (double alpha, double inner, double norm2, double label) {
01718   if (vl_abs_d(alpha) <= 1) {
01719     double palpha = (label - inner) / norm2 + alpha ;
01720     return VL_MAX(-1.0, VL_MIN(1.0, palpha)) - alpha ;
01721   } else {
01722     return VL_INFINITY_D ;
01723   }
01724 }
01725 
01728 double
01729 vl_svm_l2_loss (double inner,double label)
01730 {
01731   double z = label - inner ;
01732   return z*z ;
01733 }
01734 
01737 double
01738 vl_svm_l2_loss_derivative (double inner, double label)
01739 {
01740   return - 2 * (label - inner) ;
01741 }
01742 
01745 double
01746 vl_svm_l2_conjugate_loss (double u, double label) {
01747   return (label + u/4) * u ;
01748 }
01749 
01752 double
01753 vl_svm_l2_dca_update (double alpha, double inner, double norm2, double label) {
01754   return (label - inner - 0.5*alpha) / (norm2 + 0.5) ;
01755 }
01756 
01759 double
01760 vl_svm_logistic_loss (double inner,double label)
01761 {
01762   double z = label * inner ;
01763   if (z >= 0) {
01764     return log(1.0 + exp(-z)) ;
01765   } else {
01766     return -z + log(exp(z) + 1.0) ;
01767   }
01768 }
01769 
01772 double
01773 vl_svm_logistic_loss_derivative (double inner, double label)
01774 {
01775   double z = label * inner ;
01776   double t = 1 / (1 + exp(-z)) ; /* this is stable for z << 0 too */
01777   return label * (t - 1) ; /*  = -label exp(-z) / (1 + exp(-z)) */
01778 }
01779 
01780 VL_INLINE double xlogx(double x)
01781 {
01782   if (x <= 1e-10) return 0 ;
01783   return x*log(x) ;
01784 }
01785 
01788 double
01789 vl_svm_logistic_conjugate_loss (double u, double label) {
01790   double z = label * u ;
01791   if (-1 <= z && z <= 0) {
01792     return xlogx(-z) + xlogx(1+z) ;
01793   } else {
01794     return VL_INFINITY_D ;
01795   }
01796 }
01797 
01800 double
01801 vl_svm_logistic_dca_update (double alpha, double inner, double norm2, double label) {
01802   /*
01803    The goal is to solve the problem
01804 
01805    min_delta A/2 delta^2 + B delta + l*(-alpha - delta|y),  -1 <= - y (alpha+delta) <= 0
01806 
01807    where A = norm2, B = inner, and y = label. To simplify the notation, we set
01808 
01809      f(beta) = beta * log(beta) + (1 - beta) * log(1 - beta)
01810 
01811    where beta = y(alpha + delta) such that
01812 
01813      l*(-alpha - delta |y) = f(beta).
01814 
01815    Hence 0 <= beta <= 1, delta = + y beta - alpha. Substituting
01816 
01817      min_beta A/2 beta^2 + y (B - A alpha) beta + f(beta) + const
01818 
01819    The Newton step is then given by
01820 
01821      beta = beta - (A beta + y(B - A alpha) + df) / (A + ddf).
01822 
01823    However, the function is singluar for beta=0 and beta=1 (infinite
01824    first and second order derivatives). Since the function is monotonic
01825    (second derivarive always strictly greater than zero) and smooth,
01826    we canuse bisection to find the zero crossing of the first derivative.
01827    Once one is sufficiently close to the optimum, a one or two Newton
01828    steps are sufficien to land on it with excellent accuracy.
01829    */
01830 
01831   double  df, ddf, der, dder ;
01832   vl_index t ;
01833 
01834   /* bisection */
01835   double beta1 = 0 ;
01836   double beta2 = 1 ;
01837   double beta = 0.5 ;
01838 
01839   for (t = 0 ; t < 5 ; ++t) {
01840     df = log(beta) - log(1-beta) ;
01841     der = norm2 * beta + label * (inner - norm2*alpha) + df ;
01842     if (der >= 0) {
01843       beta2 = beta ;
01844     } else {
01845       beta1 = beta ;
01846     }
01847     beta = 0.5 * (beta1 + beta2) ;
01848   }
01849 
01850 #if 1
01851   /* a final Newton step, but not too close to the singularities */
01852   for (t = 0 ; (t < 2) & (beta > VL_EPSILON_D) & (beta < 1-VL_EPSILON_D) ; ++t) {
01853     df = log(beta) - log(1-beta) ;
01854     ddf = 1 / (beta * (1-beta)) ;
01855     der = norm2 * beta + label * (inner - norm2*alpha) + df ;
01856     dder = norm2 + ddf ;
01857     beta -= der / dder ;
01858     beta = VL_MAX(0, VL_MIN(1, beta)) ;
01859   }
01860 #endif
01861 
01862   return label * beta - alpha ;
01863 }
01864 
01865 /* ---------------------------------------------------------------- */
01866 
01871 void _vl_svm_update_statistics (VlSvm *self)
01872 {
01873   vl_size i, k ;
01874   double inner, p ;
01875 
01876   memset(&self->statistics, 0, sizeof(VlSvmStatistics)) ;
01877 
01878   self->statistics.regularizer = self->bias * self->bias ;
01879   for (i = 0; i < self->dimension; i++) {
01880     self->statistics.regularizer += self->model[i] * self->model[i] ;
01881   }
01882   self->statistics.regularizer *= self->lambda * 0.5 ;
01883 
01884   for (k = 0; k < self->numData ; k++) {
01885     p = (self->weights) ? self->weights[k] : 1.0 ;
01886     if (p <= 0) continue ;
01887     inner = self->innerProductFn(self->data, k, self->model) ;
01888     inner += self->bias * self->biasMultiplier ;
01889     self->scores[k] = inner ;
01890     self->statistics.loss += p * self->lossFn(inner, self->labels[k]) ;
01891     if (self->solver == VlSvmSolverSdca) {
01892 
01893       self->statistics.dualLoss -= p * self->conjugateLossFn(- self->alpha[k] / p, self->labels[k]) ;
01894     }
01895   }
01896 
01897   self->statistics.loss /= self->numData ;
01898   self->statistics.objective = self->statistics.regularizer + self->statistics.loss ;
01899 
01900   if (self->solver == VlSvmSolverSdca) {
01901     self->statistics.dualLoss /= self->numData ;
01902     self->statistics.dualObjective = - self->statistics.regularizer + self->statistics.dualLoss ;
01903     self->statistics.dualityGap = self->statistics.objective - self->statistics.dualObjective ;
01904   }
01905 }
01906 
01907 /* ---------------------------------------------------------------- */
01908 /*                                       Evaluate rather than solve */
01909 /* ---------------------------------------------------------------- */
01910 
01911 void _vl_svm_evaluate (VlSvm *self)
01912 {
01913   double startTime = vl_get_cpu_time () ;
01914 
01915   _vl_svm_update_statistics (self) ;
01916 
01917   self->statistics.elapsedTime = vl_get_cpu_time() - startTime ;
01918   self->statistics.iteration = 0 ;
01919   self->statistics.epoch = 0 ;
01920   self->statistics.status = VlSvmStatusConverged ;
01921 
01922   if (self->diagnosticFn) {
01923     self->diagnosticFn(self, self->diagnosticFnData) ;
01924   }
01925 }
01926 
01927 /* ---------------------------------------------------------------- */
01928 /*                         Stochastic Dual Coordinate Ascent Solver */
01929 /* ---------------------------------------------------------------- */
01930 
01931 void _vl_svm_sdca_train (VlSvm *self)
01932 {
01933   double * norm2 ;
01934   vl_index * permutation ;
01935   vl_uindex i, t  ;
01936   double inner, delta, multiplier, p ;
01937 
01938   double startTime = vl_get_cpu_time () ;
01939   VlRand * rand = vl_get_rand() ;
01940 
01941   norm2 = (double*) vl_calloc(self->numData, sizeof(double));
01942   permutation = vl_calloc(self->numData, sizeof(vl_index)) ;
01943 
01944   {
01945     double * buffer = vl_calloc(self->dimension, sizeof(double)) ;
01946     for (i = 0 ; i < (unsigned)self->numData; i++) {
01947       double n2 ;
01948       permutation [i] = i ;
01949       memset(buffer, 0, self->dimension * sizeof(double)) ;
01950       self->accumulateFn (self->data, i, buffer, 1) ;
01951       n2 = self->innerProductFn (self->data, i, buffer) ;
01952       n2 += self->biasMultiplier * self->biasMultiplier ;
01953       norm2[i] = n2 / (self->lambda * self->numData) ;
01954     }
01955     vl_free(buffer) ;
01956   }
01957 
01958   for (t = 0 ; 1 ; ++t) {
01959 
01960     if (t % self->numData == 0) {
01961       /* once a new epoch is reached (all data have been visited),
01962        change permutation */
01963       vl_rand_permute_indexes(rand, permutation, self->numData) ;
01964     }
01965 
01966     /* pick a sample and compute update */
01967     i = permutation[t % self->numData] ;
01968     p = (self->weights) ? self->weights[i] : 1.0 ;
01969     if (p > 0) {
01970       inner = self->innerProductFn(self->data, i, self->model) ;
01971       inner += self->bias * self->biasMultiplier ;
01972       delta = p * self->dcaUpdateFn(self->alpha[i] / p, inner, p * norm2[i], self->labels[i]) ;
01973     } else {
01974       delta = 0 ;
01975     }
01976 
01977     /* apply update */
01978     if (delta != 0) {
01979       self->alpha[i] += delta ;
01980       multiplier = delta / (self->numData * self->lambda) ;
01981       self->accumulateFn(self->data,i,self->model,multiplier) ;
01982       self->bias += self->biasMultiplier * multiplier;
01983     }
01984 
01985     /* call diagnostic occasionally */
01986     if ((t + 1) % self->diagnosticFrequency == 0 || t + 1 == self->maxNumIterations) {
01987       _vl_svm_update_statistics (self) ;
01988       self->statistics.elapsedTime = vl_get_cpu_time() - startTime ;
01989       self->statistics.iteration = t ;
01990       self->statistics.epoch = t / self->numData ;
01991 
01992       self->statistics.status = VlSvmStatusTraining ;
01993       if (self->statistics.dualityGap < self->epsilon) {
01994         self->statistics.status = VlSvmStatusConverged ;
01995       }
01996       else if (t + 1 == self->maxNumIterations) {
01997         self->statistics.status = VlSvmStatusMaxNumIterationsReached ;
01998       }
01999 
02000       if (self->diagnosticFn) {
02001         self->diagnosticFn(self, self->diagnosticFnData) ;
02002       }
02003 
02004       if (self->statistics.status != VlSvmStatusTraining) {
02005         break ;
02006       }
02007     }
02008   } /* next iteration */
02009 
02010   vl_free (norm2) ;
02011   vl_free (permutation) ;
02012 }
02013 
02014 /* ---------------------------------------------------------------- */
02015 /*                               Stochastic Gradient Descent Solver */
02016 /* ---------------------------------------------------------------- */
02017 
02018 void _vl_svm_sgd_train (VlSvm *self)
02019 {
02020   vl_index * permutation ;
02021   double * scores ;
02022   double * previousScores ;
02023   vl_uindex i, t, k ;
02024   double inner, gradient, rate, biasRate, p ;
02025   double factor = 1.0 ;
02026   double biasFactor = 1.0 ; /* to allow slower bias learning rate */
02027   vl_index t0 = VL_MAX(2, vl_ceil_d(1.0 / self->lambda)) ;
02028   //t0=2 ;
02029 
02030   double startTime = vl_get_cpu_time () ;
02031   VlRand * rand = vl_get_rand() ;
02032 
02033   permutation = vl_calloc(self->numData, sizeof(vl_index)) ;
02034   scores = vl_calloc(self->numData * 2, sizeof(double)) ;
02035   previousScores = scores + self->numData ;
02036 
02037   for (i = 0 ; i < (unsigned)self->numData; i++) {
02038     permutation [i] = i ;
02039     previousScores [i] = - VL_INFINITY_D ;
02040   }
02041 
02042   /*
02043    We store the w vector as the product fw (factor * model).
02044    We also use a different factor for the bias: biasFactor * biasMultiplier
02045    to enable a slower learning rate for the bias.
02046 
02047    Given this representation, it is easy to carry the two key operations:
02048 
02049    * Inner product: <fw,x> = f <w,x>
02050 
02051    * Model update: fp wp = fw - rate * lambda * w - rate * g
02052                          = f(1 - rate * lambda) w - rate * g
02053 
02054      Thus the update equations are:
02055 
02056                    fp = f(1 - rate * lambda), and
02057                    wp = w + rate / fp * g ;
02058 
02059    * Realization of the scaling factor. Before the statistics function
02060      is called, or training finishes, the factor (and biasFactor)
02061      are explicitly applied to the model and the bias.
02062   */
02063 
02064   for (t = 0 ; 1 ; ++t) {
02065 
02066     if (t % self->numData == 0) {
02067       /* once a new epoch is reached (all data have been visited),
02068        change permutation */
02069       vl_rand_permute_indexes(rand, permutation, self->numData) ;
02070     }
02071 
02072     /* pick a sample and compute update */
02073     i = permutation[t % self->numData] ;
02074     p = (self->weights) ? self->weights[i] : 1.0 ;
02075     p = VL_MAX(0.0, p) ; /* we assume non-negative weights, so this is just for robustness */
02076     inner = factor * self->innerProductFn(self->data, i, self->model) ;
02077     inner += biasFactor * (self->biasMultiplier * self->bias) ;
02078     gradient = p * self->lossDerivativeFn(inner, self->labels[i]) ;
02079     previousScores[i] = scores[i] ;
02080     scores[i] = inner ;
02081 
02082     /* apply update */
02083     rate = 1.0 /  (self->lambda * (t + t0)) ;
02084     biasRate = rate * self->biasLearningRate ;
02085     factor *= (1.0 - self->lambda * rate) ;
02086     biasFactor *= (1.0 - self->lambda * biasRate) ;
02087 
02088     /* debug: realize the scaling factor all the times */
02089     /*
02090     for (k = 0 ; k < self->dimension ; ++k) self->model[k] *= factor ;
02091     self->bias *= biasFactor;
02092     factor = 1.0 ;
02093     biasFactor = 1.0 ;
02094     */
02095 
02096     if (gradient != 0) {
02097       self->accumulateFn(self->data, i, self->model, - gradient * rate / factor) ;
02098       self->bias += self->biasMultiplier * (- gradient * biasRate / biasFactor) ;
02099     }
02100 
02101     /* call diagnostic occasionally */
02102     if ((t + 1) % self->diagnosticFrequency == 0 || t + 1 == self->maxNumIterations) {
02103 
02104       /* realize factor before computing statistics or completing training */
02105       for (k = 0 ; k < self->dimension ; ++k) self->model[k] *= factor ;
02106       self->bias *= biasFactor;
02107       factor = 1.0 ;
02108       biasFactor = 1.0 ;
02109 
02110       _vl_svm_update_statistics (self) ;
02111 
02112       for (k = 0 ; k < self->numData ; ++k) {
02113         double delta = scores[k] - previousScores[k] ;
02114         self->statistics.scoresVariation += delta * delta ;
02115       }
02116       self->statistics.scoresVariation = sqrt(self->statistics.scoresVariation) / self->numData ;
02117 
02118       self->statistics.elapsedTime = vl_get_cpu_time() - startTime ;
02119       self->statistics.iteration = t ;
02120       self->statistics.epoch = t / self->numData ;
02121 
02122       self->statistics.status = VlSvmStatusTraining ;
02123       if (self->statistics.scoresVariation < self->epsilon) {
02124         self->statistics.status = VlSvmStatusConverged ;
02125       }
02126       else if (t + 1 == self->maxNumIterations) {
02127         self->statistics.status = VlSvmStatusMaxNumIterationsReached ;
02128       }
02129 
02130       if (self->diagnosticFn) {
02131         self->diagnosticFn(self, self->diagnosticFnData) ;
02132       }
02133 
02134       if (self->statistics.status != VlSvmStatusTraining) {
02135         break ;
02136       }
02137     }
02138   } /* next iteration */
02139 
02140   vl_free (scores) ;
02141   vl_free (permutation) ;
02142 }
02143 
02144 /* ---------------------------------------------------------------- */
02145 /*                                                       Dispatcher */
02146 /* ---------------------------------------------------------------- */
02147 
02156 void vl_svm_train (VlSvm * self)
02157 {
02158   assert (self) ;
02159   switch (self->solver) {
02160     case VlSvmSolverSdca:
02161       _vl_svm_sdca_train(self) ;
02162       break ;
02163     case VlSvmSolverSgd:
02164       _vl_svm_sgd_train(self) ;
02165       break ;
02166     case VlSvmSolverNone:
02167       _vl_svm_evaluate(self) ;
02168       break ;
02169     default:
02170       assert(0) ;
02171   }
02172 }


libvlfeat
Author(s): Andrea Vedaldi
autogenerated on Thu Jun 6 2019 20:25:51