Imported Upstream version 1.7.0
[platform/core/ml/nnfw.git] / compiler / locomotiv / src / Node / MaxPool2D.test.cpp
1 /*
2  * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *    http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "NodeExecution.h"
18
19 #include "locomotiv/NodeData.h"
20 #include "NodeDataImpl.h"
21 #include "NodeDomain.h"
22
23 #include <nncc/core/ADT/tensor/Shape.h>
24 #include <nncc/core/ADT/tensor/Buffer.h>
25 #include <nncc/core/ADT/tensor/Overlay.h>
26 #include <nncc/core/ADT/tensor/LexicalLayout.h>
27 #include "nncc/core/ADT/tensor/IndexEnumerator.h"
28
29 #include <gtest/gtest.h>
30
31 namespace
32 {
33 using nncc::core::ADT::tensor::Shape;
34 using nncc::core::ADT::tensor::LexicalLayout;
35 using nncc::core::ADT::tensor::make_buffer;
36 using nncc::core::ADT::tensor::make_overlay;
37
38 void run_test(const float *ifm, const float *expected_ofm, const Shape &ifm_shape,
39               const Shape &ofm_shape, const uint32_t window_v, const uint32_t window_h,
40               const uint32_t stride_v, const uint32_t stride_h, const uint32_t pad_top,
41               const uint32_t pad_bottom, const uint32_t pad_left, const uint32_t pad_right)
42 {
43   // Let's make FeatureEncode-MaxPool2D graph
44   auto g = loco::make_graph();
45   auto enc = g->nodes()->create<loco::FeatureEncode>();
46
47   // Fill output data of FeatureEncode from ifm
48   auto enc_buf = make_buffer<float, LexicalLayout>(ifm_shape);
49
50   auto ifm_overlay = make_overlay<float, LexicalLayout>(ifm_shape, const_cast<float *>(ifm));
51   for (nncc::core::ADT::tensor::IndexEnumerator e{ifm_shape}; e.valid(); e.advance())
52   {
53     const auto &ind = e.current();
54     enc_buf.at(ind) = ifm_overlay.at(ind);
55   }
56
57   auto enc_data = locomotiv::make_data(enc_buf);
58   locomotiv::annot_data(enc, std::move(enc_data));
59   locomotiv::annot_domain(enc, loco::Domain::Feature);
60
61   // build MaxPool2D
62   auto maxpool2d = g->nodes()->create<loco::MaxPool2D>();
63   maxpool2d->ifm(enc);
64   maxpool2d->window()->vertical(window_v);
65   maxpool2d->window()->horizontal(window_h);
66   maxpool2d->stride()->vertical(stride_v);
67   maxpool2d->stride()->horizontal(stride_h);
68   maxpool2d->pad()->top(pad_top);
69   maxpool2d->pad()->bottom(pad_bottom);
70   maxpool2d->pad()->left(pad_left);
71   maxpool2d->pad()->right(pad_right);
72
73   // run interpreter
74   locomotiv::NodeExecution::get().run(maxpool2d);
75
76   // get result of calculation
77   auto maxpool2d_data = locomotiv::annot_data(maxpool2d);
78
79   // check the result
80   ASSERT_NE(maxpool2d_data, nullptr);
81   ASSERT_TRUE(maxpool2d_data->dtype() == loco::DataType::FLOAT32);
82   ASSERT_TRUE(*(maxpool2d_data->shape()) == ofm_shape);
83
84   auto ofm_overlay =
85       make_overlay<float, LexicalLayout>(ofm_shape, const_cast<float *>(expected_ofm));
86   for (nncc::core::ADT::tensor::IndexEnumerator e{ofm_shape}; e.valid(); e.advance())
87   {
88     const auto &ind = e.current();
89     ASSERT_FLOAT_EQ(ofm_overlay.at(ind), maxpool2d_data->as_f32_bufptr()->at(ind));
90   }
91
92   ASSERT_EQ(loco::Domain::Feature, locomotiv::annot_domain(maxpool2d));
93 }
94
95 } // namespace
96
97 // clang-format off
98 /* ifm and ofm are from the code below:
99
100   value = tf.random_normal([1, 3, 3, 1], stddev=1)
101   maxpool = tf.nn.max_pool(value, ksize = [1, 2, 2, 1], strides = [1, 1, 1, 1], padding= 'VALID',
102                           data_format="NHWC")
103   with tf.Session() as sess:
104       print(sess.run(maxpool))
105 */
106
107 TEST(NodeExecution_MaxPool2D, f32_1x3x3x1_calculation)
108 {
109   using nncc::core::ADT::tensor::Shape;
110
111   const float ifm[] =
112   {
113     -1.5510627,   0.3653609,    1.9002001,
114     -0.15861237,  -0.32944828,  1.2053918,
115     0.50054574,  -0.8533826,   0.131492,
116   };
117
118   const float ofm[] =
119   {
120     0.3653609, 1.9002001,
121     0.50054574, 1.2053918
122   };
123
124   run_test(ifm, ofm,
125            Shape{1, 3, 3, 1}, Shape{1, 2, 2, 1}, // input shape , output shape
126            2, 2,       // kernel
127            1, 1,       // stride
128            0, 0, 0, 0  // padding
129   );
130 }
131
132 TEST(NodeExecution_MaxPool2D, with_padding)
133 {
134   using nncc::core::ADT::tensor::Shape;
135
136   const float ifm[] =
137   {
138      1,  2,  3,  4,  5,
139      6,  7,  8,  9, 10,
140     11, 12, 13, 14, 15,
141     16, 17, 18, 19, 20,
142     21, 22, 23, 24, 25
143   };
144
145   const float ofm[] =
146   {
147      7,  9, 10,
148     17, 19, 20,
149     22, 24, 25
150   };
151
152   run_test(ifm, ofm,
153            Shape{1, 5, 5, 1}, Shape{1, 3, 3, 1}, // input shape , output shape
154            3, 3,       // kernel
155            2, 2,       // stride
156            1, 1, 1, 1  // padding - this mimics SAME padding
157   );
158 }
159 // clang-format on