00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include <algorithm>
00017 #include <shogun/classifier/vw/VowpalWabbit.h>
00018
00019 using namespace std;
00020 using namespace shogun;
00021
00022 CVowpalWabbit::CVowpalWabbit()
00023 : COnlineLinearMachine()
00024 {
00025 reg=NULL;
00026 learner=NULL;
00027 init(NULL);
00028 }
00029
00030 CVowpalWabbit::CVowpalWabbit(CStreamingVwFeatures* feat)
00031 : COnlineLinearMachine()
00032 {
00033 reg=NULL;
00034 learner=NULL;
00035 init(feat);
00036 }
00037
00038 CVowpalWabbit::CVowpalWabbit(CVowpalWabbit *vw)
00039 : COnlineLinearMachine()
00040 {
00041 features = vw->features;
00042 env = vw->env;
00043 reg = new CVwRegressor(env);
00044 SG_REF(env);
00045 SG_REF(reg);
00046
00047 quiet = vw->quiet;
00048 no_training = vw->no_training;
00049 dump_interval = vw->dump_interval;
00050 sum_loss_since_last_dump = 0.;
00051 reg_name = vw->reg_name;
00052 reg_dump_text = vw->reg_dump_text;
00053 save_predictions = vw->save_predictions;
00054 prediction_fd = vw->prediction_fd;
00055
00056 w = reg->weight_vectors[0];
00057 copy(vw->w, vw->w+vw->w_dim, w);
00058 w_dim = vw->w_dim;
00059 bias = vw->bias;
00060 }
00061
00062 CVowpalWabbit::~CVowpalWabbit()
00063 {
00064 SG_UNREF(env);
00065 SG_UNREF(reg);
00066 SG_UNREF(learner);
00067 }
00068
00069 void CVowpalWabbit::reinitialize_weights()
00070 {
00071 if (reg->weight_vectors)
00072 {
00073 if (reg->weight_vectors[0])
00074 SG_FREE(reg->weight_vectors[0]);
00075 SG_FREE(reg->weight_vectors);
00076 }
00077
00078 reg->init(env);
00079 w = reg->weight_vectors[0];
00080 }
00081
00082 void CVowpalWabbit::set_adaptive(bool adaptive_learning)
00083 {
00084 if (adaptive_learning)
00085 {
00086 env->adaptive = true;
00087 env->set_stride(2);
00088 env->power_t = 0.;
00089 reinitialize_weights();
00090 }
00091 else
00092 env->adaptive = false;
00093 }
00094
00095 void CVowpalWabbit::set_exact_adaptive_norm(bool exact_adaptive)
00096 {
00097 if (exact_adaptive)
00098 {
00099 set_adaptive(true);
00100 env->exact_adaptive_norm = true;
00101 }
00102 else
00103 env->exact_adaptive_norm = false;
00104 }
00105
00106 void CVowpalWabbit::load_regressor(char* file_name)
00107 {
00108 reg->load_regressor(file_name);
00109 w = reg->weight_vectors[0];
00110 w_dim = 1 << env->num_bits;
00111 }
00112
00113 void CVowpalWabbit::set_regressor_out(char* file_name, bool is_text)
00114 {
00115 reg_name = file_name;
00116 reg_dump_text = is_text;
00117 }
00118
00119 void CVowpalWabbit::set_prediction_out(char* file_name)
00120 {
00121 save_predictions = true;
00122 prediction_fd = open(file_name, O_CREAT|O_TRUNC|O_WRONLY, 0666);
00123 if (prediction_fd < 0)
00124 SG_SERROR("Unable to open prediction file %s for writing!\n", file_name);
00125 }
00126
00127 void CVowpalWabbit::add_quadratic_pair(char* pair)
00128 {
00129 env->pairs.push_back(pair);
00130 }
00131
00132 bool CVowpalWabbit::train_machine(CFeatures* feat)
00133 {
00134 ASSERT(features || feat);
00135 if (feat && (features != (CStreamingVwFeatures*) feat))
00136 {
00137 SG_UNREF(features);
00138 init((CStreamingVwFeatures*) feat);
00139 }
00140
00141 set_learner();
00142
00143 VwExample* example = NULL;
00144 vw_size_t current_pass = 0;
00145
00146 const char* header_fmt = "%-10s %-10s %8s %8s %10s %8s %8s\n";
00147
00148 if (!quiet)
00149 {
00150 SG_SPRINT(header_fmt,
00151 "average", "since", "example", "example",
00152 "current", "current", "current");
00153 SG_SPRINT(header_fmt,
00154 "loss", "last", "counter", "weight", "label", "predict", "features");
00155 }
00156
00157 features->start_parser();
00158 while (env->passes_complete < env->num_passes)
00159 {
00160 while (features->get_next_example())
00161 {
00162 example = features->get_example();
00163
00164
00165 if (!no_training)
00166 {
00167 if (example->pass != current_pass)
00168 {
00169 env->eta *= env->eta_decay_rate;
00170 current_pass = example->pass;
00171 }
00172
00173 predict_and_finalize(example);
00174
00175 learner->train(example, example->eta_round);
00176 example->eta_round = 0.;
00177
00178 output_example(example);
00179 }
00180
00181 features->release_example();
00182 }
00183 env->passes_complete++;
00184 if (env->passes_complete < env->num_passes)
00185 features->reset_stream();
00186 }
00187 features->end_parser();
00188
00189 if (env->l1_regularization > 0.)
00190 {
00191 uint32_t length = 1 << env->num_bits;
00192 vw_size_t stride = env->stride;
00193 float32_t gravity = env->l1_regularization * env->update_sum;
00194 for (uint32_t i = 0; i < length; i++)
00195 reg->weight_vectors[0][stride*i] = real_weight(reg->weight_vectors[0][stride*i], gravity);
00196 }
00197
00198 if (reg_name != NULL)
00199 reg->dump_regressor(reg_name, reg_dump_text);
00200
00201 return true;
00202 }
00203
00204 float32_t CVowpalWabbit::predict_and_finalize(VwExample* ex)
00205 {
00206 float32_t prediction;
00207 if (env->l1_regularization != 0.)
00208 prediction = inline_l1_predict(ex);
00209 else
00210 prediction = inline_predict(ex);
00211
00212 ex->final_prediction = 0;
00213 ex->final_prediction += prediction;
00214 ex->final_prediction = finalize_prediction(ex->final_prediction);
00215 float32_t t = ex->example_t;
00216
00217 if (ex->ld->label != FLT_MAX)
00218 {
00219 ex->loss = reg->get_loss(ex->final_prediction, ex->ld->label) * ex->ld->weight;
00220 float64_t update = 0.;
00221 if (env->adaptive && env->exact_adaptive_norm)
00222 {
00223 float32_t sum_abs_x = 0.;
00224 float32_t exact_norm = compute_exact_norm(ex, sum_abs_x);
00225 update = (env->eta * exact_norm)/sum_abs_x;
00226 env->update_sum += update;
00227 ex->eta_round = reg->get_update(ex->final_prediction, ex->ld->label, update, exact_norm);
00228 }
00229 else
00230 {
00231 update = (env->eta)/pow(t, env->power_t) * ex->ld->weight;
00232 ex->eta_round = reg->get_update(ex->final_prediction, ex->ld->label, update, ex->total_sum_feat_sq);
00233 }
00234 env->update_sum += update;
00235 }
00236
00237 return prediction;
00238 }
00239
00240 void CVowpalWabbit::init(CStreamingVwFeatures* feat)
00241 {
00242 features = feat;
00243 env = feat->get_env();
00244 reg = new CVwRegressor(env);
00245 SG_REF(env);
00246 SG_REF(reg);
00247
00248 quiet = true;
00249 no_training = false;
00250 dump_interval = exp(1.);
00251 sum_loss_since_last_dump = 0.;
00252 reg_name = NULL;
00253 reg_dump_text = true;
00254 save_predictions = false;
00255 prediction_fd = -1;
00256
00257 w = reg->weight_vectors[0];
00258 w_dim = 1 << env->num_bits;
00259 bias = 0.;
00260 }
00261
00262 void CVowpalWabbit::set_learner()
00263 {
00264 if (env->adaptive)
00265 learner = new CVwAdaptiveLearner(reg, env);
00266 else
00267 learner = new CVwNonAdaptiveLearner(reg, env);
00268 SG_REF(learner);
00269 }
00270
00271 float32_t CVowpalWabbit::inline_l1_predict(VwExample* &ex)
00272 {
00273 vw_size_t thread_num = 0;
00274
00275 float32_t prediction = ex->ld->get_initial();
00276
00277 float32_t* weights = reg->weight_vectors[thread_num];
00278 vw_size_t thread_mask = env->thread_mask;
00279
00280 prediction += features->dense_dot_truncated(weights, ex, env->l1_regularization * env->update_sum);
00281
00282 for (int32_t k = 0; k < env->pairs.get_num_elements(); k++)
00283 {
00284 char* i = env->pairs.get_element(k);
00285
00286 v_array<VwFeature> temp = ex->atomics[(int32_t)(i[0])];
00287 temp.begin = ex->atomics[(int32_t)(i[0])].begin;
00288 temp.end = ex->atomics[(int32_t)(i[0])].end;
00289 for (; temp.begin != temp.end; temp.begin++)
00290 prediction += one_pf_quad_predict_trunc(weights, *temp.begin,
00291 ex->atomics[(int32_t)(i[1])], thread_mask,
00292 env->l1_regularization * env->update_sum);
00293 }
00294
00295 return prediction;
00296 }
00297
00298 float32_t CVowpalWabbit::inline_predict(VwExample* &ex)
00299 {
00300 vw_size_t thread_num = 0;
00301 float32_t prediction = ex->ld->initial;
00302
00303 float32_t* weights = reg->weight_vectors[thread_num];
00304 vw_size_t thread_mask = env->thread_mask;
00305 prediction += features->dense_dot(weights, 0);
00306
00307 for (int32_t k = 0; k < env->pairs.get_num_elements(); k++)
00308 {
00309 char* i = env->pairs.get_element(k);
00310
00311 v_array<VwFeature> temp = ex->atomics[(int32_t)(i[0])];
00312 temp.begin = ex->atomics[(int32_t)(i[0])].begin;
00313 temp.end = ex->atomics[(int32_t)(i[0])].end;
00314 for (; temp.begin != temp.end; temp.begin++)
00315 prediction += one_pf_quad_predict(weights, *temp.begin,
00316 ex->atomics[(int32_t)(i[1])],
00317 thread_mask);
00318 }
00319
00320 return prediction;
00321 }
00322
00323 float32_t CVowpalWabbit::finalize_prediction(float32_t ret)
00324 {
00325 if (isnan(ret))
00326 return 0.5;
00327 if (ret > env->max_label)
00328 return env->max_label;
00329 if (ret < env->min_label)
00330 return env->min_label;
00331
00332 return ret;
00333 }
00334
00335 void CVowpalWabbit::output_example(VwExample* &example)
00336 {
00337 if (!quiet)
00338 {
00339 sum_loss_since_last_dump += example->loss;
00340 if (env->weighted_examples + example->ld->weight > dump_interval)
00341 {
00342 print_update(example);
00343 dump_interval *= 2;
00344 }
00345 }
00346
00347 if (save_predictions)
00348 {
00349 float32_t wt = 0.;
00350 if (reg->weight_vectors)
00351 wt = reg->weight_vectors[0][0];
00352
00353 output_prediction(prediction_fd, example->final_prediction, wt * example->global_weight, example->tag);
00354 }
00355 }
00356
00357 void CVowpalWabbit::print_update(VwExample* &ex)
00358 {
00359 SG_SPRINT("%-10.6f %-10.6f %8lld %8.1f %8.4f %8.4f %8lu\n",
00360 (env->sum_loss + ex->loss)/(env->weighted_examples + ex->ld->weight),
00361 sum_loss_since_last_dump/(env->weighted_examples + ex->ld->weight - old_weighted_examples),
00362 env->example_number + 1,
00363 env->weighted_examples + ex->ld->weight,
00364 ex->ld->label,
00365 ex->final_prediction,
00366 (long unsigned int)ex->num_features);
00367 sum_loss_since_last_dump = 0.0;
00368 old_weighted_examples = env->weighted_examples + ex->ld->weight;
00369 }
00370
00371
00372 void CVowpalWabbit::output_prediction(int32_t f, float32_t res, float32_t weight, v_array<char> tag)
00373 {
00374 if (f >= 0)
00375 {
00376 char temp[30];
00377 int32_t num = sprintf(temp, "%f", res);
00378 ssize_t t;
00379 t = write(f, temp, num);
00380 if (t != num)
00381 SG_SERROR("Write error!\n");
00382
00383 if (tag.begin != tag.end)
00384 {
00385 temp[0] = ' ';
00386 t = write(f, temp, 1);
00387 if (t != 1)
00388 SG_SERROR("Write error!\n");
00389
00390 t = write(f, tag.begin, sizeof(char)*tag.index());
00391 if (t != (ssize_t) (sizeof(char)*tag.index()))
00392 SG_SERROR("Write error!\n");
00393 }
00394
00395 temp[0] = '\n';
00396 t = write(f, temp, 1);
00397 if (t != 1)
00398 SG_SERROR("Write error!\n");
00399 }
00400 }
00401
00402 void CVowpalWabbit::set_verbose(bool verbose)
00403 {
00404 quiet=verbose==false;
00405 }
00406
00407
00408 float32_t CVowpalWabbit::compute_exact_norm(VwExample* &ex, float32_t& sum_abs_x)
00409 {
00410
00411 vw_size_t thread_mask = env->thread_mask;
00412 vw_size_t thread_num = 0;
00413
00414 float32_t g = reg->loss->get_square_grad(ex->final_prediction, ex->ld->label) * ex->ld->weight;
00415 if (g == 0) return 0.;
00416
00417 float32_t xGx = 0.;
00418
00419 float32_t* weights = reg->weight_vectors[thread_num];
00420 for (vw_size_t* i = ex->indices.begin; i != ex->indices.end; i++)
00421 {
00422 for (VwFeature* f = ex->atomics[*i].begin; f != ex->atomics[*i].end; f++)
00423 {
00424 float32_t* w_vec = &weights[f->weight_index & thread_mask];
00425 float32_t t = f->x * CMath::invsqrt(w_vec[1] + g * f->x * f->x);
00426 xGx += t * f->x;
00427 sum_abs_x += fabsf(f->x);
00428 }
00429 }
00430
00431 for (int32_t k = 0; k < env->pairs.get_num_elements(); k++)
00432 {
00433 char* i = env->pairs.get_element(k);
00434
00435 v_array<VwFeature> temp = ex->atomics[(int32_t)(i[0])];
00436 temp.begin = ex->atomics[(int32_t)(i[0])].begin;
00437 temp.end = ex->atomics[(int32_t)(i[0])].end;
00438 for (; temp.begin != temp.end; temp.begin++)
00439 xGx += compute_exact_norm_quad(weights, *temp.begin, ex->atomics[(int32_t)(i[1])], thread_mask, g, sum_abs_x);
00440 }
00441
00442 return xGx;
00443 }
00444
00445 float32_t CVowpalWabbit::compute_exact_norm_quad(float32_t* weights, VwFeature& page_feature, v_array<VwFeature> &offer_features,
00446 vw_size_t mask, float32_t g, float32_t& sum_abs_x)
00447 {
00448 vw_size_t halfhash = quadratic_constant * page_feature.weight_index;
00449 float32_t xGx = 0.;
00450 float32_t update2 = g * page_feature.x * page_feature.x;
00451 for (VwFeature* elem = offer_features.begin; elem != offer_features.end; elem++)
00452 {
00453 float32_t* w_vec = &weights[(halfhash + elem->weight_index) & mask];
00454 float32_t t = elem->x * CMath::invsqrt(w_vec[1] + update2 * elem->x * elem->x);
00455 xGx += t * elem->x;
00456 sum_abs_x += fabsf(elem->x);
00457 }
00458 return xGx;
00459 }