From 27c08abe6947b1ee5b266799f2bb2bf0a05d0def Mon Sep 17 00:00:00 2001 From: Alex Gilday Date: Thu, 22 Feb 2018 11:36:16 +0000 Subject: COMPMID-754: Add validation to LocallyConnected and NEDeconv layers Change-Id: Ifed8713f4d7f1315af684b30d11323db2b533f10 Reviewed-on: https://eu-gerrit-1.euhpc.arm.com/121783 Reviewed-by: Anthony Barbier Tested-by: Jenkins Reviewed-by: Michalis Spyrou --- .../CL/functions/CLLocallyConnectedLayer.cpp | 132 ++++++++++++++------- 1 file changed, 88 insertions(+), 44 deletions(-) (limited to 'src/runtime/CL/functions/CLLocallyConnectedLayer.cpp') diff --git a/src/runtime/CL/functions/CLLocallyConnectedLayer.cpp b/src/runtime/CL/functions/CLLocallyConnectedLayer.cpp index d284949323..a3eb5010bd 100644 --- a/src/runtime/CL/functions/CLLocallyConnectedLayer.cpp +++ b/src/runtime/CL/functions/CLLocallyConnectedLayer.cpp @@ -33,40 +33,102 @@ using namespace arm_compute; +namespace +{ +void calculate_shapes(const ITensorInfo *input, const ITensorInfo *weights, const ITensorInfo *biases, const ITensorInfo *output, const PadStrideInfo &conv_info, + TensorShape &shape_wr, TensorShape &shape_im2col, TensorShape &shape_gemm) +{ + ARM_COMPUTE_UNUSED(output); + + const unsigned int kernel_width = weights->dimension(0); + const unsigned int kernel_height = weights->dimension(1); + + bool has_bias = (biases != nullptr); + + // Get convolved dimensions + unsigned int conv_w = 0; + unsigned int conv_h = 0; + std::tie(conv_w, conv_h) = scaled_dimensions(input->dimension(0), input->dimension(1), kernel_width, kernel_height, + conv_info); + + const size_t mat_weights_cols = weights->dimension(3); + const size_t mat_weights_rows = weights->dimension(0) * weights->dimension(1) * weights->dimension(2) + ((has_bias) ? 1 : 0); + const size_t mat_weights_num = weights->dimension(4); + + shape_wr = TensorShape(mat_weights_cols, mat_weights_rows, mat_weights_num); + + const size_t mat_input_cols = mat_weights_rows; + const size_t mat_input_rows = conv_w * conv_h; + + shape_im2col = input->tensor_shape(); + shape_im2col.set(0, mat_input_cols); + shape_im2col.set(1, mat_input_rows); + shape_im2col.set(2, 1); + + shape_gemm = shape_im2col; + shape_gemm.set(0, mat_weights_cols); + shape_gemm.set(1, mat_input_rows); +} +} // namespace + CLLocallyConnectedLayer::CLLocallyConnectedLayer(std::shared_ptr memory_manager) : _memory_group(std::move(memory_manager)), _input_im2col_kernel(), _weights_reshape_kernel(), _mm_kernel(), _output_col2im_kernel(), _input_im2col_reshaped(), _weights_reshaped(), _gemm_output(), _is_first_run(false) { } -void CLLocallyConnectedLayer::configure(const ICLTensor *input, const ICLTensor *weights, const ICLTensor *biases, ICLTensor *output, const PadStrideInfo &conv_info) +Status CLLocallyConnectedLayer::validate(const ITensorInfo *input, const ITensorInfo *weights, const ITensorInfo *biases, const ITensorInfo *output, const PadStrideInfo &conv_info) { - ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::F32); - ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(weights, 1, DataType::F32); - ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(output, 1, DataType::F32); - ARM_COMPUTE_ERROR_ON_MISMATCHING_DATA_TYPES(input, weights, output); - ARM_COMPUTE_ERROR_ON(weights->info()->dimension(2) != input->info()->dimension(2)); - ARM_COMPUTE_ERROR_ON(!conv_info.padding_is_symmetric()); - - if(biases != nullptr) + ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(input, weights, output); + ARM_COMPUTE_RETURN_ERROR_ON(weights->dimension(2) != input->dimension(2)); + ARM_COMPUTE_RETURN_ERROR_ON(!conv_info.padding_is_symmetric()); + + bool has_bias = (biases != nullptr); + + if(has_bias) { - ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(biases, 1, DataType::F32); - ARM_COMPUTE_ERROR_ON_MISMATCHING_DATA_TYPES(input, biases); - ARM_COMPUTE_ERROR_ON(biases->info()->dimension(0) != weights->info()->dimension(3)); - ARM_COMPUTE_ERROR_ON(biases->info()->num_dimensions() > 2); + ARM_COMPUTE_RETURN_ERROR_ON(biases->dimension(0) != weights->dimension(3)); + ARM_COMPUTE_RETURN_ERROR_ON(biases->num_dimensions() > 2); } + const unsigned int kernel_width = weights->dimension(0); + const unsigned int kernel_height = weights->dimension(1); + + // Get convolved dimensions + unsigned int conv_w = 0; + unsigned int conv_h = 0; + std::tie(conv_w, conv_h) = scaled_dimensions(input->dimension(0), input->dimension(1), kernel_width, kernel_height, + conv_info); + + ARM_COMPUTE_RETURN_ERROR_ON_MSG((output->dimension(0) != conv_w) || (output->dimension(1) != conv_h), "Output shape does not match the expected one"); + ARM_COMPUTE_RETURN_ERROR_ON_MSG(weights->dimension(4) != (conv_w * conv_h), "Weights shape does not match the expected one"); + + // Calculate intermediate buffer shapes + TensorShape shape_wr; + TensorShape shape_im2col; + TensorShape shape_gemm; + calculate_shapes(input, weights, biases, output, conv_info, shape_wr, shape_im2col, shape_gemm); + + TensorInfo weights_reshaped_info(shape_wr, 1, weights->data_type()); + TensorInfo input_im2col_reshaped_info(shape_im2col, 1, input->data_type()); + TensorInfo gemm_output_info(shape_gemm, 1, input->data_type()); + + ARM_COMPUTE_RETURN_ON_ERROR(CLIm2ColKernel::validate(input, &input_im2col_reshaped_info, Size2D(kernel_width, kernel_height), conv_info, has_bias)); + ARM_COMPUTE_RETURN_ON_ERROR(CLWeightsReshapeKernel::validate(weights, biases, &weights_reshaped_info)); + ARM_COMPUTE_RETURN_ON_ERROR(CLLocallyConnectedMatrixMultiplyKernel::validate(&input_im2col_reshaped_info, &weights_reshaped_info, &gemm_output_info)); + ARM_COMPUTE_RETURN_ON_ERROR(CLCol2ImKernel::validate(&gemm_output_info, output, std::make_pair(conv_w, conv_h))); + + return Status{}; +} + +void CLLocallyConnectedLayer::configure(const ICLTensor *input, const ICLTensor *weights, const ICLTensor *biases, ICLTensor *output, const PadStrideInfo &conv_info) +{ + ARM_COMPUTE_ERROR_ON_NULLPTR(input, weights, output); + ARM_COMPUTE_ERROR_THROW_ON(CLLocallyConnectedLayer::validate(input->info(), weights->info(), biases == nullptr ? nullptr : biases->info(), output->info(), conv_info)); + bool _has_bias = (biases != nullptr); _is_first_run = true; - // Get parameters for conv_info - unsigned int stride_x = 0; - unsigned int stride_y = 0; - unsigned int pad_x = 0; - unsigned int pad_y = 0; - std::tie(stride_x, stride_y) = conv_info.stride(); - std::tie(pad_x, pad_y) = conv_info.pad(); - const unsigned int kernel_width = weights->info()->dimension(0); const unsigned int kernel_height = weights->info()->dimension(1); @@ -76,32 +138,14 @@ void CLLocallyConnectedLayer::configure(const ICLTensor *input, const ICLTensor std::tie(conv_w, conv_h) = scaled_dimensions(input->info()->dimension(0), input->info()->dimension(1), kernel_width, kernel_height, conv_info); - ARM_COMPUTE_ERROR_ON_MSG((output->info()->dimension(0) != conv_w) || (output->info()->dimension(1) != conv_h), "Output shape does not match the expected one"); - ARM_COMPUTE_ERROR_ON_MSG(weights->info()->dimension(4) != (conv_w * conv_h), "Weights shape does not match the expected one"); - - // Create tensor to store the reshaped weights - const size_t mat_weights_cols = weights->info()->dimension(3); - const size_t mat_weights_rows = weights->info()->dimension(0) * weights->info()->dimension(1) * weights->info()->dimension(2) + ((_has_bias) ? 1 : 0); - const size_t mat_weights_num = weights->info()->dimension(4); - - const TensorShape shape_wr(mat_weights_cols, mat_weights_rows, mat_weights_num); + // Calculate intermediate buffer shapes + TensorShape shape_wr; + TensorShape shape_im2col; + TensorShape shape_gemm; + calculate_shapes(input->info(), weights->info(), biases == nullptr ? nullptr : biases->info(), output->info(), conv_info, shape_wr, shape_im2col, shape_gemm); _weights_reshaped.allocator()->init(TensorInfo(shape_wr, 1, weights->info()->data_type())); - - // Create tensor to store im2col reshaped inputs - const size_t mat_input_cols = mat_weights_rows; - const size_t mat_input_rows = conv_w * conv_h; - TensorShape shape_im2col = input->info()->tensor_shape(); - shape_im2col.set(0, mat_input_cols); - shape_im2col.set(1, mat_input_rows); - shape_im2col.set(2, 1); - _input_im2col_reshaped.allocator()->init(TensorInfo(shape_im2col, 1, input->info()->data_type())); - - // Create locally connected layer output tensor - TensorShape shape_gemm = _input_im2col_reshaped.info()->tensor_shape(); - shape_gemm.set(0, mat_weights_cols); - shape_gemm.set(1, mat_input_rows); _gemm_output.allocator()->init(TensorInfo(shape_gemm, 1, input->info()->data_type())); // Manage intermediate buffers -- cgit v1.2.1