BlackCat_Tensors
A GPU-supported autograd and linear algebra library, designed for neural network construction
layer_manager.h
Go to the documentation of this file.
1 /*
2  * Layer_Manager.h
3  *
4  * Created on: Jul 23, 2019
5  * Author: joseph
6  */
7 
8 #ifndef LAYER_MANAGER_H_
9 #define LAYER_MANAGER_H_
10 
11 #include "layer_cache.h"
12 
13 namespace bc {
14 namespace nn {
15 
16 template<class Derived, class Layer>
17 struct Layer_Manager: Layer {
18 
19  template<class D, class L>
20  friend class Layer_Manager;
21 
26 
30 
31  template<char C, class Tensor, cache_key_type override=cache_key_type::inherit>
33 
34 private:
35 
40 
42 
43  Cache m_cache;
44 
45 public:
46 
47  template<class... Args>
48  Layer_Manager(Args... args):
49  Layer(args...) {}
50 
51  template<class T, class l=Layer>
52  auto forward_propagation(const T& expression) {
53  static_assert(T::tensor_dim == Layer::input_tensor_dim::value + 1,
54  "Invalid tensor_dim in forward_propagation");
55  BC_ASSERT(expression.get_shape() == this->get_batched_input_shape(),
56  "forward_propagation input must have the same shape as "
57  "get_batched_input_shape() of the current layer "
58  "(Invalid input dims) "
59  "\nLayer: " + Layer::classname() +
60  "\nExpected shape: " + this->get_batched_input_shape().to_string() +
61  "\nReceived Shape: " + expression.get_shape().inner_shape().to_string());
62 
63  return forward_supply_outputs(
65  store_batched_inputs(expression));
66  }
67 
68  template<class T>
69  auto back_propagation(const T& dy) {
70  static_assert(T::tensor_dim == output_tensor_dim::value + 1,
71  "Invalid tensor_dim in back_propagation");
72  BC_ASSERT(dy.get_shape() == this->get_batched_output_shape(),
73  "back_propagation input must have the same shape as "
74  "get_batched_output_shape() of the current layer "
75  "(Invalid input dims) "
76  "\nLayer: " + Layer::classname() +
77  "\nExpected shape: " + this->get_batched_input_shape().to_string() +
78  "\nReceived Shape: " + dy.get_shape().inner_shape().to_string());
79 
80  return backward_supply_outputs(
82  get_batched_inputs(),
83  maybe_cache_delta(dy));
84  }
85 
86  //TODO batched_predict_input_key
87  template<class T>
88  auto predict(const T& expression) {
89  static_assert(T::tensor_dim == input_tensor_dim::value + 1,
90  "Invalid tensor_dim in predict");
91  BC_ASSERT(expression.get_shape() == this->get_batched_input_shape(),
92  "predict<T> input must have the same shape as "
93  "get_batched_input_shape() of the current layer "
94  "(Invalid input dims) "
95  "\nLayer: " + Layer::classname() +
96  "\nExpected shape: " + this->get_batched_input_shape().to_string() +
97  "\nReceived Shape: " + expression.get_shape().inner_shape().to_string());
98 
99  return predict_supply_outputs(
101  store_batched_inputs(expression));
102  }
103 
104  //TODO input_key -> predict_input_key
105  template<class T>
106  auto single_predict(const T& expression) {
107  static_assert(T::tensor_dim == input_tensor_dim::value,
108  "Invalid tensor_dim in single_predict");
109  BC_ASSERT(expression.get_shape() == this->get_input_shape(),
110  "single_predict<T> input must have the same shape as "
111  "get_input_shape() of the current layer "
112  "(Invalid input dims) "
113  "\nLayer: " + Layer::classname() +
114  "\nExpected shape: " + this->get_input_shape().to_string() +
115  "\nReceived Shape: " + expression.get_shape().inner_shape().to_string());
116 
117  static_assert(T::tensor_dim ==
118  traits::input_tensor_dim::value,
119  "assert same dim as layer");
120 
121  return single_predict_supply_outputs(
123  this->m_cache.store(input_key(), expression));
124  }
125 
126  void update_weights() {
127  Layer::update_weights();
129  Layer::clear_bp_storage(m_cache);
130  }
131 
132  virtual void save(Layer_Loader& loader) const override {
133  loader.save_variable(get_batched_inputs(), "x");
134  Layer::save(loader);
135  Layer::save_from_cache(loader, m_cache);
136  }
137 
138  virtual void load (Layer_Loader& loader) override {
139  loader.load_variable(get_batched_inputs(), "x");
140  Layer::load(loader);
141  Layer::load_to_cache(loader, m_cache);
142  }
143 
144  void copy_training_data_to_single_predict(int batch_index) {
145  Layer::copy_training_data_to_single_predict(m_cache, batch_index);
146  get_predict_inputs() = get_batched_inputs()[batch_index];
147  }
148 
149  const Cache& get_cache() const {
150  return m_cache;
151  }
152 
154  return m_cache;
155  }
156 
158  m_cache.zero_time_index();
159  }
160 
162  m_cache.increment_time_index();
163  }
164 
165 private:
166 
167  auto& get_batched_inputs() const {
168  return m_cache.load(
170  this->default_batched_input_tensor_factory());
171  }
172 
173  auto& get_predict_inputs() const {
174  return m_cache.load(
175  input_key(),
176  this->default_input_tensor_factory());
177  }
178 
179  template<class X>
180  auto& store_batched_inputs(const X& x) {
181  return this->m_cache.store(batched_input_key(), x);
182  }
183 
184  auto& next_layer() {
185  return static_cast<Derived&>(*this).next().layer();
186  }
187 
188  // Handle Forward Args ------------------------------------------------
189 
190  template<class X>
191  auto forward_supply_outputs(std::false_type, const X& inputs) {
192  return forward_supply_cache(
193  typename traits::requires_extra_cache(),
194  inputs);
195  }
196 
197  template<class Input>
198  auto forward_supply_outputs(std::true_type, const Input& inputs) {
199  auto& outputs = next_layer().get_batched_inputs();
200  return forward_supply_cache(
201  typename traits::requires_extra_cache(),
202  inputs,
203  outputs);
204  }
205 
206  template<class... Args>
207  auto forward_supply_cache(std::false_type, const Args&... args) {
208  return Layer::forward_propagation(args...);
209  }
210 
211  template<class... Args>
212  auto forward_supply_cache(std::true_type, const Args&... args) {
213  return Layer::forward_propagation(args..., m_cache);
214  }
215 
216  //Handle Predict Args ------------------------------------------------
217 
218  template<class X>
219  auto predict_supply_outputs(std::false_type, const X& inputs) {
220  return predict_supply_cache(typename traits::requires_extra_cache(), inputs);
221  }
222 
223  template<class Input>
224  auto predict_supply_outputs(std::true_type, const Input& inputs) {
225  auto& outputs = next_layer().get_batched_inputs();
226  return predict_supply_cache(typename traits::requires_extra_cache(), inputs, outputs);
227  }
228 
229  template<class... Args>
230  auto predict_supply_cache(std::false_type, Args&&... args) {
231  return traits::select_on_predict(*this, std::forward<Args>(args)...);
232  }
233 
234  template<class... Args>
235  auto predict_supply_cache(std::true_type, Args&&... args) {
236  return traits::select_on_predict(*this, std::forward<Args>(args)..., m_cache);
237  }
238 
239  //Handle Single Predict Args -------------------------------------------
240 
241  template<class X>
242  auto single_predict_supply_outputs(std::false_type, const X& inputs) {
243  static_assert(X::tensor_dim == input_tensor_dim::value,
244  "Assert single-batch dim for Neural_Network.predict()");
245  return single_predict_supply_cache(typename traits::requires_extra_cache(), inputs);
246  }
247 
248  template<class Input>
249  auto single_predict_supply_outputs(std::true_type, const Input& inputs) {
250  auto default_factory = [&]() {
251  return input_tensor_type(this->get_output_shape()).zero();
252  };
253 
254  using key_type = typename std::decay_t<decltype(next_layer())>::input_key;
255  auto& outputs = next_layer().m_cache.load(key_type(), default_factory);
256  return single_predict_supply_cache(typename traits::requires_extra_cache(), inputs, outputs);
257  }
258 
259  template<class... Args>
260  auto single_predict_supply_cache(std::false_type, const Args&... args) {
261  return traits::select_on_single_predict(*this, args...);
262  }
263 
264  template<class... Args>
265  auto single_predict_supply_cache(std::true_type, const Args&... args) {
266  return traits::select_on_single_predict(*this, args..., m_cache);
267  }
268 
269  //Handel backward args ------------------------------------------------
270 
271  template<class X, class... T>
272  auto backward_supply_outputs(std::false_type, const X& x, const T&... args) {
273  return backward_supply_cache(typename traits::requires_extra_cache(), x, args...);
274  }
275 
276  template<class Input, class Dy>
277  auto backward_supply_outputs(std::true_type, const Input& inputs, const Dy& delta) {
278  auto& outputs = next_layer().get_batched_inputs();
279  return backward_supply_cache(typename traits::requires_extra_cache(), inputs, outputs, delta);
280  }
281 
282  template<class... Args>
283  auto backward_supply_cache(std::false_type, const Args&... args) {
284  return Layer::back_propagation(args...);
285  }
286 
287  template<class... Args>
288  auto backward_supply_cache(std::true_type, Args&... args) {
289  return Layer::back_propagation(args..., m_cache);
290  }
291 
292  template<class T>
293  auto&& maybe_cache_delta(const T& dy) {
294  using should_greedy_eval = bc::traits::truth_type<
296  traits::greedy_evaluate_delta::value>;
297 
298  return maybe_cache_delta_impl(should_greedy_eval(), dy);
299  }
300 
301  template<class T>
302  auto& maybe_cache_delta_impl(std::true_type cache_delta, const T& dy) {
303  return m_cache.store(batched_delta_key(), dy);
304  }
305 
306  template<class T>
307  const T& maybe_cache_delta_impl(std::false_type cache_delta, const T& dy) {
308  return dy;
309  }
310 };
311 
312 
313 } // namespace nn
314 } // namespace BC
315 
316 
317 
318 #endif /* LAYER_MANAGER_H_ */
bc::Tensor< input_tensor_dim::value, value_type, allocator_type > input_tensor_type
Definition: layer_manager.h:27
typename layer_traits< CurrentLayer >::output_tensor_dim output_tensor_dim
Definition: layer_manager.h:23
typename layer_traits< CurrentLayer >::allocator_type allocator_type
Definition: layer_manager.h:24
Layer_Manager(Args... args)
Definition: layer_manager.h:48
A Dictionary designed to store any type using the &#39;store&#39; and &#39;load&#39; functions.
Definition: layer_cache.h:46
Definition: layer_loader.h:19
bc::tensors::Tensor_Base< bc::tensors::exprs::Array< bc::Shape< dim >, ValueType, Allocator > > Tensor
Definition: tensors.h:39
auto forward_propagation(const T &expression)
Definition: layer_manager.h:52
bc::traits::conditional_detected_t< bc::traits::query_value_type, T, typename system_tag::default_floating_point_type > value_type
Definition: layer_traits.h:60
virtual void save(Layer_Loader &loader) const override
Definition: layer_manager.h:132
void save_variable(const T &tensor, string variable_name)
Definition: layer_loader.h:44
Definition: layer_cache.h:33
typename layer_traits< CurrentLayer >::value_type value_type
Definition: layer_manager.h:25
Definition: layer_traits.h:42
typename layer_traits< CurrentLayer >::input_tensor_dim input_tensor_dim
Definition: layer_manager.h:22
void copy_training_data_to_single_predict(int batch_index)
Definition: layer_manager.h:144
void zero_time_index()
Definition: layer_cache.h:187
bc::traits::conditional_detected_t< detail::query_forward_requires_outputs, T, std::false_type > forward_requires_outputs
Definition: layer_traits.h:80
void zero_time_index()
Definition: layer_manager.h:157
cache_key< bc::utility::Name< C >, Tensor, override > key_type
Definition: layer_manager.h:32
bc::traits::conditional_detected_t< bc::traits::query_allocator_type, T, bc::Allocator< value_type, system_tag > > allocator_type
Definition: layer_traits.h:65
Cache & get_cache()
Definition: layer_manager.h:153
auto back_propagation(const T &dy)
Definition: layer_manager.h:69
Definition: expression_template_traits.h:76
void increment_time_index()
Definition: layer_cache.h:185
void clear_bp_storage(key_type< K, V, cache_key_type::always_forward > key)
Definition: layer_cache.h:191
bc::traits::conditional_detected_t< detail::query_requires_extra_cache, T, std::false_type > requires_extra_cache
Definition: layer_traits.h:68
auto predict(const T &expression)
Definition: layer_manager.h:88
Definition: layer_manager.h:17
bc::traits::conditional_detected_t< detail::query_output_tensor_dim, T, input_tensor_dim > output_tensor_dim
Definition: layer_traits.h:74
auto single_predict(const T &expression)
Definition: layer_manager.h:106
void update_weights()
Definition: layer_manager.h:126
auto & store(key_type< K, V, cache_key_type::inherit > key, U &&expression)
Definition: layer_cache.h:104
static auto select_on_single_predict(T &layer, Args &&... args)
Definition: layer_traits.h:111
void load_variable(T &tensor, string variable_name)
Definition: layer_loader.h:50
auto & load(key_type< K, V, cache_key_type::inherit > key, int t_modifier=0) const
Definition: layer_cache.h:80
conditional_t< Bool, true_type, false_type > truth_type
Definition: type_traits.h:49
static auto select_on_predict(T &layer, Args &&... args)
Definition: layer_traits.h:102
#define BC_ASSERT(condition, message)
Definition: common.h:185
bc::traits::conditional_detected_t< detail::query_input_tensor_dim, T, bc::traits::Integer< 1 > > input_tensor_dim
Definition: layer_traits.h:71
void increment_time_index()
Definition: layer_manager.h:161
const Cache & get_cache() const
Definition: layer_manager.h:149
virtual void load(Layer_Loader &loader) override
Definition: layer_manager.h:138
bc::traits::conditional_detected_t< detail::query_backward_requires_outputs, T, std::false_type > backward_requires_outputs
Definition: layer_traits.h:89
The Evaluator determines if an expression needs to be greedily optimized.
Definition: algorithms.h:22