autoppl  v0.8
A C++ template library for probabilistic programming
var_adapter.hpp
Go to the documentation of this file.
1 #pragma once
3 
4 namespace ppl {
5 
9 struct unit_var {};
10 struct diag_var {};
11 struct dense_var {};
12 
17 struct VarConfig
18 {
19  size_t init_buffer = 75;
20  size_t term_buffer = 50;
21  size_t window_base = 25;
22 };
23 
24 namespace mcmc {
25 
30 template <class VarPolicy>
31 struct VarAdapter {};
32 
36 template <>
38 {
39  // For consistent API
40  VarAdapter(size_t,
41  size_t,
42  size_t,
43  size_t,
44  size_t)
45  {}
46 };
47 
55 template <>
57 {
58  VarAdapter(size_t n_params,
59  size_t warmup,
60  size_t init_buffer,
61  size_t term_buffer,
62  size_t window_base)
63  : var_estimator_(n_params)
64  , warmup_{warmup}
65  , counter_{0}
66  , window_begin_{init_buffer}
67  , window_end_{warmup - term_buffer}
68  , init_buffer_{init_buffer}
69  , term_buffer_{term_buffer}
70  , window_base_{window_base}
71  {
72  // constructor guarantees that at least 1 window computed
73 
74  // if warmup less than 20, just do 1 window
75  if (warmup_ <= 20) {
76  init_buffer_ = 0;
77  term_buffer_ = 0;
78  window_base_ = warmup_;
79  }
80 
81  // else if warmup less than init + 1 window + term,
82  // change to 15% init, 75% 1 window, 10% term (see STAN)
83  else if (warmup_ < init_buffer_ + term_buffer_ + window_base_) {
84  init_buffer_ = 0.15 * warmup_;
85  term_buffer_ = 0.10 * warmup_;
86  window_base_ = warmup_ - init_buffer_ - term_buffer_;
87  }
88 
89  window_begin_ = init_buffer_;
90  window_end_ = window_begin_ + window_base_;
91  size_t next_window_end = window_end_ + 2 * window_base_;
92 
93  // if next window ends lies inside term buffer,
94  // just make current window extend until term buffer
95  if (next_window_end > warmup_ - term_buffer_) {
96  window_end_ = warmup_ - term_buffer_;
97  }
98  }
99 
100  // If in init buffer or term buffer, don't adapt variance
101  // otherwise, adapt variance if within window.
102  // If reached end of current window, update variance, reset estimator, get new window.
103  template <class MatType1, class MatType2>
104  bool adapt(const Eigen::MatrixBase<MatType1>& x,
105  Eigen::MatrixBase<MatType2>& var)
106  {
107  // if counter is not at the end of all windows
108  if (counter_ >= init_buffer_ &&
109  counter_ < warmup_ - term_buffer_) {
110  var_estimator_.update(x);
111  }
112 
113  // if currently at the end of the window,
114  // get updated variance and reset estimator
115  if (counter_ == window_end_ - 1) {
116  auto&& v = var_estimator_.get_variance();
117  double n = var_estimator_.get_n_samples();
118  // regularized sample variance (see STAN)
119  var.array() = ( (n / ((n + 5.0) * (n - 1.))) * v.array() +
120  1e-3 * (5.0 / (n + 5.0)) );
121  var_estimator_.reset();
122  shift_window();
123  ++counter_;
124  return true;
125  }
126 
127  // init or term buffer => no adapt variance
128  static_cast<void>(x);
129  static_cast<void>(var);
130  ++counter_;
131  return false;
132  }
133 
134 private:
135 
136  // invariant: at the beginning of the call,
137  // next window is guaranteed to be fully before term buffer
138  // OR current window reaches the end of the window
139  void shift_window()
140  {
141  if (window_end_ == warmup_ - term_buffer_) { return; }
142 
143  size_t window_size = window_end_ - window_begin_;
144  window_begin_ = window_end_;
145  window_end_ = window_begin_ + 2 * window_size;
146 
147  // optimization
148  if (window_end_ == warmup_ - term_buffer_) { return; }
149 
150  size_t next_window_end = window_end_ + 4 * window_size;
151  if (next_window_end > warmup_ - term_buffer_) {
152  window_end_ = warmup_ - term_buffer_;
153  }
154  }
155 
156  math::WelfordVar var_estimator_;
157  const size_t warmup_;
158  size_t counter_;
159  size_t window_begin_;
160  size_t window_end_;
161  size_t init_buffer_;
162  size_t term_buffer_;
163  size_t window_base_;
164 };
165 
166 } // namespace mcmc
167 } // namespace ppl
ppl::dense_var
Definition: var_adapter.hpp:11
welford.hpp
ppl::mcmc::VarAdapter< diag_var >::adapt
bool adapt(const Eigen::MatrixBase< MatType1 > &x, Eigen::MatrixBase< MatType2 > &var)
Definition: var_adapter.hpp:104
ppl::unit_var
Definition: var_adapter.hpp:9
ppl::mcmc::VarAdapter
Definition: var_adapter.hpp:31
ppl::VarConfig::window_base
size_t window_base
Definition: var_adapter.hpp:21
ppl::diag_var
Definition: var_adapter.hpp:10
ppl::VarConfig
Definition: var_adapter.hpp:18
ppl
Definition: bounded.hpp:11
ppl::VarConfig::term_buffer
size_t term_buffer
Definition: var_adapter.hpp:20
ppl::mcmc::VarAdapter< diag_var >::VarAdapter
VarAdapter(size_t n_params, size_t warmup, size_t init_buffer, size_t term_buffer, size_t window_base)
Definition: var_adapter.hpp:58
ppl::VarConfig::init_buffer
size_t init_buffer
Definition: var_adapter.hpp:19
ppl::mcmc::VarAdapter< unit_var >::VarAdapter
VarAdapter(size_t, size_t, size_t, size_t, size_t)
Definition: var_adapter.hpp:40