keras_model.cc
Go to the documentation of this file.
1 #include "keras_model.h"
2 
3 #include "tbb/parallel_for.h"
4 
5 #include <fstream>
6 #include <algorithm>
7 #include <math.h>
8 using namespace std;
9 
10 
11 std::vector<float> keras::read_1d_array(std::ifstream &fin, int cols) {
12  vector<float> arr;
13  float tmp_float;
14  char tmp_char;
15  fin >> tmp_char; // for '['
16  for(int n = 0; n < cols; ++n) {
17  fin >> tmp_float;
18  arr.push_back(tmp_float);
19  }
20  fin >> tmp_char; // for ']'
21  return arr;
22 }
23 
25  ifstream fin(fname.c_str());
26  fin >> m_depth >> m_rows >> m_cols;
27 
28  for(int d = 0; d < m_depth; ++d) {
29  vector<vector<float> > tmp_single_depth;
30  for(int r = 0; r < m_rows; ++r) {
31  vector<float> tmp_row = keras::read_1d_array(fin, m_cols);
32  tmp_single_depth.push_back(tmp_row);
33  }
34  data.push_back(tmp_single_depth);
35  }
36  fin.close();
37 }
38 
39 
40 void keras::LayerConv2D::load_weights(std::ifstream &fin) {
41  char tmp_char = ' ';
42  string tmp_str = "";
43  float tmp_float;
44  bool skip = false;
45  fin >> m_kernels_cnt >> m_depth >> m_rows >> m_cols >> m_border_mode;
46  if (m_border_mode == "[") { m_border_mode = "valid"; skip = true; }
47 
48  cout << "LayerConv2D " << m_kernels_cnt
49  << "x" << m_depth << "x" << m_rows << "x" << m_cols << " border_mode " << m_border_mode << endl;
50  // reading kernel weights
51  for(int k = 0; k < m_kernels_cnt; ++k) {
52  vector<vector<vector<float> > > tmp_depths;
53  for(int d = 0; d < m_depth; ++d) {
54  vector<vector<float> > tmp_single_depth;
55  for(int r = 0; r < m_rows; ++r) {
56  if (!skip) { fin >> tmp_char; } // for '['
57  else { skip = false; }
58  vector<float> tmp_row;
59  for(int c = 0; c < m_cols; ++c) {
60  fin >> tmp_float;
61  //cout << tmp_float << " ";
62  tmp_row.push_back(tmp_float);
63  }
64  fin >> tmp_char; // for ']'
65  tmp_single_depth.push_back(tmp_row);
66  }
67  tmp_depths.push_back(tmp_single_depth);
68  }
69  m_kernels.push_back(tmp_depths);
70  }
71  // reading kernel biases
72  fin >> tmp_char; // for '['
73  for(int k = 0; k < m_kernels_cnt; ++k) {
74  fin >> tmp_float;
75  m_bias.push_back(tmp_float);
76  }
77  fin >> tmp_char; // for ']'
78 
79 }
80 
81 void keras::LayerActivation::load_weights(std::ifstream &fin) {
82  fin >> m_activation_type;
83  cout << "Activation type " << m_activation_type << endl;
84 }
85 
86 void keras::LayerMaxPooling::load_weights(std::ifstream &fin) {
87  fin >> m_pool_x >> m_pool_y;
88  cout << "MaxPooling " << m_pool_x << "x" << m_pool_y << endl;
89 }
90 
91 void keras::LayerDense::load_weights(std::ifstream &fin) {
92  fin >> m_input_cnt >> m_neurons;
93  float tmp_float;
94  char tmp_char = ' ';
95  for(int i = 0; i < m_input_cnt; ++i) {
96  vector<float> tmp_n;
97  fin >> tmp_char; // for '['
98  for(int n = 0; n < m_neurons; ++n) {
99  fin >> tmp_float;
100  tmp_n.push_back(tmp_float);
101  }
102  fin >> tmp_char; // for ']'
103  m_weights.push_back(tmp_n);
104  }
105  cout << "weights " << m_weights.size() << endl;
106  fin >> tmp_char; // for '['
107  for(int n = 0; n < m_neurons; ++n) {
108  fin >> tmp_float;
109  m_bias.push_back(tmp_float);
110  }
111  fin >> tmp_char; // for ']'
112  cout << "bias " << m_bias.size() << endl;
113 
114 }
115 
116 keras::KerasModel::KerasModel(const string &input_fname) {
117  load_weights(input_fname);
118 }
119 
120 
122  vector<vector<vector<float> > > im = dc->get_3d();
123 
124  size_t csize = im[0].size();
125  size_t rsize = im[0][0].size();
126  size_t size = im.size() * csize * rsize;
127  keras::DataChunkFlat *out = new DataChunkFlat(size);
128  float * y_ret = out->get_1d_rw().data();
129  for(size_t i = 0, dst = 0; i < im.size(); ++i) {
130  for(size_t j = 0; j < csize; ++j) {
131  float * row = im[i][j].data();
132  for(size_t k = 0; k < rsize; ++k) {
133  y_ret[dst++] = row[k];
134  }
135  }
136  }
137 
138  return out;
139 }
140 
141 
143  vector<vector<vector<float> > > im = dc->get_3d();
144  vector<vector<vector<float> > > y_ret;
145  for(unsigned int i = 0; i < im.size(); ++i) {
146  vector<vector<float> > tmp_y;
147  for(unsigned int j = 0; j < (unsigned int)(im[0].size()/m_pool_x); ++j) {
148  tmp_y.push_back(vector<float>((int)(im[0][0].size()/m_pool_y), 0.0));
149  }
150  y_ret.push_back(tmp_y);
151  }
152  for(unsigned int d = 0; d < y_ret.size(); ++d) {
153  for(unsigned int x = 0; x < y_ret[0].size(); ++x) {
154  unsigned int start_x = x*m_pool_x;
155  unsigned int end_x = start_x + m_pool_x;
156  for(unsigned int y = 0; y < y_ret[0][0].size(); ++y) {
157  unsigned int start_y = y*m_pool_y;
158  unsigned int end_y = start_y + m_pool_y;
159 
160  vector<float> values;
161  for(unsigned int i = start_x; i < end_x; ++i) {
162  for(unsigned int j = start_y; j < end_y; ++j) {
163  values.push_back(im[d][i][j]);
164  }
165  }
166  y_ret[d][x][y] = *max_element(values.begin(), values.end());
167  }
168  }
169  }
171  out->set_data(y_ret);
172  return out;
173 }
174 
175 void keras::missing_activation_impl(const string &act) {
176  cout << "Activation " << act << " not defined!" << endl;
177  cout << "Please add its implementation before use." << endl;
178  exit(1);
179 }
180 
182 
183  if (dc->get_data_dim() == 3) {
184  vector<vector<vector<float> > > y = dc->get_3d();
185  if(m_activation_type == "relu") {
186  for(unsigned int i = 0; i < y.size(); ++i) {
187  for(unsigned int j = 0; j < y[0].size(); ++j) {
188  for(unsigned int k = 0; k < y[0][0].size(); ++k) {
189  if(y[i][j][k] < 0) y[i][j][k] = 0;
190  }
191  }
192  }
193  } else if(m_activation_type == "tanh") {
194  for(unsigned int i = 0; i < y.size(); ++i) {
195  for(unsigned int j = 0; j < y[0].size(); ++j) {
196  for(unsigned int k = 0; k < y[0][0].size(); ++k) {
197  y[i][j][k] = tanh(y[i][j][k]);
198  }
199  }
200  }
201  } else {
202  keras::missing_activation_impl(m_activation_type);
203  }
204 
206  out->set_data(y);
207  return out;
208 
209  } else if (dc->get_data_dim() == 1) { // flat data, use 1D
210  vector<float> y = dc->get_1d();
211  if(m_activation_type == "relu") {
212  for(unsigned int k = 0; k < y.size(); ++k) {
213  if(y[k] < 0) y[k] = 0;
214  }
215  } else if(m_activation_type == "softmax") {
216  float sum = 0.0;
217  for(unsigned int k = 0; k < y.size(); ++k) {
218  y[k] = exp(y[k]);
219  sum += y[k];
220  }
221  for(unsigned int k = 0; k < y.size(); ++k) {
222  y[k] /= sum;
223  }
224  } else if(m_activation_type == "tanh") {
225  for(unsigned int k = 0; k < y.size(); ++k) {
226  y[k] = tanh(y[k]);
227  }
228  } else if(m_activation_type == "sigmoid") {
229  for(unsigned int k = 0; k < y.size(); ++k) {
230  y[k] = 1.0F / (1.0F + exp(-y[k]));
231  }
232  } else {
233  keras::missing_activation_impl(m_activation_type);
234  }
235 
236  keras::DataChunk *out = new DataChunkFlat();
237  out->set_data(y);
238  return out;
239 
240  } else { throw "data dim not supported"; }
241 
242  return dc;
243 }
244 
245 // with border mode = valid
247  std::vector< std::vector<float> > & y, // accumulate here
248  std::vector< std::vector<float> > const & im,
249  std::vector< std::vector<float> > const & k)
250 {
251  size_t k1_size = k.size(), k2_size = k[0].size();
252  unsigned int st_x = (k1_size - 1) >> 1;
253  unsigned int st_y = (k2_size - 1) >> 1;
254 
255  for(unsigned int i = st_x; i < im.size()-st_x; ++i) {
256  for(unsigned int j = st_y; j < im[0].size()-st_y; ++j) {
257 
258  float sum = 0;
259  for(unsigned int k1 = 0; k1 < k1_size; ++k1) {
260  //const float * k_data = k[k1_size-k1-1].data();
261  //const float * im_data = im[i-st_x+k1].data();
262  for(unsigned int k2 = 0; k2 < k2_size; ++k2) {
263  //sum += k_data[k2_size-k2-1] * im_data[j-st_y+k2];
264  sum += k[k1_size-k1-1][k2_size-k2-1] * im[i-st_x+k1][j-st_y+k2];
265  }
266  }
267  y[i-st_x][j-st_y] += sum;
268  }
269  }
270 }
271 
272 // with border mode = same
274  std::vector< std::vector<float> > & y, // accumulate here
275  std::vector< std::vector<float> > const & im,
276  std::vector< std::vector<float> > const & k)
277 {
278  size_t k1_size = k.size(), k2_size = k[0].size();
279  unsigned int st_x = (k1_size - 1) >> 1;
280  unsigned int st_y = (k2_size - 1) >> 1;
281 
282  size_t max_imc = im.size() - 1;
283  size_t max_imr = im[0].size() - 1;
284 
285  for(unsigned int i = 0; i < im.size(); ++i) {
286  for(unsigned int j = 0; j < im[0].size(); ++j) {
287 
288  float sum = 0;
289  for(unsigned int k1 = 0; k1 < k1_size; ++k1) {
290  //const float * k_data = k[k1_size-k1-1].data();
291  //const float * im_data = im[i-st_x+k1].data();
292  for(unsigned int k2 = 0; k2 < k2_size; ++k2) {
293  if(i+k1 < st_x) continue;
294  if(i+k1 > max_imc+st_x) continue;
295  if(j+k2 < st_y) continue;
296  if(j+k2 > max_imr+st_y) continue;
297 
298  //sum += k_data[k2_size-k2-1] * im_data[j-st_y+k2];
299  sum += k[k1_size-k1-1][k2_size-k2-1] * im[i-st_x+k1][j-st_y+k2];
300  }
301  }
302  y[i][j] += sum;
303  }
304  }
305 }
306 
308  unsigned int st_x = (m_kernels[0][0].size()-1) >> 1;
309  unsigned int st_y = (m_kernels[0][0][0].size()-1) >> 1;
310  auto const & im = dc->get_3d();
311 
312  size_t size_x = (m_border_mode == "valid")? im[0].size() - 2 * st_x : im[0].size();
313  size_t size_y = (m_border_mode == "valid")? im[0][0].size() - 2 * st_y: im[0][0].size();
314 
315  // depth rows cols
316  keras::DataChunk2D *out = new keras::DataChunk2D(m_kernels.size(), size_x, size_y, 0);
317  auto & y_ret = out->get_3d_rw();
318 
319  //auto t1 = std::chrono::high_resolution_clock::now();
320 
321  // Parallelize the kernal calculation
322  tbb::parallel_for( size_t(0), size_t(m_kernels.size()), [&]( size_t j ) {
323 
324  for(unsigned int m = 0; m < im.size(); ++m) { // loop over image depth
325  if (m_border_mode == "valid")
326  keras::conv_single_depth_valid(y_ret[j], im[m], m_kernels[j][m]);
327  else
328  keras::conv_single_depth_same(y_ret[j], im[m], m_kernels[j][m]);
329  }
330 
331  for(unsigned int x = 0; x < y_ret[0].size(); ++x) {
332 
333  size_t size = y_ret[0][0].size();
334  float bias = m_bias[j];
335  size_t k = 0;
336 
337  for(unsigned int y = 0; y < size/8; ++y) {
338  y_ret[j][x][k] += bias;
339  y_ret[j][x][k+1] += bias;
340  y_ret[j][x][k+2] += bias;
341  y_ret[j][x][k+3] += bias;
342  y_ret[j][x][k+4] += bias;
343  y_ret[j][x][k+5] += bias;
344  y_ret[j][x][k+6] += bias;
345  y_ret[j][x][k+7] += bias;
346  k += 8;
347  }
348  while (k < size) { y_ret[j][x][k] += bias; ++k; }
349 
350  }
351  });
352 
353  //auto t2 = std::chrono::high_resolution_clock::now();
354  /*
355  cout << "Parallal : "
356  << std::chrono::duration_cast<std::chrono::microseconds>(t2-t1).count()
357  << " microseconds." << endl;
358  */
359 
360  return out;
361 }
362 
364  //cout << "weights: input size " << m_weights.size() << endl;
365  //cout << "weights: neurons size " << m_weights[0].size() << endl;
366  //cout << "bias " << m_bias.size() << endl;
367  size_t size = m_weights[0].size();
368  size_t size8 = size >> 3;
369 
370  keras::DataChunkFlat *out = new DataChunkFlat(size, 0);
371  float * y_ret = out->get_1d_rw().data();
372 
373  auto const & im = dc->get_1d();
374 
375  for (size_t j = 0; j < m_weights.size(); ++j) { // iter over input
376  const float * w = m_weights[j].data();
377  float p = im[j];
378  size_t k = 0;
379  for (size_t i = 0; i < size8; ++i) { // iter over neurons
380  y_ret[k] += w[k] * p; // vectorize if you can
381  y_ret[k+1] += w[k+1] * p;
382  y_ret[k+2] += w[k+2] * p;
383  y_ret[k+3] += w[k+3] * p;
384  y_ret[k+4] += w[k+4] * p;
385  y_ret[k+5] += w[k+5] * p;
386  y_ret[k+6] += w[k+6] * p;
387  y_ret[k+7] += w[k+7] * p;
388  k += 8;
389  }
390  while (k < size) { y_ret[k] += w[k] * p; ++k; }
391  }
392  for (size_t i = 0; i < size; ++i) { // add biases
393  y_ret[i] += m_bias[i];
394  }
395 
396  return out;
397 }
398 
399 
401  //cout << endl << "KerasModel compute output" << endl;
402  //cout << "Input data size:" << endl;
403  //dc->show_name();
404 
405  keras::DataChunk *inp = dc;
406  keras::DataChunk *out = 0;
407  for(int l = 0; l < (int)m_layers.size(); ++l) {
408  //cout << "Processing layer " << m_layers[l]->get_name() << endl;
409  out = m_layers[l]->compute_output(inp);
410 
411  //cout << "Input" << endl;
412  //inp->show_name();
413  //cout << "Output" << endl;
414  //out->show_name();
415 
416  if (inp != dc) delete inp;
417  inp = 0L;
418  inp = out;
419  }
420 
421  //cout << "Output: ";
422  //out->show_values();
423 
424  std::vector<float> flat_out = out->get_1d();
425  delete out;
426 
427  return flat_out;
428 }
429 
430 void keras::KerasModel::load_weights(const string &input_fname) {
431  cout << "Reading model from " << input_fname << endl;
432  ifstream fin(input_fname.c_str());
433  string layer_type = "";
434  string tmp_str = "";
435  int tmp_int = 0;
436 
437  fin >> tmp_str >> m_layers_cnt;
438  cout << "Layers " << m_layers_cnt << endl;
439 
440  for(int layer = 0; layer < m_layers_cnt; ++layer) { // iterate over layers
441  fin >> tmp_str >> tmp_int >> layer_type;
442  cout << "Layer " << tmp_int << " " << layer_type << endl;
443 
444  Layer *l = 0L;
445  if(layer_type == "Convolution2D") {
446  l = new LayerConv2D();
447  } else if(layer_type == "Activation") {
448  l = new LayerActivation();
449  } else if(layer_type == "MaxPooling2D") {
450  l = new LayerMaxPooling();
451  } else if(layer_type == "Flatten") {
452  l = new LayerFlatten();
453  } else if(layer_type == "Dense") {
454  l = new LayerDense();
455  } else if(layer_type == "Dropout") {
456  continue; // we dont need dropout layer in prediciton mode
457  }
458  if(l == 0L) {
459  cout << "Layer is empty, maybe it is not defined? Cannot define network." << endl;
460  return;
461  }
462  l->load_weights(fin);
463  m_layers.push_back(l);
464  }
465 
466  fin.close();
467 }
468 
470  for(int i = 0; i < (int)m_layers.size(); ++i) {
471  delete m_layers[i];
472  }
473 }
474 
476 {
477  int i = m_layers.size() - 1;
478  while ((i > 0) && (m_layers[i]->get_output_units() == 0)) --i;
479  return m_layers[i]->get_output_units();
480 }
void load_weights(std::ifstream &fin)
Definition: keras_model.cc:40
void conv_single_depth_valid(std::vector< std::vector< float > > &y, std::vector< std::vector< float > > const &im, std::vector< std::vector< float > > const &k)
Definition: keras_model.cc:246
KerasModel(const std::string &input_fname)
Definition: keras_model.cc:116
keras::DataChunk * compute_output(keras::DataChunk *)
Definition: keras_model.cc:307
std::string string
Definition: nybbler.cc:12
int get_output_length() const
Definition: keras_model.cc:475
struct vector vector
virtual void set_data(std::vector< std::vector< std::vector< float > > > const &)
Definition: keras_model.h:47
STL namespace.
void load_weights(const std::string &input_fname)
Definition: keras_model.cc:430
virtual void load_weights(std::ifstream &fin)=0
virtual std::vector< std::vector< std::vector< float > > > const & get_3d() const
Definition: keras_model.h:46
virtual size_t get_data_dim(void) const
Definition: keras_model.h:44
keras::DataChunk * compute_output(keras::DataChunk *)
Definition: keras_model.cc:363
keras::DataChunk * compute_output(keras::DataChunk *)
Definition: keras_model.cc:121
std::vector< float > compute_output(keras::DataChunk *dc)
Definition: keras_model.cc:400
static QStrList * l
Definition: config.cpp:1044
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:92
void read_from_file(const std::string &fname)
Definition: keras_model.cc:24
std::void_t< T > n
std::vector< std::vector< std::vector< float > > > & get_3d_rw()
Definition: keras_model.h:62
p
Definition: test.py:223
keras::DataChunk * compute_output(keras::DataChunk *)
Definition: keras_model.cc:181
void missing_activation_impl(const std::string &act)
Definition: keras_model.cc:175
Q_UINT16 values[128]
void load_weights(std::ifstream &fin)
Definition: keras_model.cc:91
keras::DataChunk * compute_output(keras::DataChunk *)
Definition: keras_model.cc:142
std::vector< float > & get_1d_rw()
Definition: keras_model.h:102
list x
Definition: train.py:276
void load_weights(std::ifstream &fin)
Definition: keras_model.cc:81
void load_weights(std::ifstream &fin)
Definition: keras_model.cc:86
virtual std::vector< float > const & get_1d() const
Definition: keras_model.h:45
void conv_single_depth_same(std::vector< std::vector< float > > &y, std::vector< std::vector< float > > const &im, std::vector< std::vector< float > > const &k)
Definition: keras_model.cc:273
std::vector< float > read_1d_array(std::ifstream &fin, int cols)
Definition: keras_model.cc:11
QTextStream & endl(QTextStream &s)