SubGradientLPM.cpp

Go to the documentation of this file.
00001 /*
00002  * This program is free software; you can redistribute it and/or modify
00003  * it under the terms of the GNU General Public License as published by
00004  * the Free Software Foundation; either version 3 of the License, or
00005  * (at your option) any later version.
00006  *
00007  * Written (W) 2007-2008 Soeren Sonnenburg
00008  * Written (W) 2007-2008 Vojtech Franc
00009  * Copyright (C) 2007-2008 Fraunhofer Institute FIRST and Max-Planck-Society
00010  */
00011 
00012 #include "lib/config.h"
00013 
00014 #ifdef USE_CPLEX
00015 
00016 #include "lib/Mathematics.h"
00017 #include "lib/Signal.h"
00018 #include "lib/Time.h"
00019 #include "classifier/SparseLinearClassifier.h"
00020 #include "classifier/SubGradientLPM.h"
00021 #include "classifier/svm/qpbsvmlib.h"
00022 #include "features/SparseFeatures.h"
00023 #include "features/Labels.h"
00024 
00025 #define DEBUG_SUBGRADIENTLPM
00026 
00027 extern float64_t sparsity;
00028 float64_t lpmtim;
00029 
00030 CSubGradientLPM::CSubGradientLPM()
00031 : CSparseLinearClassifier(), C1(1), C2(1), epsilon(1e-5), qpsize(42),
00032     qpsize_max(2000), use_bias(false), delta_active(0), delta_bound(0)
00033 {
00034 }
00035 
00036 CSubGradientLPM::CSubGradientLPM(
00037     float64_t C, CSparseFeatures<float64_t>* traindat, CLabels* trainlab)
00038 : CSparseLinearClassifier(), C1(C), C2(C), epsilon(1e-5), qpsize(42),
00039     qpsize_max(2000), use_bias(false), delta_active(0), delta_bound(0)
00040 {
00041     CSparseLinearClassifier::features=traindat;
00042     CClassifier::labels=trainlab;
00043 }
00044 
00045 
00046 CSubGradientLPM::~CSubGradientLPM()
00047 {
00048     cleanup();
00049 }
00050 
00051 int32_t CSubGradientLPM::find_active(
00052     int32_t num_feat, int32_t num_vec, int32_t& num_active, int32_t& num_bound)
00053 {
00054     //delta_active=0;
00055     //num_active=0;
00056     //num_bound=0;
00057 
00058     //for (int32_t i=0; i<num_vec; i++)
00059     //{
00060     //  active[i]=0;
00061 
00062     //  //within margin/wrong side
00063     //  if (proj[i] < 1-work_epsilon)
00064     //  {
00065     //      idx_active[num_active++]=i;
00066     //      active[i]=1;
00067     //  }
00068 
00069     //  //on margin
00070     //  if (CMath::abs(proj[i]-1) <= work_epsilon)
00071     //  {
00072     //      idx_bound[num_bound++]=i;
00073     //      active[i]=2;
00074     //  }
00075 
00076     //  if (active[i]!=old_active[i])
00077     //      delta_active++;
00078     //}
00079 
00080     delta_bound=0;
00081     delta_active=0;
00082     num_active=0;
00083     num_bound=0;
00084 
00085     for (int32_t i=0; i<num_vec; i++)
00086     {
00087         active[i]=0;
00088 
00089         //within margin/wrong side
00090         if (proj[i] < 1-autoselected_epsilon)
00091         {
00092             idx_active[num_active++]=i;
00093             active[i]=1;
00094         }
00095 
00096         //on margin
00097         if (CMath::abs(proj[i]-1) <= autoselected_epsilon)
00098         {
00099             idx_bound[num_bound++]=i;
00100             active[i]=2;
00101         }
00102 
00103         if (active[i]!=old_active[i])
00104             delta_active++;
00105 
00106         if (active[i]==2 && old_active[i]==2)
00107             delta_bound++;
00108     }
00109 
00110 
00111     if (delta_active==0 && work_epsilon<=epsilon) //we converged
00112         return 0;
00113     else if (delta_active==0) //lets decrease work_epsilon
00114     {
00115         work_epsilon=CMath::min(work_epsilon/2, autoselected_epsilon);
00116         work_epsilon=CMath::max(work_epsilon, epsilon);
00117         num_bound=qpsize;
00118     }
00119 
00120     delta_bound=0;
00121     delta_active=0;
00122     num_active=0;
00123     num_bound=0;
00124 
00125     for (int32_t i=0; i<num_vec; i++)
00126     {
00127         tmp_proj[i]=CMath::abs(proj[i]-1);
00128         tmp_proj_idx[i]=i;
00129     }
00130 
00131     CMath::qsort_index(tmp_proj, tmp_proj_idx, num_vec);
00132 
00133     autoselected_epsilon=tmp_proj[CMath::min(qpsize,num_vec)];
00134 
00135 #ifdef DEBUG_SUBGRADIENTSVM
00136     //SG_PRINT("autoseleps: %15.15f\n", autoselected_epsilon);
00137 #endif
00138 
00139     if (autoselected_epsilon>work_epsilon)
00140         autoselected_epsilon=work_epsilon;
00141 
00142     if (autoselected_epsilon<epsilon)
00143     {
00144         autoselected_epsilon=epsilon;
00145 
00146         int32_t i=0;
00147         while (i < num_vec && tmp_proj[i] <= autoselected_epsilon)
00148             i++;
00149 
00150         //SG_PRINT("lower bound on epsilon requires %d variables in qp\n", i);
00151 
00152         if (i>=qpsize_max && autoselected_epsilon>epsilon) //qpsize limit
00153         {
00154             SG_PRINT("qpsize limit (%d) reached\n", qpsize_max);
00155             int32_t num_in_qp=i;
00156             while (--i>=0 && num_in_qp>=qpsize_max)
00157             {
00158                 if (tmp_proj[i] < autoselected_epsilon)
00159                 {
00160                     autoselected_epsilon=tmp_proj[i];
00161                     num_in_qp--;
00162                 }
00163             }
00164 
00165             //SG_PRINT("new qpsize will be %d, autoeps:%15.15f\n", num_in_qp, autoselected_epsilon);
00166         }
00167     }
00168 
00169     for (int32_t i=0; i<num_vec; i++)
00170     {
00171         active[i]=0;
00172 
00173         //within margin/wrong side
00174         if (proj[i] < 1-autoselected_epsilon)
00175         {
00176             idx_active[num_active++]=i;
00177             active[i]=1;
00178         }
00179 
00180         //on margin
00181         if (CMath::abs(proj[i]-1) <= autoselected_epsilon)
00182         {
00183             idx_bound[num_bound++]=i;
00184             active[i]=2;
00185         }
00186 
00187         if (active[i]!=old_active[i])
00188             delta_active++;
00189 
00190         if (active[i]==2 && old_active[i]==2)
00191             delta_bound++;
00192     }
00193 
00194     pos_idx=0;
00195     neg_idx=0;
00196     zero_idx=0;
00197 
00198     for (int32_t i=0; i<num_feat; i++)
00199     {
00200         if (w[i]>work_epsilon)
00201         {
00202             w_pos[pos_idx++]=i;
00203             grad_w[i]=1;
00204         }
00205         else if (w[i]<-work_epsilon)
00206         {
00207             w_neg[neg_idx++]=i;
00208             grad_w[i]=-1;
00209         }
00210 
00211         if (CMath::abs(w[i])<=work_epsilon)
00212         {
00213             w_zero[zero_idx++]=i;
00214             grad_w[i]=-1;
00215         }
00216     }
00217 
00218     return delta_active;
00219 }
00220 
00221 
00222 void CSubGradientLPM::update_active(int32_t num_feat, int32_t num_vec)
00223 {
00224     for (int32_t i=0; i<num_vec; i++)
00225     {
00226         if (active[i]==1 && old_active[i]!=1)
00227         {
00228             features->add_to_dense_vec(C1*get_label(i), i, sum_CXy_active, num_feat);
00229             if (use_bias)
00230                 sum_Cy_active+=C1*get_label(i);
00231         }
00232         else if (old_active[i]==1 && active[i]!=1)
00233         {
00234             features->add_to_dense_vec(-C1*get_label(i), i, sum_CXy_active, num_feat);
00235             if (use_bias)
00236                 sum_Cy_active-=C1*get_label(i);
00237         }
00238     }
00239 
00240     CMath::swap(active,old_active);
00241 }
00242 
00243 float64_t CSubGradientLPM::line_search(int32_t num_feat, int32_t num_vec)
00244 {
00245     int32_t num_hinge=0;
00246     float64_t alpha=0;
00247     float64_t sgrad=0;
00248 
00249     float64_t* A=new float64_t[num_feat+num_vec];
00250     float64_t* B=new float64_t[num_feat+num_vec];
00251     float64_t* C=new float64_t[num_feat+num_vec];
00252     float64_t* D=new float64_t[num_feat+num_vec];
00253 
00254     for (int32_t i=0; i<num_feat+num_vec; i++)
00255     {
00256         if (i<num_feat)
00257         {
00258             A[i]=-grad_w[i];
00259             B[i]=w[i];
00260             C[i]=+grad_w[i];
00261             D[i]=-w[i];
00262         }
00263         else
00264         {
00265             float64_t p=get_label(i-num_feat)*features->dense_dot(1.0, i-num_feat, grad_w, num_feat, grad_b);
00266             grad_proj[i-num_feat]=p;
00267             
00268             A[i]=0;
00269             B[i]=0;
00270             C[i]=C1*p;
00271             D[i]=C1*(1-proj[i-num_feat]);
00272         }
00273 
00274         if (A[i]==C[i] && B[i]>D[i])
00275             sgrad+=A[i]+C[i];
00276         else if (A[i]==C[i] && B[i]==D[i])
00277             sgrad+=CMath::max(A[i],C[i]);
00278         else if (A[i]!=C[i])
00279         {
00280             hinge_point[num_hinge]=(D[i]-B[i])/(A[i]-C[i]);
00281             hinge_idx[num_hinge]=i; // index into A,B,C,D arrays
00282             num_hinge++;
00283 
00284             if (A[i]>C[i])
00285                 sgrad+=C[i];
00286             if (A[i]<C[i])
00287                 sgrad+=A[i];
00288         }
00289     }
00290 
00291     //SG_PRINT("sgrad:%f\n", sgrad);
00292     //CMath::display_vector(A, num_feat+num_vec, "A");
00293     //CMath::display_vector(B, num_feat+num_vec, "B");
00294     //CMath::display_vector(C, num_feat+num_vec, "C");
00295     //CMath::display_vector(D, num_feat+num_vec, "D");
00296     //CMath::display_vector(hinge_point, num_feat+num_vec, "hinge_point");
00297     //CMath::display_vector(hinge_idx, num_feat+num_vec, "hinge_idx");
00298     //ASSERT(0);
00299 
00300     CMath::qsort_index(hinge_point, hinge_idx, num_hinge);
00301     //CMath::display_vector(hinge_point, num_feat+num_vec, "hinge_point_sorted");
00302 
00303 
00304     int32_t i=-1;
00305     while (i < num_hinge-1 && sgrad < 0)
00306     {
00307         i+=1;
00308 
00309         if (A[hinge_idx[i]] > C[hinge_idx[i]])
00310             sgrad += A[hinge_idx[i]] - C[hinge_idx[i]];
00311         else
00312             sgrad += C[hinge_idx[i]] - A[hinge_idx[i]];
00313     }
00314 
00315     alpha = hinge_point[i];
00316 
00317     delete[] D;
00318     delete[] C;
00319     delete[] B;
00320     delete[] A;
00321 
00322     //SG_PRINT("alpha=%f\n", alpha);
00323     return alpha;
00324 }
00325 
00326 float64_t CSubGradientLPM::compute_min_subgradient(
00327     int32_t num_feat, int32_t num_vec, int32_t num_active, int32_t num_bound)
00328 {
00329     float64_t dir_deriv=0;
00330     solver->init(E_QP);
00331 
00332     if (zero_idx+num_bound > 0)
00333     {
00334         //SG_PRINT("num_var:%d (zero:%d, bound:%d) num_feat:%d\n", zero_idx+num_bound, zero_idx,num_bound, num_feat);
00335         //CMath::display_vector(grad_w, num_feat+1, "grad_w");
00336         CMath::add(grad_w, 1.0, grad_w, -1.0, sum_CXy_active, num_feat);
00337         grad_w[num_feat]= -sum_Cy_active;
00338 
00339         grad_b = -sum_Cy_active;
00340 
00341         //CMath::display_vector(sum_CXy_active, num_feat, "sum_CXy_active");
00342         //SG_PRINT("sum_Cy_active=%10.10f\n", sum_Cy_active);
00343 
00344         //CMath::display_vector(grad_w, num_feat+1, "grad_w");
00345 
00346         solver->setup_subgradientlpm_QP(C1, labels, features, idx_bound, num_bound,
00347                 w_zero, zero_idx,
00348                 grad_w, num_feat+1,
00349                 use_bias);
00350 
00351         solver->optimize(beta);
00352         //CMath::display_vector(beta, num_feat+1, "v");
00353 
00354         //compute dir_deriv here, variable grad_w constains still 'v' and beta
00355         //contains the future gradient
00356         dir_deriv = CMath::dot(beta, grad_w, num_feat);
00357         dir_deriv-=beta[num_feat]*sum_Cy_active;
00358 
00359         for (int32_t i=0; i<num_bound; i++)
00360         {
00361             float64_t val= C1*get_label(idx_bound[i])*features->dense_dot(1.0, idx_bound[i], beta, num_feat, beta[num_feat]);
00362             dir_deriv += CMath::max(0.0, val);
00363         }
00364 
00365         for (int32_t i=0; i<num_feat; i++)
00366             grad_w[i]=beta[i];
00367 
00368         if (use_bias)
00369             grad_b=beta[num_feat];
00370 
00371         //for (int32_t i=0; i<zero_idx+num_bound; i++)
00372         //  beta[i]=beta[i+num_feat+1];
00373 
00374         //CMath::display_vector(beta, zero_idx+num_bound, "beta");
00375         //SG_PRINT("beta[0]=%10.16f\n", beta[0]);
00376         //ASSERT(0);
00377 
00378         //for (int32_t i=0; i<zero_idx+num_bound; i++)
00379         //{
00380         //  if (i<zero_idx)
00381         //      grad_w[w_zero[i]]+=beta[w_zero[i]];
00382         //  else
00383         //  {
00384         //      features->add_to_dense_vec(-C1*beta[i]*get_label(idx_bound[i-zero_idx]), idx_bound[i-zero_idx], grad_w, num_feat);
00385         //      if (use_bias)
00386         //          grad_b -=  C1 * get_label(idx_bound[i-zero_idx])*beta[i-zero_idx];
00387         //  }
00388         //}
00389 
00390         //CMath::display_vector(w_zero, zero_idx, "w_zero");
00391         //CMath::display_vector(grad_w, num_feat, "grad_w");
00392         //SG_PRINT("grad_b=%f\n", grad_b);
00393         //
00394     }
00395     else
00396     {
00397         CMath::add(grad_w, 1.0, w, -1.0, sum_CXy_active, num_feat);
00398         grad_b = -sum_Cy_active;
00399 
00400         dir_deriv = CMath::dot(grad_w, grad_w, num_feat)+ grad_b*grad_b;
00401     }
00402 
00403     solver->cleanup();
00404 
00405 
00406     //SG_PRINT("Gradient   : |subgrad_W|^2=%f, |subgrad_b|^2=%f\n",
00407     //      CMath::dot(grad_w, grad_w, num_feat), grad_b*grad_b);
00408 
00409     return dir_deriv;
00410 }
00411 
00412 float64_t CSubGradientLPM::compute_objective(int32_t num_feat, int32_t num_vec)
00413 {
00414     float64_t result= CMath::sum_abs(w, num_feat);
00415     
00416     for (int32_t i=0; i<num_vec; i++)
00417     {
00418         if (proj[i]<1.0)
00419             result += C1 * (1.0-proj[i]);
00420     }
00421 
00422     return result;
00423 }
00424 
00425 void CSubGradientLPM::compute_projection(int32_t num_feat, int32_t num_vec)
00426 {
00427     for (int32_t i=0; i<num_vec; i++)
00428         proj[i]=get_label(i)*features->dense_dot(1.0, i, w, num_feat, bias);
00429 }
00430 
00431 void CSubGradientLPM::update_projection(float64_t alpha, int32_t num_vec)
00432 {
00433     CMath::vec1_plus_scalar_times_vec2(proj,-alpha, grad_proj, num_vec);
00434 }
00435 
00436 void CSubGradientLPM::init(int32_t num_vec, int32_t num_feat)
00437 {
00438     // alloc normal and bias inited with 0
00439     delete[] w;
00440     w=new float64_t[num_feat];
00441     for (int32_t i=0; i<num_feat; i++)
00442         w[i]=1.0;
00443     //CMath::random_vector(w, num_feat, -1.0, 1.0);
00444     bias=0;
00445     num_it_noimprovement=0;
00446     grad_b=0;
00447     set_w(w, num_feat);
00448 
00449     w_pos=new int32_t[num_feat];
00450     memset(w_pos,0,sizeof(int32_t)*num_feat);
00451 
00452     w_zero=new int32_t[num_feat];
00453     memset(w_zero,0,sizeof(int32_t)*num_feat);
00454 
00455     w_neg=new int32_t[num_feat];
00456     memset(w_neg,0,sizeof(int32_t)*num_feat);
00457 
00458     grad_w=new float64_t[num_feat+1];
00459     memset(grad_w,0,sizeof(float64_t)*(num_feat+1));
00460 
00461     sum_CXy_active=new float64_t[num_feat];
00462     memset(sum_CXy_active,0,sizeof(float64_t)*num_feat);
00463 
00464     sum_Cy_active=0;
00465 
00466     proj=new float64_t[num_vec];
00467     memset(proj,0,sizeof(float64_t)*num_vec);
00468 
00469     tmp_proj=new float64_t[num_vec];
00470     memset(proj,0,sizeof(float64_t)*num_vec);
00471 
00472     tmp_proj_idx=new int32_t[num_vec];
00473     memset(tmp_proj_idx,0,sizeof(int32_t)*num_vec);
00474 
00475     grad_proj=new float64_t[num_vec];
00476     memset(grad_proj,0,sizeof(float64_t)*num_vec);
00477 
00478     hinge_point=new float64_t[num_vec+num_feat];
00479     memset(hinge_point,0,sizeof(float64_t)*(num_vec+num_feat));
00480 
00481     hinge_idx=new int32_t[num_vec+num_feat];
00482     memset(hinge_idx,0,sizeof(int32_t)*(num_vec+num_feat));
00483 
00484     active=new uint8_t[num_vec];
00485     memset(active,0,sizeof(uint8_t)*num_vec);
00486 
00487     old_active=new uint8_t[num_vec];
00488     memset(old_active,0,sizeof(uint8_t)*num_vec);
00489 
00490     idx_bound=new int32_t[num_vec];
00491     memset(idx_bound,0,sizeof(int32_t)*num_vec);
00492 
00493     idx_active=new int32_t[num_vec];
00494     memset(idx_active,0,sizeof(int32_t)*num_vec);
00495 
00496     beta=new float64_t[num_feat+1+num_feat+num_vec];
00497     memset(beta,0,sizeof(float64_t)*num_feat+1+num_feat+num_vec);
00498 
00499     solver=new CCplex();
00500 }
00501 
00502 void CSubGradientLPM::cleanup()
00503 {
00504     delete[] hinge_idx;
00505     delete[] hinge_point;
00506     delete[] grad_proj;
00507     delete[] proj;
00508     delete[] tmp_proj;
00509     delete[] tmp_proj_idx;
00510     delete[] active;
00511     delete[] old_active;
00512     delete[] idx_bound;
00513     delete[] idx_active;
00514     delete[] sum_CXy_active;
00515     delete[] w_pos;
00516     delete[] w_zero;
00517     delete[] w_neg;
00518     delete[] grad_w;
00519     delete[] beta;
00520 
00521     hinge_idx=NULL;
00522     hinge_point=NULL;
00523     grad_proj=NULL;
00524     proj=NULL;
00525     tmp_proj=NULL;
00526     tmp_proj_idx=NULL;
00527     active=NULL;
00528     old_active=NULL;
00529     idx_bound=NULL;
00530     idx_active=NULL;
00531     sum_CXy_active=NULL;
00532     w_pos=NULL;
00533     w_zero=NULL;
00534     w_neg=NULL;
00535     grad_w=NULL;
00536     beta=NULL;
00537 
00538     delete solver;
00539     solver=NULL;
00540 }
00541 
00542 bool CSubGradientLPM::train()
00543 {
00544     lpmtim=0;
00545     SG_INFO("C=%f epsilon=%f\n", C1, epsilon);
00546     ASSERT(labels);
00547     ASSERT(features);
00548 
00549     int32_t num_iterations=0;
00550     int32_t num_train_labels=labels->get_num_labels();
00551     int32_t num_feat=features->get_num_features();
00552     int32_t num_vec=features->get_num_vectors();
00553 
00554     ASSERT(num_vec==num_train_labels);
00555 
00556     init(num_vec, num_feat);
00557 
00558     int32_t num_active=0;
00559     int32_t num_bound=0;
00560     float64_t alpha=0;
00561     float64_t dir_deriv=0;
00562     float64_t obj=0;
00563     delta_active=num_vec;
00564     last_it_noimprovement=-1;
00565 
00566     work_epsilon=0.99;
00567     autoselected_epsilon=work_epsilon;
00568 
00569     compute_projection(num_feat, num_vec);
00570 
00571     CTime time;
00572     float64_t loop_time=0;
00573     while (!(CSignal::cancel_computations()))
00574     {
00575         CTime t;
00576         delta_active=find_active(num_feat, num_vec, num_active, num_bound);
00577 
00578         update_active(num_feat, num_vec);
00579 
00580 #ifdef DEBUG_SUBGRADIENTLPM
00581         SG_PRINT("==================================================\niteration: %d ", num_iterations);
00582         obj=compute_objective(num_feat, num_vec);
00583         SG_PRINT("objective:%.10f alpha: %.10f dir_deriv: %f num_bound: %d num_active: %d work_eps: %10.10f eps: %10.10f auto_eps: %10.10f time:%f\n",
00584                 obj, alpha, dir_deriv, num_bound, num_active, work_epsilon, epsilon, autoselected_epsilon, loop_time);
00585 #else
00586       SG_ABS_PROGRESS(work_epsilon, -CMath::log10(work_epsilon), -CMath::log10(0.99999999), -CMath::log10(epsilon), 6);
00587 #endif
00588         //CMath::display_vector(w, w_dim, "w");
00589         //SG_PRINT("bias: %f\n", bias);
00590         //CMath::display_vector(proj, num_vec, "proj");
00591         //CMath::display_vector(idx_active, num_active, "idx_active");
00592         //SG_PRINT("num_active: %d\n", num_active);
00593         //CMath::display_vector(idx_bound, num_bound, "idx_bound");
00594         //SG_PRINT("num_bound: %d\n", num_bound);
00595         //CMath::display_vector(sum_CXy_active, num_feat, "sum_CXy_active");
00596         //SG_PRINT("sum_Cy_active: %f\n", sum_Cy_active);
00597         //CMath::display_vector(grad_w, num_feat, "grad_w");
00598         //SG_PRINT("grad_b:%f\n", grad_b);
00599         
00600         dir_deriv=compute_min_subgradient(num_feat, num_vec, num_active, num_bound);
00601 
00602         alpha=line_search(num_feat, num_vec);
00603 
00604         if (num_it_noimprovement==10 || num_bound<qpsize_max)
00605         {
00606             float64_t norm_grad=CMath::dot(grad_w, grad_w, num_feat) +
00607                 grad_b*grad_b;
00608 
00609             SG_PRINT("CHECKING OPTIMALITY CONDITIONS: "
00610                     "work_epsilon: %10.10f delta_active:%d alpha: %10.10f norm_grad: %10.10f a*norm_grad:%10.16f\n",
00611                     work_epsilon, delta_active, alpha, norm_grad, CMath::abs(alpha*norm_grad));
00612 
00613             if (work_epsilon<=epsilon && delta_active==0 && CMath::abs(alpha*norm_grad)<1e-6)
00614                 break;
00615             else
00616                 num_it_noimprovement=0;
00617         }
00618 
00619         //if (work_epsilon<=epsilon && delta_active==0 && num_it_noimprovement)
00620         if ((dir_deriv<0 || alpha==0) && (work_epsilon<=epsilon && delta_active==0))
00621         {
00622             if (last_it_noimprovement==num_iterations-1)
00623             {
00624                 SG_PRINT("no improvement...\n");
00625                 num_it_noimprovement++;
00626             }
00627             else
00628                 num_it_noimprovement=0;
00629 
00630             last_it_noimprovement=num_iterations;
00631         }
00632 
00633         CMath::vec1_plus_scalar_times_vec2(w, -alpha, grad_w, num_feat);
00634         bias-=alpha*grad_b;
00635 
00636         update_projection(alpha, num_vec);
00637 
00638         t.stop();
00639         loop_time=t.time_diff_sec();
00640         num_iterations++;
00641 
00642         if (get_max_train_time()>0 && time.cur_time_diff()>get_max_train_time())
00643             break;
00644     }
00645 
00646     SG_INFO("converged after %d iterations\n", num_iterations);
00647 
00648     obj=compute_objective(num_feat, num_vec);
00649     SG_INFO("objective: %f alpha: %f dir_deriv: %f num_bound: %d num_active: %d sparsity: %f\n",
00650             obj, alpha, dir_deriv, num_bound, num_active, sparsity/num_iterations);
00651 
00652 #ifdef DEBUG_SUBGRADIENTLPM
00653     CMath::display_vector(w, w_dim, "w");
00654     SG_PRINT("bias: %f\n", bias);
00655 #endif
00656     SG_PRINT("solver time:%f s\n", lpmtim);
00657 
00658     cleanup();
00659 
00660     return true;
00661 }
00662 #endif //USE_CPLEX

SHOGUN Machine Learning Toolbox - Documentation