MachineIntelligenceCore:NeuralNets
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Friends Macros
Convolution.hpp
Go to the documentation of this file.
1 
23 #ifndef SRC_MLNN_CONVOLUTION_HPP_
24 #define SRC_MLNN_CONVOLUTION_HPP_
25 
26 #include <mlnn/layer/Layer.hpp>
27 
28 #include<types/MatrixTypes.hpp>
29 #include<types/MatrixArray.hpp>
30 
31 namespace mic {
32 namespace mlnn {
33 namespace convolution {
34 
40 template <typename eT=float>
41 class Convolution : public mic::mlnn::Layer<eT> {
42 public:
43 
54  Convolution(size_t input_height_, size_t input_width_, size_t input_channels_, size_t number_of_filters_, size_t filter_size_, size_t stride_, std::string name_ = "Convolution") :
55  Layer<eT>::Layer(input_height_, input_width_, input_channels_,
56  /* height, width: temporary output values to be set in constructor!*/
57  1, 1, number_of_filters_,
58  LayerTypes::Convolution, name_),
59  filter_size(filter_size_),
60  stride(stride_)
61  {
62  // Calculate number of receptive fields within a "single input channel".
63  assert(input_height >= filter_size);
64  int height_rest = (int)input_height-filter_size;
65  output_height = 1;
66  while(height_rest >= (int)stride){
67  output_height++;
68  height_rest -= stride;
69  }//: while width
70  // Filters must "exactly" fit!
71  if (height_rest != 0) {
72  LOG(LERROR) << " Filter width and stride does not fit image height";
73  LOG(LINFO) << streamLayerParameters();
74  exit(-1);
75  }
76 
77  assert(input_width >= filter_size);
78  int width_rest = (int)input_width-filter_size;
79  output_width= 1;
80  while(width_rest >= (int)stride){
81  output_width++;
82  width_rest -= stride;
83  }//: while width
84  // Filters must "exactly" fit!
85  if (height_rest != 0) {
86  LOG(LINFO) << "Filter height and stride does not fit image height";
87  LOG(LNOTICE) << streamLayerParameters();
88  exit(-1);
89  }
90 
91  LOG(LDEBUG)<<streamLayerParameters();
92 
93  // Set output height and resize matrices!
94  s["y"]->resize(Layer<eT>::outputSize(), batch_size); // outputs
95  g["y"]->resize(Layer<eT>::outputSize(), batch_size); // gradients
96  m["ys"]->resize(Layer<eT>::outputSize(), 1); // sample
97  m["yc"]->resize(output_width*output_height, 1); // channel
98 
99 
100  // Calculate "range" - for initialization.
101  eT range_init = (eT) (input_width * input_height * input_depth) +
102  (output_width * output_height * output_depth);
103  eT range = sqrt(6.0 / range_init);
104 
105  // Create filters.
106  for (size_t fi=0; fi< output_depth; fi++) {
107  // A given filter (neuron layer) has in fact connection to all input channels.
108  for (size_t ic=0; ic< input_depth; ic++) {
109  // Create the weights matrix - a row vector.
110  p.add ("W"+std::to_string(fi)+"x"+std::to_string(ic), 1, filter_size*filter_size);
111  // Initialize weights of the W matrix.
112  p["W"+std::to_string(fi)+"x"+std::to_string(ic)]->rand(-range, range);
113  //std::cout<<"W.dims = " << p["W"+std::to_string(fi)+std::to_string(ic)]->rows() << "," << p["W"+std::to_string(fi)+std::to_string(ic)]->cols() << "\n";
114 
115  // Create the weights matrix for updates/gradients.
116  g.add ("W"+std::to_string(fi)+"x"+std::to_string(ic), 1, filter_size*filter_size);
117  }//: for input channels.
118 
119  }//: for filter
120 
121  // Create a single bias vector for all filters.
122  p.add ("b", output_depth, 1);
123  p["b"]->setZero();
124  // Bias gradient.
125  g.add ("b", output_depth, 1);
126 
127  // Allocate (temporary) memory for "input receptive fields".
128  for (size_t ry=0; ry< output_height; ry++) {
129  for (size_t rx=0; rx< output_width; rx++) {
130  // Create receptive field matrix.
131  m.add ("xrf"+std::to_string(ry)+"x"+std::to_string(rx), filter_size, filter_size);
132  }//: for
133  }//: for
134 
135  // Allocate (temporary) memory for "output channels" - matrices.
136  for (size_t fi=0; fi< output_depth; fi++) {
137  // Create output channel matrix.
138  m.add ("yc"+std::to_string(fi), output_height, output_width);
139  }//: for
140 
141  // Allocate (temporary) memory for "inverse input receptive fields" - used in backpropagation.
142  for (size_t ry=0; ry< filter_size; ry++) {
143  for (size_t rx=0; rx< filter_size; rx++) {
144  // Create receptive field matrix.
145  m.add ("ixrf"+std::to_string(ry)+"x"+std::to_string(rx), output_height, output_width);
146  }//: for
147  }//: for
148 
149  // Allocate memory for "filter similarity".
150  m.add ("fs", input_depth*output_depth, input_depth*output_depth);
151 
152  // Set gradient descent as default optimization function.
153  Layer<eT>::template setOptimization<mic::neural_nets::optimization::GradientDescent<eT> > ();
154  };
155 
159  virtual ~Convolution() {};
160 
165  virtual std::string streamLayerParameters() {
166  std::ostringstream os_;
167  // Display id/type.
168  os_ << " [" << Layer<eT>::type() << "]: " << Layer<eT>::layer_name << ": "
169  << Layer<eT>::inputSize() << "x" << batch_size << " -> " << Layer<eT>::outputSize() << "x" << batch_size << "\n";
170  // Display dimensions.
171  os_<<" * input_height = " << input_height <<std::endl;
172  os_<<" * input_width = " << input_width <<std::endl;
173  os_<<" * input_channels = " << input_depth <<std::endl;
174  os_<<" * filter_size = " << filter_size <<std::endl;
175  os_<<" * stride = " << stride <<std::endl;
176  os_<<" * output_height = " << output_height <<std::endl;
177  os_<<" * output_width = " << output_width <<std::endl;
178  os_<<" * output_channels = " << output_depth;
179 
180  return os_.str();
181  }
182 
186  void forward(bool test = false) {
187 // std::cout << "forward()\n";
188  // Get input matrix.
189  mic::types::MatrixPtr<eT> batch_x = s['x'];
190  //std::cout<< "forward batch_x=\n" << (*batch) << std::endl;
191  //std::cout << "forward input x activation: min:" << (*batch_x).minCoeff() <<" max: " << (*batch_x).maxCoeff() << std::endl;
192 
193  // Get output pointer - so the results will be stored!
194  mic::types::MatrixPtr<eT> batch_y = s['y'];
195  batch_y->setZero();
196 
197  // Iterate through samples in the input batch.
198 //#pragma omp parallel for
199  for (size_t ib=0; ib< batch_size; ib++) {
200 
201  // The "output sample" that will "concatenate" the output channels into one "column vector".
202  mic::types::MatrixPtr<eT> y_sample = m["ys"];
203 
204  // 1. "Reset" output "channels".
205  for (size_t fi=0; fi< output_depth; fi++) {
206  // Get output channel matrix.
207  mic::types::MatrixPtr<eT> y_channel = m["yc"+std::to_string(fi)];
208  // Resize it to a matrix (!).
209  y_channel->resize(output_height, output_width);
210  // And "reset" i.e. set value of all cells to bias (so we can skip adding it later).
211  y_channel->setValue((*p["b"])[fi]);
212  }//: filters
213 
214  // 2. Get input sample from batch!
215  mic::types::MatrixPtr<eT> sample = m["xs"];
216  (*sample) = batch_x->col(ib);
217  //std::cout<< "sample=\n" << (*sample) << std::endl;
218 
219  // 3. Iterate through input channels.
220  for (size_t ic=0; ic< input_depth; ic++) {
221  // 3.1. Get input channel from image.
222  mic::types::MatrixPtr<eT> ichannel = m["xc"];
223  // Copy block - resizes the input channel matrix.
224  (*ichannel) = sample->block(ic*input_height*input_width, 0, input_height*input_width, 1);
225  // Resize channel using the given dimensions.
226  ichannel->resize(input_height, input_width);
227  //std::cout<< "====== switching input channel = " << ic <<" ichannel=\n" << (*ichannel) << std::endl;
228 
229  // 3.2. Fill receptive fields from given input channel.
230  // Iterate through receptive fields - vertical and horizontal
231  // and copy data from given channel to array of "input receptive fields".
232  // Image coordinates: ix, iy.
233  // Receptive field "id" coordinates: rx, ry.
234  for (size_t ry=0, iy = 0; ry< output_height; ry++, iy+=stride) {
235  for (size_t rx=0, ix = 0; rx< output_width; rx++, ix+=stride) {
236  //std::cout<<"ry =" << ry <<" rx =" << rx <<" iy =" << iy <<" ix =" << ix << std::endl;
237  // Get receptive field matrix...
238  mic::types::MatrixPtr<eT> field = m["xrf"+std::to_string(ry)+"x"+std::to_string(rx)];
239  // Copy block from channel - resizes the field matrix.
240  (*field) = ichannel->block(iy,ix,filter_size, filter_size);
241  //std::cout<< "field=\n" << (*field) << std::endl;
242  // Resize the field to a column vector.
243  field->resize(filter_size*filter_size, 1);
244  }//: for rx
245  }//: for ry
246 
247  // 3.3. Convolve receptive fields with filters.
248 
249  // Iterate through filters and calculate the result of the convolution.
250  for (size_t fi=0; fi< output_depth; fi++) {
251  // Get output channel for a given filter.
252  mic::types::MatrixPtr<eT> y_channel = m["yc"+std::to_string(fi)];
253  // Resize to matrix.
254  y_channel->resize(output_height, output_width);
255  //std::cout << "==== switching to oc " << fi << " = \n" << (*y_channel)<<std::endl;
256  // Get "part of a given neuron" responding to a given input channel.
257  mic::types::MatrixPtr<eT> W = p["W"+std::to_string(fi)+"x"+std::to_string(ic)];
258  // Not required - just in case. :]
259  W->resize(1,filter_size*filter_size);
260  // Iterate through receptive fields.
261  for (size_t ry=0; ry< output_height; ry++) {
262  for (size_t rx=0; rx< output_width; rx++) {
263  // Get receptive field matrix of size (1, filter_size^2)...
264  mic::types::MatrixPtr<eT> xrf = m["xrf"+std::to_string(ry)+"x"+std::to_string(rx)];
265  // ... and result of "convolution" of that filter with the part of the input "below" the receptive field.
266  /*std::cout<<"ic = " << ic << " filter = " << fi << " ry =" << ry <<" rx =" << rx <<std::endl;
267  std::cout<< "W=\n" << (*W) << std::endl;
268  std::cout<< "xrf=\n" << (*xrf) << std::endl;
269  std::cout<< " result = " << ((*W)*(*xrf)) << std::endl;*/
270  (*y_channel)(ry, rx) += ((*W)*(*xrf))(0);
271  }//: for rx
272  }//: for ry
273  //std::cout << "==== ic = " << ic << " filter= " << fi << " oc = \n" << (*y_channel)<<std::endl;
274 
275  // Resize output channel to a column vector.
276  y_channel->resize(output_height*output_width, 1);
277  // Concatenate.
278  y_sample->block(fi*output_height*output_width, 0, output_height*output_width, 1)
279  = (*y_channel);
280  }//: for filters
281 
282  }//: for channels
283  //std::cout <<"output before adding y =" << (*y) <<std::endl;
284  // Set column in the output batch.
285  batch_y->col(ib) = (*y_sample);
286 
287  }//: for batch
288 
289  //std::cout <<"output y =" << (*batch_y).transpose() <<std::endl;
290  //std::cout << "forward output y activation: min:" << (*batch_y).minCoeff() <<" max: " << (*batch_y).maxCoeff() << std::endl;
291  }//: forward
292 
296  void backward() {
297  mic::types::MatrixPtr<eT> batch_dy = g['y'];
298  //std::cout << "backward gradient dy: min:" << (*batch_dy).minCoeff() <<" max: " << (*batch_dy).maxCoeff() << std::endl;
299 
300  //std::cout<<"backpropagade_dy_to_dx!\n";
301  // To dx.
303 
304  //std::cout<<"backpropagade_dy_to_dW!\n";
305  // To dW.
307 
308  //std::cout<<"backpropagade_dy_to_db!\n";
309  // To db.
311 
312  /*mic::types::MatrixPtr<eT> batch_dx = g['x'];
313  std::cout << "backward gradient dx: min:" << (*batch_dx).minCoeff() <<" max: " << (*batch_dx).maxCoeff() << std::endl;
314 
315 
316  for (size_t fi=0; fi< output_depth; fi++) {
317  // A given filter (neuron layer) has in fact connection to all input channels.
318  for (size_t ic=0; ic< input_depth; ic++) {
319  mic::types::MatrixPtr<eT> dw = g['W'+std::to_string(fi)+"x"+std::to_string(ic)];
320  std::cout << "backward gradient dW"<< fi <<"x"<< ic <<": min:" << (*dw).minCoeff() <<" max: " << (*dw).maxCoeff() << std::endl;
321  }//: for
322  }//: for
323 
324  mic::types::MatrixPtr<eT> db = g['b'];
325  std::cout << "backward gradient db: min:" << (*db).minCoeff() <<" max: " << (*db).maxCoeff() << std::endl;
326  */
327 
328  //std::cout<<"After Backward!\n";
329  }//: backward
330 
331 
336  // Get matrices.
337  mic::types::MatrixPtr<eT> batch_dy = g['y'];
338  mic::types::MatrixPtr<eT> batch_x = s['x'];
339  //std::cout<< "backpropagate to dx batch_x=\n" << (*batch_x) << std::endl;
340  // Get output pointers - so the results will be stored!
341  mic::types::MatrixPtr<eT> batch_dx = g['x'];
342 
343  // Backpropagate gradient from dy to dx.
344 
345 
346  // Calculate dx for a given batch of dy gradients.
347  // Iterate through samples in the input batch.
348 //#pragma omp parallel for
349  for (size_t ib=0; ib< batch_size; ib++) {
350 
351  // Get y gradient sample from batch.
352  mic::types::MatrixPtr<eT> gys = m["ys"];
353  (*gys) = batch_dy->col(ib);
354 
355  /*///////////////////////
356  // Get gradient y channel.
357  mic::types::MatrixPtr<eT> gyc = m["yc"];
358  for (size_t fi=0; fi< number_of_filters; fi++) {
359  (*gyc) = gys->block(fi*output_height*output_width, 0, output_height*output_width, 1);
360  (*gyc).resize(output_height, output_width);
361  std::cout<< "============ dy channel = " << fi << "(*gyc) = \n" << (*gyc) << std::endl;
362  }// to remove*/
363 
364 
365  // Get pointer to x gradient sample matrix.
366  mic::types::MatrixPtr<eT> gxs = m["xs"];
367  gxs->setZero();
368 
369  // Convolve reWs with sample channel by channel.
370  for (size_t ic=0; ic< input_depth; ic++) {
371  //std::cout<< "====== switching input channel = " << ic << std::endl;
372 
373  // Get pointer to x gradient channel "storage".
374  mic::types::MatrixPtr<eT> gxc = m["xc"];
375  // Clean it up!
376  gxc->setZero();
377  // Resize just in case.
378  gxc->resize(input_height, input_width);
379 
380 
381  // For each filter.
382  for (size_t fi=0; fi< output_depth; fi++) {
383  //std::cout<< "====== switching filter = " << fi << std::endl;
384 
385  // Get filter weight matrix.
386  mic::types::MatrixPtr<eT> W = p["W"+std::to_string(fi)+"x"+std::to_string(ic)];
387  W->resize(filter_size, filter_size);
388 
389  // Get gradient y channel.
390  mic::types::MatrixPtr<eT> gyc = m["yc"];
391  // Copy block - resizes the input channel matrix.
392  (*gyc) = gys->block(fi*output_height*output_width, 0, output_height*output_width, 1);
393  (*gyc).resize(output_height, output_width);
394  //std::cout<< "fi = " << fi << "(*gyc) = \n" << (*gyc) << std::endl;
395 
396 /* // Get reW.
397  mic::types::MatrixPtr<eT> reW = m["reW"+std::to_string(fi)+std::to_string(ic)];
398  // Get pointer to "reverse receptive field".
399  mic::types::MatrixPtr<eT> rerf = m["rerf"];*/
400 
401  // Iterate through "stride blocks" - their number is equal to output size.
402  // Those are also coordinates of the outputs.
403  for(size_t oy=0; oy < output_height; oy++) {
404  for(size_t ox=0; ox < output_width; ox++) {
405  // Get top upper coordinate of input block.
406  size_t isby = oy * stride;
407  size_t isbx = ox * stride;
408  //std::cout<< "block coordinates: isby = " << isby << " isbx=" << isbx << std::endl;
409 
410  // Iterate through the elements and add them to gxc.
411  for (size_t iy=0; iy<filter_size; iy++) {
412  for (size_t ix=0; ix<filter_size; ix++) {
413 
414  eT conv = (*W)(iy,ix)*(*gyc)(oy,ox);//((*rerf)*(*gyc))(0);//1;
415  size_t y = isby+iy;
416  size_t x = isbx+ix;
417  //std::cout<< "adding to (*gxc) = \n" << (*gxc) << "\n in: " << " y=" << y<< " x=" << x << std::endl;
418  (*gxc)(y,x) += conv;
419 
420  }//: for ix
421  }//: for iy
422 
423 
424  }//: for stride blocks y
425  }//: for stride blocks x
426  //std::cout<< "filter = "<< fi << " resulting (*gxc) = \n" << (*gxc) << std::endl;
427  }//: for filters
428  //std::cout<< "result for input channel = "<< ic << " (*gxc) = \n" << (*gxc) << std::endl;
429  // Resize gradient channel to a column vector.
430  gxc->resize(input_height * input_width, 1);
431 
432  // Concatenate gradient.
433  gxs->block(ic*input_height*input_width, 0, input_height*input_width, 1)
434  = (*gxc);
435 
436  //std::cout<< "(*gs) = \n" << (*gxs) << std::endl;
437  }//: for channels
438 
439  // Set column in the gradient batch.
440  batch_dx->col(ib) = (*gxs);
441 
442  }//: batch
443 
444  }
445 
450  // Get weight delta matrix.
451  //mic::types::MatrixPtr<eT> dW = g['W'];
452 
453  // Get matrices.
454  mic::types::MatrixPtr<eT> batch_dy = g['y'];
455  mic::types::MatrixPtr<eT> batch_x = s['x'];
456  //std::cout<< "backpropagate to dW batch_x=\n" << (*batch_x) << std::endl;
457 
458  // Reset weight gradiends.
459  for (size_t fi=0; fi< output_depth; fi++) {
460  // A given filter (neuron layer) has in fact connection to all input channels.
461  for (size_t ic=0; ic< input_depth; ic++) {
462  g["W"+std::to_string(fi)+"x"+std::to_string(ic)]->setZero();
463  }//: for ic
464  }//: for fi
465 
466 
467  // Iterate through samples in the input batch.
468  for (size_t ib=0; ib< batch_size; ib++) {
469 
470  // Get y gradient sample from batch.
471  mic::types::MatrixPtr<eT> gys = m["ys"];
472  (*gys) = batch_dy->col(ib);
473 
474  // Get x sample from batch.
475  mic::types::MatrixPtr<eT> xs = m["xs"];
476  (*xs) = batch_x->col(ib);
477  //std::cout<< "xs=\n" << (*xs) << std::endl;
478 
479  // Iterate through input channels.
480  for (size_t ic=0; ic< input_depth; ic++) {
481  // 3.1. Get input channel from image.
482  mic::types::MatrixPtr<eT> x_channel = m["xc"];
483  // Copy block - resizes the input channel matrix.
484  (*x_channel) = xs->block(ic*input_height*input_width, 0, input_height*input_width, 1);
485  // Resize channel using the given dimensions.
486  x_channel->resize(input_height, input_width);
487  //std::cout<< "====== switching input channel = " << ic << " x_channel=\n" << (*x_channel) << std::endl;
488 
489  // Fill "inverse input receptive fields" from given input channel.
490  // Image coordinates: ix, iy.
491  // Coordinates in the filter space: fx, fy.
492  for (size_t fy=0; fy< filter_size; fy++) {
493  for (size_t fx=0; fx< filter_size; fx++) {
494  // Get inverse receptive field matrix.
495  mic::types::MatrixPtr<eT> ixrf = m["ixrf"+std::to_string(fy)+"x"+std::to_string(fx)];
496  ixrf->setZero();
497  //std::cout << (*x_field).rows() << "x" << (*x_field).cols() <<std::endl;
498  //std::cout<< "x_field=\n" << (*x_field) << std::endl;
499  ixrf->resize(output_height, output_width);
500  ixrf->setZero();
501  // Iterate through the input channel using stride.
502  for (size_t iy=0; iy< output_height; iy++) {
503  for (size_t ix=0; ix< output_width; ix++) {
504  /*std::cout<<"fy =" << fy <<" fx =" << fx <<" iy =" << iy <<" ix =" << ix << std::endl;
505  std::cout<<"fy*iy*stride =" << fy*iy*stride <<" fx+ix*stride =" << fx+ix*stride <<std::endl;*/
506  // Copy cell - one by one :]
507  (*ixrf)(iy, ix) = (*x_channel)(fy+iy*stride,fx+ix*stride);
508 
509  }//: for ix
510  }//: for iy
511  //(*ixrf) = (*x_channel).block(fy, fx, output_height, output_width);
512  // Resize the field to a column vector.
513  ixrf->resize(1, output_height*output_width);
514  //std::cout<< "x_field=\n" << (*x_field) << std::endl;
515  }//: for rx
516  }//: for ry
517 
518  // For each filter (= each output channel).
519  for (size_t fi=0; fi< output_depth; fi++) {
520  // Get output channel for a given filter.
521  mic::types::MatrixPtr<eT> gyc = m["yc"+std::to_string(fi)];
522  (*gyc) = gys->block(fi*output_height*output_width, 0, output_height*output_width, 1);
523  //std::cout<< "gyc=\n" << (*gyc) << std::endl;
524 
525  // Get matrix of a given "part of a given neuron".
526  mic::types::MatrixPtr<eT> dW = g["W"+std::to_string(fi)+"x"+std::to_string(ic)];
527  // Not required - just in case. :]
528  dW->resize(filter_size, filter_size);
529  // Iterate through inverse receptive fields and CONVOLVE.
530  for (size_t ry=0; ry< filter_size; ry++) {
531  for (size_t rx=0; rx< filter_size; rx++) {
532  //std::cout<<"filter = " << fi << " ry =" << ry <<" rx =" << rx <<std::endl;
533  // Get inverse receptive field matrix of size (filter_size^2, 1)...
534  mic::types::MatrixPtr<eT> ixrf = m["ixrf"+std::to_string(ry)+"x"+std::to_string(rx)];
535  ixrf->resize(1, output_height*output_width);
536  /*std::cout<< "x_field=\n" << (*ixrf) << std::endl;
537  std::cout<< "gyc=\n" << (*gyc) << std::endl;
538  std::cout<< " result = \n" << ((*ixrf)*(*gyc)) << std::endl;*/
539  // ... and convolve it with dy channel.
540  (*dW)(ry, rx) += ((*ixrf)*(*gyc))(0);
541  }//: for rx
542  }//: for ry
543  //std::cout << "==== result: dW [" << fi << ic <<"] = " << (*dW)<<std::endl;
544  //std::cout<<"fi = " << fi << std::endl<< (*dW) << std::endl;
545  //dW->setValue(fi);
546 
547  }//: for filter
548 
549  }//: for input_channels
550  }//: for batch
551  }
552 
553 
554 
559  // Get bias delta matrix (vector).
560  mic::types::MatrixPtr<eT> db = g['b'];
561  // Get dy matrix - input.
562  mic::types::MatrixPtr<eT> batch_dy = g['y'];
563 
564  // Iterate through output channels i.e. filters.
565  for (size_t fi=0; fi< output_depth; fi++) {
566  // Sum block [output_channel x batch].
567  eT channel_bach_sum = batch_dy->block(fi*output_height*output_width, 0, output_height*output_width, batch_size).sum();
568  //std::cout<< "fi = " << fi << "channel_bach_sum = " << channel_bach_sum << std::endl;
569  (*db)[fi] = channel_bach_sum;
570  }//: for filters
571 
572  // And that's it! :)
573  }
574 
575 
579  void resetGrads() {
580  // Reset array matrix with gradients.
581  g.setZero();
582  }
583 
584 
590  void update(eT alpha_, eT decay_ = 0.0f) {
591  // Get keys of all parameters.
592  std::map<std::string, size_t> keys = p.keys();
593 
594  for (auto& i: keys) {
595 /* std::cout << "* " << i.first << "\t = < " << (*p[i.first]).minCoeff() << ",\t " << (*p[i.first]).maxCoeff() << ">" <<
596  " * d" << i.first << "\t = <" << (*g[i.first]).minCoeff() << ",\t " << (*g[i.first]).maxCoeff() << ">" << std::endl;*/
597  opt[i.first]->update(p[i.first], g[i.first], 1.0*alpha_, decay_);
598  /*for (size_t j=0; j<(size_t)p[i.first]->size(); j++)
599  (*p[i.first])[j] -= alpha_ * (*g[i.first])[j];*/
600  }//: for
601 
602  /*std::string key = "W0x0";
603  std::cout << "* " << key << "\t = < " << (*p[key])[0] <<",\t " << (*p[key])[1];
604  std::cout << "\t* d" << key << "\t = < " << (*g[key])[0] <<",\t " << (*g[key])[1] << std::endl;*/
605 
606  }
607 
608 
609 
613  std::vector< std::shared_ptr <mic::types::Matrix<eT> > > & getWeightActivations() {
614 
615  // Allocate memory.
617 
618  // Iterate through filters and generate "activation image" for each one.
619  for (size_t fi=0; fi< output_depth; fi++) {
620 
621  // Iterate through input channels.
622  for (size_t ic=0; ic< input_depth; ic++) {
623  // Get matrix of a given "part of a given neuron".
624  mic::types::MatrixPtr<eT> W = p["W"+std::to_string(fi)+"x"+std::to_string(ic)];
625 
626  // Get row.
627  mic::types::MatrixPtr<eT> row = w_activations[fi*input_depth + ic];
628  // Copy data.
629  (*row) = (*W);
630  row->resize(filter_size, filter_size);
631 
632  }//: for channels
633  }//: for filters
634 
635  // Return activations.
636  return w_activations;
637  }
638 
639 
640 
644  std::vector< std::shared_ptr <mic::types::Matrix<eT> > > & getWeightGradientActivations() {
645 
646  // Allocate memory.
648 
649  // Iterate through filters and generate "activation image" for each one.
650  for (size_t fi=0; fi< output_depth; fi++) {
651 
652  // Iterate through input channels.
653  for (size_t ic=0; ic< input_depth; ic++) {
654 
655  // Get matrix of a given "part of a given neuron dW".
656  mic::types::MatrixPtr<eT> W = g["W"+std::to_string(fi)+"x"+std::to_string(ic)];
657 
658  // Get row.
659  mic::types::MatrixPtr<eT> row = dw_activations[fi*input_depth + ic];
660  // Copy data.
661  (*row) = (*W);
662 
663  }//: for channel
664  }//: for filter
665 
666  // Return activations.
667  return dw_activations;
668  }
669 
670 
675  std::vector< std::shared_ptr <mic::types::Matrix<eT> > > & getReceptiveFields() {
676 
677  // TODO: batch!
678  //assert(batch_size==1);
679 
680  // Allocate memory.
682 
683  // Receptive field "id" coordinates: rx, ry.
684  for (size_t ry=0; ry< output_height; ry++) {
685  for (size_t rx=0; rx< output_width; rx++) {
686  // Get receptive field matrix...
687  mic::types::MatrixPtr<eT> xrf = m["xrf"+std::to_string(ry)+"x"+std::to_string(rx)];
688 
689  // Get activation "row".
690  mic::types::MatrixPtr<eT> row = xrf_activations[ry*output_width + rx];
691 
692  // Copy field.
693  (*row) = *(xrf);
694  row->resize(filter_size, filter_size);
695 
696  }//: for ry
697  }//: for rx
698 
699  // Return activations.
700  return xrf_activations;
701  }
702 
707  std::vector< std::shared_ptr <mic::types::Matrix<eT> > > & getInverseReceptiveFields() {
708 
709  // TODO: batch!
710  //assert(batch_size==1);
711 
712  // Allocate memory.
714 
715  for (size_t fy=0; fy< filter_size; fy++) {
716  for (size_t fx=0; fx< filter_size; fx++) {
717  // Get inverse receptive field matrix.
718  mic::types::MatrixPtr<eT> ixrf = m["ixrf"+std::to_string(fy)+"x"+std::to_string(fx)];
719 
720  // Get activation "row".
721  mic::types::MatrixPtr<eT> row = irf_activations[fy*filter_size + fx];
722 
723  // Copy field.
724  (*row) = *(ixrf);
725  row->resize(output_height, output_width);
726 
727  }//: for rx
728  }//: for ry
729 
730  // Return activations.
731  return irf_activations;
732  }
733 
738  mic::types::MatrixPtr<eT> getFilterSimilarityMatrix() {
739  // Get filter similarity matrix.
740  mic::types::MatrixPtr<eT> fs = m["fs"];
741  // Reset.
742  fs->zeros();
743 
744  // Iterate through filters.
745  for (size_t fi=0; fi< output_depth; fi++) {
746  // A given filter (neuron layer) has in fact connection to all input channels.
747  for (size_t ic=0; ic< input_depth; ic++) {
748  // Get i-th filter.
749  mic::types::MatrixPtr<eT> iW = p["W"+std::to_string(fi)+"x"+std::to_string(ic)];
750  // Calculate index.
751  size_t i = fi*input_depth + ic;
752 
753  for (size_t fj=0; fj < fi; fj++) {
754  // A given filter (neuron layer) has in fact connection to all input channels.
755  for (size_t jc=0; jc< input_depth; jc++) {
756  // Get j-th filter.
757  mic::types::MatrixPtr<eT> jW = p["W"+std::to_string(fj)+"x"+std::to_string(jc)];
758  // Calculate index.
759  size_t j = fj*input_depth + jc;
760 
761  // Calculate the similarity - absolute value!
762  //(*fs)(j, i) =
763  (*fs)(i, j) = cosineSimilarity(iW->data(), jW->data(), filter_size*filter_size);
764  }
765  }// :for j
766  }
767  }//: for i
768  return fs;
769  }
770 
777  eT cosineSimilarity(eT *A, eT *B, size_t length_)
778  {
779  eT dot = 0.0, denom_a = 0.0, denom_b = 0.0 ;
780  for(size_t i = 0; i < length_; ++i) {
781  dot += A[i] * B[i] ;
782  denom_a += A[i] * A[i] ;
783  denom_b += B[i] * B[i] ;
784  }
785  return dot / (sqrt(denom_a) * sqrt(denom_b)) ;
786  }
787 
788 
789  // Unhide the overloaded methods inherited from the template class Layer fields via "using" statement.
790  using Layer<eT>::forward;
791  using Layer<eT>::backward;
792 
793 protected:
794  // Unhide the fields inherited from the template class Layer via "using" statement.
795  using Layer<eT>::g;
796  using Layer<eT>::s;
797  using Layer<eT>::p;
798  using Layer<eT>::m;
799  using Layer<eT>::opt;
800 
801  // Uncover "sizes" for visualization.
808  using Layer<eT>::batch_size;
809 
811  size_t filter_size;
812 
814  size_t stride;
815 
816  // Uncover methods useful in visualization.
818 
819 private:
820  // Friend class - required for using boost serialization.
821  template<typename tmp> friend class mic::mlnn::MultiLayerNeuralNetwork;
822 
824  std::vector<mic::types::MatrixPtr<eT> > w_activations;
825 
827  std::vector<mic::types::MatrixPtr<eT> > dw_activations;
828 
830  std::vector<mic::types::MatrixPtr<eT> > xrf_activations;
831 
833  std::vector<mic::types::MatrixPtr<eT> > irf_activations;
834 
839 
840 };
841 
842 } /* convolution */
843 } /* namespace mlnn */
844 } /* namespace mic */
845 
846 #endif /* SRC_MLNN_CONVOLUTION_HPP_ */
void update(eT alpha_, eT decay_=0.0f)
Class representing a convolution layer, with "valid padding" and variable stride. ...
Definition: Convolution.hpp:41
std::vector< mic::types::MatrixPtr< eT > > xrf_activations
Vector containing receptive fields.
size_t inputSize()
Returns size (length) of inputs.
Definition: Layer.hpp:255
std::vector< std::shared_ptr< mic::types::Matrix< eT > > > & getWeightGradientActivations()
size_t input_depth
Number of channels of the input (e.g. 3 for RGB images).
Definition: Layer.hpp:732
size_t batch_size
Size (length) of (mini)batch.
Definition: Layer.hpp:744
size_t outputSize()
Returns size (length) of outputs.
Definition: Layer.hpp:260
const std::string type() const
Definition: Layer.hpp:323
size_t stride
Stride (assuming equal vertical and horizontal strides).
size_t filter_size
Size of filters (assuming square filters). Filter_size^2 = length of the output vector.
std::vector< std::shared_ptr< mic::types::Matrix< eT > > > & getWeightActivations()
std::vector< mic::types::MatrixPtr< eT > > dw_activations
Vector containing activations of gradients of weights (dW).
std::vector< mic::types::MatrixPtr< eT > > irf_activations
Vector containing inverse receptive fields.
std::vector< mic::types::MatrixPtr< eT > > w_activations
Vector containing activations of weights/filters.
mic::types::MatrixPtr< eT > getFilterSimilarityMatrix()
virtual std::string streamLayerParameters()
size_t input_height
Height of the input (e.g. 28 for MNIST).
Definition: Layer.hpp:726
void lazyAllocateMatrixVector(std::vector< std::shared_ptr< mic::types::Matrix< eT > > > &vector_, size_t vector_size_, size_t matrix_height_, size_t matrix_width_)
Definition: Layer.hpp:543
Convolution(size_t input_height_, size_t input_width_, size_t input_channels_, size_t number_of_filters_, size_t filter_size_, size_t stride_, std::string name_="Convolution")
Definition: Convolution.hpp:54
Class representing a multi-layer neural network.
Definition: Layer.hpp:86
size_t output_depth
Number of filters = number of output channels.
Definition: Layer.hpp:741
std::vector< std::shared_ptr< mic::types::Matrix< eT > > > & getInverseReceptiveFields()
mic::neural_nets::optimization::OptimizationArray< eT > opt
Array of optimization functions.
Definition: Layer.hpp:765
LayerTypes
Enumeration of possible layer types.
Definition: Layer.hpp:58
std::vector< std::shared_ptr< mic::types::Matrix< eT > > > & getReceptiveFields()
mic::types::MatrixArray< eT > s
States - contains input [x] and output [y] matrices.
Definition: Layer.hpp:753
mic::types::MatrixArray< eT > g
Gradients - contains input [x] and output [y] matrices.
Definition: Layer.hpp:756
size_t input_width
Width of the input (e.g. 28 for MNIST).
Definition: Layer.hpp:729
size_t output_height
Number of receptive fields in a single channel - vertical direction.
Definition: Layer.hpp:735
eT cosineSimilarity(eT *A, eT *B, size_t length_)
size_t output_width
Number of receptive fields in a single channel - horizontal direction.
Definition: Layer.hpp:738
Contains a template class representing a layer.
mic::types::MatrixArray< eT > m
Memory - a list of temporal parameters, to be used by the derived classes.
Definition: Layer.hpp:762
mic::types::MatrixArray< eT > p
Parameters - parameters of the layer, to be used by the derived classes.
Definition: Layer.hpp:759