ceras
yet another deep learning engine
model.hpp
Go to the documentation of this file.
1 #ifndef BPLYFMIFNNWSGMLLEKBJMAJDBRSPHHRAYMOHTWSTCMNMFSLLYNQTTCCAQXKXSLMSLKESHRASL
2 #define BPLYFMIFNNWSGMLLEKBJMAJDBRSPHHRAYMOHTWSTCMNMFSLLYNQTTCCAQXKXSLMSLKESHRASL
3 
4 #include "./includes.hpp"
5 #include "./operation.hpp"
6 #include "./place_holder.hpp"
7 #include "./tensor.hpp"
8 #include "./utils/better_assert.hpp"
9 #include "./utils/context_cast.hpp"
10 #include "./utils/tqdm.hpp"
11 
12 namespace ceras
13 {
17  template< Expression Ex >
18  void make_trainable( Ex& ex , bool t )
19  {
20  if constexpr (is_variable_v<Ex>)
21  {
22  ex.trainable( t );
23  }
24  else if constexpr (is_binary_operator_v<Ex>)
25  {
26  make_trainable( ex.lhs_op_, t );
27  make_trainable( ex.rhs_op_, t );
28  }
29  else if constexpr (is_unary_operator_v<Ex>)
30  {
31  make_trainable( ex.op_, t );
32  }
33  }
34 
43  template< Expression Ex, Place_Holder Ph, Expression Ey >
44  auto replace_placeholder_with_expression( Ex const& ex, Ph const& old_place_holder, Ey const& new_expression )
45  {
46  if constexpr (is_value_v<Ex> || is_constant_v<Ex> || is_variable_v<Ex>)
47  {
48  return ex;
49  }
50  else if constexpr (is_place_holder_v<Ex>)
51  {
52  return new_expression; // assuming only one place holder in the model
53  //return (ex == old_place_holder) ? new_expression : ex;
54  }
55  else if constexpr (is_unary_operator_v<Ex>)
56  {
57  return make_unary_operator( ex.forward_action_, ex.backward_action_, ex.name_ )( replace_placeholder_with_expression( ex.op_, old_place_holder, new_expression ) );
58  }
59  else if constexpr (is_binary_operator_v<Ex>)
60  {
61  return make_binary_operator( ex.forward_action_, ex.backward_action_, ex.name_ )
62  ( replace_placeholder_with_expression( ex.lhs_op_, old_place_holder, new_expression ),
63  replace_placeholder_with_expression( ex.rhs_op_, old_place_holder, new_expression ) );
64  }
65  else
66  {
67  better_assert( false, "replace::Should never reach here!" );
68  }
69  }
70 
71  template< typename Model, typename Optimizer, typename Loss >
73  {
74  typedef typename Model::input_layer_type io_layer_type;
75  typedef decltype(std::declval<Optimizer>()(std::declval<Loss&>())) optimizer_type; // defined because the compiled optimizer takes a reference to an expression as its parameter
76 
77  Model model_;
80  Loss loss_; // MeanSquaredError()( model_.output() )( find a input );
81  Optimizer optimizer_; // Adam( ... )
83 
84  compiled_model( Model const& m, io_layer_type const& input_place_holder, io_layer_type const& ground_truth_place_holder, Loss const& loss, Optimizer const& optimizer ):
85  model_{m}, input_place_holder_{input_place_holder}, ground_truth_place_holder_{ground_truth_place_holder}, loss_{loss}, optimizer_{optimizer}, compiled_optimizer_{ optimizer_(loss_) } { }
86 
94  template< Tensor Tsor >
95  auto evaluate( Tsor const& inputs, Tsor const& outputs, unsigned long batch_size=32 )
96  {
97  // extract size of samples
98  unsigned long const samples = *(inputs.shape().begin());
99  unsigned long const loops = samples / batch_size;
100 
101  // prepare tensor for inputs
102  std::vector<unsigned long> batch_input_shape = inputs.shape();
103  batch_input_shape[0] = batch_size;
104  Tsor input_samples{ batch_input_shape };
105  unsigned long const input_size_per_batch = input_samples.size();
106 
107  // prepare tensor for outputs
108  std::vector<unsigned long> batch_output_shape = outputs.shape();
109  batch_output_shape[0] = batch_size;
110  Tsor output_samples{ batch_output_shape };
111  unsigned long const output_size_per_batch = output_samples.size();
112 
113  // bind tensors to place holders
114  //session<Tsor> s;
115  auto& s = get_default_session<Tsor>();
116  s.bind( input_place_holder_, input_samples );
117  s.bind( ground_truth_place_holder_, output_samples );
118 
119  typedef typename Tsor::value_type value_type;
120  value_type validation_error = 0;
121 
122  learning_phase = 0; // for different behaviours in normalization and drop-out layers
123 
124  for ( auto l : tq::trange( loops ) )
125  {
126  // feed data
127  std::copy_n( inputs.data() + l * input_size_per_batch, input_size_per_batch, input_samples.data() );
128  std::copy_n( outputs.data() + l * output_size_per_batch, output_size_per_batch, output_samples.data() );
129  // forward pass
130  auto error = s.run( loss_ ).as_scalar();
131  // in case of training split, do backpropagation
132  validation_error += error;
133  }
134 
135  learning_phase = 1; // for different behaviours in normalization and drop-out layers
136 
137  return validation_error / loops;
138  }
139 
163  template< Tensor Tsor >
164  auto fit( Tsor const& inputs, Tsor const& outputs, unsigned long batch_size, unsigned long epoch=1, int verbose=0, double validation_split=0.0 )
165  {
166  // extract size of samples
167  unsigned long const samples = *(inputs.shape().begin());
168  unsigned long const loops_per_epoch = samples / batch_size;
169  unsigned long const training_loops = ( 1.0 - validation_split ) * loops_per_epoch;
170  unsigned long const validation_loops = loops_per_epoch - training_loops;
171 
172  // prepare tensor for inputs
173  std::vector<unsigned long> batch_input_shape = inputs.shape();
174  batch_input_shape[0] = batch_size;
175  Tsor input_samples{ batch_input_shape };
176  unsigned long const input_size_per_batch = input_samples.size();
177 
178  // prepare tensor for outputs
179  std::vector<unsigned long> batch_output_shape = outputs.shape();
180  batch_output_shape[0] = batch_size;
181  Tsor output_samples{ batch_output_shape };
182  unsigned long const output_size_per_batch = output_samples.size();
183 
184  // bind tensors to place holders
185  //session<Tsor> s;
186  auto& s = get_default_session<Tsor>();//.get();
187  s.bind( input_place_holder_, input_samples );
188  s.bind( ground_truth_place_holder_, output_samples );
189 
190  // collect training errors
191  typedef typename Tsor::value_type value_type;
192  std::vector<value_type> training_errors;
193  std::vector<value_type> validation_errors;
194 
195  learning_phase = 1; // for different behaviours in normalization and drop-out layers
196 
197  for ( auto e : range( epoch ) )
198  {
199  value_type training_error = 0;
200  value_type validation_error = 0;
201  for ( auto l : tq::trange( loops_per_epoch ) )
202  {
203  // feed data
204  std::copy_n( inputs.data() + l * input_size_per_batch, input_size_per_batch, input_samples.data() );
205  std::copy_n( outputs.data() + l * output_size_per_batch, output_size_per_batch, output_samples.data() );
206  // forward pass
207  auto error = s.run( loss_ ).as_scalar();
208  // in case of training split, do backpropagation
209  if ( l <= training_loops )
210  {
211  training_error += error;
212  s.run( compiled_optimizer_ );
213  }
214  else // in case of validation split, just collect errors
215  {
216  validation_error += error;
217  }
218  }
219  training_errors.push_back( training_error / training_loops );
220  validation_errors.push_back( validation_error / validation_loops );
221  if ( verbose )
222  std::cout << "\nTraining error: " << training_error / training_loops << " and validation error: " << validation_error / validation_loops << " at epoch: " << e+1 << "/" << epoch;
223  std::cout << std::endl;
224  }
225  return std::make_tuple( training_errors, validation_errors );
226  }
227 
246  template< Tensor Tsor >
247  auto train_on_batch( Tsor const& input, Tsor const& output )
248  {
249  learning_phase = 1; // for different behaviours in normalization and drop-out layers
250  auto& s = get_default_session<Tsor>();//.get();
251  s.bind( input_place_holder_, input );
252  s.bind( ground_truth_place_holder_, output );
253  //debug_log( "Training on batch forward pass." );
254  auto error = s.run( loss_ );
255  //debug_log( "Training on batch backward pass." );
256  s.run( compiled_optimizer_ );
257  return error.as_scalar();
258  }
259 
260  template< Tensor Tsor>
261  auto predict( Tsor const& input_tensor )
262  {
263  auto m = model_;
264  return m.predict( input_tensor );
265  }
266 
267  template< Expression Exp >
268  auto operator()( Exp const& ex ) const noexcept
269  {
270  return model_( ex );
271  }
272 
273  void trainable( bool t )
274  {
275  model_.trainable( t );
276  }
277  };
278 
279  template< typename Model, typename Optimizer, typename Loss >
280  inline auto make_compiled_model( Model const& m, Loss const& l, Optimizer const& o )
281  {
282  auto input_place_holder = m.input();
283  auto ground_truth_place_holder = typename Model::input_layer_type{};
284  auto loss = l( m.output() )( ground_truth_place_holder );
285  auto optimizer = o( loss );
286  return compiled_model{ m, input_place_holder, ground_truth_place_holder, loss, o};
287  }
288 
295  template< Expression Ex, Place_Holder Ph >
296  struct model
297  {
298  typedef Ph input_layer_type;
299  typedef Ex output_layer_type;
300 
302  input_layer_type place_holder_;//< input layer of the model.
303 
304 
308  input_layer_type input() const noexcept { return place_holder_; }
309 
313  output_layer_type output() const noexcept { return expression_; }
314 
328 
345  template< Tensor Tsor>
346  auto predict( Tsor const& input_tensor )
347  {
348  learning_phase = 0; // for different behaviours in normalization and drop-out layers
349 
350  //session<Tsor> s;
351  auto& s = get_default_session<Tsor>();//.get();
352  s.bind( place_holder_, input_tensor );
353 
354  auto ans = s.run( expression_ );
355 
356  learning_phase = 1; // restore learning phase
357 
358  return ans;
359  }
360 
381  template< Expression Exp >
382  auto operator()( Exp const& ex ) const noexcept
383  {
385  }
386 
401  template< typename Loss, typename Optimizer >
402  auto compile( Loss const& l, Optimizer const& o )
403  {
404  return make_compiled_model( *this, l, o );
405  }
406 
407  void trainable( bool t )
408  {
410  }
411 
412 
416  void save_weights( std::string const& file )
417  {
418  auto& s = get_default_session<tensor<float>>();
419  s.serialize( file );
420  }
421 
425  void load_weights( std::string const& file )
426  {
427  auto& s = get_default_session<tensor<float>>();
428  s.deserialize( file );
429  }
430 
431 
436  void summary(std::string const& file_name=std::string{}) const noexcept
437  {
438  auto g = computation_graph( expression_ );
439 
440  if ( file_name.empty() )
441  {
442  std::cout << g << std::endl;
443  return;
444  }
445 
446  std::ofstream ofs{ file_name };
447  ofs << g;
448  }
449 
450 
451  };
452 
453 }//namespace ceras
454 
455 #endif//BPLYFMIFNNWSGMLLEKBJMAJDBRSPHHRAYMOHTWSTCMNMFSLLYNQTTCCAQXKXSLMSLKESHRASLCalculate the loss for the model in test model
Definition: activation.hpp:12
static constexpr auto make_binary_operator
Definition: operation.hpp:108
auto make_compiled_model(Model const &m, Loss const &l, Optimizer const &o)
Definition: model.hpp:280
auto replace_placeholder_with_expression(Ex const &ex, Ph const &old_place_holder, Ey const &new_expression)
Definition: model.hpp:44
std::string computation_graph(Ex const &ex) noexcept
Definition: operation.hpp:178
void make_trainable(Ex &ex, bool t)
Definition: model.hpp:18
static constexpr auto make_unary_operator
Definition: operation.hpp:49
Definition: model.hpp:73
auto fit(Tsor const &inputs, Tsor const &outputs, unsigned long batch_size, unsigned long epoch=1, int verbose=0, double validation_split=0.0)
Definition: model.hpp:164
Loss loss_
Definition: model.hpp:80
Optimizer optimizer_
Definition: model.hpp:81
optimizer_type compiled_optimizer_
Definition: model.hpp:82
decltype(std::declval< Optimizer >()(std::declval< Loss & >())) typedef optimizer_type
Definition: model.hpp:75
auto evaluate(Tsor const &inputs, Tsor const &outputs, unsigned long batch_size=32)
Definition: model.hpp:95
Model model_
Definition: model.hpp:77
auto operator()(Exp const &ex) const noexcept
Definition: model.hpp:268
io_layer_type input_place_holder_
Definition: model.hpp:78
void trainable(bool t)
Definition: model.hpp:273
Model::input_layer_type io_layer_type
Definition: model.hpp:74
io_layer_type ground_truth_place_holder_
Definition: model.hpp:79
auto train_on_batch(Tsor const &input, Tsor const &output)
Definition: model.hpp:247
auto predict(Tsor const &input_tensor)
Definition: model.hpp:261
Definition: model.hpp:297
Ex output_layer_type
Definition: model.hpp:299
auto compile(Loss const &l, Optimizer const &o)
Definition: model.hpp:402
model(input_layer_type const &place_holder, output_layer_type const &expression)
Definition: model.hpp:327
void trainable(bool t)
Definition: model.hpp:407
input_layer_type place_holder_
Definition: model.hpp:302
output_layer_type expression_
output layer of the model.
Definition: model.hpp:301
void save_weights(std::string const &file)
Definition: model.hpp:416
auto operator()(Exp const &ex) const noexcept
Definition: model.hpp:382
output_layer_type output() const noexcept
Definition: model.hpp:313
input_layer_type input() const noexcept
Definition: model.hpp:308
void summary(std::string const &file_name=std::string{}) const noexcept
Definition: model.hpp:436
auto predict(Tsor const &input_tensor)
Definition: model.hpp:346
Ph input_layer_type
Definition: model.hpp:298
void load_weights(std::string const &file)
Definition: model.hpp:425
Definition: place_holder.hpp:24