Unverified Commit 5cf027bf authored by Robert Kimball's avatar Robert Kimball Committed by GitHub

Merge branch 'master' into bob/pch

parents befe170c b95135c6
......@@ -63,6 +63,7 @@ set (SRC
pass/pass.cpp
pass/topological_sort.cpp
pass/visualize_tree.cpp
runtime/aligned_buffer.cpp
runtime/backend.cpp
runtime/manager.cpp
runtime/ngvm/call_frame.cpp
......@@ -113,7 +114,6 @@ if (NGRAPH_CPU_ENABLE AND LLVM_INCLUDE_DIR AND
runtime/cpu/cpu_kernels.cpp
runtime/cpu/emitter.cpp
runtime/cpu/external_function.cpp
runtime/cpu/memory_handler.cpp
runtime/cpu/tensor_view.cpp
)
# 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 @@
#include "ngraph/common.hpp"
#include "ngraph/descriptor/buffer.hpp"
#include "ngraph/descriptor/call_frame.hpp"
#include "ngraph/descriptor/input.hpp"
#include "ngraph/descriptor/layout/dense_tensor_view_layout.hpp"
#include "ngraph/descriptor/layout/tensor_view_layout.hpp"
......
......@@ -12,32 +12,42 @@
// 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;
runtime::cpu::MemoryHandler::MemoryHandler(size_t byte_size, size_t alignment)
: m_allocated_buffer_pool(nullptr)
, m_aligned_buffer_pool(nullptr)
runtime::AlignedBuffer::AlignedBuffer()
: m_allocated_buffer(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;
m_allocated_buffer_pool = static_cast<char*>(malloc(allocation_size));
m_aligned_buffer_pool = m_allocated_buffer_pool;
size_t mod = size_t(m_aligned_buffer_pool) % alignment;
size_t allocation_size = m_byte_size + alignment;
m_allocated_buffer = static_cast<char*>(malloc(allocation_size));
m_aligned_buffer = m_allocated_buffer;
size_t mod = size_t(m_aligned_buffer) % alignment;
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
{
namespace runtime
{
namespace cpu
{
class MemoryHandler;
}
class AlignedBuffer;
}
}
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:
MemoryHandler(size_t pool_size, size_t alignment);
~MemoryHandler();
AlignedBuffer(size_t byte_size, size_t alignment);
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:
char* m_allocated_buffer_pool;
char* m_aligned_buffer_pool;
char* m_allocated_buffer;
char* m_aligned_buffer;
size_t m_byte_size;
};
......@@ -15,6 +15,7 @@
#include <memory>
#include "ngraph/runtime/backend.hpp"
#include "ngraph/runtime/parameterized_tensor_view.hpp"
#include "ngraph/runtime/tensor_view.hpp"
#include "ngraph/runtime/tuple.hpp"
#include "ngraph/types/element_type.hpp"
......@@ -24,7 +25,48 @@ using namespace ngraph::runtime;
std::shared_ptr<TensorView>
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>
......
......@@ -64,17 +64,6 @@ namespace ngraph
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.
virtual std::shared_ptr<ngraph::runtime::Tuple>
make_tuple(const std::vector<std::shared_ptr<ngraph::runtime::Value>>& elements);
......
......@@ -190,9 +190,9 @@ void ExternalFunction::compile()
#include <Eigen/Dense>
#include "ngraph/runtime/aligned_buffer.hpp"
#include "ngraph/runtime/cpu/cpu_kernels.hpp"
#include "ngraph/runtime/cpu/eigen_utils.hpp"
#include "ngraph/runtime/cpu/memory_handler.hpp"
using namespace ngraph::runtime::cpu::eigen;
......@@ -229,7 +229,7 @@ using namespace ngraph::runtime::cpu::eigen;
{
size_t temp_pool_size = pass_manager.get_state().get_temporary_pool_size();
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";
TU << "\n";
......
......@@ -14,8 +14,10 @@
#include <memory>
#include "cpu_backend.hpp"
#include "tensor_view.hpp"
#include "ngraph/descriptor/layout/dense_tensor_view_layout.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 std;
......
......@@ -58,13 +58,14 @@ namespace ngraph
template <typename ET>
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>
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:
......
......@@ -41,8 +41,7 @@ namespace ngraph
virtual void execute(CallFrame& call_frame) const override
{
call_frame.get_parameterized_tensor_view<ET>(m_out.get_index())
->get_vector() = m_value;
call_frame.get_tensor_view(m_out.get_index())->write(m_value);
}
protected:
......
......@@ -44,8 +44,8 @@ namespace ngraph
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_in)->get_vector();
call_frame.get_parameterized_tensor_view<ET>(m_out)->write(
call_frame.get_parameterized_tensor_view<ET>(m_in)->get_vector());
}
protected:
......
......@@ -51,10 +51,8 @@ namespace ngraph
std::shared_ptr<CallFrame> cf =
std::dynamic_pointer_cast<CallFrame>(ef->make_call_frame());
auto tx = ngraph::runtime::make_tensor<ET>(Shape{});
*tx = std::vector<typename ET::type>({x});
auto ty = ngraph::runtime::make_tensor<ET>(Shape{});
*ty = std::vector<typename ET::type>({y});
auto tx = ngraph::runtime::make_tensor<ET>(Shape{}, {x});
auto ty = ngraph::runtime::make_tensor<ET>(Shape{}, {y});
auto tr = ngraph::runtime::make_tensor<ET>(Shape{});
(*cf)({tx, ty}, {tr});
......
......@@ -51,10 +51,8 @@ namespace ngraph
std::shared_ptr<CallFrame> cf =
std::dynamic_pointer_cast<CallFrame>(ef->make_call_frame());
auto tx = ngraph::runtime::make_tensor<ET>(Shape{});
*tx = std::vector<typename ET::type>({x});
auto ty = ngraph::runtime::make_tensor<ET>(Shape{});
*ty = std::vector<typename ET::type>({y});
auto tx = ngraph::runtime::make_tensor<ET>(Shape{}, {x});
auto ty = ngraph::runtime::make_tensor<ET>(Shape{}, {y});
auto tr = ngraph::runtime::make_tensor<ET>(Shape{});
(*cf)({tx, ty}, {tr});
......
......@@ -51,10 +51,8 @@ namespace ngraph
std::shared_ptr<CallFrame> cf =
std::dynamic_pointer_cast<CallFrame>(ef->make_call_frame());
auto tx = ngraph::runtime::make_tensor<ET>(Shape{});
*tx = std::vector<typename ET::type>({x});
auto ty = ngraph::runtime::make_tensor<ET>(Shape{});
*ty = std::vector<typename ET::type>({y});
auto tx = ngraph::runtime::make_tensor<ET>(Shape{}, {x});
auto ty = ngraph::runtime::make_tensor<ET>(Shape{}, {y});
auto tr = ngraph::runtime::make_tensor<ET>(Shape{});
(*cf)({tx, ty}, {tr});
......
......@@ -319,13 +319,24 @@ ExternalFunction::ExternalFunction(const std::shared_ptr<ngraph::Function>& func
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) \
{ \
REGISTER_INSTRUCTION( \
op::ParameterizedConstant<T>, \
eigen::ConstantInstruction<T>, \
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]); \
}
......
......@@ -23,7 +23,6 @@
#include "ngraph/descriptor/layout/dense_tensor_view_layout.hpp"
#include "ngraph/descriptor/primary_tensor_view.hpp"
#include "ngraph/runtime/ndarray.hpp"
#include "ngraph/runtime/tensor_view.hpp"
#include "ngraph/shape.hpp"
#include "ngraph/types/element_type.hpp"
......@@ -33,7 +32,7 @@ namespace ngraph
namespace runtime
{
template <typename ET>
class ParameterizedTensorView : public TensorView
class ParameterizedTensorView : public runtime::TensorView
{
public:
/// Create a tensor
......@@ -50,37 +49,12 @@ namespace ngraph
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 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
storage_type& get_vector() { 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
{
size_t elt_offset = tensor_offset / sizeof(typename ET::type);
......@@ -102,6 +76,12 @@ namespace ngraph
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
{
size_t elt_offset = tensor_offset / sizeof(typename ET::type);
......@@ -123,11 +103,6 @@ namespace ngraph
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:
storage_type m_vector;
};
......
......@@ -15,6 +15,7 @@
#include "ngraph/runtime/tensor_view.hpp"
#include "ngraph/common.hpp"
#include "ngraph/types/element_type.hpp"
#include "ngraph/types/type.hpp"
using namespace ngraph::runtime;
......
......@@ -33,9 +33,6 @@ namespace ngraph
namespace runtime
{
template <typename ET>
class ParameterizedTensorView;
class TensorView : public Value
{
protected:
......@@ -46,11 +43,7 @@ namespace ngraph
public:
virtual ~TensorView() {}
template <typename ET>
ParameterizedTensorView<ET>* get_parameterized_tensor_view()
{
return dynamic_cast<ParameterizedTensorView<ET>*>(this);
}
TensorView& operator=(const TensorView&) = default;
std::shared_ptr<const ngraph::descriptor::TensorView>
get_tensor_view_descriptor() const;
......@@ -71,6 +64,12 @@ namespace ngraph
/// @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;
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
/// @param p Pointer to destination for data
/// @param tensor_offset Offset into tensor storage to begin reading. Must be element-aligned.
......
......@@ -34,6 +34,16 @@ namespace ngraph
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.
std::shared_ptr<ngraph::runtime::Tuple>
make_tuple(const std::vector<std::shared_ptr<ngraph::runtime::Value>>& elements);
......
......@@ -35,6 +35,7 @@ namespace ngraph
{
public:
virtual ~Value() {}
Value& operator=(const Value&) = default;
/// @brief The compile-time descriptor for this value.
virtual std::shared_ptr<ngraph::descriptor::Value> get_descriptor() const = 0;
......
......@@ -21,35 +21,42 @@
using namespace ngraph;
ngraph::element::Type::Type(size_t bitwidth,
bool is_float,
bool is_signed,
const std::string& cname)
const element::Type element::boolean(8, false, false, "bool");
const element::Type element::f32(32, true, true, "float");
const element::Type element::f64(64, true, true, "double");
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_is_float{is_float}
, m_is_real{is_real}
, m_is_signed{is_signed}
, m_cname{cname}
{
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;
}
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;
}
size_t ngraph::element::Type::size() const
size_t element::Type::size() const
{
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;
return out;
......
......@@ -26,11 +26,15 @@
#include "ngraph/common.hpp"
#include "ngraph/except.hpp"
#include "ngraph/runtime/parameterized_tensor_view.hpp"
#include "ngraph/runtime/tensor_view.hpp"
namespace ngraph
{
namespace runtime
{
template <typename ET>
class ParameterizedTensorView;
}
namespace element
{
class Type
......@@ -40,7 +44,7 @@ namespace ngraph
public:
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;
size_t size() const;
......@@ -50,9 +54,6 @@ namespace ngraph
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 { return !(*this == other); }
friend std::ostream& operator<<(std::ostream&, const Type&);
......@@ -60,11 +61,21 @@ namespace ngraph
private:
static std::map<std::string, Type> m_element_list;
size_t m_bitwidth;
bool m_is_float;
bool m_is_real;
bool m_is_signed;
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);
// Provides a compile-time name for a C++ type.
......@@ -111,12 +122,6 @@ namespace ngraph
static TraitedType<T> 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)
......
......@@ -37,10 +37,7 @@ set (SRC
tensor.cpp
topological_sort.cpp
type_prop.cpp
util/all_close.cpp
util/autodiff/backprop_derivative.cpp
util/autodiff/backprop_function.cpp
util/autodiff/numeric_derivative.cpp
util/test_tools.cpp
util.cpp
uuid.cpp
......
......@@ -1068,8 +1068,7 @@ TEST(${BACKEND_NAME}, subtract)
TEST(${BACKEND_NAME}, scalar_constant)
{
auto shape = Shape{};
auto t = runtime::make_tensor<element::Float32>(shape);
(*t) = std::vector<float>{-3.0f};
auto t = runtime::make_tensor<element::Float32>(shape, {-3.0f});
auto A = make_shared<op::ParameterizedConstant<element::Float32>>(shape, t);
auto rt = make_shared<TensorViewType>(element::Float32::element_type(), shape);
auto f = make_shared<Function>(A, rt, op::Parameters{});
......@@ -1089,8 +1088,7 @@ TEST(${BACKEND_NAME}, scalar_constant)
TEST(${BACKEND_NAME}, tensor_constant)
{
auto shape = Shape{2, 2, 2};
auto t = runtime::make_tensor<element::Float32>(shape);
(*t) = std::vector<float>{1, 2, 3, 4, 5, 6, 7, 8};
auto t = runtime::make_tensor<element::Float32>(shape, {1, 2, 3, 4, 5, 6, 7, 8});
auto A = make_shared<op::ParameterizedConstant<element::Float32>>(shape, t);
auto rt = make_shared<TensorViewType>(element::Float32::element_type(), shape);
auto f = make_shared<Function>(A, rt, op::Parameters{});
......@@ -1110,8 +1108,7 @@ TEST(${BACKEND_NAME}, tensor_constant)
TEST(${BACKEND_NAME}, tensor_constant_with_op)
{
auto shape = Shape{2, 2, 2};
auto t = runtime::make_tensor<element::Float32>(shape);
(*t) = std::vector<float>{-1, 2, 3, -4, 5, -6, -7, 8};
auto t = runtime::make_tensor<element::Float32>(shape, {-1, 2, 3, -4, 5, -6, -7, 8});
auto A = make_shared<op::ParameterizedConstant<element::Float32>>(shape, t);
auto rt = make_shared<TensorViewType>(element::Float32::element_type(), shape);
auto f = make_shared<Function>(make_shared<op::Abs>(A), rt, op::Parameters{});
......
......@@ -81,8 +81,7 @@ TEST(build_graph, literal)
{
// float scalar from a float
//auto float0 = FloatConstant::make(3.0);
auto float_t = ngraph::runtime::make_tensor<element::Float32>(Shape{});
(*float_t) = std::vector<float>{3.0};
auto float_t = ngraph::runtime::make_tensor<element::Float32>(Shape{}, {3.0});
auto float0 = make_shared<op::Float32Constant>(Shape{}, float_t);
auto float_scalar_type = make_shared<TensorViewType>(element::Float32::element_type(), Shape{});
ASSERT_EQ(float0->get_value()->get_vector(), std::vector<float>{3.0});
......@@ -91,8 +90,7 @@ TEST(build_graph, literal)
ASSERT_EQ(d->get_arguments().at(0), float0);
ASSERT_EQ(d->get_arguments().at(1), float0);
auto int32_t = ngraph::runtime::make_tensor<element::Int32>(Shape{});
(*int32_t) = std::vector<int>{3};
auto int32_t = ngraph::runtime::make_tensor<element::Int32>(Shape{}, {3});
auto int32_0 = make_shared<op::Int32Constant>(Shape{}, int32_t);
auto int32_scalar_type = make_shared<TensorViewType>(element::Int32::element_type(), Shape{});
ASSERT_EQ(int32_0->get_value()->get_vector(), std::vector<int>{3});
......
......@@ -22,6 +22,13 @@
using namespace std;
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>
bool check_unary()
{
......@@ -128,11 +135,12 @@ TEST(copy, parameterized_constant)
auto backend = manager->allocate_backend();
// Create some tensors for input/output
auto c = backend->make_parameterized_tensor_view<element::Float32>(
runtime::NDArray<float, 2>({{1, 2}, {3, 4}}));
auto c = backend->make_primary_tensor_view(element::Float32::element_type(), Shape{2, 2});
copy_data(c, runtime::NDArray<float, 2>({{1, 2}, {3, 4}}).get_vector());
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 node_cast = dynamic_pointer_cast<op::ParameterizedConstant<element::Float32>>(new_node);
ASSERT_TRUE(nullptr != new_node);
......
......@@ -89,7 +89,6 @@ void test_read_write(const std::vector<typename ET::type>& x)
auto backend = manager->allocate_backend();
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());
......@@ -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));
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);
std::vector<T> result1(x.size());
......
......@@ -25,6 +25,13 @@
using namespace std;
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)
{
{
......@@ -178,15 +185,17 @@ TEST(util, all_close)
auto backend = manager->allocate_backend();
// Create some tensors for input/output
auto a = backend->make_parameterized_tensor_view<element::Float32>(
runtime::NDArray<float, 2>({{1, 2, 3}, {3, 4, 5}}));
auto b = backend->make_parameterized_tensor_view<element::Float32>(
runtime::NDArray<float, 2>({{1, 2, 3}, {3, 4, 5}}));
auto a = backend->make_parameterized_tensor_view<element::Float32>(Shape{2, 3});
auto b = backend->make_parameterized_tensor_view<element::Float32>(Shape{2, 3});
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));
auto c = backend->make_parameterized_tensor_view<element::Float32>(
runtime::NDArray<float, 2>({{1.1f, 2, 3}, {3, 4, 5}}));
auto c = backend->make_parameterized_tensor_view<element::Float32>(Shape{2, 3});
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_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
namespace test
{
/// @brief Same as numpy.allclose
/// @param as First tensors to compare
/// @param bs Second tensors to compare
/// @param a First tensor to compare
/// @param b Second tensor to compare
/// @param rtol Relative tolerance
/// @param atol Absolute tolerance
/// Returns true if shapes match and for all elements, |a_i-b_i| <= atol + rtol*|b_i|.
template <typename ET>
bool 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);
extern template bool all_close<element::Float32>(
const std::vector<std::shared_ptr<runtime::ParameterizedTensorView<element::Float32>>>&
as,
const std::vector<std::shared_ptr<runtime::ParameterizedTensorView<element::Float32>>>&
bs,
element::Float32::type rtol,
element::Float32::type atol);
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);
/// @returns true if shapes match and for all elements, |a_i-b_i| <= atol + rtol*|b_i|.
template <typename T>
bool all_close(const std::vector<T>& a,
const std::vector<T>& b,
T rtol = 1e-5f,
T atol = 1e-8f)
{
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;
}
/// @brief Same as numpy.allclose
/// @param a First tensor to compare
......@@ -63,44 +57,45 @@ namespace ngraph
bool all_close(const std::shared_ptr<ngraph::runtime::ParameterizedTensorView<ET>>& a,
const std::shared_ptr<ngraph::runtime::ParameterizedTensorView<ET>>& b,
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>(
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);
if (a->get_shape() != b->get_shape())
return false;
extern template bool 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);
return all_close(a->get_vector(), b->get_vector(), rtol, atol);
}
/// @brief Same as numpy.allclose
/// @param a First tensor to compare
/// @param b Second tensor to compare
/// @param as First tensors to compare
/// @param bs Second tensors to compare
/// @param rtol Relative tolerance
/// @param atol Absolute tolerance
/// @returns true if shapes match and for all elements, |a_i-b_i| <= atol + rtol*|b_i|.
template <typename T>
bool all_close(const std::vector<T>& a,
const std::vector<T>& b,
T rtol = 1e-5f,
T atol = 1e-8f);
extern template bool all_close<float>(const std::vector<float>& a,
const std::vector<float>& b,
float rtol,
float atol);
extern template bool all_close<double>(const std::vector<double>& a,
const std::vector<double>& b,
double rtol,
double atol);
/// Returns true if shapes match and for all elements, |a_i-b_i| <= atol + rtol*|b_i|.
template <typename ET>
bool 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;
}
}
}
// ----------------------------------------------------------------------------
// 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 @@
#include <memory>
#include "ngraph/log.hpp"
#include "ngraph/runtime/parameterized_tensor_view.hpp"
#include "ngraph/types/element_type.hpp"
#include "ngraph/util.hpp"
namespace ngraph
{
......@@ -42,24 +44,76 @@ namespace ngraph
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);
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;
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
/// @param f is f(X_i...)
/// @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);
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
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);
typename ET::type delta)
{
auto y = f->get_result();
extern template std::vector<
std::shared_ptr<runtime::ParameterizedTensorView<element::Float32>>>
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);
Shape y_shape =
std::dynamic_pointer_cast<const TensorViewType>(y->get_value_type())->get_shape();
extern template std::vector<
std::shared_ptr<runtime::ParameterizedTensorView<element::Float64>>>
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);
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;
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
const std::shared_ptr<runtime::ParameterizedTensorView<ET>>
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();
}
ptv->write(vec);
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