Commit eec7201d authored by Adam Procter's avatar Adam Procter Committed by GitHub

Implement function calls through VM and type checking for reduce operator (#151)

* Add reduce op class and type propagation

* Implement FunctionCall through VM

* Changes Function to require explicit return type at construction time
parent b90bea14
......@@ -29,9 +29,11 @@ set (SRC
ops/constant.cpp
ops/convert.cpp
ops/dot.cpp
ops/function_call.cpp
ops/get_tuple_element.cpp
ops/op.cpp
ops/parameter.cpp
ops/reduce.cpp
ops/select.cpp
ops/tuple.cpp
ops/unary_elementwise_arithmetic.cpp
......
......@@ -20,10 +20,12 @@ using namespace std;
using namespace ngraph;
Function::Function(const std::shared_ptr<Node>& result,
const std::shared_ptr<ValueType>& result_type,
const std::vector<std::shared_ptr<op::Parameter>>& parameters)
: m_result(result)
, m_parameters(parameters)
, m_name("Function")
, m_result_type(result_type)
{
size_t i = 0;
for (auto parameter : parameters)
......
......@@ -33,6 +33,7 @@ namespace ngraph
{
public:
Function(const std::shared_ptr<Node>& result,
const std::shared_ptr<ValueType>& result_type,
const std::vector<std::shared_ptr<op::Parameter>>& parameters);
std::shared_ptr<Node> get_result() { return m_result; }
......@@ -40,10 +41,15 @@ namespace ngraph
{
return m_parameters;
}
const std::shared_ptr<ValueType> get_result_type() const
{
return m_result_type;
}
std::string get_name() const { return m_name; }
protected:
std::shared_ptr<Node> m_result;
std::vector<std::shared_ptr<ngraph::op::Parameter>> m_parameters;
std::string m_name;
std::shared_ptr<ValueType> m_result_type;
};
}
......@@ -60,6 +60,7 @@
#include "ngraph/ops/equal.hpp"
#include "ngraph/ops/exp.hpp"
#include "ngraph/ops/floor.hpp"
#include "ngraph/ops/function_call.hpp"
#include "ngraph/ops/get_tuple_element.hpp"
#include "ngraph/ops/greater.hpp"
#include "ngraph/ops/less.hpp"
......@@ -72,6 +73,7 @@
#include "ngraph/ops/op.hpp"
#include "ngraph/ops/parameter.hpp"
#include "ngraph/ops/power.hpp"
#include "ngraph/ops/reduce.hpp"
#include "ngraph/ops/remainder.hpp"
#include "ngraph/ops/select.hpp"
#include "ngraph/ops/subtract.hpp"
......
// ----------------------------------------------------------------------------
// Copyright 2017 Nervana Systems Inc.
// 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
// ----------------------------------------------------------------------------
#include "ngraph/ngraph.hpp"
#include "ngraph/pass/topological_sort.hpp"
using namespace std;
using namespace ngraph::op;
void FunctionCall::propagate_types()
{
auto& function_params = m_function->get_parameters();
if (m_arguments.size() != function_params.size())
{
throw ngraph_error("Wrong number of arguments.");
}
for (size_t i = 0; i < m_arguments.size(); i++)
{
if (nullptr == m_arguments.at(i)->get_value_type())
{
throw ngraph_error("Function call argument is missing type.");
}
if (nullptr == function_params.at(i)->get_value_type())
{
throw ngraph_error("Function parameter is missing type.");
}
if (*(m_arguments.at(i)->get_value_type()) != *(function_params.at(i)->get_value_type()))
{
throw ngraph_error("Function argument type mismatch.");
}
}
auto f_result_type = m_function->get_result_type();
set_value_type_checked(f_result_type);
}
// ----------------------------------------------------------------------------
// Copyright 2017 Nervana Systems Inc.
// 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
// ----------------------------------------------------------------------------
#pragma once
#include "ngraph/pass/manager.hpp"
#include "ngraph/pass/propagate_types.hpp"
namespace ngraph
{
namespace op
{
class FunctionCall : public Builtin
{
public:
///
/// @param function The function to be called
/// @param args The function arguments
///
FunctionCall(const std::shared_ptr<Function>& function,
const std::vector<std::shared_ptr<Node>>& args)
: Builtin(args)
, m_function(function)
{
}
virtual std::string description() const override { return "FunctionCall"; }
virtual void propagate_types() override;
std::shared_ptr<Function> get_function() const { return m_function; }
protected:
std::shared_ptr<Function> m_function;
};
}
}
......@@ -25,16 +25,6 @@ namespace ngraph
// TODO: These class definitions are to be moved into separate files in the op directory
namespace op
{
/// A Function invokes a function on node arguments. In addition to the argument
/// we need to preserve the function.
class FunctionCall : public Node
{
virtual std::string description() const override { return "FunctionCall"; }
protected:
std::shared_ptr<Node> m_function;
};
/// The is an operation we handle directly, i.e. all type checking, etc.
/// are defined in C++ rather than in terms of ngraph operations.
class Builtin : public Node
......
// ----------------------------------------------------------------------------
// Copyright 2017 Nervana Systems Inc.
// 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
// ----------------------------------------------------------------------------
#include "ngraph/ngraph.hpp"
#include "ngraph/pass/topological_sort.hpp"
using namespace std;
using namespace ngraph::op;
void Reduce::propagate_types()
{
if (m_arguments.size() != 2)
{
throw ngraph_error("Wrong number of arguments.");
}
auto arg_reductee_type = m_arguments.at(0)->get_value_type();
if (nullptr == arg_reductee_type)
{
throw ngraph_error("Argument to reduce is missing type.");
}
auto arg_reductee_tensor_view_type = dynamic_pointer_cast<const TensorViewType>(arg_reductee_type);
if (nullptr == arg_reductee_tensor_view_type)
{
throw ngraph_error("Argument to reduce is not a tensor view");
}
auto arg_init_type = m_arguments.at(1)->get_value_type();
if (nullptr == arg_init_type)
{
throw ngraph_error("Argument for initial value is missing type.");
}
auto arg_init_tensor_view_type = dynamic_pointer_cast<const TensorViewType>(arg_init_type);
if (nullptr == arg_init_tensor_view_type)
{
throw ngraph_error("Argument for initial value is not a tensor view");
}
if (arg_init_tensor_view_type->get_shape().size() != 0)
{
throw ngraph_error("Argument for initial value is not a scalar");
}
if (arg_init_tensor_view_type->get_element_type() != arg_reductee_tensor_view_type->get_element_type())
{
throw ngraph_error("Element types for reductee and initial values do not match");
}
auto arg_reductee_shape = arg_reductee_tensor_view_type->get_shape();
for (auto axis : m_reduction_axes)
{
if (axis >= arg_reductee_shape.size())
{
throw ngraph_error("Reduction axis is out of bounds");
}
}
Shape result_shape;
for (size_t i = 0; i < arg_reductee_shape.size(); i++)
{
if (m_reduction_axes.count(i) == 0)
{
result_shape.push_back(arg_reductee_shape.at(i));
}
}
auto f_params = m_reduction_function->get_parameters();
if (f_params.size() != 2)
{
throw ngraph_error("Reduction function has wrong number of parameters (should be two)");
}
if (*(f_params.at(0)->get_value_type()) != *(arg_init_type))
{
throw ngraph_error("Argument 0 of reduction function has wrong type");
}
if (*(f_params.at(1)->get_value_type()) != *(arg_init_type))
{
throw ngraph_error("Argument 1 of reduction function has wrong type");
}
auto f_result_type = m_reduction_function->get_result_type();
if (*(f_result_type) != *(arg_init_type))
{
throw ngraph_error("Return type from reduction function does not match expected");
}
set_value_type_checked(make_shared<TensorViewType>(arg_reductee_tensor_view_type->get_element_type(), result_shape));
}
// ----------------------------------------------------------------------------
// Copyright 2017 Nervana Systems Inc.
// 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
// ----------------------------------------------------------------------------
#pragma once
namespace ngraph
{
namespace op
{
class Reduce : public Builtin
{
public:
///
/// @param arg_reductee The tensor view to be reduced.
/// @param arg_init The initial value for reduction.
/// @param reduction_function The reduction function to use.
/// @param reduction_axes The axis positions (0-based) to be reduced.
///
Reduce(const std::shared_ptr<Node>& arg_reductee,
const std::shared_ptr<Node>& arg_init,
const std::shared_ptr<Function>& reduction_function,
const AxisSet& reduction_axes)
: Builtin({arg_reductee,arg_init})
, m_reduction_function(reduction_function)
, m_reduction_axes(reduction_axes)
{
}
virtual std::string description() const override { return "Reduce"; }
virtual void propagate_types() override;
std::shared_ptr<Function> get_reduction_function() const { return m_reduction_function; }
const AxisSet& get_reduction_axes() const { return m_reduction_axes; }
protected:
std::shared_ptr<Function> m_reduction_function;
AxisSet m_reduction_axes;
};
}
}
......@@ -42,10 +42,10 @@ namespace ngraph
///
/// Tuples will be expanded into their tensor views to build the call frame.
void operator()(const std::vector<std::shared_ptr<ngraph::runtime::Value>>& inputs,
const std::vector<std::shared_ptr<ngraph::runtime::Value>>& outpus);
const std::vector<std::shared_ptr<ngraph::runtime::Value>>& outputs);
/// @brief Invoke the function with tuples pre-expanded to their underlying tensor views.
void tensor_call(const TensorViewPtrs& inputs, const TensorViewPtrs& outpus);
void tensor_call(const TensorViewPtrs& inputs, const TensorViewPtrs& outputs);
void set_return() { m_return = true; }
......
// ----------------------------------------------------------------------------
// Copyright 2017 Nervana Systems Inc.
// 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
// ----------------------------------------------------------------------------
#pragma once
#include "ngraph/runtime/call_frame.hpp"
#include "ngraph/runtime/external_function.hpp"
#include "ngraph/runtime/eigen/utils.hpp"
#include "ngraph/runtime/instruction.hpp"
#include "ngraph/runtime/tensor_view.hpp"
namespace ngraph
{
namespace runtime
{
namespace eigen
{
class CallInstruction : public Instruction
{
public:
CallInstruction(std::shared_ptr<ExternalFunction> ef,std::vector<size_t> in, std::vector<size_t> out)
: m_external_function(ef)
, m_in(in)
, m_out(out)
{
}
virtual void execute(CallFrame& call_frame) const override
{
std::shared_ptr<CallFrame> cf = m_external_function->make_call_frame();
std::vector<std::shared_ptr<ngraph::runtime::Value>> inputs;
std::vector<std::shared_ptr<ngraph::runtime::Value>> outputs;
for (auto in : m_in)
{
inputs.push_back(call_frame.get_tensor_view(in));
}
for (auto out : m_out)
{
outputs.push_back(call_frame.get_tensor_view(out));
}
(*cf)(inputs,outputs);
}
protected:
std::shared_ptr<ExternalFunction> m_external_function;
std::vector<size_t> m_in;
std::vector<size_t> m_out;
};
}
}
}
......@@ -29,6 +29,7 @@
#include "ngraph/ops/divide.hpp"
#include "ngraph/ops/dot.hpp"
#include "ngraph/ops/equal.hpp"
#include "ngraph/ops/function_call.hpp"
#include "ngraph/ops/get_tuple_element.hpp"
#include "ngraph/ops/less.hpp"
#include "ngraph/ops/log.hpp"
......@@ -36,6 +37,7 @@
#include "ngraph/ops/multiply.hpp"
#include "ngraph/ops/negative.hpp"
#include "ngraph/ops/not_equal.hpp"
#include "ngraph/ops/reduce.hpp"
#include "ngraph/ops/select.hpp"
#include "ngraph/ops/subtract.hpp"
#include "ngraph/ops/tuple.hpp"
......@@ -45,6 +47,7 @@
#include "ngraph/pass/topological_sort.hpp"
#include "ngraph/runtime/eigen/abs.hpp"
#include "ngraph/runtime/eigen/add.hpp"
#include "ngraph/runtime/eigen/call.hpp"
#include "ngraph/runtime/eigen/concat_matrix.hpp"
#include "ngraph/runtime/eigen/concat_vector.hpp"
#include "ngraph/runtime/eigen/constant.hpp"
......@@ -79,12 +82,16 @@ ExternalFunction::ExternalFunction(const std::shared_ptr<ngraph::Function>& func
{
}
#define REGISTER_INSTRUCTION(op_class, instr_class, ...) \
op_map[type_index(typeid(op_class))] = [](const Node* n, \
ExternalFunction* ef, \
const std::vector<size_t>& in, \
const std::vector<size_t>& out) { \
ef->get_instructions()->push_back(make_shared<instr_class>(__VA_ARGS__)); \
#define REGISTER_TO_OP_MAP(op_class) \
op_map[type_index(typeid(op_class))] = [](const Node* n, \
ExternalFunction* ef, \
FunctionMap& function_map, \
const std::vector<size_t>& in, \
const std::vector<size_t>& out)
#define REGISTER_INSTRUCTION(op_class, instr_class, ...) \
REGISTER_TO_OP_MAP(op_class) { \
ef->get_instructions()->push_back(make_shared<instr_class>(__VA_ARGS__)); \
}
#define REGISTER_UNOP(op_class, instr_class) \
......@@ -127,10 +134,8 @@ ExternalFunction::OpMap& ExternalFunction::get_op_map()
dynamic_cast<const op::TensorConstant<element::Float32>*>(n)->get_value()->get_vector(),
out[0]);
op_map[type_index(typeid(op::Concat))] = [](const Node* n,
ExternalFunction* ef,
const std::vector<size_t>& in,
const std::vector<size_t>& out) {
REGISTER_TO_OP_MAP(op::Concat)
{
auto result_tensor_type =
dynamic_pointer_cast<const TensorViewType>(n->get_value_type());
assert(nullptr != result_tensor_type);
......@@ -157,10 +162,8 @@ ExternalFunction::OpMap& ExternalFunction::get_op_map()
}
};
op_map[type_index(typeid(op::Dot))] = [](const Node* n,
ExternalFunction* ef,
const std::vector<size_t>& in,
const std::vector<size_t>& out) {
REGISTER_TO_OP_MAP(op::Dot)
{
auto& arg_nodes = n->get_arguments();
assert(arg_nodes.size() == 2);
......@@ -222,27 +225,21 @@ ExternalFunction::OpMap& ExternalFunction::get_op_map()
};
// Parameter is a "runtime no-op" because the output tensor has already been filled.
op_map[type_index(typeid(op::Parameter))] = [](const Node* n,
ExternalFunction* ef,
const std::vector<size_t>& in,
const std::vector<size_t>& out) {};
REGISTER_TO_OP_MAP(op::Parameter) {};
// GetTupleElement will be spliced out, with the users of out redirected to in's source, but, for now, we need to copy.
op_map[type_index(typeid(op::GetTupleElement))] = [](const Node* n,
ExternalFunction* ef,
const std::vector<size_t>& in,
const std::vector<size_t>& out) {
REGISTER_TO_OP_MAP(op::GetTupleElement)
{
auto get_tuple_element = static_cast<const op::GetTupleElement*>(n);
ef->get_instructions()->push_back(
make_shared<runtime::eigen::CopyInstruction<element::Float32>>(
in.at(get_tuple_element->get_n()), out.at(0)));
};
// Tuple will be spliced out, with the users of out connected to the corresponding in's source, but, for now, we need to copy.
op_map[type_index(typeid(op::Tuple))] = [](const Node* n,
ExternalFunction* ef,
const std::vector<size_t>& in,
const std::vector<size_t>& out) {
REGISTER_TO_OP_MAP(op::Tuple)
{
for (size_t i = 0; i < in.size(); ++i)
{
ef->get_instructions()->push_back(
......@@ -251,12 +248,39 @@ ExternalFunction::OpMap& ExternalFunction::get_op_map()
}
};
REGISTER_TO_OP_MAP(op::FunctionCall)
{
auto function_call = static_cast<const op::FunctionCall*>(n);
auto function = function_call->get_function();
std::shared_ptr<ExternalFunction> external;
try
{
external = function_map.at(function);
}
catch (const std::out_of_range)
{
external = make_shared<ngraph::runtime::ExternalFunction>(
function_call->get_function());
function_map.insert({function,external});
}
ef->get_instructions()->push_back(
make_shared<runtime::eigen::CallInstruction>(external,in,out));
};
REGISTER_TO_OP_MAP(op::Reduce)
{
throw ngraph_error("op::Reduce not implemented yet");
};
initialized = true;
}
return op_map;
}
void ExternalFunction::compile()
void ExternalFunction::compile(FunctionMap& function_map)
{
if (m_is_compiled)
{
......@@ -331,7 +355,7 @@ void ExternalFunction::compile()
auto tv = output.get_tensor_view();
out.push_back(tensor_index.at(tv));
}
handler_it->second(node, this, in, out);
handler_it->second(node, this, function_map, in, out);
}
m_instructions->push_back(make_shared<runtime::eigen::ReturnInstruction>());
m_is_compiled = true;
......@@ -342,10 +366,16 @@ void ExternalFunction::compile()
}
shared_ptr<ngraph::runtime::CallFrame> ExternalFunction::make_call_frame()
{
FunctionMap function_map;
return make_call_frame(function_map);
}
shared_ptr<ngraph::runtime::CallFrame> ExternalFunction::make_call_frame(FunctionMap& function_map)
{
if (!m_is_compiled)
{
compile();
compile(function_map);
}
std::vector<std::shared_ptr<ngraph::runtime::TensorView>> temps;
for (auto tv : m_temp_views)
......
......@@ -27,16 +27,20 @@ namespace ngraph
{
class ExternalFunction
{
using OpFunction = std::function<void(const ngraph::Node*,
ExternalFunction*,
const std::vector<size_t>& inputs,
const std::vector<size_t>& outputs)>;
using OpMap = std::unordered_map<std::type_index, OpFunction>;
using FunctionMap = std::unordered_map<std::shared_ptr<Function>,std::shared_ptr<ExternalFunction>>;
using OpFunction = std::function<void(const ngraph::Node*,
ExternalFunction*,
FunctionMap&,
const std::vector<size_t>& inputs,
const std::vector<size_t>& outputs)>;
using OpMap = std::unordered_map<std::type_index, OpFunction>;
public:
ExternalFunction(const std::shared_ptr<ngraph::Function>& function,
bool release_function = true);
std::shared_ptr<ngraph::runtime::CallFrame> make_call_frame();
std::shared_ptr<ngraph::runtime::CallFrame> make_call_frame(FunctionMap& function_map);
std::shared_ptr<std::vector<std::shared_ptr<ngraph::runtime::Instruction>>>
get_instructions()
{
......@@ -48,6 +52,7 @@ namespace ngraph
protected:
void compile();
void compile(FunctionMap& function_map);
std::shared_ptr<ngraph::Function> m_function;
bool m_release_function;
......
......@@ -33,7 +33,8 @@ TEST(build_graph, build_simple)
ASSERT_EQ(dot->get_arguments()[0], arg2);
ASSERT_EQ(dot->get_arguments()[1], arg0);
auto cluster_0 = make_shared<Function>(dot, op::Parameters{arg0, arg1, arg2, arg3});
auto result_type = make_shared<TensorViewType>(element::Float32::element_type(), Shape{10,32,7});
auto cluster_0 = make_shared<Function>(dot, result_type, op::Parameters{arg0, arg1, arg2, arg3});
ASSERT_EQ(cluster_0->get_result(), dot);
}
......
This diff is collapsed.
......@@ -44,7 +44,8 @@ TEST(tensor, size)
{
auto arg0 = make_shared<op::Parameter>(element::Float32::element_type(), Shape{2, 3});
auto add = make_shared<op::Add>(arg0, arg0);
auto f0 = make_shared<Function>(add, op::Parameters{arg0});
auto rt = make_shared<TensorViewType>(element::Float32::element_type(), Shape{2, 3});
auto f0 = make_shared<Function>(add, rt, op::Parameters{arg0});
pass_manager.run_passes(f0);
......@@ -57,7 +58,8 @@ TEST(tensor, size)
{
auto arg0 = make_shared<op::Parameter>(element::Float32::element_type(), Shape{});
auto add = make_shared<op::Add>(arg0, arg0);
auto f0 = make_shared<Function>(add, op::Parameters{arg0});
auto rt = make_shared<TensorViewType>(element::Float32::element_type(), Shape{});
auto f0 = make_shared<Function>(add, rt, op::Parameters{arg0});
pass_manager.run_passes(f0);
......@@ -70,7 +72,8 @@ TEST(tensor, size)
{
auto arg0 = make_shared<op::Parameter>(element::Float32::element_type(), Shape{1});
auto add = make_shared<op::Add>(arg0, arg0);
auto f0 = make_shared<Function>(add, op::Parameters{arg0});
auto rt = make_shared<TensorViewType>(element::Float32::element_type(), Shape{1});
auto f0 = make_shared<Function>(add, rt, op::Parameters{arg0});
pass_manager.run_passes(f0);
......
......@@ -71,7 +71,9 @@ shared_ptr<Function> make_test_graph()
auto r0 = make_shared<op::Add>(t3, t4);
auto f0 = make_shared<Function>(r0, op::Parameters{arg_0, arg_1, arg_2, arg_3, arg_4, arg_5});
auto rt = make_shared<TensorViewType>(element::Float32::element_type(), Shape{});
auto f0 = make_shared<Function>(r0, rt, op::Parameters{arg_0, arg_1, arg_2, arg_3, arg_4, arg_5});
return f0;
}
......
......@@ -35,7 +35,7 @@ TEST(topological_sort, basic)
vector<shared_ptr<op::Parameter>> args;
for (int i = 0; i < 10; i++)
{
auto arg = make_shared<op::Parameter>(element::Float32::element_type(), Shape{1});
auto arg = make_shared<op::Parameter>(element::Float32::element_type(), Shape{});
ASSERT_NE(nullptr, arg);
args.push_back(arg);
}
......@@ -55,7 +55,10 @@ TEST(topological_sort, basic)
auto r0 = make_shared<op::Add>(t3, t4);
ASSERT_NE(nullptr, r0);
auto f0 = make_shared<Function>(r0, args);
auto rt = make_shared<TensorViewType>(element::Float32::element_type(), Shape{});
ASSERT_NE(nullptr, rt);
auto f0 = make_shared<Function>(r0, rt, args);
ASSERT_NE(nullptr, f0);
ASSERT_EQ(2, r0->get_arguments().size());
......@@ -102,16 +105,17 @@ TEST(benchmark, topological_sort)
// x[i+1] = tanh(dot(W,x[i])+b)
shared_ptr<Node> result;
vector<shared_ptr<op::Parameter>> args;
result = make_shared<op::Parameter>(element::Float32::element_type(), Shape{1});
result = make_shared<op::Parameter>(element::Float32::element_type(), Shape{});
for (int i=0; i<1000000; i++)
{
auto in_1 = make_shared<op::Parameter>(element::Float32::element_type(), Shape{1});
auto in_2 = make_shared<op::Parameter>(element::Float32::element_type(), Shape{1});
auto in_1 = make_shared<op::Parameter>(element::Float32::element_type(), Shape{});
auto in_2 = make_shared<op::Parameter>(element::Float32::element_type(), Shape{});
args.push_back(in_1);
args.push_back(in_2);
result = make_cell(result, in_1, in_2);
}
auto f0 = make_shared<Function>(result, args);
auto rt = make_shared<TensorViewType>(element::Float32::element_type(), Shape{});
auto f0 = make_shared<Function>(result, rt, args);
timer.start();
pass::Manager pass_manager;
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment