9#include "convolutional_layer.h"
10#include "pooling_layer.h"
11#include "perceptron_layer.h"
12#include "probabilistic_layer.h"
14#include "numerical_differentiation.h"
36 const Tensor<Index, 1>& new_kernels_dimensions) :
Layer()
40 set(new_inputs_dimensions, new_kernels_dimensions);
61 switch(convolution_type)
63 case ConvolutionType::Valid: padded_output = inputs;
return;
65 case ConvolutionType::Same:
67 Eigen::array<pair<int, int>, 4> paddings;
69 paddings[0] = make_pair(0, 0);
70 paddings[1] = make_pair(0, 0);
71 paddings[2] = make_pair(pad, pad);
72 paddings[3] = make_pair(pad, pad);
73 padded_output = inputs.pad(paddings);
84 const Index images_number = inputs.dimension(0);
87 const Eigen::array<ptrdiff_t, 3> dims = {0, 1, 2};
89 Tensor<type, 3> kernel;
92 for(Index i = 0; i < images_number; i++)
94 for(Index j = 0; j < kernels_number; j++)
98 combinations.chip(i, 0).chip(j, 0) = inputs.chip(i, 0).convolve(kernel, dims) +
biases(j);
105 const Tensor<type, 2>& potential_biases,
106 const Tensor<type, 4>& potential_synaptic_weights,
107 Tensor<type, 4>& convolutions)
const
109 const Index number_of_kernels = potential_synaptic_weights.dimension(0);
110 const Index number_of_images = inputs.dimension(0);
114 const Eigen::array<ptrdiff_t, 3> dims = {0, 1, 2};
116 Tensor<type, 3> kernel;
119 for(Index i = 0; i < number_of_images; i++)
121 for(Index j = 0; j < number_of_kernels; j++)
123 kernel = potential_synaptic_weights.chip(j, 0);
125 convolutions.chip(i, 0).chip(j, 0) = inputs.chip(i, 0).convolve(kernel, dims) + potential_biases(j, 0);
136 switch(activation_function)
138 case ActivationFunction::Linear: linear(inputs, activations);
return;
140 case ActivationFunction::Logistic: logistic(inputs, activations);
return;
142 case ActivationFunction::HyperbolicTangent: hyperbolic_tangent(inputs, activations);
return;
144 case ActivationFunction::Threshold: threshold(inputs, activations);
return;
146 case ActivationFunction::SymmetricThreshold: symmetric_threshold(inputs, activations);
return;
148 case ActivationFunction::RectifiedLinear: rectified_linear(inputs, activations);
return;
150 case ActivationFunction::ScaledExponentialLinear: scaled_exponential_linear(inputs, activations);
return;
152 case ActivationFunction::SoftPlus: soft_plus(inputs, activations);
return;
154 case ActivationFunction::SoftSign: soft_sign(inputs, activations);
return;
156 case ActivationFunction::HardSigmoid: hard_sigmoid(inputs, activations);
return;
158 case ActivationFunction::ExponentialLinear: exponential_linear(inputs, activations);
return;
163void ConvolutionalLayer::calculate_activations_derivatives(
const Tensor<type, 4>& combinations_4d,
164 Tensor<type, 4>& activations,
165 Tensor<type, 4>& activations_derivatives)
const
167 switch(activation_function)
169 case ActivationFunction::Linear: linear_derivatives(combinations_4d, activations, activations_derivatives);
return;
171 case ActivationFunction::Logistic: logistic_derivatives(combinations_4d, activations, activations_derivatives);
return;
173 case ActivationFunction::HyperbolicTangent: hyperbolic_tangent_derivatives(combinations_4d, activations, activations_derivatives);
return;
175 case ActivationFunction::Threshold: threshold_derivatives(combinations_4d, activations, activations_derivatives);
return;
177 case ActivationFunction::SymmetricThreshold: symmetric_threshold_derivatives(combinations_4d, activations, activations_derivatives);
return;
179 case ActivationFunction::RectifiedLinear: rectified_linear_derivatives(combinations_4d, activations, activations_derivatives);
return;
181 case ActivationFunction::ScaledExponentialLinear: scaled_exponential_linear_derivatives(combinations_4d, activations, activations_derivatives);
return;
183 case ActivationFunction::SoftPlus: soft_plus_derivatives(combinations_4d, activations, activations_derivatives);
return;
185 case ActivationFunction::SoftSign: soft_sign_derivatives(combinations_4d, activations, activations_derivatives);
return;
187 case ActivationFunction::HardSigmoid: hard_sigmoid_derivatives(combinations_4d, activations, activations_derivatives);
return;
189 case ActivationFunction::ExponentialLinear: exponential_linear_derivatives(combinations_4d, activations, activations_derivatives);
return;
202 outputs.resize(outputs_dimensions(0), outputs_dimensions(1), outputs_dimensions(2), outputs_dimensions(3));
204 Tensor<type, 4> combinations(outputs_dimensions(0), outputs_dimensions(1), outputs_dimensions(2), outputs_dimensions(3));
212void ConvolutionalLayer::forward_propagate(
const Tensor<type, 4> &inputs,
LayerForwardPropagation* forward_propagation)
219 convolutional_layer_forward_propagation->combinations.resize(outputs_dimensions(0),
220 outputs_dimensions(1),
221 outputs_dimensions(2),
222 outputs_dimensions(3));
224 convolutional_layer_forward_propagation->activations.resize(outputs_dimensions(0),
225 outputs_dimensions(1),
226 outputs_dimensions(2),
227 outputs_dimensions(3));
229 convolutional_layer_forward_propagation->activations_derivatives.resize(outputs_dimensions(0),
230 outputs_dimensions(1),
231 outputs_dimensions(2),
232 outputs_dimensions(3));
235 convolutional_layer_forward_propagation->combinations);
237 calculate_activations_derivatives(convolutional_layer_forward_propagation->combinations,
238 convolutional_layer_forward_propagation->activations,
239 convolutional_layer_forward_propagation->activations_derivatives);
247void ConvolutionalLayer::forward_propagate(
const Tensor<type, 2>&inputs, LayerForwardPropagation* forward_propagation)
249 const Eigen::array<Eigen::Index, 4> four_dims = {input_variables_dimensions(3),
250 input_variables_dimensions(2),
251 input_variables_dimensions(1),
252 inputs.dimension(0)};
253 const Eigen::array<Eigen::Index, 2> shuffle_dims_2D = {1, 0};
254 const Eigen::array<Eigen::Index, 4> shuffle_dims_4D = {3, 2, 1, 0};
256 const Tensor<type, 4> inputs_4d = inputs.shuffle(shuffle_dims_2D).reshape(four_dims).shuffle(shuffle_dims_4D);
258 forward_propagate(inputs_4d, forward_propagation);
262void ConvolutionalLayer::forward_propagate(
const Tensor<type, 4>& inputs,
263 Tensor<type, 1> potential_parameters,
264 LayerForwardPropagation* forward_propagation)
266 ConvolutionalLayerForwardPropagation* convolutional_layer_forward_propagation =
static_cast<ConvolutionalLayerForwardPropagation*
>(forward_propagation);
270 convolutional_layer_forward_propagation->combinations.resize(output_dimensions(0),
271 output_dimensions(1),
272 output_dimensions(2),
273 output_dimensions(3));
275 convolutional_layer_forward_propagation->activations.resize(output_dimensions(0),
276 output_dimensions(1),
277 output_dimensions(2),
278 output_dimensions(3));
280 convolutional_layer_forward_propagation->activations_derivatives.resize(output_dimensions(0),
281 output_dimensions(1),
282 output_dimensions(2),
283 output_dimensions(3));
287 const TensorMap<Tensor<type, 2>> potential_biases(potential_parameters.data(),
302 Tensor<type, 4> potential_synaptic_weights(kernels_number,
303 kernels_channels_number,
305 kernels_columns_number);
306 Index element_index = 0;
309 for(Index i = 0; i < kernels_number; i++)
311 for(Index j = 0; j < kernels_channels_number; j++)
313 for(Index k = 0; k < kernels_rows_number; k++)
315 for(Index l = 0; l < kernels_columns_number; l++)
317 potential_synaptic_weights(i ,j, k, l) = potential_parameters(kernels_number + element_index);
326 potential_synaptic_weights,
327 convolutional_layer_forward_propagation->combinations);
329 calculate_activations_derivatives(convolutional_layer_forward_propagation->combinations,
330 convolutional_layer_forward_propagation->activations,
331 convolutional_layer_forward_propagation->activations_derivatives);
335void ConvolutionalLayer::forward_propagate(
const Tensor<type, 2>& inputs,
336 Tensor<type, 1> potential_parameters,
337 LayerForwardPropagation* forward_propagation)
339 const Eigen::array<Eigen::Index, 4> four_dims = {
340 input_variables_dimensions(0),
341 input_variables_dimensions(1),
342 input_variables_dimensions(2),
343 input_variables_dimensions(3)};
345 const Eigen::array<Eigen::Index, 2> shuffle_dims_2D = {1, 0};
346 const Eigen::array<Eigen::Index, 4> shuffle_dims_4D = {3, 2, 1, 0};
348 const Tensor<type, 4> inputs_4d = inputs.shuffle(shuffle_dims_2D).reshape(four_dims).shuffle(shuffle_dims_4D);
351 forward_propagate(inputs_4d, potential_parameters, forward_propagation);
355void ConvolutionalLayer::calculate_hidden_delta(Layer* next_layer_pointer,
356 LayerForwardPropagation* forward_propagation,
357 const Tensor<type, 2>& next_layer_delta,
358 Tensor<type, 2>& hidden_delta)
const
360 ConvolutionalLayerForwardPropagation* convolutional_layer_forward_propagation =
static_cast<ConvolutionalLayerForwardPropagation*
>(forward_propagation);
362 const Type next_layer_type = next_layer_pointer->get_type();
364 if(next_layer_type == Type::Convolutional)
374 else if(next_layer_type == Type::Pooling)
376 PoolingLayer* pooling_layer =
dynamic_cast<PoolingLayer*
>(next_layer_pointer);
378 calculate_hidden_delta_pooling(pooling_layer,
379 convolutional_layer_forward_propagation->activations,
380 convolutional_layer_forward_propagation->activations_derivatives,
384 else if(next_layer_type == Type::Perceptron)
386 PerceptronLayer* perceptron_layer =
static_cast<PerceptronLayer*
>(next_layer_pointer);
395 else if(next_layer_type == Type::Probabilistic)
397 ProbabilisticLayer* probabilistic_layer =
dynamic_cast<ProbabilisticLayer*
>(next_layer_pointer);
399 calculate_hidden_delta_probabilistic(probabilistic_layer,
400 convolutional_layer_forward_propagation->activations,
401 convolutional_layer_forward_propagation->activations_derivatives,
408void ConvolutionalLayer::calculate_hidden_delta_convolutional(ConvolutionalLayer* next_layer_pointer,
409 const Tensor<type, 4>& activations,
410 const Tensor<type, 4>& activations_derivatives,
411 const Tensor<type, 4>& next_layer_delta,
412 Tensor<type, 2>& hidden_delta)
const
417 const auto images_number = next_layer_delta.dimension(3);
425 const Index next_layers_kernels_number = next_layer_pointer->get_kernels_number();
426 const Index next_layers_kernel_rows = next_layer_pointer->get_kernels_rows_number();
427 const Index next_layers_kernel_columns = next_layer_pointer->get_kernels_columns_number();
429 const Index next_layers_output_rows = next_layer_pointer->get_outputs_rows_number();
430 const Index next_layers_output_columns = next_layer_pointer->get_outputs_columns_number();
432 const Index next_layers_row_stride = next_layer_pointer->get_row_stride();
433 const Index next_layers_column_stride = next_layer_pointer->get_column_stride();
435 const Tensor<type, 4> next_layers_weights = next_layer_pointer->get_synaptic_weights();
440 hidden_delta.resize(images_number, kernels_number * output_rows_number * output_columns_number);
442 const Index size = hidden_delta.size();
444 #pragma omp parallel for
446 for(Index tensor_index = 0; tensor_index < size; tensor_index++)
448 const Index image_index = tensor_index / (kernels_number * output_rows_number * output_columns_number);
449 const Index channel_index = (tensor_index / (output_rows_number * output_columns_number)) % kernels_number;
450 const Index row_index = (tensor_index / output_columns_number) % output_rows_number;
451 const Index column_index = tensor_index % output_columns_number;
455 const Index lower_row_index = (row_index - next_layers_kernel_rows) / next_layers_row_stride + 1;
456 const Index upper_row_index = min(row_index/next_layers_row_stride + 1, next_layers_output_rows);
457 const Index lower_column_index = (column_index - next_layers_kernel_columns) / next_layers_column_stride + 1;
458 const Index upper_column_index = min(column_index / next_layers_column_stride + 1, next_layers_output_columns);
460 for(Index i = 0; i < next_layers_kernels_number; i++)
462 for(Index j = lower_row_index; j < upper_row_index; j++)
464 for(Index k = lower_column_index; k < upper_column_index; k++)
466 const type delta_element = next_layer_delta(image_index, i, j, k);
468 const type weight = next_layers_weights(row_index - j * next_layers_row_stride,
469 column_index - k * next_layers_column_stride,
473 sum += delta_element*weight;
478 hidden_delta(row_index, column_index + channel_index + image_index) = sum;
485void ConvolutionalLayer::calculate_hidden_delta_pooling(PoolingLayer* next_layer_pointer,
486 const Tensor<type, 4>& activations,
487 const Tensor<type, 4>& activations_derivatives,
488 const Tensor<type, 2>& next_layer_delta,
489 Tensor<type, 2>& hidden_delta)
const
492 switch(next_layer_pointer->get_pooling_method())
494 case OpenNN::PoolingLayer::PoolingMethod::NoPooling:
499 case OpenNN::PoolingLayer::PoolingMethod::AveragePooling:
503 const Index images_number = next_layer_delta.dimension(0);
510 const Index next_layers_pool_rows = next_layer_pointer->get_pool_rows_number();
511 const Index next_layers_pool_columns = next_layer_pointer->get_pool_columns_number();
512 const Index next_layers_output_rows = next_layer_pointer->get_outputs_rows_number();
513 const Index next_layers_output_columns = next_layer_pointer->get_outputs_columns_number();
514 const Index next_layers_row_stride = next_layer_pointer->get_row_stride();
515 const Index next_layers_column_stride = next_layer_pointer->get_column_stride();
519 hidden_delta.resize(images_number, kernels_number * output_rows_number * output_columns_number);
521 const Index size = hidden_delta.size();
523 #pragma omp parallel for
525 for(Index tensor_index = 0; tensor_index < size; tensor_index++)
527 const Index image_index = tensor_index/(kernels_number*output_rows_number*output_columns_number);
528 const Index channel_index = (tensor_index/(output_rows_number*output_columns_number))%kernels_number;
529 const Index row_index = (tensor_index/output_columns_number)%output_rows_number;
530 const Index column_index = tensor_index%output_columns_number;
534 const Index lower_row_index = (row_index - next_layers_pool_rows)/next_layers_row_stride + 1;
535 const Index upper_row_index = min(row_index/next_layers_row_stride + 1, next_layers_output_rows);
536 const Index lower_column_index = (column_index - next_layers_pool_columns)/next_layers_column_stride + 1;
537 const Index upper_column_index = min(column_index/next_layers_column_stride + 1, next_layers_output_columns);
539 for(Index i = lower_row_index; i < upper_row_index; i++)
541 for(Index j = lower_column_index; j < upper_column_index; j++)
550 hidden_delta(image_index, channel_index + row_index + column_index) = sum;
556 case OpenNN::PoolingLayer::PoolingMethod::MaxPooling:
560 const Index images_number = next_layer_delta.dimension(0);
567 const Index next_layers_pool_rows = next_layer_pointer->get_pool_rows_number();
568 const Index next_layers_pool_columns = next_layer_pointer->get_pool_columns_number();
569 const Index next_layers_output_rows = next_layer_pointer->get_outputs_rows_number();
570 const Index next_layers_output_columns = next_layer_pointer->get_outputs_columns_number();
571 const Index next_layers_row_stride = next_layer_pointer->get_row_stride();
572 const Index next_layers_column_stride = next_layer_pointer->get_column_stride();
576 hidden_delta.resize(images_number, kernels_number * output_rows_number * output_columns_number);
578 const Index size = hidden_delta.size();
580 #pragma omp parallel for
582 for(Index tensor_index = 0; tensor_index < size; tensor_index++)
584 const Index image_index = tensor_index/(kernels_number*output_rows_number*output_columns_number);
585 const Index channel_index = (tensor_index/(output_rows_number*output_columns_number))%kernels_number;
586 const Index row_index = (tensor_index/output_columns_number)%output_rows_number;
587 const Index column_index = tensor_index%output_columns_number;
591 const Index lower_row_index = (row_index - next_layers_pool_rows)/next_layers_row_stride + 1;
592 const Index upper_row_index = min(row_index/next_layers_row_stride + 1, next_layers_output_rows);
593 const Index lower_column_index = (column_index - next_layers_pool_columns)/next_layers_column_stride + 1;
594 const Index upper_column_index = min(column_index/next_layers_column_stride + 1, next_layers_output_columns);
596 for(Index i = lower_row_index; i < upper_row_index; i++)
598 for(Index j = lower_column_index; j < upper_column_index; j++)
602 Tensor<type, 2> activations_current_submatrix(next_layers_pool_rows, next_layers_pool_columns);
604 for(Index submatrix_row_index = 0; submatrix_row_index < next_layers_pool_rows; submatrix_row_index++)
606 for(Index submatrix_column_index = 0; submatrix_column_index < next_layers_pool_columns; submatrix_column_index++)
613 Tensor<type, 2> multiply_not_multiply(next_layers_pool_rows, next_layers_pool_columns);
615 type max_value = activations_current_submatrix(0,0);
617 for(Index submatrix_row_index = 0; submatrix_row_index < next_layers_pool_rows; submatrix_row_index++)
619 for(Index submatrix_column_index = 0; submatrix_column_index < next_layers_pool_columns; submatrix_column_index++)
621 if(activations_current_submatrix(submatrix_row_index, submatrix_column_index) > max_value)
623 max_value = activations_current_submatrix(submatrix_row_index, submatrix_column_index);
626 multiply_not_multiply(submatrix_row_index, submatrix_column_index) = type(1);
631 const type max_derivative = multiply_not_multiply(row_index - i*next_layers_row_stride, column_index - j*next_layers_column_stride);
638 hidden_delta(image_index + channel_index + row_index + column_index) = sum;
650 const Tensor<type, 4>& ,
651 const Tensor<type, 2>& activations_derivatives,
652 const Tensor<type, 2>& next_layer_delta,
653 Tensor<type, 2>& hidden_delta)
const
668 hidden_delta = next_layer_delta.contract(next_layer_weights, A_BT);
670 hidden_delta.device(*thread_pool_device) = hidden_delta*activations_derivatives;
674 const Index next_layers_output_columns = next_layer_delta.dimension(1);
682 const Index size = hidden_delta.size();
686 for(Index tensor_index = 0; tensor_index < size; tensor_index++)
709void ConvolutionalLayer::calculate_hidden_delta_probabilistic(
ProbabilisticLayer* next_layer_pointer,
710 const Tensor<type, 4>& activations,
711 const Tensor<type, 4>& activations_derivatives,
712 const Tensor<type, 2>& next_layer_delta,
713 Tensor<type, 2>& hidden_delta)
const
716 const Index images_number = next_layer_delta.dimension(0);
723 const Index next_layers_output_columns = next_layer_delta.dimension(1);
729 hidden_delta.resize(images_number, kernels_number * output_rows_number * output_columns_number);
731 const Index size = hidden_delta.size();
733 #pragma omp parallel for
735 for(Index tensor_index = 0; tensor_index < size; tensor_index++)
743 const Index image_index = tensor_index / (kernels_number * output_rows_number * output_columns_number);
745 const Index channel_index = (tensor_index / (output_rows_number * output_columns_number)) % kernels_number;
746 const Index row_index = (tensor_index / output_columns_number) % output_rows_number;
747 const Index column_index = tensor_index % output_columns_number;
751 for(Index sum_index = 0; sum_index < next_layers_output_columns; sum_index++)
758 const type delta_element = next_layer_delta(image_index, sum_index);
761 const type weight = next_layers_weights(channel_index + row_index + column_index,
769 hidden_delta(image_index, channel_index + row_index + column_index) = sum;
772 hidden_delta.device(*thread_pool_device) = hidden_delta * activations_derivatives;
776void ConvolutionalLayer::calculate_error_gradient(
const Tensor<type, 4>& inputs,
777 LayerForwardPropagation* forward_propagation,
778 LayerBackPropagation& back_propagation)
const
780 Tensor<type, 4> layers_inputs;
782 switch(convolution_type) {
784 case OpenNN::ConvolutionalLayer::ConvolutionType::Valid:
786 layers_inputs = inputs;
790 case OpenNN::ConvolutionalLayer::ConvolutionType::Same:
792 layers_inputs = inputs;
807 const Index images_number = inputs.dimension(0);
815 const Eigen::array<ptrdiff_t, 3> dims = {0, 1, 2};
817 Index image_index = 0;
818 Index kernel_index = 0;
820 for(Index i = 0; i < images_number; i++)
822 image_index = i*kernels_number*(kernels_rows_number*kernels_columns_number);
824 for(Index j = 0; j < kernels_number; j++)
829 kernel_index = j*kernels_rows_number*kernels_columns_number;
838void ConvolutionalLayer::calculate_error_gradient(
const Tensor<type, 2>& inputs,
839 LayerForwardPropagation* forward_propagation,
840 LayerBackPropagation& back_propagation)
const
842 const Eigen::array<Eigen::Index, 4> four_dims = {input_variables_dimensions(3),
843 input_variables_dimensions(2),
844 input_variables_dimensions(1),
845 inputs.dimension(0)};
847 const Eigen::array<Eigen::Index, 2> shuffle_dims_2D = {1, 0};
848 const Eigen::array<Eigen::Index, 4> shuffle_dims_4D = {3, 2, 1, 0};
850 const Tensor<type, 4> inputs_4d = inputs.shuffle(shuffle_dims_2D).reshape(four_dims).shuffle(shuffle_dims_4D);
852 calculate_error_gradient(inputs_4d, forward_propagation, back_propagation);
856void ConvolutionalLayer::insert_gradient(LayerBackPropagation* back_propagation,
const Index& index, Tensor<type, 1>& gradient)
const
858 ConvolutionalLayerBackPropagation* convolutional_layer_back_propagation =
859 static_cast<ConvolutionalLayerBackPropagation*
>(back_propagation);
861 const Index biases_number =
biases.size();
864 memcpy(gradient.data() + index,
865 convolutional_layer_back_propagation->biases_derivatives.data(),
866 static_cast<size_t>(biases_number)*
sizeof(type));
868 memcpy(gradient.data() + index + biases_number,
869 convolutional_layer_back_propagation->synaptic_weights_derivatives.data(),
870 static_cast<size_t>(synaptic_weights_number)*
sizeof(type));
878 return activation_function;
890 return ((input_variables_dimensions(2) - kernels_rows_number + 2 * padding_height)/row_stride) + 1;
902 return ((input_variables_dimensions(3) - kernels_columns_number + 2 * padding_width)/column_stride) + 1;
910 Tensor<Index, 1> outputs_dimensions(4);
912 outputs_dimensions(0) = input_variables_dimensions(0);
917 return outputs_dimensions;
925 return input_variables_dimensions;
933 return convolution_type;
941 return column_stride;
989 switch(convolution_type)
991 case ConvolutionType::Valid:
996 case ConvolutionType::Same:
1010 switch(convolution_type)
1012 case ConvolutionType::Valid:
1017 case ConvolutionType::Same:
1019 return row_stride*(input_variables_dimensions[1] - 1) - input_variables_dimensions[1] +
get_kernels_rows_number();
1043 return kernels_number*kernels_rows_number*kernels_columns_number;
1060 Index element_index = 0;
1062 for(Index i = 0; i < kernels_number; i++)
1064 for(Index j = 0; j < kernels_channels_number; j++)
1066 for(Index k = 0; k < kernels_rows_number; k++)
1068 for(Index l = 0; l < kernels_columns_number; l++)
1077 for(
int i = 0; i <
biases.size(); i++)
1079 parameters(i) =
biases(i);
1104 const Index inputs_dimensions_number = new_inputs_dimensions.size();
1106 if(inputs_dimensions_number != 4)
1108 ostringstream buffer;
1109 buffer <<
"OpenNN Exception: ConvolutionalLayer class.\n"
1110 <<
"ConvolutionalLayer(const Tensor<Index, 1>&) constructor.\n"
1111 <<
"Number of inputs dimensions (" << inputs_dimensions_number <<
") must be 4 (number of images, channels, rows, columns).\n";
1113 throw logic_error(buffer.str());
1120 const Index kernels_dimensions_number = new_kernels_dimensions.size();
1122 if(kernels_dimensions_number != 4)
1124 ostringstream buffer;
1126 buffer <<
"OpenNN Exception: ConvolutionalLayer class.\n"
1127 <<
"void set(const Tensor<Index, 1>&) method.\n"
1128 <<
"Number of kernels dimensions (" << kernels_dimensions_number <<
") must be 4 (number of images, kernels, rows, columns).\n";
1130 throw logic_error(buffer.str());
1135 const Index kernels_number = new_kernels_dimensions[0];
1136 const Index kernels_channels_number = new_inputs_dimensions[1];
1137 const Index kernels_rows_number = new_kernels_dimensions[2];
1138 const Index kernels_columns_number = new_kernels_dimensions[3];
1140 biases.resize(kernels_number);
1143 synaptic_weights.resize(kernels_number, kernels_channels_number, kernels_rows_number, kernels_columns_number);
1146 input_variables_dimensions = new_inputs_dimensions;
1156void ConvolutionalLayer::set(
const Tensor<type, 4>& new_inputs,
const Tensor<type, 4>& new_kernels,
const Tensor<type, 1>& new_biases)
1160 if(new_kernels.dimension(3) != new_biases.size())
1162 ostringstream buffer;
1164 buffer <<
"OpenNN Exception: ConvolutionalLayer class.\n"
1165 <<
"void set(const Tensor<type, 4>& , const Tensor<type, 4>& , const Tensor<type, 1>& ) method.\n"
1166 <<
"Biases size must be equal to number of kernels.\n";
1168 throw logic_error(buffer.str());
1175 Tensor<Index, 1> new_inputs_dimensions(4);
1176 new_inputs_dimensions(0) = new_inputs.dimension(0);
1177 new_inputs_dimensions(1) = new_inputs.dimension(1);
1178 new_inputs_dimensions(2) = new_inputs.dimension(2);
1179 new_inputs_dimensions(3) = new_inputs.dimension(3);
1185 input_variables_dimensions = new_inputs_dimensions;
1194 biases.setConstant(value);
1220void ConvolutionalLayer::set_parameters_random()
1233 activation_function = new_activation_function;
1260 convolution_type = new_convolution_type;
1269 if(new_stride_row <= 0)
1271 throw (
"EXCEPTION: new_stride_row must be a positive number");
1274 row_stride = new_stride_row;
1283 if(new_stride_column <= 0)
1285 throw (
"EXCEPTION: new_stride_column must be a positive number");
1288 column_stride = new_stride_column;
1302 synaptic_weights.resize(kernels_number, kernels_channels_number, kernels_rows_number, kernels_columns_number);
1303 biases.resize(kernels_number);
1306 new_parameters.data(),
1307 static_cast<size_t>(kernels_number)*
sizeof(type));
1309 Index element_index = kernels_number;
1312 for(Index i = 0; i < kernels_number; i++)
1314 for(Index j = 0; j < kernels_channels_number; j++)
1316 for(Index k = 0; k < kernels_rows_number; k++)
1318 for(Index l = 0; l < kernels_columns_number; l++)
1357 return input_variables_dimensions[1];
1365 return input_variables_dimensions[2];
1373 return input_variables_dimensions[3];
1377void ConvolutionalLayer::to_2d(
const Tensor<type, 4>& input_4d, Tensor<type, 2>& output_2d)
const
1379 Eigen::array<Index, 2> dimensions =
1380 {Eigen::array<Index, 2>({input_4d.dimension(0), input_4d.dimension(1) * input_4d.dimension(2) * input_4d.dimension(3)})};
1382 output_2d = input_4d.reshape(dimensions);
Tensor< Index, 1 > get_input_variables_dimensions() const
Returns the dimension of the input variables.
void set_parameters_constant(const type &)
Index get_synaptic_weights_number() const
Returns the number of layer's synaptic weights.
Index get_column_stride() const
Returns the column stride.
Index get_inputs_number() const
Returns the number of inputs.
Index get_kernels_number() const
Returns the number of kernels of the layer.
Index get_outputs_rows_number() const
Returns the number of rows the result of applying the layer's kernels to an image will have.
void set_biases_constant(const type &)
Tensor< type, 4 > synaptic_weights
This tensor containing conection strengths from a layer's inputs to its neurons.
Index get_inputs_channels_number() const
Returns the number of channels of the input.
Index get_kernels_channels_number() const
Returns the number of channels of the layer's kernels.
ActivationFunction
Enumeration of available activation functions for the convolutional layer.
bool is_empty() const
Returns a boolean, true if convolutional layer is empty and false otherwise.
void set_synaptic_weights(const Tensor< type, 4 > &)
Index get_inputs_rows_number() const
Returns the number of rows of the input.
void set_activation_function(const ActivationFunction &)
Index get_inputs_columns_number() const
Returns the number of columns of the input.
void set_row_stride(const Index &)
void set(const Tensor< Index, 1 > &, const Tensor< Index, 1 > &)
void insert_padding(const Tensor< type, 4 > &, Tensor< type, 4 > &)
const Tensor< type, 1 > & get_biases() const
Returns the layer's biases.
Index get_outputs_columns_number() const
Returns the number of columns the result of applying the layer's kernels to an image will have.
void set_column_stride(const Index &)
Index get_padding_width() const
Returns the total number of columns of zeroes to be added to an image before applying a kernel,...
Index get_neurons_number() const
Returns the number of neurons.
ConvolutionType get_convolution_type() const
Returns the padding option.
void set_biases(const Tensor< type, 1 > &)
Index get_kernels_rows_number() const
Returns the number of rows of the layer's kernels.
Tensor< Index, 1 > get_outputs_dimensions() const
Returns a vector containing the number of channels, rows and columns of the result of applying the la...
void calculate_activations(const Tensor< type, 4 > &, Tensor< type, 4 > &) const
Calculates activations.
ActivationFunction get_activation_function() const
Returns the convolutional layer's activation function.
Index get_row_stride() const
Returns the row stride.
void set_synaptic_weights_constant(const type &)
Index get_padding_height() const
Returns the total number of rows of zeroes to be added to an image before applying a kernel,...
const Tensor< type, 4 > & get_synaptic_weights() const
Returns the layer's synaptic weights.
Index get_kernels_columns_number() const
Returns the number of columns of the layer's kernels.
void set_convolution_type(const ConvolutionType &)
void calculate_convolutions(const Tensor< type, 4 > &, Tensor< type, 4 > &) const
Calculate convolutions.
Index get_parameters_number() const
Returns the number of parameters of the layer.
void calculate_hidden_delta_perceptron(const PerceptronLayer *, const Tensor< type, 4 > &, const Tensor< type, 2 > &, const Tensor< type, 2 > &, Tensor< type, 2 > &) const
void calculate_outputs(const Tensor< type, 4 > &, Tensor< type, 4 > &)
void set_parameters(const Tensor< type, 1 > &, const Index &index)
Tensor< type, 1 > get_parameters() const
Returns the layer's parameters in the form of a vector.
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.
This class represents a layer of perceptrons.
const Tensor< type, 2 > & get_synaptic_weights() const
This class represents a layer of probabilistic neurons.
const Tensor< type, 2 > & get_synaptic_weights() const
Returns the synaptic weights of the layer.