9#include "pooling_layer.h"
39 pool_rows_number = pool_dimensions[0];
41 pool_columns_number = pool_dimensions[1];
61 const Index input_variables_dimensions_number = inputs.rank();
63 if(input_variables_dimensions_number != 4)
67 buffer <<
"OpenNN Exception: ConvolutionalLayer class.\n"
68 <<
"Tensor<type, 2> calculate_outputs(const Tensor<type, 2>&) method.\n"
69 <<
"Number of inputs dimensions (" << input_variables_dimensions_number <<
") must be 4 (batch, filters, rows, columns).\n";
71 throw logic_error(buffer.str());
76 switch(pooling_method)
78 case PoolingMethod::NoPooling:
81 case PoolingMethod::MaxPooling:
84 case PoolingMethod::AveragePooling:
88 return Tensor<type, 4>();
97 const Index images_number = inputs.dimension(0);
99 const Index channels_number = inputs.dimension(1);
101 const Index inputs_rows_number = inputs.dimension(2);
103 const Index inputs_columns_number = inputs.dimension(3);
105 const Index outputs_rows_number = (inputs_rows_number - pool_rows_number)/row_stride + 1;
107 const Index outputs_columns_number = (inputs_columns_number - pool_columns_number)/column_stride + 1;
109 Tensor<type, 4> outputs(images_number, channels_number, outputs_rows_number, outputs_columns_number);
111 for(Index image_index = 0; image_index < images_number; image_index ++)
113 for(Index channel_index = 0; channel_index < channels_number; channel_index ++)
115 for(Index row_index = 0; row_index < outputs_rows_number; row_index ++)
117 for(Index column_index = 0; column_index < outputs_columns_number; column_index ++)
119 outputs(image_index, channel_index, row_index, column_index) = type(0);
121 for(Index window_row = 0; window_row < pool_rows_number; window_row ++)
123 const Index row = row_index*row_stride + window_row;
125 for(Index window_column = 0; window_column < pool_columns_number; window_column ++)
127 const Index column = column_index*column_stride + window_column;
129 outputs(image_index, channel_index, row_index, column_index) += inputs(image_index, channel_index, row, column);
133 outputs(image_index, channel_index, row_index, column_index) /= type(pool_rows_number*pool_columns_number);
157 const Index images_number = inputs.dimension(0);
159 const Index channels_number = inputs.dimension(1);
161 const Index inputs_rows_number = inputs.dimension(2);
163 const Index inputs_columns_number = inputs.dimension(3);
165 const Index outputs_rows_number = (inputs_rows_number - pool_rows_number)/row_stride + 1;
167 const Index outputs_columns_number = (inputs_columns_number - pool_columns_number)/column_stride + 1;
169 Tensor<type, 4> outputs(images_number, channels_number, outputs_rows_number, outputs_columns_number);
171 for(Index image_index = 0; image_index < images_number; image_index ++)
173 for(Index channel_index = 0; channel_index < channels_number; channel_index ++)
175 for(Index row_index = 0; row_index < outputs_rows_number; row_index ++)
177 for(Index column_index = 0; column_index < outputs_columns_number; column_index ++)
179 outputs(image_index, channel_index, row_index, column_index) =
180 inputs(image_index, channel_index, row_index*row_stride, column_index*column_stride);
182 for(Index window_row = 0; window_row < pool_rows_number; window_row ++)
184 const Index row = row_index*row_stride + window_row;
186 for(Index window_column = 0; window_column < pool_columns_number; window_column ++)
188 const Index column = column_index*column_stride + window_column;
190 if(inputs(image_index, channel_index, row, column) > outputs(image_index, channel_index, row_index, column_index))
192 outputs(image_index, channel_index, row_index, column_index) = inputs(image_index, channel_index, row, column);
206Tensor<type, 4> PoolingLayer::calculate_hidden_delta(
Layer* next_layer_pointer,
207 const Tensor<type, 4>& activations,
208 const Tensor<type, 4>& activations_derivatives,
209 const Tensor<type, 4>& next_layer_delta)
const
211 if(pooling_method == PoolingMethod::NoPooling)
return next_layer_delta;
221 return calculate_hidden_delta_convolutional(convolutional_layer, activations, activations_derivatives, next_layer_delta);
227 return calculate_hidden_delta_pooling(pooling_layer, activations, activations_derivatives, next_layer_delta);
231 PerceptronLayer* perceptron_layer =
static_cast<PerceptronLayer*
>(next_layer_pointer);
233 return calculate_hidden_delta_perceptron(perceptron_layer, activations, activations_derivatives, next_layer_delta);
237 ProbabilisticLayer* probabilistic_layer =
dynamic_cast<ProbabilisticLayer*
>(next_layer_pointer);
239 return calculate_hidden_delta_probabilistic(probabilistic_layer, activations, activations_derivatives, next_layer_delta);
243 return Tensor<type, 4>();
247Tensor<type, 4> PoolingLayer::calculate_hidden_delta_convolutional(ConvolutionalLayer* next_layer_pointer,
248 const Tensor<type, 4>&,
249 const Tensor<type, 4>&,
250 const Tensor<type, 4>& next_layer_delta)
const
254 const Index images_number = next_layer_delta.dimension(0);
261 const Index next_layers_filters_number = next_layer_pointer->get_kernels_number();
262 const Index next_layers_filter_rows = next_layer_pointer->get_kernels_rows_number();
263 const Index next_layers_filter_columns = next_layer_pointer->get_kernels_columns_number();
264 const Index next_layers_output_rows = next_layer_pointer->get_outputs_rows_number();
265 const Index next_layers_output_columns = next_layer_pointer->get_outputs_columns_number();
266 const Index next_layers_row_stride = next_layer_pointer->get_row_stride();
267 const Index next_layers_column_stride = next_layer_pointer->get_column_stride();
269 const Tensor<type, 4> next_layers_weights = next_layer_pointer->get_synaptic_weights();
273 Tensor<type, 4> hidden_delta(images_number, channels_number, output_rows_number, output_columns_number);
275 const Index size = hidden_delta.size();
277 #pragma omp parallel for
279 for(Index tensor_index = 0; tensor_index < size; tensor_index++)
281 const Index image_index = tensor_index/(channels_number*output_rows_number*output_columns_number);
282 const Index channel_index = (tensor_index/(output_rows_number*output_columns_number))%channels_number;
283 const Index row_index = (tensor_index/output_columns_number)%output_rows_number;
284 const Index column_index = tensor_index%output_columns_number;
288 const Index lower_row_index = (row_index - next_layers_filter_rows)/next_layers_row_stride + 1;
289 const Index upper_row_index = min(row_index/next_layers_row_stride + 1, next_layers_output_rows);
290 const Index lower_column_index = (column_index - next_layers_filter_columns)/next_layers_column_stride + 1;
291 const Index upper_column_index = min(column_index/next_layers_column_stride + 1, next_layers_output_columns);
293 for(Index i = 0; i < next_layers_filters_number; i++)
295 for(Index j = lower_row_index; j < upper_row_index; j++)
297 for(Index k = lower_column_index; k < upper_column_index; k++)
299 const type delta_element = next_layer_delta(image_index, i, j, k);
301 const type weight = next_layers_weights(i, channel_index, row_index - j*next_layers_row_stride, column_index - k*next_layers_column_stride);
303 sum += delta_element*weight;
308 hidden_delta(image_index, channel_index, row_index, column_index) = sum;
315Tensor<type, 4> PoolingLayer::calculate_hidden_delta_pooling(PoolingLayer* next_layer_pointer,
316 const Tensor<type, 4>& activations,
317 const Tensor<type, 4>&,
318 const Tensor<type, 4>& next_layer_delta)
const
320 switch(next_layer_pointer->get_pooling_method())
322 case OpenNN::PoolingLayer::PoolingMethod::NoPooling:
324 return next_layer_delta;
327 case OpenNN::PoolingLayer::PoolingMethod::AveragePooling:
331 const Index images_number = next_layer_delta.dimension(0);
338 const Index next_layers_pool_rows = next_layer_pointer->get_pool_rows_number();
339 const Index next_layers_pool_columns = next_layer_pointer->get_pool_columns_number();
340 const Index next_layers_output_rows = next_layer_pointer->get_outputs_rows_number();
341 const Index next_layers_output_columns = next_layer_pointer->get_outputs_columns_number();
342 const Index next_layers_row_stride = next_layer_pointer->get_row_stride();
343 const Index next_layers_column_stride = next_layer_pointer->get_column_stride();
347 Tensor<type, 4> hidden_delta(images_number, channels_number, output_rows_number, output_columns_number);
349 const Index size = hidden_delta.size();
351 #pragma omp parallel for
353 for(Index tensor_index = 0; tensor_index < size; tensor_index++)
355 const Index image_index = tensor_index/(channels_number*output_rows_number*output_columns_number);
356 const Index channel_index = (tensor_index/(output_rows_number*output_columns_number))%channels_number;
357 const Index row_index = (tensor_index/output_columns_number)%output_rows_number;
358 const Index column_index = tensor_index%output_columns_number;
362 const Index lower_row_index = (row_index - next_layers_pool_rows)/next_layers_row_stride + 1;
363 const Index upper_row_index = min(row_index/next_layers_row_stride + 1, next_layers_output_rows);
364 const Index lower_column_index = (column_index - next_layers_pool_columns)/next_layers_column_stride + 1;
365 const Index upper_column_index = min(column_index/next_layers_column_stride + 1, next_layers_output_columns);
367 for(Index i = lower_row_index; i < upper_row_index; i++)
369 for(Index j = lower_column_index; j < upper_column_index; j++)
371 const type delta_element = next_layer_delta(image_index, channel_index, i, j);
373 sum += delta_element;
377 hidden_delta(image_index, channel_index, row_index, column_index) = sum;
383 case OpenNN::PoolingLayer::PoolingMethod::MaxPooling:
387 const Index images_number = next_layer_delta.dimension(0);
394 const Index next_layers_pool_rows = next_layer_pointer->get_pool_rows_number();
395 const Index next_layers_pool_columns = next_layer_pointer->get_pool_columns_number();
396 const Index next_layers_output_rows = next_layer_pointer->get_outputs_rows_number();
397 const Index next_layers_output_columns = next_layer_pointer->get_outputs_columns_number();
398 const Index next_layers_row_stride = next_layer_pointer->get_row_stride();
399 const Index next_layers_column_stride = next_layer_pointer->get_column_stride();
403 Tensor<type, 4> hidden_delta(images_number, channels_number, output_rows_number, output_columns_number);
405 const Index size = hidden_delta.size();
407 #pragma omp parallel for
409 for(Index tensor_index = 0; tensor_index < size; tensor_index++)
411 const Index image_index = tensor_index/(channels_number*output_rows_number*output_columns_number);
412 const Index channel_index = (tensor_index/(output_rows_number*output_columns_number))%channels_number;
413 const Index row_index = (tensor_index/output_columns_number)%output_rows_number;
414 const Index column_index = tensor_index%output_columns_number;
418 const Index lower_row_index = (row_index - next_layers_pool_rows)/next_layers_row_stride + 1;
419 const Index upper_row_index = min(row_index/next_layers_row_stride + 1, next_layers_output_rows);
420 const Index lower_column_index = (column_index - next_layers_pool_columns)/next_layers_column_stride + 1;
421 const Index upper_column_index = min(column_index/next_layers_column_stride + 1, next_layers_output_columns);
423 for(Index i = lower_row_index; i < upper_row_index; i++)
425 for(Index j = lower_column_index; j < upper_column_index; j++)
427 Tensor<type, 2> activations_current_submatrix(next_layers_pool_rows, next_layers_pool_columns);
429 for(Index submatrix_row_index = 0; submatrix_row_index < next_layers_pool_rows; submatrix_row_index++)
431 for(Index submatrix_column_index = 0; submatrix_column_index < next_layers_pool_columns; submatrix_column_index++)
433 activations_current_submatrix(submatrix_row_index, submatrix_column_index) =
434 activations(image_index, channel_index, i*next_layers_row_stride + submatrix_row_index, j*next_layers_column_stride + submatrix_column_index);
438 Tensor<type, 2> multiply_not_multiply(next_layers_pool_rows, next_layers_pool_columns);
440 type max_value = activations_current_submatrix(0,0);
442 for(Index submatrix_row_index = 0; submatrix_row_index < next_layers_pool_rows; submatrix_row_index++)
444 for(Index submatrix_column_index = 0; submatrix_column_index < next_layers_pool_columns; submatrix_column_index++)
446 if(activations_current_submatrix(submatrix_row_index, submatrix_column_index) > max_value)
448 max_value = activations_current_submatrix(submatrix_row_index, submatrix_column_index);
456 const type delta_element = next_layer_delta(image_index, channel_index, i, j);
458 const type max_derivative = multiply_not_multiply(row_index - i*next_layers_row_stride, column_index - j*next_layers_column_stride);
460 sum += delta_element*max_derivative;
464 hidden_delta(image_index, channel_index, row_index, column_index) = sum;
471 return Tensor<type, 4>();
475Tensor<type, 4> PoolingLayer::calculate_hidden_delta_perceptron(PerceptronLayer* next_layer_pointer,
476 const Tensor<type, 4>&,
477 const Tensor<type, 4>&,
478 const Tensor<type, 4>& next_layer_delta)
const
482 const Index images_number = next_layer_delta.dimension(0);
489 const Index next_layers_output_columns = next_layer_delta.dimension(1);
491 const Tensor<type, 2> next_layers_weights = next_layer_pointer->get_synaptic_weights();
495 Tensor<type, 4> hidden_delta(images_number, channels_number, output_rows_number, output_columns_number);
497 const Index size = hidden_delta.size();
499 #pragma omp parallel for
501 for(Index tensor_index = 0; tensor_index < size; tensor_index++)
510 for(Index sum_index = 0; sum_index < next_layers_output_columns; sum_index++)
526Tensor<type, 4> PoolingLayer::calculate_hidden_delta_probabilistic(ProbabilisticLayer* next_layer_pointer,
527 const Tensor<type, 4>&,
528 const Tensor<type, 4>&,
529 const Tensor<type, 4>& next_layer_delta)
const
533 const Index images_number = next_layer_delta.dimension(0);
540 const Index next_layers_output_columns = next_layer_delta.dimension(1);
542 const Tensor<type, 2> next_layers_weights = next_layer_pointer->get_synaptic_weights();
546 Tensor<type, 4> hidden_delta(images_number, channels_number, output_rows_number, output_columns_number);
548 const Index size = hidden_delta.size();
550 #pragma omp parallel for
552 for(Index tensor_index = 0; tensor_index < size; tensor_index++)
561 for(Index sum_index = 0; sum_index < next_layers_output_columns; sum_index++)
577Tensor<type, 1> PoolingLayer::calculate_error_gradient(
const Tensor<type, 2>&,
578 const LayerForwardPropagation&,
579 const Tensor<type, 2>&)
581 return Tensor<type, 1>();
597 Tensor<Index, 1> outputs_dimensions(3);
603 return outputs_dimensions;
611 return input_variables_dimensions.size();
669 return padding_width;
685 return column_stride;
693 return pool_rows_number;
701 return pool_columns_number;
717 return Tensor<type, 1>();
725 return pooling_method;
734 input_variables_dimensions = new_input_variables_dimensions;
743 padding_width = new_padding_width;
752 row_stride = new_row_stride;
761 column_stride = new_column_stride;
770 const Index& new_pool_columns_number)
772 pool_rows_number = new_pool_rows_number;
774 pool_columns_number = new_pool_columns_number;
783 pooling_method = new_pooling_method;
This abstract class represents the concept of layer of neurons in OpenNN.
Type
This enumeration represents the possible types of layers.
Type layer_type
Layer type.
void set_input_variables_dimensions(const Tensor< Index, 1 > &)
virtual ~PoolingLayer()
Destructor.
Tensor< type, 4 > calculate_max_pooling_outputs(const Tensor< type, 4 > &) const
Tensor< type, 4 > calculate_average_pooling_outputs(const Tensor< type, 4 > &) const
Index get_column_stride() const
Returns the pooling filter's column stride.
Index get_inputs_number() const
Returns the number of inputs of the layer.
Tensor< type, 4 > calculate_outputs(const Tensor< type, 4 > &)
Index get_outputs_rows_number() const
Returns the number of rows of the layer's output.
void set_pooling_method(const PoolingMethod &)
void set_default()
Sets the layer type to Layer::Pooling.
Index get_inputs_channels_number() const
Returns the number of channels of the layers' input.
Tensor< type, 4 > calculate_no_pooling_outputs(const Tensor< type, 4 > &) const
Index get_pool_rows_number() const
Returns the number of rows of the pooling filter.
Index get_inputs_rows_number() const
Returns the number of rows of the layer's input.
Index get_inputs_columns_number() const
Returns the number of columns of the layer's input.
void set_row_stride(const Index &)
Index get_outputs_columns_number() const
Returns the number of columns of the layer's output.
void set_pool_size(const Index &, const Index &)
void set_column_stride(const Index &)
PoolingMethod
Enumeration of available methods for pooling data.
Index get_padding_width() const
Returns the padding width.
Index get_neurons_number() const
Returns the number of neurons the layer applies to an image.
void set_padding_width(const Index &)
Tensor< Index, 1 > get_outputs_dimensions() const
Returns the layer's outputs dimensions.
Index get_row_stride() const
Returns the pooling filter's row stride.
PoolingMethod get_pooling_method() const
Returns the pooling method.
Index get_parameters_number() const
Returns the number of parameters of the layer.
Index get_pool_columns_number() const
Returns the number of columns of the pooling filter.
Tensor< type, 1 > get_parameters() const
Returns the layer's parameters.