SHOGUN
v3.2.0
|
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-2010 Soeren Sonnenburg 00008 * Written (W) 2011 Shashwat Lal Das 00009 * Modifications (W) 2013 Thoralf Klein 00010 * Copyright (c) 2007-2009 The LIBLINEAR Project. 00011 * Copyright (C) 2007-2010 Fraunhofer Institute FIRST and Max-Planck-Society 00012 */ 00013 00014 #include <shogun/classifier/svm/OnlineLibLinear.h> 00015 #include <shogun/features/streaming/StreamingDenseFeatures.h> 00016 #include <shogun/features/streaming/StreamingSparseFeatures.h> 00017 #include <shogun/lib/Time.h> 00018 00019 using namespace shogun; 00020 00021 COnlineLibLinear::COnlineLibLinear() 00022 : COnlineLinearMachine() 00023 { 00024 init(); 00025 } 00026 00027 COnlineLibLinear::COnlineLibLinear(float64_t C_reg) 00028 { 00029 init(); 00030 C1=C_reg; 00031 C2=C_reg; 00032 use_bias=true; 00033 } 00034 00035 COnlineLibLinear::COnlineLibLinear( 00036 float64_t C_reg, CStreamingDotFeatures* traindat) 00037 { 00038 init(); 00039 C1=C_reg; 00040 C2=C_reg; 00041 use_bias=true; 00042 00043 set_features(traindat); 00044 } 00045 00046 COnlineLibLinear::COnlineLibLinear(COnlineLibLinear *mch) 00047 { 00048 init(); 00049 C1 = mch->C1; 00050 C2 = mch->C2; 00051 use_bias = mch->use_bias; 00052 00053 set_features(mch->features); 00054 00055 w_dim = mch->w_dim; 00056 if (w_dim > 0) 00057 { 00058 w = SG_MALLOC(float32_t, w_dim); 00059 memcpy(w, mch->w, w_dim*sizeof(float32_t)); 00060 } 00061 else 00062 { 00063 w = NULL; 00064 } 00065 bias = mch->bias; 00066 } 00067 00068 00069 void COnlineLibLinear::init() 00070 { 00071 C1=1; 00072 C2=1; 00073 use_bias=false; 00074 00075 m_parameters->add(&C1, "C1", "C Cost constant 1."); 00076 m_parameters->add(&C2, "C2", "C Cost constant 2."); 00077 m_parameters->add(&use_bias, "use_bias", "Indicates if bias is used."); 00078 } 00079 00080 COnlineLibLinear::~COnlineLibLinear() 00081 { 00082 } 00083 00084 void COnlineLibLinear::start_train() 00085 { 00086 Cp = C1; 00087 Cn = C2; 00088 PGmax_old = CMath::INFTY; 00089 PGmin_old = -CMath::INFTY; 00090 PGmax_new = -CMath::INFTY; 00091 PGmin_new = CMath::INFTY; 00092 00093 diag[0]=0;diag[1]=0;diag[2]=0; 00094 upper_bound[0]=Cn;upper_bound[1]=0;upper_bound[2]=Cp; 00095 00096 bias = 0; 00097 00098 PGmax_new = -CMath::INFTY; 00099 PGmin_new = CMath::INFTY; 00100 00101 v = 0; 00102 nSV = 0; 00103 } 00104 00105 void COnlineLibLinear::stop_train() 00106 { 00107 float64_t gap = PGmax_new - PGmin_new; 00108 00109 SG_DONE() 00110 SG_INFO("Optimization finished.\n") 00111 00112 // calculate objective value 00113 for (int32_t i=0; i<w_dim; i++) 00114 v += w[i]*w[i]; 00115 v += bias*bias; 00116 00117 SG_INFO("Objective value = %lf\n", v/2) 00118 SG_INFO("nSV = %d\n", nSV) 00119 SG_INFO("gap = %g\n", gap) 00120 } 00121 00122 void COnlineLibLinear::train_one(SGVector<float32_t> ex, float64_t label) 00123 { 00124 alpha_current = 0; 00125 if (label > 0) 00126 y_current = +1; 00127 else 00128 y_current = -1; 00129 00130 QD = diag[y_current + 1]; 00131 // Dot product of vector with itself 00132 QD += SGVector<float32_t>::dot(ex.vector, ex.vector, ex.vlen); 00133 00134 // Dot product of vector with learned weights 00135 G = SGVector<float32_t>::dot(ex.vector, w, w_dim); 00136 00137 if (use_bias) 00138 G += bias; 00139 G = G*y_current - 1; 00140 // LINEAR TERM PART? 00141 00142 C = upper_bound[y_current + 1]; 00143 G += alpha_current*diag[y_current + 1]; // Can be eliminated, since diag = 0 vector 00144 00145 PG = 0; 00146 if (alpha_current == 0) // This condition will always be true in the online version 00147 { 00148 if (G > PGmax_old) 00149 { 00150 return; 00151 } 00152 else if (G < 0) 00153 PG = G; 00154 } 00155 else if (alpha_current == C) 00156 { 00157 if (G < PGmin_old) 00158 { 00159 return; 00160 } 00161 else if (G > 0) 00162 PG = G; 00163 } 00164 else 00165 PG = G; 00166 00167 PGmax_new = CMath::max(PGmax_new, PG); 00168 PGmin_new = CMath::min(PGmin_new, PG); 00169 00170 if (fabs(PG) > 1.0e-12) 00171 { 00172 float64_t alpha_old = alpha_current; 00173 alpha_current = CMath::min(CMath::max(alpha_current - G/QD, 0.0), C); 00174 d = (alpha_current - alpha_old) * y_current; 00175 00176 for (int32_t i=0; i < w_dim; ++i) 00177 w[i] += d*ex[i]; 00178 00179 00180 if (use_bias) 00181 bias += d; 00182 } 00183 00184 v += alpha_current*(alpha_current*diag[y_current + 1] - 2); 00185 if (alpha_current > 0) 00186 nSV++; 00187 } 00188 00189 void COnlineLibLinear::train_one(SGSparseVector<float32_t> ex, float64_t label) 00190 { 00191 alpha_current = 0; 00192 if (label > 0) 00193 y_current = +1; 00194 else 00195 y_current = -1; 00196 00197 QD = diag[y_current + 1]; 00198 // Dot product of vector with itself 00199 QD += SGSparseVector<float32_t>::sparse_dot(ex, ex); 00200 00201 // Dot product of vector with learned weights 00202 G = ex.dense_dot(1.0,w,w_dim,0.0); 00203 00204 if (use_bias) 00205 G += bias; 00206 G = G*y_current - 1; 00207 // LINEAR TERM PART? 00208 00209 C = upper_bound[y_current + 1]; 00210 G += alpha_current*diag[y_current + 1]; // Can be eliminated, since diag = 0 vector 00211 00212 PG = 0; 00213 if (alpha_current == 0) // This condition will always be true in the online version 00214 { 00215 if (G > PGmax_old) 00216 { 00217 return; 00218 } 00219 else if (G < 0) 00220 PG = G; 00221 } 00222 else if (alpha_current == C) 00223 { 00224 if (G < PGmin_old) 00225 { 00226 return; 00227 } 00228 else if (G > 0) 00229 PG = G; 00230 } 00231 else 00232 PG = G; 00233 00234 PGmax_new = CMath::max(PGmax_new, PG); 00235 PGmin_new = CMath::min(PGmin_new, PG); 00236 00237 if (fabs(PG) > 1.0e-12) 00238 { 00239 float64_t alpha_old = alpha_current; 00240 alpha_current = CMath::min(CMath::max(alpha_current - G/QD, 0.0), C); 00241 d = (alpha_current - alpha_old) * y_current; 00242 00243 for (int32_t i=0; i < ex.num_feat_entries; i++) 00244 w[ex.features[i].feat_index] += d*ex.features[i].entry; 00245 00246 00247 if (use_bias) 00248 bias += d; 00249 } 00250 00251 v += alpha_current*(alpha_current*diag[y_current + 1] - 2); 00252 if (alpha_current > 0) 00253 nSV++; 00254 } 00255 00256 void COnlineLibLinear::train_example(CStreamingDotFeatures *feature, float64_t label) 00257 { 00258 features->expand_if_required(w, w_dim); 00259 00260 if (features->get_feature_class() == C_STREAMING_DENSE) { 00261 CStreamingDenseFeatures<float32_t> *feat = 00262 dynamic_cast<CStreamingDenseFeatures<float32_t> *>(feature); 00263 if (feat == NULL) 00264 SG_ERROR("Expected streaming dense feature <float32_t>\n") 00265 00266 train_one(feat->get_vector(), label); 00267 } 00268 else if (features->get_feature_class() == C_STREAMING_SPARSE) { 00269 CStreamingSparseFeatures<float32_t> *feat = 00270 dynamic_cast<CStreamingSparseFeatures<float32_t> *>(feature); 00271 if (feat == NULL) 00272 SG_ERROR("Expected streaming sparse feature <float32_t>\n") 00273 00274 train_one(feat->get_vector(), label); 00275 } 00276 else { 00277 SG_NOTIMPLEMENTED 00278 } 00279 }