1#ifndef FSTCLASSIFIERLOGREG_H
2#define FSTCLASSIFIERLOGREG_H
110template<
class RETURNTYPE,
typename DATATYPE,
typename REALTYPE,
typename IDXTYPE,
typename DIMTYPE,
class SUBSET,
class DATAACCESSOR>
111class Classifier_Logistic_Regression :
public Clonable_Impl<Classifier_Logistic_Regression<RETURNTYPE,DATATYPE,REALTYPE,IDXTYPE,DIMTYPE,SUBSET,DATAACCESSOR>,Classifier<RETURNTYPE,DIMTYPE,SUBSET,DATAACCESSOR> > {
115 typedef std::shared_ptr<SUBSET>
const PSubset;
118 {
notify(
"Classifier_Logistic_Regression constructor.");}
121 void set_lambda(
const REALTYPE lambda) {
if(lambda<0.0)
throw fst_error(
"Classifier_Logistic_Regression: lambda must be >=0");
_lambda=lambda;}
140 virtual std::ostream&
print(std::ostream& os)
const override {os <<
"Classifier_Logistic_Regression(lambda=" <<
_lambda <<
", max_iter=" <<
_max_iter <<
", tol=" <<
_tol <<
")";
return os;}
156 std::vector<REALTYPE>
_W;
159 std::vector<REALTYPE>
_Z;
160 std::vector<DIMTYPE>
_y;
161 std::vector<REALTYPE>
_P;
162 std::vector<REALTYPE>
_H;
166 std::vector<REALTYPE>
_sc;
172 REALTYPE
eval_objective(
const std::vector<REALTYPE> &W,
const bool want_grad);
181template<
class RETURNTYPE,
typename DATATYPE,
typename REALTYPE,
typename IDXTYPE,
typename DIMTYPE,
class SUBSET,
class DATAACCESSOR>
184 notify(
"Classifier_Logistic_Regression::initialize().");
186 assert(da->getNoOfFeatures()>0);
187 if(da->getNoOfClasses()<2)
throw fst_error(
"Classifier_Logistic_Regression requires at least 2 classes");
194template<
class RETURNTYPE,
typename DATATYPE,
typename REALTYPE,
typename IDXTYPE,
typename DIMTYPE,
class SUBSET,
class DATAACCESSOR>
199 if(want_grad) {
_grad.assign(K*dp1,0.0);
_P.resize(N*K);}
201 for(std::size_t i=0;i<N;i++)
203 const REALTYPE *z=&
_Z[i*dp1];
205 for(std::size_t c=0;c<K;c++) {
207 const REALTYPE *w=&W[c*dp1];
208 for(std::size_t f=0;f<dp1;f++) s+=w[f]*z[f];
210 if(c==0 || s>smax) smax=s;
213 for(std::size_t c=0;c<K;c++) {
_sc[c]=std::exp(
_sc[c]-smax); sumexp+=
_sc[c];}
214 J-=std::log(
_sc[
_y[i]]/sumexp);
216 for(std::size_t c=0;c<K;c++) {
217 const REALTYPE p=
_sc[c]/sumexp;
219 const REALTYPE r=p-(c==(std::size_t)
_y[i]?1.0:0.0);
220 REALTYPE *g=&
_grad[c*dp1];
221 for(std::size_t f=0;f<dp1;f++) g[f]+=r*z[f];
225 REALTYPE penalty=0.0;
226 for(std::size_t c=0;c<K;c++)
227 for(std::size_t f=0;f<d;f++) penalty+=W[c*dp1+f]*W[c*dp1+f];
230 for(std::size_t c=0;c<K;c++)
231 for(std::size_t f=0;f<dp1;f++) {
232 _grad[c*dp1+f]/=(REALTYPE)N;
238template<
class RETURNTYPE,
typename DATATYPE,
typename REALTYPE,
typename IDXTYPE,
typename DIMTYPE,
class SUBSET,
class DATAACCESSOR>
243 for(std::size_t n=0;n<N;n++)
245 const REALTYPE *z=&
_Z[n*dp1];
246 const REALTYPE *pr=&
_P[n*K];
247 for(std::size_t c1=0;c1<K;c1++)
248 for(std::size_t c2=0;c2<=c1;c2++)
250 const REALTYPE coef=(c1==c2)?pr[c1]*(1.0-pr[c1]):-pr[c1]*pr[c2];
251 if(coef==0.0)
continue;
252 REALTYPE *hblk=&
_H[(c1*dp1)*m+c2*dp1];
253 for(std::size_t
f1=0;
f1<dp1;
f1++)
255 const REALTYPE zc=coef*z[
f1];
256 const std::size_t fend=(c1==c2)?
f1+1:dp1;
257 for(std::size_t f2=0;f2<fend;f2++) hblk[
f1*m+f2]+=zc*z[f2];
261 for(std::size_t j=0;j<m*m;j++)
_H[j]/=(REALTYPE)N;
262 for(std::size_t c=0;c<K;c++)
263 for(std::size_t f=0;f<dp1;f++)
265 const std::size_t j=c*dp1+f;
269 _H[j*m+j]+=((f<d)?
_lambda:(REALTYPE)1e-8)+extra_ridge;
273template<
class RETURNTYPE,
typename DATATYPE,
typename REALTYPE,
typename IDXTYPE,
typename DIMTYPE,
class SUBSET,
class DATAACCESSOR>
276 notify(
"Classifier_Logistic_Regression::train().");
279 assert(sub->get_frozen_mode()==
false);
280 assert(
_classes==da->getNoOfClasses());
281 assert(
_features==da->getNoOfFeatures());
282 assert(sub->get_n_raw()==da->getNoOfFeatures());
293 if(m>8192)
throw fst_error(
"Classifier_Logistic_Regression: Newton system too large (classes*(subset size+1) > 8192); use smaller subsets (e.g. a forward search bounded to a small target subset size)");
299 [
this](
const auto *pat,
const DIMTYPE c){(void)pat;
_Z.push_back(1.0);
_y.push_back(c);});
300 if(N==0)
return false;
304 _sc.resize(K>dp1?K:dp1);
307 for(
unsigned int iter=0;iter<
_max_iter;iter++)
310 for(std::size_t j=0;j<m;j++) {
const REALTYPE a=std::fabs(
_grad[j]);
if(a>gmax) gmax=a;}
320 while(!factored && ridge<1.0)
322 ridge=(ridge==0.0)?(REALTYPE)1e-6:ridge*100.0;
326 if(!factored)
return false;
335 for(
int half=0;half<60;half++)
339 if(Jtry<J && std::isfinite(Jtry)) {improved=
true;
_W.swap(
_Wtry); J=Jtry;
break;}
348template<
class RETURNTYPE,
typename DATATYPE,
typename REALTYPE,
typename IDXTYPE,
typename DIMTYPE,
class SUBSET,
class DATAACCESSOR>
351 notify(
"Classifier_Logistic_Regression::classify().");
354 assert(
_W.size()==K*dp1);
357 for(std::size_t c=0;c<K;c++)
359 const REALTYPE *w=&
_W[c*dp1];
361 for(std::size_t f=0;f<d;f++) score+=w[f]*(((REALTYPE)pattern[
_index[f]]-
_mean[f])/
_scale[f]);
362 if(c==0 || score>best) {best=score; cls=(DIMTYPE)c;}
367template<
class RETURNTYPE,
typename DATATYPE,
typename REALTYPE,
typename IDXTYPE,
typename DIMTYPE,
class SUBSET,
class DATAACCESSOR>
371 notify(
"Classifier_Logistic_Regression::classify_scores().");
374 assert(
_W.size()==K*dp1);
376 for(std::size_t c=0;c<K;c++)
378 const REALTYPE *w=&
_W[c*dp1];
380 for(std::size_t f=0;f<d;f++) score+=w[f]*(((REALTYPE)pattern[
_index[f]]-
_mean[f])/
_scale[f]);
381 scores[c]=(RETURNTYPE)score;
Implements multinomial (softmax) logistic regression classifier.
Definition classifier_logreg.hpp:111
DIMTYPE _features
raw (full) feature count, as recorded by initialize()
Definition classifier_logreg.hpp:149
REALTYPE get_lambda() const
current L2 weight penalty
Definition classifier_logreg.hpp:124
REALTYPE _tol
gradient infinity-norm stopping tolerance
Definition classifier_logreg.hpp:145
DIMTYPE _subfeatures
d = current subset size
Definition classifier_logreg.hpp:152
DIMTYPE get_d() const
current subset dimensionality, as recorded by the last train()
Definition classifier_logreg.hpp:138
virtual bool classify(DIMTYPE &cls, const PPattern &pattern) override
Definition classifier_logreg.hpp:349
virtual bool train(const PDataAccessor da, const PSubset sub) override
learns from designated training part of data
Definition classifier_logreg.hpp:274
std::vector< REALTYPE > _mean
standardization shift per subset position
Definition classifier_logreg.hpp:154
void set_lambda(const REALTYPE lambda)
sets the L2 weight penalty (must be >=0); default 0.01
Definition classifier_logreg.hpp:121
std::vector< REALTYPE > _Z
N x (d+1) standardized training data, last column fixed 1 (bias coordinate).
Definition classifier_logreg.hpp:159
std::vector< DIMTYPE > _y
N training labels.
Definition classifier_logreg.hpp:160
std::vector< REALTYPE > _step
Newton step solved from the Hessian system (see assemble_hessian()).
Definition classifier_logreg.hpp:164
std::vector< REALTYPE > _H
Newton system, m x m, m=classes*(d+1) (lower triangle used).
Definition classifier_logreg.hpp:162
void set_max_iter(const unsigned int max_iter)
sets the damped-Newton iteration cap (must be >=1); default 100
Definition classifier_logreg.hpp:122
DIMTYPE _classes
number of classes, as recorded by initialize()
Definition classifier_logreg.hpp:148
std::vector< REALTYPE > _W
classes x (d+1) row-major; column d = bias
Definition classifier_logreg.hpp:156
DATAACCESSOR::PPattern PPattern
one data sample as exposed by DATAACCESSOR (a raw pointer to its feature vector)
Definition classifier_logreg.hpp:116
Clonable_Impl< Classifier_Logistic_Regression, Classifier< RETURNTYPE, DIMTYPE, SUBSET, DATAACCESSOR > > parent_impl
implements clone() via the (implicit, member-wise) copy-constructor - all members are value-semantic
Definition classifier_logreg.hpp:113
REALTYPE eval_objective(const std::vector< REALTYPE > &W, const bool want_grad)
Definition classifier_logreg.hpp:195
REALTYPE _lambda
L2 weight penalty (biases unpenalized).
Definition classifier_logreg.hpp:143
std::shared_ptr< SUBSET > const PSubset
shared pointer to the (fixed, non-reassignable) feature subset being trained/classified on
Definition classifier_logreg.hpp:115
virtual bool classify_scores(std::vector< RETURNTYPE > &scores, const PPattern &pattern) override
Definition classifier_logreg.hpp:368
std::shared_ptr< DATAACCESSOR > PDataAccessor
shared pointer to the data accessor supplying train/test blocks
Definition classifier_logreg.hpp:114
std::vector< REALTYPE > _scale
standardization scale per subset position (1 for constant features)
Definition classifier_logreg.hpp:155
REALTYPE get_tolerance() const
current gradient infinity-norm stopping tolerance
Definition classifier_logreg.hpp:126
std::vector< REALTYPE > _Wtry
trial weights during step-halving line search in train()
Definition classifier_logreg.hpp:165
DIMTYPE get_n() const
raw (full) feature count, as recorded by initialize()
Definition classifier_logreg.hpp:137
void initialize(const PDataAccessor da)
Records data shape (classes, raw feature count) and resets to "no model yet". Must be called before t...
Definition classifier_logreg.hpp:182
void set_tolerance(const REALTYPE tol)
sets the gradient infinity-norm stopping tolerance (must be >0); default 1e-6
Definition classifier_logreg.hpp:123
unsigned int _max_iter
Newton iteration cap.
Definition classifier_logreg.hpp:144
std::vector< REALTYPE > _grad
objective gradient at the current Newton iterate (see eval_objective())
Definition classifier_logreg.hpp:163
virtual std::ostream & print(std::ostream &os) const override
writes a human-readable identification of the object; base default writes nothing
Definition classifier_logreg.hpp:140
void assemble_hessian(const std::size_t m, const REALTYPE extra_ridge)
Definition classifier_logreg.hpp:239
unsigned int get_max_iter() const
current Newton iteration cap
Definition classifier_logreg.hpp:125
std::vector< DIMTYPE > _index
subset position -> raw feature index (first d entries valid)
Definition classifier_logreg.hpp:153
std::vector< REALTYPE > _P
N x classes posterior cache for Hessian assembly.
Definition classifier_logreg.hpp:161
std::vector< REALTYPE > _sc
per-class softmax score scratch used by eval_objective() (sized max(classes,d+1))
Definition classifier_logreg.hpp:166
CRTP mixin implementing the Clonable protocol for a concrete class.
Definition clonable.hpp:184
FST4 specific error passing class.
Definition error.hpp:61
Defines interface for classifier implementations.
FST4 specific error passing class.
The Feature Selection Toolbox 4 library: every library component – data access, criteria and classifi...
Definition data_accessor.hpp:80
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
bool cholesky_factor(std::vector< REALTYPE > &A, const std::size_t m)
Definition dense_train_tools.hpp:133
void cholesky_solve(const std::vector< REALTYPE > &A, const std::size_t m, const REALTYPE *rhs, const bool negate_rhs, REALTYPE *out)
Definition dense_train_tools.hpp:156
@ f1
classification, two-class data: F1 of the positive class, which is Metric_Spec::f1_positive (class in...
Definition wrapper_metrics.hpp:63