summaryrefslogtreecommitdiff
path: root/compiler/loco/src/IR/PermutingCodec.test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/loco/src/IR/PermutingCodec.test.cpp')
-rw-r--r--compiler/loco/src/IR/PermutingCodec.test.cpp553
1 files changed, 553 insertions, 0 deletions
diff --git a/compiler/loco/src/IR/PermutingCodec.test.cpp b/compiler/loco/src/IR/PermutingCodec.test.cpp
new file mode 100644
index 000000000..2eff286d0
--- /dev/null
+++ b/compiler/loco/src/IR/PermutingCodec.test.cpp
@@ -0,0 +1,553 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "loco/IR/PermutingCodec.h"
+
+#include <gtest/gtest.h>
+
+using namespace loco;
+
+TEST(PemutationTest, feature)
+{
+ Permutation<Domain::Feature> perm;
+
+ // All values are invalid at the beginning
+ ASSERT_FALSE(perm.mapped(FeatureAxis::Count));
+ ASSERT_FALSE(perm.mapped(FeatureAxis::Depth));
+ ASSERT_FALSE(perm.mapped(FeatureAxis::Height));
+ ASSERT_FALSE(perm.mapped(FeatureAxis::Width));
+
+ // Update mapping
+ perm[FeatureAxis::Count] = 5;
+ perm[FeatureAxis::Depth] = 6;
+ perm[FeatureAxis::Height] = 7;
+ perm[FeatureAxis::Width] = 8;
+
+ // Now perm has a mapping for all the axes
+ ASSERT_TRUE(perm.mapped(FeatureAxis::Count));
+ ASSERT_TRUE(perm.mapped(FeatureAxis::Depth));
+ ASSERT_TRUE(perm.mapped(FeatureAxis::Height));
+ ASSERT_TRUE(perm.mapped(FeatureAxis::Width));
+
+ // Check the value
+ ASSERT_EQ(perm[FeatureAxis::Count], 5);
+ ASSERT_EQ(perm[FeatureAxis::Depth], 6);
+ ASSERT_EQ(perm[FeatureAxis::Height], 7);
+ ASSERT_EQ(perm[FeatureAxis::Width], 8);
+}
+
+TEST(PemutationTest, filter)
+{
+ Permutation<Domain::Filter> perm;
+
+ // All values are invalid at the beginning
+ ASSERT_FALSE(perm.mapped(FilterAxis::Count));
+ ASSERT_FALSE(perm.mapped(FilterAxis::Depth));
+ ASSERT_FALSE(perm.mapped(FilterAxis::Height));
+ ASSERT_FALSE(perm.mapped(FilterAxis::Width));
+
+ // Update mapping
+ perm[FilterAxis::Count] = 5;
+ perm[FilterAxis::Depth] = 6;
+ perm[FilterAxis::Height] = 7;
+ perm[FilterAxis::Width] = 8;
+
+ // Now perm has a mapping for all the axes
+ ASSERT_TRUE(perm.mapped(FilterAxis::Count));
+ ASSERT_TRUE(perm.mapped(FilterAxis::Depth));
+ ASSERT_TRUE(perm.mapped(FilterAxis::Height));
+ ASSERT_TRUE(perm.mapped(FilterAxis::Width));
+
+ // Check the value
+ ASSERT_EQ(perm[FilterAxis::Count], 5);
+ ASSERT_EQ(perm[FilterAxis::Depth], 6);
+ ASSERT_EQ(perm[FilterAxis::Height], 7);
+ ASSERT_EQ(perm[FilterAxis::Width], 8);
+}
+
+TEST(PemutationTest, depthwise_filter)
+{
+ Permutation<Domain::DepthwiseFilter> perm;
+
+ // All values are invalid at the beginning
+ ASSERT_FALSE(perm.mapped(DepthwiseFilterAxis::Depth));
+ ASSERT_FALSE(perm.mapped(DepthwiseFilterAxis::Multiplier));
+ ASSERT_FALSE(perm.mapped(DepthwiseFilterAxis::Height));
+ ASSERT_FALSE(perm.mapped(DepthwiseFilterAxis::Width));
+
+ // Update mapping
+ perm[DepthwiseFilterAxis::Depth] = 5;
+ perm[DepthwiseFilterAxis::Multiplier] = 6;
+ perm[DepthwiseFilterAxis::Height] = 7;
+ perm[DepthwiseFilterAxis::Width] = 8;
+
+ // Now perm has a mapping for all the axes
+ ASSERT_TRUE(perm.mapped(DepthwiseFilterAxis::Depth));
+ ASSERT_TRUE(perm.mapped(DepthwiseFilterAxis::Multiplier));
+ ASSERT_TRUE(perm.mapped(DepthwiseFilterAxis::Height));
+ ASSERT_TRUE(perm.mapped(DepthwiseFilterAxis::Width));
+
+ // Check the value
+ ASSERT_EQ(perm[DepthwiseFilterAxis::Depth], 5);
+ ASSERT_EQ(perm[DepthwiseFilterAxis::Multiplier], 6);
+ ASSERT_EQ(perm[DepthwiseFilterAxis::Height], 7);
+ ASSERT_EQ(perm[DepthwiseFilterAxis::Width], 8);
+}
+
+TEST(PermutingEncoderTest, feature)
+{
+ PermutingEncoder<Domain::Feature> enc;
+
+ // Encoder is invalid at the beginning
+ ASSERT_FALSE(enc.valid());
+
+ // Set "invalid" mapping
+ enc.perm()->axis(FeatureAxis::Count) = 0;
+ enc.perm()->axis(FeatureAxis::Depth) = 6;
+ enc.perm()->axis(FeatureAxis::Height) = 1;
+ enc.perm()->axis(FeatureAxis::Width) = 2;
+
+ // Encoder is still invalid
+ ASSERT_FALSE(enc.valid());
+
+ // Set another "invalid" mapping
+ enc.perm()->axis(FeatureAxis::Depth) = 1;
+
+ // Encoder is still invalid
+ ASSERT_FALSE(enc.valid());
+
+ // Set "valid" mapping
+ enc.perm()->axis(FeatureAxis::Depth) = 3;
+
+ // Encoder is now valid
+ ASSERT_TRUE(enc.valid());
+
+ // Let's test with a HD (1280x720) RGB image
+ TensorShape tensor_shape;
+
+ tensor_shape.rank(4);
+ tensor_shape.dim(0) = 1; // COUNT
+ tensor_shape.dim(1) = 720; // HEIGHT
+ tensor_shape.dim(2) = 1280; // WIDTH
+ tensor_shape.dim(3) = 3; // DEPTH
+
+ // Get the feature shape corresponding to a given image
+ auto feature_shape = enc.shape(tensor_shape);
+
+ ASSERT_EQ(feature_shape.count(), 1);
+ ASSERT_EQ(feature_shape.depth(), 3);
+ ASSERT_EQ(feature_shape.height(), 720);
+ ASSERT_EQ(feature_shape.width(), 1280);
+
+ // Let's find a source tensor index!
+ FeatureIndex feature_index;
+
+ feature_index.batch() = 0;
+ feature_index.channel() = 1;
+ feature_index.row() = 2;
+ feature_index.column() = 3;
+
+ auto tensor_index = enc.value(feature_index);
+
+ ASSERT_EQ(tensor_index.at(0), 0); // BATCH(COUNT)
+ ASSERT_EQ(tensor_index.at(1), 2); // ROW(HEIGHT)
+ ASSERT_EQ(tensor_index.at(2), 3); // COLUMN(WIDTH)
+ ASSERT_EQ(tensor_index.at(3), 1); // CHANNEL(DEPTH)
+}
+
+TEST(PermutingEncoderTest, feature_clone)
+{
+ PermutingEncoder<Domain::Feature> src_enc;
+
+ auto src_perm = src_enc.perm();
+
+ src_perm->axis(FeatureAxis::Count) = 0;
+ src_perm->axis(FeatureAxis::Depth) = 3;
+ src_perm->axis(FeatureAxis::Height) = 1;
+ src_perm->axis(FeatureAxis::Width) = 2;
+
+ auto dst_enc = src_enc.clone();
+ auto dst_perm = dynamic_cast<PermutingEncoder<Domain::Feature> *>(dst_enc.get())->perm();
+
+ EXPECT_EQ(dst_perm->axis(FeatureAxis::Count), src_perm->axis(FeatureAxis::Count));
+ EXPECT_EQ(dst_perm->axis(FeatureAxis::Depth), src_perm->axis(FeatureAxis::Depth));
+ EXPECT_EQ(dst_perm->axis(FeatureAxis::Height), src_perm->axis(FeatureAxis::Height));
+ EXPECT_EQ(dst_perm->axis(FeatureAxis::Width), src_perm->axis(FeatureAxis::Width));
+
+ // Update on cloned encoder SHOULD NOT affect the original encoder
+ dst_perm->axis(FeatureAxis::Height) += 1;
+
+ EXPECT_EQ(src_perm->axis(FeatureAxis::Height), 1);
+ EXPECT_EQ(dst_perm->axis(FeatureAxis::Height), 2);
+}
+
+TEST(PermutingEncoderTest, filter)
+{
+ PermutingEncoder<Domain::Filter> enc;
+
+ // Encoder is invalid at the beginning
+ ASSERT_FALSE(enc.valid());
+
+ // Set "invalid" mapping
+ enc.perm()->axis(FilterAxis::Count) = 0;
+ enc.perm()->axis(FilterAxis::Depth) = 6;
+ enc.perm()->axis(FilterAxis::Height) = 1;
+ enc.perm()->axis(FilterAxis::Width) = 2;
+
+ // Encoder is still invalid
+ ASSERT_FALSE(enc.valid());
+
+ // Set another "invalid" mapping
+ enc.perm()->axis(FilterAxis::Depth) = 1;
+
+ // Encoder is still invalid
+ ASSERT_FALSE(enc.valid());
+
+ // Set "valid" mapping
+ enc.perm()->axis(FilterAxis::Depth) = 3;
+
+ // Encoder is now valid
+ ASSERT_TRUE(enc.valid());
+
+ TensorShape tensor_shape;
+
+ tensor_shape.rank(4);
+ tensor_shape.dim(0) = 8; // COUNT
+ tensor_shape.dim(1) = 1; // HEIGHT
+ tensor_shape.dim(2) = 7; // WIDTH
+ tensor_shape.dim(3) = 4; // DEPTH
+
+ // Get the corresponding filter shape
+ auto filter_shape = enc.shape(tensor_shape);
+
+ ASSERT_EQ(filter_shape.count(), 8);
+ ASSERT_EQ(filter_shape.depth(), 4);
+ ASSERT_EQ(filter_shape.height(), 1);
+ ASSERT_EQ(filter_shape.width(), 7);
+
+ // Let's find a source tensor index!
+ FilterIndex filter_index;
+
+ filter_index.nth() = 1;
+ filter_index.channel() = 2;
+ filter_index.row() = 0;
+ filter_index.column() = 3;
+
+ auto tensor_index = enc.value(filter_index);
+
+ ASSERT_EQ(tensor_index.at(0), 1); // NTH(COUNT)
+ ASSERT_EQ(tensor_index.at(1), 0); // ROW(HEIGHT)
+ ASSERT_EQ(tensor_index.at(2), 3); // COLUMN(WIDTH)
+ ASSERT_EQ(tensor_index.at(3), 2); // CHANNEL(DEPTH)
+}
+
+TEST(PermutingEncoderTest, depthwise_filter)
+{
+ PermutingEncoder<Domain::DepthwiseFilter> enc;
+
+ // Encoder is invalid at the beginning
+ ASSERT_FALSE(enc.valid());
+
+ // Set "invalid" mapping
+ enc.perm()->axis(DepthwiseFilterAxis::Depth) = 0;
+ enc.perm()->axis(DepthwiseFilterAxis::Multiplier) = 6;
+ enc.perm()->axis(DepthwiseFilterAxis::Height) = 1;
+ enc.perm()->axis(DepthwiseFilterAxis::Width) = 2;
+
+ // Encoder is still invalid
+ ASSERT_FALSE(enc.valid());
+
+ // Set another "invalid" mapping
+ enc.perm()->axis(DepthwiseFilterAxis::Multiplier) = 1;
+
+ // Encoder is still invalid
+ ASSERT_FALSE(enc.valid());
+
+ // Set "valid" mapping
+ enc.perm()->axis(DepthwiseFilterAxis::Multiplier) = 3;
+
+ // Encoder is now valid
+ ASSERT_TRUE(enc.valid());
+
+ TensorShape tensor_shape;
+
+ tensor_shape.rank(4);
+ tensor_shape.dim(0) = 8; // DEPTH
+ tensor_shape.dim(1) = 1; // HEIGHT
+ tensor_shape.dim(2) = 7; // WIDTH
+ tensor_shape.dim(3) = 4; // MULTIPLIER
+
+ // Get the corresponding depthwise filter shape
+ auto filter_shape = enc.shape(tensor_shape);
+
+ ASSERT_EQ(filter_shape.depth(), 8);
+ ASSERT_EQ(filter_shape.multiplier(), 4);
+ ASSERT_EQ(filter_shape.height(), 1);
+ ASSERT_EQ(filter_shape.width(), 7);
+
+ // Let's find a source tensor index!
+ DepthwiseFilterIndex filter_index;
+
+ filter_index.channel() = 1;
+ filter_index.nth() = 2;
+ filter_index.row() = 0;
+ filter_index.column() = 3;
+
+ auto tensor_index = enc.value(filter_index);
+
+ ASSERT_EQ(tensor_index.at(0), 1); // CHANNEL(DEPTH)
+ ASSERT_EQ(tensor_index.at(1), 0); // ROW(HEIGHT)
+ ASSERT_EQ(tensor_index.at(2), 3); // COLUMN(WIDTH)
+ ASSERT_EQ(tensor_index.at(3), 2); // NTH(MULTIPLIER)
+}
+
+TEST(PermutingEncoderTest, depthwisefilter_init)
+{
+ Permutation<Domain::DepthwiseFilter> src_perm;
+
+ src_perm.axis(DepthwiseFilterAxis::Multiplier) = 0;
+ src_perm.axis(DepthwiseFilterAxis::Depth) = 3;
+ src_perm.axis(DepthwiseFilterAxis::Height) = 1;
+ src_perm.axis(DepthwiseFilterAxis::Width) = 2;
+
+ PermutingEncoder<Domain::DepthwiseFilter> dst_enc{src_perm};
+ auto dst_perm = dst_enc.perm();
+
+ EXPECT_EQ(dst_perm->axis(DepthwiseFilterAxis::Multiplier),
+ src_perm.axis(DepthwiseFilterAxis::Multiplier));
+ EXPECT_EQ(dst_perm->axis(DepthwiseFilterAxis::Depth), src_perm.axis(DepthwiseFilterAxis::Depth));
+ EXPECT_EQ(dst_perm->axis(DepthwiseFilterAxis::Height),
+ src_perm.axis(DepthwiseFilterAxis::Height));
+ EXPECT_EQ(dst_perm->axis(DepthwiseFilterAxis::Width), src_perm.axis(DepthwiseFilterAxis::Width));
+
+ // Update on dst perm SHOULD NOT affect the src perm
+ dst_perm->axis(DepthwiseFilterAxis::Height) += 1;
+
+ EXPECT_EQ(src_perm.axis(DepthwiseFilterAxis::Height), 1);
+ EXPECT_EQ(dst_perm->axis(DepthwiseFilterAxis::Height), 2);
+}
+
+TEST(PermutingDecoderTest, feature)
+{
+ PermutingDecoder<Domain::Feature> dec;
+
+ // Decoder is invalid at the beginning
+ ASSERT_FALSE(dec.valid());
+
+ // Set "invalid" mapping
+ dec.perm()->axis(FeatureAxis::Count) = 0;
+ dec.perm()->axis(FeatureAxis::Depth) = 6;
+ dec.perm()->axis(FeatureAxis::Height) = 1;
+ dec.perm()->axis(FeatureAxis::Width) = 2;
+
+ // Decoder is still invalid
+ ASSERT_FALSE(dec.valid());
+
+ // Set another "invalid" mapping
+ dec.perm()->axis(FeatureAxis::Depth) = 1;
+
+ // Decoder is still invalid
+ ASSERT_FALSE(dec.valid());
+
+ // Set "valid" mapping
+ dec.perm()->axis(FeatureAxis::Depth) = 3;
+
+ // Decoder is now valid
+ ASSERT_TRUE(dec.valid());
+
+ // Let's test with a HD (1280x720) RGB image
+ FeatureShape feature_shape;
+
+ feature_shape.count() = 1;
+ feature_shape.depth() = 3;
+ feature_shape.height() = 720;
+ feature_shape.width() = 1280;
+
+ // Get the tensor shape corresponding to a given image
+ auto tensor_shape = dec.shape(feature_shape);
+
+ ASSERT_EQ(tensor_shape.rank(), 4);
+ ASSERT_EQ(tensor_shape.dim(0), 1); // COUNT
+ ASSERT_EQ(tensor_shape.dim(1), 720); // HEIGHT
+ ASSERT_EQ(tensor_shape.dim(2), 1280); // WIDTH
+ ASSERT_EQ(tensor_shape.dim(3), 3); // DEPTH
+
+ // Let's find a source feature index!
+ TensorIndex tensor_index;
+
+ tensor_index.resize(4);
+
+ tensor_index.at(0) = 0; // BATCH(COUNT)
+ tensor_index.at(3) = 1; // CHANNEL(DEPTH)
+ tensor_index.at(1) = 2; // ROW(HEIGHT)
+ tensor_index.at(2) = 3; // COLUMN(WIDTH)
+
+ auto feature_index = dec.value(tensor_index);
+
+ ASSERT_EQ(feature_index.batch(), 0);
+ ASSERT_EQ(feature_index.channel(), 1);
+ ASSERT_EQ(feature_index.row(), 2);
+ ASSERT_EQ(feature_index.column(), 3);
+}
+
+TEST(PermutingDecoderTest, feature_clone)
+{
+ PermutingDecoder<Domain::Feature> src_enc;
+
+ auto src_perm = src_enc.perm();
+
+ src_perm->axis(FeatureAxis::Count) = 0;
+ src_perm->axis(FeatureAxis::Depth) = 3;
+ src_perm->axis(FeatureAxis::Height) = 1;
+ src_perm->axis(FeatureAxis::Width) = 2;
+
+ auto dst_enc = src_enc.clone();
+ auto dst_perm = dynamic_cast<PermutingDecoder<Domain::Feature> *>(dst_enc.get())->perm();
+
+ EXPECT_EQ(dst_perm->axis(FeatureAxis::Count), src_perm->axis(FeatureAxis::Count));
+ EXPECT_EQ(dst_perm->axis(FeatureAxis::Depth), src_perm->axis(FeatureAxis::Depth));
+ EXPECT_EQ(dst_perm->axis(FeatureAxis::Height), src_perm->axis(FeatureAxis::Height));
+ EXPECT_EQ(dst_perm->axis(FeatureAxis::Width), src_perm->axis(FeatureAxis::Width));
+
+ // Update on cloned decoder SHOULD NOT affect the original decoder
+ dst_perm->axis(FeatureAxis::Height) += 1;
+
+ EXPECT_EQ(src_perm->axis(FeatureAxis::Height), 1);
+ EXPECT_EQ(dst_perm->axis(FeatureAxis::Height), 2);
+}
+
+TEST(PermutingDecoderTest, filter)
+{
+ PermutingDecoder<Domain::Filter> dec;
+
+ // Decoder is invalid at the beginning
+ ASSERT_FALSE(dec.valid());
+
+ // Set "invalid" mapping
+ dec.perm()->axis(FilterAxis::Count) = 0;
+ dec.perm()->axis(FilterAxis::Depth) = 6;
+ dec.perm()->axis(FilterAxis::Height) = 1;
+ dec.perm()->axis(FilterAxis::Width) = 2;
+
+ // Decoder is still invalid
+ ASSERT_FALSE(dec.valid());
+
+ // Set another "invalid" mapping
+ dec.perm()->axis(FilterAxis::Depth) = 1;
+
+ // Decoder is still invalid
+ ASSERT_FALSE(dec.valid());
+
+ // Set "valid" mapping
+ dec.perm()->axis(FilterAxis::Depth) = 3;
+
+ // Decoder is now valid
+ ASSERT_TRUE(dec.valid());
+
+ // Let's test with a small filter
+ FilterShape filter_shape;
+
+ filter_shape.count() = 10;
+ filter_shape.depth() = 3;
+ filter_shape.height() = 6;
+ filter_shape.width() = 8;
+
+ // Get the tensor shape corresponding to a given image
+ auto tensor_shape = dec.shape(filter_shape);
+
+ ASSERT_EQ(tensor_shape.rank(), 4);
+ ASSERT_EQ(tensor_shape.dim(0), 10); // COUNT
+ ASSERT_EQ(tensor_shape.dim(1), 6); // HEIGHT
+ ASSERT_EQ(tensor_shape.dim(2), 8); // WIDTH
+ ASSERT_EQ(tensor_shape.dim(3), 3); // DEPTH
+
+ // Let's find a source filter index!
+ TensorIndex tensor_index;
+
+ tensor_index.resize(4);
+
+ tensor_index.at(0) = 0; // BATCH(COUNT)
+ tensor_index.at(3) = 1; // CHANNEL(DEPTH)
+ tensor_index.at(1) = 2; // ROW(HEIGHT)
+ tensor_index.at(2) = 3; // COLUMN(WIDTH)
+
+ auto filter_index = dec.value(tensor_index);
+
+ ASSERT_EQ(filter_index.nth(), 0);
+ ASSERT_EQ(filter_index.channel(), 1);
+ ASSERT_EQ(filter_index.row(), 2);
+ ASSERT_EQ(filter_index.column(), 3);
+}
+
+TEST(PermutingDecoderTest, depthwise_filter)
+{
+ PermutingDecoder<Domain::DepthwiseFilter> dec;
+
+ // Decoder is invalid at the beginning
+ ASSERT_FALSE(dec.valid());
+
+ // Set "invalid" mapping
+ dec.perm()->axis(DepthwiseFilterAxis::Depth) = 0;
+ dec.perm()->axis(DepthwiseFilterAxis::Multiplier) = 6;
+ dec.perm()->axis(DepthwiseFilterAxis::Height) = 1;
+ dec.perm()->axis(DepthwiseFilterAxis::Width) = 2;
+
+ // Decoder is still invalid
+ ASSERT_FALSE(dec.valid());
+
+ // Set another "invalid" mapping
+ dec.perm()->axis(DepthwiseFilterAxis::Multiplier) = 1;
+
+ // Decoder is still invalid
+ ASSERT_FALSE(dec.valid());
+
+ // Set "valid" mapping
+ dec.perm()->axis(DepthwiseFilterAxis::Multiplier) = 3;
+
+ // Decoder is now valid
+ ASSERT_TRUE(dec.valid());
+
+ DepthwiseFilterShape dw_filter_shape;
+
+ dw_filter_shape.depth() = 8;
+ dw_filter_shape.multiplier() = 1;
+ dw_filter_shape.height() = 7;
+ dw_filter_shape.width() = 4;
+
+ // Get the corresponding depthwise filter shape
+ auto tensor_shape = dec.shape(dw_filter_shape);
+
+ ASSERT_EQ(tensor_shape.dim(0).value(), 8);
+ ASSERT_EQ(tensor_shape.dim(1).value(), 7);
+ ASSERT_EQ(tensor_shape.dim(2).value(), 4);
+ ASSERT_EQ(tensor_shape.dim(3).value(), 1);
+
+ // Let's find a source tensor index!
+ TensorIndex tensor_index;
+ tensor_index.resize(4);
+
+ tensor_index.at(0) = 4;
+ tensor_index.at(1) = 2;
+ tensor_index.at(2) = 1;
+ tensor_index.at(3) = 0;
+
+ auto dw_filter_index = dec.value(tensor_index);
+
+ ASSERT_EQ(dw_filter_index.channel(), 4);
+ ASSERT_EQ(dw_filter_index.nth(), 0);
+ ASSERT_EQ(dw_filter_index.row(), 2);
+ ASSERT_EQ(dw_filter_index.column(), 1);
+}