Commit b95135c6 authored by Robert Kimball's avatar Robert Kimball Committed by Scott Cyphers

Bob/ngvm (#250)

* wip

* remove ndarray dependency from ParameterizedTensorView

* get rid of operator= on ParameterizedTensorView

* remove unimplemented ctor

* remove get_parameterized_tensor_view from TensorView class

* cleanup

* the patient will get worse before getting better. remove ParameterizedTensorView from element type

* cleanup obsolete includes

* remove unused file

* move aligned_buffer and cleanup

* cleanup

* wip

* wip

* wip

* cleanup

* cleanup

* wip

* finally got rid of getting a non-const vector from PTV

* wips

* wip

* remove unused

* fix PR comments
parent 3bb93eb3
...@@ -63,6 +63,7 @@ set (SRC ...@@ -63,6 +63,7 @@ set (SRC
pass/pass.cpp pass/pass.cpp
pass/topological_sort.cpp pass/topological_sort.cpp
pass/visualize_tree.cpp pass/visualize_tree.cpp
runtime/aligned_buffer.cpp
runtime/backend.cpp runtime/backend.cpp
runtime/manager.cpp runtime/manager.cpp
runtime/ngvm/call_frame.cpp runtime/ngvm/call_frame.cpp
...@@ -113,7 +114,6 @@ if (NGRAPH_CPU_ENABLE AND LLVM_INCLUDE_DIR AND ...@@ -113,7 +114,6 @@ if (NGRAPH_CPU_ENABLE AND LLVM_INCLUDE_DIR AND
runtime/cpu/cpu_kernels.cpp runtime/cpu/cpu_kernels.cpp
runtime/cpu/emitter.cpp runtime/cpu/emitter.cpp
runtime/cpu/external_function.cpp runtime/cpu/external_function.cpp
runtime/cpu/memory_handler.cpp
runtime/cpu/tensor_view.cpp runtime/cpu/tensor_view.cpp
) )
# LLVM binary builds are typically built without RTTI # LLVM binary builds are typically built without RTTI
......
// ----------------------------------------------------------------------------
// 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 <memory>
#include <vector>
#include "ngraph/descriptor/tensor_view.hpp"
#include "ngraph/function.hpp"
namespace ngraph
{
namespace descriptor
{
// Describes the frame that will be used when a function is executing
class CallFrame
{
protected:
Function m_function;
// Will be provided by the caller
std::vector<std::shared_ptr<TensorView>> m_inputs;
std::vector<std::shared_ptr<TensorView>> m_outputs;
// Will be provided by the call mechanism
// Expect there to be only one buffer
std::vector<std::shared_ptr<Buffer>> m_buffers;
};
}
}
...@@ -35,7 +35,6 @@ ...@@ -35,7 +35,6 @@
#include "ngraph/common.hpp" #include "ngraph/common.hpp"
#include "ngraph/descriptor/buffer.hpp" #include "ngraph/descriptor/buffer.hpp"
#include "ngraph/descriptor/call_frame.hpp"
#include "ngraph/descriptor/input.hpp" #include "ngraph/descriptor/input.hpp"
#include "ngraph/descriptor/layout/dense_tensor_view_layout.hpp" #include "ngraph/descriptor/layout/dense_tensor_view_layout.hpp"
#include "ngraph/descriptor/layout/tensor_view_layout.hpp" #include "ngraph/descriptor/layout/tensor_view_layout.hpp"
......
...@@ -12,32 +12,42 @@ ...@@ -12,32 +12,42 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#include "ngraph/runtime/cpu/memory_handler.hpp" #include "ngraph/runtime/aligned_buffer.hpp"
using namespace ngraph; using namespace ngraph;
runtime::cpu::MemoryHandler::MemoryHandler(size_t byte_size, size_t alignment) runtime::AlignedBuffer::AlignedBuffer()
: m_allocated_buffer_pool(nullptr) : m_allocated_buffer(nullptr)
, m_aligned_buffer_pool(nullptr) , m_aligned_buffer(nullptr)
{ {
if (byte_size > 0) }
runtime::AlignedBuffer::AlignedBuffer(size_t byte_size, size_t alignment)
{
initialize(byte_size, alignment);
}
void runtime::AlignedBuffer::initialize(size_t byte_size, size_t alignment)
{
m_byte_size = byte_size;
if (m_byte_size > 0)
{ {
size_t allocation_size = byte_size + alignment; size_t allocation_size = m_byte_size + alignment;
m_allocated_buffer_pool = static_cast<char*>(malloc(allocation_size)); m_allocated_buffer = static_cast<char*>(malloc(allocation_size));
m_aligned_buffer_pool = m_allocated_buffer_pool; m_aligned_buffer = m_allocated_buffer;
size_t mod = size_t(m_aligned_buffer_pool) % alignment; size_t mod = size_t(m_aligned_buffer) % alignment;
if (mod != 0) if (mod != 0)
{ {
m_aligned_buffer_pool += (alignment - mod); m_aligned_buffer += (alignment - mod);
} }
} }
} }
runtime::cpu::MemoryHandler::~MemoryHandler() runtime::AlignedBuffer::~AlignedBuffer()
{ {
if (m_allocated_buffer_pool != nullptr) if (m_allocated_buffer != nullptr)
{ {
free(m_allocated_buffer_pool); free(m_allocated_buffer);
} }
} }
...@@ -21,21 +21,26 @@ namespace ngraph ...@@ -21,21 +21,26 @@ namespace ngraph
{ {
namespace runtime namespace runtime
{ {
namespace cpu class AlignedBuffer;
{
class MemoryHandler;
}
} }
} }
class ngraph::runtime::cpu::MemoryHandler /// @brief Allocates a block of memory on the specified alignment. The actual size of the
/// allocated memory is larger than the requested size by the alignment, so allocating 1 byte
/// on 64 byte alignment will allocate 65 bytes.
class ngraph::runtime::AlignedBuffer
{ {
public: public:
MemoryHandler(size_t pool_size, size_t alignment); AlignedBuffer(size_t byte_size, size_t alignment);
~MemoryHandler(); AlignedBuffer();
void initialize(size_t byte_size, size_t alignment);
~AlignedBuffer();
void* get_ptr(size_t offset) const { return m_aligned_buffer_pool + offset; } size_t size() const { return m_byte_size; }
void* get_ptr(size_t offset) const { return m_aligned_buffer + offset; }
void* get_ptr() const { return m_aligned_buffer; }
private: private:
char* m_allocated_buffer_pool; char* m_allocated_buffer;
char* m_aligned_buffer_pool; char* m_aligned_buffer;
size_t m_byte_size;
}; };
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <memory> #include <memory>
#include "ngraph/runtime/backend.hpp" #include "ngraph/runtime/backend.hpp"
#include "ngraph/runtime/parameterized_tensor_view.hpp"
#include "ngraph/runtime/tensor_view.hpp" #include "ngraph/runtime/tensor_view.hpp"
#include "ngraph/runtime/tuple.hpp" #include "ngraph/runtime/tuple.hpp"
#include "ngraph/types/element_type.hpp" #include "ngraph/types/element_type.hpp"
...@@ -24,7 +25,48 @@ using namespace ngraph::runtime; ...@@ -24,7 +25,48 @@ using namespace ngraph::runtime;
std::shared_ptr<TensorView> std::shared_ptr<TensorView>
Backend::make_primary_tensor_view(const ngraph::element::Type& element_type, const Shape& shape) Backend::make_primary_tensor_view(const ngraph::element::Type& element_type, const Shape& shape)
{ {
return element_type.make_primary_tensor_view(shape); std::shared_ptr<TensorView> rc;
if (element_type == element::Bool::element_type())
{
rc = std::make_shared<ParameterizedTensorView<element::Bool>>(shape);
}
else if (element_type == element::Float32::element_type())
{
rc = std::make_shared<ParameterizedTensorView<element::Float32>>(shape);
}
else if (element_type == element::Float64::element_type())
{
rc = std::make_shared<ParameterizedTensorView<element::Float64>>(shape);
}
else if (element_type == element::Int8::element_type())
{
rc = std::make_shared<ParameterizedTensorView<element::Int8>>(shape);
}
else if (element_type == element::Int32::element_type())
{
rc = std::make_shared<ParameterizedTensorView<element::Int32>>(shape);
}
else if (element_type == element::Int64::element_type())
{
rc = std::make_shared<ParameterizedTensorView<element::Int64>>(shape);
}
else if (element_type == element::UInt8::element_type())
{
rc = std::make_shared<ParameterizedTensorView<element::UInt8>>(shape);
}
else if (element_type == element::UInt32::element_type())
{
rc = std::make_shared<ParameterizedTensorView<element::UInt32>>(shape);
}
else if (element_type == element::UInt64::element_type())
{
rc = std::make_shared<ParameterizedTensorView<element::UInt64>>(shape);
}
else
{
throw std::invalid_argument("Unknown element type in make_primary_tensor_view");
}
return rc;
} }
std::shared_ptr<ngraph::runtime::Tuple> std::shared_ptr<ngraph::runtime::Tuple>
......
...@@ -64,17 +64,6 @@ namespace ngraph ...@@ -64,17 +64,6 @@ namespace ngraph
make_primary_tensor_view(ET::element_type(), shape)); make_primary_tensor_view(ET::element_type(), shape));
} }
template <typename ET>
std::shared_ptr<ngraph::runtime::ParameterizedTensorView<ET>>
make_parameterized_tensor_view(const NDArrayBase<typename ET::type>& ndarray)
{
auto result =
std::dynamic_pointer_cast<ngraph::runtime::ParameterizedTensorView<ET>>(
make_primary_tensor_view(ET::element_type(), ndarray.get_shape()));
*result = ndarray;
return result;
}
/// @brief Construct a tuple handle from a sequence of values. /// @brief Construct a tuple handle from a sequence of values.
virtual std::shared_ptr<ngraph::runtime::Tuple> virtual std::shared_ptr<ngraph::runtime::Tuple>
make_tuple(const std::vector<std::shared_ptr<ngraph::runtime::Value>>& elements); make_tuple(const std::vector<std::shared_ptr<ngraph::runtime::Value>>& elements);
......
...@@ -190,9 +190,9 @@ void ExternalFunction::compile() ...@@ -190,9 +190,9 @@ void ExternalFunction::compile()
#include <Eigen/Dense> #include <Eigen/Dense>
#include "ngraph/runtime/aligned_buffer.hpp"
#include "ngraph/runtime/cpu/cpu_kernels.hpp" #include "ngraph/runtime/cpu/cpu_kernels.hpp"
#include "ngraph/runtime/cpu/eigen_utils.hpp" #include "ngraph/runtime/cpu/eigen_utils.hpp"
#include "ngraph/runtime/cpu/memory_handler.hpp"
using namespace ngraph::runtime::cpu::eigen; using namespace ngraph::runtime::cpu::eigen;
...@@ -228,7 +228,7 @@ using namespace ngraph::runtime::cpu::eigen; ...@@ -228,7 +228,7 @@ using namespace ngraph::runtime::cpu::eigen;
{ {
size_t temp_pool_size = pass_manager.get_state().get_temporary_pool_size(); size_t temp_pool_size = pass_manager.get_state().get_temporary_pool_size();
TU << "// Allocate the memory pool\n"; TU << "// Allocate the memory pool\n";
TU << "ngraph::runtime::cpu::MemoryHandler memory_handler(" << temp_pool_size << ", " TU << "ngraph::runtime::AlignedBuffer memory_handler(" << temp_pool_size << ", "
<< ngraph::runtime::cpu::alignment << ");\n"; << ngraph::runtime::cpu::alignment << ");\n";
TU << "\n"; TU << "\n";
......
...@@ -14,8 +14,10 @@ ...@@ -14,8 +14,10 @@
#include <memory> #include <memory>
#include "cpu_backend.hpp" #include "ngraph/descriptor/layout/dense_tensor_view_layout.hpp"
#include "tensor_view.hpp" #include "ngraph/descriptor/primary_tensor_view.hpp"
#include "ngraph/runtime/cpu/cpu_backend.hpp"
#include "ngraph/runtime/cpu/tensor_view.hpp"
using namespace ngraph; using namespace ngraph;
using namespace std; using namespace std;
......
...@@ -58,13 +58,14 @@ namespace ngraph ...@@ -58,13 +58,14 @@ namespace ngraph
template <typename ET> template <typename ET>
ParameterizedTensorView<ET>* get_parameterized_tensor_view(size_t i) ParameterizedTensorView<ET>* get_parameterized_tensor_view(size_t i)
{ {
return m_tensor_views[i]->get_parameterized_tensor_view<ET>(); return dynamic_cast<ParameterizedTensorView<ET>*>(m_tensor_views[i].get());
} }
template <typename ET> template <typename ET>
typename ET::type* get_tensor_view_data(size_t i) typename ET::type* get_tensor_view_data(size_t i)
{ {
return &get_parameterized_tensor_view<ET>(i)->get_vector()[0]; return static_cast<typename ET::type*>(
get_parameterized_tensor_view<ET>(i)->get_data_ptr());
} }
protected: protected:
......
...@@ -41,8 +41,7 @@ namespace ngraph ...@@ -41,8 +41,7 @@ namespace ngraph
virtual void execute(CallFrame& call_frame) const override virtual void execute(CallFrame& call_frame) const override
{ {
call_frame.get_parameterized_tensor_view<ET>(m_out.get_index()) call_frame.get_tensor_view(m_out.get_index())->write(m_value);
->get_vector() = m_value;
} }
protected: protected:
......
...@@ -44,8 +44,8 @@ namespace ngraph ...@@ -44,8 +44,8 @@ namespace ngraph
virtual void execute(CallFrame& call_frame) const override virtual void execute(CallFrame& call_frame) const override
{ {
call_frame.get_parameterized_tensor_view<ET>(m_out)->get_vector() = call_frame.get_parameterized_tensor_view<ET>(m_out)->write(
call_frame.get_parameterized_tensor_view<ET>(m_in)->get_vector(); call_frame.get_parameterized_tensor_view<ET>(m_in)->get_vector());
} }
protected: protected:
......
...@@ -51,10 +51,8 @@ namespace ngraph ...@@ -51,10 +51,8 @@ namespace ngraph
std::shared_ptr<CallFrame> cf = std::shared_ptr<CallFrame> cf =
std::dynamic_pointer_cast<CallFrame>(ef->make_call_frame()); std::dynamic_pointer_cast<CallFrame>(ef->make_call_frame());
auto tx = ngraph::runtime::make_tensor<ET>(Shape{}); auto tx = ngraph::runtime::make_tensor<ET>(Shape{}, {x});
*tx = std::vector<typename ET::type>({x}); auto ty = ngraph::runtime::make_tensor<ET>(Shape{}, {y});
auto ty = ngraph::runtime::make_tensor<ET>(Shape{});
*ty = std::vector<typename ET::type>({y});
auto tr = ngraph::runtime::make_tensor<ET>(Shape{}); auto tr = ngraph::runtime::make_tensor<ET>(Shape{});
(*cf)({tx, ty}, {tr}); (*cf)({tx, ty}, {tr});
......
...@@ -51,10 +51,8 @@ namespace ngraph ...@@ -51,10 +51,8 @@ namespace ngraph
std::shared_ptr<CallFrame> cf = std::shared_ptr<CallFrame> cf =
std::dynamic_pointer_cast<CallFrame>(ef->make_call_frame()); std::dynamic_pointer_cast<CallFrame>(ef->make_call_frame());
auto tx = ngraph::runtime::make_tensor<ET>(Shape{}); auto tx = ngraph::runtime::make_tensor<ET>(Shape{}, {x});
*tx = std::vector<typename ET::type>({x}); auto ty = ngraph::runtime::make_tensor<ET>(Shape{}, {y});
auto ty = ngraph::runtime::make_tensor<ET>(Shape{});
*ty = std::vector<typename ET::type>({y});
auto tr = ngraph::runtime::make_tensor<ET>(Shape{}); auto tr = ngraph::runtime::make_tensor<ET>(Shape{});
(*cf)({tx, ty}, {tr}); (*cf)({tx, ty}, {tr});
......
...@@ -51,10 +51,8 @@ namespace ngraph ...@@ -51,10 +51,8 @@ namespace ngraph
std::shared_ptr<CallFrame> cf = std::shared_ptr<CallFrame> cf =
std::dynamic_pointer_cast<CallFrame>(ef->make_call_frame()); std::dynamic_pointer_cast<CallFrame>(ef->make_call_frame());
auto tx = ngraph::runtime::make_tensor<ET>(Shape{}); auto tx = ngraph::runtime::make_tensor<ET>(Shape{}, {x});
*tx = std::vector<typename ET::type>({x}); auto ty = ngraph::runtime::make_tensor<ET>(Shape{}, {y});
auto ty = ngraph::runtime::make_tensor<ET>(Shape{});
*ty = std::vector<typename ET::type>({y});
auto tr = ngraph::runtime::make_tensor<ET>(Shape{}); auto tr = ngraph::runtime::make_tensor<ET>(Shape{});
(*cf)({tx, ty}, {tr}); (*cf)({tx, ty}, {tr});
......
...@@ -319,13 +319,24 @@ ExternalFunction::ExternalFunction(const std::shared_ptr<ngraph::Function>& func ...@@ -319,13 +319,24 @@ ExternalFunction::ExternalFunction(const std::shared_ptr<ngraph::Function>& func
instr_class); \ instr_class); \
} }
template <typename ET>
std::vector<typename ET::type>
get_vector(std::shared_ptr<ngraph::runtime::ParameterizedTensorView<ET>> ptv)
{
std::vector<typename ET::type> rc;
rc = ptv->get_vector();
return rc;
}
#define REGISTER_CONSTANT_INSTRUCTIONS(T) \ #define REGISTER_CONSTANT_INSTRUCTIONS(T) \
{ \ { \
REGISTER_INSTRUCTION( \ REGISTER_INSTRUCTION( \
op::ParameterizedConstant<T>, \ op::ParameterizedConstant<T>, \
eigen::ConstantInstruction<T>, \ eigen::ConstantInstruction<T>, \
std::vector<T::type>{ \ std::vector<T::type>{ \
dynamic_cast<const op::ParameterizedConstant<T>*>(n)->get_value()->get_vector()}, \ get_vector<T>(dynamic_cast<const op::ParameterizedConstant<T>*>(n)->get_value())}, \
out[0]); \ out[0]); \
} }
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#include "ngraph/descriptor/layout/dense_tensor_view_layout.hpp" #include "ngraph/descriptor/layout/dense_tensor_view_layout.hpp"
#include "ngraph/descriptor/primary_tensor_view.hpp" #include "ngraph/descriptor/primary_tensor_view.hpp"
#include "ngraph/runtime/ndarray.hpp"
#include "ngraph/runtime/tensor_view.hpp" #include "ngraph/runtime/tensor_view.hpp"
#include "ngraph/shape.hpp" #include "ngraph/shape.hpp"
#include "ngraph/types/element_type.hpp" #include "ngraph/types/element_type.hpp"
...@@ -33,7 +32,7 @@ namespace ngraph ...@@ -33,7 +32,7 @@ namespace ngraph
namespace runtime namespace runtime
{ {
template <typename ET> template <typename ET>
class ParameterizedTensorView : public TensorView class ParameterizedTensorView : public runtime::TensorView
{ {
public: public:
/// Create a tensor /// Create a tensor
...@@ -50,37 +49,12 @@ namespace ngraph ...@@ -50,37 +49,12 @@ namespace ngraph
m_vector.resize(m_descriptor->get_tensor_view_layout()->get_size()); m_vector.resize(m_descriptor->get_tensor_view_layout()->get_size());
} }
ParameterizedTensorView(
const std::shared_ptr<ngraph::descriptor::TensorView>& descriptor);
ParameterizedTensorView(const NDArrayBase<typename ET::type>& initializer)
: ParameterizedTensorView(initializer.get_shape())
{
m_vector = initializer.get_vector();
}
using element_type = ET;
using value_type = typename ET::type; using value_type = typename ET::type;
using storage_type = std::vector<value_type>; using storage_type = std::vector<value_type>;
template <typename T>
ParameterizedTensorView<ET>& operator=(const std::vector<T>& value)
{
get_vector() = value;
return *this;
}
template <typename T>
ParameterizedTensorView<ET>& operator=(const NDArrayBase<T>& ndarray)
{
assert(ndarray.get_shape() == get_shape());
std::copy(ndarray.begin(), ndarray.end(), m_vector.begin());
return *this;
}
// For getting the data out // For getting the data out
storage_type& get_vector() { return m_vector; }
const storage_type& get_vector() const { return m_vector; } const storage_type& get_vector() const { return m_vector; }
void* get_data_ptr() { return m_vector.data(); }
virtual void write(const void* p, size_t tensor_offset, size_t n) override virtual void write(const void* p, size_t tensor_offset, size_t n) override
{ {
size_t elt_offset = tensor_offset / sizeof(typename ET::type); size_t elt_offset = tensor_offset / sizeof(typename ET::type);
...@@ -102,6 +76,12 @@ namespace ngraph ...@@ -102,6 +76,12 @@ namespace ngraph
std::memcpy(&m_vector[elt_offset], p, n); std::memcpy(&m_vector[elt_offset], p, n);
} }
template <typename T>
void write(const std::vector<T>& values)
{
write(values.data(), 0, values.size() * sizeof(T));
}
virtual void read(void* p, size_t tensor_offset, size_t n) const override virtual void read(void* p, size_t tensor_offset, size_t n) const override
{ {
size_t elt_offset = tensor_offset / sizeof(typename ET::type); size_t elt_offset = tensor_offset / sizeof(typename ET::type);
...@@ -123,11 +103,6 @@ namespace ngraph ...@@ -123,11 +103,6 @@ namespace ngraph
std::memcpy(p, &m_vector[elt_offset], n); std::memcpy(p, &m_vector[elt_offset], n);
} }
bool operator==(const NDArrayBase<typename ET::type>& ndarray) const
{
return get_shape() == ndarray.get_shape() && get_vector() == ndarray.get_vector();
}
protected: protected:
storage_type m_vector; storage_type m_vector;
}; };
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "ngraph/runtime/tensor_view.hpp" #include "ngraph/runtime/tensor_view.hpp"
#include "ngraph/common.hpp" #include "ngraph/common.hpp"
#include "ngraph/types/element_type.hpp" #include "ngraph/types/element_type.hpp"
#include "ngraph/types/type.hpp"
using namespace ngraph::runtime; using namespace ngraph::runtime;
......
...@@ -33,9 +33,6 @@ namespace ngraph ...@@ -33,9 +33,6 @@ namespace ngraph
namespace runtime namespace runtime
{ {
template <typename ET>
class ParameterizedTensorView;
class TensorView : public Value class TensorView : public Value
{ {
protected: protected:
...@@ -46,11 +43,7 @@ namespace ngraph ...@@ -46,11 +43,7 @@ namespace ngraph
public: public:
virtual ~TensorView() {} virtual ~TensorView() {}
template <typename ET> TensorView& operator=(const TensorView&) = default;
ParameterizedTensorView<ET>* get_parameterized_tensor_view()
{
return dynamic_cast<ParameterizedTensorView<ET>*>(this);
}
std::shared_ptr<const ngraph::descriptor::TensorView> std::shared_ptr<const ngraph::descriptor::TensorView>
get_tensor_view_descriptor() const; get_tensor_view_descriptor() const;
...@@ -71,6 +64,12 @@ namespace ngraph ...@@ -71,6 +64,12 @@ namespace ngraph
/// @param n Number of bytes to write, must be integral number of elements. /// @param n Number of bytes to write, must be integral number of elements.
virtual void write(const void* p, size_t tensor_offset, size_t n) = 0; virtual void write(const void* p, size_t tensor_offset, size_t n) = 0;
template <typename T>
void write(const std::vector<T>& values)
{
write(values.data(), 0, values.size() * sizeof(T));
}
/// @brief Read bytes directly from the tensor /// @brief Read bytes directly from the tensor
/// @param p Pointer to destination for data /// @param p Pointer to destination for data
/// @param tensor_offset Offset into tensor storage to begin reading. Must be element-aligned. /// @param tensor_offset Offset into tensor storage to begin reading. Must be element-aligned.
......
...@@ -34,6 +34,16 @@ namespace ngraph ...@@ -34,6 +34,16 @@ namespace ngraph
return std::make_shared<runtime::ParameterizedTensorView<ET>>(shape); return std::make_shared<runtime::ParameterizedTensorView<ET>>(shape);
} }
/// @brief Framework constructor of a tensor of a specific element type and shape.
template <typename ET>
std::shared_ptr<ngraph::runtime::ParameterizedTensorView<ET>>
make_tensor(const Shape& shape, const std::vector<typename ET::type>& data)
{
auto rc = std::make_shared<runtime::ParameterizedTensorView<ET>>(shape);
rc->write(data.data(), 0, data.size() * sizeof(typename ET::type));
return rc;
}
/// @brief Framework constructor of a tuple from a sequence of values. /// @brief Framework constructor of a tuple from a sequence of values.
std::shared_ptr<ngraph::runtime::Tuple> std::shared_ptr<ngraph::runtime::Tuple>
make_tuple(const std::vector<std::shared_ptr<ngraph::runtime::Value>>& elements); make_tuple(const std::vector<std::shared_ptr<ngraph::runtime::Value>>& elements);
......
...@@ -35,6 +35,7 @@ namespace ngraph ...@@ -35,6 +35,7 @@ namespace ngraph
{ {
public: public:
virtual ~Value() {} virtual ~Value() {}
Value& operator=(const Value&) = default;
/// @brief The compile-time descriptor for this value. /// @brief The compile-time descriptor for this value.
virtual std::shared_ptr<ngraph::descriptor::Value> get_descriptor() const = 0; virtual std::shared_ptr<ngraph::descriptor::Value> get_descriptor() const = 0;
......
...@@ -21,35 +21,42 @@ ...@@ -21,35 +21,42 @@
using namespace ngraph; using namespace ngraph;
ngraph::element::Type::Type(size_t bitwidth, const element::Type element::boolean(8, false, false, "bool");
bool is_float, const element::Type element::f32(32, true, true, "float");
bool is_signed, const element::Type element::f64(64, true, true, "double");
const std::string& cname) const element::Type element::i8(8, false, true, "int8_t");
const element::Type element::i32(32, false, true, "int32_t");
const element::Type element::i64(64, false, true, "int64_t");
const element::Type element::u8(8, false, false, "uint8_t");
const element::Type element::u32(32, false, false, "uint32_t");
const element::Type element::u64(64, false, false, "uint64_t");
element::Type::Type(size_t bitwidth, bool is_real, bool is_signed, const std::string& cname)
: m_bitwidth{bitwidth} : m_bitwidth{bitwidth}
, m_is_float{is_float} , m_is_real{is_real}
, m_is_signed{is_signed} , m_is_signed{is_signed}
, m_cname{cname} , m_cname{cname}
{ {
assert(m_bitwidth % 8 == 0); assert(m_bitwidth % 8 == 0);
} }
const std::string& ngraph::element::Type::c_type_string() const const std::string& element::Type::c_type_string() const
{ {
return m_cname; return m_cname;
} }
bool ngraph::element::Type::operator==(const element::Type& other) const bool element::Type::operator==(const element::Type& other) const
{ {
return m_bitwidth == other.m_bitwidth && m_is_float == other.m_is_float && return m_bitwidth == other.m_bitwidth && m_is_real == other.m_is_real &&
m_is_signed == other.m_is_signed && m_cname == other.m_cname; m_is_signed == other.m_is_signed && m_cname == other.m_cname;
} }
size_t ngraph::element::Type::size() const size_t element::Type::size() const
{ {
return std::ceil(static_cast<float>(m_bitwidth) / 8.0f); return std::ceil(static_cast<float>(m_bitwidth) / 8.0f);
} }
std::ostream& ngraph::element::operator<<(std::ostream& out, const ngraph::element::Type& obj) std::ostream& element::operator<<(std::ostream& out, const element::Type& obj)
{ {
out << obj.m_cname; out << obj.m_cname;
return out; return out;
......
...@@ -26,11 +26,15 @@ ...@@ -26,11 +26,15 @@
#include "ngraph/common.hpp" #include "ngraph/common.hpp"
#include "ngraph/except.hpp" #include "ngraph/except.hpp"
#include "ngraph/runtime/parameterized_tensor_view.hpp"
#include "ngraph/runtime/tensor_view.hpp"
namespace ngraph namespace ngraph
{ {
namespace runtime
{
template <typename ET>
class ParameterizedTensorView;
}
namespace element namespace element
{ {
class Type class Type
...@@ -40,7 +44,7 @@ namespace ngraph ...@@ -40,7 +44,7 @@ namespace ngraph
public: public:
virtual ~Type() {} virtual ~Type() {}
Type(size_t bitwidth, bool is_float, bool is_signed, const std::string& cname); Type(size_t bitwidth, bool is_real, 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;
...@@ -50,9 +54,6 @@ namespace ngraph ...@@ -50,9 +54,6 @@ namespace ngraph
return h(m_cname); return h(m_cname);
} }
virtual std::shared_ptr<ngraph::runtime::TensorView>
make_primary_tensor_view(const Shape& shape) const = 0;
bool operator==(const Type& other) const; bool operator==(const Type& other) const;
bool operator!=(const Type& other) const { return !(*this == other); } bool operator!=(const Type& other) const { return !(*this == other); }
friend std::ostream& operator<<(std::ostream&, const Type&); friend std::ostream& operator<<(std::ostream&, const Type&);
...@@ -60,11 +61,21 @@ namespace ngraph ...@@ -60,11 +61,21 @@ namespace ngraph
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_real;
bool m_is_signed; bool m_is_signed;
const std::string m_cname; const std::string m_cname;
}; };
extern const Type boolean;
extern const Type f32;
extern const Type f64;
extern const Type i8;
extern const Type i32;
extern const Type i64;
extern const Type u8;
extern const Type u32;
extern const Type u64;
std::ostream& operator<<(std::ostream& out, const ngraph::element::Type& obj); std::ostream& operator<<(std::ostream& out, const ngraph::element::Type& obj);
// Provides a compile-time name for a C++ type. // Provides a compile-time name for a C++ type.
...@@ -111,12 +122,6 @@ namespace ngraph ...@@ -111,12 +122,6 @@ namespace ngraph
static TraitedType<T> t; static TraitedType<T> t;
return t; return t;
} }
virtual std::shared_ptr<ngraph::runtime::TensorView>
make_primary_tensor_view(const ngraph::Shape& shape) const override
{
return std::make_shared<runtime::ParameterizedTensorView<TraitedType<T>>>(shape);
}
}; };
NGRAPH_DEFINE_TRAITED_TYPE_NAME(char) NGRAPH_DEFINE_TRAITED_TYPE_NAME(char)
......
...@@ -37,10 +37,7 @@ set (SRC ...@@ -37,10 +37,7 @@ set (SRC
tensor.cpp tensor.cpp
topological_sort.cpp topological_sort.cpp
type_prop.cpp type_prop.cpp
util/all_close.cpp
util/autodiff/backprop_derivative.cpp
util/autodiff/backprop_function.cpp util/autodiff/backprop_function.cpp
util/autodiff/numeric_derivative.cpp
util/test_tools.cpp util/test_tools.cpp
util.cpp util.cpp
uuid.cpp uuid.cpp
......
...@@ -1068,8 +1068,7 @@ TEST(${BACKEND_NAME}, subtract) ...@@ -1068,8 +1068,7 @@ TEST(${BACKEND_NAME}, subtract)
TEST(${BACKEND_NAME}, scalar_constant) TEST(${BACKEND_NAME}, scalar_constant)
{ {
auto shape = Shape{}; auto shape = Shape{};
auto t = runtime::make_tensor<element::Float32>(shape); auto t = runtime::make_tensor<element::Float32>(shape, {-3.0f});
(*t) = std::vector<float>{-3.0f};
auto A = make_shared<op::ParameterizedConstant<element::Float32>>(shape, t); auto A = make_shared<op::ParameterizedConstant<element::Float32>>(shape, t);
auto rt = make_shared<TensorViewType>(element::Float32::element_type(), shape); auto rt = make_shared<TensorViewType>(element::Float32::element_type(), shape);
auto f = make_shared<Function>(A, rt, op::Parameters{}); auto f = make_shared<Function>(A, rt, op::Parameters{});
...@@ -1089,8 +1088,7 @@ TEST(${BACKEND_NAME}, scalar_constant) ...@@ -1089,8 +1088,7 @@ TEST(${BACKEND_NAME}, scalar_constant)
TEST(${BACKEND_NAME}, tensor_constant) TEST(${BACKEND_NAME}, tensor_constant)
{ {
auto shape = Shape{2, 2, 2}; auto shape = Shape{2, 2, 2};
auto t = runtime::make_tensor<element::Float32>(shape); auto t = runtime::make_tensor<element::Float32>(shape, {1, 2, 3, 4, 5, 6, 7, 8});
(*t) = std::vector<float>{1, 2, 3, 4, 5, 6, 7, 8};
auto A = make_shared<op::ParameterizedConstant<element::Float32>>(shape, t); auto A = make_shared<op::ParameterizedConstant<element::Float32>>(shape, t);
auto rt = make_shared<TensorViewType>(element::Float32::element_type(), shape); auto rt = make_shared<TensorViewType>(element::Float32::element_type(), shape);
auto f = make_shared<Function>(A, rt, op::Parameters{}); auto f = make_shared<Function>(A, rt, op::Parameters{});
...@@ -1110,8 +1108,7 @@ TEST(${BACKEND_NAME}, tensor_constant) ...@@ -1110,8 +1108,7 @@ TEST(${BACKEND_NAME}, tensor_constant)
TEST(${BACKEND_NAME}, tensor_constant_with_op) TEST(${BACKEND_NAME}, tensor_constant_with_op)
{ {
auto shape = Shape{2, 2, 2}; auto shape = Shape{2, 2, 2};
auto t = runtime::make_tensor<element::Float32>(shape); auto t = runtime::make_tensor<element::Float32>(shape, {-1, 2, 3, -4, 5, -6, -7, 8});
(*t) = std::vector<float>{-1, 2, 3, -4, 5, -6, -7, 8};
auto A = make_shared<op::ParameterizedConstant<element::Float32>>(shape, t); auto A = make_shared<op::ParameterizedConstant<element::Float32>>(shape, t);
auto rt = make_shared<TensorViewType>(element::Float32::element_type(), shape); auto rt = make_shared<TensorViewType>(element::Float32::element_type(), shape);
auto f = make_shared<Function>(make_shared<op::Abs>(A), rt, op::Parameters{}); auto f = make_shared<Function>(make_shared<op::Abs>(A), rt, op::Parameters{});
......
...@@ -81,8 +81,7 @@ TEST(build_graph, literal) ...@@ -81,8 +81,7 @@ TEST(build_graph, literal)
{ {
// float scalar from a float // float scalar from a float
//auto float0 = FloatConstant::make(3.0); //auto float0 = FloatConstant::make(3.0);
auto float_t = ngraph::runtime::make_tensor<element::Float32>(Shape{}); auto float_t = ngraph::runtime::make_tensor<element::Float32>(Shape{}, {3.0});
(*float_t) = std::vector<float>{3.0};
auto float0 = make_shared<op::Float32Constant>(Shape{}, float_t); auto float0 = make_shared<op::Float32Constant>(Shape{}, float_t);
auto float_scalar_type = make_shared<TensorViewType>(element::Float32::element_type(), Shape{}); auto float_scalar_type = make_shared<TensorViewType>(element::Float32::element_type(), Shape{});
ASSERT_EQ(float0->get_value()->get_vector(), std::vector<float>{3.0}); ASSERT_EQ(float0->get_value()->get_vector(), std::vector<float>{3.0});
...@@ -91,8 +90,7 @@ TEST(build_graph, literal) ...@@ -91,8 +90,7 @@ TEST(build_graph, literal)
ASSERT_EQ(d->get_arguments().at(0), float0); ASSERT_EQ(d->get_arguments().at(0), float0);
ASSERT_EQ(d->get_arguments().at(1), float0); ASSERT_EQ(d->get_arguments().at(1), float0);
auto int32_t = ngraph::runtime::make_tensor<element::Int32>(Shape{}); auto int32_t = ngraph::runtime::make_tensor<element::Int32>(Shape{}, {3});
(*int32_t) = std::vector<int>{3};
auto int32_0 = make_shared<op::Int32Constant>(Shape{}, int32_t); auto int32_0 = make_shared<op::Int32Constant>(Shape{}, int32_t);
auto int32_scalar_type = make_shared<TensorViewType>(element::Int32::element_type(), Shape{}); auto int32_scalar_type = make_shared<TensorViewType>(element::Int32::element_type(), Shape{});
ASSERT_EQ(int32_0->get_value()->get_vector(), std::vector<int>{3}); ASSERT_EQ(int32_0->get_value()->get_vector(), std::vector<int>{3});
......
...@@ -22,6 +22,13 @@ ...@@ -22,6 +22,13 @@
using namespace std; using namespace std;
using namespace ngraph; using namespace ngraph;
template <typename T>
static void copy_data(shared_ptr<runtime::TensorView> tv, const vector<T>& data)
{
size_t data_size = data.size() * sizeof(T);
tv->write(data.data(), 0, data_size);
}
template <typename OP> template <typename OP>
bool check_unary() bool check_unary()
{ {
...@@ -128,11 +135,12 @@ TEST(copy, parameterized_constant) ...@@ -128,11 +135,12 @@ TEST(copy, parameterized_constant)
auto backend = manager->allocate_backend(); auto backend = manager->allocate_backend();
// Create some tensors for input/output // Create some tensors for input/output
auto c = backend->make_parameterized_tensor_view<element::Float32>( auto c = backend->make_primary_tensor_view(element::Float32::element_type(), Shape{2, 2});
runtime::NDArray<float, 2>({{1, 2}, {3, 4}})); copy_data(c, runtime::NDArray<float, 2>({{1, 2}, {3, 4}}).get_vector());
Shape shape{2, 2}; Shape shape{2, 2};
auto node = make_shared<op::ParameterizedConstant<element::Float32>>(shape, c); auto cptv = dynamic_pointer_cast<ngraph::runtime::ParameterizedTensorView<element::Float32>>(c);
auto node = make_shared<op::ParameterizedConstant<element::Float32>>(shape, cptv);
auto new_node = node->copy_with_new_args(Nodes{}); auto new_node = node->copy_with_new_args(Nodes{});
auto node_cast = dynamic_pointer_cast<op::ParameterizedConstant<element::Float32>>(new_node); auto node_cast = dynamic_pointer_cast<op::ParameterizedConstant<element::Float32>>(new_node);
ASSERT_TRUE(nullptr != new_node); ASSERT_TRUE(nullptr != new_node);
......
...@@ -89,7 +89,6 @@ void test_read_write(const std::vector<typename ET::type>& x) ...@@ -89,7 +89,6 @@ void test_read_write(const std::vector<typename ET::type>& x)
auto backend = manager->allocate_backend(); auto backend = manager->allocate_backend();
auto a = backend->make_primary_tensor_view(ET::element_type(), Shape{2, x.size()}); auto a = backend->make_primary_tensor_view(ET::element_type(), Shape{2, x.size()});
auto af = a->template get_parameterized_tensor_view<ET>();
std::vector<T> result(2 * x.size()); std::vector<T> result(2 * x.size());
...@@ -98,7 +97,8 @@ void test_read_write(const std::vector<typename ET::type>& x) ...@@ -98,7 +97,8 @@ void test_read_write(const std::vector<typename ET::type>& x)
a->write(&x[0], x.size() * sizeof(T), x.size() * sizeof(T)); a->write(&x[0], x.size() * sizeof(T), x.size() * sizeof(T));
std::copy(x.begin(), x.end(), result.begin() + x.size()); std::copy(x.begin(), x.end(), result.begin() + x.size());
auto& af_vector = af->get_vector(); std::vector<T> af_vector(2 * x.size());
a->read(af_vector.data(), 0, af_vector.size() * sizeof(typename ET::type));
ASSERT_EQ(af_vector, result); ASSERT_EQ(af_vector, result);
std::vector<T> result1(x.size()); std::vector<T> result1(x.size());
......
...@@ -25,6 +25,13 @@ ...@@ -25,6 +25,13 @@
using namespace std; using namespace std;
using namespace ngraph; using namespace ngraph;
template <typename T>
static void copy_data(shared_ptr<runtime::TensorView> tv, const vector<T>& data)
{
size_t data_size = data.size() * sizeof(T);
tv->write(data.data(), 0, data_size);
}
TEST(util, split) TEST(util, split)
{ {
{ {
...@@ -178,15 +185,17 @@ TEST(util, all_close) ...@@ -178,15 +185,17 @@ TEST(util, all_close)
auto backend = manager->allocate_backend(); auto backend = manager->allocate_backend();
// Create some tensors for input/output // Create some tensors for input/output
auto a = backend->make_parameterized_tensor_view<element::Float32>( auto a = backend->make_parameterized_tensor_view<element::Float32>(Shape{2, 3});
runtime::NDArray<float, 2>({{1, 2, 3}, {3, 4, 5}})); auto b = backend->make_parameterized_tensor_view<element::Float32>(Shape{2, 3});
auto b = backend->make_parameterized_tensor_view<element::Float32>(
runtime::NDArray<float, 2>({{1, 2, 3}, {3, 4, 5}})); copy_data(a, runtime::NDArray<float, 2>({{1, 2, 3}, {3, 4, 5}}).get_vector());
copy_data(b, runtime::NDArray<float, 2>({{1, 2, 3}, {3, 4, 5}}).get_vector());
EXPECT_TRUE(ngraph::test::all_close(a, b)); EXPECT_TRUE(ngraph::test::all_close(a, b));
auto c = backend->make_parameterized_tensor_view<element::Float32>( auto c = backend->make_parameterized_tensor_view<element::Float32>(Shape{2, 3});
runtime::NDArray<float, 2>({{1.1f, 2, 3}, {3, 4, 5}})); copy_data(c, runtime::NDArray<float, 2>({{1.1f, 2, 3}, {3, 4, 5}}).get_vector());
EXPECT_FALSE(ngraph::test::all_close(c, a, 0, .05f)); EXPECT_FALSE(ngraph::test::all_close(c, a, 0, .05f));
EXPECT_TRUE(ngraph::test::all_close(c, a, 0, .11f)); EXPECT_TRUE(ngraph::test::all_close(c, a, 0, .11f));
......
// ----------------------------------------------------------------------------
// 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 <cmath>
#include <memory>
#include <vector>
#include "all_close.hpp"
#include "ngraph/except.hpp"
template <typename ET>
bool ngraph::test::all_close(
const std::vector<std::shared_ptr<ngraph::runtime::ParameterizedTensorView<ET>>>& as,
const std::vector<std::shared_ptr<ngraph::runtime::ParameterizedTensorView<ET>>>& bs,
typename ET::type rtol,
typename ET::type atol)
{
if (as.size() != bs.size())
{
return false;
}
for (size_t i = 0; i < as.size(); ++i)
{
if (!all_close(as[i], bs[i], rtol, atol))
{
return false;
}
}
return true;
}
template bool ngraph::test::all_close<ngraph::element::Float32>(
const std::vector<
std::shared_ptr<ngraph::runtime::ParameterizedTensorView<ngraph::element::Float32>>>& as,
const std::vector<
std::shared_ptr<ngraph::runtime::ParameterizedTensorView<ngraph::element::Float32>>>& bs,
ngraph::element::Float32::type rtol,
ngraph::element::Float32::type atol);
template bool ngraph::test::all_close<ngraph::element::Float64>(
const std::vector<
std::shared_ptr<ngraph::runtime::ParameterizedTensorView<ngraph::element::Float64>>>& as,
const std::vector<
std::shared_ptr<ngraph::runtime::ParameterizedTensorView<ngraph::element::Float64>>>& bs,
ngraph::element::Float64::type rtol,
ngraph::element::Float64::type atol);
template <typename ET>
bool ngraph::test::all_close(const std::shared_ptr<ngraph::runtime::ParameterizedTensorView<ET>>& a,
const std::shared_ptr<ngraph::runtime::ParameterizedTensorView<ET>>& b,
typename ET::type rtol,
typename ET::type atol)
{
// Check that the layouts are compatible
if (*a->get_tensor_view_layout() != *b->get_tensor_view_layout())
{
throw ngraph_error("Cannot compare tensors with different layouts");
}
if (a->get_shape() != b->get_shape())
return false;
return all_close(a->get_vector(), b->get_vector(), rtol, atol);
}
template bool ngraph::test::all_close<ngraph::element::Float32>(
const std::shared_ptr<ngraph::runtime::ParameterizedTensorView<ngraph::element::Float32>>& a,
const std::shared_ptr<ngraph::runtime::ParameterizedTensorView<ngraph::element::Float32>>& b,
ngraph::element::Float32::type rtol,
ngraph::element::Float32::type atol);
template bool ngraph::test::all_close<ngraph::element::Float64>(
const std::shared_ptr<ngraph::runtime::ParameterizedTensorView<ngraph::element::Float64>>& a,
const std::shared_ptr<ngraph::runtime::ParameterizedTensorView<ngraph::element::Float64>>& b,
ngraph::element::Float64::type rtol,
ngraph::element::Float64::type atol);
template <typename T>
bool ngraph::test::all_close(const std::vector<T>& a, const std::vector<T>& b, T rtol, T atol)
{
assert(a.size() == b.size());
for (size_t i = 0; i < a.size(); ++i)
{
if (std::abs(a[i] - b[i]) > atol + rtol * std::abs(b[i]))
{
return false;
}
}
return true;
}
template bool ngraph::test::all_close<float>(const std::vector<float>& a,
const std::vector<float>& b,
float rtol,
float atol);
template bool ngraph::test::all_close<double>(const std::vector<double>& a,
const std::vector<double>& b,
double rtol,
double atol);
...@@ -25,33 +25,27 @@ namespace ngraph ...@@ -25,33 +25,27 @@ namespace ngraph
namespace test namespace test
{ {
/// @brief Same as numpy.allclose /// @brief Same as numpy.allclose
/// @param as First tensors to compare /// @param a First tensor to compare
/// @param bs Second tensors to compare /// @param b Second tensor to compare
/// @param rtol Relative tolerance /// @param rtol Relative tolerance
/// @param atol Absolute tolerance /// @param atol Absolute tolerance
/// Returns true if shapes match and for all elements, |a_i-b_i| <= atol + rtol*|b_i|. /// @returns true if shapes match and for all elements, |a_i-b_i| <= atol + rtol*|b_i|.
template <typename ET> template <typename T>
bool all_close( bool all_close(const std::vector<T>& a,
const std::vector<std::shared_ptr<ngraph::runtime::ParameterizedTensorView<ET>>>& as, const std::vector<T>& b,
const std::vector<std::shared_ptr<ngraph::runtime::ParameterizedTensorView<ET>>>& bs, T rtol = 1e-5f,
typename ET::type rtol, T atol = 1e-8f)
typename ET::type atol); {
assert(a.size() == b.size());
extern template bool all_close<element::Float32>( for (size_t i = 0; i < a.size(); ++i)
const std::vector<std::shared_ptr<runtime::ParameterizedTensorView<element::Float32>>>& {
as, if (std::abs(a[i] - b[i]) > atol + rtol * std::abs(b[i]))
const std::vector<std::shared_ptr<runtime::ParameterizedTensorView<element::Float32>>>& {
bs, return false;
element::Float32::type rtol, }
element::Float32::type atol); }
return true;
extern template bool all_close<element::Float64>( }
const std::vector<std::shared_ptr<runtime::ParameterizedTensorView<element::Float64>>>&
as,
const std::vector<std::shared_ptr<runtime::ParameterizedTensorView<element::Float64>>>&
bs,
element::Float64::type rtol,
element::Float64::type atol);
/// @brief Same as numpy.allclose /// @brief Same as numpy.allclose
/// @param a First tensor to compare /// @param a First tensor to compare
...@@ -63,44 +57,45 @@ namespace ngraph ...@@ -63,44 +57,45 @@ namespace ngraph
bool all_close(const std::shared_ptr<ngraph::runtime::ParameterizedTensorView<ET>>& a, bool all_close(const std::shared_ptr<ngraph::runtime::ParameterizedTensorView<ET>>& a,
const std::shared_ptr<ngraph::runtime::ParameterizedTensorView<ET>>& b, const std::shared_ptr<ngraph::runtime::ParameterizedTensorView<ET>>& b,
typename ET::type rtol = 1e-5f, typename ET::type rtol = 1e-5f,
typename ET::type atol = 1e-8f); typename ET::type atol = 1e-8f)
{
// Check that the layouts are compatible
if (*a->get_tensor_view_layout() != *b->get_tensor_view_layout())
{
throw ngraph_error("Cannot compare tensors with different layouts");
}
extern template bool all_close<ngraph::element::Float32>( if (a->get_shape() != b->get_shape())
const std::shared_ptr< return false;
ngraph::runtime::ParameterizedTensorView<ngraph::element::Float32>>& a,
const std::shared_ptr<
ngraph::runtime::ParameterizedTensorView<ngraph::element::Float32>>& b,
ngraph::element::Float32::type rtol,
ngraph::element::Float32::type atol);
extern template bool all_close<ngraph::element::Float64>( return all_close(a->get_vector(), b->get_vector(), rtol, atol);
const std::shared_ptr< }
ngraph::runtime::ParameterizedTensorView<ngraph::element::Float64>>& a,
const std::shared_ptr<
ngraph::runtime::ParameterizedTensorView<ngraph::element::Float64>>& b,
ngraph::element::Float64::type rtol,
ngraph::element::Float64::type atol);
/// @brief Same as numpy.allclose /// @brief Same as numpy.allclose
/// @param a First tensor to compare /// @param as First tensors to compare
/// @param b Second tensor to compare /// @param bs Second tensors to compare
/// @param rtol Relative tolerance /// @param rtol Relative tolerance
/// @param atol Absolute tolerance /// @param atol Absolute tolerance
/// @returns true if shapes match and for all elements, |a_i-b_i| <= atol + rtol*|b_i|. /// Returns true if shapes match and for all elements, |a_i-b_i| <= atol + rtol*|b_i|.
template <typename T> template <typename ET>
bool all_close(const std::vector<T>& a, bool all_close(
const std::vector<T>& b, const std::vector<std::shared_ptr<ngraph::runtime::ParameterizedTensorView<ET>>>& as,
T rtol = 1e-5f, const std::vector<std::shared_ptr<ngraph::runtime::ParameterizedTensorView<ET>>>& bs,
T atol = 1e-8f); typename ET::type rtol,
typename ET::type atol)
extern template bool all_close<float>(const std::vector<float>& a, {
const std::vector<float>& b, if (as.size() != bs.size())
float rtol, {
float atol); return false;
}
extern template bool all_close<double>(const std::vector<double>& a, for (size_t i = 0; i < as.size(); ++i)
const std::vector<double>& b, {
double rtol, if (!all_close(as[i], bs[i], rtol, atol))
double atol); {
return false;
}
}
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
// ----------------------------------------------------------------------------
#include <memory>
#include <vector>
#include "backprop_derivative.hpp"
#include "ngraph/function.hpp"
#include "ngraph/ops/tuple.hpp"
#include "ngraph/runtime/backend.hpp"
#include "ngraph/runtime/call_frame.hpp"
#include "ngraph/runtime/manager.hpp"
#include "ngraph/runtime/parameterized_tensor_view.hpp"
#include "ngraph/types/type.hpp"
using namespace ngraph;
template <typename ET>
std::vector<std::shared_ptr<ngraph::runtime::ParameterizedTensorView<ET>>>
autodiff::backprop_derivative(
const std::shared_ptr<runtime::Manager>& manager,
const std::shared_ptr<runtime::Backend>& backend,
const std::shared_ptr<Function>& f,
const std::vector<std::shared_ptr<runtime::ParameterizedTensorView<ET>>>& args)
{
auto y = f->get_result();
Shape y_shape =
std::dynamic_pointer_cast<const TensorViewType>(y->get_value_type())->get_shape();
auto c_param = std::make_shared<op::Parameter>(ET::element_type(), y_shape);
auto c_arg = backend->make_parameterized_tensor_view<ET>(y_shape);
auto params = f->get_parameters();
std::vector<std::shared_ptr<Node>> deriv_nodes;
std::vector<std::shared_ptr<runtime::ParameterizedTensorView<ET>>> bprops;
std::vector<std::shared_ptr<runtime::ParameterizedTensorView<ET>>> results;
for (auto param : params)
{
Shape s = y_shape;
auto param_shape =
std::dynamic_pointer_cast<const TensorViewType>(param->get_value_type())->get_shape();
s.insert(s.end(), param_shape.begin(), param_shape.end());
results.push_back(backend->make_parameterized_tensor_view<ET>(s));
bprops.push_back(backend->make_parameterized_tensor_view<ET>(param_shape));
deriv_nodes.push_back(y->backprop_node(param, c_param));
}
std::vector<std::shared_ptr<op::Parameter>> df_params = params;
df_params.push_back(c_param);
auto df_result = std::make_shared<op::Tuple>(deriv_nodes);
auto df = std::make_shared<Function>(df_result, df_result->get_value_type(), df_params);
auto external = manager->compile(df);
auto cf = backend->make_call_frame(external);
// We compute the derivatives chunk by chunk
std::vector<typename std::vector<typename ET::type>::iterator> result_pos;
for (auto result : results)
{
result_pos.push_back(result->get_vector().begin());
}
ngraph::runtime::TensorViewPtrs args_tv;
args_tv.insert(args_tv.begin(), args.begin(), args.end());
args_tv.push_back(c_arg);
runtime::TensorViewPtrs bprops_tv;
bprops_tv.insert(bprops_tv.begin(), bprops.begin(), bprops.end());
auto& c_vec = c_arg->get_vector();
for (size_t i = 0; i < c_vec.size(); i++)
{
c_vec[i] = 1;
cf->tensor_call(args_tv, bprops_tv);
c_vec[i] = 0;
for (size_t j = 0; j < results.size(); j++)
{
auto& bprop_vec = bprops[j]->get_vector();
result_pos[j] = std::copy(bprop_vec.begin(), bprop_vec.end(), result_pos[j]);
}
}
return results;
}
template std::vector<
std::shared_ptr<ngraph::runtime::ParameterizedTensorView<ngraph::element::Float32>>>
autodiff::backprop_derivative<ngraph::element::Float32>(
const std::shared_ptr<runtime::Manager>& manager,
const std::shared_ptr<runtime::Backend>& backend,
const std::shared_ptr<Function>& f,
const std::vector<
std::shared_ptr<ngraph::runtime::ParameterizedTensorView<element::Float32>>>& args);
template std::vector<
std::shared_ptr<ngraph::runtime::ParameterizedTensorView<ngraph::element::Float64>>>
autodiff::backprop_derivative<ngraph::element::Float64>(
const std::shared_ptr<runtime::Manager>& manager,
const std::shared_ptr<runtime::Backend>& backend,
const std::shared_ptr<Function>& f,
const std::vector<
std::shared_ptr<ngraph::runtime::ParameterizedTensorView<element::Float64>>>& args);
...@@ -16,8 +16,10 @@ ...@@ -16,8 +16,10 @@
#include <memory> #include <memory>
#include "ngraph/log.hpp"
#include "ngraph/runtime/parameterized_tensor_view.hpp" #include "ngraph/runtime/parameterized_tensor_view.hpp"
#include "ngraph/types/element_type.hpp" #include "ngraph/types/element_type.hpp"
#include "ngraph/util.hpp"
namespace ngraph namespace ngraph
{ {
...@@ -42,24 +44,76 @@ namespace ngraph ...@@ -42,24 +44,76 @@ namespace ngraph
const std::shared_ptr<runtime::Manager>& manager, const std::shared_ptr<runtime::Manager>& manager,
const std::shared_ptr<runtime::Backend>& backend, const std::shared_ptr<runtime::Backend>& backend,
const std::shared_ptr<Function>& f, const std::shared_ptr<Function>& f,
const std::vector<std::shared_ptr<runtime::ParameterizedTensorView<ET>>>& args); const std::vector<std::shared_ptr<runtime::ParameterizedTensorView<ET>>>& args)
{
extern template std::vector< auto y = f->get_result();
std::shared_ptr<runtime::ParameterizedTensorView<ngraph::element::Float32>>> Shape y_shape =
backprop_derivative<ngraph::element::Float32>( std::dynamic_pointer_cast<const TensorViewType>(y->get_value_type())->get_shape();
const std::shared_ptr<runtime::Manager>& manager,
const std::shared_ptr<runtime::Backend>& backend, auto c_param = std::make_shared<op::Parameter>(ET::element_type(), y_shape);
const std::shared_ptr<Function>& f, auto c_arg = backend->make_parameterized_tensor_view<ET>(y_shape);
const std::vector< auto params = f->get_parameters();
std::shared_ptr<runtime::ParameterizedTensorView<element::Float32>>>& args);
std::vector<std::shared_ptr<Node>> deriv_nodes;
extern template std::vector< std::vector<std::shared_ptr<runtime::ParameterizedTensorView<ET>>> bprops;
std::shared_ptr<runtime::ParameterizedTensorView<ngraph::element::Float64>>> std::vector<std::shared_ptr<runtime::ParameterizedTensorView<ET>>> results;
backprop_derivative<ngraph::element::Float64>( for (auto param : params)
const std::shared_ptr<runtime::Manager>& manager, {
const std::shared_ptr<runtime::Backend>& backend, Shape s = y_shape;
const std::shared_ptr<Function>& f, auto param_shape =
const std::vector< std::dynamic_pointer_cast<const TensorViewType>(param->get_value_type())
std::shared_ptr<runtime::ParameterizedTensorView<element::Float64>>>& args); ->get_shape();
s.insert(s.end(), param_shape.begin(), param_shape.end());
results.push_back(backend->make_parameterized_tensor_view<ET>(s));
bprops.push_back(backend->make_parameterized_tensor_view<ET>(param_shape));
deriv_nodes.push_back(y->backprop_node(param, c_param));
}
std::vector<std::shared_ptr<op::Parameter>> df_params = params;
df_params.push_back(c_param);
auto df_result = std::make_shared<op::Tuple>(deriv_nodes);
auto df = std::make_shared<Function>(df_result, df_result->get_value_type(), df_params);
auto external = manager->compile(df);
auto cf = backend->make_call_frame(external);
// We compute the derivatives chunk by chunk
std::vector<typename std::vector<typename ET::type>::iterator> result_pos;
std::vector<std::vector<typename ET::type>> result_vect;
for (auto result : results)
{
result_vect.push_back(result->get_vector()); // storage for results
result_pos.push_back(result_vect.back().begin());
}
ngraph::runtime::TensorViewPtrs args_tv;
args_tv.insert(args_tv.begin(), args.begin(), args.end());
args_tv.push_back(c_arg);
runtime::TensorViewPtrs bprops_tv;
bprops_tv.insert(bprops_tv.begin(), bprops.begin(), bprops.end());
auto c_vec = c_arg->get_vector();
for (size_t i = 0; i < c_vec.size(); i++)
{
c_vec[i] = 1;
c_arg->write(c_vec);
cf->tensor_call(args_tv, bprops_tv);
c_vec[i] = 0;
c_arg->write(c_vec);
for (size_t j = 0; j < results.size(); j++)
{
auto bprop_vec = bprops[j]->get_vector();
result_pos[j] = std::copy(bprop_vec.begin(), bprop_vec.end(), result_pos[j]);
}
}
// Copy results from temp to result vector
for (size_t j = 0; j < results.size(); j++)
{
results[j]->write(result_vect[j]);
}
return results;
}
} }
} }
...@@ -36,30 +36,5 @@ namespace ngraph ...@@ -36,30 +36,5 @@ namespace ngraph
/// @param f is f(X_i...) /// @param f is f(X_i...)
/// @returns f'(X_i..., c) where f'(x_i, ..., c)_j is backprop for X_j /// @returns f'(X_i..., c) where f'(x_i, ..., c)_j is backprop for X_j
std::shared_ptr<Function> backprop_function(const std::shared_ptr<Function>& f); std::shared_ptr<Function> backprop_function(const std::shared_ptr<Function>& f);
template <typename ET>
std::vector<std::shared_ptr<runtime::ParameterizedTensorView<ET>>> backprop_derivative(
const std::shared_ptr<runtime::Manager>& manager,
const std::shared_ptr<runtime::Backend>& backend,
const std::shared_ptr<Function>& f,
const std::vector<std::shared_ptr<runtime::ParameterizedTensorView<ET>>>& args);
extern template std::vector<
std::shared_ptr<runtime::ParameterizedTensorView<ngraph::element::Float32>>>
backprop_derivative<ngraph::element::Float32>(
const std::shared_ptr<runtime::Manager>& manager,
const std::shared_ptr<runtime::Backend>& backend,
const std::shared_ptr<Function>& f,
const std::vector<
std::shared_ptr<runtime::ParameterizedTensorView<element::Float32>>>& args);
extern template std::vector<
std::shared_ptr<runtime::ParameterizedTensorView<ngraph::element::Float64>>>
backprop_derivative<ngraph::element::Float64>(
const std::shared_ptr<runtime::Manager>& manager,
const std::shared_ptr<runtime::Backend>& backend,
const std::shared_ptr<Function>& f,
const std::vector<
std::shared_ptr<runtime::ParameterizedTensorView<element::Float64>>>& args);
} }
} }
// ----------------------------------------------------------------------------
// 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 <algorithm>
#include <cassert>
#include <cmath>
#include "ngraph/function.hpp"
#include "ngraph/ops/tuple.hpp"
#include "ngraph/runtime/call_frame.hpp"
#include "numeric_derivative.hpp"
using namespace ngraph;
template <typename ET>
std::vector<std::shared_ptr<ngraph::runtime::ParameterizedTensorView<ET>>>
autodiff::numeric_derivative(
const std::shared_ptr<runtime::Manager>& manager,
const std::shared_ptr<runtime::Backend>& backend,
const std::shared_ptr<Function>& f,
const std::vector<std::shared_ptr<runtime::ParameterizedTensorView<ET>>>& args,
typename ET::type delta)
{
auto y = f->get_result();
Shape y_shape =
std::dynamic_pointer_cast<const TensorViewType>(y->get_value_type())->get_shape();
auto params = f->get_parameters();
// Results for each derivative, shape Y|X_i
std::vector<std::shared_ptr<runtime::ParameterizedTensorView<ET>>> results;
for (auto param : params)
{
Shape s = y_shape;
auto param_shape =
std::dynamic_pointer_cast<const TensorViewType>(param->get_value_type())->get_shape();
s.insert(s.end(), param_shape.begin(), param_shape.end());
results.push_back(backend->make_parameterized_tensor_view<ET>(s));
}
auto external = manager->compile(f);
auto cf = backend->make_call_frame(external);
// ref_y is the function evaluated at the args
auto ref_y = backend->make_parameterized_tensor_view<ET>(y_shape);
ngraph::runtime::TensorViewPtrs args_tv;
args_tv.insert(args_tv.begin(), args.begin(), args.end());
cf->tensor_call(args_tv, runtime::TensorViewPtrs{ref_y});
auto& ref_vec = ref_y->get_vector();
// inc_y will hold f(x+dx) values
auto inc_y = backend->make_parameterized_tensor_view<ET>(y_shape);
auto& inc_vec = inc_y->get_vector();
// Assuming vars, y, and results are row-major
typename ET::type inv_delta = 1 / delta;
for (size_t i = 0; i < args.size(); ++i)
{
auto arg = args[i];
auto& res = results[i]->get_vector();
auto& vec = arg->get_vector();
for (size_t j = 0; j < vec.size(); j++)
{
auto old_val = vec[j];
vec[j] += delta;
cf->tensor_call(args_tv, {inc_y});
vec[j] = old_val;
size_t res_k = j;
for (size_t k = 0; k < inc_vec.size(); k++)
{
auto y1 = inc_vec[k];
auto y0 = ref_vec[k];
res[res_k] = inv_delta * (y1 - y0);
res_k += vec.size();
}
}
}
return results;
}
template std::vector<std::shared_ptr<runtime::ParameterizedTensorView<element::Float32>>>
autodiff::numeric_derivative(
const std::shared_ptr<runtime::Manager>& manager,
const std::shared_ptr<runtime::Backend>& backend,
const std::shared_ptr<Function>& f,
const std::vector<std::shared_ptr<runtime::ParameterizedTensorView<element::Float32>>>&
args,
element::Float32::type delta);
template std::vector<std::shared_ptr<ngraph::runtime::ParameterizedTensorView<element::Float64>>>
autodiff::numeric_derivative(
const std::shared_ptr<runtime::Manager>& manager,
const std::shared_ptr<runtime::Backend>& backend,
const std::shared_ptr<Function>& f,
const std::vector<std::shared_ptr<runtime::ParameterizedTensorView<element::Float64>>>&
args,
element::Float64::type delta);
...@@ -39,26 +39,71 @@ namespace ngraph ...@@ -39,26 +39,71 @@ namespace ngraph
const std::shared_ptr<runtime::Backend>& backend, const std::shared_ptr<runtime::Backend>& backend,
const std::shared_ptr<Function>& f, const std::shared_ptr<Function>& f,
const std::vector<std::shared_ptr<runtime::ParameterizedTensorView<ET>>>& args, const std::vector<std::shared_ptr<runtime::ParameterizedTensorView<ET>>>& args,
typename ET::type delta); typename ET::type delta)
{
auto y = f->get_result();
extern template std::vector< Shape y_shape =
std::shared_ptr<runtime::ParameterizedTensorView<element::Float32>>> std::dynamic_pointer_cast<const TensorViewType>(y->get_value_type())->get_shape();
numeric_derivative(
const std::shared_ptr<runtime::Manager>& manager,
const std::shared_ptr<runtime::Backend>& backend,
const std::shared_ptr<Function>& f,
const std::vector<
std::shared_ptr<runtime::ParameterizedTensorView<element::Float32>>>& args,
element::Float32::type delta);
extern template std::vector< auto params = f->get_parameters();
std::shared_ptr<runtime::ParameterizedTensorView<element::Float64>>>
numeric_derivative( // Results for each derivative, shape Y|X_i
const std::shared_ptr<runtime::Manager>& manager, std::vector<std::shared_ptr<runtime::ParameterizedTensorView<ET>>> results;
const std::shared_ptr<runtime::Backend>& backend, for (auto param : params)
const std::shared_ptr<Function>& f, {
const std::vector< Shape s = y_shape;
std::shared_ptr<runtime::ParameterizedTensorView<element::Float64>>>& args, auto param_shape =
element::Float64::type delta); std::dynamic_pointer_cast<const TensorViewType>(param->get_value_type())
->get_shape();
s.insert(s.end(), param_shape.begin(), param_shape.end());
results.push_back(backend->make_parameterized_tensor_view<ET>(s));
}
auto external = manager->compile(f);
auto cf = backend->make_call_frame(external);
// ref_y is the function evaluated at the args
auto ref_y = backend->make_parameterized_tensor_view<ET>(y_shape);
ngraph::runtime::TensorViewPtrs args_tv;
args_tv.insert(args_tv.begin(), args.begin(), args.end());
cf->tensor_call(args_tv, runtime::TensorViewPtrs{ref_y});
auto& ref_vec = ref_y->get_vector();
// inc_y will hold f(x+dx) values
auto inc_y = backend->make_parameterized_tensor_view<ET>(y_shape);
auto& inc_vec = inc_y->get_vector();
// Assuming vars, y, and results are row-major
typename ET::type inv_delta = 1 / delta;
for (size_t i = 0; i < args.size(); ++i)
{
auto arg = args[i];
auto res = results[i]->get_vector();
auto vec = arg->get_vector();
for (size_t j = 0; j < vec.size(); j++)
{
auto old_val = vec[j];
vec[j] += delta;
arg->write(vec);
cf->tensor_call(args_tv, {inc_y});
vec[j] = old_val;
arg->write(vec);
size_t res_k = j;
for (size_t k = 0; k < inc_vec.size(); k++)
{
auto y1 = inc_vec[k];
auto y0 = ref_vec[k];
res[res_k] = inv_delta * (y1 - y0);
res_k += vec.size();
}
}
results[i]->write(res);
}
return results;
}
} }
} }
...@@ -43,10 +43,12 @@ namespace ngraph ...@@ -43,10 +43,12 @@ namespace ngraph
const std::shared_ptr<runtime::ParameterizedTensorView<ET>> const std::shared_ptr<runtime::ParameterizedTensorView<ET>>
initialize(const std::shared_ptr<runtime::ParameterizedTensorView<ET>>& ptv) initialize(const std::shared_ptr<runtime::ParameterizedTensorView<ET>>& ptv)
{ {
for (auto& elt : ptv->get_vector()) auto vec = ptv->get_vector();
for (auto& elt : vec)
{ {
elt = m_r(); elt = m_r();
} }
ptv->write(vec);
return ptv; return ptv;
} }
......
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