[GPU] Add sub/div mode in eltwise fusing (#8759) (#8759)

- Add sub/div operation of eltwise fusing
- Propergate dep ordered info to Jitter
- Add sub/div to the fusing gpu tests
This commit is contained in:
Paul Youngsoo Ahn authored and GitHub committed 2021-12-13 10:24:37 +03:00
1 parent 4f62a48077
commit 4e8a6d5a4b
13 files changed
+295 -73

No files matched your search

@@ -190,7 +190,9 @@ public:
bool extract_and_remove(program_node& node);
// Fuses two nodes into fused_node and removes peer_node from graph
void fuse_nodes(program_node& fused_node, program_node& peer_node, std::map<primitive_id, std::vector<primitive_id>>* fusing_history);
void fuse_nodes(program_node& fused_node,
program_node& peer_node,
std::map<primitive_id, std::vector<std::pair<primitive_id, size_t>>>* fusing_history);
// returns if 'node' has been removed
bool remove_if_dangling(program_node& node);
@@ -225,10 +225,12 @@ JitConstants BinaryConvolutionKernel1x1::GetFusedPrimitivesJitConstants(const bi
eltwise_fused_ops += "\\\n\t" + data_type + " " + e_add + " = (oc < 16) ? " +
get_shuffle(var_name + ".s0", "oc") + " : " + get_shuffle(var_name + ".s1", "oc") + ";";
eltwise_fused_ops += "\\\n\tres = res+" + e_add + ";";
} else {
} else if (eltwise_p->mode == EltwiseMode::MUL) {
eltwise_fused_ops += "\\\n\t" + data_type + " " + e_mul + " = (oc < 16) ? " +
get_shuffle(var_name + ".s0", "oc") + " : " + get_shuffle(var_name + ".s1", "oc") + ";";
eltwise_fused_ops += "\\\n\tres = res*" + e_mul + ";";
} else {
throw std::invalid_argument("Not supported eltwise fusing op in binary_convolution_1x1 kernel: " + params.layerID);
}
break;
@@ -184,9 +184,11 @@ JitConstants BinaryConvolutionKernel1x1_b_fs_yx_fsv16::GetFusedPrimitivesJitCons
if (eltwise_p->mode == EltwiseMode::ADD) {
eltwise_fused_ops += "\\\n\t" + data_type + " " + e_add + " = " + get_shuffle(var_name, "oc") + ";";
eltwise_fused_ops += "\\\n\tres = res+" + var_name + ";";
} else {
} else if (eltwise_p->mode == EltwiseMode::MUL) {
eltwise_fused_ops += "\\\n\t" + data_type + " " + e_mul + " = " + get_shuffle(var_name, "oc") + ";";
eltwise_fused_ops += "\\\n\tres = res*" + var_name + ";";
} else {
throw std::invalid_argument("Not supported eltwise fusing op in binary_convolution_1x1_fsv16 kernel: " + params.layerID);
}
break;
@@ -238,9 +238,11 @@ JitConstants BinaryConvolutionKernelGeneric::GetFusedPrimitivesJitConstants(cons
if (eltwise_p->mode == EltwiseMode::ADD) {
eltwise_fused_ops += data_type + " " + e_add + " = (i < 16) ? " + var_name + ".s0" + " : " + var_name + ".s1;";
eltwise_fused_ops += "res = res+" + e_add +";";
} else {
} else if (eltwise_p->mode == EltwiseMode::MUL) {
eltwise_fused_ops += data_type + " " + e_mul + " = (i < 16) ? " + var_name + ".s0" + " : " + var_name + ".s1;";
eltwise_fused_ops += "res = res*" + e_mul +";";
} else {
throw std::invalid_argument("Not supported eltwise fusing op in binary_convolution_generic kernel: " + params.layerID);
}
break;
@@ -1509,7 +1509,18 @@ JitConstants FusedOpsCodeGenerator::MakeOpJitConstants(const FusedOpsConfigurati
auto idx = conf.bfzyx_idx_order;
std::string shuffle_var = conf.shuffle_var_name;
bool is_shuffled = false;
auto& fused_op_ids = desc.fused_op_ids;
auto& dep_data = desc.dep_data;
int first_fused_ops_idx = -1;
size_t dep_idx = 0;
for (auto dep : dep_data) {
if (dep.dep_type == kernel_selector::DepType::INTERNAL) {
first_fused_ops_idx = static_cast<int>(dep_idx);
break;
}
dep_idx++;
}
std::vector<std::string> input_vars;
out_var = GetOutputVarName(in_var, desc.op_id);
@@ -1531,12 +1542,8 @@ JitConstants FusedOpsCodeGenerator::MakeOpJitConstants(const FusedOpsConfigurati
auto get_acc_t = [&]() -> Datatype {
std::vector<Datatype> input_types = {desc.output_tensor.GetDType()};
for (auto& in : desc.tensors) {
input_types.push_back(in.GetDType());
}
for (auto& in : fused_op_ids) {
input_types.push_back(in.second);
for (auto& dep : dep_data) {
input_types.push_back(dep.data_type);
}
std::vector<Datatype> types_prioritized = { Datatype::F32, Datatype::F16 };
@@ -1551,15 +1558,11 @@ JitConstants FusedOpsCodeGenerator::MakeOpJitConstants(const FusedOpsConfigurati
};
auto get_input = [&](size_t index) -> std::string {
auto input_name = in_var;
auto input_type = in_type;
if (index > 0) {
size_t input_idx = index - 1;
size_t tensors_len = desc.tensors.size();
input_name = (input_idx < tensors_len)? GetInputVarName(input_idx, is_shuffled, shuffle_var)
: GetOutputVarName(in_var, fused_op_ids[input_idx - tensors_len].first);
input_type = (input_idx < tensors_len)? desc.tensors[input_idx].GetDType() : fused_op_ids[input_idx - tensors_len].second;
}
const auto dep = dep_data[index];
auto input_name = (dep.dep_type == kernel_selector::DepType::ORIGINAL)? in_var :
(dep.dep_type == kernel_selector::DepType::INTERNAL)? GetOutputVarName(in_var, dep.op_id)
: GetInputVarName(dep.op_id, is_shuffled, shuffle_var);
auto input_type = (dep.dep_type == kernel_selector::DepType::ORIGINAL)? in_type : dep.data_type;
auto acc_t = get_acc_t();
if (input_type != acc_t)
@@ -1568,13 +1571,7 @@ JitConstants FusedOpsCodeGenerator::MakeOpJitConstants(const FusedOpsConfigurati
return input_name;
};
// Generate input variable list: dst + tensor inputs + fused ops input
// If the input_vars_length are larger than max_num_input_vars, do not add dst to input variable list.
// because dst is not used, when Fused op has both tensor and fused input.
size_t input_vars_length = 1 + desc.tensors.size() + fused_op_ids.size(); // dst + tensor inputs + fused ops input
size_t max_num_input_vars = (desc.tensors.size() > 1)? 3 : 2;
size_t start_idx = (input_vars_length > max_num_input_vars) ? 1 : 0;
for (size_t i = start_idx; i < input_vars_length; i++) {
for (size_t i = 0; i < dep_data.size(); i++) {
input_vars.push_back(get_input(i));
}
@@ -1595,7 +1592,6 @@ JitConstants FusedOpsCodeGenerator::MakeOpJitConstants(const FusedOpsConfigurati
auto p = desc.GetOpParams<eltwise_fuse_params>();
if (!p)
throw std::runtime_error("[clDNN] Eltwise fuse params can't be nullptr");
std::string op = "";
switch (p->mode) {
case kernel_selector::EltwiseMode::ADD:
@@ -1604,6 +1600,12 @@ JitConstants FusedOpsCodeGenerator::MakeOpJitConstants(const FusedOpsConfigurati
case kernel_selector::EltwiseMode::MUL:
op = "*";
break;
case kernel_selector::EltwiseMode::SUB:
op = "-";
break;
case kernel_selector::EltwiseMode::DIV:
op = "/";
break;
default:
throw std::runtime_error("[clDNN] Eltwise mode is not supported in fused ops codegen");
}
@@ -1618,8 +1620,8 @@ JitConstants FusedOpsCodeGenerator::MakeOpJitConstants(const FusedOpsConfigurati
if (!p)
throw std::runtime_error("[clDNN] Quantize fuse params can't be nullptr");
std::string in_converted = (fused_op_ids.empty()) ? in_var : GetOutputVarName(in_var, fused_op_ids[0].first);
Datatype input_type = (fused_op_ids.empty()) ? in_type : fused_op_ids[0].second;
std::string in_converted = (first_fused_ops_idx < 0) ? in_var : GetOutputVarName(in_var, dep_data[first_fused_ops_idx].op_id);
Datatype input_type = (first_fused_ops_idx < 0) ? in_type : dep_data[first_fused_ops_idx].data_type;
Datatype tmp_type = Datatype::F32;
std::string tmp_type_str = GetType(tmp_type, vec_size);
std::string tmp_var = out_var + "_tmp";
@@ -1722,8 +1724,7 @@ JitConstants FusedOpsCodeGenerator::MakeOpJitConstants(const FusedOpsConfigurati
case KernelType::ACTIVATION: {
auto p = desc.GetOpParams<activation_fuse_params>();
base_activation_params activation_p = p->param;
std::string new_in_var = (fused_op_ids.empty()) ? in_var : GetOutputVarName(in_var, fused_op_ids[0].first);
std::string new_in_var = (first_fused_ops_idx < 0) ? in_var : GetOutputVarName(in_var, dep_data[first_fused_ops_idx].op_id);
op_decls += "\\\n\t" + GetOutputType(vec_size) + " " + out_var + " = " + ConvertToOutputType(new_in_var, vec_size) + ";";
if (activation_p.function != ActivationFunction::NONE) {
auto suffix = "_FUSED_OP"+toCodeString(desc.op_id) + conf.suffix;
@@ -14,6 +14,7 @@
#include <tuple>
#include <set>
#include <iostream>
#include "intel_gpu/runtime/debug_configuration.hpp"
// #define ENABLE_ENV
// #define ENABLE_ENV_PRINT
@@ -98,8 +99,14 @@ KernelsData kernel_selector_base::GetNaiveBestKernel(const Params& params,
}
#endif
}
} catch (std::runtime_error&) {
} catch (std::runtime_error& ex) {
// we have to handle it in order to avoid exception in KernelSelector as much we can
GPU_DEBUG_GET_INSTANCE(debug_config);
GPU_DEBUG_IF(debug_config->verbose >= 3) {
kernelName = (implementation != nullptr)? implementation->GetName() : "[impl is null]";
GPU_DEBUG_COUT << "layerID: " << params.layerID << " kenrel: "
<< kernelName << " - " << ex.what() << std::endl;
}
}
}
@@ -187,8 +194,14 @@ KernelsData kernel_selector_base::GetAutoTuneBestKernel(const Params& params,
kernelName = implementation->GetName();
}
}
} catch (std::runtime_error&) {
} catch (std::runtime_error& ex) {
// we have to handle it in order to avoid exception in KernelSelector as much we can
GPU_DEBUG_GET_INSTANCE(debug_config);
GPU_DEBUG_IF(debug_config->verbose >= 3) {
kernelName = (implementation != nullptr)? implementation->GetName() : "[impl is null]";
GPU_DEBUG_COUT << "layerID: " << params.layerID << " kenrel: "
<< kernelName << " - " << ex.what() << std::endl;
}
}
}
}
@@ -210,8 +223,14 @@ KernelsData kernel_selector_base::GetAutoTuneBestKernel(const Params& params,
kernelName = implementation->GetName();
}
}
} catch (std::runtime_error&) {
} catch (std::runtime_error& ex) {
// we have to handle it in order to avoid exception in KernelSelector as much we can
GPU_DEBUG_GET_INSTANCE(debug_config);
GPU_DEBUG_IF(debug_config->verbose >= 3) {
kernelName = (implementation != nullptr)? implementation->GetName() : "[impl is null]";
GPU_DEBUG_COUT << "layerID: " << params.layerID << " kenrel: "
<< kernelName << " - " << ex.what() << std::endl;
}
}
}
}
@@ -490,6 +490,26 @@ struct FusedOpsConfiguration {
bool IsPostReorderFused(void) const { return orig_output_layout != DataLayout::DataLayoutCount; }
};
// Dependency(Input) type of fusing operation in fused node.
// There are different ways to generate input var name and type by the dependency(input) type in MakeOpJitConstants in jitter
// - ORIGINAL: The input of the operation is the fused node such as Conv
// - EXTERNAL: The input of the operation is the external node outside the fused node
// - INTERNAL: The input of the operation is the another fused operation in the fused node
enum class DepType {
UNDEFINED = -1,
ORIGINAL = 0,
EXTERNAL = 1,
INTERNAL = 2
};
// Dependency(Input) information of fusing operation which is used to generate input var name and type
// in MakeOpJitConstants in jitter
struct dep_info {
DepType dep_type = DepType::UNDEFINED;
size_t op_id;
Datatype data_type;
};
// Instance of fused_operation_desc is added to fused_ops vector if a node has been fused to current one using program::fuse_nodes
// method. In order to process fused ops following modifications should be done in a kernel:
// option 1 - using common generator:
@@ -542,7 +562,7 @@ struct fused_operation_desc {
MultiDataTensor tensors;
DataTensor output_tensor;
size_t op_id;
std::vector<std::pair<size_t, Datatype>> fused_op_ids;
std::vector<dep_info> dep_data = {};
// Helper functions for operation generation
KernelType GetType() const { return op_params->GetType(); }
@@ -185,7 +185,7 @@ void prepare_primitive_fusing::fuse_reorders(program &p) {
void prepare_primitive_fusing::fuse_activations(program &p) {
bool is_debug = p.get_options().get<build_option_type::debug>()->enabled();
std::map<primitive_id, std::vector<primitive_id>> fusing_history;
std::map<primitive_id, std::vector<std::pair<primitive_id, size_t>>> fusing_history;
bool use_onednn_impls = false;
#ifdef ENABLE_ONEDNN_FOR_GPU
@@ -457,7 +457,7 @@ void prepare_primitive_fusing::fuse_bias(program &p) {
void prepare_primitive_fusing::fuse_simple_primitives(program &p) {
bool recalc_processing_order = false;
std::map<primitive_id, std::vector<primitive_id>> fusing_history;
std::map<primitive_id, std::vector<std::pair<primitive_id, size_t>>> fusing_history;
const uint8_t supports_immad = p.get_engine().get_device_info().supports_immad;
auto itr = p.get_processing_order().begin();
@@ -631,13 +631,15 @@ void prepare_primitive_fusing::fuse_simple_primitives(program &p) {
return true;
};
auto get_users_from_fusing_history = [&](primitive_id id) {
auto get_users_from_fusing_history = [&](const primitive_id& id) {
std::vector<primitive_id> users;
for (auto deps_data : fusing_history) {
auto key = deps_data.first;
auto deps_vec = deps_data.second;
auto iter = std::find(deps_vec.begin(), deps_vec.end(), id);
if (iter != deps_vec.end()) {
for (auto fusing_info : fusing_history) {
auto key = fusing_info.first;
auto dep_info_vec = fusing_info.second;
auto iter = std::find_if(dep_info_vec.begin(), dep_info_vec.end(), [&](std::pair<primitive_id, size_t>& dep_info) {
return (id == dep_info.first);
});
if (iter != dep_info_vec.end()) {
users.push_back(key);
}
}
@@ -660,7 +662,7 @@ void prepare_primitive_fusing::fuse_simple_primitives(program &p) {
auto& fused_descs = input_data.get_fused_primitives();
auto origin_input_iter = std::find_if(fused_descs.begin(), fused_descs.end(),
[&](cldnn::fused_primitive_desc& desc) {
return (desc.node->id() == prim_id);
return (desc.node->id() == prim_id.first);
});
if (origin_input_iter != fused_descs.end()) {
auto users = get_users_from_fusing_history(origin_input_iter->node->id());
@@ -922,7 +924,9 @@ void prepare_primitive_fusing::fuse_simple_primitives(program &p) {
std::shared_ptr<const cldnn::eltwise> prim = node.get_primitive();
const std::vector<eltwise_mode> supported_modes = {
eltwise_mode::sum,
eltwise_mode::prod
eltwise_mode::prod,
eltwise_mode::sub,
eltwise_mode::div
};
if (node.is_output() || node.inputs_count() != 2 ||
@@ -937,7 +941,8 @@ void prepare_primitive_fusing::fuse_simple_primitives(program &p) {
for (size_t i = 0; i < parents.size(); i++) {
can_fuse_parents[i] = (parents[i]->is_type<convolution>() && conv_supports_fusings(parents[i]->as<convolution>())) ||
(parents[i]->is_type<binary_convolution>() && bin_conv_supports_eltw_fusings(parents[i]->as<binary_convolution>())) ||
((prim->mode == eltwise_mode::sum || prim->mode == eltwise_mode::prod) &&
((parents[i]->is_type<binary_convolution>() && bin_conv_supports_eltw_fusings(parents[i]->as<binary_convolution>())) ||
(parents[i]->is_type<mvn>() && mvn_supports_fusings(parents[i]->as<mvn>())) ||
(parents[i]->is_type<deconvolution>()) ||
(parents[i]->is_type<permute>()) ||
@@ -955,7 +960,7 @@ void prepare_primitive_fusing::fuse_simple_primitives(program &p) {
(parents[i]->is_type<scatter_elements_update>()) ||
(parents[i]->is_type<pooling>() && pooling_supports_fusings(parents[i]->as<pooling>())) ||
(parents[i]->is_type<depth_to_space>() && dts_supports_fusings(parents[i]->as<depth_to_space>())) ||
(parents[i]->is_type<reduce>() && reduce_supports_fusings(parents[i]->as<reduce>()));
(parents[i]->is_type<reduce>() && reduce_supports_fusings(parents[i]->as<reduce>()))));
}
// Disable fusion to a node on constant path when second input is in data flow
@@ -1096,12 +1101,11 @@ void prepare_primitive_fusing::fuse_simple_primitives(program &p) {
} while (node_queue.size() > 1);
} else {
merge_allowed = fused_node->get_users().size() == 1;
for (auto& parent : fused_node->get_dependencies())
if (parent->id() == peer_node->id())
merge_allowed = false;
}
for (auto& parent : fused_node->get_dependencies())
if (parent->id() == peer_node->id())
merge_allowed = false;
if (!merge_allowed)
return;
@@ -1150,13 +1154,10 @@ void prepare_primitive_fusing::optimize_fused_ops(program& p) {
if (desc.node->id() == prim.node->id()) {
continue;
}
auto rm_iter = std::find_if(prim.fused_deps.begin(), prim.fused_deps.end(), [&](primitive_id& dep_id){
return (desc.node->id() == dep_id);
});
auto rm_iter = prim.fused_deps.find(desc.node->id());
if (rm_iter != prim.fused_deps.end()) {
prim.fused_deps.erase(rm_iter);
prim.fused_deps.insert(prim.fused_deps.end(), desc.fused_deps.begin(), desc.fused_deps.end());
prim.fused_deps.insert(desc.fused_deps.begin(), desc.fused_deps.end());
}
}
};
@@ -160,7 +160,7 @@ inline params_t get_default_params(const arg_t& arg, uint32_t split = 1) {
params.layerID = arg.id();
convert_fused_activation_func_params(arg, params.activations);
std::map<primitive_id, std::pair<size_t, kernel_selector::Datatype>> prim_op_id_map;
std::map<primitive_id, std::pair<size_t, kernel_selector::Datatype>> prim_id_type_map;
size_t op_id = 0;
for (auto& fused_prim : arg.get_fused_primitives()) {
kernel_selector::fused_operation_desc desc;
@@ -169,22 +169,43 @@ inline params_t get_default_params(const arg_t& arg, uint32_t split = 1) {
CLDNN_ERROR_MESSAGE(arg.id(), "Invalid fused operation (" + fused_prim.node->id() + ") of type " +
fused_prim.node->get_primitive()->type_string() );
}
desc.dep_idx_start = fused_prim.dep_start_idx;
desc.dep_size = fused_prim.deps.size();
desc.op_id = op_id++;
desc.output_tensor = convert_data_tensor(fused_prim.output_layout);
prim_op_id_map[fused_prim.node->id()] = std::make_pair(desc.op_id, desc.output_tensor.GetDType());
for (auto& dep : fused_prim.fused_deps) {
auto iter = prim_op_id_map.find(dep);
if (iter != prim_op_id_map.end()) {
desc.fused_op_ids.push_back(iter->second);
}
}
prim_id_type_map[fused_prim.node->id()] = std::make_pair(desc.op_id, desc.output_tensor.GetDType());
for (size_t i = desc.dep_idx_start; i < desc.dep_idx_start + desc.dep_size; i++) {
desc.tensors.push_back(convert_data_tensor(arg.get_dependency(i).get_output_layout()));
}
if (fused_prim.total_num_deps > 0) {
desc.dep_data.resize(fused_prim.total_num_deps);
for (auto& dep : fused_prim.fused_deps) {
auto iter = prim_id_type_map.find(dep.first);
if (iter != prim_id_type_map.end()) {
auto& op_data = iter->second;
desc.dep_data[dep.second].dep_type = kernel_selector::DepType::INTERNAL;
desc.dep_data[dep.second].op_id = op_data.first;
desc.dep_data[dep.second].data_type = op_data.second;
}
}
int idx = 0;
for (auto& dep : fused_prim.deps) {
desc.dep_data[dep.second].dep_type = kernel_selector::DepType::EXTERNAL;
desc.dep_data[dep.second].op_id = idx;
desc.dep_data[dep.second].data_type = desc.tensors[idx++].GetDType();
}
for (auto& dep : desc.dep_data) {
if (dep.dep_type == kernel_selector::DepType::UNDEFINED) {
dep.dep_type = kernel_selector::DepType::ORIGINAL;
break;
}
}
}
params.fused_ops.push_back(desc);
}
@@ -60,8 +60,9 @@ struct fused_primitive_desc_onednn {
struct fused_primitive_desc {
std::shared_ptr<program_node> node;
size_t dep_start_idx;
std::vector<primitive_id> deps;
std::vector<primitive_id> fused_deps;
std::map<primitive_id, size_t> deps;
std::map<primitive_id, size_t> fused_deps;
size_t total_num_deps = 0;
activation_func activation;
activation_additional_params activation_params;
layout input_layout = layout(data_types::f32, format::bfyx, tensor());
+20 -5
View File
@@ -993,11 +993,15 @@ bool program::extract_and_remove(program_node& node) {
return true;
}
void program::fuse_nodes(program_node &fused_node, program_node &peer_node, std::map<primitive_id, std::vector<primitive_id>>* fusing_history) {
void program::fuse_nodes(program_node &fused_node,
program_node &peer_node,
std::map<primitive_id, std::vector<std::pair<primitive_id, size_t>>>* fusing_history) {
auto peer_layout = peer_node.get_output_layout();
fused_primitive_desc local_desc;
local_desc.node = get_node_ptr(peer_node.id());
local_desc.dep_start_idx = fused_node.get_dependencies().size();
local_desc.total_num_deps = peer_node.get_dependencies().size();
local_desc.output_layout = peer_layout;
local_desc.activation = activation_func::none;
if (!peer_node.get_fused_activations_funcs().empty()) {
@@ -1014,15 +1018,18 @@ void program::fuse_nodes(program_node &fused_node, program_node &peer_node, std:
auto history_iter = fusing_history->find(peer_node.id());
if (history_iter != fusing_history->end()) {
for (auto& id : history_iter->second) {
local_desc.fused_deps.push_back(id);
local_desc.fused_deps.emplace(id.first, id.second);
}
}
// Add new dependencies to the fused_node
size_t deps_idx = 0;
for (size_t i = 0; i < peer_node.get_dependencies().size(); i++) {
auto& dep = peer_node.get_dependency(i);
if (dep.id() == fused_node.id())
if (dep.id() == fused_node.id()) {
deps_idx++;
continue;
}
if (peer_node.is_type<quantize>()) {
quantize_node& q_node = peer_node.as<quantize>();
@@ -1048,9 +1055,11 @@ void program::fuse_nodes(program_node &fused_node, program_node &peer_node, std:
}
}
fused_node.dependencies.push_back(&dep);
local_desc.deps.push_back(dep.id());
local_desc.deps.emplace(dep.id(), deps_idx++);
dep.users.push_back(&fused_node);
}
local_desc.total_num_deps = std::min(local_desc.total_num_deps, deps_idx);
fused_node.add_fused_primitive(local_desc);
// This shouldn't happen, but who knows...
if (peer_node.has_fused_primitives()) {
@@ -1059,7 +1068,13 @@ void program::fuse_nodes(program_node &fused_node, program_node &peer_node, std:
add_optimized_primitive_info(peer_node.id(), { fused_node.id() });
for (auto& user : peer_node.users) {
(*fusing_history)[user->id()].push_back(peer_node.id());
size_t dep_idx = 0;
for (auto& dep : user->dependencies) {
if (dep->id() == peer_node.id())
break;
dep_idx++;
}
(*fusing_history)[user->id()].push_back(std::make_pair(peer_node.id(), dep_idx));
}
// Remove all edges connected with peer node
+5 -1
View File
@@ -107,7 +107,11 @@ std::unique_ptr<json_composite> program_node::desc_to_json() const {
for (auto& fused_desc : get_fused_primitives()) {
json_composite fused_node_info;
fused_node_info.add("id", fused_desc.node->id());
fused_node_info.add("dependencies", fused_desc.deps);
std::vector<primitive_id> dep_ids;
for (auto dep : fused_desc.deps) {
dep_ids.push_back(dep.first);
}
fused_node_info.add("dependencies", dep_ids);
fused_node_info.add("dep start_idx", fused_desc.dep_start_idx);
json_composite info;
info.add("data type", dt_to_str(fused_desc.output_layout.data_type));
@@ -1052,6 +1052,138 @@ INSTANTIATE_TEST_SUITE_P(fusings_gpu, conv_fp32_multi_eltwise_4_clamp,
bc_test_params{CASE_CONV_FP16_4, 2, 7},
}));
class conv_fp32_eltwise_fusing_extend_ops : public ConvFusingTest {};
TEST_P(conv_fp32_eltwise_fusing_extend_ops, pattern01_simple_sub) {
if (engine.get_device_info().supports_immad) {
return;
}
auto p = GetParam();
create_topologies(input_layout("input", get_input_layout(p)),
data("eltwise_data1", get_mem(get_output_layout(p))),
data("eltwise_data2", get_mem(get_output_layout(p))),
data("eltwise_data4", get_mem(get_output_layout(p))),
data("bias", get_mem(get_bias_layout(p))),
data("weights", get_mem(get_weights_layout(p))),
convolution("conv_prim", "input", { "weights" }, {"bias"}, p.groups, p.stride, p.pad, p.dilation),
eltwise("eltwise1_sum", "conv_prim", "eltwise_data1", eltwise_mode::sum),
eltwise("eltwise2_sub", "conv_prim", "eltwise_data2", eltwise_mode::sub),
eltwise("eltwise3_prod", "eltwise1_sum", "eltwise2_sub", eltwise_mode::prod),
eltwise("eltwise4_sum", "eltwise3_prod", "eltwise_data4", eltwise_mode::sum),
concatenation("concat", { "eltwise4_sum", "eltwise4_sum" }, cldnn::concatenation::along_f),
reorder("reorder_bfyx", "concat", p.default_format, data_types::f32)
);
implementation_desc conv_impl = { format::b_fs_yx_fsv16, ""};
bo_fused.set_option(build_option::force_implementations({ {"conv_prim", conv_impl} }));
tolerance = 1e-5f;
execute(p);
}
TEST_P(conv_fp32_eltwise_fusing_extend_ops, pattern02_sub_scale) {
if (engine.get_device_info().supports_immad) {
return;
}
auto p = GetParam();
create_topologies(input_layout("input", get_input_layout(p)),
data("eltwise_data1", get_mem(get_output_layout(p))),
data("eltwise_data2", get_mem(get_output_layout(p))),
data("scale_data", get_mem(get_per_channel_layout(p), 1.0f/p.kernel.count())),
data("bias", get_mem(get_bias_layout(p))),
data("weights", get_mem(get_weights_layout(p))),
convolution("conv_prim", "input", { "weights" }, {"bias"}, p.groups, p.stride, p.pad, p.dilation),
eltwise("eltwise1_sum", "conv_prim", "eltwise_data1", eltwise_mode::sum),
eltwise("eltwise2_sub", "conv_prim", "eltwise1_sum", eltwise_mode::sub),
eltwise("eltwise3_prod", "eltwise2_sub", "eltwise_data2", eltwise_mode::prod),
scale("scale", "eltwise3_prod", "scale_data"),
concatenation("concat", { "scale", "scale" }, cldnn::concatenation::along_f),
reorder("reorder_bfyx", "concat", p.default_format, data_types::f32)
);
implementation_desc conv_impl = { format::b_fs_yx_fsv16, ""};
bo_fused.set_option(build_option::force_implementations({ {"conv_prim", conv_impl} }));
tolerance = 1e-5f;
execute(p);
}
TEST_P(conv_fp32_eltwise_fusing_extend_ops, pattern03_sub_div) {
if (engine.get_device_info().supports_immad) {
return;
}
auto p = GetParam();
create_topologies(input_layout("input", get_input_layout(p)),
data("eltwise_data1", get_mem(get_output_layout(p))),
data("eltwise_data2", get_mem(get_output_layout(p), 1.0f)),
data("eltwise_data3", get_mem(get_output_layout(p))),
data("eltwise_data4", get_mem(get_output_layout(p))),
data("bias", get_mem(get_bias_layout(p))),
data("weights", get_mem(get_weights_layout(p))),
convolution("conv_prim", "input", { "weights" }, {"bias"}, p.groups, p.stride, p.pad, p.dilation),
eltwise("eltwise1_sum", "conv_prim", "eltwise_data1", eltwise_mode::sum),
eltwise("eltwise2_div", "eltwise1_sum", "eltwise_data2", eltwise_mode::div),
eltwise("eltwise3_prod", "eltwise2_div", "eltwise_data3", eltwise_mode::prod),
eltwise("eltwise4_sum", "eltwise3_prod", "eltwise_data4", eltwise_mode::sum),
concatenation("concat", { "eltwise4_sum", "eltwise4_sum" }, cldnn::concatenation::along_f),
reorder("reorder_bfyx", "concat", p.default_format, data_types::f32)
);
implementation_desc conv_impl = { format::b_fs_yx_fsv16, ""};
bo_fused.set_option(build_option::force_implementations({ {"conv_prim", conv_impl} }));
tolerance = 1e-5f;
execute(p);
}
INSTANTIATE_TEST_SUITE_P(fusings_gpu, conv_fp32_eltwise_fusing_extend_ops,
::testing::ValuesIn(std::vector<bc_test_params>{
bc_test_params{CASE_CONV_FP32_2, 3, 7},
bc_test_params{CASE_CONV_FP32_3, 3, 7},
bc_test_params{CASE_CONV_FP32_4, 3, 7},
bc_test_params{CASE_CONV_FP16_2, 3, 7},
bc_test_params{CASE_CONV_FP16_3, 3, 7},
bc_test_params{CASE_CONV_FP16_4, 3, 7},
}));
class conv_fp32_eltwise_fusing_2conv : public ConvFusingTest {};
TEST_P(conv_fp32_eltwise_fusing_2conv, basic) {
if (engine.get_device_info().supports_immad) {
return;
}
auto p = GetParam();
create_topologies(input_layout("input", get_input_layout(p)),
data("bias0", get_mem(get_bias_layout(p))),
data("weights0", get_mem(get_weights_layout(p))),
data("bias", get_mem(get_bias_layout(p))),
data("weights", get_mem(get_weights_layout(p))),
convolution("conv_prim0", "input", { "weights0" }, {"bias0"}, p.groups, p.stride, p.pad, p.dilation),
convolution("conv_prim", "input", { "weights" }, {"bias"}, p.groups, p.stride, p.pad, p.dilation),
eltwise("eltwise1", "conv_prim0", "conv_prim", eltwise_mode::sum),
eltwise("eltwise2", "conv_prim0", "conv_prim", eltwise_mode::sum),
eltwise("eltwise3", "eltwise1", "eltwise2", eltwise_mode::prod),
concatenation("concat", { "eltwise3", "eltwise3" }, cldnn::concatenation::along_f),
reorder("reorder_bfyx", "concat", p.default_format, data_types::f32)
);
implementation_desc conv_impl = { format::b_fs_yx_fsv16, ""};
bo_fused.set_option(build_option::force_implementations({ {"conv_prim0", conv_impl}, {"conv_prim", conv_impl} }));
tolerance = 1e-5f;
execute(p);
}
INSTANTIATE_TEST_SUITE_P(fusings_gpu, conv_fp32_eltwise_fusing_2conv,
::testing::ValuesIn(std::vector<bc_test_params>{
bc_test_params{CASE_CONV_FP32_2, 4, 7},
bc_test_params{CASE_CONV_FP32_3, 4, 7},
bc_test_params{CASE_CONV_FP32_4, 4, 7},
bc_test_params{CASE_CONV_FP16_2, 4, 7},
bc_test_params{CASE_CONV_FP16_3, 4, 7},
bc_test_params{CASE_CONV_FP16_4, 4, 7},
}));
class conv_fp32_multi_eltwise_3_fusing : public ConvFusingTest {};
TEST_P(conv_fp32_multi_eltwise_3_fusing, basic) {