Vowpal Wabbit
interact.cc
Go to the documentation of this file.
1 /*
2 Copyright (c) by respective owners including Yahoo!, Microsoft, and
3 individual contributors. All rights reserved. Released under a BSD (revised)
4 license as described in the file LICENSE.
5  */
6 #include <sstream>
7 #include <cfloat>
8 #include "reductions.h"
9 #include "v_array.h"
10 
11 using namespace VW::config;
12 
13 struct interact
14 {
15  unsigned char n1, n2; // namespaces to interact
17  vw* all;
18  float n1_feat_sq;
20  size_t num_features;
21 
22  ~interact() { feat_store.delete_v(); }
23 };
24 
25 bool contains_valid_namespaces(vw& all, features& f_src1, features& f_src2, interact& in)
26 {
27  // first feature must be 1 so we're sure that the anchor feature is present
28  if (f_src1.size() == 0 || f_src2.size() == 0)
29  return false;
30 
31  if (f_src1.values[0] != 1)
32  {
33  all.trace_message << "Namespace '" << (char)in.n1 << "' misses anchor feature with value 1";
34  return false;
35  }
36 
37  if (f_src2.values[0] != 1)
38  {
39  all.trace_message << "Namespace '" << (char)in.n2 << "' misses anchor feature with value 1";
40  return false;
41  }
42 
43  return true;
44 }
45 
46 void multiply(features& f_dest, features& f_src2, interact& in)
47 {
48  f_dest.clear();
49  features& f_src1 = in.feat_store;
50  vw* all = in.all;
51  uint64_t weight_mask = all->weights.mask();
52  uint64_t base_id1 = f_src1.indicies[0] & weight_mask;
53  uint64_t base_id2 = f_src2.indicies[0] & weight_mask;
54 
55  f_dest.push_back(f_src1.values[0] * f_src2.values[0], f_src1.indicies[0]);
56 
57  uint64_t prev_id1 = 0;
58  uint64_t prev_id2 = 0;
59 
60  for (size_t i1 = 1, i2 = 1; i1 < f_src1.size() && i2 < f_src2.size();)
61  {
62  // calculating the relative offset from the namespace offset used to match features
63  uint64_t cur_id1 = (uint64_t)(((f_src1.indicies[i1] & weight_mask) - base_id1) & weight_mask);
64  uint64_t cur_id2 = (uint64_t)(((f_src2.indicies[i2] & weight_mask) - base_id2) & weight_mask);
65 
66  // checking for sorting requirement
67  if (cur_id1 < prev_id1)
68  {
69  std::cout << "interact features are out of order: " << cur_id1 << " < " << prev_id1 << ". Skipping features."
70  << std::endl;
71  return;
72  }
73 
74  if (cur_id2 < prev_id2)
75  {
76  std::cout << "interact features are out of order: " << cur_id2 << " < " << prev_id2 << ". Skipping features."
77  << std::endl;
78  return;
79  }
80 
81  if (cur_id1 == cur_id2)
82  {
83  f_dest.push_back(f_src1.values[i1] * f_src2.values[i2], f_src1.indicies[i1]);
84  i1++;
85  i2++;
86  }
87  else if (cur_id1 < cur_id2)
88  i1++;
89  else
90  i2++;
91  prev_id1 = cur_id1;
92  prev_id2 = cur_id2;
93  }
94 }
95 
96 template <bool is_learn, bool print_all>
98 {
99  features& f1 = ec.feature_space[in.n1];
100  features& f2 = ec.feature_space[in.n2];
101 
102  if (!contains_valid_namespaces(*in.all, f1, f2, in))
103  {
104  if (is_learn)
105  base.learn(ec);
106  else
107  base.predict(ec);
108 
109  return;
110  }
111 
112  in.num_features = ec.num_features;
116  ec.num_features -= f1.size();
117  ec.num_features -= f2.size();
118 
119  in.feat_store.deep_copy_from(f1);
120 
121  multiply(f1, f2, in);
123  ec.num_features += f1.size();
124 
125  /*for(uint64_t i = 0;i < f1.size();i++)
126  std::cout<<f1[i].weight_index<<":"<<f1[i].x<<" ";
127  std::cout<< std::endl;*/
128 
129  // remove 2nd namespace
130  int n2_i = -1;
131  for (size_t i = 0; i < ec.indices.size(); i++)
132  {
133  if (ec.indices[i] == in.n2)
134  {
135  n2_i = (int)i;
136  memmove(&ec.indices[n2_i], &ec.indices[n2_i + 1], sizeof(unsigned char) * (ec.indices.size() - n2_i - 1));
137  ec.indices.decr();
138  break;
139  }
140  }
141 
142  base.predict(ec);
143  if (is_learn)
144  base.learn(ec);
145 
146  // re-insert namespace into the right position
147  ec.indices.incr();
148  memmove(&ec.indices[n2_i + 1], &ec.indices[n2_i], sizeof(unsigned char) * (ec.indices.size() - n2_i - 1));
149  ec.indices[n2_i] = in.n2;
150 
151  f1.deep_copy_from(in.feat_store);
153  ec.num_features = in.num_features;
154 }
155 
157 {
158  std::string s;
159  option_group_definition new_options("Interact via elementwise multiplication");
160  new_options.add(
161  make_option("interact", s).keep().help("Put weights on feature products from namespaces <n1> and <n2>"));
162  options.add_and_parse(new_options);
163 
164  if (!options.was_supplied("interact"))
165  return nullptr;
166 
167  if (s.length() != 2)
168  {
169  std::cerr << "Need two namespace arguments to interact: " << s << " won't do EXITING\n";
170  return nullptr;
171  }
172 
173  auto data = scoped_calloc_or_throw<interact>();
174 
175  data->n1 = (unsigned char)s[0];
176  data->n2 = (unsigned char)s[1];
177  if (!all.quiet)
178  std::cerr << "Interacting namespaces " << data->n1 << " and " << data->n2 << std::endl;
179  data->all = &all;
180 
183  data, as_singleline(setup_base(options, all)), predict_or_learn<true, true>, predict_or_learn<false, true>, 1);
184 
185  return make_base(*l);
186 }
bool contains_valid_namespaces(vw &all, features &f_src1, features &f_src2, interact &in)
Definition: interact.cc:25
v_array< namespace_index > indices
parameters weights
Definition: global_data.h:537
void predict(E &ec, size_t i=0)
Definition: learner.h:169
void incr()
Definition: v_array.h:61
void deep_copy_from(const features &src)
~interact()
Definition: interact.cc:22
void push_back(feature_value v, feature_index i)
v_array< feature_index > indicies
unsigned char n2
Definition: interact.cc:15
void delete_v()
the core definition of a set of features.
base_learner * make_base(learner< T, E > &base)
Definition: learner.h:462
bool quiet
Definition: global_data.h:487
v_array< feature_value > values
virtual void add_and_parse(const option_group_definition &group)=0
float n1_feat_sq
Definition: interact.cc:18
size_t size() const
Definition: v_array.h:68
std::array< features, NUM_NAMESPACES > feature_space
single_learner * as_singleline(learner< T, E > *l)
Definition: learner.h:476
size_t size() const
learner< T, E > & init_learner(free_ptr< T > &dat, L *base, void(*learn)(T &, L &, E &), void(*predict)(T &, L &, E &), size_t ws, prediction_type::prediction_type_t pred_type)
Definition: learner.h:369
void multiply(features &f_dest, features &f_src2, interact &in)
Definition: interact.cc:46
vw_ostream trace_message
Definition: global_data.h:424
size_t num_features
Definition: example.h:67
virtual bool was_supplied(const std::string &key)=0
size_t num_features
Definition: interact.cc:20
void clear()
LEARNER::base_learner * interact_setup(options_i &options, vw &all)
Definition: interact.cc:156
void predict_or_learn(interact &in, LEARNER::single_learner &base, example &ec)
Definition: interact.cc:97
option_group_definition & add(T &&op)
Definition: options.h:90
typed_option< T > make_option(std::string name, T &location)
Definition: options.h:80
float total_sum_feat_sq
Definition: example.h:71
features feat_store
Definition: interact.cc:16
float sum_feat_sq
vw * all
Definition: interact.cc:17
float total_sum_feat_sq
Definition: interact.cc:19
LEARNER::base_learner * setup_base(options_i &options, vw &all)
Definition: parse_args.cc:1222
void learn(E &ec, size_t i=0)
Definition: learner.h:160
void decr()
Definition: v_array.h:60
uint64_t mask()
unsigned char n1
Definition: interact.cc:15