Imported Upstream version 1.7.0
[platform/core/ml/nnfw.git] / compiler / locomotiv / src / Node / MatrixCodec.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 <loco/IR/PermutingCodec.h>
24
25 #include <nncc/core/ADT/tensor/Shape.h>
26 #include <nncc/core/ADT/tensor/Buffer.h>
27 #include <nncc/core/ADT/tensor/LexicalLayout.h>
28 #include <nncc/core/ADT/tensor/IndexEnumerator.h>
29
30 #include <gtest/gtest.h>
31
32 using nncc::core::ADT::tensor::Index;
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::IndexEnumerator;
37 using nncc::core::ADT::tensor::Buffer;
38
39 // This file is intended to test MatrixEncode and MatrixDecode at once
40 namespace
41 {
42
43 class NodeExecution_MatrixCodec : public ::testing::Test
44 {
45 private:
46   loco::Graph g;
47
48 protected:
49   /// @brief Make Pull node and set data by given buffer and data type
50   template <typename DT> loco::Pull *pull_layer(Buffer<DT> &pull_buf, loco::DataType dtype)
51   {
52     auto pull = g.nodes()->create<loco::Pull>();
53     pull->dtype(dtype);
54
55     auto pull_data = locomotiv::make_data(pull_buf);
56     locomotiv::annot_data(pull, std::move(pull_data));
57     locomotiv::annot_domain(pull, loco::Domain::Tensor);
58
59     return pull;
60   }
61
62   /// @brief Make MatrixEncode node with given input and encoding permutation
63   loco::MatrixEncode *matrix_encode_layer(loco::Node *input,
64                                           const loco::Permutation<loco::Domain::Matrix> &perm)
65   {
66     auto encoder = std::unique_ptr<loco::PermutingEncoder<loco::Domain::Matrix>>(
67         new loco::PermutingEncoder<loco::Domain::Matrix>);
68
69     encoder->perm(perm);
70
71     auto enc = g.nodes()->create<loco::MatrixEncode>();
72     enc->input(input);
73     enc->encoder(std::move(encoder));
74
75     return enc;
76   }
77
78   /// @brief Make MatrixDecode node with given input and decoding permutation
79   loco::MatrixDecode *matrix_decode_layer(loco::Node *input,
80                                           const loco::Permutation<loco::Domain::Matrix> &perm)
81   {
82     auto decoder = std::unique_ptr<loco::PermutingDecoder<loco::Domain::Matrix>>(
83         new loco::PermutingDecoder<loco::Domain::Matrix>);
84
85     decoder->perm(perm);
86
87     auto dec = g.nodes()->create<loco::MatrixDecode>();
88     dec->input(input);
89     dec->decoder(std::move(decoder));
90
91     return dec;
92   }
93 };
94
95 } // namespace
96
97 TEST_F(NodeExecution_MatrixCodec, HW_s32)
98 {
99   const uint32_t H = 3;
100   const uint32_t W = 4;
101
102   // Make HW data for pull node
103   auto pull_buf = make_buffer<int32_t, LexicalLayout>(Shape{H, W});
104   int32_t i = 0;
105   for (IndexEnumerator e{pull_buf.shape()}; e.valid(); e.advance())
106   {
107     pull_buf.at(e.current()) = i;
108     ++i; // Doesn't matter what it is
109   }
110
111   // Make HW permutation for encoder and decoder
112   loco::Permutation<loco::Domain::Matrix> HW;
113
114   HW.axis(loco::MatrixAxis::Height) = 0;
115   HW.axis(loco::MatrixAxis::Width) = 1;
116
117   // Pull
118   auto pull = pull_layer(pull_buf, loco::DataType::S32);
119
120   // MatrixEncode
121   auto enc = matrix_encode_layer(pull, HW);
122   locomotiv::NodeExecution::get().run(enc);
123
124   // Test MatrixEncode
125   auto enc_data = locomotiv::annot_data(enc);
126   ASSERT_NE(enc_data, nullptr);
127   ASSERT_EQ(loco::DataType::S32, enc_data->dtype());
128   ASSERT_EQ((Shape{H, W}), *(enc_data->shape())); // locomotiv matrix is HW
129   auto enc_buf = enc_data->as_s32_bufptr();
130   for (uint32_t h = 0; h < H; ++h)
131     for (uint32_t w = 0; w < W; ++w)
132       ASSERT_EQ(enc_buf->at(Index{h, w}), pull_buf.at(Index{h, w}));
133
134   ASSERT_EQ(loco::Domain::Matrix, locomotiv::annot_domain(enc));
135
136   // MatrixDecode
137   auto dec = matrix_decode_layer(enc, HW);
138   locomotiv::NodeExecution::get().run(dec);
139
140   // Test MatrixDecode: Encode -> Decode == identity
141   auto dec_data = locomotiv::annot_data(dec);
142   ASSERT_NE(dec_data, nullptr);
143   ASSERT_EQ(loco::DataType::S32, dec_data->dtype());
144   ASSERT_EQ((Shape{H, W}), *(dec_data->shape()));
145   auto dec_buf = dec_data->as_s32_bufptr();
146   for (uint32_t h = 0; h < H; ++h)
147     for (uint32_t w = 0; w < W; ++w)
148       ASSERT_EQ(dec_buf->at(Index{h, w}), pull_buf.at(Index{h, w}));
149
150   ASSERT_EQ(loco::Domain::Tensor, locomotiv::annot_domain(dec));
151 }
152
153 TEST_F(NodeExecution_MatrixCodec, WH_f32)
154 {
155   const uint32_t W = 6;
156   const uint32_t H = 5;
157
158   // Make crazy WH data for pull node
159   auto pull_buf = make_buffer<float, LexicalLayout>(Shape{W, H});
160   float f = 0.0f;
161   for (IndexEnumerator e{pull_buf.shape()}; e.valid(); e.advance())
162   {
163     pull_buf.at(e.current()) = f;
164     f += 0.1f; // Doesn't matter what it is
165   }
166
167   // Make WH permutation for encoder and decoder
168   loco::Permutation<loco::Domain::Matrix> WH;
169
170   WH.axis(loco::MatrixAxis::Width) = 0;
171   WH.axis(loco::MatrixAxis::Height) = 1;
172
173   // Pull
174   auto pull = pull_layer(pull_buf, loco::DataType::FLOAT32);
175
176   // MatrixEncode
177   auto enc = matrix_encode_layer(pull, WH);
178   locomotiv::NodeExecution::get().run(enc);
179
180   // Test MatrixEncode
181   auto enc_data = locomotiv::annot_data(enc);
182   ASSERT_NE(enc_data, nullptr);
183   ASSERT_EQ(loco::DataType::FLOAT32, enc_data->dtype());
184   ASSERT_EQ((Shape{H, W}), *(enc_data->shape())); // locomotiv matrix is HW
185   auto enc_buf = enc_data->as_f32_bufptr();
186   for (uint32_t h = 0; h < H; ++h)
187     for (uint32_t w = 0; w < W; ++w)
188       ASSERT_FLOAT_EQ(enc_buf->at(Index{h, w}), pull_buf.at(Index{w, h}));
189
190   ASSERT_EQ(loco::Domain::Matrix, locomotiv::annot_domain(enc));
191
192   // MatrixDecode
193   auto dec = matrix_decode_layer(enc, WH);
194   locomotiv::NodeExecution::get().run(dec);
195
196   // Test MatrixDecode: Encode -> Decode == identity
197   auto dec_data = locomotiv::annot_data(dec);
198   ASSERT_NE(dec_data, nullptr);
199   ASSERT_EQ(loco::DataType::FLOAT32, dec_data->dtype());
200   ASSERT_EQ((Shape{W, H}), *(dec_data->shape()));
201   auto dec_buf = dec_data->as_f32_bufptr();
202   for (uint32_t h = 0; h < H; ++h)
203     for (uint32_t w = 0; w < W; ++w)
204       ASSERT_FLOAT_EQ(dec_buf->at(Index{w, h}), pull_buf.at(Index{w, h}));
205
206   ASSERT_EQ(loco::Domain::Tensor, locomotiv::annot_domain(dec));
207 }