From 9053a8f01c9f0fbaaf1df4136bc10532e2cda922 Mon Sep 17 00:00:00 2001 From: Sergey Lisitsyn Date: Sat, 4 Mar 2017 01:34:09 +0300 Subject: [PATCH] Use weight vector *only* through getters/setters --- src/shogun/classifier/AveragedPerceptron.cpp | 6 +++-- .../FeatureBlockLogisticRegression.cpp | 6 +++-- src/shogun/classifier/LDA.cpp | 4 ++- src/shogun/classifier/Perceptron.cpp | 7 +++-- src/shogun/classifier/svm/LibLinear.cpp | 18 ++++++++----- src/shogun/classifier/svm/LibLinear.h | 7 ++--- src/shogun/classifier/svm/SGDQN.cpp | 4 ++- src/shogun/classifier/svm/SVMOcas.cpp | 26 +++++++++---------- src/shogun/classifier/svm/SVMOcas.h | 2 ++ src/shogun/classifier/svm/SVMSGD.cpp | 4 ++- src/shogun/latent/LatentSOSVM.cpp | 3 +-- src/shogun/latent/LatentSVM.cpp | 4 +-- src/shogun/machine/LinearLatentMachine.cpp | 4 ++- src/shogun/machine/LinearMachine.cpp | 4 +-- src/shogun/machine/LinearMachine.h | 5 +++- .../regression/LeastAngleRegression.cpp | 2 +- src/shogun/regression/LeastAngleRegression.h | 2 ++ .../regression/svr/LibLinearRegression.cpp | 9 ++++--- .../regression/svr/LibLinearRegression.h | 2 +- .../transfer/multitask/LibLinearMTL.cpp | 3 ++- 20 files changed, 77 insertions(+), 45 deletions(-) diff --git a/src/shogun/classifier/AveragedPerceptron.cpp b/src/shogun/classifier/AveragedPerceptron.cpp index 0762b74eb6d..35d89daa710 100644 --- a/src/shogun/classifier/AveragedPerceptron.cpp +++ b/src/shogun/classifier/AveragedPerceptron.cpp @@ -50,7 +50,7 @@ bool CAveragedPerceptron::train_machine(CFeatures* data) int32_t num_vec=features->get_num_vectors(); ASSERT(num_vec==train_labels.vlen) - w=SGVector(num_feat); + SGVector w(num_feat); float64_t* tmp_w=SG_MALLOC(float64_t, num_feat); float64_t* output=SG_MALLOC(float64_t, num_vec); @@ -71,7 +71,7 @@ bool CAveragedPerceptron::train_machine(CFeatures* data) for (int32_t i=0; idense_dot(i, w.vector, w.vlen) + bias; if (CMath::sign(output[i]) != train_labels.vector[i]) { @@ -102,5 +102,7 @@ bool CAveragedPerceptron::train_machine(CFeatures* data) SG_FREE(output); SG_FREE(tmp_w); + set_w(w); + return converged; } diff --git a/src/shogun/classifier/FeatureBlockLogisticRegression.cpp b/src/shogun/classifier/FeatureBlockLogisticRegression.cpp index d665f1169b9..dd3aa8cdd22 100644 --- a/src/shogun/classifier/FeatureBlockLogisticRegression.cpp +++ b/src/shogun/classifier/FeatureBlockLogisticRegression.cpp @@ -191,7 +191,7 @@ bool CFeatureBlockLogisticRegression::train_machine(CFeatures* data) new_w[i] = result.w[i]; set_bias(result.c[0]); - w = new_w; + set_w(new_w); } break; case TREE: @@ -221,7 +221,7 @@ bool CFeatureBlockLogisticRegression::train_machine(CFeatures* data) set_bias(result.c[0]); - w = new_w; + set_w(new_w); } break; default: @@ -233,6 +233,7 @@ bool CFeatureBlockLogisticRegression::train_machine(CFeatures* data) float64_t CFeatureBlockLogisticRegression::apply_one(int32_t vec_idx) { + SGVector w = get_w(); return CMath::exp(-(features->dense_dot(vec_idx, w.vector, w.vlen) + bias)); } @@ -250,6 +251,7 @@ SGVector CFeatureBlockLogisticRegression::apply_get_outputs(CFeatures return SGVector(); int32_t num=features->get_num_vectors(); + SGVector w = get_w(); ASSERT(num>0) ASSERT(w.vlen==features->get_dim_feature_space()) diff --git a/src/shogun/classifier/LDA.cpp b/src/shogun/classifier/LDA.cpp index 8120d00e595..6c2969ee1c5 100644 --- a/src/shogun/classifier/LDA.cpp +++ b/src/shogun/classifier/LDA.cpp @@ -251,12 +251,14 @@ bool CLDA::train_machine_templated(SGVector train_labels, CFeatures *da bias=bias*(-1); } - w=SGVector(num_feat); + SGVector w(num_feat); w.zero(); //copy w_st into w for(i = 0; i < w.size(); ++i) w[i] = (float64_t) w_st[i]; + set_w(w); + return true; } diff --git a/src/shogun/classifier/Perceptron.cpp b/src/shogun/classifier/Perceptron.cpp index 17002907d3a..07cc289e5ab 100644 --- a/src/shogun/classifier/Perceptron.cpp +++ b/src/shogun/classifier/Perceptron.cpp @@ -54,10 +54,11 @@ bool CPerceptron::train_machine(CFeatures* data) ASSERT(num_vec==train_labels.vlen) float64_t* output=SG_MALLOC(float64_t, num_vec); + SGVector w = get_w(); if (m_initialize_hyperplane) { + w = SGVector(num_feat); //start with uniform w, bias=0 - w=SGVector(num_feat); bias=0; for (int32_t i=0; idense_dot(i, w.vector, w.vlen) + bias; if (CMath::sign(output[i]) != train_labels.vector[i]) { @@ -91,6 +92,8 @@ bool CPerceptron::train_machine(CFeatures* data) SG_FREE(output); + set_w(w); + return converged; } diff --git a/src/shogun/classifier/svm/LibLinear.cpp b/src/shogun/classifier/svm/LibLinear.cpp index 8c8a681abb7..d81989f62d6 100644 --- a/src/shogun/classifier/svm/LibLinear.cpp +++ b/src/shogun/classifier/svm/LibLinear.cpp @@ -117,6 +117,7 @@ bool CLibLinear::train_machine(CFeatures* data) num_vec, num_train_labels); } } + SGVector w; if (use_bias) w=SGVector(SG_MALLOC(float64_t, num_feat+1), num_feat); else @@ -188,26 +189,26 @@ bool CLibLinear::train_machine(CFeatures* data) break; } case L2R_L2LOSS_SVC_DUAL: - solve_l2r_l1l2_svc(&prob, epsilon, Cp, Cn, L2R_L2LOSS_SVC_DUAL); + solve_l2r_l1l2_svc(w, &prob, epsilon, Cp, Cn, L2R_L2LOSS_SVC_DUAL); break; case L2R_L1LOSS_SVC_DUAL: - solve_l2r_l1l2_svc(&prob, epsilon, Cp, Cn, L2R_L1LOSS_SVC_DUAL); + solve_l2r_l1l2_svc(w, &prob, epsilon, Cp, Cn, L2R_L1LOSS_SVC_DUAL); break; case L1R_L2LOSS_SVC: { //ASSUME FEATURES ARE TRANSPOSED ALREADY - solve_l1r_l2_svc(&prob, epsilon*CMath::min(pos,neg)/prob.l, Cp, Cn); + solve_l1r_l2_svc(w, &prob, epsilon*CMath::min(pos,neg)/prob.l, Cp, Cn); break; } case L1R_LR: { //ASSUME FEATURES ARE TRANSPOSED ALREADY - solve_l1r_lr(&prob, epsilon*CMath::min(pos,neg)/prob.l, Cp, Cn); + solve_l1r_lr(w, &prob, epsilon*CMath::min(pos,neg)/prob.l, Cp, Cn); break; } case L2R_LR_DUAL: { - solve_l2r_lr_dual(&prob, epsilon, Cp, Cn); + solve_l2r_lr_dual(w, &prob, epsilon, Cp, Cn); break; } default: @@ -215,6 +216,8 @@ bool CLibLinear::train_machine(CFeatures* data) break; } + set_w(w); + if (use_bias) set_bias(w[w.vlen]); else @@ -255,6 +258,7 @@ bool CLibLinear::train_machine(CFeatures* data) // To support weights for instances, use GETI(i) (i) void CLibLinear::solve_l2r_l1l2_svc( + SGVector& w, const liblinear_problem *prob, double eps, double Cp, double Cn, LIBLINEAR_SOLVER_TYPE st) { int l = prob->l; @@ -455,6 +459,7 @@ void CLibLinear::solve_l2r_l1l2_svc( // To support weights for instances, use GETI(i) (i) void CLibLinear::solve_l1r_l2_svc( + SGVector& w, liblinear_problem *prob_col, double eps, double Cp, double Cn) { int l = prob_col->l; @@ -801,6 +806,7 @@ void CLibLinear::solve_l1r_l2_svc( // To support weights for instances, use GETI(i) (i) void CLibLinear::solve_l1r_lr( + SGVector& w, const liblinear_problem *prob_col, double eps, double Cp, double Cn) { @@ -1172,7 +1178,7 @@ void CLibLinear::solve_l1r_lr( #define GETI(i) (y[i]+1) // To support weights for instances, use GETI(i) (i) -void CLibLinear::solve_l2r_lr_dual(const liblinear_problem *prob, double eps, double Cp, double Cn) +void CLibLinear::solve_l2r_lr_dual(SGVector& w, const liblinear_problem *prob, double eps, double Cp, double Cn) { int l = prob->l; int w_size = prob->n; diff --git a/src/shogun/classifier/svm/LibLinear.h b/src/shogun/classifier/svm/LibLinear.h index ab950c30061..d573bee726d 100644 --- a/src/shogun/classifier/svm/LibLinear.h +++ b/src/shogun/classifier/svm/LibLinear.h @@ -192,11 +192,12 @@ class CLibLinear : public CLinearMachine void train_one(const liblinear_problem *prob, const liblinear_parameter *param, double Cp, double Cn); void solve_l2r_l1l2_svc( + SGVector& w, const liblinear_problem *prob, double eps, double Cp, double Cn, LIBLINEAR_SOLVER_TYPE st); - void solve_l1r_l2_svc(liblinear_problem *prob_col, double eps, double Cp, double Cn); - void solve_l1r_lr(const liblinear_problem *prob_col, double eps, double Cp, double Cn); - void solve_l2r_lr_dual(const liblinear_problem *prob, double eps, double Cp, double Cn); + void solve_l1r_l2_svc(SGVector& w, liblinear_problem *prob_col, double eps, double Cp, double Cn); + void solve_l1r_lr(SGVector& w, const liblinear_problem *prob_col, double eps, double Cp, double Cn); + void solve_l2r_lr_dual(SGVector& w, const liblinear_problem *prob, double eps, double Cp, double Cn); protected: diff --git a/src/shogun/classifier/svm/SGDQN.cpp b/src/shogun/classifier/svm/SGDQN.cpp index f56f6c3790b..e005485b7cc 100644 --- a/src/shogun/classifier/svm/SGDQN.cpp +++ b/src/shogun/classifier/svm/SGDQN.cpp @@ -111,7 +111,7 @@ bool CSGDQN::train(CFeatures* data) ASSERT(num_vec==num_train_labels) ASSERT(num_vec>0) - w=SGVector(features->get_dim_feature_space()); + SGVector w(features->get_dim_feature_space()); w.zero(); float64_t lambda= 1.0/(C1*num_vec); @@ -198,6 +198,8 @@ bool CSGDQN::train(CFeatures* data) SG_FREE(result); SG_FREE(B); + set_w(w); + return true; } diff --git a/src/shogun/classifier/svm/SVMOcas.cpp b/src/shogun/classifier/svm/SVMOcas.cpp index 506c86eda3f..ee63169fdbd 100644 --- a/src/shogun/classifier/svm/SVMOcas.cpp +++ b/src/shogun/classifier/svm/SVMOcas.cpp @@ -74,18 +74,18 @@ bool CSVMOcas::train_machine(CFeatures* data) for (int32_t i=0; iget_label(i); - w=SGVector(features->get_dim_feature_space()); - w.zero(); + current_w = SGVector(features->get_dim_feature_space()); + current_w.zero(); if (num_vec!=lab.vlen || num_vec<=0) SG_ERROR("num_vec=%d num_train_labels=%d\n", num_vec, lab.vlen) SG_FREE(old_w); - old_w=SG_CALLOC(float64_t, w.vlen); + old_w=SG_CALLOC(float64_t, current_w.vlen); bias=0; old_bias=0; - tmp_a_buf=SG_CALLOC(float64_t, w.vlen); + tmp_a_buf=SG_CALLOC(float64_t, current_w.vlen); cp_value=SG_CALLOC(float64_t*, bufsize); cp_index=SG_CALLOC(uint32_t*, bufsize); cp_nz_dims=SG_CALLOC(uint32_t, bufsize); @@ -144,6 +144,8 @@ bool CSVMOcas::train_machine(CFeatures* data) SG_FREE(old_w); old_w=NULL; + set_w(current_w); + return true; } @@ -158,8 +160,8 @@ float64_t CSVMOcas::update_W( float64_t t, void* ptr ) { float64_t sq_norm_W = 0; CSVMOcas* o = (CSVMOcas*) ptr; - uint32_t nDim = (uint32_t) o->w.vlen; - float64_t* W=o->w.vector; + uint32_t nDim = (uint32_t) o->current_w.vlen; + float64_t* W = o->current_w.vector; float64_t* oldW=o->old_w; for(uint32_t j=0; j features; - uint32_t nDim=(uint32_t) o->w.vlen; + uint32_t nDim=(uint32_t) o->current_w.vlen; float64_t* y = o->lab.vector; float64_t** c_val = o->cp_value; @@ -276,12 +278,10 @@ int CSVMOcas::compute_output(float64_t *output, void* ptr) float64_t* y = o->lab.vector; - f->dense_dot_range(output, 0, nData, y, o->w.vector, o->w.vlen, 0.0); + f->dense_dot_range(output, 0, nData, y, o->current_w.vector, o->current_w.vlen, 0.0); for (int32_t i=0; ibias; - //CMath::display_vector(o->w, o->w.vlen, "w"); - //CMath::display_vector(output, nData, "out"); return 0; } @@ -299,9 +299,9 @@ void CSVMOcas::compute_W( void* ptr ) { CSVMOcas* o = (CSVMOcas*) ptr; - uint32_t nDim= (uint32_t) o->w.vlen; - CMath::swap(o->w.vector, o->old_w); - float64_t* W=o->w.vector; + uint32_t nDim= (uint32_t) o->current_w.vlen; + CMath::swap(o->current_w.vector, o->old_w); + float64_t* W=o->current_w.vector; float64_t* oldW=o->old_w; memset(W, 0, sizeof(float64_t)*nDim); float64_t old_bias=o->bias; diff --git a/src/shogun/classifier/svm/SVMOcas.h b/src/shogun/classifier/svm/SVMOcas.h index 0695d7b8c5a..838385a9406 100644 --- a/src/shogun/classifier/svm/SVMOcas.h +++ b/src/shogun/classifier/svm/SVMOcas.h @@ -212,6 +212,8 @@ class CSVMOcas : public CLinearMachine /** method */ E_SVM_TYPE method; + /** current W */ + SGVector current_w; /** old W */ float64_t* old_w; /** old bias */ diff --git a/src/shogun/classifier/svm/SVMSGD.cpp b/src/shogun/classifier/svm/SVMSGD.cpp index bbd47c79cdf..f608ff3eef0 100644 --- a/src/shogun/classifier/svm/SVMSGD.cpp +++ b/src/shogun/classifier/svm/SVMSGD.cpp @@ -88,7 +88,7 @@ bool CSVMSGD::train_machine(CFeatures* data) ASSERT(num_vec==num_train_labels) ASSERT(num_vec>0) - w=SGVector(features->get_dim_feature_space()); + SGVector w(features->get_dim_feature_space()); w.zero(); bias=0; @@ -153,6 +153,8 @@ bool CSVMSGD::train_machine(CFeatures* data) float64_t wnorm = CMath::dot(w.vector,w.vector, w.vlen); SG_INFO("Norm: %.6f, Bias: %.6f\n", wnorm, bias) + set_w(w); + return true; } diff --git a/src/shogun/latent/LatentSOSVM.cpp b/src/shogun/latent/LatentSOSVM.cpp index f6d89bc5371..01e0b303e1e 100644 --- a/src/shogun/latent/LatentSOSVM.cpp +++ b/src/shogun/latent/LatentSOSVM.cpp @@ -53,8 +53,7 @@ float64_t CLatentSOSVM::do_inner_loop(float64_t cooling_eps) so->train(); /* copy the resulting w */ - SGVector cur_w = so->get_w(); - sg_memcpy(w.vector, cur_w.vector, cur_w.vlen*sizeof(float64_t)); + set_w(so->get_w().clone()); /* get the primal objective value */ float64_t po = so->get_result().Fp; diff --git a/src/shogun/latent/LatentSVM.cpp b/src/shogun/latent/LatentSVM.cpp index 862591e5aac..c0b99d10294 100644 --- a/src/shogun/latent/LatentSVM.cpp +++ b/src/shogun/latent/LatentSVM.cpp @@ -40,6 +40,7 @@ CLatentLabels* CLatentSVM::apply_latent() if (m_model->get_num_vectors() < 1) return NULL; + SGVector w = get_w(); index_t num_examples = m_model->get_num_vectors(); CLatentLabels* hs = new CLatentLabels(num_examples); CBinaryLabels* ys = new CBinaryLabels(num_examples); @@ -73,8 +74,7 @@ float64_t CLatentSVM::do_inner_loop(float64_t cooling_eps) SG_UNREF(feats); /* copy the resulting w */ - SGVector cur_w = svm.get_w(); - sg_memcpy(w.vector, cur_w.vector, cur_w.vlen*sizeof(float64_t)); + set_w(svm.get_w().clone()); return svm.compute_primal_objective(); } diff --git a/src/shogun/machine/LinearLatentMachine.cpp b/src/shogun/machine/LinearLatentMachine.cpp index a30622f7e89..32e5b7d2a71 100644 --- a/src/shogun/machine/LinearLatentMachine.cpp +++ b/src/shogun/machine/LinearLatentMachine.cpp @@ -28,8 +28,10 @@ CLinearLatentMachine::CLinearLatentMachine(CLatentModel* model, float64_t C) set_model(model); index_t feat_dim = m_model->get_dim(); + SGVector w; w.resize_vector(feat_dim); w.zero(); + set_w(w); } CLinearLatentMachine::~CLinearLatentMachine() @@ -99,7 +101,7 @@ bool CLinearLatentMachine::train_machine(CFeatures* data) /* find argmaxH */ SG_DEBUG("Find and set h_i = argmax_h (w, psi(x_i,h))\n") - m_model->argmax_h(w); + m_model->argmax_h(get_w()); SG_DEBUG("Recalculating PSI (x,h) with the new h variables\n") m_model->cache_psi_features(); diff --git a/src/shogun/machine/LinearMachine.cpp b/src/shogun/machine/LinearMachine.cpp index 78fa85d6c0b..eee71ba8ba1 100644 --- a/src/shogun/machine/LinearMachine.cpp +++ b/src/shogun/machine/LinearMachine.cpp @@ -102,7 +102,7 @@ SGVector CLinearMachine::get_w() const void CLinearMachine::set_w(const SGVector src_w) { - w=src_w; + w = src_w; } void CLinearMachine::set_bias(float64_t b) @@ -189,4 +189,4 @@ bool CLinearMachine::train(CFeatures* data) compute_bias(data); return result; -} \ No newline at end of file +} diff --git a/src/shogun/machine/LinearMachine.h b/src/shogun/machine/LinearMachine.h index 9b9dd041dd2..a9371a18516 100644 --- a/src/shogun/machine/LinearMachine.h +++ b/src/shogun/machine/LinearMachine.h @@ -185,9 +185,12 @@ class CLinearMachine : public CMachine void init(); - protected: + private: + /** w */ SGVector w; + + protected: /** bias */ float64_t bias; /** features */ diff --git a/src/shogun/regression/LeastAngleRegression.cpp b/src/shogun/regression/LeastAngleRegression.cpp index 00573b66dea..4c83bdf86ae 100644 --- a/src/shogun/regression/LeastAngleRegression.cpp +++ b/src/shogun/regression/LeastAngleRegression.cpp @@ -355,7 +355,7 @@ bool CLeastAngleRegression::train_machine_templated(CDenseFeatures * data) } // assign default estimator - w.vlen = n_fea; + set_w(SGVector(n_fea)); switch_w(m_beta_idx.size()-1); return true; diff --git a/src/shogun/regression/LeastAngleRegression.h b/src/shogun/regression/LeastAngleRegression.h index 8b58692829b..f0ab7f1614a 100644 --- a/src/shogun/regression/LeastAngleRegression.h +++ b/src/shogun/regression/LeastAngleRegression.h @@ -124,6 +124,7 @@ class CLeastAngleRegression: public CLinearMachine void switch_w(int32_t num_variable) { + SGVector w = get_w(); REQUIRE(w.vlen > 0,"Please train the model (i.e. run the model's train() method) before updating its weights.\n") REQUIRE(size_t(num_variable) < m_beta_idx.size() && num_variable >= 0, "Cannot switch to an estimator of %d non-zero coefficients.\n", num_variable) @@ -158,6 +159,7 @@ class CLeastAngleRegression: public CLinearMachine */ SGVector get_w_for_var(int32_t num_var) { + SGVector w = get_w(); return SGVector(&m_beta_path[m_beta_idx[num_var]][0], w.vlen, false); } diff --git a/src/shogun/regression/svr/LibLinearRegression.cpp b/src/shogun/regression/svr/LibLinearRegression.cpp index 0afe96f6dd6..e85ea7369a2 100644 --- a/src/shogun/regression/svr/LibLinearRegression.cpp +++ b/src/shogun/regression/svr/LibLinearRegression.cpp @@ -76,6 +76,7 @@ bool CLibLinearRegression::train_machine(CFeatures* data) num_vec, num_train_labels); } + SGVector w; if (m_use_bias) w=SGVector(SG_MALLOC(float64_t, num_feat+1), num_feat); else @@ -113,16 +114,18 @@ bool CLibLinearRegression::train_machine(CFeatures* data) } case L2R_L1LOSS_SVR_DUAL: - solve_l2r_l1l2_svr(&prob); + solve_l2r_l1l2_svr(w, &prob); break; case L2R_L2LOSS_SVR_DUAL: - solve_l2r_l1l2_svr(&prob); + solve_l2r_l1l2_svr(w, &prob); break; default: SG_ERROR("Error: unknown regression type\n") break; } + set_w(w); + return true; } @@ -154,7 +157,7 @@ bool CLibLinearRegression::train_machine(CFeatures* data) #define GETI(i) (0) // To support weights for instances, use GETI(i) (i) -void CLibLinearRegression::solve_l2r_l1l2_svr(const liblinear_problem *prob) +void CLibLinearRegression::solve_l2r_l1l2_svr(SGVector& w, const liblinear_problem *prob) { int l = prob->l; double C = m_C; diff --git a/src/shogun/regression/svr/LibLinearRegression.h b/src/shogun/regression/svr/LibLinearRegression.h index 6c254a5cff2..5943bb8e0ee 100644 --- a/src/shogun/regression/svr/LibLinearRegression.h +++ b/src/shogun/regression/svr/LibLinearRegression.h @@ -155,7 +155,7 @@ class CLibLinearRegression : public CLinearMachine private: /** solve svr with l1 or l2 loss */ - void solve_l2r_l1l2_svr(const liblinear_problem *prob); + void solve_l2r_l1l2_svr(SGVector& w, const liblinear_problem *prob); /** init defaults */ void init_defaults(); diff --git a/src/shogun/transfer/multitask/LibLinearMTL.cpp b/src/shogun/transfer/multitask/LibLinearMTL.cpp index a9765af4f72..4b79636e172 100644 --- a/src/shogun/transfer/multitask/LibLinearMTL.cpp +++ b/src/shogun/transfer/multitask/LibLinearMTL.cpp @@ -145,9 +145,10 @@ bool CLibLinearMTL::train_machine(CFeatures* data) SG_FREE(prob.y); - w = SGVector(num_feat); + SGVector w(num_feat); for (int32_t i=0; i