SHOGUN  3.2.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
VowpalWabbit.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2009 Yahoo! Inc. All rights reserved. The copyrights
3  * embodied in the content of this file are licensed under the BSD
4  * (revised) open source license.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Written (W) 2011 Shashwat Lal Das
12  * Adaptation of Vowpal Wabbit v5.1.
13  * Copyright (C) 2011 Berlin Institute of Technology and Max-Planck-Society.
14  */
15 
16 #include <algorithm>
18 #include <fcntl.h>
19 
20 using namespace std;
21 using namespace shogun;
22 
23 CVowpalWabbit::CVowpalWabbit()
25 {
26  reg=NULL;
27  learner=NULL;
28  init(NULL);
29 }
30 
33 {
34  reg=NULL;
35  learner=NULL;
36  init(feat);
37 }
38 
41 {
42  features = vw->features;
43  env = vw->env;
44  reg = new CVwRegressor(env);
45  SG_REF(env);
46  SG_REF(reg);
47 
48  quiet = vw->quiet;
49  no_training = vw->no_training;
50  dump_interval = vw->dump_interval;
51  sum_loss_since_last_dump = 0.;
52  reg_name = vw->reg_name;
53  reg_dump_text = vw->reg_dump_text;
54  save_predictions = vw->save_predictions;
55  prediction_fd = vw->prediction_fd;
56 
57  w = reg->weight_vectors[0];
58  copy(vw->w, vw->w+vw->w_dim, w);
59  w_dim = vw->w_dim;
60  bias = vw->bias;
61 }
62 
64 {
65  SG_UNREF(env);
66  SG_UNREF(reg);
68 }
69 
71 {
72  if (reg->weight_vectors)
73  {
74  if (reg->weight_vectors[0])
75  SG_FREE(reg->weight_vectors[0]);
76  SG_FREE(reg->weight_vectors);
77  }
78 
79  reg->init(env);
80  w = reg->weight_vectors[0];
81 }
82 
83 void CVowpalWabbit::set_adaptive(bool adaptive_learning)
84 {
85  if (adaptive_learning)
86  {
87  env->adaptive = true;
88  env->set_stride(2);
89  env->power_t = 0.;
91  }
92  else
93  env->adaptive = false;
94 }
95 
96 void CVowpalWabbit::set_exact_adaptive_norm(bool exact_adaptive)
97 {
98  if (exact_adaptive)
99  {
100  set_adaptive(true);
101  env->exact_adaptive_norm = true;
102  }
103  else
104  env->exact_adaptive_norm = false;
105 }
106 
107 void CVowpalWabbit::load_regressor(char* file_name)
108 {
109  reg->load_regressor(file_name);
110  w = reg->weight_vectors[0];
111  w_dim = 1 << env->num_bits;
112 }
113 
114 void CVowpalWabbit::set_regressor_out(char* file_name, bool is_text)
115 {
116  reg_name = file_name;
117  reg_dump_text = is_text;
118 }
119 
121 {
122  save_predictions = true;
123  prediction_fd = open(file_name, O_CREAT|O_TRUNC|O_WRONLY, 0666);
124  if (prediction_fd < 0)
125  SG_SERROR("Unable to open prediction file %s for writing!\n", file_name)
126 }
127 
129 {
130  env->pairs.push_back(pair);
131 }
132 
134 {
135  ASSERT(features || feat)
136  if (feat && (features != (CStreamingVwFeatures*) feat))
137  {
139  init((CStreamingVwFeatures*) feat);
140  }
141 
142  set_learner();
143 
144  VwExample* example = NULL;
145  vw_size_t current_pass = 0;
146 
147  const char* header_fmt = "%-10s %-10s %8s %8s %10s %8s %8s\n";
148 
149  if (!quiet)
150  {
151  SG_SPRINT(header_fmt,
152  "average", "since", "example", "example",
153  "current", "current", "current");
154  SG_SPRINT(header_fmt,
155  "loss", "last", "counter", "weight", "label", "predict", "features");
156  }
157 
159  while (env->passes_complete < env->num_passes)
160  {
161  while (features->get_next_example())
162  {
163  example = features->get_example();
164 
165  // Check if we shouldn't train (generally used for cache creation)
166  if (!no_training)
167  {
168  if (example->pass != current_pass)
169  {
170  env->eta *= env->eta_decay_rate;
171  current_pass = example->pass;
172  }
173 
174  predict_and_finalize(example);
175 
176  learner->train(example, example->eta_round);
177  example->eta_round = 0.;
178 
179  output_example(example);
180  }
181 
183  }
184  env->passes_complete++;
187  }
188  features->end_parser();
189 
190  if (env->l1_regularization > 0.)
191  {
192  uint32_t length = 1 << env->num_bits;
193  vw_size_t stride = env->stride;
195  for (uint32_t i = 0; i < length; i++)
196  reg->weight_vectors[0][stride*i] = real_weight(reg->weight_vectors[0][stride*i], gravity);
197  }
198 
199  if (reg_name != NULL)
200  reg->dump_regressor(reg_name, reg_dump_text);
201 
202  return true;
203 }
204 
206 {
207  float32_t prediction;
208  if (env->l1_regularization != 0.)
209  prediction = inline_l1_predict(ex);
210  else
211  prediction = inline_predict(ex);
212 
213  ex->final_prediction = 0;
214  ex->final_prediction += prediction;
215  ex->final_prediction = finalize_prediction(ex->final_prediction);
216  float32_t t = ex->example_t;
217 
218  if (ex->ld->label != FLT_MAX)
219  {
220  ex->loss = reg->get_loss(ex->final_prediction, ex->ld->label) * ex->ld->weight;
221  float64_t update = 0.;
223  {
224  float32_t sum_abs_x = 0.;
225  float32_t exact_norm = compute_exact_norm(ex, sum_abs_x);
226  update = (env->eta * exact_norm)/sum_abs_x;
227  env->update_sum += update;
228  ex->eta_round = reg->get_update(ex->final_prediction, ex->ld->label, update, exact_norm);
229  }
230  else
231  {
232  update = (env->eta)/pow(t, env->power_t) * ex->ld->weight;
233  ex->eta_round = reg->get_update(ex->final_prediction, ex->ld->label, update, ex->total_sum_feat_sq);
234  }
235  env->update_sum += update;
236  }
237 
238  return prediction;
239 }
240 
241 void CVowpalWabbit::init(CStreamingVwFeatures* feat)
242 {
243  features = feat;
244 
245  if (feat)
246  env = feat->get_env();
247  else
248  {
249  env=new CVwEnvironment();
250  SG_REF(env);
251  }
252 
253  reg = new CVwRegressor(env);
254  SG_REF(reg);
255 
256  quiet = true;
257  no_training = false;
258  dump_interval = exp(1.);
259  sum_loss_since_last_dump = 0.;
260  reg_name = NULL;
261  reg_dump_text = true;
262  save_predictions = false;
263  prediction_fd = -1;
264 
265  w = reg->weight_vectors[0];
266  w_dim = 1 << env->num_bits;
267  bias = 0.;
268 }
269 
271 {
272  if (env->adaptive)
274  else
276  SG_REF(learner);
277 }
278 
279 float32_t CVowpalWabbit::inline_l1_predict(VwExample* &ex)
280 {
281  vw_size_t thread_num = 0;
282 
283  float32_t prediction = ex->ld->get_initial();
284 
285  float32_t* weights = reg->weight_vectors[thread_num];
286  vw_size_t thread_mask = env->thread_mask;
287 
288  prediction += features->dense_dot_truncated(weights, ex, env->l1_regularization * env->update_sum);
289 
290  for (int32_t k = 0; k < env->pairs.get_num_elements(); k++)
291  {
292  char* i = env->pairs.get_element(k);
293 
294  v_array<VwFeature> temp = ex->atomics[(int32_t)(i[0])];
295  temp.begin = ex->atomics[(int32_t)(i[0])].begin;
296  temp.end = ex->atomics[(int32_t)(i[0])].end;
297  for (; temp.begin != temp.end; temp.begin++)
298  prediction += one_pf_quad_predict_trunc(weights, *temp.begin,
299  ex->atomics[(int32_t)(i[1])], thread_mask,
301  }
302 
303  return prediction;
304 }
305 
306 float32_t CVowpalWabbit::inline_predict(VwExample* &ex)
307 {
308  vw_size_t thread_num = 0;
309  float32_t prediction = ex->ld->initial;
310 
311  float32_t* weights = reg->weight_vectors[thread_num];
312  vw_size_t thread_mask = env->thread_mask;
313  prediction += features->dense_dot(weights, 0);
314 
315  for (int32_t k = 0; k < env->pairs.get_num_elements(); k++)
316  {
317  char* i = env->pairs.get_element(k);
318 
319  v_array<VwFeature> temp = ex->atomics[(int32_t)(i[0])];
320  temp.begin = ex->atomics[(int32_t)(i[0])].begin;
321  temp.end = ex->atomics[(int32_t)(i[0])].end;
322  for (; temp.begin != temp.end; temp.begin++)
323  prediction += one_pf_quad_predict(weights, *temp.begin,
324  ex->atomics[(int32_t)(i[1])],
325  thread_mask);
326  }
327 
328  return prediction;
329 }
330 
331 float32_t CVowpalWabbit::finalize_prediction(float32_t ret)
332 {
333  if (isnan(ret))
334  return 0.5;
335  if (ret > env->max_label)
336  return env->max_label;
337  if (ret < env->min_label)
338  return env->min_label;
339 
340  return ret;
341 }
342 
343 void CVowpalWabbit::output_example(VwExample* &example)
344 {
345  if (!quiet)
346  {
347  sum_loss_since_last_dump += example->loss;
348  if (env->weighted_examples + example->ld->weight > dump_interval)
349  {
350  print_update(example);
351  dump_interval *= 2;
352  }
353  }
354 
355  if (save_predictions)
356  {
357  float32_t wt = 0.;
358  if (reg->weight_vectors)
359  wt = reg->weight_vectors[0][0];
360 
361  output_prediction(prediction_fd, example->final_prediction, wt * example->global_weight, example->tag);
362  }
363 }
364 
365 void CVowpalWabbit::print_update(VwExample* &ex)
366 {
367  SG_SPRINT("%-10.6f %-10.6f %8lld %8.1f %8.4f %8.4f %8lu\n",
368  (env->sum_loss + ex->loss)/(env->weighted_examples + ex->ld->weight),
369  sum_loss_since_last_dump/(env->weighted_examples + ex->ld->weight - old_weighted_examples),
370  env->example_number + 1,
371  env->weighted_examples + ex->ld->weight,
372  ex->ld->label,
373  ex->final_prediction,
374  (long unsigned int)ex->num_features);
375  sum_loss_since_last_dump = 0.0;
376  old_weighted_examples = env->weighted_examples + ex->ld->weight;
377 }
378 
379 
380 void CVowpalWabbit::output_prediction(int32_t f, float32_t res, float32_t weight, v_array<char> tag)
381 {
382  if (f >= 0)
383  {
384  char temp[30];
385  int32_t num = sprintf(temp, "%f", res);
386  ssize_t t;
387  t = write(f, temp, num);
388  if (t != num)
389  SG_SERROR("Write error!\n")
390 
391  if (tag.begin != tag.end)
392  {
393  temp[0] = ' ';
394  t = write(f, temp, 1);
395  if (t != 1)
396  SG_SERROR("Write error!\n")
397 
398  t = write(f, tag.begin, sizeof(char)*tag.index());
399  if (t != (ssize_t) (sizeof(char)*tag.index()))
400  SG_SERROR("Write error!\n")
401  }
402 
403  temp[0] = '\n';
404  t = write(f, temp, 1);
405  if (t != 1)
406  SG_SERROR("Write error!\n")
407  }
408 }
409 
410 void CVowpalWabbit::set_verbose(bool verbose)
411 {
412  quiet=verbose==false;
413 }
414 
415 
417 {
418  // We must traverse the features in _precisely_ the same order as during training.
419  vw_size_t thread_mask = env->thread_mask;
420  vw_size_t thread_num = 0;
421 
423  if (g == 0) return 0.;
424 
425  float32_t xGx = 0.;
426 
427  float32_t* weights = reg->weight_vectors[thread_num];
428  for (vw_size_t* i = ex->indices.begin; i != ex->indices.end; i++)
429  {
430  for (VwFeature* f = ex->atomics[*i].begin; f != ex->atomics[*i].end; f++)
431  {
432  float32_t* w_vec = &weights[f->weight_index & thread_mask];
433  float32_t t = f->x * CMath::invsqrt(w_vec[1] + g * f->x * f->x);
434  xGx += t * f->x;
435  sum_abs_x += fabsf(f->x);
436  }
437  }
438 
439  for (int32_t k = 0; k < env->pairs.get_num_elements(); k++)
440  {
441  char* i = env->pairs.get_element(k);
442 
443  v_array<VwFeature> temp = ex->atomics[(int32_t)(i[0])];
444  temp.begin = ex->atomics[(int32_t)(i[0])].begin;
445  temp.end = ex->atomics[(int32_t)(i[0])].end;
446  for (; temp.begin != temp.end; temp.begin++)
447  xGx += compute_exact_norm_quad(weights, *temp.begin, ex->atomics[(int32_t)(i[1])], thread_mask, g, sum_abs_x);
448  }
449 
450  return xGx;
451 }
452 
454  vw_size_t mask, float32_t g, float32_t& sum_abs_x)
455 {
456  vw_size_t halfhash = quadratic_constant * page_feature.weight_index;
457  float32_t xGx = 0.;
458  float32_t update2 = g * page_feature.x * page_feature.x;
459  for (VwFeature* elem = offer_features.begin; elem != offer_features.end; elem++)
460  {
461  float32_t* w_vec = &weights[(halfhash + elem->weight_index) & mask];
462  float32_t t = elem->x * CMath::invsqrt(w_vec[1] + update2 * elem->x * elem->x);
463  xGx += t * elem->x;
464  sum_abs_x += fabsf(elem->x);
465  }
466  return xGx;
467 }

SHOGUN Machine Learning Toolbox - Documentation