Vowpal Wabbit
array_parameters.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <string.h>
4 #include <unordered_map>
5 #include <cstddef>
6 
7 #ifndef _WIN32
8 #define NOMINMAX
9 #include <sys/mman.h>
10 #endif
11 
12 // It appears that on OSX MAP_ANONYMOUS is mapped to MAP_ANON
13 // https://github.com/leftmike/foment/issues/4
14 #ifdef __APPLE__
15 #define MAP_ANONYMOUS MAP_ANON
16 #endif
17 
18 #include "array_parameters_dense.h"
19 #include "vw_exception.h"
20 
22 typedef std::unordered_map<uint64_t, weight*> weight_map;
23 
24 template <typename T>
26 {
27  private:
28  weight_map::iterator _iter;
29  uint32_t _stride;
30 
31  public:
32  typedef std::forward_iterator_tag iterator_category;
33  typedef T value_type;
34  typedef ptrdiff_t difference_type;
35  typedef T* pointer;
36  typedef T& reference;
37 
38  sparse_iterator(weight_map::iterator& iter, uint32_t stride) : _iter(iter), _stride(stride) {}
39 
41  {
42  _iter = other._iter;
43  _stride = other._stride;
44  return *this;
45  }
46  uint64_t index() { return _iter->first; }
47 
48  T& operator*() { return *(_iter->second); }
49 
51  {
52  _iter++;
53  return *this;
54  }
55 
56  bool operator==(const sparse_iterator& rhs) const { return _iter == rhs._iter; }
57  bool operator!=(const sparse_iterator& rhs) const { return _iter != rhs._iter; }
58 };
59 
61 {
62  private:
64  uint64_t _weight_mask; // (stride*(1 << num_bits) -1)
65  uint32_t _stride_shift;
66  bool _seeded; // whether the instance is sharing model state with others
67  bool _delete;
68  void* default_data;
69  float* default_value;
70 
71  public:
74 
75  private:
76  void (*fun)(const weight*, void*);
77 
78  public:
79  sparse_parameters(size_t length, uint32_t stride_shift = 0)
80  : _map()
81  , _weight_mask((length << stride_shift) - 1)
82  , _stride_shift(stride_shift)
83  , _seeded(false)
84  , _delete(false)
85  , default_data(nullptr)
86  , fun(nullptr)
87  {
88  default_value = calloc_mergable_or_throw<weight>(stride());
89  }
90 
92  : _map(), _weight_mask(0), _stride_shift(0), _seeded(false), _delete(false), default_data(nullptr), fun(nullptr)
93  {
94  default_value = calloc_mergable_or_throw<weight>(stride());
95  }
96 
97  bool not_null() { return (_weight_mask > 0 && !_map.empty()); }
98 
99  sparse_parameters(const sparse_parameters& other) { shallow_copy(other); }
101 
102  weight* first() { THROW_OR_RETURN("Allreduce currently not supported in sparse", nullptr); }
103 
104  // iterator with stride
105  iterator begin()
106  {
107  weight_map::iterator i = _map.begin();
108  return iterator(i, stride());
109  }
110  iterator end()
111  {
112  weight_map::iterator i = _map.end();
113  return iterator(i, stride());
114  }
115 
116  // const iterator
117  const_iterator cbegin()
118  {
119  weight_map::iterator i = _map.begin();
120  return const_iterator(i, stride());
121  }
122  const_iterator cend()
123  {
124  weight_map::iterator i = _map.begin();
125  return const_iterator(i, stride());
126  }
127 
128  inline weight& operator[](size_t i)
129  {
130  uint64_t index = i & _weight_mask;
131  weight_map::iterator iter = _map.find(index);
132  if (iter == _map.end())
133  {
134  _map.insert(std::make_pair(index, calloc_mergable_or_throw<weight>(stride())));
135  iter = _map.find(index);
136  if (fun != nullptr)
137  fun(iter->second, default_data);
138  }
139  return *(iter->second);
140  }
141 
142  inline const weight& operator[](size_t i) const
143  {
144  uint64_t index = i & _weight_mask;
145  weight_map::const_iterator iter = _map.find(index);
146  if (iter == _map.end())
147  return *default_value;
148  return *(iter->second);
149  }
150 
151  inline weight& strided_index(size_t index) { return operator[](index << _stride_shift); }
152 
153  void shallow_copy(const sparse_parameters& input)
154  {
155  // TODO: this is level-1 copy (weight* are stilled shared)
156  if (!_seeded)
157  {
158  for (auto iter = _map.begin(); iter != _map.end(); ++iter) free(iter->second);
159  }
160  _map = input._map;
161  _weight_mask = input._weight_mask;
162  _stride_shift = input._stride_shift;
163  free(default_value);
164  default_value = calloc_mergable_or_throw<weight>(stride());
165  memcpy(default_value, input.default_value, stride());
166  default_data = input.default_data;
167  _seeded = true;
168  }
169 
170  template <class R, class T>
171  void set_default(R& info)
172  {
173  R& new_R = calloc_or_throw<R>();
174  new_R = info;
175  default_data = &new_R;
176  fun = (void (*)(const weight*, void*))T::func;
177  fun(default_value, default_data);
178  }
179 
180  template <class T>
181  void set_default()
182  {
183  fun = (void (*)(const weight*, void*))T::func;
184  }
185 
186  void set_zero(size_t offset)
187  {
188  for (weight_map::iterator iter = _map.begin(); iter != _map.end(); ++iter) (&(*(iter->second)))[offset] = 0;
189  }
190 
191  uint64_t mask() const { return _weight_mask; }
192 
193  uint64_t seeded() const { return _seeded; }
194 
195  uint32_t stride() const { return 1 << _stride_shift; }
196 
197  uint32_t stride_shift() const { return _stride_shift; }
198 
199  void stride_shift(uint32_t stride_shift)
200  {
201  _stride_shift = stride_shift;
202  free(default_value);
203  default_value = calloc_mergable_or_throw<weight>(stride());
204  if (fun != nullptr)
205  fun(default_value, default_data);
206  }
207 
208 #ifndef _WIN32
209  void share(size_t /* length */) { THROW_OR_RETURN("Operation not supported on Windows"); }
210 #endif
211 
213  {
214  if (!_delete && !_seeded) // don't free weight vector if it is shared with another instance
215  {
216  for (auto iter = _map.begin(); iter != _map.end(); ++iter) free(iter->second);
217  _map.clear();
218  _delete = true;
219  }
220  if (default_data != nullptr)
221  free(default_data);
222  free(default_value);
223  }
224 };
225 
227 {
228  public:
229  bool adaptive;
231 
232  bool sparse;
235 
236  inline weight& operator[](size_t i)
237  {
238  if (sparse)
239  return sparse_weights[i];
240  else
241  return dense_weights[i];
242  }
243 
244  inline uint32_t stride_shift()
245  {
246  if (sparse)
247  return sparse_weights.stride_shift();
248  else
249  return dense_weights.stride_shift();
250  }
251 
252  inline uint32_t stride()
253  {
254  if (sparse)
255  return sparse_weights.stride();
256  else
257  return dense_weights.stride();
258  }
259 
260  inline uint64_t mask()
261  {
262  if (sparse)
263  return sparse_weights.mask();
264  else
265  return dense_weights.mask();
266  }
267 
268  inline uint64_t seeded()
269  {
270  if (sparse)
271  return sparse_weights.seeded();
272  else
273  return dense_weights.seeded();
274  }
275 
276  inline void shallow_copy(const parameters& input)
277  {
278  if (sparse)
279  sparse_weights.shallow_copy(input.sparse_weights);
280  else
281  dense_weights.shallow_copy(input.dense_weights);
282  }
283 
284  inline void set_zero(size_t offset)
285  {
286  if (sparse)
287  sparse_weights.set_zero(offset);
288  else
289  dense_weights.set_zero(offset);
290  }
291 #ifndef _WIN32
292 #ifndef DISABLE_SHARED_WEIGHTS
293  inline void share(size_t length)
294  {
295  if (sparse)
296  sparse_weights.share(length);
297  else
298  dense_weights.share(length);
299  }
300 #endif
301 #endif
302 
303  inline void stride_shift(uint32_t stride_shift)
304  {
305  if (sparse)
306  sparse_weights.stride_shift(stride_shift);
307  else
308  dense_weights.stride_shift(stride_shift);
309  }
310 
311  inline weight& strided_index(size_t index)
312  {
313  if (sparse)
314  return sparse_weights.strided_index(index);
315  else
316  return dense_weights.strided_index(index);
317  }
318 
319  inline bool not_null()
320  {
321  if (sparse)
322  return sparse_weights.not_null();
323  else
324  return dense_weights.not_null();
325  }
326 };
uint64_t seeded() const
const weight & operator[](size_t i) const
void stride_shift(uint32_t stride_shift)
weight & operator[](size_t i)
uint64_t stride_shift(const stagewise_poly &poly, uint64_t idx)
bool operator!=(const sparse_iterator &rhs) const
uint32_t stride_shift() const
uint32_t stride()
sparse_iterator< weight > iterator
void set_default(R &info)
void shallow_copy(const sparse_parameters &input)
void set_zero(size_t offset)
bool operator==(const sparse_iterator &rhs) const
sparse_iterator & operator++()
uint32_t stride() const
weight & strided_index(size_t index)
void stride_shift(uint32_t stride_shift)
void share(size_t length)
sparse_iterator< const weight > const_iterator
void set_zero(size_t offset)
uint32_t stride() const
void share(size_t length)
dense_parameters dense_weights
uint64_t mask() const
weight & strided_index(size_t index)
void set_zero(size_t offset)
sparse_parameters(const sparse_parameters &other)
sparse_iterator & operator=(const sparse_iterator &other)
ptrdiff_t difference_type
float weight
weight & strided_index(size_t index)
std::forward_iterator_tag iterator_category
#define THROW_OR_RETURN(...)
Definition: vw_exception.h:208
std::unordered_map< uint64_t, weight * > weight_map
sparse_parameters sparse_weights
sparse_parameters(size_t length, uint32_t stride_shift=0)
weight_map::iterator _iter
uint32_t stride_shift()
weight & operator[](size_t i)
const_iterator cend()
uint64_t seeded()
void shallow_copy(const parameters &input)
const_iterator cbegin()
void shallow_copy(const dense_parameters &input)
uint64_t mask()
uint32_t stride_shift() const
sparse_iterator(weight_map::iterator &iter, uint32_t stride)
uint64_t seeded() const