Vowpal Wabbit
ut_vw.cc
Go to the documentation of this file.
1 #include "gtest/gtest.h"
2 #include "gmock/gmock.h"
3 
4 #include "ut_util.h"
5 
6 #include <vector>
7 #include <set>
8 #include <stdlib.h>
9 #include <streambuf>
10 #include <array>
11 
12 #include <fstream>
14 #include "array_parameters.h"
15 #include "data.h"
16 
17 using namespace ::testing;
18 using namespace vw_slim;
19 using namespace exploration;
20 
21 // #define VW_SLIM_TEST_DEBUG "vwslim-debug.log"
22 
23 // some gymnastics to re-use the float reading code
24 struct membuf : std::streambuf
25 {
26  membuf(char* begin, char* end) { this->setg(begin, begin, end); }
27 };
28 
29 std::vector<float> read_floats(std::istream& data)
30 {
31  std::vector<float> floats;
32 
33  std::string line;
34  while (std::getline(data, line)) floats.push_back((float)atof(line.c_str()));
35 
36  return floats;
37 }
38 std::vector<float> read_floats(unsigned char* data, unsigned int len)
39 {
40  membuf mb((char*)data, (char*)(data + len));
41  std::istream in(&mb);
42  return read_floats(in);
43 }
44 
45 std::vector<float> read_floats(const char* filename)
46 {
47  std::ifstream data(filename);
48  return read_floats(data);
49 }
50 
51 struct test_data
52 {
53  unsigned char* model;
54  unsigned int model_len;
55  unsigned char* pred;
56  unsigned int pred_len;
57 };
58 
59 #define TEST_DATA(input, filename) \
60  { \
61  if (!strcmp(input, #filename)) \
62  { \
63  td.model = filename##_model; \
64  td.model_len = filename##_model_len; \
65  td.pred = filename##_pred; \
66  td.pred_len = filename##_pred_len; \
67  } \
68  }
69 
70 test_data get_test_data(const char* model_filename)
71 {
72  test_data td;
73  memset(&td, 0, sizeof(test_data));
74 
75  TEST_DATA(model_filename, regression_data_1);
76  TEST_DATA(model_filename, regression_data_2);
77  TEST_DATA(model_filename, regression_data_3);
78  TEST_DATA(model_filename, regression_data_3);
79  TEST_DATA(model_filename, regression_data_4);
80  TEST_DATA(model_filename, regression_data_5);
81  TEST_DATA(model_filename, regression_data_6);
82  TEST_DATA(model_filename, regression_data_7);
83  TEST_DATA(model_filename, regression_data_no_constant);
84  TEST_DATA(model_filename, regression_data_ignore_linear);
85  TEST_DATA(model_filename, multiclass_data_4);
86  TEST_DATA(model_filename, cb_data_epsilon_0_skype_jb);
87  TEST_DATA(model_filename, cb_data_5);
88  TEST_DATA(model_filename, cb_data_6);
89  TEST_DATA(model_filename, cb_data_7);
90  TEST_DATA(model_filename, cb_data_8);
91 
92  return td;
93 }
94 
95 template <typename W>
97  const char* model_filename, const char* data_filename, const char* prediction_reference_filename)
98 {
99  std::vector<float> preds;
100 
102  // if files would be available
103  test_data td = get_test_data(model_filename);
104  ASSERT_EQ(S_VW_PREDICT_OK, vw.load((const char*)td.model, td.model_len));
105  EXPECT_FALSE(vw.is_cb_explore_adf());
106 
107  float score;
108  if (!strcmp(data_filename, "regression_data_1.txt"))
109  {
110  safe_example_predict ex[2];
111  // 1 |0 0:1
113  b0.push_feature(0, 1.f);
114  // 1 |0 0:5
116  b1.push_feature(0, 5.f);
117 
118  for (auto& e : ex)
119  {
120  ASSERT_EQ(S_VW_PREDICT_OK, vw.predict(e, score));
121  preds.push_back(score);
122  }
123  }
124  else if (!strcmp(data_filename, "regression_data_2.txt"))
125  {
126  safe_example_predict ex[2];
127  // 1 |0 0:1 |a 0:2
129  b00.push_feature(0, 1.f);
130  example_predict_builder b0a(&ex[0], (char*)"a");
131  b0a.push_feature(0, 2.f);
132  // 0 |c 0:3
133  example_predict_builder b1(&ex[1], (char*)"c");
134  b1.push_feature(0, 3.f);
135 
136  for (auto& e : ex)
137  {
138  ASSERT_EQ(S_VW_PREDICT_OK, vw.predict(e, score));
139  preds.push_back(score);
140  }
141  }
142  else if (!strcmp(data_filename, "regression_data_3.txt"))
143  {
144  safe_example_predict ex[2];
145  // 1 |a 0:1 |b 2:2
146  example_predict_builder b0a(&ex[0], (char*)"a");
147  b0a.push_feature(0, 1.f);
148  example_predict_builder b0b(&ex[0], (char*)"b");
149  b0b.push_feature(2, 2.f);
150  // 0 |a 0:1 |b 2:4
151  example_predict_builder b1a(&ex[1], (char*)"a");
152  b1a.push_feature(0, 1.f);
153  example_predict_builder b1b(&ex[1], (char*)"b");
154  b1b.push_feature(2, 4.f);
155 
156  for (auto& e : ex)
157  {
158  ASSERT_EQ(S_VW_PREDICT_OK, vw.predict(e, score));
159  preds.push_back(score);
160  }
161  }
162  else if (!strcmp(data_filename, "regression_data_4.txt"))
163  {
164  safe_example_predict ex[2];
165  // 1 |a 0:1 |b 2:2 |c 3:3 |d 4:4
166  example_predict_builder b0a(&ex[0], (char*)"a");
167  b0a.push_feature(0, 1.f);
168  example_predict_builder b0b(&ex[0], (char*)"b");
169  b0b.push_feature(2, 2.f);
170  example_predict_builder b0c(&ex[0], (char*)"c");
171  b0c.push_feature(3, 3.f);
172  example_predict_builder b0d(&ex[0], (char*)"d");
173  b0d.push_feature(4, 4.f);
174  // 0 |a 0:1 |b 2:4 |c 3:1 |d 1:2
175  example_predict_builder b1a(&ex[1], (char*)"a");
176  b1a.push_feature(0, 1.f);
177  example_predict_builder b1b(&ex[1], (char*)"b");
178  b1b.push_feature(2, 4.f);
179  example_predict_builder b1c(&ex[1], (char*)"c");
180  b1c.push_feature(3, 1.f);
181  example_predict_builder b1d(&ex[1], (char*)"d");
182  b1d.push_feature(1, 2.f);
183 
184  for (auto& e : ex)
185  {
186  ASSERT_EQ(S_VW_PREDICT_OK, vw.predict(e, score));
187  preds.push_back(score);
188  }
189  }
190  else if (!strcmp(data_filename, "regression_data_7.txt"))
191  {
192  safe_example_predict ex[2];
193  // 1 |a x:1 |b y:2
194  example_predict_builder b0a(&ex[0], (char*)"a");
195  b0a.push_feature_string((char*)"x", 1.f);
196  example_predict_builder b0b(&ex[0], (char*)"b");
197  b0b.push_feature_string((char*)"y", 2.f);
198  // 0 |a x:1 |5 y:4
199  example_predict_builder b1a(&ex[1], (char*)"a");
200  b1a.push_feature_string((char*)"x", 1.f);
201  example_predict_builder b1b(&ex[1], 5);
202  b1b.push_feature_string((char*)"y", 4.f);
203 
204  for (auto& e : ex)
205  {
206  ASSERT_EQ(S_VW_PREDICT_OK, vw.predict(e, score));
207  preds.push_back(score);
208  }
209  }
210  else
211  FAIL() << "Unknown data file: " << data_filename;
212 
213  // compare output
214  std::vector<float> preds_expected = read_floats(td.pred, td.pred_len);
215 
216  EXPECT_THAT(preds, Pointwise(FloatNearPointwise(1e-5f), preds_expected));
217 }
218 
220 {
224 };
225 
227 {
228  const char* model_filename;
229  const char* data_filename;
232 };
233 
234 // nice rendering in unit tests
235 ::std::ostream& operator<<(::std::ostream& os, const PredictParam& param)
236 {
237  return os << param.model_filename << " " << param.data_filename << " "
238  << (param.weight_type == PredictParamWeightType::Sparse ? "sparse" : "dense");
239 }
240 
241 class PredictTest : public ::testing::TestWithParam<PredictParam>
242 {
243 };
244 
246 {
247  if (GetParam().weight_type == PredictParamWeightType::Sparse)
248  run_predict_in_memory<sparse_parameters>(
249  GetParam().model_filename, GetParam().data_filename, GetParam().prediction_reference_filename);
250  else
251  run_predict_in_memory<dense_parameters>(
252  GetParam().model_filename, GetParam().data_filename, GetParam().prediction_reference_filename);
253 }
254 
255 std::vector<PredictParam> GenerateTestParams()
256 {
257  std::vector<PredictParam> fixtures;
258 
259  PredictParam predict_params[] = {
260  {"regression_data_1", "regression_data_1.txt", "regression_data_1.pred", PredictParamWeightType::All},
261  {"regression_data_2", "regression_data_2.txt", "regression_data_2.pred", PredictParamWeightType::All},
262  {"regression_data_no_constant", "regression_data_1.txt", "regression_data_no-constant.pred",
264  {"regression_data_ignore_linear", "regression_data_2.txt", "regression_data_ignore_linear.pred",
266  {"regression_data_3", "regression_data_3.txt", "regression_data_3.pred", PredictParamWeightType::All},
267  {"regression_data_4", "regression_data_4.txt", "regression_data_4.pred", PredictParamWeightType::All},
268  {"regression_data_5", "regression_data_4.txt", "regression_data_5.pred", PredictParamWeightType::All},
269  {"regression_data_6", "regression_data_3.txt", "regression_data_6.pred", PredictParamWeightType::Sparse},
270  {"regression_data_7", "regression_data_7.txt", "regression_data_7.pred", PredictParamWeightType::All}};
271 
272  for (int i = 0; i < sizeof(predict_params) / sizeof(PredictParam); i++)
273  {
274  PredictParam p = predict_params[i];
276  fixtures.push_back(p);
277  else
278  {
279  for (int weight_type = PredictParamWeightType::Sparse; weight_type <= PredictParamWeightType::Dense;
280  weight_type++)
281  {
282  p.weight_type = static_cast<PredictParamWeightType>(weight_type);
283  fixtures.push_back(p);
284  }
285  }
286  }
287 
288  return fixtures;
289 }
290 
291 INSTANTIATE_TEST_SUITE_P(VowpalWabbitSlim, PredictTest, ::testing::ValuesIn(GenerateTestParams()));
292 
294 {
295  const char* name;
296  unsigned char* model;
297  unsigned int model_len;
298  std::set<size_t> undetectable_offsets;
300 };
301 
302 // nice rendering in unit tests
303 ::std::ostream& operator<<(::std::ostream& os, const InvalidModelParam& param) { return os << param.name; }
304 
305 class InvalidModelTest : public ::testing::TestWithParam<InvalidModelParam>
306 {
307 };
308 
310 {
311  const char* model_file = (const char*)GetParam().model;
312  size_t model_file_size = (size_t)GetParam().model_len;
313 
314  auto& undetectable_offsets = GetParam().undetectable_offsets;
315 
316  for (size_t end = 0; end < model_file_size - 1; ++end)
317  {
318  // we're not able to detect if complete index:weight pairs are missing
319  if (undetectable_offsets.find(end) != undetectable_offsets.end())
320  continue;
321 
322  // type parameterized and value parameterized test cases can't be combined:
323  // https://stackoverflow.com/questions/8507385/google-test-is-there-a-way-to-combine-a-test-which-is-both-type-parameterized-a
324  if (GetParam().weight_type == PredictParamWeightType::Sparse)
325  {
327  EXPECT_NE(S_VW_PREDICT_OK, vw.load(&model_file[0], end)) << "partial model read until " << end << " didn't throw";
328  }
329  else
330  {
332  EXPECT_NE(S_VW_PREDICT_OK, vw.load(&model_file[0], end)) << "partial model read until " << end << " didn't throw";
333  }
334  }
335 }
336 
338  {"regression_data_1", regression_data_1_model, regression_data_1_model_len, {84, 92},
339  PredictParamWeightType::Sparse}, // 2 weights
340  {"regression_data_1", regression_data_1_model, regression_data_1_model_len, {84, 92},
341  PredictParamWeightType::Dense}, // 2 weights
342  {"regression_data_6", regression_data_6_model, regression_data_6_model_len, {99, 111, 123, 135},
343  PredictParamWeightType::Sparse} // 4 weights
344 };
345 
346 INSTANTIATE_TEST_SUITE_P(VowpalWabbitSlim, InvalidModelTest, ::testing::ValuesIn(invalid_model_param));
347 
348 TEST(VowpalWabbitSlim, multiclass_data_4)
349 {
351  test_data td = get_test_data("multiclass_data_4");
352  ASSERT_EQ(0, vw.load((const char*)td.model, td.model_len));
353 
354  std::vector<float> out_scores;
355 
357  // shared |a 0:1 5:12
358  example_predict_builder bs(&shared, (char*)"a");
359  bs.push_feature(0, 1.f);
360  bs.push_feature(5, 12.f);
361 
362  safe_example_predict ex[3];
363  // 1:1.0 |b 0:1
364  example_predict_builder b0(&ex[0], (char*)"b");
365  b0.push_feature(0, 1.f);
366  // 2:0.3 |b 0:2
367  example_predict_builder b1(&ex[1], (char*)"b");
368  b1.push_feature(0, 2.f);
369  // 3:0.1 |b 0:3
370  example_predict_builder b2(&ex[2], (char*)"b");
371  b2.push_feature(0, 3.f);
372 
373  ASSERT_EQ(S_VW_PREDICT_OK, vw.predict(shared, ex, 3, out_scores));
374 
375  // 2:0.0386223,1:0.46983,0:0.901038
376  std::vector<float> preds_expected = {0.901038f, 0.46983f, 0.0386223f};
377 
378  // compare output
379  EXPECT_THAT(out_scores, Pointwise(FloatNearPointwise(1e-5f), preds_expected));
380 }
381 
382 void cb_data_epsilon_0_skype_jb_test_runner(int call_type, int modality, int network_type, int platform,
383  std::vector<int> ranking_expected, std::vector<float> pdf_expected)
384 {
385  // load model.
387  test_data td = get_test_data("cb_data_epsilon_0_skype_jb");
388  ASSERT_EQ(0, vw.load((const char*)td.model, td.model_len));
389 
390  // we have loaded the model and can push the features
392  vw_slim::example_predict_builder bOa(&features, (char*)"64");
393  bOa.push_feature(static_cast<int>(call_type), 1.f);
394  vw_slim::example_predict_builder bOb(&features, (char*)"16");
395  bOb.push_feature(static_cast<int>(modality), 1.f);
396  vw_slim::example_predict_builder bOc(&features, (char*)"32");
397  bOc.push_feature(static_cast<int>(network_type), 1.f);
398  vw_slim::example_predict_builder bOd(&features, (char*)"48");
399  bOd.push_feature(static_cast<int>(platform), 1.f);
400 
401  // push actions
402  const int min_delay_actions = 10;
403  safe_example_predict actions[min_delay_actions];
404  for (int i = 0; i < min_delay_actions; i++)
405  {
406  vw_slim::example_predict_builder bOe(&actions[i], (char*)"80");
407  bOe.push_feature(i, 1.f);
408  }
409 
410  // predict CB value
411  std::vector<float> pdfs;
412  std::vector<int> rankings;
413  int result = vw.predict("eid", features, actions, min_delay_actions, pdfs, rankings);
414 
415  // compare output with expected.
416  EXPECT_EQ(result, 0);
417  EXPECT_THAT(pdfs, Pointwise(FloatNearPointwise(1e-5f), pdf_expected));
418  EXPECT_THAT(rankings, ranking_expected);
419 }
420 
421 TEST(VowpalWabbitSlim, interaction_num_bits_bug)
422 {
423  std::ifstream input("data/Delay_Margin_AudioNetworkPCR_all_cb_FF8.model", std::ios::in | std::ios::binary);
424  input.seekg(0, std::ios::end);
425  auto length = input.tellg();
426  input.seekg(0, std::ios::beg);
427  std::unique_ptr<char> buffer_ptr(new char[length]);
428  input.read(buffer_ptr.get(),
429  length); // Extract how many bytes need to be decoded and resize the payload based on those bytes.
430 
432 
433  int result = vw.load(buffer_ptr.get(), length);
434  EXPECT_EQ(result, 0);
435 
436  // we have loaded the model and can push the features
438 
439  // Test with the single namespace.
440  vw_slim::example_predict_builder bOa(&features, "Features", vw.feature_index_num_bits());
441  bOa.push_feature_string("Networkmobile", 1.f);
442  bOa.push_feature_string("CallTypeP2P", 1.f);
443  bOa.push_feature_string("PlatformAndroid", 1.f);
444  bOa.push_feature_string("MediaTypeVideo", 1.f);
445 
446  const int MINDELAYACTIONS = 10;
447  // push actions
448  safe_example_predict actions[MINDELAYACTIONS];
449  for (int i = 0; i < MINDELAYACTIONS; i++)
450  {
451  vw_slim::example_predict_builder bOe(&actions[i], "80");
452  bOe.push_feature(i, 1.f);
453  }
454 
455  // generate UUID
456  std::string uuidString("EventId_0");
457 
458  std::vector<float> pdfs;
459  std::vector<int> rankings;
460 
461  result = vw.predict(uuidString.c_str(), features, actions, MINDELAYACTIONS, pdfs, rankings);
462  EXPECT_EQ(result, 0);
463  EXPECT_EQ(rankings[0], 3);
464 }
465 
466 TEST(VowpalWabbitSlim, cb_data_epsilon_0_skype_jb)
467 {
468  // Since the model is epsilon=0, the first entry should always be 0.
469  std::vector<float> pdf_expected = {1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
470 
471  // {0, 1, 2, 0} => 1
472  std::vector<int> ranking_expected = {1, 0, 2, 3, 4, 5, 7, 6, 8, 9};
473  cb_data_epsilon_0_skype_jb_test_runner(0, 1, 2, 0, ranking_expected, pdf_expected);
474 
475  // {0, 1, 4, 0} => 1
476  ranking_expected = {1, 0, 2, 3, 4, 5, 6, 8, 7, 9};
477  cb_data_epsilon_0_skype_jb_test_runner(0, 1, 4, 0, ranking_expected, pdf_expected);
478 
479  // {0, 0, 2, 0} => 1
480  ranking_expected = {1, 2, 0, 3, 4, 5, 6, 7, 8, 9};
481  cb_data_epsilon_0_skype_jb_test_runner(0, 0, 2, 0, ranking_expected, pdf_expected);
482 
483  // {0, 0, 4, 0} => 1
484  ranking_expected = {1, 3, 2, 0, 4, 6, 5, 8, 7, 9};
485  cb_data_epsilon_0_skype_jb_test_runner(0, 0, 4, 0, ranking_expected, pdf_expected);
486 
487  // {2, 0, 4, 0} => 3
488  ranking_expected = {3, 1, 0, 2, 5, 4, 7, 6, 8, 9};
489  cb_data_epsilon_0_skype_jb_test_runner(2, 0, 4, 0, ranking_expected, pdf_expected);
490 
491  // {0, 1, 999, 0} => 2
492  ranking_expected = {2, 4, 6, 1, 0, 5, 3, 7, 8, 9};
493  cb_data_epsilon_0_skype_jb_test_runner(0, 1, 999, 0, ranking_expected, pdf_expected);
494 
495  // {0, 0, 999, 0} => 2
496  ranking_expected = {2, 4, 6, 1, 3, 5, 0, 7, 8, 9};
497  cb_data_epsilon_0_skype_jb_test_runner(0, 0, 999, 0, ranking_expected, pdf_expected);
498 
499  // {2, 0, 999, 0} => 2
500  ranking_expected = {2, 5, 4, 3, 6, 1, 0, 7, 8, 9};
501  cb_data_epsilon_0_skype_jb_test_runner(2, 0, 999, 0, ranking_expected, pdf_expected);
502 
503  // {999, 0, 4, 0} => 1
504  ranking_expected = {0, 1, 4, 2, 6, 3, 8, 7, 5, 9};
505  cb_data_epsilon_0_skype_jb_test_runner(999, 0, 4, 0, ranking_expected, pdf_expected);
506 
507  // {999, 0, 2, 0} => 2
508  ranking_expected = {0, 1, 4, 2, 7, 3, 6, 8, 5, 9};
509  cb_data_epsilon_0_skype_jb_test_runner(999, 0, 2, 0, ranking_expected, pdf_expected);
510 }
511 
513 {
514  // clean features
515  shared.clear();
516  ex[0].clear();
517  ex[1].clear();
518  ex[2].clear();
519 
520  // shared |a 0:1 5:12
521  example_predict_builder bs(&shared, (char*)"a");
522  bs.push_feature(0, 1.f);
523  bs.push_feature(5, 12.f);
524 
525  // |b 0:1
526  example_predict_builder b0(&ex[0], (char*)"b");
527  b0.push_feature(0, 1.f);
528  // |b 0:2
529  example_predict_builder b1(&ex[1], (char*)"b");
530  b1.push_feature(0, 2.f);
531  // |b 0:3
532  example_predict_builder b2(&ex[2], (char*)"b");
533  b2.push_feature(0, 3.f);
534 }
535 
536 std::string generate_string_seed(size_t i)
537 {
538  std::stringstream s;
539  s << "abcde" << i;
540  return s.str();
541 }
542 
544 {
545  const char* description;
546  const char* model_filename;
547 
549 
550  std::vector<float> pdf_expected;
551  std::vector<float> ranking_pdf_expected;
552 };
553 
554 // nice rendering in unit tests
555 ::std::ostream& operator<<(::std::ostream& os, const CBPredictParam& param)
556 {
557  return os << param.description << " " << param.model_filename;
558 }
559 
560 class CBPredictTest : public ::testing::TestWithParam<CBPredictParam>
561 {
562 };
563 
564 TEST_P(CBPredictTest, CBRunPredict)
565 {
567  test_data td = get_test_data(GetParam().model_filename);
568  ASSERT_EQ(S_VW_PREDICT_OK, vw.load((const char*)td.model, td.model_len));
569 
570  EXPECT_TRUE(vw.is_cb_explore_adf());
571 
572  std::vector<float> pdf_expected = GetParam().pdf_expected;
573  std::vector<float> histogram(pdf_expected.size() * pdf_expected.size());
574 
576  safe_example_predict ex[3];
577 
578  std::vector<int> ranking;
579 
580  generate_cb_data_5(shared, ex);
581 
582  size_t rep = GetParam().replications;
583  for (size_t i = 0; i < rep; i++)
584  {
585  std::vector<float> pdf;
586 
587  // invoke prediction
588  ASSERT_EQ(S_VW_PREDICT_OK, vw.predict(generate_string_seed(i).c_str(), shared, ex, 3, pdf, ranking));
589 
590  ASSERT_EQ(pdf_expected.size(), ranking.size());
591  for (size_t i = 0; i < ranking.size(); i++) histogram[i * ranking.size() + ranking[i]]++;
592  }
593 
594  for (auto& d : histogram) d /= rep;
595 
596 #ifdef VW_SLIM_TEST_DEBUG
597  // std::fstream log(VW_SLIM_TEST_DEBUG, std::fstream::app);
598  // for (size_t i = 0; i < 3; i++)
599  //{
600  // log << "slot " << i << " ";
601  // for (size_t j = 0; j < 3; j++)
602  // log << histogram[i * 3 + j] << " ";
603  // log << std::endl;
604  //}
605 #endif
606 
607  EXPECT_THAT(histogram, Pointwise(FloatNearPointwise(1e-2f), GetParam().ranking_pdf_expected));
608 }
609 
611  {"CB Epsilon Greedy", "cb_data_5", 10000, {0.1f, 0.1f, 0.8f},
612  {
613  // see top action 2 w / 0.8
614  0.1f, 0.09f, 0.80f, // slot 0
615  // most of the time we should see action 2
616  // in 10% we should see the top action 0 swapped from top-slot to here
617  0.0f, 0.90f, 0.09f, // slot 1
618  // most of the time we should see action 1
619  // in 20% we should see the top action 2 swapped from top-slot to here
620  0.89f, 0.0f, 0.10f, // slot 2
621  }},
622  {"CB Softmax", "cb_data_6", 1000, {0.329f, 0.333f, 0.337f},
623  {
624  0.328f, 0.354f, 0.316f, // slot 0
625  0.000f, 0.644f, 0.354f, // slot 1
626  0.671f, 0.000f, 0.328f, // slot 2
627  }},
628  {"CB Bag", "cb_data_7", 5, {0.0f, 0.0f, 1.0f},
629  {
630  0.0f, 0.0f, 1.0f, // slot 0
631  0.0f, 1.0f, 0.0f, // slot 1
632  1.0f, 0.0f, 0.0f, // slot 2
633  }},
634  {"CB Bag Epsilon Greedy", "cb_data_8", 10000, {0.09f, 0.09f, 0.82f},
635  {
636  0.091f, 0.086f, 0.82f, // slot 0
637  0.00f, 0.91f, 0.086f, // slot 1
638  0.90f, 0.00f, 0.09f, // slot 2
639  }},
640 };
641 
642 INSTANTIATE_TEST_SUITE_P(VowpalWabbitSlim, CBPredictTest, ::testing::ValuesIn(cb_predict_params));
643 
644 // Test fixture to allow for both sparse and dense parameters
645 template <typename W>
646 class VwSlimTest : public ::testing::Test
647 {
648 };
649 
651 
652 typedef ::testing::Types<sparse_parameters, dense_parameters> WeightParameters;
653 
654 TYPED_TEST_P(VwSlimTest, model_not_loaded)
655 {
657  example_predict ex;
658  example_predict* actions = nullptr;
659  std::vector<float> scores;
660  std::vector<int> ranking;
661  float score;
662 
663  EXPECT_EQ(E_VW_PREDICT_ERR_NO_MODEL_LOADED, vw.predict(ex, score));
664 
665  EXPECT_EQ(E_VW_PREDICT_ERR_NO_MODEL_LOADED, vw.predict(ex, actions, 0, scores));
666  EXPECT_EQ(E_VW_PREDICT_ERR_NO_MODEL_LOADED, vw.predict("abc", ex, actions, 0, scores, ranking));
667 }
668 
669 TYPED_TEST_P(VwSlimTest, model_reduction_mismatch)
670 {
672  example_predict ex;
673  example_predict* actions = nullptr;
674  std::vector<float> scores;
675  std::vector<int> ranking;
676 
677  test_data td = get_test_data("regression_data_1");
678  ASSERT_EQ(0, vw.load((const char*)td.model, td.model_len));
679 
680  EXPECT_EQ(E_VW_PREDICT_ERR_NO_A_CSOAA_MODEL, vw.predict(ex, actions, 0, scores));
681  EXPECT_EQ(E_VW_PREDICT_ERR_NOT_A_CB_MODEL, vw.predict("abc", ex, actions, 0, scores, ranking));
682 }
683 
684 TYPED_TEST_P(VwSlimTest, model_corrupted)
685 {
686  test_data td = get_test_data("regression_data_1");
687 
689 
690  size_t num_bytes_to_corrupt = 10;
691  float rand = 0;
692  for (size_t i = 0; i < 100; i++)
693  {
694  std::vector<char> model_copy(td.model, td.model + td.model_len);
695  for (size_t j = 0; j < num_bytes_to_corrupt; j++)
696  {
697  rand = uniform_random_merand48((uint64_t)rand);
698  size_t random_idx = (size_t)(rand * model_copy.size());
699 
700  rand = uniform_random_merand48((uint64_t)rand);
701 
702  model_copy[random_idx] = (char)rand;
703 
704  ASSERT_NE(0, vw.load((const char*)&model_copy[0], model_copy.size()));
705  }
706  }
707 }
708 
709 REGISTER_TYPED_TEST_SUITE_P(VwSlimTest, model_not_loaded, model_reduction_mismatch, model_corrupted);
711 
712 TEST(ColdStartModel, action_set_not_reordered)
713 {
714  std::ifstream input("data/cold_start.model", std::ios::in | std::ios::binary);
715  input.seekg(0, std::ios::end);
716  auto length = input.tellg();
717  input.seekg(0, std::ios::beg);
718  std::unique_ptr<char> buffer_ptr(new char[length]);
719  input.read(buffer_ptr.get(), length);
720 
722 
723  int result = vw.load(buffer_ptr.get(), length);
724  EXPECT_EQ(result, 0);
725 
727 
728  vw_slim::example_predict_builder bOa(&features, "Features", vw.feature_index_num_bits());
729  bOa.push_feature_string("f1", 1.f);
730 
731  const int NUM_ACTIONS = 5;
732  std::array<safe_example_predict, NUM_ACTIONS> actions;
733  for (int i = 0; i < actions.size(); i++)
734  {
735  vw_slim::example_predict_builder bOe(&actions[i], "ActionFeatures");
736  bOe.push_feature(i, 1.f);
737  }
738 
739  std::string uuidString("EventId_0");
740 
741  std::vector<float> pdfs;
742  std::vector<int> rankings;
743 
744  result = vw.predict(uuidString.c_str(), features, actions.data(), NUM_ACTIONS, pdfs, rankings);
745 
746  EXPECT_GT(pdfs[0], 0.8);
747  EXPECT_GT(pdfs[0], pdfs[1]);
748  EXPECT_THAT(rankings, ElementsAre(0, 1, 2, 3, 4));
749 }
void push_feature(feature_index feature_idx, feature_value value)
#define E_VW_PREDICT_ERR_NOT_A_CB_MODEL
Definition: bs.cc:23
#define S_VW_PREDICT_OK
unsigned int regression_data_1_model_len
Definition: data.h:8
const char * name
Definition: ut_vw.cc:295
bool is_cb_explore_adf()
True if the model describes a contextual bandit (cb) model using action dependent features (afd) ...
PredictParamWeightType weight_type
Definition: ut_vw.cc:299
CBPredictParam cb_predict_params[]
Definition: ut_vw.cc:610
Definition: ut_vw.cc:222
int replications
Definition: ut_vw.cc:548
unsigned char regression_data_6_model[]
Definition: data.h:83
Vowpal Wabbit slim predictor. Supports: regression, multi-class classification and contextual bandits...
const char * model_filename
Definition: ut_vw.cc:228
INSTANTIATE_TYPED_TEST_SUITE_P(VowpalWabbitSlim, VwSlimTest, WeightParameters)
TYPED_TEST_SUITE_P(VwSlimTest)
the core definition of a set of features.
const char * data_filename
Definition: ut_vw.cc:229
unsigned int regression_data_6_model_len
Definition: data.h:92
InvalidModelParam invalid_model_param[]
Definition: ut_vw.cc:337
unsigned int model_len
Definition: ut_vw.cc:54
std::vector< float > pdf_expected
Definition: ut_vw.cc:550
void run_predict_in_memory(const char *model_filename, const char *data_filename, const char *prediction_reference_filename)
Definition: ut_vw.cc:96
void cb_data_epsilon_0_skype_jb_test_runner(int call_type, int modality, int network_type, int platform, std::vector< int > ranking_expected, std::vector< float > pdf_expected)
Definition: ut_vw.cc:382
INSTANTIATE_TEST_SUITE_P(VowpalWabbitSlim, PredictTest, ::testing::ValuesIn(GenerateTestParams()))
membuf(char *begin, char *end)
Definition: ut_vw.cc:26
Definition: ut_vw.cc:223
const char * prediction_reference_filename
Definition: ut_vw.cc:230
unsigned char * pred
Definition: ut_vw.cc:55
void generate_cb_data_5(safe_example_predict &shared, safe_example_predict *ex)
Definition: ut_vw.cc:512
int load(const char *model, size_t length)
Reads the Vowpal Wabbit model from the supplied buffer (produced using vw -f <modelname>) ...
unsigned char * model
Definition: ut_vw.cc:53
const char * description
Definition: ut_vw.cc:545
REGISTER_TYPED_TEST_SUITE_P(VwSlimTest, model_not_loaded, model_reduction_mismatch, model_corrupted)
const char * model_filename
Definition: ut_vw.cc:546
unsigned char namespace_index
std::vector< float > ranking_pdf_expected
Definition: ut_vw.cc:551
Definition: ut_vw.cc:221
Definition: ut_vw.cc:24
unsigned int pred_len
Definition: ut_vw.cc:56
unsigned char regression_data_1_model[]
Definition: data.h:2
TEST_P(PredictTest, Run)
Definition: ut_vw.cc:245
uint32_t feature_index_num_bits()
#define E_VW_PREDICT_ERR_NO_A_CSOAA_MODEL
unsigned int model_len
Definition: ut_vw.cc:297
TYPED_TEST_P(VwSlimTest, model_not_loaded)
Definition: ut_vw.cc:654
void push_feature_string(char *feature_idx, feature_value value)
std::vector< PredictParam > GenerateTestParams()
Definition: ut_vw.cc:255
PredictParamWeightType
Definition: ut_vw.cc:219
test_data get_test_data(const char *model_filename)
Definition: ut_vw.cc:70
#define E_VW_PREDICT_ERR_NO_MODEL_LOADED
TEST(VowpalWabbitSlim, multiclass_data_4)
Definition: ut_vw.cc:348
::std::ostream & operator<<(::std::ostream &os, const PredictParam &param)
Definition: ut_vw.cc:235
#define TEST_DATA(input, filename)
Definition: ut_vw.cc:59
PredictParamWeightType weight_type
Definition: ut_vw.cc:231
unsigned char * model
Definition: ut_vw.cc:296
std::string generate_string_seed(size_t i)
Definition: ut_vw.cc:536
::testing::Types< sparse_parameters, dense_parameters > WeightParameters
Definition: ut_vw.cc:652
std::set< size_t > undetectable_offsets
Definition: ut_vw.cc:298
int predict(example_predict &ex, float &score)
Predicts a score (as in regression) for the provided example.
float f
Definition: cache.cc:40
std::vector< float > read_floats(std::istream &data)
Definition: ut_vw.cc:29
float uniform_random_merand48(uint64_t initial)