mindspore/tests/ut/cpp/mindapi/mindapi_test.cc

422 lines
14 KiB
C++

/**
* Copyright 2021 Huawei Technologies Co., Ltd
*
* 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 <cmath>
#include <memory>
#include <sstream>
#include <unordered_map>
#include "common/common_test.h"
#include "mindapi/base/logging.h"
#include "mindapi/ir/func_graph.h"
#include "mindapi/ir/tensor.h"
#include "mindapi/ir/utils.h"
namespace mindspore::api {
class TestMindApi : public UT::Common {
public:
TestMindApi() = default;
};
/// Feature: MindAPI
/// Description: test basic 'is()' 'cast()'
/// Expectation: is/cast works correctly.
TEST_F(TestMindApi, test_base_isa_cast) {
auto value_node = MakeShared<ValueNode>(MakeValue(0));
auto base = MakeShared<Base>(value_node->impl());
ASSERT_TRUE(base->isa<Base>());
ASSERT_TRUE(base->isa<AnfNode>());
ASSERT_TRUE(base->isa<ValueNode>());
ASSERT_FALSE(base->isa<AbstractBase>());
auto anf_node = base->cast<AnfNodePtr>();
ASSERT_TRUE(anf_node != nullptr);
ASSERT_TRUE(anf_node->impl() == value_node->impl());
ASSERT_TRUE(base->cast<AbstractBasePtr>() == nullptr);
}
/// Feature: MindAPI
/// Description: test graph construction.
/// Expectation: graph is constructed as expected.
TEST_F(TestMindApi, test_graph_construction) {
// fg(x) { return myprim(x, 1); }
auto fg = FuncGraph::Create();
auto x = fg->add_parameter();
x->set_name("x");
auto prim = MakeShared<Primitive>("myprim");
auto prim_node = MakeShared<ValueNode>(prim);
auto value_node = MakeShared<ValueNode>(MakeValue(1));
auto cnode = fg->NewCNode({prim_node, x, value_node});
fg->set_output(cnode);
// Now we check the graph.
ASSERT_EQ(fg->parameters().size(), 1);
ASSERT_TRUE(fg->parameters()[0]->isa<Parameter>());
ASSERT_EQ(fg->parameters()[0]->cast<ParameterPtr>()->name(), "x");
auto ret_node = fg->get_return();
ASSERT_TRUE(ret_node != nullptr);
auto output_node = fg->output();
ASSERT_TRUE(output_node != nullptr);
ASSERT_TRUE(output_node->isa<CNode>());
auto output_cnode = output_node->cast<CNodePtr>();
ASSERT_EQ(output_cnode->inputs().size(), 3);
ASSERT_TRUE(output_cnode->input(0)->isa<ValueNode>());
ASSERT_TRUE(output_cnode->input(0)->cast<ValueNodePtr>()->value()->isa<Primitive>());
ASSERT_EQ(output_cnode->input(0)->cast<ValueNodePtr>()->value()->cast<PrimitivePtr>()->name(), "myprim");
ASSERT_TRUE(output_cnode->input(1)->isa<Parameter>());
ASSERT_EQ(output_cnode->input(1)->cast<ParameterPtr>()->name(), "x");
ASSERT_TRUE(output_cnode->input(2)->isa<ValueNode>());
ASSERT_EQ(output_cnode->impl(), cnode->impl());
}
/// Feature: MindAPI
/// Description: test value related functions.
/// Expectation: value related functions work as expected.
TEST_F(TestMindApi, test_values) {
int64_t one = 1;
auto s = MakeValue("hello");
auto i = MakeValue(one);
auto i2 = MakeValue(2);
auto b = MakeValue(true);
auto f = MakeValue(3.14f);
auto seq = MakeValue(std::vector<int64_t>{3, 4, 5});
auto seq_str = MakeValue(std::vector<std::string>({"this", "is", "mindspore", "api"}));
ASSERT_TRUE(s->isa<StringImm>());
ASSERT_TRUE(i->isa<Int64Imm>());
ASSERT_TRUE(i2->isa<Int64Imm>());
ASSERT_TRUE(b->isa<BoolImm>());
ASSERT_TRUE(f->isa<FP32Imm>());
ASSERT_TRUE(seq->isa<ValueSequence>());
ASSERT_TRUE(seq_str->isa<ValueSequence>());
ASSERT_EQ(GetValue<std::string>(s), "hello");
ASSERT_EQ(GetValue<int64_t>(i), one);
ASSERT_EQ(GetValue<int64_t>(i2), 2);
ASSERT_TRUE(GetValue<bool>(b));
ASSERT_TRUE(std::abs(GetValue<float>(f) - 3.14f) < 0.00001f);
ASSERT_EQ(GetValue<std::string>(i), "");
ASSERT_EQ(GetValue<int64_t>(s), 0);
ASSERT_FALSE(GetValue<bool>(s));
ASSERT_EQ(GetValue<float>(s), 0.0f);
auto seq_ptr = seq->cast<ValueSequencePtr>();
ASSERT_TRUE(seq_ptr != nullptr);
ASSERT_EQ(seq_ptr->size(), 3);
ASSERT_EQ(seq_ptr->value().size(), 3);
ASSERT_TRUE(seq_ptr->value()[0]->isa<Int64Imm>());
ASSERT_EQ(GetValue<int64_t>(seq_ptr->value()[0]), 3);
ASSERT_EQ(GetValue<int64_t>(seq_ptr->value()[1]), 4);
ASSERT_EQ(GetValue<int64_t>(seq_ptr->value()[2]), 5);
auto seq_values = GetValue<std::vector<int64_t>>(seq);
ASSERT_EQ(seq_values.size(), 3);
ASSERT_EQ(seq_values[0], 3);
ASSERT_EQ(seq_values[1], 4);
ASSERT_EQ(seq_values[2], 5);
auto str_values = GetValue<std::vector<std::string>>(seq_str);
ASSERT_EQ(str_values.size(), 4);
ASSERT_EQ(str_values[0], "this");
ASSERT_EQ(str_values[1], "is");
ASSERT_EQ(str_values[2], "mindspore");
ASSERT_EQ(str_values[3], "api");
auto value_list = GetValue<ValuePtrList>(seq);
ASSERT_EQ(value_list.size(), 3);
ASSERT_EQ(utils::cast<int64_t>(value_list[0]), 3);
ASSERT_EQ(utils::cast<int64_t>(value_list[1]), 4);
ASSERT_EQ(utils::cast<int64_t>(value_list[2]), 5);
std::vector<uint8_t> vec_uint8{5, 6, 7};
auto uint8_seq = MakeValue<std::vector<uint8_t>>(vec_uint8);
ASSERT_TRUE(uint8_seq->isa<ValueSequence>());
auto uint8_values = GetValue<std::vector<uint8_t>>(uint8_seq);
ASSERT_EQ(uint8_values.size(), 3);
ASSERT_EQ(uint8_values[0], 5);
ASSERT_EQ(uint8_values[1], 6);
ASSERT_EQ(uint8_values[2], 7);
}
/// Feature: MindAPI
/// Description: test graph manager functions.
/// Expectation: graph manager functions work as expected.
TEST_F(TestMindApi, test_func_graph_manager) {
// fg(x, y) { return myprim(add(x, y), 1); }
auto fg = FuncGraph::Create();
auto x = fg->add_parameter();
x->set_name("x");
auto y = fg->add_parameter();
y->set_name("y");
auto add = MakeShared<Primitive>("add");
auto add_node = MakeShared<ValueNode>(add);
auto add_cnode = fg->NewCNode({add_node, x, y});
auto prim = MakeShared<Primitive>("myprim");
auto prim_node = MakeShared<ValueNode>(prim);
auto value_node = MakeShared<ValueNode>(MakeValue(1));
auto cnode = fg->NewCNode({prim_node, add_cnode, value_node});
fg->set_output(cnode);
auto mgr = FuncGraphManager::Manage(fg);
ASSERT_TRUE(mgr != nullptr);
ASSERT_TRUE(fg->manager() != nullptr);
ASSERT_EQ(fg->manager()->impl(), mgr->impl());
ASSERT_EQ(fg->manager(), mgr);
ASSERT_EQ(cnode->input(1)->impl(), add_cnode->impl());
mgr->Replace(add_cnode, x);
ASSERT_EQ(cnode->input(1)->impl(), x->impl());
mgr->SetEdge(cnode, 1, y);
ASSERT_EQ(cnode->input(1)->impl(), y->impl());
mgr->AddEdge(cnode, x);
ASSERT_EQ(cnode->size(), 4);
ASSERT_EQ(cnode->input(3)->impl(), x->impl());
auto users = mgr->GetUsers(value_node);
ASSERT_EQ(users.size(), 1);
ASSERT_EQ(users[0].first, cnode);
ASSERT_EQ(users[0].second, 2);
}
/// Feature: MindAPI
/// Description: test value node utils.
/// Expectation: value node utils work as expected.
TEST_F(TestMindApi, test_value_node_utils) {
auto fg = FuncGraph::Create();
auto fg_node = MakeShared<ValueNode>(fg);
auto prim = MakeShared<Primitive>("myprim");
auto prim_node = MakeShared<ValueNode>(prim);
auto one = MakeShared<ValueNode>(MakeValue(1));
auto cnode = fg->NewCNode({fg_node, prim_node, one});
ASSERT_TRUE(GetValueNode<FuncGraphPtr>(cnode) == nullptr);
auto fg1 = GetValueNode<FuncGraphPtr>(cnode->input(0));
ASSERT_TRUE(fg1 != nullptr);
ASSERT_TRUE(fg1->isa<FuncGraph>());
auto prim1 = GetValueNode<PrimitivePtr>(cnode->input(1));
ASSERT_TRUE(prim1 != nullptr);
ASSERT_TRUE(prim1->isa<Primitive>());
auto imm = GetValueNode<Int64ImmPtr>(cnode->input(2));
ASSERT_TRUE(imm != nullptr);
ASSERT_TRUE(imm->isa<Int64Imm>());
ASSERT_EQ(imm->cast<Int64ImmPtr>()->value(), 1);
auto value = GetValueNode(cnode->input(2));
ASSERT_TRUE(value != nullptr);
ASSERT_EQ(GetValue<int64_t>(value), 1);
ASSERT_TRUE(GetValueNode<PrimitivePtr>(cnode->input(0)) == nullptr);
ASSERT_TRUE(GetValueNode<FuncGraphPtr>(cnode->input(1)) == nullptr);
ASSERT_TRUE(GetValueNode<StringImmPtr>(cnode->input(2)) == nullptr);
// Test NewValueNode.
auto int_node = NewValueNode(1);
auto bool_node = NewValueNode(true);
auto float_node = NewValueNode(1.23f);
auto str_node = NewValueNode("hello");
ASSERT_TRUE(int_node->value()->isa<Int64Imm>());
ASSERT_EQ(int_node->value()->cast<Int64ImmPtr>()->value(), 1);
ASSERT_TRUE(bool_node->value()->isa<BoolImm>());
ASSERT_TRUE(bool_node->value()->cast<BoolImmPtr>()->value());
ASSERT_TRUE(float_node->value()->isa<FP32Imm>());
ASSERT_TRUE(std::abs(float_node->value()->cast<FP32ImmPtr>()->value() - 1.23f) < 0.0000001f);
ASSERT_TRUE(str_node->value()->isa<StringImm>());
ASSERT_EQ(str_node->value()->cast<StringImmPtr>()->value(), "hello");
}
/// Feature: MindAPI
/// Description: test SharedPtr.
/// Expectation: SharedPtr work as expected.
TEST_F(TestMindApi, test_object_ptr) {
auto fg = FuncGraph::Create();
auto fg_node = MakeShared<ValueNode>(fg);
auto prim = MakeShared<Primitive>("myprim");
auto prim_node = MakeShared<ValueNode>(prim);
auto one = MakeShared<ValueNode>(MakeValue(1));
auto cnode = fg->NewCNode({fg_node, prim_node, one});
ASSERT_TRUE(fg != nullptr);
ASSERT_FALSE(!fg);
ASSERT_TRUE(fg ? true : false);
ASSERT_TRUE((*cnode).input(0) == fg_node);
ASSERT_TRUE(cnode->input(0) == fg_node);
ASSERT_TRUE(cnode.get()->input(0) == fg_node);
ASSERT_EQ(cnode->input(0), fg_node);
ASSERT_EQ(cnode->input(1), prim_node);
ASSERT_EQ(cnode->input(2), one);
ASSERT_TRUE(cnode->input(0) != fg);
AnfNodePtr p = fg_node;
ASSERT_TRUE(p == fg_node);
ASSERT_TRUE(p->isa<ValueNode>());
ASSERT_TRUE(p->cast<ValueNodePtr>() != nullptr);
ASSERT_TRUE(p->cast<ValueNodePtr>() == fg_node);
p = cnode;
ASSERT_TRUE(p == cnode);
ASSERT_TRUE(p->isa<CNode>());
ASSERT_TRUE(p->cast<CNodePtr>() != nullptr);
ASSERT_TRUE(p->cast<CNodePtr>() == cnode);
ASSERT_TRUE(p.get() == cnode.get());
ASSERT_TRUE(p != nullptr);
ASSERT_FALSE(p == nullptr);
ASSERT_TRUE(p > nullptr);
ASSERT_FALSE(p < nullptr);
ASSERT_TRUE(p >= nullptr);
ASSERT_FALSE(p <= nullptr);
ASSERT_TRUE(nullptr != p);
ASSERT_FALSE(nullptr == p);
ASSERT_TRUE(nullptr < p);
ASSERT_FALSE(nullptr > p);
ASSERT_TRUE(nullptr <= p);
ASSERT_FALSE(nullptr >= p);
AnfNodePtr q = fg_node;
ASSERT_TRUE(p != q);
if (p.get()->impl() > q.get()->impl()) {
ASSERT_TRUE(p > q);
ASSERT_TRUE(p >= q);
ASSERT_TRUE(q < p);
ASSERT_TRUE(q <= p);
} else {
ASSERT_TRUE(p < q);
ASSERT_TRUE(p <= q);
ASSERT_TRUE(q > p);
ASSERT_TRUE(q >= p);
}
std::stringstream ss1;
std::stringstream ss2;
ss1 << p;
ss2 << cnode.get()->impl().get();
ASSERT_EQ(ss1.str(), ss2.str());
std::unordered_map<AnfNodePtr, AnfNodePtr> mymap;
mymap.emplace(p, q);
mymap.emplace(q, p);
ASSERT_TRUE(mymap.find(p) != mymap.end());
ASSERT_TRUE(mymap.find(q) != mymap.end());
ASSERT_TRUE(mymap[p] == q);
ASSERT_TRUE(mymap[q] == p);
}
/// Feature: MindAPI
/// Description: test Tensor API.
/// Expectation: Tensor API work as expected.
TEST_F(TestMindApi, test_tensor_api) {
ShapeVector shape{1, 2, 3};
auto tensor = MakeShared<Tensor>(kNumberTypeFloat32, shape);
ASSERT_EQ(tensor->data_type(), kNumberTypeFloat32);
ASSERT_EQ(tensor->shape(), shape);
ASSERT_EQ(tensor->DataSize(), 6);
ASSERT_EQ(tensor->Size(), 24);
ShapeVector shape2{2, 3};
tensor->set_data_type(kNumberTypeInt32);
tensor->set_shape(shape2);
ASSERT_EQ(tensor->data_type(), kNumberTypeInt32);
ASSERT_EQ(tensor->shape(), shape2);
// TensorType.
TypePtr tensor_type = MakeShared<TensorType>(Type::GetType(TypeId::kNumberTypeFloat32));
ASSERT_TRUE(tensor_type->isa<TensorType>());
ASSERT_EQ(tensor_type->cast<TensorTypePtr>()->element()->type_id(), kNumberTypeFloat32);
}
/// Feature: MindAPI
/// Description: test utils API.
/// Expectation: Tensor API work as expected.
TEST_F(TestMindApi, test_api_utils) {
// Test utils::isa, utils::cast.
auto anf_node = NewValueNode("hello");
ASSERT_TRUE(utils::isa<AnfNode>(anf_node));
ASSERT_TRUE(utils::isa<AnfNodePtr>(anf_node));
ASSERT_FALSE(utils::isa<AbstractBase>(anf_node));
ASSERT_TRUE(utils::cast<AnfNodePtr>(anf_node) != nullptr);
ASSERT_TRUE(utils::cast<AbstractBasePtr>(anf_node) == nullptr);
ASSERT_TRUE(utils::isa<std::string>(anf_node->value()));
ASSERT_EQ(utils::cast<std::string>(anf_node->value()), "hello");
auto int_value = MakeValue(123);
ASSERT_TRUE(utils::isa<int64_t>(int_value));
ASSERT_EQ(utils::cast<int64_t>(int_value), 123);
anf_node = nullptr;
ASSERT_FALSE(utils::isa<AnfNode>(anf_node));
ASSERT_FALSE(utils::isa<AnfNodePtr>(anf_node));
ASSERT_TRUE(utils::cast<AnfNodePtr>(anf_node) == nullptr);
// Test clone graph.
auto fg = FuncGraph::Create();
auto x = fg->add_parameter();
x->set_name("x");
auto y = fg->add_parameter();
y->set_name("y");
auto add = MakeShared<Primitive>("add");
auto add_node = MakeShared<ValueNode>(add);
auto add_cnode = fg->NewCNode({add_node, x, y});
auto prim = MakeShared<Primitive>("myprim");
auto prim_node = MakeShared<ValueNode>(prim);
auto value_node = MakeShared<ValueNode>(MakeValue(1));
auto cnode = fg->NewCNode({prim_node, add_cnode, value_node});
fg->set_output(cnode);
auto cloned_fg = utils::CloneGraph(fg);
ASSERT_TRUE(cloned_fg != nullptr);
ASSERT_EQ(cloned_fg->parameters().size(), 2);
auto new_output = cloned_fg->output();
ASSERT_TRUE(new_output != nullptr);
ASSERT_TRUE(new_output->isa<CNode>());
ASSERT_EQ(new_output->cast<CNodePtr>()->size(), cnode->size());
ASSERT_TRUE(new_output != cnode);
ASSERT_TRUE(new_output->cast<CNodePtr>() != cnode);
// Test get pad mode.
auto pm_lower = MakeValue("pad");
auto pm_upper = MakeValue("PAD");
ASSERT_EQ(utils::GetPadMode(pm_lower), 0);
ASSERT_EQ(utils::GetPadMode(pm_lower, false), 0);
ASSERT_EQ(utils::GetPadMode(pm_upper, true), 0);
}
/// Feature: MindAPI
/// Description: test logging API.
/// Expectation: logging work as expected.
TEST_F(TestMindApi, test_api_logging) {
MS_LOG(DEBUG) << "hello debug";
MS_LOG(INFO) << "hello info";
MS_LOG(WARNING) << "hello warning";
MS_LOG(ERROR) << "hello error";
try {
MS_LOG(EXCEPTION) << "hello exception";
ASSERT_TRUE(false);
} catch (...) {
}
ASSERT_TRUE(true);
}
} // namespace mindspore::api