Commit 2c30e819 authored by Scott Cyphers's avatar Scott Cyphers Committed by GitHub

Merge pull request #63 from NervanaSystems/cyphers/mnist

Two shape propagates/checks, bulk of ops.
parents 8ade5867 67163443
...@@ -29,7 +29,7 @@ namespace ngraph ...@@ -29,7 +29,7 @@ namespace ngraph
{ {
public: public:
Type(size_t bitwidth, bool is_float, bool is_signed, const std::string& cname); Type(size_t bitwidth, bool is_float, bool is_signed, const std::string& cname);
const std::string& c_type_string() const; const std::string& c_type_string() const;
size_t size() const; size_t size() const;
size_t hash() const size_t hash() const
...@@ -37,23 +37,24 @@ namespace ngraph ...@@ -37,23 +37,24 @@ namespace ngraph
std::hash<std::string> h; std::hash<std::string> h;
return h(m_cname); return h(m_cname);
} }
bool operator==(const Type& other) const; bool operator==(const Type& other) const;
bool operator!=(const Type& other) const { return !(*this == other); }
private: private:
static std::map<std::string, Type> m_element_list; static std::map<std::string, Type> m_element_list;
size_t m_bitwidth; size_t m_bitwidth;
bool m_is_float; bool m_is_float;
bool m_is_signed; bool m_is_signed;
const std::string m_cname; const std::string m_cname;
}; };
const Type float32_t= Type(32, true, true, "float"); const Type float32_t = Type(32, true, true, "float");
const Type int8_t = Type(8, false, true, "int8_t"); const Type int8_t = Type(8, false, true, "int8_t");
const Type int32_t = Type(32, false, true, "int32_t"); const Type int32_t = Type(32, false, true, "int32_t");
const Type int64_t = Type(64, false, true, "int64_t"); const Type int64_t = Type(64, false, true, "int64_t");
const Type uint8_t = Type(8, false, false, "int8_t"); const Type uint8_t = Type(8, false, false, "int8_t");
const Type uint32_t = Type(32, false, false, "int32_t"); const Type uint32_t = Type(32, false, false, "int32_t");
const Type uint64_t = Type(64, false, false, "int64_t"); const Type uint64_t = Type(64, false, false, "int64_t");
} }
} }
// ----------------------------------------------------------------------------
// 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 <stdexcept>
namespace ngraph
{
/// Base error for ngraph runtime errors.
struct ngraph_error : std::runtime_error
{
explicit ngraph_error(const std::string& what_arg)
: std::runtime_error(what_arg)
{
}
explicit ngraph_error(const char* what_arg)
: std::runtime_error(what_arg)
{
}
};
}
...@@ -35,6 +35,8 @@ namespace ngraph ...@@ -35,6 +35,8 @@ namespace ngraph
std::string description() const override { return "Parameter"; } std::string description() const override { return "Parameter"; }
virtual void propagate_types() override;
protected: protected:
Function& m_function; Function& m_function;
size_t m_index; size_t m_index;
...@@ -59,7 +61,7 @@ namespace ngraph ...@@ -59,7 +61,7 @@ namespace ngraph
/** /**
** A user-defined function. ** A user-defined function.
**/ **/
class Function : public Op class Function
{ {
public: public:
Function(size_t n_parameters); Function(size_t n_parameters);
...@@ -68,7 +70,7 @@ namespace ngraph ...@@ -68,7 +70,7 @@ namespace ngraph
Parameter::ptr parameter(size_t i) { return m_parameters[i]; } Parameter::ptr parameter(size_t i) { return m_parameters[i]; }
std::string name() const override { return m_name; } std::string name() const { return m_name; }
protected: protected:
std::vector<Parameter::ptr> m_parameters; std::vector<Parameter::ptr> m_parameters;
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#pragma once #pragma once
#include "ngraph/element_type.hpp" #include "ngraph/element_type.hpp"
#include "ngraph/except.hpp"
#include "ngraph/function.hpp" #include "ngraph/function.hpp"
#include "ngraph/node.hpp" #include "ngraph/node.hpp"
#include "ngraph/op.hpp" #include "ngraph/op.hpp"
......
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <iostream>
#include "ngraph/type.hpp" #include "ngraph/type.hpp"
namespace ngraph namespace ngraph
...@@ -53,17 +55,22 @@ namespace ngraph ...@@ -53,17 +55,22 @@ namespace ngraph
virtual std::string description() const = 0; virtual std::string description() const = 0;
/// Propagate types and check arguments for consistency /// Propagate types and check arguments for consistency
// virtual void propagate_types() = 0; virtual void propagate_types() = 0;
const std::vector<Node::ptr> arguments() const { return m_arguments; } const std::vector<Node::ptr>& arguments() const { return m_arguments; }
std::vector<Node::ptr> arguments() { return m_arguments; }
const std::multiset<Node*> users() const { return m_users; } const std::multiset<Node*>& users() const { return m_users; }
std::multiset<Node*> users() { return m_users; }
std::string name() const { return m_name; } std::string name() const { return m_name; }
void name(const std::string& name) { m_name = name; } void name(const std::string& name) { m_name = name; }
/**
** Return true if this has the same implementing class as node. This
** will be used by the pattern matcher when comparing a pattern
** graph against the graph.
**/
bool is_same_op_type(const Node::ptr& node) const { return typeid(*this) == typeid(*node.get()); }
protected: protected:
std::vector<Node::ptr> m_arguments; std::vector<Node::ptr> m_arguments;
std::multiset<Node*> m_users; std::multiset<Node*> m_users;
......
...@@ -21,82 +21,121 @@ ...@@ -21,82 +21,121 @@
namespace ngraph namespace ngraph
{ {
/** namespace op
** Every instance of Op corresponds to a unique defined operation.
**/
class Op
{ {
protected: Node::ptr abs(const Node::ptr& arg);
virtual ~Op() {} Node::ptr add(const Node::ptr& arg0, const Node::ptr& arg1);
Node::ptr broadcast(const Node::ptr& tensor,
const Shape& shape,
const std::vector<size_t>& broadcast_axes);
public: //Node::ptr candidate();
virtual std::string name() const = 0; Node::ptr ceiling(const Node::ptr& arg0, const Node::ptr& arg1);
}; //Node::ptr concatenate();
//Node::ptr constant();
//Node::ptr convert();
//Node::ptr convolution();
Node::ptr divide(const Node::ptr& arg0, const Node::ptr& arg1);
Node::ptr dot(const Node::ptr& arg0, const Node::ptr& arg1);
Node::ptr equal(const Node::ptr& arg0, const Node::ptr& arg1);
Node::ptr exponential(const Node::ptr& arg0);
Node::ptr floor(const Node::ptr& arg0, const Node::ptr& arg1);
//Node::ptr get();
Node::ptr greater(const Node::ptr& arg0, const Node::ptr& arg1);
Node::ptr less(const Node::ptr& arg0, const Node::ptr& arg1);
Node::ptr log(const Node::ptr& arg0);
//Node::ptr logical();
Node::ptr maximum(const Node::ptr& arg0, const Node::ptr& arg1);
Node::ptr minimum(const Node::ptr& arg0, const Node::ptr& arg1);
Node::ptr multiply(const Node::ptr& arg0, const Node::ptr& arg1);
Node::ptr negate(const Node::ptr& arg0);
//Node::ptr pad();
Node::ptr power(const Node::ptr& arg0, const Node::ptr& arg1);
//Node::ptr reduce();
Node::ptr remainder(const Node::ptr& arg0, const Node::ptr& arg1);
Node::ptr reshape(const Node::ptr& arg0, const Shape& shape);
//Node::ptr reverse();
//Node::ptr rng();
//Node::ptr select();
//Node::ptr slice();
Node::ptr subtract(const Node::ptr& arg0, const Node::ptr& arg1);
//Node::ptr transpose();
//Node::ptr tuple();
//Node::ptr while();
}
/** /**
** Call nodes are nodes whose value is the result of some operation, the op, ** Op nodes are nodes whose value is the result of some operation
** applied to its arguments. We use the op as a callable to construct the ** applied to its arguments. For calls to user functions, the op will
** call nodes. For calls to user functions, the op will be the user function. ** reference the user function.
**/ **/
class Call : public Node class Op : public Node
{ {
public: public:
std::shared_ptr<Op> op() const { return m_op; }
Call(const std::shared_ptr<Op>& op, const std::vector<Node::ptr>& arguments) Op(const std::vector<Node::ptr>& arguments)
: Node(arguments, nullptr) : Node(arguments, nullptr)
, m_op(op)
{ {
} }
};
virtual std::string description() const override { return m_op->name(); } /**
** A FunctionOp invokes a function on node arguments. In addition to the argument
** we need to preserve the function.
**/
class FunctionOp : public Op
{
virtual std::string description() const override { return "FunctionOp"; }
protected: protected:
std::shared_ptr<Op> m_op; Node::ptr m_function;
}; };
/** /**
** There is exactly one instance of builtin op for each pre-defined operation. These ** The is an operation we handle directly, i.e. all type checking, etc.
** are intended to be used when matching calls in different graphs; every FooCall ** are defined in C++ rather than in terms of ngraph operations.
** will have the same op.
**/ **/
class BuiltinOp : public Op class BuiltinOp : public Op
{ {
friend class Call;
public: public:
BuiltinOp(const std::string& name) virtual std::string description() const override { return "BuiltinOp"; }
: m_name(name) /// Name of the builtin op, for debugging and logging.
virtual std::string op_name() const = 0;
// TODO: Implement for each op
virtual void propagate_types() override {}
protected:
BuiltinOp(const std::vector<Node::ptr>& args)
: Op(args)
{ {
} }
};
class AbsOp : public BuiltinOp
{
public: public:
std::string name() const override { return m_name; } AbsOp(const Node::ptr& arg0)
: BuiltinOp({arg0})
{
}
protected: virtual std::string op_name() const override { return "abs"; }
std::string m_name; //virtual void propagate_types() override;
}; };
class BuiltinCall : public Call class AddOp : public BuiltinOp
{ {
public: public:
virtual std::string description() const override { return "BuiltinCall"; } AddOp(const Node::ptr& arg0, const Node::ptr& arg1)
: BuiltinOp({arg0, arg1})
protected:
BuiltinCall(const std::shared_ptr<Op>& op, const std::vector<Node::ptr>& args)
: Call(op, args)
{ {
} }
virtual std::string op_name() const override { return "add"; }
//virtual void propagate_types() override;
}; };
namespace op class BroadcastOp : public BuiltinOp
{
std::shared_ptr<Node> broadcast(const Node::ptr& tensor,
const Shape& shape,
const std::vector<size_t>& broadcast_axes);
}
class BroadcastCall : public BuiltinCall
{ {
public: public:
/** /**
...@@ -105,34 +144,226 @@ namespace ngraph ...@@ -105,34 +144,226 @@ namespace ngraph
** /param broadcast_axes The axis positions (0-based) in the result that are being broadcast. ** /param broadcast_axes The axis positions (0-based) in the result that are being broadcast.
** the remaining axes in shape must be the same as the shape of arg. ** the remaining axes in shape must be the same as the shape of arg.
**/ **/
BroadcastCall(const Node::ptr& arg, const Shape& shape, std::vector<size_t> broadcast_axes) BroadcastOp(const Node::ptr& arg, const Shape& shape, std::vector<size_t> broadcast_axes)
: BuiltinCall(s_op, {arg}) : BuiltinOp({arg})
, m_shape(shape) , m_shape(shape)
, m_broadcast_axes(broadcast_axes) , m_broadcast_axes(broadcast_axes)
{ {
} }
virtual std::string op_name() const override { return "broadcast"; }
virtual void propagate_types() override;
protected:
Shape m_shape; Shape m_shape;
std::vector<size_t> m_broadcast_axes; std::vector<size_t> m_broadcast_axes;
};
protected: class CeilingOp : public BuiltinOp
static std::shared_ptr<BuiltinOp> s_op; {
public:
CeilingOp(const Node::ptr& arg0, const Node::ptr& arg1)
: BuiltinOp({arg0, arg1})
{
}
virtual std::string op_name() const override { return "ceiling"; }
//virtual void propagate_types() override;
}; };
namespace op class DivideOp : public BuiltinOp
{ {
std::shared_ptr<Node> dot(const Node::ptr& arg0, const Node::ptr& arg1); public:
} DivideOp(const Node::ptr& arg0, const Node::ptr& arg1)
: BuiltinOp({arg0, arg1})
{
}
virtual std::string op_name() const override { return "divide"; }
//virtual void propagate_types() override;
};
class DotCall : public BuiltinCall class DotOp : public BuiltinOp
{ {
public: public:
/// TODO: Semantics of arg0 and arg1 axes wrt reduction. /// TODO: Semantics of arg0 and arg1 axes wrt reduction.
DotCall(const Node::ptr& arg0, const Node::ptr& arg1) DotOp(const Node::ptr& arg0, const Node::ptr& arg1)
: BuiltinCall(s_op, {arg0, arg1}) : BuiltinOp({arg0, arg1})
{
}
virtual std::string op_name() const override { return "dot"; }
virtual void propagate_types() override;
};
class EqualOp : public BuiltinOp
{
public:
EqualOp(const Node::ptr& arg0, const Node::ptr& arg1)
: BuiltinOp({arg0, arg1})
{
}
virtual std::string op_name() const override { return "equal"; }
//virtual void propagate_types() override;
};
class ExponentialOp : public BuiltinOp
{
public:
ExponentialOp(const Node::ptr& arg0)
: BuiltinOp({arg0})
{
}
virtual std::string op_name() const override { return "exp"; }
//virtual void propagate_types() override;
};
class FloorOp : public BuiltinOp
{
public:
FloorOp(const Node::ptr& arg0, const Node::ptr& arg1)
: BuiltinOp({arg0, arg1})
{
}
virtual std::string op_name() const override { return "floor"; }
//virtual void propagate_types() override;
};
class GreaterOp : public BuiltinOp
{
public:
GreaterOp(const Node::ptr& arg0, const Node::ptr& arg1)
: BuiltinOp({arg0, arg1})
{
}
virtual std::string op_name() const override { return "greater"; }
//virtual void propagate_types() override;
};
class LessOp : public BuiltinOp
{
public:
LessOp(const Node::ptr& arg0, const Node::ptr& arg1)
: BuiltinOp({arg0, arg1})
{
}
virtual std::string op_name() const override { return "less"; }
//virtual void propagate_types() override;
};
class LogOp : public BuiltinOp
{
public:
LogOp(const Node::ptr& arg0)
: BuiltinOp({arg0})
{
}
virtual std::string op_name() const override { return "log"; }
//virtual void propagate_types() override;
};
class MaximumOp : public BuiltinOp
{
public:
MaximumOp(const Node::ptr& arg0, const Node::ptr& arg1)
: BuiltinOp({arg0, arg1})
{
}
virtual std::string op_name() const override { return "max"; }
//virtual void propagate_types() override;
};
class MinimumOp : public BuiltinOp
{
public:
MinimumOp(const Node::ptr& arg0, const Node::ptr& arg1)
: BuiltinOp({arg0, arg1})
{
}
virtual std::string op_name() const override { return "min"; }
//virtual void propagate_types() override;
};
class MultiplyOp : public BuiltinOp
{
public:
MultiplyOp(const Node::ptr& arg0, const Node::ptr& arg1)
: BuiltinOp({arg0, arg1})
{
}
virtual std::string op_name() const override { return "multiply"; }
//virtual void propagate_types() override;
};
class NegateOp : public BuiltinOp
{
public:
NegateOp(const Node::ptr& arg0)
: BuiltinOp({arg0})
{
}
virtual std::string op_name() const override { return "negate"; }
//virtual void propagate_types() override;
};
class PowerOp : public BuiltinOp
{
public:
PowerOp(const Node::ptr& arg0, const Node::ptr& arg1)
: BuiltinOp({arg0, arg1})
{
}
virtual std::string op_name() const override { return "power"; }
//virtual void propagate_types() override;
};
class RemainderOp : public BuiltinOp
{
public:
RemainderOp(const Node::ptr& arg0, const Node::ptr& arg1)
: BuiltinOp({arg0, arg1})
{ {
} }
virtual std::string op_name() const override { return "remainder"; }
//virtual void propagate_types() override;
};
class ReshapeOp : public BuiltinOp
{
public:
ReshapeOp(const Node::ptr& arg0, const Shape& shape)
: BuiltinOp({arg0})
, m_shape(shape)
{
}
virtual std::string op_name() const override { return "reshape"; }
//virtual void propagate_types() override;
protected: protected:
static std::shared_ptr<BuiltinOp> s_op; Shape m_shape;
};
class SubtractOp : public BuiltinOp
{
public:
SubtractOp(const Node::ptr& arg0, const Node::ptr& arg1)
: BuiltinOp({arg0, arg1})
{
}
virtual std::string op_name() const override { return "subtract"; }
//virtual void propagate_types() override;
}; };
} }
...@@ -32,11 +32,19 @@ namespace ngraph ...@@ -32,11 +32,19 @@ namespace ngraph
{ {
} }
Shape(const std::vector<size_t>& sizes)
: m_sizes(sizes)
{
}
/** /**
** Conversion to a vector of sizes. ** Conversion to a vector of sizes.
**/ **/
operator const std::vector<size_t>&() const { return m_sizes; } operator const std::vector<size_t>&() const { return m_sizes; }
bool operator==(const Shape& shape) const { return m_sizes == shape.m_sizes; }
bool operator!=(const Shape& shape) const { return m_sizes != shape.m_sizes; }
protected: protected:
std::vector<size_t> m_sizes; std::vector<size_t> m_sizes;
}; };
......
...@@ -22,6 +22,9 @@ ...@@ -22,6 +22,9 @@
namespace ngraph namespace ngraph
{ {
class TensorViewType;
class TupleType;
/** /**
** ValueType is ** ValueType is
** TensorViewType ** TensorViewType
...@@ -34,6 +37,8 @@ namespace ngraph ...@@ -34,6 +37,8 @@ namespace ngraph
** Preferred handle ** Preferred handle
**/ **/
using ptr = std::shared_ptr<ValueType>; using ptr = std::shared_ptr<ValueType>;
virtual ~ValueType() {}
}; };
/** /**
...@@ -57,6 +62,9 @@ namespace ngraph ...@@ -57,6 +62,9 @@ namespace ngraph
{ {
} }
const element::Type& element_type() const { return m_element_type; }
const Shape& shape() const { return m_shape; }
protected: protected:
const element::Type& m_element_type; const element::Type& m_element_type;
Shape m_shape; Shape m_shape;
......
...@@ -24,6 +24,14 @@ Parameter::Parameter(Function& function, size_t index) ...@@ -24,6 +24,14 @@ Parameter::Parameter(Function& function, size_t index)
{ {
} }
void Parameter::propagate_types()
{
if (m_type == nullptr)
{
throw ngraph_error{"Unitialized parameter"};
}
}
Function::Function(size_t n_parameters) Function::Function(size_t n_parameters)
: m_parameters(n_parameters) : m_parameters(n_parameters)
, m_name("Function") , m_name("Function")
......
...@@ -12,12 +12,22 @@ ...@@ -12,12 +12,22 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#include <algorithm>
#include "ngraph/ngraph.hpp" #include "ngraph/ngraph.hpp"
using namespace ngraph; using namespace ngraph;
using namespace std; using namespace std;
std::shared_ptr<BuiltinOp> BroadcastCall::s_op = make_shared<BuiltinOp>("broadcast"); Node::ptr ngraph::op::abs(const Node::ptr& arg)
{
return make_shared<AbsOp>(arg);
}
Node::ptr ngraph::op::add(const Node::ptr& arg0, const Node::ptr& arg1)
{
return make_shared<AddOp>(arg0, arg1);
}
/** /**
** /param arg The tensor view to be broadcast. ** /param arg The tensor view to be broadcast.
...@@ -25,17 +35,163 @@ std::shared_ptr<BuiltinOp> BroadcastCall::s_op = make_shared<BuiltinOp>("broadca ...@@ -25,17 +35,163 @@ std::shared_ptr<BuiltinOp> BroadcastCall::s_op = make_shared<BuiltinOp>("broadca
** /param broadcast_axes The axis positions (0-based) in the result that are being broadcast. ** /param broadcast_axes The axis positions (0-based) in the result that are being broadcast.
** the remaining axes in shape must be the same as the shape of arg. ** the remaining axes in shape must be the same as the shape of arg.
**/ **/
shared_ptr<Node> ngraph::op::broadcast(const Node::ptr& tensor, Node::ptr ngraph::op::broadcast(const Node::ptr& tensor,
const Shape& shape, const Shape& shape,
const vector<size_t>& broadcast_axes) const vector<size_t>& broadcast_axes)
{
return make_shared<BroadcastOp>(tensor, shape, broadcast_axes);
}
void BroadcastOp::propagate_types()
{ {
return make_shared<BroadcastCall>(tensor, shape, broadcast_axes); auto arg_type = m_arguments.at(0)->type();
if (nullptr == arg_type)
{
throw ngraph_error("Argument to broadcast is missing type.");
}
auto arg_tensor_view_type = dynamic_pointer_cast<TensorViewType>(arg_type);
if (nullptr == arg_tensor_view_type)
{
throw ngraph_error("Argument to broadcast is not a tensor view");
}
vector<size_t> target_shape = m_shape;
for (auto i = m_broadcast_axes.rbegin(); i != m_broadcast_axes.rend(); ++i)
{
target_shape.erase(target_shape.begin() + *i);
}
if (Shape{target_shape} != arg_tensor_view_type->shape())
{
throw ngraph_error("Broadcast arg, shape, and axes are incompatible");
}
// TODO If m_type is already set (by framework), this should verify that the type
// we expect is consistent with the type the framework expects.
m_type = make_shared<TensorViewType>(arg_tensor_view_type->element_type(), m_shape);
} }
std::shared_ptr<BuiltinOp> DotCall::s_op = make_shared<BuiltinOp>("dot"); Node::ptr ngraph::op::ceiling(const Node::ptr& arg0, const Node::ptr& arg1)
{
return make_shared<CeilingOp>(arg0, arg1);
}
// 'concatenate',
// 'constant',
// 'convert',
// 'convolution',
Node::ptr ngraph::op::divide(const Node::ptr& arg0, const Node::ptr& arg1)
{
return make_shared<DivideOp>(arg0, arg1);
}
/// TODO: Semantics of arg0 and arg1 axes wrt reduction. /// TODO: Semantics of arg0 and arg1 axes wrt reduction.
shared_ptr<Node> ngraph::op::dot(const Node::ptr& arg0, const Node::ptr& arg1) Node::ptr ngraph::op::dot(const Node::ptr& arg0, const Node::ptr& arg1)
{
return make_shared<DotOp>(arg0, arg1);
}
void DotOp::propagate_types()
{
auto arg0_tensor_type = dynamic_pointer_cast<TensorViewType>(m_arguments.at(0)->type());
auto arg1_tensor_type = dynamic_pointer_cast<TensorViewType>(m_arguments.at(1)->type());
if (nullptr == arg0_tensor_type || nullptr == arg1_tensor_type)
{
throw ngraph_error("Arguments to dot must be tensor views");
}
if (arg0_tensor_type->element_type() != arg1_tensor_type->element_type())
{
throw ngraph_error("Arguments to dot must have the same element type");
}
// Use NumPy semantics for now
// Last axis of first arg reduces against second to last of second arg if more than one axis, else axis.
vector<size_t> arg0_shape = arg0_tensor_type->shape();
vector<size_t> arg1_shape = arg1_tensor_type->shape();
size_t arg0_reduction = arg0_shape.size() - 1;
size_t arg1_reduction;
if (arg1_shape.size() > 1)
{
arg1_reduction = arg1_shape.size() - 2;
}
else
{
arg1_reduction = arg1_shape.size() - 1;
}
if (arg0_shape.at(arg0_reduction) != arg1_shape.at(arg1_reduction))
{
throw ngraph_error("Dot reduction axes not compatible");
}
vector<size_t> result_shape;
copy(arg0_shape.begin(), arg0_shape.begin() + arg1_reduction, result_shape.end());
copy(arg1_shape.begin(), arg1_shape.begin() + arg1_reduction, result_shape.end());
copy(arg1_shape.begin() + arg1_reduction, arg1_shape.end(), result_shape.end());
m_type = make_shared<TensorViewType>(arg0_tensor_type->element_type(), result_shape);
}
Node::ptr ngraph::op::exponential(const Node::ptr& arg0)
{
return make_shared<ExponentialOp>(arg0);
}
Node::ptr ngraph::op::floor(const Node::ptr& arg0, const Node::ptr& arg1)
{
return make_shared<FloorOp>(arg0, arg1);
}
Node::ptr ngraph::op::log(const Node::ptr& arg0)
{ {
return make_shared<DotCall>(arg0, arg1); return make_shared<LogOp>(arg0);
} }
Node::ptr ngraph::op::maximum(const Node::ptr& arg0, const Node::ptr& arg1)
{
return make_shared<MaximumOp>(arg0, arg1);
}
Node::ptr ngraph::op::minimum(const Node::ptr& arg0, const Node::ptr& arg1)
{
return make_shared<MinimumOp>(arg0, arg1);
}
Node::ptr ngraph::op::multiply(const Node::ptr& arg0, const Node::ptr& arg1)
{
return make_shared<MultiplyOp>(arg0, arg1);
}
Node::ptr ngraph::op::negate(const Node::ptr& arg0)
{
return make_shared<NegateOp>(arg0);
}
// 'pad',
// 'parameter',
Node::ptr ngraph::op::power(const Node::ptr& arg0, const Node::ptr& arg1)
{
return make_shared<PowerOp>(arg0, arg1);
}
//'reduce',
Node::ptr ngraph::op::remainder(const Node::ptr& arg0, const Node::ptr& arg1)
{
return make_shared<RemainderOp>(arg0, arg1);
}
Node::ptr ngraph::op::reshape(const Node::ptr& arg0, const Shape& shape)
{
return make_shared<ReshapeOp>(arg0, shape);
}
//'reverse',
//'rng',
// 'select',
//'slice',
Node::ptr ngraph::op::subtract(const Node::ptr& arg0, const Node::ptr& arg1)
{
return make_shared<SubtractOp>(arg0, arg1);
}
// 'transpose',
//'tuple',
// 'while'
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
using namespace std; using namespace std;
using namespace ngraph; using namespace ngraph;
TEST(DISABLED_graph, build_simple) TEST(build_graph, build_simple)
{ {
// Function with 4 parameters // Function with 4 parameters
auto cluster_0 = make_shared<Function>(4); auto cluster_0 = make_shared<Function>(4);
...@@ -29,11 +29,9 @@ TEST(DISABLED_graph, build_simple) ...@@ -29,11 +29,9 @@ TEST(DISABLED_graph, build_simple)
cluster_0->parameter(2)->type(element::float32_t, {32, 7}); cluster_0->parameter(2)->type(element::float32_t, {32, 7});
cluster_0->parameter(3)->type(element::float32_t, {32, 7}); cluster_0->parameter(3)->type(element::float32_t, {32, 7});
auto arg3 = cluster_0->parameter(3); auto arg3 = cluster_0->parameter(3);
// call broadcast op on arg3, broadcasting on axis 0.
auto broadcast_1 = op::broadcast(arg3, {10, 32, 7}, {0}); auto broadcast_1 = op::broadcast(arg3, {10, 32, 7}, {0});
auto arg2 = cluster_0->parameter(2); auto arg2 = cluster_0->parameter(2);
auto arg0 = cluster_0->parameter(0); auto arg0 = cluster_0->parameter(0);
// call dot op
auto dot = op::dot(arg2, arg0); auto dot = op::dot(arg2, arg0);
ASSERT_EQ(dot->arguments()[0], arg2); ASSERT_EQ(dot->arguments()[0], arg2);
ASSERT_EQ(dot->arguments()[1], arg0); ASSERT_EQ(dot->arguments()[1], arg0);
...@@ -42,3 +40,52 @@ TEST(DISABLED_graph, build_simple) ...@@ -42,3 +40,52 @@ TEST(DISABLED_graph, build_simple)
ASSERT_EQ(cluster_0->result()->value(), dot); ASSERT_EQ(cluster_0->result()->value(), dot);
} }
// Check upcasting from ValueType.
TEST(build_graph, as_type)
{
// Check upcasting a ValueType::ptr that is a TensorViewType to a TensorViewType and Tuple.
ValueType::ptr tv_vt = make_shared<TensorViewType>(element::float32_t, Shape{2, 3, 5});
auto tv_tv = dynamic_pointer_cast<TensorViewType>(tv_vt);
ASSERT_EQ(tv_vt, tv_tv);
auto tv_tp = dynamic_pointer_cast<TupleType>(tv_vt);
ASSERT_EQ(nullptr, tv_tp);
// Check upcasting a ValueType::ptr that is a TupleType to a TensorViewType and Tuple.
ValueType::ptr tp_vt = make_shared<TupleType>(vector<ValueType::ptr>{tv_vt, tv_vt});
auto tp_tv = dynamic_pointer_cast<TensorViewType>(tp_vt);
ASSERT_EQ(nullptr, tp_tv);
auto tp_tp = dynamic_pointer_cast<TupleType>(tp_vt);
ASSERT_EQ(tp_vt, tp_tp);
}
// Check node comparisons
TEST(build_graph, node_comparison)
{
auto fun = make_shared<Function>(3);
fun->parameter(0)->type(element::float32_t, {32, 3});
fun->parameter(1)->type(element::float32_t, {3});
fun->parameter(2)->type(element::float32_t, {32});
auto arg0 = fun->parameter(0);
auto arg1 = fun->parameter(1);
auto arg2 = fun->parameter(2);
auto dot = op::dot(arg0, arg1);
auto add = op::add(dot, arg2);
auto pattern = make_shared<Function>(1);
pattern->parameter(0)->type(element::float32_t, {});
auto parg = pattern->parameter(0);
auto pattern_dot = op::dot(parg, parg);
ASSERT_TRUE(pattern_dot->is_same_op_type(dot));
// TODO This passes because typeid is not behaving as documented.
// Need to figure out what's wrong.
ASSERT_FALSE(pattern_dot->is_same_op_type(add));
}
// Check argument inverses
TEST(build_graph, arg_inverse)
{
}
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