MachineIntelligenceCore:NeuralNets
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Friends Macros
ConvHebbian.hpp
Go to the documentation of this file.
1 
26 #ifndef SRC_MLNN_CONVHEBBIAN_HPP_
27 #define SRC_MLNN_CONVHEBBIAN_HPP_
28 
29 #include <mlnn/layer/Layer.hpp>
30 
31 namespace mic {
32 namespace mlnn {
33 namespace experimental {
34 
39 template <typename eT=float>
40 class ConvHebbian : public mic::mlnn::Layer<eT> {
41 public:
42 
49  ConvHebbian<eT>(size_t input_width, size_t input_height, size_t input_depth, size_t nfilters, size_t filter_size, size_t stride = 1, std::string name_ = "ConvHebbian") :
53  stride(stride),
54  x2col(new mic::types::Matrix<eT>(filter_size * filter_size, output_width * output_height)),
55  conv2col(new mic::types::Matrix<eT>(filter_size * filter_size, output_width * output_height))
56  {
57  // Create the weights matrix, each row is a filter kernel
58  p.add("W", nfilters, filter_size * filter_size);
59  mic::types::MatrixPtr<eT> W = p["W"];
60 
61  // Set normalized, zero sum, hebbian learning as default optimization function.
62  Layer<eT>::template setOptimization<mic::neural_nets::learning::NormalizedZerosumHebbianRule<eT> > ();
63 
64  // Initialize weights of all the columns of W.
65  W->rand();
66  for(auto i = 0 ; i < W->rows() ; i++) {
67  // Make the matrix Zero Sum
68  W->row(i).array() -= W->row(i).sum() / W->row(i).cols();
69  if(W->row(i).norm() != 0){
70  W->row(i) = W->row(i).normalized();
71  }
72  }
73  }
74 
75 
79  virtual ~ConvHebbian() {}
80 
85  void forward(bool test_ = false) {
86  // Get input matrices.
87  mic::types::Matrix<eT> x = (*s["x"]);
88  mic::types::Matrix<eT> W = (*p["W"]);
89  // Get output pointer - so the results will be stored!
90  mic::types::MatrixPtr<eT> y = s["y"];
91 
92  // IM2COL
93  // Iterate over the output matrix (number of image patches)
94  for(size_t oy = 0 ; oy < output_height ; oy++){
95  for(size_t ox = 0 ; ox < output_width ; ox++){
96  // Iterate over the rows of the patch
97  for(size_t patch_y = 0 ; patch_y < filter_size ; patch_y++){
98  // Copy each row of the image patch into appropriate position in x2col
99  x2col->block(patch_y * filter_size, ox + (output_width * oy), filter_size, 1) =
100  x.block((((oy * stride) + patch_y) * input_width) + (ox * stride), 0, filter_size, 1);
101  }
102  }
103  }
104  // Forward pass.
105  (*y) = W * (*x2col);
106  o_reconstruction_updated = false;
107  // ReLU
108  //(*y) = (*y).cwiseMax(0);
109  }
110 
114  void backward() {
115  //LOG(LERROR) << "Backward propagation should not be used with layers using Hebbian learning!";
116  }
117 
123  void update(eT alpha_, eT decay_ = 0.0f) {
124  opt["W"]->update(p["W"], x2col, s["y"], alpha_);
125  }
126 
127 
128 
132  std::vector< std::shared_ptr <mic::types::Matrix<eT> > > & getOutputActivations() {
133 
134  // Allocate memory.
136 
137  mic::types::MatrixPtr<eT> W = s["y"];
138 
139  // Iterate through "neurons" and generate "activation image" for each one.
140  for (size_t i = 0 ; i < nfilters ; i++) {
141  // Get row.
142  mic::types::MatrixPtr<eT> row = o_activations[i];
143  // Copy data.
144  (*row) = W->row(i);
145  // Resize row.
146  row->resize(output_width, output_height);
147 
148  }//: for filters
149 
150  // Return activations.
151  return o_activations;
152  }
153 
157  std::vector< std::shared_ptr <mic::types::Matrix<eT> > > & getOutputReconstruction() {
158 
159  // Allocate memory.
161  o_reconstruction[0]->zeros();
162  conv2col->zeros();
163 
164  mic::types::MatrixPtr<eT> o = s["y"];
165  mic::types::MatrixPtr<eT> w = p["W"];
166 
167  //Reconstruct in im2col format
168  for(size_t i = 0 ; i < output_width * output_height ; i++){
169  for(size_t ker = 0 ; ker < nfilters ; ker++){
170  // ReLU on the filters and feature maps
171  mic::types::Matrix<eT> k;
172  k = (w->row(ker)).transpose();
173  k = k.array().max(0.);
174  conv2col->col(i) += ((*o)(ker, i) > 0 ? (*o)(ker, i) : 0) * k;
175  // No ReLU at all
176  // conv2col->col(i) += ((*o)(ker, i) > 0 ? (*o)(ker, i) : 0)
177  // * w->row(ker);
178  }
179  }
180 
181  for(size_t x = 0 ; x < output_width ; x ++){
182  for(size_t y = 0 ; y < output_height ; y ++){
183  for(size_t ker = 0 ; ker < nfilters ; ker++){
184  mic::types::Matrix<eT> temp;
185  temp = conv2col->col(y + (x * output_height));
186  temp.resize(filter_size, filter_size);
187  o_reconstruction[0]->block(y * stride, x * stride, filter_size, filter_size) += temp;
188  }
189  }
190  }
191 
192  // Return reconstruction
194  return o_reconstruction;
195  }
196 
205  }
206 
207  Eigen::Map<Eigen::Matrix<eT, Eigen::Dynamic, 1> > r(o_reconstruction[0]->data(), o_reconstruction[0]->size());
208 
209  mic::types::Matrix<eT> diff;
210  diff = r.normalized() - (*s["x"]).normalized();
211  eT error = diff.squaredNorm();
212  return error;
213  }
214 
218  std::vector< std::shared_ptr <mic::types::Matrix<eT> > > & getWeightActivations() {
219 
220  // Allocate memory.
222 
223  mic::types::MatrixPtr<eT> W = p["W"];
224 
225  // Iterate through "neurons" and generate "activation image" for each one.
226  for (size_t i = 0 ; i < nfilters ; i++) {
227  // Get row.
228  mic::types::MatrixPtr<eT> row = w_activations[i];
229  // Copy data.
230  (*row) = W->row(i);
231  // Resize row.
232  row->resize(filter_size, filter_size);
233  }//: for filters
234 
235  // Return activations.
236  return w_activations;
237  }
238 
244  std::vector< std::shared_ptr <mic::types::Matrix<eT> > > & getWeightSimilarity(bool fillDiagonal = false) {
245 
246  // Allocate memory.
248 
249  mic::types::MatrixPtr<eT> W = p["W"];
250  mic::types::MatrixPtr<eT> row = w_similarity[0];
251 
252  // Iterate through "neurons" and generate "activation image" for each one.
253  for (size_t i = 0 ; i < nfilters ; i++) {
254  for(size_t j = 0 ; j < i ; j++) {
255  // Compute cosine similarity between filter i and j
256  eT sim = W->row(j).dot(W->row(i));
257  sim /= W->row(i).norm() * W->row(j).norm();
258  if(sim > 0.) // positive similarity above diagonal
259  (*row)(j + (nfilters * i)) = sim;
260  else // negative similarity below diagonal
261  (*row)(i + (nfilters * j)) = sim;
262  }
263  }
264 
265  if(fillDiagonal) {
266  // Fill diagonal with alternating 1,-1 to 'calibrate' visualization
267  for (size_t i = 0 ; i < nfilters ; i++) {
268  (*row)(i + (nfilters * i)) = 1 - (int)(2 * (i % 2));
269  }
270  }
271 
272  row->resize(nfilters, nfilters);
273 
274  // Return activations.
275  return w_similarity;
276  }
277 
281  std::vector< std::shared_ptr <mic::types::Matrix<eT> > > & getWeightDissimilarity() {
282 
283  // Allocate memory.
285 
286  mic::types::MatrixPtr<eT> W = p["W"];
287  mic::types::MatrixPtr<eT> row = w_dissimilarity[0];
288 
289  // Iterate through "neurons" and generate "activation image" for each one.
290  for (size_t i = 0 ; i < nfilters ; i++) {
291  for(size_t j = 0 ; j < nfilters ; j++){
292  // Compute cosine similarity between filter i and j
293  (*row)(j + (nfilters * i)) = std::abs(W->row(j).dot(W->row(i)));
294  (*row)(j + (nfilters * i)) /= W->row(i).norm() * W->row(j).norm();
295  // Convert to sine
296  (*row)(j + (nfilters * i)) = std::sqrt(1 - std::pow((*row)(j + (nfilters * i)), 2));
297  }
298  }
299 
300  row->resize(nfilters, nfilters);
301 
302  // Return activations.
303  return w_dissimilarity;
304  }
305 
312  // Unhide the overloaded methods inherited from the template class Layer fields via "using" statement.
313  using Layer<eT>::forward;
314  using Layer<eT>::backward;
315 
316 protected:
317  // Unhide the fields inherited from the template class Layer via "using" statement.
318  using Layer<eT>::s;
319  using Layer<eT>::m;
320  using Layer<eT>::p;
321  using Layer<eT>::opt;
322 
323  // Uncover "sizes" for visualization.
330  using Layer<eT>::batch_size;
331 
332  // Uncover methods useful in visualization.
334 
335  size_t nfilters = 0;
336  size_t filter_size = 0;
337  size_t stride = 0;
338  // Vector of channels, Each containing a vector of filters
339  std::vector<std::vector<mic::types::Matrix<eT> > > W;
340  mic::types::MatrixPtr<eT> x2col;
341  mic::types::MatrixPtr<eT> conv2col;
342 
343 private:
344  // Friend class - required for using boost serialization.
345  template<typename tmp> friend class mic::mlnn::MultiLayerNeuralNetwork;
346 
348  std::vector< std::shared_ptr <mic::types::Matrix<eT> > > w_activations;
349  std::vector< std::shared_ptr <mic::types::Matrix<eT> > > o_activations;
350  std::vector< std::shared_ptr <mic::types::Matrix<eT> > > o_reconstruction;
352  std::vector< std::shared_ptr <mic::types::Matrix<eT> > > w_similarity;
353  std::vector< std::shared_ptr <mic::types::Matrix<eT> > > w_dissimilarity;
358 };
359 
360 
361 } /* namespace fully_connected */
362 } /* namespace mlnn */
363 } /* namespace mic */
364 
365 #endif /* SRC_MLNN_CONVHEBBIAN_HPP_ */
mic::types::MatrixPtr< eT > x2col
std::vector< std::shared_ptr< mic::types::Matrix< eT > > > o_activations
std::vector< std::shared_ptr< mic::types::Matrix< eT > > > w_similarity
std::vector< std::shared_ptr< mic::types::Matrix< eT > > > w_activations
Vector containing activations of neurons.
size_t input_depth
Number of channels of the input (e.g. 3 for RGB images).
Definition: Layer.hpp:732
mic::types::MatrixPtr< eT > conv2col
std::vector< std::shared_ptr< mic::types::Matrix< eT > > > w_dissimilarity
std::vector< std::shared_ptr< mic::types::Matrix< eT > > > & getWeightDissimilarity()
std::vector< std::shared_ptr< mic::types::Matrix< eT > > > o_reconstruction
Class implementing a convolutional hebbian layer.
Definition: ConvHebbian.hpp:40
void forward(bool test_=false)
Definition: ConvHebbian.hpp:85
eT getOutputReconstructionError()
getOutputReconstructionError
std::vector< std::vector< mic::types::Matrix< eT > > > W
std::vector< std::shared_ptr< mic::types::Matrix< eT > > > & getWeightActivations()
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
Class representing a multi-layer neural network.
Definition: Layer.hpp:86
void update(eT alpha_, eT decay_=0.0f)
mic::neural_nets::optimization::OptimizationArray< eT > opt
Array of optimization functions.
Definition: Layer.hpp:765
std::vector< std::shared_ptr< mic::types::Matrix< eT > > > & getWeightSimilarity(bool fillDiagonal=false)
Returns cosine similarity matrix of filters.
mic::types::MatrixArray< eT > s
States - contains input [x] and output [y] matrices.
Definition: Layer.hpp:753
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
std::vector< std::shared_ptr< mic::types::Matrix< eT > > > & getOutputReconstruction()
std::vector< std::shared_ptr< mic::types::Matrix< eT > > > & getOutputActivations()
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 > p
Parameters - parameters of the layer, to be used by the derived classes.
Definition: Layer.hpp:759