1#ifndef FSTCLASSIFIERRBFSVM_H
2#define FSTCLASSIFIERRBFSVM_H
127template<
class RETURNTYPE,
typename DATATYPE,
typename REALTYPE,
typename IDXTYPE,
typename DIMTYPE,
class SUBSET,
class DATAACCESSOR>
128class Classifier_RBF_SVM :
public Clonable_Impl<Classifier_RBF_SVM<RETURNTYPE,DATATYPE,REALTYPE,IDXTYPE,DIMTYPE,SUBSET,DATAACCESSOR>,Classifier<RETURNTYPE,DIMTYPE,SUBSET,DATAACCESSOR> > {
163 const double lgC_min=-5,
const double lgC_max=9,
const double lggamma_min=-15,
const double lggamma_max=3, std::ostream& os=std::cout);
189 virtual std::ostream&
print(std::ostream& os)
const override
191 os <<
"Classifier_RBF_SVM(C=" <<
_C <<
", gamma=";
193 os <<
", loss=" << (
_l2loss?
"l2":
"l1") <<
", max_iter=" <<
_max_iter <<
", tol=" <<
_tol <<
")";
213 std::vector<REALTYPE>
_sv;
217 std::vector<REALTYPE>
_Z;
218 std::vector<DIMTYPE>
_y;
220 std::vector<REALTYPE>
_s;
221 std::vector<REALTYPE>
_K;
238 for(std::size_t f=0;f<(std::size_t)
_subfeatures;f++) {
const REALTYPE dd=a[f]-b[f]; dist2+=dd*dd;}
239 return std::exp(-
_gamma_eff*dist2)+(REALTYPE)1.0;
246 const REALTYPE*
kernel_row(
const std::size_t i,
const std::size_t N)
248 if(!
_K.empty())
return &
_K[i*N];
260 void solve_dual(REALTYPE *beta,
const DIMTYPE positive_class);
264template<
class RETURNTYPE,
typename DATATYPE,
typename REALTYPE,
typename IDXTYPE,
typename DIMTYPE,
class SUBSET,
class DATAACCESSOR>
267 notify(
"Classifier_RBF_SVM::initialize().");
269 assert(da->getNoOfFeatures()>0);
270 if(da->getNoOfClasses()<2)
throw fst_error(
"Classifier_RBF_SVM requires at least 2 classes");
277template<
class RETURNTYPE,
typename DATATYPE,
typename REALTYPE,
typename IDXTYPE,
typename DIMTYPE,
class SUBSET,
class DATAACCESSOR>
280 RETURNTYPE val, result=0.0, cnt=0.0;
281 for(
bool b=da->getFirstSplit();b==
true;b=da->getNextSplit()) {
282 if(!
train(da,sub))
return false;
283 if(!this->
test(val,da))
return false;
287 mean=result/(RETURNTYPE)cnt;
291template<
class RETURNTYPE,
typename DATATYPE,
typename REALTYPE,
typename IDXTYPE,
typename DIMTYPE,
class SUBSET,
class DATAACCESSOR>
292bool Classifier_RBF_SVM<RETURNTYPE,DATATYPE,REALTYPE,IDXTYPE,DIMTYPE,SUBSET,DATAACCESSOR>::optimize_parameters(
const PDataAccessor da,
const PSubset sub,
const int max_points,
const int max_throws,
const double lgC_min,
const double lgC_max,
const double lggamma_min,
const double lggamma_max, std::ostream& os)
297 assert(sub->get_d_raw()>0);
298 assert(max_points>0);
299 assert(max_throws>0);
300 assert(lgC_max>lgC_min);
301 assert(lggamma_max>lggamma_min);
302 const double lgCrange=lgC_max-lgC_min;
303 const double lggammarange=lggamma_max-lggamma_min;
304 struct PSet {RETURNTYPE val;
double Cpar, gamma;};
305 std::vector<PSet> paramlist;
307 RETURNTYPE val, maxval, firstval;
314 std::ostringstream sos;
315 sos <<
"RBF SVM before optimization: accuracy=" << val <<
", C=" <<
_C <<
", gamma=" <<
_gamma_eff << std::endl;
318 paramlist.push_back(PSet{val,(double)
_C,(
double)
_gamma_eff});
319 PSet tmpset{0.0,0.0,0.0}, bestset{0.0,0.0,0.0};
320 for(
int i=0;i<max_points;i++)
322 double maxdistmin=0.0;
323 for(
int j=0;j<max_throws;j++)
326 tmpset.Cpar =std::exp(lgC_min+(((
double)
fst_rand()*(
double)(lgC_max-lgC_min))/(
double)
FST_RAND_MAX));
327 tmpset.gamma=std::exp(lggamma_min+(((
double)
fst_rand()*(
double)(lggamma_max-lggamma_min))/(
double)
FST_RAND_MAX));
329 for(
const PSet &ps : paramlist)
331 const double dC=(std::log(tmpset.Cpar)-std::log(ps.Cpar))/lgCrange;
332 const double dG=(std::log(tmpset.gamma)-std::log(ps.gamma))/lggammarange;
333 const double dist=std::sqrt(dC*dC+dG*dG);
337 if(distmin<0 || dist*ps.val<distmin) distmin=dist*ps.val;
339 assert(distmin>=0.0);
340 if(distmin>maxdistmin) {maxdistmin=distmin; bestset=tmpset;}
347 paramlist.push_back(bestset);
349 std::ostringstream sos;
351 if(val>maxval) {maxval=val; sos <<
"BEST accuracy=";}
else sos <<
"test accuracy=";
352 sos << bestset.val <<
", C=" <<
_C <<
", gamma=" <<
_gamma << std::endl;
357 assert(!paramlist.empty());
358 bestset=paramlist.front();
359 for(
const PSet &ps : paramlist)
if(ps.val>bestset.val) bestset=ps;
363 std::ostringstream sos;
364 sos <<
"RBF SVM after optimization: accuracy=" << bestset.val <<
", C=" <<
_C <<
", gamma=" <<
_gamma << std::endl;
365 sos <<
"Accuracy difference=" << bestset.val-firstval << std::endl << std::endl;
371template<
class RETURNTYPE,
typename DATATYPE,
typename REALTYPE,
typename IDXTYPE,
typename DIMTYPE,
class SUBSET,
class DATAACCESSOR>
377 const std::size_t N=
_y.size();
378 const REALTYPE U=
_l2loss?std::numeric_limits<REALTYPE>::infinity():
_C;
379 const REALTYPE Dii=
_l2loss?(REALTYPE)1.0/((REALTYPE)2.0*
_C):(REALTYPE)0.0;
380 const REALTYPE Qii=(REALTYPE)2.0+Dii;
384 for(
unsigned int sweep=0;sweep<
_max_iter;sweep++)
387 for(std::size_t i=0;i<N;i++)
389 const REALTYPE yi=(
_y[i]==positive_class)?(REALTYPE)1.0:(REALTYPE)-1.0;
390 const REALTYPE g=yi*
_s[i]-(REALTYPE)1.0+Dii*
_alpha[i];
393 if(
_alpha[i]<=0.0 && g>0.0) pg=0.0;
394 else if(
_alpha[i]>=U && g<0.0) pg=0.0;
395 const REALTYPE apg=std::fabs(pg);
396 if(apg>pg_max) pg_max=apg;
399 const REALTYPE aold=
_alpha[i];
400 REALTYPE anew=aold-g/Qii;
401 if(anew<0.0) anew=0.0;
else if(anew>U) anew=U;
402 const REALTYPE step=(anew-aold)*yi;
407 for(std::size_t k=0;k<N;k++)
_s[k]+=step*row[k];
411 if(pg_max<
_tol)
break;
413 for(std::size_t i=0;i<N;i++) beta[i]=
_alpha[i]*((
_y[i]==positive_class)?(REALTYPE)1.0:(REALTYPE)-1.0);
416template<
class RETURNTYPE,
typename DATATYPE,
typename REALTYPE,
typename IDXTYPE,
typename DIMTYPE,
class SUBSET,
class DATAACCESSOR>
419 notify(
"Classifier_RBF_SVM::train().");
422 assert(
_classes==da->getNoOfClasses());
423 assert(
_features==da->getNoOfFeatures());
424 assert(sub->get_n_raw()==da->getNoOfFeatures());
437 [
this](
const auto *pat,
const DIMTYPE c){(void)pat;
_y.push_back(c);});
438 if(N==0)
return false;
446 for(std::size_t a=0;a<N;a++)
448 _K[a*N+a]=(REALTYPE)2.0;
453 else {
_K.clear();
_krow.resize(N);}
463 std::vector<std::size_t> keep;
464 for(std::size_t n=0;n<N;n++)
467 for(DIMTYPE m=0;m<M && !used;m++)
if(
_beta_full[(std::size_t)m*N+n]!=0.0) used=
true;
468 if(used) keep.push_back(n);
471 _sv.resize(keep.size()*d);
472 _beta.resize((std::size_t)M*keep.size());
473 for(std::size_t k=0;k<keep.size();k++)
475 for(std::size_t f=0;f<d;f++)
_sv[k*d+f]=
_Z[keep[k]*d+f];
476 for(DIMTYPE m=0;m<M;m++)
_beta[(std::size_t)m*keep.size()+k]=
_beta_full[(std::size_t)m*N+keep[k]];
481template<
class RETURNTYPE,
typename DATATYPE,
typename REALTYPE,
typename IDXTYPE,
typename DIMTYPE,
class SUBSET,
class DATAACCESSOR>
492 for(DIMTYPE m=0;m<M;m++)
494 const REALTYPE *b=&
_beta[(std::size_t)m*nsv];
496 for(std::size_t k=0;k<nsv;k++) dec+=b[k]*
_cs_kv[k];
497 scores[m]=(RETURNTYPE)dec;
499 if(
_classes==2) scores[1]=-scores[0];
503template<
class RETURNTYPE,
typename DATATYPE,
typename REALTYPE,
typename IDXTYPE,
typename DIMTYPE,
class SUBSET,
class DATAACCESSOR>
Dependency-free RBF kernel SVM trained by kernel dual coordinate descent (implemented from scratch,...
Definition classifier_rbf_svm.hpp:128
std::vector< REALTYPE > _beta
models x sv_count dual coefficients alpha_i*y_i; two-class data holds ONE model
Definition classifier_rbf_svm.hpp:214
void solve_dual(REALTYPE *beta, const DIMTYPE positive_class)
One one-vs-rest kernel dual coordinate-descent run: patterns of class positive_class are the +1 side,...
Definition classifier_rbf_svm.hpp:372
std::vector< REALTYPE > _sv
sv_count x d standardized support-vector values
Definition classifier_rbf_svm.hpp:213
void initialize(const PDataAccessor da)
records data shape, allocates the index buffer
Definition classifier_rbf_svm.hpp:265
DIMTYPE _classes
class count, set by initialize()
Definition classifier_rbf_svm.hpp:205
bool mean_cv_accuracy(const PDataAccessor da, const PSubset sub, RETURNTYPE &mean)
train+test over the accessor's split loop (optimize_parameters' evaluation)
Definition classifier_rbf_svm.hpp:278
Clonable_Impl< Classifier_RBF_SVM, parent > parent_impl
implements clone() via the (implicit, member-wise) copy-constructor – all members are value-semantic
Definition classifier_rbf_svm.hpp:131
void set_l2_loss(const bool l2)
false = hinge (C-SVC correspondence, default), true = squared hinge
Definition classifier_rbf_svm.hpp:141
DIMTYPE _subfeatures
d = current subset size
Definition classifier_rbf_svm.hpp:207
std::vector< REALTYPE > _scale
standardization scale per subset position (1 for constant features)
Definition classifier_rbf_svm.hpp:210
static constexpr std::size_t KERNEL_BUDGET_ENTRIES
kernel-matrix memory budget in entries (512 MB of double); above it rows are recomputed on demand
Definition classifier_rbf_svm.hpp:229
std::vector< REALTYPE > _beta_full
models x N pre-compaction dual coefficients (solve_dual() output before the support-vector compaction...
Definition classifier_rbf_svm.hpp:226
REALTYPE get_parameter_C() const
returns the configured C
Definition classifier_rbf_svm.hpp:144
REALTYPE _C
regularization parameter, see set_parameter_C()
Definition classifier_rbf_svm.hpp:198
bool optimize_parameters(const PDataAccessor da, const PSubset sub, const int max_points=100, const int max_throws=100, const double lgC_min=-5, const double lgC_max=9, const double lggamma_min=-15, const double lggamma_max=3, std::ostream &os=std::cout)
Definition classifier_rbf_svm.hpp:292
REALTYPE kernel_value(const REALTYPE *a, const REALTYPE *b) const
The penalized-bias RBF kernel K'(a,b) = exp(-gamma_eff*||a-b||^2) + 1 over the current _subfeatures s...
Definition classifier_rbf_svm.hpp:235
bool _l2loss
false = hinge loss (default), true = squared hinge
Definition classifier_rbf_svm.hpp:200
DATAACCESSOR::PPattern PPattern
one data sample as exposed by DATAACCESSOR
Definition classifier_rbf_svm.hpp:134
std::vector< DIMTYPE > _index
subset position -> raw feature index (first d entries valid)
Definition classifier_rbf_svm.hpp:208
std::vector< REALTYPE > _cs_x
classify_scores() per-pattern scratch: the standardized query pattern (kept as a member to avoid per-...
Definition classifier_rbf_svm.hpp:223
virtual bool classify(DIMTYPE &cls, const PPattern &pattern) override
Definition classifier_rbf_svm.hpp:504
std::shared_ptr< DATAACCESSOR > PDataAccessor
shared pointer to the data accessor supplying train/test blocks
Definition classifier_rbf_svm.hpp:132
std::vector< RETURNTYPE > _cs_sc
classify() score scratch
Definition classifier_rbf_svm.hpp:225
DIMTYPE _features
raw (full, unnarrowed) feature count, set by initialize()
Definition classifier_rbf_svm.hpp:206
REALTYPE _tol
max |projected gradient| sweep-stopping threshold
Definition classifier_rbf_svm.hpp:202
virtual bool train(const PDataAccessor da, const PSubset sub) override
Trains the RBF-kernel SVM: buffers the subset index, standardizes the design (dense_train_tools....
Definition classifier_rbf_svm.hpp:417
void set_tolerance(const REALTYPE t)
max |projected gradient| sweep-stopping threshold; default 0.1
Definition classifier_rbf_svm.hpp:143
virtual std::ostream & print(std::ostream &os) const override
writes a human-readable identification of the object; base default writes nothing
Definition classifier_rbf_svm.hpp:189
std::vector< REALTYPE > _K
N x N kernel matrix K' (only when within budget, else empty – see KERNEL_BUDGET_ENTRIES).
Definition classifier_rbf_svm.hpp:221
unsigned int _max_iter
cap on full coordinate sweeps in solve_dual()
Definition classifier_rbf_svm.hpp:201
const REALTYPE * kernel_row(const std::size_t i, const std::size_t N)
Row i of the N x N kernel matrix over the N training patterns in _Z. When _K was precomputed (the wit...
Definition classifier_rbf_svm.hpp:246
std::vector< REALTYPE > _mean
standardization shift per subset position
Definition classifier_rbf_svm.hpp:209
REALTYPE _gamma_eff
gamma actually used by the trained model (resolves _gamma's 0=auto to 1/d)
Definition classifier_rbf_svm.hpp:211
std::vector< REALTYPE > _alpha
N dual variables of the model currently being trained (solve_dual() scratch).
Definition classifier_rbf_svm.hpp:219
std::vector< REALTYPE > _krow
kernel-row scratch for the above-budget mode (filled by kernel_row())
Definition classifier_rbf_svm.hpp:222
std::shared_ptr< SUBSET > PSubset
shared pointer to the feature subset being trained/evaluated
Definition classifier_rbf_svm.hpp:133
std::vector< REALTYPE > _cs_kv
classify_scores() per-pattern scratch: kernel value against each support vector
Definition classifier_rbf_svm.hpp:224
void set_parameter_gamma(const REALTYPE g)
RBF width on standardized features; 0 = auto (1/d), which is the default.
Definition classifier_rbf_svm.hpp:140
DIMTYPE model_count() const
number of one-vs-rest models actually trained: 1 for two-class data (the single model scores both sid...
Definition classifier_rbf_svm.hpp:261
void set_parameter_C(const REALTYPE c)
sets the SVM regularization parameter C (box constraint upper bound U under L1-loss); default 1
Definition classifier_rbf_svm.hpp:139
std::vector< REALTYPE > _s
N maintained margin sums s_k = sum_j alpha_j y_j K'_jk.
Definition classifier_rbf_svm.hpp:220
std::vector< REALTYPE > _Z
N x d standardized design (no bias coordinate — the +1 kernel offset carries it).
Definition classifier_rbf_svm.hpp:217
void set_max_iter(const unsigned int mi)
cap on full coordinate sweeps; default 1000
Definition classifier_rbf_svm.hpp:142
std::vector< DIMTYPE > _y
N training labels.
Definition classifier_rbf_svm.hpp:218
Classifier< RETURNTYPE, DIMTYPE, SUBSET, DATAACCESSOR > parent
the immediate abstract base
Definition classifier_rbf_svm.hpp:130
IDXTYPE _sv_count
support vectors kept (nonzero dual coefficient in ANY model)
Definition classifier_rbf_svm.hpp:212
virtual bool classify_scores(std::vector< RETURNTYPE > &scores, const PPattern &pattern) override
Definition classifier_rbf_svm.hpp:482
REALTYPE _gamma
configured RBF gamma; 0 = auto: 1/d per train() (the effective value actually used is _gamma_eff)
Definition classifier_rbf_svm.hpp:199
REALTYPE get_parameter_gamma() const
the configured value (0 = auto 1/d until set explicitly)
Definition classifier_rbf_svm.hpp:145
abstract class, defines interface for classifier implementations (mainly to be used in wrappers)
Definition classifier.hpp:97
virtual bool test(RETURNTYPE &result, const PDataAccessor da)
Definition classifier.hpp:153
CRTP mixin implementing the Clonable protocol for a concrete class.
Definition clonable.hpp:184
FST4 specific error passing class.
Definition error.hpp:61
static void print(std::ostream &os, std::ostringstream &sos)
Writes sos's buffered content to os, serializing concurrent writers under FST_THREADED via a shared m...
Definition global.hpp:86
Defines interface for classifier implementations.
Defines interface for classes that may need to get cloned.
FST4 specific error passing class.
FST4-owned pseudo-random number generator (UCRT-compatible LCG), replacing platform-specific std::ran...
The Feature Selection Toolbox 4 library: every library component – data access, criteria and classifi...
Definition data_accessor.hpp:80
int fst_rand()
Returns the next pseudo-random draw in 0..FST_RAND_MAX; use instead of std::rand().
Definition fst_rand.hpp:93
const int FST_RAND_MAX
Maximum value fst_rand() can return; use instead of the libc macro RAND_MAX.
Definition fst_rand.hpp:101
void notify(const std::string msg)
Prints msg followed by a newline via syncout::print(); a no-op unless the preprocessor macro DEBUG is...
Definition global.hpp:112
std::size_t standardize_design(const std::shared_ptr< DATAACCESSOR > &da, const DIMTYPE classes, const std::size_t d, const std::size_t zstride, const std::vector< DIMTYPE > &index, std::vector< REALTYPE > &Z, std::vector< REALTYPE > &mean, std::vector< REALTYPE > &scale, AFTERPATTERN after_pattern)
Definition dense_train_tools.hpp:84