aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorGeorgios Pinitas <georgios.pinitas@arm.com>2017-06-19 16:11:53 +0100
committerAnthony Barbier <anthony.barbier@arm.com>2018-09-17 14:14:20 +0100
commitce093143ec7b554edefc533c90e45c80946cde51 (patch)
tree1e4aa13ba3fe10c93ca42e2f5477bd2c4888324e /tests
parent4c2938ed50a78753bfbdbb2f3cbf43f5fed779f9 (diff)
downloadComputeLibrary-ce093143ec7b554edefc533c90e45c80946cde51.tar.gz
COMPMID-403:Add support for 7x7 pooling on CL.
Change-Id: I3c2c8d7e8e61d7737170cb1568900ce4ac337068 Reviewed-on: http://mpd-gerrit.cambridge.arm.com/78181 Reviewed-by: Michele DiGiorgio <michele.digiorgio@arm.com> Tested-by: Kaizen <jeremy.johnson+kaizengerrit@arm.com> Reviewed-by: Moritz Pflanzer <moritz.pflanzer@arm.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/Utils.h40
-rw-r--r--tests/dataset/PoolingTypesDataset.h55
-rw-r--r--tests/dataset/ShapeDatasets.h2
-rw-r--r--tests/dataset/ThresholdDataset.h4
-rw-r--r--tests/validation/CL/PoolingLayer.cpp119
-rw-r--r--tests/validation/Datasets.h7
-rw-r--r--tests/validation/NEON/PoolingLayer.cpp (renamed from tests/validation/NEON/Pooling/PoolingLayer.cpp)2
-rw-r--r--tests/validation/TensorOperations.h84
8 files changed, 267 insertions, 46 deletions
diff --git a/tests/Utils.h b/tests/Utils.h
index 53f749df48..f3622cafaa 100644
--- a/tests/Utils.h
+++ b/tests/Utils.h
@@ -615,13 +615,47 @@ inline int coord2index(const TensorShape &shape, const Coordinates &coord)
return index;
}
+/** Check if Coordinates dimensionality can match the respective shape one.
+ *
+ * @param coords Coordinates
+ * @param shape Shape to match dimensionality
+ *
+ * @return True if Coordinates can match the dimensionality of the shape else false.
+ */
+inline bool match_shape(Coordinates &coords, const TensorShape &shape)
+{
+ auto check_nz = [](unsigned int i)
+ {
+ return i != 0;
+ };
+
+ unsigned int coords_dims = coords.num_dimensions();
+ unsigned int shape_dims = shape.num_dimensions();
+
+ // Increase coordinates scenario
+ if(coords_dims < shape_dims)
+ {
+ coords.set_num_dimensions(shape_dims);
+ return true;
+ }
+ // Decrease coordinates scenario
+ if(coords_dims > shape_dims && !std::any_of(coords.begin() + shape_dims, coords.end(), check_nz))
+ {
+ coords.set_num_dimensions(shape_dims);
+ return true;
+ }
+
+ return (coords_dims == shape_dims);
+}
+
/** Check if a coordinate is within a valid region */
inline bool is_in_valid_region(const ValidRegion &valid_region, const Coordinates &coord)
{
- ARM_COMPUTE_ERROR_ON_MSG(valid_region.shape.num_dimensions() != coord.num_dimensions(), "Shapes of valid region and coordinates do not agree");
- for(int d = 0; static_cast<size_t>(d) < coord.num_dimensions(); ++d)
+ Coordinates coords(coord);
+ ARM_COMPUTE_ERROR_ON_MSG(!match_shape(coords, valid_region.shape), "Shapes of valid region and coordinates do not agree");
+ for(int d = 0; static_cast<size_t>(d) < coords.num_dimensions(); ++d)
{
- if(coord[d] < valid_region.start(d) || coord[d] >= valid_region.end(d))
+ if(coords[d] < valid_region.start(d) || coords[d] >= valid_region.end(d))
{
return false;
}
diff --git a/tests/dataset/PoolingTypesDataset.h b/tests/dataset/PoolingTypesDataset.h
new file mode 100644
index 0000000000..c78a20b809
--- /dev/null
+++ b/tests/dataset/PoolingTypesDataset.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017 ARM Limited.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef __ARM_COMPUTE_TEST_DATASET_POOLING_TYPE_DATASET_H__
+#define __ARM_COMPUTE_TEST_DATASET_POOLING_TYPE_DATASET_H__
+
+#include "arm_compute/core/Types.h"
+#include "dataset/GenericDataset.h"
+
+#ifdef BOOST
+#include "boost_wrapper.h"
+#endif
+
+namespace arm_compute
+{
+namespace test
+{
+/** Data set containing all possible pooling types.
+ *
+ * Can be used as input for Boost data test cases to automatically run a test
+ * case on all pooling types.
+ */
+class PoolingTypes final : public GenericDataset<PoolingType, 2>
+{
+public:
+ PoolingTypes()
+ : GenericDataset{ PoolingType::MAX, PoolingType::AVG }
+ {
+ }
+
+ ~PoolingTypes() = default;
+};
+} // namespace test
+} // namespace arm_compute
+#endif //__ARM_COMPUTE_TEST_DATASET_POOLING_TYPE_DATASET_H__
diff --git a/tests/dataset/ShapeDatasets.h b/tests/dataset/ShapeDatasets.h
index d2b82cae40..ecb478dbf0 100644
--- a/tests/dataset/ShapeDatasets.h
+++ b/tests/dataset/ShapeDatasets.h
@@ -118,7 +118,7 @@ class SmallShapes final : public ShapeDataset<3>
{
public:
SmallShapes()
- : ShapeDataset(TensorShape(5U, 5U),
+ : ShapeDataset(TensorShape(7U, 7U),
TensorShape(27U, 13U, 2U),
TensorShape(128U, 64U, 1U, 3U))
{
diff --git a/tests/dataset/ThresholdDataset.h b/tests/dataset/ThresholdDataset.h
index 956cf3d54d..a2d76e3c48 100644
--- a/tests/dataset/ThresholdDataset.h
+++ b/tests/dataset/ThresholdDataset.h
@@ -58,8 +58,8 @@ public:
std::stringstream ss;
ss << "Threshold";
ss << "_threshold_value" << threshold;
- ss << "_false_value" << false_value;
- ss << "_true_value" << true_value;
+ ss << "_false_value" << std::boolalpha << false_value;
+ ss << "_true_value" << std::boolalpha << true_value;
ss << "_type";
ss << ((type == ThresholdType::BINARY) ? "binary" : "range");
ss << "_upper" << upper;
diff --git a/tests/validation/CL/PoolingLayer.cpp b/tests/validation/CL/PoolingLayer.cpp
new file mode 100644
index 0000000000..1d0e745088
--- /dev/null
+++ b/tests/validation/CL/PoolingLayer.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2017 ARM Limited.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "CL/CLAccessor.h"
+#include "CL/Helper.h"
+#include "TypePrinter.h"
+#include "arm_compute/runtime/CL/functions/CLPoolingLayer.h"
+#include "tests/dataset/PoolingLayerDataset.h"
+#include "validation/Datasets.h"
+#include "validation/Reference.h"
+#include "validation/Validation.h"
+
+#include <random>
+
+using namespace arm_compute;
+using namespace arm_compute::test;
+using namespace arm_compute::test::cl;
+using namespace arm_compute::test::validation;
+
+namespace
+{
+const float tolerance_f = 1e-05; /**< Tolerance value for comparing reference's output against implementation's output for float input */
+
+/** Compute CL pooling layer function.
+ *
+ * @param[in] shape Shape of the input and output tensors.
+ * @param[in] dt Data type of input and output tensors.
+ * @param[in] pool_info Pooling Layer information.
+ *
+ * @return Computed output tensor.
+ */
+CLTensor compute_pooling_layer(const TensorShape &shape_in, const TensorShape &shape_out, DataType dt, PoolingLayerInfo pool_info)
+{
+ // Create tensors
+ CLTensor src = create_tensor(shape_in, dt);
+ CLTensor dst = create_tensor(shape_out, dt);
+
+ // Create and configure function
+ CLPoolingLayer pool;
+ pool.configure(&src, &dst, pool_info);
+
+ // Allocate tensors
+ src.allocator()->allocate();
+ dst.allocator()->allocate();
+
+ BOOST_TEST(!src.info()->is_resizable());
+ BOOST_TEST(!dst.info()->is_resizable());
+
+ // Fill tensors
+ std::uniform_real_distribution<> distribution(-1, 1);
+ library->fill(CLAccessor(src), distribution, 0);
+
+ // Compute function
+ pool.run();
+
+ return dst;
+}
+
+TensorShape get_output_shape(TensorShape in_shape, const PoolingLayerInfo &pool_info)
+{
+ TensorShape out_shape(in_shape);
+ const std::pair<unsigned int, unsigned int> scaled_dims = arm_compute::scaled_dimensions(in_shape.x(),
+ in_shape.y(),
+ pool_info.pool_size(),
+ pool_info.pad_stride_info().stride().first, pool_info.pad_stride_info().stride().second,
+ pool_info.pad_stride_info().pad().first, pool_info.pad_stride_info().pad().second,
+ pool_info.pad_stride_info().round());
+ out_shape.set(0, scaled_dims.first);
+ out_shape.set(1, scaled_dims.second);
+ return out_shape;
+}
+} // namespace
+
+#ifndef DOXYGEN_SKIP_THIS
+BOOST_AUTO_TEST_SUITE(CL)
+BOOST_AUTO_TEST_SUITE(PoolingLayer)
+
+BOOST_AUTO_TEST_SUITE(Float)
+BOOST_TEST_DECORATOR(*boost::unit_test::label("precommit"))
+BOOST_DATA_TEST_CASE(RunSmall, SmallShapes() * CNNFloatDataTypes() * PoolingTypes() * boost::unit_test::data::make({ 2, 3, 7 }) * boost::unit_test::data::make({ 1, 2 }) * boost::unit_test::data::make({ 0, 1 }),
+ src_shape, dt, pool_type, pool_size, pool_stride, pool_pad)
+{
+ PoolingLayerInfo pool_info(pool_type, pool_size, PadStrideInfo(pool_stride, pool_stride, pool_pad, pool_pad, DimensionRoundingType::CEIL));
+ TensorShape dst_shape = get_output_shape(src_shape, pool_info);
+
+ // Compute function
+ CLTensor dst = compute_pooling_layer(src_shape, dst_shape, dt, pool_info);
+
+ // Compute reference
+ RawTensor ref_dst = Reference::compute_reference_pooling_layer(src_shape, dst_shape, dt, pool_info);
+
+ // Validate output
+ validate(CLAccessor(dst), ref_dst, tolerance_f);
+}
+BOOST_AUTO_TEST_SUITE_END()
+
+BOOST_AUTO_TEST_SUITE_END()
+BOOST_AUTO_TEST_SUITE_END()
+#endif
diff --git a/tests/validation/Datasets.h b/tests/validation/Datasets.h
index ab21787f45..33776d2e44 100644
--- a/tests/validation/Datasets.h
+++ b/tests/validation/Datasets.h
@@ -36,6 +36,7 @@
#include "dataset/InterpolationPolicyDataset.h"
#include "dataset/NormalizationTypeDataset.h"
#include "dataset/PoolingLayerDataset.h"
+#include "dataset/PoolingTypesDataset.h"
#include "dataset/RoundingPolicyDataset.h"
#include "dataset/ShapeDatasets.h"
#include "dataset/ThresholdDataset.h"
@@ -186,6 +187,12 @@ struct is_dataset<arm_compute::test::RoundingPolicies> : boost::mpl::true_
/// Register the data set with Boost
template <>
+struct is_dataset<arm_compute::test::PoolingTypes> : boost::mpl::true_
+{
+};
+
+/// Register the data set with Boost
+template <>
struct is_dataset<arm_compute::test::AlexNetConvolutionLayerDataset> : boost::mpl::true_
{
};
diff --git a/tests/validation/NEON/Pooling/PoolingLayer.cpp b/tests/validation/NEON/PoolingLayer.cpp
index b15ad1c5e6..10b9a5250e 100644
--- a/tests/validation/NEON/Pooling/PoolingLayer.cpp
+++ b/tests/validation/NEON/PoolingLayer.cpp
@@ -96,7 +96,6 @@ Tensor compute_pooling_layer(const TensorShape &shape_in, const TensorShape &sha
#ifndef DOXYGEN_SKIP_THIS
BOOST_AUTO_TEST_SUITE(NEON)
-BOOST_AUTO_TEST_SUITE(Pooling)
BOOST_AUTO_TEST_SUITE(PoolingLayer)
BOOST_AUTO_TEST_SUITE(Float)
@@ -135,5 +134,4 @@ BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE_END()
-BOOST_AUTO_TEST_SUITE_END()
#endif
diff --git a/tests/validation/TensorOperations.h b/tests/validation/TensorOperations.h
index 119be02423..7337924b47 100644
--- a/tests/validation/TensorOperations.h
+++ b/tests/validation/TensorOperations.h
@@ -1154,47 +1154,57 @@ void pooling_layer(const Tensor<T> &in, Tensor<T> &out, PoolingLayerInfo pool_in
std::tie(pool_stride_x, pool_stride_y) = pool_info.pad_stride_info().stride();
std::tie(pad_x, pad_y) = pool_info.pad_stride_info().pad();
- const int cols_in = static_cast<int>(in.shape()[0]);
- const int rows_in = static_cast<int>(in.shape()[1]);
+ const int w_in = static_cast<int>(in.shape()[0]);
+ const int h_in = static_cast<int>(in.shape()[1]);
- const int cols_out = static_cast<int>(out.shape()[0]);
- const int rows_out = static_cast<int>(out.shape()[1]);
+ const int w_out = static_cast<int>(out.shape()[0]);
+ const int h_out = static_cast<int>(out.shape()[1]);
- int upper_dims = in.shape().total_size() / (cols_in * rows_in);
+ int upper_dims = in.shape().total_size() / (w_in * h_in);
- int pooled_height = static_cast<int>(ceil(static_cast<float>(rows_in + 2 * pad_x - pool_size) / pool_stride_x)) + 1;
- int pooled_width = static_cast<int>(ceil(static_cast<float>(cols_in + 2 * pad_y - pool_size) / pool_stride_y)) + 1;
+ int pooled_w = 0;
+ int pooled_h = 0;
+ if(pool_info.pad_stride_info().round() == DimensionRoundingType::CEIL)
+ {
+ pooled_w = static_cast<int>(ceil(static_cast<float>(w_in + 2 * pad_x - pool_size) / pool_stride_x)) + 1;
+ pooled_h = static_cast<int>(ceil(static_cast<float>(h_in + 2 * pad_y - pool_size) / pool_stride_y)) + 1;
+ }
+ else
+ {
+ pooled_w = static_cast<int>(floor(static_cast<float>(w_in + 2 * pad_x - pool_size) / pool_stride_x)) + 1;
+ pooled_h = static_cast<int>(floor(static_cast<float>(h_in + 2 * pad_y - pool_size) / pool_stride_y)) + 1;
+ }
- if((pooled_height - 1) * pool_stride_x >= rows_in + pad_x)
+ if((pooled_w - 1) * pool_stride_x >= w_in + pad_x)
{
- --pooled_height;
+ --pooled_w;
}
- if((pooled_width - 1) * pool_stride_y >= cols_in + pad_y)
+ if((pooled_h - 1) * pool_stride_y >= h_in + pad_y)
{
- --pooled_width;
+ --pooled_h;
}
if(type == PoolingType::MAX)
{
for(int r = 0; r < upper_dims; ++r)
{
- for(int i = 0; i < pooled_height; ++i)
+ for(int h = 0; h < pooled_h; ++h)
{
- for(int k = 0; k < pooled_width; ++k)
+ for(int w = 0; w < pooled_w; ++w)
{
- int hstart = i * pool_stride_x - pad_x;
- int wstart = k * pool_stride_y - pad_y;
- int hend = std::min(hstart + pool_size, rows_in);
- int wend = std::min(wstart + pool_size, cols_in);
- hstart = std::max(hstart, 0);
+ int wstart = w * pool_stride_x - pad_x;
+ int hstart = h * pool_stride_y - pad_y;
+ int wend = std::min(wstart + pool_size, w_in);
+ int hend = std::min(hstart + pool_size, h_in);
wstart = std::max(wstart, 0);
+ hstart = std::max(hstart, 0);
T max_val = std::numeric_limits<T>::lowest();
for(int y = hstart; y < hend; ++y)
{
for(int x = wstart; x < wend; ++x)
{
- T val = in[r * cols_in * rows_in + y * cols_in + x];
+ T val = in[r * h_in * w_in + y * w_in + x];
if(val > max_val)
{
max_val = val;
@@ -1202,7 +1212,7 @@ void pooling_layer(const Tensor<T> &in, Tensor<T> &out, PoolingLayerInfo pool_in
}
}
- out[r * rows_out * cols_out + i * pooled_width + k] = max_val;
+ out[r * h_out * w_out + h * pooled_w + w] = max_val;
}
}
}
@@ -1211,32 +1221,30 @@ void pooling_layer(const Tensor<T> &in, Tensor<T> &out, PoolingLayerInfo pool_in
{
for(int r = 0; r < upper_dims; ++r)
{
- for(int i = 0; i < pooled_height; ++i)
+ for(int h = 0; h < pooled_h; ++h)
{
- for(int k = 0; k < pooled_width; ++k)
+ for(int w = 0; w < pooled_w; ++w)
{
- T avg_val = 0;
-
- int hstart = i * pool_stride_x - pad_x;
- int wstart = k * pool_stride_y - pad_y;
- int hend = std::min(hstart + pool_size, cols_in + pad_x);
- int wend = std::min(wstart + pool_size, rows_in + pad_y);
- int pool = (hend - hstart) * (wend - wstart);
- hstart = std::max(hstart, 0);
- wstart = std::max(wstart, 0);
- hend = std::min(hend, rows_in);
- wend = std::min(wend, cols_in);
-
+ T avg_val = 0;
+ int wstart = w * pool_stride_x - pad_x;
+ int hstart = h * pool_stride_y - pad_y;
+ int wend = std::min(wstart + pool_size, w_in + pad_x);
+ int hend = std::min(hstart + pool_size, h_in + pad_y);
+ int pool = (hend - hstart) * (wend - wstart);
+ wstart = std::max(wstart, 0);
+ hstart = std::max(hstart, 0);
+ wend = std::min(wend, w_in);
+ hend = std::min(hend, h_in);
if(std::is_floating_point<T>::value)
{
for(int y = hstart; y < hend; ++y)
{
for(int x = wstart; x < wend; ++x)
{
- avg_val += in[r * cols_in * rows_in + y * cols_in + x];
+ avg_val += in[r * h_in * w_in + y * w_in + x];
}
}
- out[r * rows_out * cols_out + i * pooled_width + k] = avg_val / pool;
+ out[r * h_out * w_out + h * pooled_w + w] = avg_val / pool;
}
else
{
@@ -1247,10 +1255,10 @@ void pooling_layer(const Tensor<T> &in, Tensor<T> &out, PoolingLayerInfo pool_in
{
for(int x = wstart; x < wend; ++x)
{
- avg_val = sqadd_qs8(avg_val, in[r * cols_in * rows_in + y * cols_in + x]);
+ avg_val = sqadd_qs8(avg_val, in[r * h_in * w_in + y * w_in + x]);
}
}
- out[r * rows_out * cols_out + i * pooled_width + k] = sqmul_qs8(avg_val, (scale_values_q8[pool] >> (7 - fixed_point_position)), fixed_point_position);
+ out[r * h_out * w_out + h * pooled_w + w] = sqmul_qs8(avg_val, (scale_values_q8[pool] >> (7 - fixed_point_position)), fixed_point_position);
}
}
}