2 * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "NodeExecution.h"
19 #include "locomotiv/NodeData.h"
20 #include "NodeDataImpl.h"
21 #include "NodeDomain.h"
23 #include <loco/IR/PermutingCodec.h>
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>
30 #include <gtest/gtest.h>
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;
39 // This file is intended to test MatrixEncode and MatrixDecode at once
43 class NodeExecution_MatrixCodec : public ::testing::Test
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)
52 auto pull = g.nodes()->create<loco::Pull>();
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);
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)
66 auto encoder = std::unique_ptr<loco::PermutingEncoder<loco::Domain::Matrix>>(
67 new loco::PermutingEncoder<loco::Domain::Matrix>);
71 auto enc = g.nodes()->create<loco::MatrixEncode>();
73 enc->encoder(std::move(encoder));
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)
82 auto decoder = std::unique_ptr<loco::PermutingDecoder<loco::Domain::Matrix>>(
83 new loco::PermutingDecoder<loco::Domain::Matrix>);
87 auto dec = g.nodes()->create<loco::MatrixDecode>();
89 dec->decoder(std::move(decoder));
97 TEST_F(NodeExecution_MatrixCodec, HW_s32)
100 const uint32_t W = 4;
102 // Make HW data for pull node
103 auto pull_buf = make_buffer<int32_t, LexicalLayout>(Shape{H, W});
105 for (IndexEnumerator e{pull_buf.shape()}; e.valid(); e.advance())
107 pull_buf.at(e.current()) = i;
108 ++i; // Doesn't matter what it is
111 // Make HW permutation for encoder and decoder
112 loco::Permutation<loco::Domain::Matrix> HW;
114 HW.axis(loco::MatrixAxis::Height) = 0;
115 HW.axis(loco::MatrixAxis::Width) = 1;
118 auto pull = pull_layer(pull_buf, loco::DataType::S32);
121 auto enc = matrix_encode_layer(pull, HW);
122 locomotiv::NodeExecution::get().run(enc);
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}));
134 ASSERT_EQ(loco::Domain::Matrix, locomotiv::annot_domain(enc));
137 auto dec = matrix_decode_layer(enc, HW);
138 locomotiv::NodeExecution::get().run(dec);
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}));
150 ASSERT_EQ(loco::Domain::Tensor, locomotiv::annot_domain(dec));
153 TEST_F(NodeExecution_MatrixCodec, WH_f32)
155 const uint32_t W = 6;
156 const uint32_t H = 5;
158 // Make crazy WH data for pull node
159 auto pull_buf = make_buffer<float, LexicalLayout>(Shape{W, H});
161 for (IndexEnumerator e{pull_buf.shape()}; e.valid(); e.advance())
163 pull_buf.at(e.current()) = f;
164 f += 0.1f; // Doesn't matter what it is
167 // Make WH permutation for encoder and decoder
168 loco::Permutation<loco::Domain::Matrix> WH;
170 WH.axis(loco::MatrixAxis::Width) = 0;
171 WH.axis(loco::MatrixAxis::Height) = 1;
174 auto pull = pull_layer(pull_buf, loco::DataType::FLOAT32);
177 auto enc = matrix_encode_layer(pull, WH);
178 locomotiv::NodeExecution::get().run(enc);
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}));
190 ASSERT_EQ(loco::Domain::Matrix, locomotiv::annot_domain(enc));
193 auto dec = matrix_decode_layer(enc, WH);
194 locomotiv::NodeExecution::get().run(dec);
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}));
206 ASSERT_EQ(loco::Domain::Tensor, locomotiv::annot_domain(dec));