Imported Upstream version 1.7.0
[platform/core/ml/nnfw.git] / compiler / locomotiv / src / Node / TransposedConv2D.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 *ker, const float *expected_ofm, const Shape &ifm_shape,
39               const Shape ker_shape, const Shape ofm_shape, const uint32_t stride_v,
40               const uint32_t stride_h, const uint32_t pad_top = 0, const uint32_t pad_bottom = 0,
41               const uint32_t pad_left = 0, const uint32_t pad_right = 0)
42 {
43   auto g = loco::make_graph();
44
45   // Fill output data of FeatureEncode from ifm
46   auto ifm_enc = g->nodes()->create<loco::FeatureEncode>();
47   {
48     auto ifm_enc_buf = make_buffer<float, LexicalLayout>(ifm_shape);
49     auto ifm_overlay = make_overlay<float, LexicalLayout>(ifm_shape, const_cast<float *>(ifm));
50     for (nncc::core::ADT::tensor::IndexEnumerator e{ifm_shape}; e.valid(); e.advance())
51     {
52       const auto &ind = e.current();
53       ifm_enc_buf.at(ind) = ifm_overlay.at(ind);
54     }
55
56     auto enc_data = locomotiv::make_data(ifm_enc_buf);
57     locomotiv::annot_data(ifm_enc, std::move(enc_data));
58     locomotiv::annot_domain(ifm_enc, loco::Domain::Feature);
59   }
60
61   // Fill output data of FilterEncode from ker
62   auto ker_enc = g->nodes()->create<loco::FilterEncode>();
63   {
64     auto ker_enc_buf = make_buffer<float, LexicalLayout>(ker_shape);
65     auto ker_overlay = make_overlay<float, LexicalLayout>(ker_shape, const_cast<float *>(ker));
66     for (nncc::core::ADT::tensor::IndexEnumerator e{ker_shape}; e.valid(); e.advance())
67     {
68       const auto &ind = e.current();
69       ker_enc_buf.at(ind) = ker_overlay.at(ind);
70     }
71
72     auto enc_data = locomotiv::make_data(ker_enc_buf);
73     locomotiv::annot_data(ker_enc, std::move(enc_data));
74     locomotiv::annot_domain(ker_enc, loco::Domain::Filter);
75   }
76
77   // build TransposedConv2D
78   auto tr_conv2d = g->nodes()->create<loco::TransposedConv2D>();
79   tr_conv2d->ifm(ifm_enc);
80   tr_conv2d->ker(ker_enc);
81   tr_conv2d->stride()->vertical(stride_v);
82   tr_conv2d->stride()->horizontal(stride_h);
83   tr_conv2d->pad()->top(pad_top);
84   tr_conv2d->pad()->bottom(pad_bottom);
85   tr_conv2d->pad()->left(pad_left);
86   tr_conv2d->pad()->right(pad_right);
87
88   // run interpreter
89   locomotiv::NodeExecution::get().run(tr_conv2d);
90
91   // get result of calculation
92   auto conv2d_result = locomotiv::annot_data(tr_conv2d);
93
94   // check the result
95   ASSERT_NE(conv2d_result, nullptr);
96   ASSERT_TRUE(conv2d_result->dtype() == loco::DataType::FLOAT32);
97   ASSERT_TRUE(*(conv2d_result->shape()) == ofm_shape);
98
99   auto ofm_overlay =
100       make_overlay<float, LexicalLayout>(ofm_shape, const_cast<float *>(expected_ofm));
101   for (nncc::core::ADT::tensor::IndexEnumerator e{ofm_shape}; e.valid(); e.advance())
102   {
103     const auto &ind = e.current();
104     ASSERT_FLOAT_EQ(ofm_overlay.at(ind), conv2d_result->as_f32_bufptr()->at(ind));
105   }
106
107   ASSERT_EQ(loco::Domain::Feature, locomotiv::annot_domain(tr_conv2d));
108 }
109
110 } // namespace
111
112 // clang-format off
113 /*
114 ifm = tf.constant(1.1, shape = [1, 2, 2, 4])
115 ker = tf.constant(2.2, shape = [3, 3, 2, 4])
116 tr_conv = tf.nn.conv2d_transpose(ifm, ker, output_shape = (1, 5, 5, 2), strides = [1, 2, 2, 1], padding = "VALID")
117
118 with tf.Session() as session:
119   tr_conv_data = session.run(tr_conv)
120  */
121 TEST(NodeExecution_TransposedConv2D, f32)
122 {
123   using nncc::core::ADT::tensor::Shape;
124
125   float ifm[1 * 2 * 2 * 4];
126   for (int n = 0; n < 1 * 2 * 2 * 4; n++)
127     ifm[n] = 1.1;
128
129   float ker[2 * 3 * 3 * 4]; // NHWC 
130   for (int n = 0; n < 2 * 3 * 3 * 4; n++)
131     ker[n] = 2.2;
132
133   float ofm[1 * 5 * 5 * 2] = {9.68,  9.68,  9.68,  9.68,  19.36, 19.36, 9.68,  9.68,  9.68,  9.68,
134                               9.68,  9.68,  9.68,  9.68,  19.36, 19.36, 9.68,  9.68,  9.68,  9.68,
135                               19.36, 19.36, 19.36, 19.36, 38.72, 38.72, 19.36, 19.36, 19.36, 19.36,
136                               9.68,  9.68,  9.68,  9.68,  19.36, 19.36, 9.68,  9.68,  9.68,  9.68,
137                               9.68,  9.68,  9.68,  9.68,  19.36, 19.36, 9.68,  9.68,  9.68,  9.68};
138
139   run_test(ifm, ker, ofm,
140            Shape{1, 2, 2, 4}, Shape{2, 3, 3, 4}, Shape{1, 5, 5, 2}, // shapes of ifm, ker, ofm
141            2, 2 // stride
142            );
143 }
144 // clang-format on