[GPU] Serialization of loop primitive (#14703)

This commit is contained in:
Eddy Kim authored and GitHub committed 2022-12-26 13:28:55 +04:00
1 parent dea5c1b06e
commit 0ce82204bb
9 files changed
+380 -104

No files matched your search

@@ -0,0 +1,58 @@
// Copyright (C) 2018-2022 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma once
#include <vector>
#include <type_traits>
#include "buffer.hpp"
#include "helpers.hpp"
#include "intel_gpu/primitives/loop.hpp"
namespace cldnn {
template <typename BufferType>
class Serializer<BufferType, cldnn::loop::io_primitive_map, typename std::enable_if<std::is_base_of<OutputBuffer<BufferType>, BufferType>::value>::type> {
public:
static void save(BufferType& buffer, const cldnn::loop::io_primitive_map& io_primitive_map) {
buffer << io_primitive_map.external_id;
buffer << io_primitive_map.internal_id;
buffer << io_primitive_map.axis;
buffer << io_primitive_map.start;
buffer << io_primitive_map.end;
buffer << io_primitive_map.stride;
}
};
template <typename BufferType>
class Serializer<BufferType, cldnn::loop::io_primitive_map, typename std::enable_if<std::is_base_of<InputBuffer<BufferType>, BufferType>::value>::type> {
public:
static void load(BufferType& buffer, cldnn::loop::io_primitive_map& io_primitive_map) {
buffer >> io_primitive_map.external_id;
buffer >> io_primitive_map.internal_id;
buffer >> io_primitive_map.axis;
buffer >> io_primitive_map.start;
buffer >> io_primitive_map.end;
buffer >> io_primitive_map.stride;
}
};
template <typename BufferType>
class Serializer<BufferType, cldnn::loop::backedge_mapping, typename std::enable_if<std::is_base_of<OutputBuffer<BufferType>, BufferType>::value>::type> {
public:
static void save(BufferType& buffer, const cldnn::loop::backedge_mapping& backedge_mapping) {
buffer << backedge_mapping.from;
buffer << backedge_mapping.to;
}
};
template <typename BufferType>
class Serializer<BufferType, cldnn::loop::backedge_mapping, typename std::enable_if<std::is_base_of<InputBuffer<BufferType>, BufferType>::value>::type> {
public:
static void load(BufferType& buffer, cldnn::loop::backedge_mapping& backedge_mapping) {
buffer >> backedge_mapping.from;
buffer >> backedge_mapping.to;
}
};
} // namespace cldnn
@@ -76,6 +76,7 @@ struct loop : public primitive_base<loop> {
end(end),
stride(stride)
{}
io_primitive_map() {}
primitive_id external_id;
primitive_id internal_id;
int64_t axis;
@@ -91,6 +92,7 @@ struct loop : public primitive_base<loop> {
/// @param to Input data primitive id of body topology
backedge_mapping(primitive_id from, primitive_id to)
: from(from), to(to) {}
backedge_mapping() {}
primitive_id from;
primitive_id to;
};
@@ -8,12 +8,16 @@
#include "register.hpp"
#include "mutable_data_inst.h"
#include "input_layout_inst.h"
#include "intel_gpu/graph/serialization/loop_serializer.hpp"
#include <vector>
#include <algorithm>
namespace cldnn {
namespace common {
struct loop_impl : typed_primitive_impl<loop> {
using parent = typed_primitive_impl<loop>;
using parent::parent;
DECLARE_OBJECT_TYPE_SERIALIZATION
std::unique_ptr<primitive_impl> clone() const override {
@@ -22,6 +26,8 @@ struct loop_impl : typed_primitive_impl<loop> {
void init_kernels(const kernels_cache&) override {}
loop_impl() : parent() {}
loop_impl(const loop_impl& other) : typed_primitive_impl<loop>(other),
_node_id(other._node_id),
_current_iteration_id(other._current_iteration_id),
@@ -191,6 +197,34 @@ struct loop_impl : typed_primitive_impl<loop> {
return make_unique<loop_impl>(arg);
}
void save(BinaryOutputBuffer& ob) const override {
parent::save(ob);
ob << _node_id;
ob << _current_iteration_id;
ob << _trip_count_id;
ob << _initial_execution_id;
ob << _condition_id;
ob << _num_iteration_id;
ob << _max_iteration;
ob << _is_current_iteration_used;
ob << _is_execution_condition_used;
ob << _back_edges;
}
void load(BinaryInputBuffer& ib) override {
parent::load(ib);
ib >> _node_id;
ib >> _current_iteration_id;
ib >> _trip_count_id;
ib >> _initial_execution_id;
ib >> _condition_id;
ib >> _num_iteration_id;
ib >> _max_iteration;
ib >> _is_current_iteration_used;
ib >> _is_execution_condition_used;
ib >> _back_edges;
}
private:
primitive_id _node_id;
primitive_id _current_iteration_id;
@@ -201,7 +235,7 @@ private:
int64_t _max_iteration;
bool _is_current_iteration_used = false;
bool _is_execution_condition_used = false;
std::vector<cldnn::loop::backedge_mapping> _back_edges{};
std::vector<cldnn::loop::backedge_mapping> _back_edges;
};
namespace detail {
@@ -213,4 +247,4 @@ attach_loop_common::attach_loop_common() {
} // namespace common
} // namespace cldnn
ASSIGN_TYPE_NAME(cldnn::common::loop_impl)
BIND_BINARY_BUFFER_WITH_TYPE(cldnn::common::loop_impl)
@@ -52,36 +52,6 @@ public:
bool is_current_iteration_used() const { return use_current_iteration; }
bool is_execution_condition_used() const { return use_execution_condition; }
std::vector<const loop::io_primitive_map*> find_io_primitive_maps(
const primitive_id& prim_id,
bool is_external) const {
std::vector<const loop::io_primitive_map*> ret;
if (is_external) {
for (const auto& it : input_primitive_maps) {
if (it.external_id == prim_id) {
ret.push_back(&it);
}
}
for (const auto& it : output_primitive_maps) {
if (it.external_id == prim_id) {
ret.push_back(&it);
}
}
} else {
for (const auto& it : input_primitive_maps) {
if (it.internal_id == prim_id) {
ret.push_back(&it);
}
}
for (const auto& it : output_primitive_maps) {
if (it.internal_id == prim_id) {
ret.push_back(&it);
}
}
}
return ret;
}
static size_t convert_to_raw_axis(size_t axis, size_t ndim) {
// convert between bfyx, bfzyx, bfzyxw and tensor.size.raw
if (axis >= ndim) {
@@ -572,11 +542,22 @@ public:
}
return backedge_memory_mappings.at(current_iteratoin_backedge_mapping_idx);
}
void save(BinaryOutputBuffer& ob) const override;
void load(BinaryInputBuffer& ib) override;
private:
network::ptr body_network;
memory::ptr get_external_memory(const primitive_id& external_id) const;
std::vector<memory::ptr> get_sliced_mem(const primitive_id& internal_id) const;
std::vector<loop::io_primitive_map> _input_primitive_maps;
std::vector<loop::io_primitive_map> _output_primitive_maps;
std::vector<loop::backedge_mapping> _back_edges;
primitive_id _trip_count_id;
primitive_id _initial_execution_id;
primitive_id _current_iteration_id;
primitive_id _condition_id;
primitive_id _num_iteration_id;
int64_t _max_iteration;
};
using loop_inst = typed_primitive_inst<loop>;
@@ -45,6 +45,8 @@ public:
typed_primitive_inst(network& network, mutable_data_node const& node);
void set_output_memory(memory::ptr mem, bool check = true, size_t idx = 0) override;
const std::list<primitive_id>& get_user_ids() const { return _user_ids; }
void save(BinaryOutputBuffer& ob) const override;
void load(BinaryInputBuffer& ib) override;
private:
std::list<primitive_id> _user_ids;
+102 -29
View File
@@ -9,6 +9,7 @@
#include "primitive_type_base.h"
#include "intel_gpu/primitives/data.hpp"
#include "intel_gpu/primitives/mutable_data.hpp"
#include "intel_gpu/graph/serialization/loop_serializer.hpp"
#include <string>
#include <exception>
#include <algorithm>
@@ -134,6 +135,38 @@ std::string loop_inst::to_string(const loop_node & node) {
return primitive_description.str();
}
static std::vector<const loop::io_primitive_map*> find_io_primitive_maps(
const std::vector<loop::io_primitive_map>& input_primitive_maps,
const std::vector<loop::io_primitive_map>& output_primitive_maps,
const primitive_id& prim_id,
bool is_external) {
std::vector<const loop::io_primitive_map*> ret;
if (is_external) {
for (const auto& it : input_primitive_maps) {
if (it.external_id == prim_id) {
ret.push_back(&it);
}
}
for (const auto& it : output_primitive_maps) {
if (it.external_id == prim_id) {
ret.push_back(&it);
}
}
} else {
for (const auto& it : input_primitive_maps) {
if (it.internal_id == prim_id) {
ret.push_back(&it);
}
}
for (const auto& it : output_primitive_maps) {
if (it.internal_id == prim_id) {
ret.push_back(&it);
}
}
}
return ret;
}
static void validate_mappings(loop_node const & node) {
const auto outer_inputs = node.get_dependencies_ids();
const auto& input_primitive_maps = node.get_input_primitive_maps();
@@ -146,7 +179,8 @@ static void validate_mappings(loop_node const & node) {
id == node.get_num_iteration_id()) {
continue;
}
const auto results = node.find_io_primitive_maps(id, true);
const auto results = find_io_primitive_maps(node.get_input_primitive_maps(),
node.get_output_primitive_maps(), id, true);
if (results.size() == 0) {
std::string msg = "outer input '" + id + "' does not have primitive map";
CLDNN_ERROR_MESSAGE(node.id(), msg.c_str());
@@ -190,9 +224,8 @@ void loop_inst::update_mapped_memory() {
return;
}
// update output memory
const auto& output_primitive_maps = node->get_output_primitive_maps();
for (size_t i = 0; i < output_primitive_maps.size(); ++i) {
const auto& output_mapping = output_primitive_maps.at(i);
for (size_t i = 0; i < _output_primitive_maps.size(); ++i) {
const auto& output_mapping = _output_primitive_maps.at(i);
const primitive_id& external_id = output_mapping.external_id;
const primitive_id& internal_id = output_mapping.internal_id;
memory::ptr to_mem = get_external_memory(external_id);
@@ -210,10 +243,11 @@ void loop_inst::update_mapped_memory() {
// update input memory
for (size_t memory_num = 0; memory_num < inputs_memory_count(); memory_num++) {
const primitive_id& input_external_id = dependencies().at(memory_num).first->id();
auto input_map_ptrs = node->find_io_primitive_maps(input_external_id, true);
auto input_map_ptrs = find_io_primitive_maps(_input_primitive_maps,
_output_primitive_maps, input_external_id, true);
if (input_map_ptrs.empty()) {
if (input_external_id == node->get_trip_count_id() ||
input_external_id == node->get_initial_execution_id()) {
if (input_external_id == _trip_count_id ||
input_external_id == _initial_execution_id) {
continue;
}
}
@@ -235,11 +269,11 @@ void loop_inst::update_mapped_memory() {
}
}
//update backedges memory
const auto& back_edges = node->get_back_edges();
// checking if memory is a destination of a backedge
for (const auto& back_edge : back_edges) {
for (const auto& back_edge : _back_edges) {
//find corresponding input of the backedge
const auto input_map_ptrs = node->find_io_primitive_maps(back_edge.to, false);
const auto input_map_ptrs = find_io_primitive_maps(_input_primitive_maps,
_output_primitive_maps, back_edge.to, false);
assert(input_map_ptrs.size() == 1);
const auto& input_map = input_map_ptrs.front();
auto backedged_sliced_output_mems = get_sliced_mem(back_edge.from);
@@ -252,8 +286,8 @@ void loop_inst::update_mapped_memory() {
backedge_mapping.to_primitive->id() == backedge_to_prim->id()) {
if (backedged_sliced_output_mems.empty()) {
// backedge output which does not need concatenation
// input memory = output memory = loop output memory
const auto output_mapping = node->find_io_primitive_maps(back_edge.from, false);
const auto output_mapping = find_io_primitive_maps(_input_primitive_maps,
_output_primitive_maps, back_edge.from, false);
memory::ptr backedge_mem;
if (output_mapping.empty()) {
// from and to primitives in backedge are connected directly
@@ -290,10 +324,9 @@ void loop_inst::set_output_memory(memory::ptr mem, bool check, size_t idx) {
void loop_inst::preprocess_output_memory() {
auto& engine = _network.get_engine();
const auto& output_primitive_maps = node->get_output_primitive_maps();
concatenated_output_mem_mappings.reserve(output_primitive_maps.size());
for (size_t i = 0; i < output_primitive_maps.size(); ++i) {
const auto& output_mapping = output_primitive_maps.at(i);
concatenated_output_mem_mappings.reserve(_output_primitive_maps.size());
for (size_t i = 0; i < _output_primitive_maps.size(); ++i) {
const auto& output_mapping = _output_primitive_maps.at(i);
const primitive_id& external_id = output_mapping.external_id;
const primitive_id& internal_id = output_mapping.internal_id;
if (output_mapping.axis < 0) {
@@ -304,7 +337,7 @@ void loop_inst::preprocess_output_memory() {
auto output_prim = body_network->get_primitive(internal_id);
layout sliced_layout = output_prim->output_memory().get_layout();
const int64_t max_iteration = node->get_max_iteration();
const int64_t max_iteration = _max_iteration;
std::vector<memory::ptr> sliced_mems;
sliced_mems.reserve(max_iteration);
for (int j=0; j < max_iteration; ++j) {
@@ -315,7 +348,7 @@ void loop_inst::preprocess_output_memory() {
const int64_t num_elements_batch = concatenated_memory_mapping::get_batch_size(
sliced_layout, output_mapping.axis);
const int64_t num_elements_iteration = sliced_layout.count() / num_elements_batch;
const int64_t start = output_mapping.start < 0? node->get_max_iteration() - 1: output_mapping.start;
const int64_t start = output_mapping.start < 0? _max_iteration - 1: output_mapping.start;
concatenated_memory_mapping memory_mapping_info(
output_mapping.axis, to_mem, sliced_mems, _network.get_stream(),
num_elements_iteration, output_mapping.stride, start);
@@ -330,10 +363,11 @@ void loop_inst::preprocess_input_memory() {
auto& iteration_mem = concatenated_input_mem_mappings;
for (size_t memory_num = 0; memory_num < inputs_memory_count(); memory_num++) {
const primitive_id& input_external_id = dependencies().at(memory_num).first->id();
auto input_map_ptrs = node->find_io_primitive_maps(input_external_id, true);
auto input_map_ptrs = find_io_primitive_maps(_input_primitive_maps,
_output_primitive_maps, input_external_id, true);
if (input_map_ptrs.size() == 0) {
if (input_external_id == node->get_trip_count_id() ||
input_external_id == node->get_initial_execution_id()) {
if (input_external_id == _trip_count_id ||
input_external_id == _initial_execution_id) {
continue;
}
CLDNN_ERROR_MESSAGE(id(), "loop primitive_map is incomplete");
@@ -346,7 +380,7 @@ void loop_inst::preprocess_input_memory() {
if (is_concatenated_input) {
layout sliced_layout
= body_network->get_primitive(input_map->internal_id)->output_memory().get_layout();
const int64_t max_iteration = node->get_max_iteration();
const int64_t max_iteration = _max_iteration;
std::vector<memory::ptr> sliced_mems;
sliced_mems.reserve(max_iteration);
for (int j=0; j < max_iteration; ++j) {
@@ -356,7 +390,7 @@ void loop_inst::preprocess_input_memory() {
const int64_t num_elements_batch = concatenated_memory_mapping::get_batch_size(
sliced_layout, input_map->axis);
const int64_t num_elements_iteration = sliced_layout.count() / num_elements_batch;
const int64_t start = input_map->start < 0? node->get_max_iteration() - 1: input_map->start;
const int64_t start = input_map->start < 0? _max_iteration - 1: input_map->start;
concatenated_memory_mapping concatenated_input_mem_mapping_info(
input_map->axis, memory, sliced_mems, _network.get_stream(),
num_elements_iteration, input_map->stride, start);
@@ -373,16 +407,16 @@ void loop_inst::preprocess_input_memory() {
}
void loop_inst::preprocess_backedge_memory() {
const auto& back_edges = node->get_back_edges();
// checking if memory is a destination of a backedge
for (const auto& back_edge : back_edges) {
for (const auto& back_edge : _back_edges) {
//find corresponding input of the backedge
const auto input_map_ptrs = node->find_io_primitive_maps(back_edge.to, false);
const auto input_map_ptrs = find_io_primitive_maps(_input_primitive_maps,
_output_primitive_maps, back_edge.to, false);
const auto backedge_to_prim = body_network->get_primitive(back_edge.to);
const auto backedge_from_prim = body_network->get_primitive(back_edge.from);
memory::ptr initial_mem;
if (back_edge.to == node->get_current_iteration_id()) {
if (back_edge.to == _current_iteration_id) {
const layout current_iteration_layout = backedge_to_prim->output_memory().get_layout();
initial_mem = get_network().get_engine().allocate_memory(current_iteration_layout);
auto& stream = get_network().get_stream();
@@ -398,8 +432,8 @@ void loop_inst::preprocess_backedge_memory() {
auto backedged_sliced_output_mems = get_sliced_mem(back_edge.from);
if (backedged_sliced_output_mems.empty()) {
// backedge output which does not need concatenation
// input memory = output memory = loop output memory
const auto output_mapping = node->find_io_primitive_maps(back_edge.from, false);
const auto output_mapping = find_io_primitive_maps(_input_primitive_maps,
_output_primitive_maps, back_edge.from, false);
memory::ptr backedge_mem;
if (output_mapping.empty()) {
// from and to primitives in backedge are connected directly
@@ -458,6 +492,45 @@ loop_inst::typed_primitive_inst(network & network, loop_node const & node)
validate_backedges(node);
validate_mappings(node);
_input_primitive_maps = node.get_input_primitive_maps();
_output_primitive_maps = node.get_output_primitive_maps();
_back_edges = node.get_back_edges();
_trip_count_id = node.get_trip_count_id();
_initial_execution_id = node.get_initial_execution_id();
_current_iteration_id = node.get_current_iteration_id();
_condition_id = node.get_condition_id();
_num_iteration_id = node.get_num_iteration_id();
_max_iteration = node.get_max_iteration();
}
void loop_inst::save(BinaryOutputBuffer& ob) const {
parent::save(ob);
ob << _input_primitive_maps;
ob << _output_primitive_maps;
ob << _back_edges;
ob << _trip_count_id;
ob << _initial_execution_id;
ob << _current_iteration_id;
ob << _condition_id;
ob << _num_iteration_id;
ob << _max_iteration;
body_network->save(ob);
}
void loop_inst::load(BinaryInputBuffer& ib) {
parent::load(ib);
preproc_memories_done = false,
ib >> _input_primitive_maps;
ib >> _output_primitive_maps;
ib >> _back_edges;
ib >> _trip_count_id;
ib >> _initial_execution_id;
ib >> _current_iteration_id;
ib >> _condition_id;
ib >> _num_iteration_id;
ib >> _max_iteration;
body_network = std::make_shared<cldnn::network>(ib, get_network().get_stream_ptr(), get_network().get_engine());
}
} // namespace cldnn
@@ -81,4 +81,46 @@ mutable_data_inst::typed_primitive_inst(network& network, mutable_data_node cons
}
}
void mutable_data_inst::save(cldnn::BinaryOutputBuffer& ob) const {
parent::save(ob);
size_t data_size = _outputs[0]->size();
ob << make_data(&data_size, sizeof(size_t));
if (data_size == 0)
return;
allocation_type _allocation_type = _outputs[0]->get_allocation_type();
if (_allocation_type == allocation_type::usm_host || _allocation_type == allocation_type::usm_shared) {
ob << make_data(_outputs[0]->buffer_ptr(), data_size);
} else {
mem_lock<char, mem_lock_type::read> lock{_outputs[0], get_node().get_program().get_stream()};
ob << make_data(lock.data(), data_size);
}
}
void mutable_data_inst::load(BinaryInputBuffer& ib) {
parent::load(ib);
size_t data_size;
ib >> make_data(&data_size, sizeof(size_t));
if (data_size == 0)
return;
OPENVINO_ASSERT(_outputs[0] != nullptr, "Output memory should be allocated before importing data.");
allocation_type _allocation_type = _outputs[0]->get_allocation_type();
if (_allocation_type == allocation_type::usm_host || _allocation_type == allocation_type::usm_shared) {
ib >> make_data(_outputs[0]->buffer_ptr(), data_size);
} else {
std::vector<uint8_t> _buf;
_buf.resize(data_size);
ib >> make_data(_buf.data(), data_size);
_outputs[0]->copy_from(get_network().get_stream(), _buf.data());
}
}
} // namespace cldnn
@@ -495,6 +495,9 @@ void primitive_inst::set_arguments() {
}
void primitive_inst::build_deps() {
if (!_deps.empty())
return;
OPENVINO_ASSERT(_node != nullptr, "_node should not be nullptr for build_deps.");
if (_deps.empty() && !_node->get_dependencies().empty()) {
@@ -25,7 +25,8 @@ using namespace cldnn;
using namespace tests;
using namespace testing;
TEST(loop_gpu, basic_no_concat)
template <typename T>
void test_loop_gpu_basic_no_concat(bool is_caching_test)
{
auto& engine = get_test_engine();
@@ -35,11 +36,11 @@ TEST(loop_gpu, basic_no_concat)
auto initial_condition_mem = engine.allocate_memory({ data_types::i32, format::bfyx, { 1, 1, 1, 1 } });
auto num_iteration_mem = engine.allocate_memory({ data_types::i32, format::bfyx, { 1, 1, 1, 1 } });
std::vector<float> input_data{
std::vector<T> input_data{
1.0f, 2.0f, -15.f, 3.0f, 4.0f, -15.f, 5.0f, 6.0f, -15.f, 7.0f,
-15.f, 0.0f, 0.0f, -15.f, 0.5f, -0.5f, -15.f, 8.0f, 1.5f, 5.2f
};
std::vector<float> eltwise_operand {
std::vector<T> eltwise_operand {
1.f, -2.f, 3.f, -4.f, 3.0f, -2.0f, 1.f, -2.f, 3.0f, -4.0f,
3.f, -2.f, 1.f, -2.f, 3.5f, -4.5f, 5.f, -4.f, 3.5f, -2.2f
};
@@ -74,12 +75,30 @@ TEST(loop_gpu, basic_no_concat)
input_primitive_maps, output_primitive_maps, back_edges, 8)
);
network network(engine, topology);
network.set_input_data("input", input_mem);
network.set_input_data("trip_count", trip_count_mem);
network.set_input_data("initial_condition", initial_condition_mem);
cldnn::network::ptr network;
auto outputs = network.execute();
if (is_caching_test) {
membuf mem_buf;
{
cldnn::network _network(engine, topology);
std::ostream out_mem(&mem_buf);
BinaryOutputBuffer ob = BinaryOutputBuffer(out_mem);
_network.save(ob);
}
{
std::istream in_mem(&mem_buf);
BinaryInputBuffer ib = BinaryInputBuffer(in_mem, engine);
network = std::make_shared<cldnn::network>(ib, get_test_stream_ptr(), engine);
}
} else {
network = std::make_shared<cldnn::network>(engine, topology);
}
network->set_input_data("input", input_mem);
network->set_input_data("trip_count", trip_count_mem);
network->set_input_data("initial_condition", initial_condition_mem);
auto outputs = network->execute();
ASSERT_EQ(outputs.size(), 1);
auto output = outputs.begin()->second.get_memory();
auto output_layout = output->get_layout();
@@ -91,7 +110,7 @@ TEST(loop_gpu, basic_no_concat)
// value check
{
mem_lock<float> output_ptr{ output, get_test_stream() };
mem_lock<T> output_ptr{ output, get_test_stream() };
ASSERT_EQ(output_ptr.size(), input_data.size());
for (size_t i = 0, iend = input_data.size(); i < iend; ++i) {
ASSERT_FLOAT_EQ(output_ptr[i], input_data[i] + eltwise_operand[i] * trip_count);
@@ -99,22 +118,22 @@ TEST(loop_gpu, basic_no_concat)
}
// allocate new output memory
layout loop_l = network.get_output_memory("loop")->get_layout();
layout loop_l = network->get_output_memory("loop")->get_layout();
auto output_mem = engine.allocate_memory(loop_l);
network.set_output_memory("loop", output_mem);
network->set_output_memory("loop", output_mem);
//one more execute
set_values(input_mem, input_data);
set_values(operand_mem, eltwise_operand);
set_values(trip_count_mem, { trip_count });
set_values(initial_condition_mem, { initial_condition });
outputs = network.execute();
outputs = network->execute();
// check everything once again
ASSERT_EQ(outputs.size(), 1);
auto output2 = outputs.begin()->second.get_memory();
{
mem_lock<float> output_ptr2{ output2, get_test_stream() };
mem_lock<T> output_ptr2{ output2, get_test_stream() };
ASSERT_EQ(output_ptr2.size(), input_data.size());
for (size_t i = 0, iend = input_data.size(); i < iend; ++i) {
ASSERT_FLOAT_EQ(output_ptr2[i], input_data[i] + eltwise_operand[i] * trip_count);
@@ -122,7 +141,16 @@ TEST(loop_gpu, basic_no_concat)
}
}
TEST(loop_gpu, basic_concat)
TEST(loop_gpu, basic_no_concat) {
test_loop_gpu_basic_no_concat<float>(false);
}
TEST(export_import_loop_gpu, basic_no_concat) {
test_loop_gpu_basic_no_concat<float>(true);
}
template <typename T>
void test_loop_gpu_basic_concat(bool is_caching_test)
{
auto& engine = get_test_engine();
@@ -132,11 +160,11 @@ TEST(loop_gpu, basic_concat)
auto initial_condition_mem = engine.allocate_memory({ data_types::i64, format::bfyx, { 1, 1, 1, 1 } });
auto num_iteration_mem = engine.allocate_memory({ data_types::i64, format::bfyx, { 1, 1, 1, 1 } });
std::vector<float> input_data{
std::vector<T> input_data{
1.0f, 2.0f, -15.f, 3.0f, 4.0f, -15.f, 5.0f, 6.0f, -15.f, 7.0f,
-15.f, 0.0f, 0.0f, -15.f, 0.5f, -0.5f, -15.f, 8.0f, 1.5f, 5.2f
};
std::vector<float> eltwise_operand {
std::vector<T> eltwise_operand {
1.f, -2.f, 3.f, -4.f
};
size_t trip_count = input_data.size()/eltwise_operand.size();
@@ -169,12 +197,30 @@ TEST(loop_gpu, basic_concat)
input_primitive_maps, output_primitive_maps, back_edges, trip_count)
);
network network(engine, topology);
network.set_input_data("input", input_mem);
network.set_input_data("trip_count", trip_count_mem);
network.set_input_data("initial_condition", initial_condition_mem);
cldnn::network::ptr network;
auto outputs = network.execute();
if (is_caching_test) {
membuf mem_buf;
{
cldnn::network _network(engine, topology);
std::ostream out_mem(&mem_buf);
BinaryOutputBuffer ob = BinaryOutputBuffer(out_mem);
_network.save(ob);
}
{
std::istream in_mem(&mem_buf);
BinaryInputBuffer ib = BinaryInputBuffer(in_mem, engine);
network = std::make_shared<cldnn::network>(ib, get_test_stream_ptr(), engine);
}
} else {
network = std::make_shared<cldnn::network>(engine, topology);
}
network->set_input_data("input", input_mem);
network->set_input_data("trip_count", trip_count_mem);
network->set_input_data("initial_condition", initial_condition_mem);
auto outputs = network->execute();
ASSERT_EQ(outputs.size(), 1);
auto output = outputs.begin()->second.get_memory();
auto output_layout = output->get_layout();
@@ -186,7 +232,7 @@ TEST(loop_gpu, basic_concat)
// value check
{
mem_lock<float> output_ptr{ output, get_test_stream() };
mem_lock<T> output_ptr{ output, get_test_stream() };
for (size_t i = 0, iend = input_data.size(); i < iend; ++i) {
const size_t j = i % eltwise_operand.size();
float expected = input_data[i] + eltwise_operand[j];
@@ -195,18 +241,18 @@ TEST(loop_gpu, basic_concat)
}
// allocate new output memory
layout loop_l = network.get_output_memory("loop")->get_layout();
layout loop_l = network->get_output_memory("loop")->get_layout();
auto output_mem = engine.allocate_memory(loop_l);
network.set_output_memory("loop", output_mem);
network->set_output_memory("loop", output_mem);
set_values(input_mem, input_data);
set_values(operand_mem, eltwise_operand);
set_values(trip_count_mem, { trip_count });
set_values(initial_condition_mem, { initial_condition });
outputs = network.execute();
outputs = network->execute();
auto output2 = outputs.begin()->second.get_memory();
{
mem_lock<float> output_ptr2{ output2, get_test_stream() };
mem_lock<T> output_ptr2{ output2, get_test_stream() };
for (size_t i = 0, iend = input_data.size(); i < iend; ++i) {
const size_t j = i % eltwise_operand.size();
float expected = input_data[i] + eltwise_operand[j];
@@ -215,7 +261,16 @@ TEST(loop_gpu, basic_concat)
}
}
TEST(loop_gpu, basic_concat_nested)
TEST(loop_gpu, basic_concat) {
test_loop_gpu_basic_concat<float>(false);
}
TEST(export_import_loop_gpu, basic_concat) {
test_loop_gpu_basic_concat<float>(true);
}
template <typename T>
void test_loop_gpu_basic_concat_nested(bool is_caching_test)
{
auto& engine = get_test_engine();
@@ -231,12 +286,12 @@ TEST(loop_gpu, basic_concat_nested)
/////////////////////////////////
// set data
/////////////////////////////////
std::vector<float> input_data{
std::vector<T> input_data{
1.0f, 2.0f, -15.f, 3.0f, 4.0f, -15.f, 5.0f, 6.0f, -15.f, 7.0f,
-15.f, 0.0f, 0.0f, -15.f, 0.5f, -0.5f, -15.f, 8.0f, 1.5f, 5.2f
};
std::vector<float> inner_eltwise_operand {
std::vector<T> inner_eltwise_operand {
1.f, -2.f, 3.f, -4.f
};
@@ -304,14 +359,32 @@ TEST(loop_gpu, basic_concat_nested)
/////////////////////////////////
// network execution
/////////////////////////////////
network network(engine, main_topology);
network.set_input_data("input", input_mem);
network.set_input_data("trip_count", trip_count_mem);
network.set_input_data("initial_condition", initial_condition_mem);
network.set_input_data("inner_trip_count", inner_trip_count_mem);
network.set_input_data("inner_initial_condition", inner_initial_condition_mem);
cldnn::network::ptr network;
auto outputs = network.execute();
if (is_caching_test) {
membuf mem_buf;
{
cldnn::network _network(engine, main_topology);
std::ostream out_mem(&mem_buf);
BinaryOutputBuffer ob = BinaryOutputBuffer(out_mem);
_network.save(ob);
}
{
std::istream in_mem(&mem_buf);
BinaryInputBuffer ib = BinaryInputBuffer(in_mem, engine);
network = std::make_shared<cldnn::network>(ib, get_test_stream_ptr(), engine);
}
} else {
network = std::make_shared<cldnn::network>(engine, main_topology);
}
network->set_input_data("input", input_mem);
network->set_input_data("trip_count", trip_count_mem);
network->set_input_data("initial_condition", initial_condition_mem);
network->set_input_data("inner_trip_count", inner_trip_count_mem);
network->set_input_data("inner_initial_condition", inner_initial_condition_mem);
auto outputs = network->execute();
ASSERT_EQ(outputs.size(), 1);
auto output = outputs.begin()->second.get_memory();
auto output_layout = output->get_layout();
@@ -319,8 +392,8 @@ TEST(loop_gpu, basic_concat_nested)
/////////////////////////////////
// calculate expected output
/////////////////////////////////
std::vector<float> input_data2(input_data);
std::vector<float> expected(input_data2.size());
std::vector<T> input_data2(input_data);
std::vector<T> expected(input_data2.size());
for (int i=0 ; i<outer_trip_count ; ++i) {
for (size_t i=0, iend = input_data2.size(); i<iend; ++i) {
// eltwise sum in inner loop
@@ -341,16 +414,16 @@ TEST(loop_gpu, basic_concat_nested)
// check output values
ASSERT_EQ(output_layout.count(), expected.size());
{
mem_lock<float> output_ptr{ output, get_test_stream() };
mem_lock<T> output_ptr{ output, get_test_stream() };
for (size_t i = 0; i < output_layout.count(); ++i) {
ASSERT_FLOAT_EQ(output_ptr[i], expected.at(i));
}
}
// allocate new output memory, run and test everything once again
layout loop_l = network.get_output_memory("loop")->get_layout();
layout loop_l = network->get_output_memory("loop")->get_layout();
auto output_mem = engine.allocate_memory(loop_l);
network.set_output_memory("loop", output_mem);
network->set_output_memory("loop", output_mem);
set_values(input_mem, input_data);
set_values(inner_operand_mem, inner_eltwise_operand);
@@ -359,12 +432,20 @@ TEST(loop_gpu, basic_concat_nested)
set_values(trip_count_mem, { outer_trip_count });
set_values(initial_condition_mem, { outer_initial_condition });
outputs = network.execute();
outputs = network->execute();
auto output2 = outputs.begin()->second.get_memory();
{
mem_lock<float> output_ptr{ output2, get_test_stream() };
mem_lock<T> output_ptr{ output2, get_test_stream() };
for (size_t i = 0; i < output_layout.count(); ++i) {
ASSERT_FLOAT_EQ(output_ptr[i], expected.at(i));
}
}
}
TEST(loop_gpu, basic_concat_nested) {
test_loop_gpu_basic_concat_nested<float>(false);
}
TEST(export_import_loop_gpu, basic_concat_nested) {
test_loop_gpu_basic_concat_nested<float>(true);
}