Vowpal Wabbit
lda_core.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 #ifdef _WIN32
7 #pragma warning(disable : 4996) // generated by inner_product use
8 #endif
9 #include <fstream>
10 #include <vector>
11 #include <queue>
12 #include <algorithm>
13 #include <numeric>
14 #include <cmath>
15 #include "correctedMath.h"
16 #include "vw_versions.h"
17 #include "vw.h"
18 #include "mwt.h"
19 #include <boost/math/special_functions/digamma.hpp>
20 #include <boost/math/special_functions/gamma.hpp>
21 
22 #ifdef _WIN32
23 #define NOMINMAX
24 #include <winsock2.h>
25 #else
26 #include <netdb.h>
27 #endif
28 
29 #include <cstring>
30 #include <cstdio>
31 #include <cassert>
32 #include "no_label.h"
33 #include "gd.h"
34 #include "rand48.h"
35 #include "reductions.h"
36 #include "array_parameters.h"
37 #include <boost/version.hpp>
38 
39 #if BOOST_VERSION >= 105600
40 #include <boost/align/is_aligned.hpp>
41 #endif
42 
43 using namespace VW::config;
44 
46 {
50 };
51 
53 {
54  public:
55  uint32_t document;
57  bool operator<(const index_feature b) const { return f.weight_index < b.f.weight_index; }
58 };
59 
60 struct lda
61 {
62  size_t topics;
63  float lda_alpha;
64  float lda_rho;
65  float lda_D;
66  float lda_epsilon;
67  size_t minibatch;
69 
78  std::vector<index_feature> sorted_features;
79 
81 
82  // size by 1 << bits
83  std::vector<uint32_t> feature_counts;
84  std::vector<std::vector<size_t>> feature_to_example_map;
85 
87 
88  double example_t;
89  vw *all; // regressor, lda
90 
91  static constexpr float underflow_threshold = 1.0e-10f;
92  inline float digamma(float x);
93  inline float lgamma(float x);
94  inline float powf(float x, float p);
95  inline void expdigammify(vw &all, float *gamma);
96  inline void expdigammify_2(vw &all, float *gamma, float *norm);
97 
98  ~lda()
99  {
100  Elogtheta.delete_v();
101  decay_levels.delete_v();
102  total_new.delete_v();
103  examples.delete_v();
104  total_lambda.delete_v();
105  doc_lengths.delete_v();
106  digammas.delete_v();
107  v.delete_v();
108  }
109 };
110 
111 // #define VW_NO_INLINE_SIMD
112 
113 namespace
114 {
115 inline bool is_aligned16(void *ptr)
116 {
117 #if BOOST_VERSION >= 105600
118  return boost::alignment::is_aligned(16, ptr);
119 #else
120  return ((reinterpret_cast<uintptr_t>(ptr) & 0x0f) == 0);
121 #endif
122 }
123 } // namespace
124 
125 namespace ldamath
126 {
127 inline float fastlog2(float x)
128 {
129  uint32_t mx;
130  memcpy(&mx, &x, sizeof(uint32_t));
131  mx = (mx & 0x007FFFFF) | (0x7e << 23);
132 
133  float mx_f;
134  memcpy(&mx_f, &mx, sizeof(float));
135 
136  uint32_t vx;
137  memcpy(&vx, &x, sizeof(uint32_t));
138 
139  float y = static_cast<float>(vx);
140  y *= 1.0f / (float)(1 << 23);
141 
142  return y - 124.22544637f - 1.498030302f * mx_f - 1.72587999f / (0.3520887068f + mx_f);
143 }
144 
145 inline float fastlog(float x) { return 0.69314718f * fastlog2(x); }
146 
147 inline float fastpow2(float p)
148 {
149  float offset = (p < 0) * 1.0f;
150  float clipp = (p < -126.0) ? -126.0f : p;
151  int w = (int)clipp;
152  float z = clipp - w + offset;
153  uint32_t approx = (uint32_t)((1 << 23) * (clipp + 121.2740838f + 27.7280233f / (4.84252568f - z) - 1.49012907f * z));
154 
155  float v;
156  memcpy(&v, &approx, sizeof(uint32_t));
157  return v;
158 }
159 
160 inline float fastexp(float p) { return fastpow2(1.442695040f * p); }
161 
162 inline float fastpow(float x, float p) { return fastpow2(p * fastlog2(x)); }
163 
164 inline float fastlgamma(float x)
165 {
166  float logterm = fastlog(x * (1.0f + x) * (2.0f + x));
167  float xp3 = 3.0f + x;
168 
169  return -2.081061466f - x + 0.0833333f / xp3 - logterm + (2.5f + x) * fastlog(xp3);
170 }
171 
172 inline float fastdigamma(float x)
173 {
174  float twopx = 2.0f + x;
175  float logterm = fastlog(twopx);
176 
177  return -(1.0f + 2.0f * x) / (x * (1.0f + x)) - (13.0f + 6.0f * x) / (12.0f * twopx * twopx) + logterm;
178 }
179 
180 #if !defined(VW_NO_INLINE_SIMD)
181 
182 #if defined(__SSE2__) || defined(__SSE3__) || defined(__SSE4_1__)
183 
184 // Include headers for the various SSE versions:
185 #if defined(__SSE2__)
186 #include <emmintrin.h>
187 #endif
188 #if defined(__SSE3__)
189 #include <tmmintrin.h>
190 #endif
191 #if defined(__SSE4_1__)
192 #include <smmintrin.h>
193 #endif
194 
195 #define HAVE_SIMD_MATHMODE
196 
197 typedef __m128 v4sf;
198 typedef __m128i v4si;
199 
200 inline v4sf v4si_to_v4sf(v4si x) { return _mm_cvtepi32_ps(x); }
201 
202 inline v4si v4sf_to_v4si(v4sf x) { return _mm_cvttps_epi32(x); }
203 
204 // Extract v[idx]
205 template <const int idx>
206 float v4sf_index(const v4sf x)
207 {
208 #if defined(__SSE4_1__)
209  float ret;
210  uint32_t val;
211 
212  val = _mm_extract_ps(x, idx);
213  // Portably convert uint32_t bit pattern to float. Optimizers will generally
214  // make this disappear.
215  memcpy(&ret, &val, sizeof(uint32_t));
216  return ret;
217 #else
218  return _mm_cvtss_f32(_mm_shuffle_ps(x, x, _MM_SHUFFLE(idx, idx, idx, idx)));
219 #endif
220 }
221 
222 // Specialization for the 0'th element
223 template <>
224 float v4sf_index<0>(const v4sf x)
225 {
226  return _mm_cvtss_f32(x);
227 }
228 
229 inline v4sf v4sfl(const float x) { return _mm_set1_ps(x); }
230 
231 inline v4si v4sil(const uint32_t x) { return _mm_set1_epi32(x); }
232 
233 #ifdef WIN32
234 
235 inline __m128 operator+(const __m128 a, const __m128 b) { return _mm_add_ps(a, b); }
236 
237 inline __m128 operator-(const __m128 a, const __m128 b) { return _mm_sub_ps(a, b); }
238 
239 inline __m128 operator*(const __m128 a, const __m128 b) { return _mm_mul_ps(a, b); }
240 
241 inline __m128 operator/(const __m128 a, const __m128 b) { return _mm_div_ps(a, b); }
242 
243 #endif
244 
245 inline v4sf vfastpow2(const v4sf p)
246 {
247  v4sf ltzero = _mm_cmplt_ps(p, v4sfl(0.0f));
248  v4sf offset = _mm_and_ps(ltzero, v4sfl(1.0f));
249  v4sf lt126 = _mm_cmplt_ps(p, v4sfl(-126.0f));
250  v4sf clipp = _mm_andnot_ps(lt126, p) + _mm_and_ps(lt126, v4sfl(-126.0f));
251  v4si w = v4sf_to_v4si(clipp);
252  v4sf z = clipp - v4si_to_v4sf(w) + offset;
253 
254  const v4sf c_121_2740838 = v4sfl(121.2740838f);
255  const v4sf c_27_7280233 = v4sfl(27.7280233f);
256  const v4sf c_4_84252568 = v4sfl(4.84252568f);
257  const v4sf c_1_49012907 = v4sfl(1.49012907f);
258 
259  v4sf v = v4sfl(1 << 23) * (clipp + c_121_2740838 + c_27_7280233 / (c_4_84252568 - z) - c_1_49012907 * z);
260 
261  return _mm_castsi128_ps(v4sf_to_v4si(v));
262 }
263 
264 inline v4sf vfastexp(const v4sf p)
265 {
266  const v4sf c_invlog_2 = v4sfl(1.442695040f);
267 
268  return vfastpow2(c_invlog_2 * p);
269 }
270 
271 inline v4sf vfastlog2(v4sf x)
272 {
273  v4si vx_i = _mm_castps_si128(x);
274  v4sf mx_f = _mm_castsi128_ps(_mm_or_si128(_mm_and_si128(vx_i, v4sil(0x007FFFFF)), v4sil(0x3f000000)));
275  v4sf y = v4si_to_v4sf(vx_i) * v4sfl(1.1920928955078125e-7f);
276 
277  const v4sf c_124_22551499 = v4sfl(124.22551499f);
278  const v4sf c_1_498030302 = v4sfl(1.498030302f);
279  const v4sf c_1_725877999 = v4sfl(1.72587999f);
280  const v4sf c_0_3520087068 = v4sfl(0.3520887068f);
281 
282  return y - c_124_22551499 - c_1_498030302 * mx_f - c_1_725877999 / (c_0_3520087068 + mx_f);
283 }
284 
285 inline v4sf vfastlog(v4sf x)
286 {
287  const v4sf c_0_69314718 = v4sfl(0.69314718f);
288 
289  return c_0_69314718 * vfastlog2(x);
290 }
291 
292 inline v4sf vfastdigamma(v4sf x)
293 {
294  v4sf twopx = v4sfl(2.0f) + x;
295  v4sf logterm = vfastlog(twopx);
296 
297  return (v4sfl(-48.0f) + x * (v4sfl(-157.0f) + x * (v4sfl(-127.0f) - v4sfl(30.0f) * x))) /
298  (v4sfl(12.0f) * x * (v4sfl(1.0f) + x) * twopx * twopx) +
299  logterm;
300 }
301 
302 void vexpdigammify(vw &all, float *gamma, const float underflow_threshold)
303 {
304  float extra_sum = 0.0f;
305  v4sf sum = v4sfl(0.0f);
306  float *fp;
307  const float *fpend = gamma + all.lda;
308 
309  // Iterate through the initial part of the array that isn't 128-bit SIMD
310  // aligned.
311  for (fp = gamma; fp < fpend && !is_aligned16(fp); ++fp)
312  {
313  extra_sum += *fp;
314  *fp = fastdigamma(*fp);
315  }
316 
317  // Rip through the aligned portion...
318  for (; is_aligned16(fp) && fp + 4 < fpend; fp += 4)
319  {
320  v4sf arg = _mm_load_ps(fp);
321  sum = sum + arg;
322  arg = vfastdigamma(arg);
323  _mm_store_ps(fp, arg);
324  }
325 
326  for (; fp < fpend; ++fp)
327  {
328  extra_sum += *fp;
329  *fp = fastdigamma(*fp);
330  }
331 
332 #if defined(__SSE3__) || defined(__SSE4_1__)
333  // Do two horizontal adds on sum, extract the total from the 0 element:
334  sum = _mm_hadd_ps(sum, sum);
335  sum = _mm_hadd_ps(sum, sum);
336  extra_sum += v4sf_index<0>(sum);
337 #else
338  extra_sum += v4sf_index<0>(sum) + v4sf_index<1>(sum) + v4sf_index<2>(sum) + v4sf_index<3>(sum);
339 #endif
340 
341  extra_sum = fastdigamma(extra_sum);
342  sum = v4sfl(extra_sum);
343 
344  for (fp = gamma; fp < fpend && !is_aligned16(fp); ++fp)
345  {
346  *fp = fmax(underflow_threshold, fastexp(*fp - extra_sum));
347  }
348 
349  for (; is_aligned16(fp) && fp + 4 < fpend; fp += 4)
350  {
351  v4sf arg = _mm_load_ps(fp);
352  arg = arg - sum;
353  arg = vfastexp(arg);
354  arg = _mm_max_ps(v4sfl(underflow_threshold), arg);
355  _mm_store_ps(fp, arg);
356  }
357 
358  for (; fp < fpend; ++fp)
359  {
360  *fp = fmax(underflow_threshold, fastexp(*fp - extra_sum));
361  }
362 }
363 
364 void vexpdigammify_2(vw &all, float *gamma, const float *norm, const float underflow_threshold)
365 {
366  float *fp = gamma;
367  const float *np;
368  const float *fpend = gamma + all.lda;
369 
370  for (np = norm; fp < fpend && !is_aligned16(fp); ++fp, ++np)
371  *fp = fmax(underflow_threshold, fastexp(fastdigamma(*fp) - *np));
372 
373  for (; is_aligned16(fp) && fp + 4 < fpend; fp += 4, np += 4)
374  {
375  v4sf arg = _mm_load_ps(fp);
376  arg = vfastdigamma(arg);
377  v4sf vnorm = _mm_loadu_ps(np);
378  arg = arg - vnorm;
379  arg = vfastexp(arg);
380  arg = _mm_max_ps(v4sfl(underflow_threshold), arg);
381  _mm_store_ps(fp, arg);
382  }
383 
384  for (; fp < fpend; ++fp, ++np) *fp = fmax(underflow_threshold, fastexp(fastdigamma(*fp) - *np));
385 }
386 
387 #else
388 // PLACEHOLDER for future ARM NEON code
389 // Also remember to define HAVE_SIMD_MATHMODE
390 #endif
391 
392 #endif // !VW_NO_INLINE_SIMD
393 
394 // Templates for common code shared between the three math modes (SIMD, fast approximations
395 // and accurate).
396 //
397 // The generic template takes a type and a specialization flag, mtype.
398 //
399 // mtype == USE_PRECISE: Use the accurate computation for lgamma, digamma.
400 // mtype == USE_FAST_APPROX: Use the fast approximations for lgamma, digamma.
401 // mtype == USE_SIMD: Use CPU SIMD instruction
402 //
403 // The generic template is specialized for the particular accuracy setting.
404 
405 // Log gamma:
406 template <typename T, const lda_math_mode mtype>
407 inline T lgamma(T /* x */)
408 {
409  BOOST_STATIC_ASSERT_MSG(true, "ldamath::lgamma is not defined for this type and math mode.");
410 }
411 
412 // Digamma:
413 template <typename T, const lda_math_mode mtype>
414 inline T digamma(T /* x */)
415 {
416  BOOST_STATIC_ASSERT_MSG(true, "ldamath::digamma is not defined for this type and math mode.");
417 }
418 
419 // Exponential
420 template <typename T, lda_math_mode mtype>
421 inline T exponential(T /* x */)
422 {
423  BOOST_STATIC_ASSERT_MSG(true, "ldamath::exponential is not defined for this type and math mode.");
424 }
425 
426 // Powf
427 template <typename T, lda_math_mode mtype>
428 inline T powf(T /* x */, T /* p */)
429 {
430  BOOST_STATIC_ASSERT_MSG(true, "ldamath::powf is not defined for this type and math mode.");
431 }
432 
433 // High accuracy float specializations:
434 
435 template <>
436 inline float lgamma<float, USE_PRECISE>(float x)
437 {
438  return boost::math::lgamma(x);
439 }
440 template <>
441 inline float digamma<float, USE_PRECISE>(float x)
442 {
443  return boost::math::digamma(x);
444 }
445 template <>
446 inline float exponential<float, USE_PRECISE>(float x)
447 {
448  return correctedExp(x);
449 }
450 template <>
451 inline float powf<float, USE_PRECISE>(float x, float p)
452 {
453  return std::pow(x, p);
454 }
455 
456 // Fast approximation float specializations:
457 
458 template <>
459 inline float lgamma<float, USE_FAST_APPROX>(float x)
460 {
461  return fastlgamma(x);
462 }
463 template <>
464 inline float digamma<float, USE_FAST_APPROX>(float x)
465 {
466  return fastdigamma(x);
467 }
468 template <>
470 {
471  return fastexp(x);
472 }
473 template <>
474 inline float powf<float, USE_FAST_APPROX>(float x, float p)
475 {
476  return fastpow(x, p);
477 }
478 
479 // SIMD specializations:
480 
481 template <>
482 inline float lgamma<float, USE_SIMD>(float x)
483 {
485 }
486 template <>
487 inline float digamma<float, USE_SIMD>(float x)
488 {
490 }
491 template <>
492 inline float exponential<float, USE_SIMD>(float x)
493 {
495 }
496 template <>
497 inline float powf<float, USE_SIMD>(float x, float p)
498 {
499  return powf<float, USE_FAST_APPROX>(x, p);
500 }
501 
502 template <typename T, const lda_math_mode mtype>
503 inline void expdigammify(vw &all, T *gamma, T threshold, T initial)
504 {
505  T sum = digamma<T, mtype>(std::accumulate(gamma, gamma + all.lda, initial));
506 
507  std::transform(gamma, gamma + all.lda, gamma,
508  [sum, threshold](T g) { return fmax(threshold, exponential<T, mtype>(digamma<T, mtype>(g) - sum)); });
509 }
510 template <>
511 inline void expdigammify<float, USE_SIMD>(vw &all, float *gamma, float threshold, float)
512 {
513 #if defined(HAVE_SIMD_MATHMODE)
514  vexpdigammify(all, gamma, threshold);
515 #else
516  // Do something sensible if SIMD math isn't available:
517  expdigammify<float, USE_FAST_APPROX>(all, gamma, threshold, 0.0);
518 #endif
519 }
520 
521 template <typename T, const lda_math_mode mtype>
522 inline void expdigammify_2(vw &all, float *gamma, T *norm, const T threshold)
523 {
524  std::transform(gamma, gamma + all.lda, norm, gamma,
525  [threshold](float g, float n) { return fmax(threshold, exponential<T, mtype>(digamma<T, mtype>(g) - n)); });
526 }
527 template <>
528 inline void expdigammify_2<float, USE_SIMD>(vw &all, float *gamma, float *norm, const float threshold)
529 {
530 #if defined(HAVE_SIMD_MATHMODE)
531  vexpdigammify_2(all, gamma, norm, threshold);
532 #else
533  // Do something sensible if SIMD math isn't available:
534  expdigammify_2<float, USE_FAST_APPROX>(all, gamma, norm, threshold);
535 #endif
536 }
537 
538 } // namespace ldamath
539 
540 float lda::digamma(float x)
541 {
542  switch (mmode)
543  {
544  case USE_FAST_APPROX:
545  // std::cerr << "lda::digamma FAST_APPROX ";
547  case USE_PRECISE:
548  // std::cerr << "lda::digamma PRECISE ";
550  case USE_SIMD:
551  // std::cerr << "lda::digamma SIMD ";
553  default:
554  // Should not happen.
555  std::cerr << "lda::digamma: Trampled or invalid math mode, aborting" << std::endl;
556  abort();
557  return 0.0f;
558  }
559 }
560 
561 float lda::lgamma(float x)
562 {
563  switch (mmode)
564  {
565  case USE_FAST_APPROX:
566  // std::cerr << "lda::lgamma FAST_APPROX ";
568  case USE_PRECISE:
569  // std::cerr << "lda::lgamma PRECISE ";
571  case USE_SIMD:
572  // std::cerr << "lda::gamma SIMD ";
574  default:
575  std::cerr << "lda::lgamma: Trampled or invalid math mode, aborting" << std::endl;
576  abort();
577  return 0.0f;
578  }
579 }
580 
581 float lda::powf(float x, float p)
582 {
583  switch (mmode)
584  {
585  case USE_FAST_APPROX:
586  // std::cerr << "lda::powf FAST_APPROX ";
588  case USE_PRECISE:
589  // std::cerr << "lda::powf PRECISE ";
591  case USE_SIMD:
592  // std::cerr << "lda::powf SIMD ";
593  return ldamath::powf<float, USE_SIMD>(x, p);
594  default:
595  std::cerr << "lda::powf: Trampled or invalid math mode, aborting" << std::endl;
596  abort();
597  return 0.0f;
598  }
599 }
600 
601 void lda::expdigammify(vw &all, float *gamma)
602 {
603  switch (mmode)
604  {
605  case USE_FAST_APPROX:
606  ldamath::expdigammify<float, USE_FAST_APPROX>(all, gamma, underflow_threshold, 0.0f);
607  break;
608  case USE_PRECISE:
609  ldamath::expdigammify<float, USE_PRECISE>(all, gamma, underflow_threshold, 0.0f);
610  break;
611  case USE_SIMD:
612  ldamath::expdigammify<float, USE_SIMD>(all, gamma, underflow_threshold, 0.0f);
613  break;
614  default:
615  std::cerr << "lda::expdigammify: Trampled or invalid math mode, aborting" << std::endl;
616  abort();
617  }
618 }
619 
620 void lda::expdigammify_2(vw &all, float *gamma, float *norm)
621 {
622  switch (mmode)
623  {
624  case USE_FAST_APPROX:
625  ldamath::expdigammify_2<float, USE_FAST_APPROX>(all, gamma, norm, underflow_threshold);
626  break;
627  case USE_PRECISE:
628  ldamath::expdigammify_2<float, USE_PRECISE>(all, gamma, norm, underflow_threshold);
629  break;
630  case USE_SIMD:
631  ldamath::expdigammify_2<float, USE_SIMD>(all, gamma, norm, underflow_threshold);
632  break;
633  default:
634  std::cerr << "lda::expdigammify_2: Trampled or invalid math mode, aborting" << std::endl;
635  abort();
636  }
637 }
638 
639 static inline float average_diff(vw &all, float *oldgamma, float *newgamma)
640 {
641  float sum;
642  float normalizer;
643 
644  // This warps the normal sense of "inner product", but it accomplishes the same
645  // thing as the "plain old" for loop. clang does a good job of reducing the
646  // common subexpressions.
647  sum = std::inner_product(
648  oldgamma, oldgamma + all.lda, newgamma, 0.0f, [](float accum, float absdiff) { return accum + absdiff; },
649  [](float old_g, float new_g) { return std::abs(old_g - new_g); });
650 
651  normalizer = std::accumulate(newgamma, newgamma + all.lda, 0.0f);
652  return sum / normalizer;
653 }
654 
655 // Returns E_q[log p(\theta)] - E_q[log q(\theta)].
656 float theta_kl(lda &l, v_array<float> &Elogtheta, float *gamma)
657 {
658  float gammasum = 0;
659  Elogtheta.clear();
660  for (size_t k = 0; k < l.topics; k++)
661  {
662  Elogtheta.push_back(l.digamma(gamma[k]));
663  gammasum += gamma[k];
664  }
665  float digammasum = l.digamma(gammasum);
666  gammasum = l.lgamma(gammasum);
667  float kl = -(l.topics * l.lgamma(l.lda_alpha));
668  kl += l.lgamma(l.lda_alpha * l.topics) - gammasum;
669  for (size_t k = 0; k < l.topics; k++)
670  {
671  Elogtheta[k] -= digammasum;
672  kl += (l.lda_alpha - gamma[k]) * Elogtheta[k];
673  kl += l.lgamma(gamma[k]);
674  }
675 
676  return kl;
677 }
678 
679 static inline float find_cw(lda &l, float *u_for_w, float *v)
680 {
681  return 1.0f / std::inner_product(u_for_w, u_for_w + l.topics, v, 0.0f);
682 }
683 
684 namespace
685 {
686 // Effectively, these are static and not visible outside the compilation unit.
687 v_array<float> new_gamma = v_init<float>();
688 v_array<float> old_gamma = v_init<float>();
689 } // namespace
690 
691 // Returns an estimate of the part of the variational bound that
692 // doesn't have to do with beta for the entire corpus for the current
693 // setting of lambda based on the document passed in. The value is
694 // divided by the total number of words in the document This can be
695 // used as a (possibly very noisy) estimate of held-out likelihood.
696 float lda_loop(lda &l, v_array<float> &Elogtheta, float *v, example *ec, float)
697 {
698  parameters &weights = l.all->weights;
699  new_gamma.clear();
700  old_gamma.clear();
701 
702  for (size_t i = 0; i < l.topics; i++)
703  {
704  new_gamma.push_back(1.f);
705  old_gamma.push_back(0.f);
706  }
707  size_t num_words = 0;
708  for (features &fs : *ec) num_words += fs.size();
709 
710  float xc_w = 0;
711  float score = 0;
712  float doc_length = 0;
713  do
714  {
715  memcpy(v, new_gamma.begin(), sizeof(float) * l.topics);
716  l.expdigammify(*l.all, v);
717 
718  memcpy(old_gamma.begin(), new_gamma.begin(), sizeof(float) * l.topics);
719  memset(new_gamma.begin(), 0, sizeof(float) * l.topics);
720 
721  score = 0;
722  size_t word_count = 0;
723  doc_length = 0;
724  for (features &fs : *ec)
725  {
726  for (features::iterator &f : fs)
727  {
728  float *u_for_w = &(weights[f.index()]) + l.topics + 1;
729  float c_w = find_cw(l, u_for_w, v);
730  xc_w = c_w * f.value();
731  score += -f.value() * log(c_w);
732  size_t max_k = l.topics;
733  for (size_t k = 0; k < max_k; k++, ++u_for_w) new_gamma[k] += xc_w * *u_for_w;
734  word_count++;
735  doc_length += f.value();
736  }
737  }
738  for (size_t k = 0; k < l.topics; k++) new_gamma[k] = new_gamma[k] * v[k] + l.lda_alpha;
739  } while (average_diff(*l.all, old_gamma.begin(), new_gamma.begin()) > l.lda_epsilon);
740 
741  ec->pred.scalars.clear();
742  ec->pred.scalars.resize(l.topics);
743  memcpy(ec->pred.scalars.begin(), new_gamma.begin(), l.topics * sizeof(float));
744  ec->pred.scalars.end() = ec->pred.scalars.begin() + l.topics;
745 
746  score += theta_kl(l, Elogtheta, new_gamma.begin());
747 
748  return score / doc_length;
749 }
750 
751 size_t next_pow2(size_t x)
752 {
753  int i = 0;
754  x = x > 0 ? x - 1 : 0;
755  while (x > 0)
756  {
757  x >>= 1;
758  i++;
759  }
760  return ((size_t)1) << i;
761 }
762 
764 {
767  bool _random;
768  uint32_t _lda;
769  uint32_t _stride;
770  initial_weights(weight initial, weight initial_random, bool random, uint32_t lda, uint32_t stride)
771  : _initial(initial), _initial_random(initial_random), _random(random), _lda(lda), _stride(stride)
772  {
773  }
774 };
775 
776 template <class T>
778 {
779  public:
780  static void func(weight &w, initial_weights &iw, uint64_t index)
781  {
782  uint32_t lda = iw._lda;
783  weight initial_random = iw._initial_random;
784  if (iw._random)
785  {
786  weight *pw = &w;
787  for (size_t i = 0; i != lda; ++i, ++index) pw[i] = (float)(-log(merand48(index) + 1e-6) + 1.0f) * initial_random;
788  }
789  (&w)[lda] = iw._initial;
790  }
791 };
792 
793 void save_load(lda &l, io_buf &model_file, bool read, bool text)
794 {
795  vw &all = *(l.all);
796  uint64_t length = (uint64_t)1 << all.num_bits;
797  if (read)
798  {
800  initial_weights init(all.initial_t, (float)(l.lda_D / all.lda / all.length() * 200), all.random_weights, all.lda,
801  all.weights.stride());
802  if (all.weights.sparse)
804  else
806  }
807  if (!model_file.files.empty())
808  {
809  uint64_t i = 0;
810  std::stringstream msg;
811  size_t brw = 1;
812 
813  do
814  {
815  brw = 0;
816  size_t K = all.lda;
817  if (!read && text)
818  msg << i << " ";
819 
820  if (!read || all.model_file_ver >= VERSION_FILE_WITH_HEADER_ID)
821  brw += bin_text_read_write_fixed(model_file, (char *)&i, sizeof(i), "", read, msg, text);
822  else
823  {
824  // support 32bit build models
825  uint32_t j;
826  brw += bin_text_read_write_fixed(model_file, (char *)&j, sizeof(j), "", read, msg, text);
827  i = j;
828  }
829 
830  if (brw != 0)
831  {
832  weight *w = &(all.weights.strided_index(i));
833  for (uint64_t k = 0; k < K; k++)
834  {
835  weight *v = w + k;
836  if (!read && text)
837  msg << *v + l.lda_rho << " ";
838  brw += bin_text_read_write_fixed(model_file, (char *)v, sizeof(*v), "", read, msg, text);
839  }
840  }
841  if (text)
842  {
843  if (!read)
844  msg << "\n";
845  brw += bin_text_read_write_fixed(model_file, nullptr, 0, "", read, msg, text);
846  }
847  if (!read)
848  ++i;
849  } while ((!read && i < length) || (read && brw > 0));
850  }
851 }
852 
853 void return_example(vw &all, example &ec)
854 {
855  all.sd->update(ec.test_only, true, ec.loss, ec.weight, ec.num_features);
856  for (int f : all.final_prediction_sink) MWT::print_scalars(f, ec.pred.scalars, ec.tag);
857 
858  if (all.sd->weighted_examples() >= all.sd->dump_interval && !all.quiet)
859  all.sd->print_update(
860  all.holdout_set_off, all.current_pass, "none", 0, ec.num_features, all.progress_add, all.progress_arg);
861  VW::finish_example(all, ec);
862 }
863 
864 void learn_batch(lda &l)
865 {
866  parameters &weights = l.all->weights;
867  if (l.sorted_features.empty()) // FAST-PASS for real "true"
868  {
869  // This can happen when the socket connection is dropped by the client.
870  // If l.sorted_features is empty, then l.sorted_features[0] does not
871  // exist, so we should not try to take its address in the beginning of
872  // the for loops down there. Since it seems that there's not much to
873  // do in this case, we just return.
874  for (size_t d = 0; d < l.examples.size(); d++)
875  {
876  l.examples[d]->pred.scalars.clear();
877  l.examples[d]->pred.scalars.resize(l.topics);
878  memset(l.examples[d]->pred.scalars.begin(), 0, l.topics * sizeof(float));
879  l.examples[d]->pred.scalars.end() = l.examples[d]->pred.scalars.begin() + l.topics;
880 
881  l.examples[d]->pred.scalars.clear();
882  return_example(*l.all, *l.examples[d]);
883  }
884  l.examples.clear();
885  return;
886  }
887 
888  float eta = -1;
889  float minuseta = -1;
890 
891  if (l.total_lambda.empty())
892  {
893  for (size_t k = 0; k < l.all->lda; k++) l.total_lambda.push_back(0.f);
894  // This part does not work with sparse parameters
895  size_t stride = weights.stride();
896  for (size_t i = 0; i <= weights.mask(); i += stride)
897  {
898  weight *w = &(weights[i]);
899  for (size_t k = 0; k < l.all->lda; k++) l.total_lambda[k] += w[k];
900  }
901  }
902 
903  l.example_t++;
904  l.total_new.clear();
905  for (size_t k = 0; k < l.all->lda; k++) l.total_new.push_back(0.f);
906 
907  size_t batch_size = l.examples.size();
908 
909  sort(l.sorted_features.begin(), l.sorted_features.end());
910 
911  eta = l.all->eta * l.powf((float)l.example_t, -l.all->power_t);
912  minuseta = 1.0f - eta;
913  eta *= l.lda_D / batch_size;
914  l.decay_levels.push_back(l.decay_levels.last() + log(minuseta));
915 
916  l.digammas.clear();
917  float additional = (float)(l.all->length()) * l.lda_rho;
918  for (size_t i = 0; i < l.all->lda; i++) l.digammas.push_back(l.digamma(l.total_lambda[i] + additional));
919 
920  uint64_t last_weight_index = -1;
921  for (index_feature *s = &l.sorted_features[0]; s <= &l.sorted_features.back(); s++)
922  {
923  if (last_weight_index == s->f.weight_index)
924  continue;
925  last_weight_index = s->f.weight_index;
926  // float *weights_for_w = &(weights[s->f.weight_index]);
927  float *weights_for_w = &(weights[s->f.weight_index & weights.mask()]);
928  float decay_component =
929  l.decay_levels.end()[-2] - l.decay_levels.end()[(int)(-1 - l.example_t + *(weights_for_w + l.all->lda))];
930  float decay = fmin(1.0f, correctedExp(decay_component));
931  float *u_for_w = weights_for_w + l.all->lda + 1;
932 
933  *(weights_for_w + l.all->lda) = (float)l.example_t;
934  for (size_t k = 0; k < l.all->lda; k++)
935  {
936  weights_for_w[k] *= decay;
937  u_for_w[k] = weights_for_w[k] + l.lda_rho;
938  }
939 
940  l.expdigammify_2(*l.all, u_for_w, l.digammas.begin());
941  }
942 
943  for (size_t d = 0; d < batch_size; d++)
944  {
945  float score = lda_loop(l, l.Elogtheta, &(l.v[d * l.all->lda]), l.examples[d], l.all->power_t);
946  if (l.all->audit)
948  // If the doc is empty, give it loss of 0.
949  if (l.doc_lengths[d] > 0)
950  {
951  l.all->sd->sum_loss -= score;
952  l.all->sd->sum_loss_since_last_dump -= score;
953  }
954  return_example(*l.all, *l.examples[d]);
955  }
956 
957  // -t there's no need to update weights (especially since it's a noop)
958  if (eta != 0)
959  {
960  for (index_feature *s = &l.sorted_features[0]; s <= &l.sorted_features.back();)
961  {
962  index_feature *next = s + 1;
963  while (next <= &l.sorted_features.back() && next->f.weight_index == s->f.weight_index) next++;
964 
965  float *word_weights = &(weights[s->f.weight_index]);
966  for (size_t k = 0; k < l.all->lda; k++, ++word_weights)
967  {
968  float new_value = minuseta * *word_weights;
969  *word_weights = new_value;
970  }
971 
972  for (; s != next; s++)
973  {
974  float *v_s = &(l.v[s->document * l.all->lda]);
975  float *u_for_w = &(weights[s->f.weight_index]) + l.all->lda + 1;
976  float c_w = eta * find_cw(l, u_for_w, v_s) * s->f.x;
977  word_weights = &(weights[s->f.weight_index]);
978  for (size_t k = 0; k < l.all->lda; k++, ++u_for_w, ++word_weights)
979  {
980  float new_value = *u_for_w * v_s[k] * c_w;
981  l.total_new[k] += new_value;
982  *word_weights += new_value;
983  }
984  }
985  }
986 
987  for (size_t k = 0; k < l.all->lda; k++)
988  {
989  l.total_lambda[k] *= minuseta;
990  l.total_lambda[k] += l.total_new[k];
991  }
992  }
993  l.sorted_features.resize(0);
994 
995  l.examples.clear();
996  l.doc_lengths.clear();
997 }
998 
1000 {
1001  uint32_t num_ex = (uint32_t)l.examples.size();
1002  l.examples.push_back(&ec);
1003  l.doc_lengths.push_back(0);
1004  for (features &fs : ec)
1005  {
1006  for (features::iterator &f : fs)
1007  {
1008  index_feature temp = {num_ex, feature(f.value(), f.index())};
1009  l.sorted_features.push_back(temp);
1010  l.doc_lengths[num_ex] += (int)f.value();
1011  }
1012  }
1013  if (++num_ex == l.minibatch)
1014  learn_batch(l);
1015 }
1016 
1018 {
1019  if (l.all->passes_complete == 0)
1020  {
1021  // build feature to example map
1022  uint64_t stride_shift = l.all->weights.stride_shift();
1023  uint64_t weight_mask = l.all->weights.mask();
1024 
1025  for (features &fs : ec)
1026  {
1027  for (features::iterator &f : fs)
1028  {
1029  uint64_t idx = (f.index() & weight_mask) >> stride_shift;
1030  l.feature_counts[idx] += (uint32_t)f.value();
1031  l.feature_to_example_map[idx].push_back(ec.example_counter);
1032  }
1033  }
1034  }
1035 
1036  learn(l, base, ec);
1037 }
1038 
1039 // placeholder
1040 void predict(lda &l, LEARNER::single_learner &base, example &ec) { learn(l, base, ec); }
1042 
1044 {
1045  // feature/word index
1046  uint64_t idx;
1047  // document count
1048  uint32_t count;
1049 };
1050 
1051 // cooccurence of 2 features/words
1053 {
1054  // feature/word 1
1055  uint64_t f1;
1056  // feature/word 2
1057  uint64_t f2;
1058 
1059  feature_pair(uint64_t _f1, uint64_t _f2) : f1(_f1), f2(_f2) {}
1060 };
1061 
1062 template <class T>
1063 void get_top_weights(vw *all, int top_words_count, int topic, std::vector<feature> &output, T &weights)
1064 {
1065  uint64_t length = (uint64_t)1 << all->num_bits;
1066 
1067  // get top features for this topic
1068  auto cmp = [](feature left, feature right) { return left.x > right.x; };
1069  std::priority_queue<feature, std::vector<feature>, decltype(cmp)> top_features(cmp);
1070  typename T::iterator iter = weights.begin();
1071 
1072  for (uint64_t i = 0; i < std::min(static_cast<uint64_t>(top_words_count), length); i++, ++iter)
1073  top_features.push({(&(*iter))[topic], iter.index()});
1074 
1075  for (uint64_t i = top_words_count; i < length; i++, ++iter)
1076  {
1077  weight v = (&(*iter))[topic];
1078  if (v > top_features.top().x)
1079  {
1080  top_features.pop();
1081  top_features.push({v, i});
1082  }
1083  }
1084 
1085  // extract idx and sort descending
1086  output.resize(top_features.size());
1087  for (int i = (int)top_features.size() - 1; i >= 0; i--)
1088  {
1089  output[i] = top_features.top();
1090  top_features.pop();
1091  }
1092 }
1093 
1094 void get_top_weights(vw *all, int top_words_count, int topic, std::vector<feature> &output)
1095 {
1096  if (all->weights.sparse)
1097  get_top_weights(all, top_words_count, topic, output, all->weights.sparse_weights);
1098  else
1099  get_top_weights(all, top_words_count, topic, output, all->weights.dense_weights);
1100 }
1101 
1102 template <class T>
1103 void compute_coherence_metrics(lda &l, T &weights)
1104 {
1105  uint64_t length = (uint64_t)1 << l.all->num_bits;
1106 
1107  std::vector<std::vector<feature_pair>> topics_word_pairs;
1108  topics_word_pairs.resize(l.topics);
1109 
1110  int top_words_count = 10; // parameterize and check
1111 
1112  for (size_t topic = 0; topic < l.topics; topic++)
1113  {
1114  // get top features for this topic
1115  auto cmp = [](feature &left, feature &right) { return left.x > right.x; };
1116  std::priority_queue<feature, std::vector<feature>, decltype(cmp)> top_features(cmp);
1117  typename T::iterator iter = weights.begin();
1118  for (uint64_t i = 0; i < std::min(static_cast<uint64_t>(top_words_count), length); i++, ++iter)
1119  top_features.push(feature((&(*iter))[topic], iter.index()));
1120 
1121  for (typename T::iterator v = weights.begin(); v != weights.end(); ++v)
1122  if ((&(*v))[topic] > top_features.top().x)
1123  {
1124  top_features.pop();
1125  top_features.push(feature((&(*v))[topic], v.index()));
1126  }
1127 
1128  // extract idx and sort descending
1129  std::vector<uint64_t> top_features_idx;
1130  top_features_idx.resize(top_features.size());
1131  for (int i = (int)top_features.size() - 1; i >= 0; i--)
1132  {
1133  top_features_idx[i] = top_features.top().weight_index;
1134  top_features.pop();
1135  }
1136 
1137  auto &word_pairs = topics_word_pairs[topic];
1138  for (size_t i = 0; i < top_features_idx.size(); i++)
1139  for (size_t j = i + 1; j < top_features_idx.size(); j++)
1140  word_pairs.emplace_back(top_features_idx[i], top_features_idx[j]);
1141  }
1142 
1143  // compress word pairs and create record for storing frequency
1144  std::map<uint64_t, std::vector<word_doc_frequency>> coWordsDFSet;
1145  for (auto &vec : topics_word_pairs)
1146  {
1147  for (auto &wp : vec)
1148  {
1149  auto f1 = wp.f1;
1150  auto f2 = wp.f2;
1151  auto wdf = coWordsDFSet.find(f1);
1152 
1153  if (wdf != coWordsDFSet.end())
1154  {
1155  // http://stackoverflow.com/questions/5377434/does-stdmapiterator-return-a-copy-of-value-or-a-value-itself
1156  // if (wdf->second.find(f2) == wdf->second.end())
1157 
1158  if (std::find_if(wdf->second.begin(), wdf->second.end(),
1159  [&f2](const word_doc_frequency &v) { return v.idx == f2; }) != wdf->second.end())
1160  {
1161  wdf->second.push_back({f2, 0});
1162  // printf(" add %d %d\n", f1, f2);
1163  }
1164  }
1165  else
1166  {
1167  std::vector<word_doc_frequency> vec = {{f2, 0}};
1168  coWordsDFSet.insert(std::make_pair(f1, vec));
1169  // printf(" insert %d %d\n", f1, f2);
1170  }
1171  }
1172  }
1173 
1174  // this.GetWordPairsDocumentFrequency(coWordsDFSet);
1175  for (auto &pair : coWordsDFSet)
1176  {
1177  auto &examples_for_f1 = l.feature_to_example_map[pair.first];
1178  for (auto &wdf : pair.second)
1179  {
1180  auto &examples_for_f2 = l.feature_to_example_map[wdf.idx];
1181 
1182  // assumes examples_for_f1 and examples_for_f2 are orderd
1183  size_t i = 0;
1184  size_t j = 0;
1185  while (i < examples_for_f1.size() && j < examples_for_f2.size())
1186  {
1187  if (examples_for_f1[i] == examples_for_f2[j])
1188  {
1189  wdf.count++;
1190  i++;
1191  j++;
1192  }
1193  else if (examples_for_f2[j] < examples_for_f1[i])
1194  j++;
1195  else
1196  i++;
1197  }
1198  }
1199  }
1200 
1201  float epsilon = 1e-6f; // TODO
1202  float avg_coherence = 0;
1203  for (size_t topic = 0; topic < l.topics; topic++)
1204  {
1205  float coherence = 0;
1206 
1207  for (auto &pairs : topics_word_pairs[topic])
1208  {
1209  auto f1 = pairs.f1;
1210  if (l.feature_counts[f1] == 0)
1211  continue;
1212 
1213  auto f2 = pairs.f2;
1214  auto &co_feature = coWordsDFSet[f1];
1215  auto co_feature_df = std::find_if(
1216  co_feature.begin(), co_feature.end(), [&f2](const word_doc_frequency &v) { return v.idx == f2; });
1217 
1218  if (co_feature_df != co_feature.end())
1219  {
1220  // printf("(%d:%d + eps)/(%d:%d)\n", f2, co_feature_df->count, f1, l.feature_counts[f1]);
1221  coherence += logf((co_feature_df->count + epsilon) / l.feature_counts[f1]);
1222  }
1223  }
1224 
1225  printf("Topic %3d coherence: %f\n", (int)topic, coherence);
1226 
1227  // TODO: expose per topic coherence
1228 
1229  // TODO: good vs. bad topics
1230  avg_coherence += coherence;
1231  }
1232 
1233  avg_coherence /= l.topics;
1234 
1235  printf("Avg topic coherence: %f\n", avg_coherence);
1236 }
1237 
1239 {
1240  if (l.all->weights.sparse)
1242  else
1244 }
1245 
1246 void end_pass(lda &l)
1247 {
1248  if (!l.examples.empty())
1249  learn_batch(l);
1250 
1252  {
1254  // FASTPASS return;
1255  }
1256 }
1257 
1258 template <class T>
1259 void end_examples(lda &l, T &weights)
1260 {
1261  for (typename T::iterator iter = weights.begin(); iter != weights.end(); ++iter)
1262  {
1263  float decay_component =
1264  l.decay_levels.last() - l.decay_levels.end()[(int)(-1 - l.example_t + (&(*iter))[l.all->lda])];
1265  float decay = fmin(1.f, correctedExp(decay_component));
1266 
1267  weight *wp = &(*iter);
1268  for (size_t i = 0; i < l.all->lda; ++i) wp[i] *= decay;
1269  }
1270 }
1271 
1273 {
1274  if (l.all->weights.sparse)
1276  else
1278 }
1279 
1280 void finish_example(vw &, lda &, example &) {}
1281 
1282 std::istream &operator>>(std::istream &in, lda_math_mode &mmode)
1283 {
1284  using namespace boost::program_options;
1285 
1286  std::string token;
1287  in >> token;
1288  if (token == "simd")
1289  mmode = USE_SIMD;
1290  else if (token == "accuracy" || token == "precise")
1291  mmode = USE_PRECISE;
1292  else if (token == "fast-approx" || token == "approx")
1293  mmode = USE_FAST_APPROX;
1294  else
1295  throw boost::program_options::invalid_option_value(token);
1296  return in;
1297 }
1298 
1300 {
1301  auto ld = scoped_calloc_or_throw<lda>();
1302  option_group_definition new_options("Latent Dirichlet Allocation");
1303  int math_mode;
1304  new_options.add(make_option("lda", ld->topics).keep().help("Run lda with <int> topics"))
1305  .add(make_option("lda_alpha", ld->lda_alpha)
1306  .keep()
1307  .default_value(0.1f)
1308  .help("Prior on sparsity of per-document topic weights"))
1309  .add(make_option("lda_rho", ld->lda_rho)
1310  .keep()
1311  .default_value(0.1f)
1312  .help("Prior on sparsity of topic distributions"))
1313  .add(make_option("lda_D", ld->lda_D).default_value(10000.0f).help("Number of documents"))
1314  .add(make_option("lda_epsilon", ld->lda_epsilon).default_value(0.001f).help("Loop convergence threshold"))
1315  .add(make_option("minibatch", ld->minibatch).default_value(1).help("Minibatch size, for LDA"))
1316  .add(make_option("math-mode", math_mode).default_value(USE_SIMD).help("Math mode: simd, accuracy, fast-approx"))
1317  .add(make_option("metrics", ld->compute_coherence_metrics).help("Compute metrics"));
1318  options.add_and_parse(new_options);
1319 
1320  // Convert from int to corresponding enum value.
1321  ld->mmode = static_cast<lda_math_mode>(math_mode);
1322 
1323  if (!options.was_supplied("lda"))
1324  return nullptr;
1325 
1326  all.lda = (uint32_t)ld->topics;
1328  ld->sorted_features = std::vector<index_feature>();
1329  ld->total_lambda_init = false;
1330  ld->all = &all;
1331  ld->example_t = all.initial_t;
1332  if (ld->compute_coherence_metrics)
1333  {
1334  ld->feature_counts.resize((uint32_t)(UINT64_ONE << all.num_bits));
1335  ld->feature_to_example_map.resize((uint32_t)(UINT64_ONE << all.num_bits));
1336  }
1337 
1338  float temp = ceilf(logf((float)(all.lda * 2 + 1)) / logf(2.f));
1339 
1340  all.weights.stride_shift((size_t)temp);
1341  all.random_weights = true;
1342  all.add_constant = false;
1343 
1344  if (all.eta > 1.)
1345  {
1346  std::cerr << "your learning rate is too high, setting it to 1" << std::endl;
1347  all.eta = std::min(all.eta, 1.f);
1348  }
1349 
1350  size_t minibatch2 = next_pow2(ld->minibatch);
1351  if (minibatch2 > all.p->ring_size)
1352  {
1353  bool previous_strict_parse = all.p->strict_parse;
1354  delete all.p;
1355  all.p = new parser{minibatch2, previous_strict_parse};
1356  }
1357 
1358  ld->v.resize(all.lda * ld->minibatch);
1359 
1360  ld->decay_levels.push_back(0.f);
1361 
1363 
1364  LEARNER::learner<lda, example> &l = init_learner(ld, ld->compute_coherence_metrics ? learn_with_metrics : learn,
1365  ld->compute_coherence_metrics ? predict_with_metrics : predict, UINT64_ONE << all.weights.stride_shift(),
1367 
1372 
1373  return make_base(l);
1374 }
v_array< example * > examples
Definition: lda_core.cc:73
v_array< int > doc_lengths
Definition: lda_core.cc:75
double sum_loss
Definition: global_data.h:145
float powf< float, USE_SIMD >(float x, float p)
Definition: lda_core.cc:497
void resize(size_t length)
Definition: v_array.h:69
v_array< char > tag
Definition: example.h:63
size_t length()
Definition: global_data.h:513
static float fastexp(float p)
Definition: nn.cc:79
bool operator<(const index_feature b) const
Definition: lda_core.cc:57
void learn_batch(lda &l)
Definition: lda_core.cc:864
#define correctedExp
Definition: correctedMath.h:27
weight _initial
Definition: lda_core.cc:765
#define VERSION_FILE_WITH_HEADER_ID
Definition: vw_versions.h:19
parameters weights
Definition: global_data.h:537
void compute_coherence_metrics(lda &l, T &weights)
Definition: lda_core.cc:1103
void print_audit_features(vw &all, example &ec)
Definition: gd.cc:331
size_t minibatch
Definition: lda_core.cc:67
void accumulate(vw &all, parameters &weights, size_t offset)
Definition: accumulate.cc:20
v_array< float > total_lambda
Definition: lda_core.cc:74
v_array< float > decay_levels
Definition: lda_core.cc:71
void learn_with_metrics(lda &l, LEARNER::single_learner &base, example &ec)
Definition: lda_core.cc:1017
void(* delete_prediction)(void *)
Definition: global_data.h:485
void initialize_regressor(vw &all, T &weights)
float powf(float x, float p)
Definition: lda_core.cc:581
uint64_t f2
Definition: lda_core.cc:1057
uint64_t stride_shift(const stagewise_poly &poly, uint64_t idx)
float x
Definition: feature_group.h:27
float initial_t
Definition: global_data.h:530
void print_scalars(int f, v_array< float > &scalars, v_array< char > &tag)
Definition: mwt.cc:149
void expdigammify< float, USE_SIMD >(vw &all, float *gamma, float threshold, float)
Definition: lda_core.cc:511
lda_math_mode mmode
Definition: lda_core.cc:68
void expdigammify_2(vw &all, float *gamma, T *norm, const T threshold)
Definition: lda_core.cc:522
lda_math_mode
Definition: lda_core.cc:45
float digamma< float, USE_SIMD >(float x)
Definition: lda_core.cc:487
bool add_constant
Definition: global_data.h:496
float lgamma< float, USE_PRECISE >(float x)
Definition: lda_core.cc:436
float powf< float, USE_PRECISE >(float x, float p)
Definition: lda_core.cc:451
float lda_rho
Definition: lda_core.cc:64
float power_t
Definition: global_data.h:447
v_array< int > final_prediction_sink
Definition: global_data.h:518
float fastdigamma(float x)
Definition: lda_core.cc:172
uint32_t stride()
vw * all
Definition: lda_core.cc:89
void expdigammify_2(vw &all, float *gamma, float *norm)
Definition: lda_core.cc:620
the core definition of a set of features.
float exponential< float, USE_PRECISE >(float x)
Definition: lda_core.cc:446
LEARNER::base_learner * lda_setup(options_i &options, vw &all)
Definition: lda_core.cc:1299
base_learner * make_base(learner< T, E > &base)
Definition: learner.h:462
T exponential(T)
Definition: lda_core.cc:421
void predict_with_metrics(lda &l, LEARNER::single_learner &base, example &ec)
Definition: lda_core.cc:1041
float exponential< float, USE_FAST_APPROX >(float x)
Definition: lda_core.cc:469
bool quiet
Definition: global_data.h:487
float exponential< float, USE_SIMD >(float x)
Definition: lda_core.cc:492
virtual void add_and_parse(const option_group_definition &group)=0
void set_save_load(void(*sl)(T &, io_buf &, bool, bool))
Definition: learner.h:257
uint32_t _stride
Definition: lda_core.cc:769
void set_default(R &info)
float merand48(uint64_t &initial)
Definition: rand48.cc:16
double example_t
Definition: lda_core.cc:88
bool holdout_set_off
Definition: global_data.h:499
uint32_t num_bits
Definition: global_data.h:398
T *& begin()
Definition: v_array.h:42
uint64_t weight_index
Definition: feature_group.h:28
bool progress_add
Definition: global_data.h:545
bool strict_parse
Definition: parser.h:107
size_t size() const
Definition: v_array.h:68
void return_example(vw &all, example &ec)
Definition: lda_core.cc:853
float lda_epsilon
Definition: lda_core.cc:66
double sum_loss_since_last_dump
Definition: global_data.h:146
parser * p
Definition: global_data.h:377
uint32_t lda
Definition: global_data.h:508
size_t next_pow2(size_t x)
Definition: lda_core.cc:751
float lgamma(float x)
Definition: lda_core.cc:561
float digamma< float, USE_PRECISE >(float x)
Definition: lda_core.cc:441
void set_finish_example(void(*f)(vw &all, T &, E &))
Definition: learner.h:307
float lda_alpha
Definition: lda_core.cc:63
float powf< float, USE_FAST_APPROX >(float x, float p)
Definition: lda_core.cc:474
float lgamma< float, USE_FAST_APPROX >(float x)
Definition: lda_core.cc:459
float lgamma< float, USE_SIMD >(float x)
Definition: lda_core.cc:482
initial_weights(weight initial, weight initial_random, bool random, uint32_t lda, uint32_t stride)
Definition: lda_core.cc:770
v_array< float > Elogtheta
Definition: lda_core.cc:70
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 push_back(const T &new_ele)
Definition: v_array.h:107
shared_data * sd
Definition: global_data.h:375
T powf(T, T)
Definition: lda_core.cc:428
size_t random(std::shared_ptr< rand_state > &rs, size_t max)
Definition: search.cc:768
float fastlgamma(float x)
Definition: lda_core.cc:164
VW::version_struct model_file_ver
Definition: global_data.h:419
float progress_arg
Definition: global_data.h:546
float lda_loop(lda &l, v_array< float > &Elogtheta, float *v, example *ec, float)
Definition: lda_core.cc:696
float lda_D
Definition: lda_core.cc:65
void delete_scalars(void *v)
Definition: example.h:37
v_array< int > files
Definition: io_buf.h:64
void clear()
Definition: v_array.h:88
~lda()
Definition: lda_core.cc:98
void print_update(bool holdout_set_off, size_t current_pass, float label, float prediction, size_t num_features, bool progress_add, float progress_arg)
Definition: global_data.h:225
size_t num_features
Definition: example.h:67
virtual bool was_supplied(const std::string &key)=0
float fastlog2(float x)
Definition: lda_core.cc:127
size_t absdiff(size_t a, size_t b)
Definition: search.cc:1946
void expdigammify_2< float, USE_SIMD >(vw &all, float *gamma, float *norm, const float threshold)
Definition: lda_core.cc:528
float theta_kl(lda &l, v_array< float > &Elogtheta, float *gamma)
Definition: lda_core.cc:656
bool random_weights
Definition: global_data.h:492
std::vector< uint32_t > feature_counts
Definition: lda_core.cc:83
dense_parameters dense_weights
std::vector< std::vector< size_t > > feature_to_example_map
Definition: lda_core.cc:84
float fastpow(float x, float p)
Definition: lda_core.cc:162
uint64_t current_pass
Definition: global_data.h:396
weight & strided_index(size_t index)
bool compute_coherence_metrics
Definition: lda_core.cc:80
static void func(weight &w, initial_weights &iw, uint64_t index)
Definition: lda_core.cc:780
const size_t ring_size
Definition: parser.h:80
Definition: io_buf.h:54
void learn(lda &l, LEARNER::single_learner &, example &ec)
Definition: lda_core.cc:999
void expdigammify(vw &all, T *gamma, T threshold, T initial)
Definition: lda_core.cc:503
void finish_example(vw &, example &)
Definition: parser.cc:881
T *& end()
Definition: v_array.h:43
void save_load(lda &l, io_buf &model_file, bool read, bool text)
Definition: lda_core.cc:793
v_array< float > digammas
Definition: lda_core.cc:76
size_t numpasses
Definition: global_data.h:451
void update(bool test_example, bool labeled_example, float loss, float weight, size_t num_features)
Definition: global_data.h:190
float loss
Definition: example.h:70
float eta
Definition: global_data.h:531
T digamma(T)
Definition: lda_core.cc:414
float weight
int add(svm_params &params, svm_example *fec)
Definition: kernel_svm.cc:546
iterator over values and indicies
v_array< float > total_new
Definition: lda_core.cc:72
size_t topics
Definition: lda_core.cc:62
constexpr uint64_t a
Definition: rand48.cc:11
size_t passes_complete
Definition: global_data.h:452
typed_option< T > make_option(std::string name, T &location)
Definition: options.h:80
void get_top_weights(vw *all, int top_words_count, int topic, std::vector< feature > &output, T &weights)
Definition: lda_core.cc:1063
constexpr uint64_t UINT64_ONE
void set_end_pass(void(*f)(T &))
Definition: learner.h:286
void expdigammify(vw &all, float *gamma)
Definition: lda_core.cc:601
sparse_parameters sparse_weights
float digamma(float x)
Definition: lda_core.cc:540
bool empty() const
Definition: v_array.h:59
uint64_t f1
Definition: lda_core.cc:1055
std::istream & operator>>(std::istream &in, lda_math_mode &mmode)
Definition: lda_core.cc:1282
weight _initial_random
Definition: lda_core.cc:766
float fastlog(float x)
Definition: lda_core.cc:145
void predict(lda &l, LEARNER::single_learner &base, example &ec)
Definition: lda_core.cc:1040
static float average_diff(vw &all, float *oldgamma, float *newgamma)
Definition: lda_core.cc:639
uint32_t stride_shift()
int cmp(size_t a, size_t b)
Definition: action_score.h:47
std::vector< index_feature > sorted_features
Definition: lda_core.cc:78
static float fastpow2(float p)
Definition: nn.cc:64
Definition: parser.h:38
static float find_cw(lda &l, float *u_for_w, float *v)
Definition: lda_core.cc:679
bool audit
Definition: global_data.h:486
T last() const
Definition: v_array.h:57
uint32_t document
Definition: lda_core.cc:55
polyprediction pred
Definition: example.h:60
void delete_v()
Definition: v_array.h:98
void end_examples(lda &l, T &weights)
Definition: lda_core.cc:1259
uint32_t _lda
Definition: lda_core.cc:768
feature f
Definition: lda_core.cc:56
bool total_lambda_init
Definition: lda_core.cc:86
void end_pass(lda &l)
Definition: lda_core.cc:1246
float weight
Definition: example.h:62
double weighted_examples()
Definition: global_data.h:188
float dump_interval
Definition: global_data.h:147
v_array< float > scalars
Definition: example.h:46
size_t bin_text_read_write_fixed(io_buf &io, char *data, size_t len, const char *read_message, bool read, std::stringstream &msg, bool text)
Definition: io_buf.h:326
uint64_t mask()
float digamma< float, USE_FAST_APPROX >(float x)
Definition: lda_core.cc:464
float f
Definition: cache.cc:40
void set_end_examples(void(*f)(T &))
Definition: learner.h:295
label_parser lp
Definition: parser.h:102
v_array< float > v
Definition: lda_core.cc:77
Definition: lda_core.cc:60
feature_pair(uint64_t _f1, uint64_t _f2)
Definition: lda_core.cc:1059
T lgamma(T)
Definition: lda_core.cc:407
label_parser no_label_parser
Definition: no_label.cc:41
bool test_only
Definition: example.h:76