diff options
author | Alex Gilday <alexander.gilday@arm.com> | 2018-02-22 11:36:16 +0000 |
---|---|---|
committer | Anthony Barbier <anthony.barbier@arm.com> | 2018-11-02 16:49:16 +0000 |
commit | 27c08abe6947b1ee5b266799f2bb2bf0a05d0def (patch) | |
tree | 32dfb3a6d6b199d5138e25b103023f07d88bce29 /src/runtime/NEON/functions/NELocallyConnectedLayer.cpp | |
parent | 9e9cbafa9e6cc6b543c89a96d52fc9c5fde04ceb (diff) | |
download | ComputeLibrary-27c08abe6947b1ee5b266799f2bb2bf0a05d0def.tar.gz |
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 <anthony.barbier@arm.com>
Tested-by: Jenkins <bsgcomp@arm.com>
Reviewed-by: Michalis Spyrou <michalis.spyrou@arm.com>
Diffstat (limited to 'src/runtime/NEON/functions/NELocallyConnectedLayer.cpp')
-rw-r--r-- | src/runtime/NEON/functions/NELocallyConnectedLayer.cpp | 132 |
1 files changed, 88 insertions, 44 deletions
diff --git a/src/runtime/NEON/functions/NELocallyConnectedLayer.cpp b/src/runtime/NEON/functions/NELocallyConnectedLayer.cpp index 45ddb70ff5..973559441f 100644 --- a/src/runtime/NEON/functions/NELocallyConnectedLayer.cpp +++ b/src/runtime/NEON/functions/NELocallyConnectedLayer.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 + NELocallyConnectedLayer::NELocallyConnectedLayer(std::shared_ptr<IMemoryManager> 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 NELocallyConnectedLayer::configure(const ITensor *input, const ITensor *weights, const ITensor *biases, ITensor *output, const PadStrideInfo &conv_info) +Status NELocallyConnectedLayer::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(NEIm2ColKernel::validate(input, &input_im2col_reshaped_info, Size2D(kernel_width, kernel_height), conv_info, has_bias, false)); + ARM_COMPUTE_RETURN_ON_ERROR(NEWeightsReshapeKernel::validate(weights, biases, &weights_reshaped_info)); + ARM_COMPUTE_RETURN_ON_ERROR(NELocallyConnectedMatrixMultiplyKernel::validate(&input_im2col_reshaped_info, &weights_reshaped_info, &gemm_output_info)); + ARM_COMPUTE_RETURN_ON_ERROR(NECol2ImKernel::validate(&gemm_output_info, output, Size2D(conv_w, conv_h))); + + return Status{}; +} + +void NELocallyConnectedLayer::configure(const ITensor *input, const ITensor *weights, const ITensor *biases, ITensor *output, const PadStrideInfo &conv_info) +{ + ARM_COMPUTE_ERROR_ON_NULLPTR(input, weights, output); + ARM_COMPUTE_ERROR_THROW_ON(NELocallyConnectedLayer::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 NELocallyConnectedLayer::configure(const ITensor *input, const ITensor *wei 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 |