summaryrefslogtreecommitdiff
path: root/compiler/luci/service/src/CircleShapeInferenceRule.test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/luci/service/src/CircleShapeInferenceRule.test.cpp')
-rw-r--r--compiler/luci/service/src/CircleShapeInferenceRule.test.cpp282
1 files changed, 282 insertions, 0 deletions
diff --git a/compiler/luci/service/src/CircleShapeInferenceRule.test.cpp b/compiler/luci/service/src/CircleShapeInferenceRule.test.cpp
new file mode 100644
index 000000000..0374251a0
--- /dev/null
+++ b/compiler/luci/service/src/CircleShapeInferenceRule.test.cpp
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2020 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 "TestGraph.h"
+#include "luci/Service/CircleShapeInferenceRule.h"
+
+#include <luci/IR/CircleNodes.h>
+#include <luci/IR/CircleDialect.h>
+
+#include <loco.h>
+#include <loco/IR/CanonicalDialect.h>
+#include <loco/Service/ShapeInference.h>
+#include <loco/Service/CanonicalShapeInferenceRule.h>
+#include <loco/Service/MultiDialectShapeInferenceRule.h>
+
+#include <gtest/gtest.h>
+
+#include <memory>
+
+namespace
+{
+
+bool shape_pass(loco::Graph *g)
+{
+ loco::CanonicalShapeInferenceRule canonical_rule;
+ luci::CircleShapeInferenceRule circle_rule;
+ loco::MultiDialectShapeInferenceRule rules;
+
+ rules.bind(loco::CanonicalDialect::get(), &canonical_rule)
+ .bind(luci::CircleDialect::get(), &circle_rule);
+
+ return loco::apply(&rules).to(g);
+}
+
+} // namespace
+
+TEST(CircleShapeInferenceRuleTest, minimal_with_CircleRelu)
+{
+ // Create a simple network
+ luci::test::TestGraph graph;
+ auto tfl_node = graph.append<luci::CircleRelu>(graph.pull);
+ graph.complete(tfl_node);
+
+ // set shape
+ {
+ graph.pull->rank(2);
+ graph.pull->dim(0) = 3;
+ graph.pull->dim(1) = 4;
+ }
+
+ // pre-check
+ ASSERT_FALSE(loco::shape_known(tfl_node));
+
+ // shape inference
+ luci::CircleShapeInferenceRule tfl_rule;
+ loco::CanonicalShapeInferenceRule canonical_rule;
+ loco::MultiDialectShapeInferenceRule rules;
+
+ rules.bind(loco::CanonicalDialect::get(), &canonical_rule)
+ .bind(luci::CircleDialect::get(), &tfl_rule);
+
+ loco::apply(&rules).to(graph.g.get());
+
+ // Verify
+ {
+ ASSERT_TRUE(loco::shape_known(tfl_node));
+ ASSERT_EQ(loco::shape_get(tfl_node).domain(), loco::Domain::Tensor);
+
+ auto shape = loco::shape_get(tfl_node).as<loco::TensorShape>();
+ ASSERT_EQ(shape.rank(), 2);
+ ASSERT_EQ(shape.dim(0), 3);
+ ASSERT_EQ(shape.dim(1), 4);
+ }
+}
+
+// based on the case shown in
+// https://www.corvil.com/kb/what-is-the-difference-between-same-and-valid-padding-in-tf-nn-max-pool-of-tensorflow
+TEST(CircleShapeInferenceRuleTest, avgpool2d_valid)
+{
+ luci::test::TestGraph graph;
+ auto tfl_node = graph.append<luci::CircleAveragePool2D>(graph.pull);
+ graph.complete();
+
+ auto pull = graph.pull;
+ {
+ pull->shape({1, 4, 3, 1});
+ }
+ // setting CircleAveragePool2D
+ {
+ tfl_node->filter()->h(2);
+ tfl_node->filter()->w(2);
+ tfl_node->stride()->h(2);
+ tfl_node->stride()->w(2);
+ tfl_node->fusedActivationFunction(luci::FusedActFunc::NONE);
+ tfl_node->padding(luci::Padding::VALID);
+ }
+ ASSERT_FALSE(loco::shape_known(tfl_node));
+
+ // shape inference
+ luci::CircleShapeInferenceRule tfl_rule;
+ loco::CanonicalShapeInferenceRule canonical_rule;
+ loco::MultiDialectShapeInferenceRule rules;
+
+ rules.bind(loco::CanonicalDialect::get(), &canonical_rule)
+ .bind(luci::CircleDialect::get(), &tfl_rule);
+
+ loco::apply(&rules).to(graph.g.get());
+
+ // Verify
+ {
+ ASSERT_TRUE(loco::shape_known(tfl_node));
+ ASSERT_EQ(loco::shape_get(tfl_node).domain(), loco::Domain::Tensor);
+
+ auto shape = loco::shape_get(tfl_node).as<loco::TensorShape>();
+ ASSERT_EQ(shape.rank(), 4);
+ ASSERT_EQ(shape.dim(0).value(), 1);
+ ASSERT_EQ(shape.dim(1).value(), 2);
+ ASSERT_EQ(shape.dim(2).value(), 1);
+ ASSERT_EQ(shape.dim(3).value(), 1);
+ }
+}
+
+TEST(CircleShapeInferenceRuleTest, avgpool2d_same)
+{
+ luci::test::TestGraph graph;
+ auto tfl_node = graph.append<luci::CircleAveragePool2D>(graph.pull);
+ graph.complete();
+
+ auto pull = graph.pull;
+ {
+ pull->shape({1, 4, 3, 1});
+ }
+
+ // setting CircleAveragePool2D
+ {
+ tfl_node->filter()->h(2);
+ tfl_node->filter()->w(2);
+ tfl_node->stride()->h(2);
+ tfl_node->stride()->w(2);
+ tfl_node->fusedActivationFunction(luci::FusedActFunc::NONE);
+ tfl_node->padding(luci::Padding::SAME);
+ }
+
+ ASSERT_FALSE(loco::shape_known(tfl_node));
+
+ // shape inference
+ shape_pass(graph.g.get());
+
+ // Verify
+ {
+ ASSERT_TRUE(loco::shape_known(tfl_node));
+ ASSERT_EQ(loco::shape_get(tfl_node).domain(), loco::Domain::Tensor);
+
+ auto shape = loco::shape_get(tfl_node).as<loco::TensorShape>();
+ ASSERT_EQ(shape.rank(), 4);
+ ASSERT_EQ(shape.dim(0).value(), 1);
+ ASSERT_EQ(shape.dim(1).value(), 2);
+ ASSERT_EQ(shape.dim(2).value(), 2);
+ ASSERT_EQ(shape.dim(3).value(), 1);
+ }
+}
+
+/**
+ * @note Function to test: Shape inference of two different input shapes
+ *
+ * Rank expansion to higher input side
+ * x(2,1,5) + y(3,5) --> x(2,1,5) + y(1,3,5)
+ * Do output shape inference like numpy
+ * x(2,1,5) + y(1,3,5) --> output(2,3,5)
+ * For each axis, dim value should be same OR one of them should be 1
+ */
+TEST(CircleShapeInferenceRuleTest, TFAdd_shapeinf_different)
+{
+ auto g = loco::make_graph();
+
+ auto x_node = g->nodes()->create<loco::Pull>();
+ {
+ x_node->rank(3);
+ x_node->dim(0) = 2;
+ x_node->dim(1) = 1;
+ x_node->dim(2) = 5;
+ }
+ auto y_node = g->nodes()->create<loco::Pull>();
+ {
+ y_node->rank(2);
+ y_node->dim(0) = 3;
+ y_node->dim(1) = 5;
+ }
+ auto tfl_node = g->nodes()->create<luci::CircleAdd>();
+ {
+ tfl_node->x(x_node);
+ tfl_node->y(y_node);
+ }
+ auto push_node = g->nodes()->create<loco::Push>();
+ {
+ push_node->from(tfl_node);
+ }
+
+ auto x_input = g->inputs()->create();
+ {
+ x_input->name("x");
+ loco::link(x_input, x_node);
+ }
+ auto y_input = g->inputs()->create();
+ {
+ y_input->name("y");
+ loco::link(y_input, y_node);
+ }
+ auto output = g->outputs()->create();
+ {
+ output->name("output");
+ loco::link(output, push_node);
+ }
+
+ // pre-check
+ ASSERT_FALSE(loco::shape_known(tfl_node));
+
+ // shape inference
+ while (shape_pass(g.get()) == true)
+ ;
+
+ // Verify
+ {
+ ASSERT_TRUE(loco::shape_known(tfl_node));
+ ASSERT_EQ(loco::shape_get(tfl_node).domain(), loco::Domain::Tensor);
+
+ auto shape = loco::shape_get(tfl_node).as<loco::TensorShape>();
+ ASSERT_EQ(shape.rank(), 3);
+ ASSERT_EQ(shape.dim(0), 2);
+ ASSERT_EQ(shape.dim(1), 3);
+ ASSERT_EQ(shape.dim(2), 5);
+ }
+}
+
+TEST(CircleShapeInferenceRuleTest, CircleTranspose_simple)
+{
+ luci::test::ExampleGraph<luci::test::ExampleGraphType::CircleTranspose> g;
+
+ g.pull->rank(3);
+ g.pull->dim(0) = 3;
+ g.pull->dim(1) = 8;
+ g.pull->dim(2) = 1;
+
+ g.const_perm->dtype(loco::DataType::S32);
+ g.const_perm->rank(1);
+ g.const_perm->dim(0) = 3;
+ g.const_perm->size<loco::DataType::S32>(3);
+ g.const_perm->at<loco::DataType::S32>(0) = 1;
+ g.const_perm->at<loco::DataType::S32>(1) = 2;
+ g.const_perm->at<loco::DataType::S32>(2) = 0;
+
+ // pre-check
+ ASSERT_FALSE(loco::shape_known(g.transpose_node));
+
+ // shape inference
+ while (shape_pass(g.graph()) == true)
+ ;
+
+ // Verify
+ {
+ ASSERT_TRUE(loco::shape_known(g.transpose_node));
+
+ auto shape = loco::shape_get(g.transpose_node).as<loco::TensorShape>();
+ ASSERT_EQ(shape.rank(), 3);
+ ASSERT_EQ(shape.dim(0), 8);
+ ASSERT_EQ(shape.dim(1), 1);
+ ASSERT_EQ(shape.dim(2), 3);
+ }
+}