[TF FE] Speed up compilation - part 2 (#21170)
Avoid use of heavy header Signed-off-by: Kazantsev, Roman <roman.kazantsev@intel.com>
This commit is contained in:
@@ -3,11 +3,16 @@
|
||||
//
|
||||
|
||||
#include "common_op_table.hpp"
|
||||
#include "openvino/opsets/opset10.hpp"
|
||||
#include "openvino/op/concat.hpp"
|
||||
#include "openvino/op/constant.hpp"
|
||||
#include "openvino/op/convert.hpp"
|
||||
#include "openvino/op/gather.hpp"
|
||||
#include "openvino/op/roi_pooling.hpp"
|
||||
#include "openvino/op/unsqueeze.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace ov;
|
||||
using namespace opset10;
|
||||
using namespace ov::op;
|
||||
|
||||
namespace ov {
|
||||
namespace frontend {
|
||||
@@ -28,21 +33,21 @@ OutputVector translate_crop_and_resize_bilinear(const NodeContext& node) {
|
||||
// concatenate boxes and box_ind inputs because
|
||||
// ROIPooling accepts ROIs in a format [batch_id, x_1, y_1, x_2, y_2]
|
||||
// prepare box_ind for futher concatenation
|
||||
auto const_one = make_shared<Constant>(element::i32, Shape{1}, 1);
|
||||
box_ind = make_shared<Unsqueeze>(box_ind, const_one);
|
||||
box_ind = make_shared<Convert>(box_ind, element::f32);
|
||||
boxes = make_shared<Concat>(OutputVector{box_ind, boxes}, 1);
|
||||
auto const_one = make_shared<v0::Constant>(element::i32, Shape{1}, 1);
|
||||
box_ind = make_shared<v0::Unsqueeze>(box_ind, const_one);
|
||||
box_ind = make_shared<v0::Convert>(box_ind, element::f32);
|
||||
boxes = make_shared<v0::Concat>(OutputVector{box_ind, boxes}, 1);
|
||||
|
||||
// boxes are going in the format [y1, x1, y2, x2]
|
||||
// so we need to adjust them to the format [x_1, y_1, x_2, y_2]
|
||||
// use Gather operation for the swapping
|
||||
auto gather_order = make_shared<Constant>(element::i32, Shape{5}, vector<int32_t>{0, 2, 1, 4, 3});
|
||||
auto gather_axis = make_shared<Constant>(element::i32, Shape{1}, vector<int32_t>{1});
|
||||
boxes = make_shared<Gather>(boxes, gather_order, gather_axis);
|
||||
auto gather_order = make_shared<v0::Constant>(element::i32, Shape{5}, vector<int32_t>{0, 2, 1, 4, 3});
|
||||
auto gather_axis = make_shared<v0::Constant>(element::i32, Shape{1}, vector<int32_t>{1});
|
||||
boxes = make_shared<v8::Gather>(boxes, gather_order, gather_axis);
|
||||
|
||||
// prepare input image for ROIPooling
|
||||
image = make_transpose(image, {0, 3, 1, 2})->output(0);
|
||||
Output<Node> roi_pooling = make_shared<ROIPooling>(image, boxes, crop_sizes, 1.0f, "bilinear");
|
||||
Output<Node> roi_pooling = make_shared<v0::ROIPooling>(image, boxes, crop_sizes, 1.0f, "bilinear");
|
||||
roi_pooling = make_transpose(roi_pooling, {0, 2, 3, 1})->output(0);
|
||||
set_node_name(node.get_name(), roi_pooling.get_node_shared_ptr());
|
||||
return {roi_pooling};
|
||||
|
||||
@@ -3,12 +3,22 @@
|
||||
//
|
||||
|
||||
#include "common_op_table.hpp"
|
||||
#include "openvino/opsets/opset8.hpp"
|
||||
#include "openvino/op/concat.hpp"
|
||||
#include "openvino/op/constant.hpp"
|
||||
#include "openvino/op/ctc_greedy_decoder_seq_len.hpp"
|
||||
#include "openvino/op/gather_nd.hpp"
|
||||
#include "openvino/op/negative.hpp"
|
||||
#include "openvino/op/non_zero.hpp"
|
||||
#include "openvino/op/not_equal.hpp"
|
||||
#include "openvino/op/reduce_max.hpp"
|
||||
#include "openvino/op/reduce_sum.hpp"
|
||||
#include "openvino/op/shape_of.hpp"
|
||||
#include "openvino/op/slice.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace ov;
|
||||
using namespace opset8;
|
||||
using namespace ov::op;
|
||||
using namespace frontend;
|
||||
using namespace frontend::tensorflow;
|
||||
|
||||
@@ -31,51 +41,54 @@ NamedOutputVector translate_ctc_greedy_decoder_op(const NodeContext& node) {
|
||||
AxisVector inputs_order = {1, 0, 2};
|
||||
inputs = frontend::tensorflow::make_transpose(inputs, inputs_order);
|
||||
|
||||
shared_ptr<CTCGreedyDecoderSeqLen> ctc_greedy_decoder = nullptr;
|
||||
shared_ptr<v6::CTCGreedyDecoderSeqLen> ctc_greedy_decoder = nullptr;
|
||||
if (blank_index == -1) {
|
||||
// default value for blank index means it should be equal to num_classes - 1
|
||||
// in this case it is not required to specify the third input for OpenVINO CTCGreedyDecoderSeqLen
|
||||
ctc_greedy_decoder =
|
||||
make_shared<CTCGreedyDecoderSeqLen>(inputs, sequence_length, merge_repeated, element::i64, element::i64);
|
||||
ctc_greedy_decoder = make_shared<v6::CTCGreedyDecoderSeqLen>(inputs,
|
||||
sequence_length,
|
||||
merge_repeated,
|
||||
element::i64,
|
||||
element::i64);
|
||||
} else {
|
||||
auto blank_index_const = create_same_type_const_scalar<int64_t>(sequence_length, blank_index);
|
||||
ctc_greedy_decoder = make_shared<CTCGreedyDecoderSeqLen>(inputs,
|
||||
sequence_length,
|
||||
blank_index_const,
|
||||
merge_repeated,
|
||||
element::i64,
|
||||
element::i64);
|
||||
ctc_greedy_decoder = make_shared<v6::CTCGreedyDecoderSeqLen>(inputs,
|
||||
sequence_length,
|
||||
blank_index_const,
|
||||
merge_repeated,
|
||||
element::i64,
|
||||
element::i64);
|
||||
}
|
||||
|
||||
// CTCGreedyDecoderSeqLen returns dense tensor holding the decoded results.
|
||||
// We need to transform this output into a sparse format.
|
||||
auto minus_one_const = make_shared<Constant>(element::i64, Shape{}, -1);
|
||||
auto decoded_mask = make_shared<NotEqual>(ctc_greedy_decoder->output(0), minus_one_const);
|
||||
auto decoded_indices = make_shared<NonZero>(decoded_mask, element::i64)->output(0);
|
||||
auto minus_one_const = make_shared<v0::Constant>(element::i64, Shape{}, -1);
|
||||
auto decoded_mask = make_shared<v1::NotEqual>(ctc_greedy_decoder->output(0), minus_one_const);
|
||||
auto decoded_indices = make_shared<v3::NonZero>(decoded_mask, element::i64)->output(0);
|
||||
|
||||
// Since the indices in row-major format, we need to transpose them before gathering values
|
||||
auto decoded_indices_transposed = frontend::tensorflow::make_transpose(decoded_indices, {1, 0});
|
||||
auto decoded_values = make_shared<GatherND>(ctc_greedy_decoder->output(0), decoded_indices_transposed);
|
||||
auto decoded_values = make_shared<v8::GatherND>(ctc_greedy_decoder->output(0), decoded_indices_transposed);
|
||||
|
||||
// Compute the shape of the smallest dense tensor that can contain the sparse
|
||||
// matrix represented by ng_indices and ng_values.
|
||||
auto max_seq_len_axis = make_shared<Constant>(element::i64, Shape{}, 0);
|
||||
auto max_seq_len = make_shared<ReduceMax>(ctc_greedy_decoder->output(1), max_seq_len_axis, true);
|
||||
auto max_seq_len_axis = make_shared<v0::Constant>(element::i64, Shape{}, 0);
|
||||
auto max_seq_len = make_shared<v1::ReduceMax>(ctc_greedy_decoder->output(1), max_seq_len_axis, true);
|
||||
// inputs shape is in the form [batch_size, time_size, num_classes]
|
||||
auto inputs_shape = make_shared<ShapeOf>(inputs, element::i64);
|
||||
auto slice_start = make_shared<Constant>(element::i64, Shape{1}, 0);
|
||||
auto slice_end = make_shared<Constant>(element::i64, Shape{1}, 1);
|
||||
auto slice_step = make_shared<Constant>(element::i64, Shape{1}, 1);
|
||||
auto batch_size = make_shared<Slice>(inputs_shape, slice_start, slice_end, slice_step);
|
||||
auto dense_shape = make_shared<Concat>(OutputVector{batch_size, max_seq_len}, 0);
|
||||
auto inputs_shape = make_shared<v3::ShapeOf>(inputs, element::i64);
|
||||
auto slice_start = make_shared<v0::Constant>(element::i64, Shape{1}, 0);
|
||||
auto slice_end = make_shared<v0::Constant>(element::i64, Shape{1}, 1);
|
||||
auto slice_step = make_shared<v0::Constant>(element::i64, Shape{1}, 1);
|
||||
auto batch_size = make_shared<v8::Slice>(inputs_shape, slice_start, slice_end, slice_step);
|
||||
auto dense_shape = make_shared<v0::Concat>(OutputVector{batch_size, max_seq_len}, 0);
|
||||
|
||||
// Compute the negative of the sum of the greatest logit at each timeframe
|
||||
// the inputs are in a form [batch_size, time_size, num_classes]
|
||||
auto max_log_probs_axis = make_shared<Constant>(element::i64, Shape{}, 2);
|
||||
auto max_log_probs = make_shared<ReduceMax>(inputs, max_log_probs_axis, false);
|
||||
auto sum_max_log_probs_axis = make_shared<Constant>(element::i64, Shape{}, 1);
|
||||
auto sum_max_log_probs = make_shared<ReduceSum>(max_log_probs, sum_max_log_probs_axis, false);
|
||||
auto neg_sum_logits = make_shared<Negative>(sum_max_log_probs);
|
||||
auto max_log_probs_axis = make_shared<v0::Constant>(element::i64, Shape{}, 2);
|
||||
auto max_log_probs = make_shared<v1::ReduceMax>(inputs, max_log_probs_axis, false);
|
||||
auto sum_max_log_probs_axis = make_shared<v0::Constant>(element::i64, Shape{}, 1);
|
||||
auto sum_max_log_probs = make_shared<v1::ReduceSum>(max_log_probs, sum_max_log_probs_axis, false);
|
||||
auto neg_sum_logits = make_shared<v0::Negative>(sum_max_log_probs);
|
||||
|
||||
set_node_name(node.get_name() + ":0", decoded_indices_transposed);
|
||||
set_node_name(node.get_name() + ":1", decoded_values);
|
||||
|
||||
@@ -2,11 +2,12 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include "openvino/op/depth_to_space.hpp"
|
||||
|
||||
#include "common_op_table.hpp"
|
||||
#include "openvino/opsets/opset8.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace ov::opset8;
|
||||
using namespace ov::op;
|
||||
|
||||
// Translate DepthToSpace op
|
||||
namespace ov {
|
||||
@@ -29,8 +30,8 @@ OutputVector translate_depth_to_space_op(const NodeContext& node) {
|
||||
bool is_nhwc = (data_format == "NHWC");
|
||||
|
||||
convert_nhwc_to_nchw(is_nhwc, input_data);
|
||||
auto mode = DepthToSpace::DepthToSpaceMode::BLOCKS_FIRST;
|
||||
auto depth_to_space = make_shared<DepthToSpace>(input_data, mode, block_size)->output(0);
|
||||
auto mode = v0::DepthToSpace::DepthToSpaceMode::BLOCKS_FIRST;
|
||||
auto depth_to_space = make_shared<v0::DepthToSpace>(input_data, mode, block_size)->output(0);
|
||||
convert_nchw_to_nhwc(is_nhwc, depth_to_space);
|
||||
set_node_name(node.get_name(), depth_to_space.get_node_shared_ptr());
|
||||
return {depth_to_space};
|
||||
|
||||
@@ -3,10 +3,13 @@
|
||||
//
|
||||
|
||||
#include "common_op_table.hpp"
|
||||
#include "openvino/opsets/opset8.hpp"
|
||||
#include "openvino/op/constant.hpp"
|
||||
#include "openvino/op/group_conv.hpp"
|
||||
#include "openvino/op/transpose.hpp"
|
||||
#include "openvino/op/unsqueeze.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace ov::opset8;
|
||||
using namespace ov::op;
|
||||
|
||||
namespace ov {
|
||||
namespace frontend {
|
||||
@@ -48,18 +51,18 @@ OutputVector translate_depthwise_conv_2d_native_op(const NodeContext& node) {
|
||||
|
||||
// prepare filter to have a number of groups equal to CIN
|
||||
auto unsqueeze_filter =
|
||||
make_shared<Unsqueeze>(filter, make_shared<Constant>(element::i64, Shape{1}, std::vector<int64_t>{3}));
|
||||
auto transposed_filter =
|
||||
make_shared<Transpose>(unsqueeze_filter,
|
||||
make_shared<Constant>(element::i64, Shape{5}, std::vector<int64_t>{2, 4, 3, 0, 1}));
|
||||
make_shared<v0::Unsqueeze>(filter, make_shared<v0::Constant>(element::i64, Shape{1}, std::vector<int64_t>{3}));
|
||||
auto transposed_filter = make_shared<v1::Transpose>(
|
||||
unsqueeze_filter,
|
||||
make_shared<v0::Constant>(element::i64, Shape{5}, std::vector<int64_t>{2, 4, 3, 0, 1}));
|
||||
|
||||
ov::Output<ov::Node> group_conv = make_shared<GroupConvolution>(input,
|
||||
transposed_filter,
|
||||
strides,
|
||||
CoordinateDiff({}),
|
||||
CoordinateDiff({}),
|
||||
dilations,
|
||||
auto_pad);
|
||||
ov::Output<ov::Node> group_conv = make_shared<v1::GroupConvolution>(input,
|
||||
transposed_filter,
|
||||
strides,
|
||||
CoordinateDiff({}),
|
||||
CoordinateDiff({}),
|
||||
dilations,
|
||||
auto_pad);
|
||||
ov::frontend::tensorflow::convert_nchw_to_nhwc(is_nhwc, group_conv, ov::Rank(4));
|
||||
ov::frontend::tensorflow::set_node_name(node.get_name(), group_conv.get_node_shared_ptr());
|
||||
return {group_conv};
|
||||
|
||||
@@ -5,12 +5,24 @@
|
||||
#include <limits>
|
||||
|
||||
#include "common_op_table.hpp"
|
||||
#include "openvino/opsets/opset10.hpp"
|
||||
#include "openvino/op/add.hpp"
|
||||
#include "openvino/op/broadcast.hpp"
|
||||
#include "openvino/op/constant.hpp"
|
||||
#include "openvino/op/convert_like.hpp"
|
||||
#include "openvino/op/gather.hpp"
|
||||
#include "openvino/op/multiply.hpp"
|
||||
#include "openvino/op/range.hpp"
|
||||
#include "openvino/op/reshape.hpp"
|
||||
#include "openvino/op/scatter_update.hpp"
|
||||
#include "openvino/op/squeeze.hpp"
|
||||
#include "openvino/op/topk.hpp"
|
||||
#include "openvino/op/unique.hpp"
|
||||
#include "openvino/op/variadic_split.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace ov;
|
||||
using namespace ov::opset10;
|
||||
using namespace ov::op;
|
||||
|
||||
namespace ov {
|
||||
namespace frontend {
|
||||
@@ -22,56 +34,56 @@ OutputVector translate_dynamic_partition_op(const NodeContext& node) {
|
||||
auto partitions = node.get_input(1);
|
||||
|
||||
// normalize partitions input since it can be a scalar or 1D tensor
|
||||
auto new_parts_shape = make_shared<Constant>(element::i64, Shape{1}, -1);
|
||||
auto norm_partitions = make_shared<Reshape>(partitions, new_parts_shape, true);
|
||||
auto new_parts_shape = make_shared<v0::Constant>(element::i64, Shape{1}, -1);
|
||||
auto norm_partitions = make_shared<v1::Reshape>(partitions, new_parts_shape, true);
|
||||
|
||||
// retrieve num_partitions attribute
|
||||
auto num_partitions = node.get_attribute<int64_t>("num_partitions");
|
||||
|
||||
// compute how many slices are collected for each partition
|
||||
// 1. initially assume that we collect zero slices for each partition
|
||||
auto const_zero = make_shared<Constant>(element::i64, Shape{}, 0);
|
||||
auto target_shape = make_shared<Constant>(element::i64, Shape{1}, num_partitions);
|
||||
Output<Node> split_legths = make_shared<Broadcast>(const_zero, target_shape);
|
||||
auto const_zero = make_shared<v0::Constant>(element::i64, Shape{}, 0);
|
||||
auto target_shape = make_shared<v0::Constant>(element::i64, Shape{1}, num_partitions);
|
||||
Output<Node> split_legths = make_shared<v3::Broadcast>(const_zero, target_shape);
|
||||
// 2. compute unique partition indices and their occurrences
|
||||
auto axis = make_shared<Constant>(element::i32, Shape{1}, 0);
|
||||
auto unique_partition_inds = make_shared<Unique>(partitions);
|
||||
auto axis = make_shared<v0::Constant>(element::i32, Shape{1}, 0);
|
||||
auto unique_partition_inds = make_shared<v10::Unique>(partitions);
|
||||
// 3. update split_lengths with a number of occurrences by each partition index
|
||||
split_legths = make_shared<ScatterUpdate>(split_legths,
|
||||
unique_partition_inds->output(0),
|
||||
unique_partition_inds->output(3),
|
||||
axis);
|
||||
split_legths = make_shared<v3::ScatterUpdate>(split_legths,
|
||||
unique_partition_inds->output(0),
|
||||
unique_partition_inds->output(3),
|
||||
axis);
|
||||
|
||||
// for stable sorting using TopK operation, we have to re-scale partition indices by the formula:
|
||||
// partition = partition * scale + partition_ind, where delta = max_int / num_partitions
|
||||
auto squeeze_axis = make_shared<Constant>(element::i64, Shape{1}, 0);
|
||||
Output<Node> norm_partitions_shape = make_shared<ShapeOf>(partitions, element::i32);
|
||||
norm_partitions_shape = make_shared<ConvertLike>(norm_partitions_shape, partitions);
|
||||
auto partitions_length = make_shared<Squeeze>(norm_partitions_shape, squeeze_axis);
|
||||
auto squeeze_axis = make_shared<v0::Constant>(element::i64, Shape{1}, 0);
|
||||
Output<Node> norm_partitions_shape = make_shared<v3::ShapeOf>(partitions, element::i32);
|
||||
norm_partitions_shape = make_shared<v1::ConvertLike>(norm_partitions_shape, partitions);
|
||||
auto partitions_length = make_shared<v0::Squeeze>(norm_partitions_shape, squeeze_axis);
|
||||
auto start2 = create_same_type_const_scalar<int32_t>(partitions, 0);
|
||||
auto step2 = create_same_type_const_scalar<int32_t>(partitions, 1);
|
||||
Output<Node> range_part_length = make_shared<Range>(start2, partitions_length, step2, element::i32);
|
||||
range_part_length = make_shared<ConvertLike>(range_part_length, partitions);
|
||||
Output<Node> range_part_length = make_shared<v4::Range>(start2, partitions_length, step2, element::i32);
|
||||
range_part_length = make_shared<v1::ConvertLike>(range_part_length, partitions);
|
||||
auto scale = create_same_type_const_scalar<int32_t>(
|
||||
partitions,
|
||||
std::numeric_limits<int32_t>::max() / static_cast<int32_t>(num_partitions));
|
||||
auto term = make_shared<Multiply>(norm_partitions, scale);
|
||||
auto rescaled_partitions = make_shared<Add>(term, range_part_length);
|
||||
auto term = make_shared<v1::Multiply>(norm_partitions, scale);
|
||||
auto rescaled_partitions = make_shared<v1::Add>(term, range_part_length);
|
||||
|
||||
// sort partition indices so that they are ascending
|
||||
// and sort slices of data in the same order
|
||||
auto sorted_partitions = make_shared<TopK>(rescaled_partitions,
|
||||
partitions_length,
|
||||
0,
|
||||
TopK::Mode::MIN,
|
||||
TopK::SortType::SORT_VALUES,
|
||||
element::i64);
|
||||
auto gather_axis = make_shared<Constant>(element::i64, Shape{1}, 0);
|
||||
auto sorted_data = make_shared<Gather>(data, sorted_partitions->output(1), gather_axis);
|
||||
auto sorted_partitions = make_shared<v3::TopK>(rescaled_partitions,
|
||||
partitions_length,
|
||||
0,
|
||||
v3::TopK::Mode::MIN,
|
||||
v3::TopK::SortType::SORT_VALUES,
|
||||
element::i64);
|
||||
auto gather_axis = make_shared<v0::Constant>(element::i64, Shape{1}, 0);
|
||||
auto sorted_data = make_shared<v8::Gather>(data, sorted_partitions->output(1), gather_axis);
|
||||
|
||||
// when the data is sorted appropriately we are ready to split it
|
||||
auto split_axis = make_shared<Constant>(element::i64, Shape{1}, 0);
|
||||
auto result = make_shared<VariadicSplit>(sorted_data, split_axis, split_legths);
|
||||
auto split_axis = make_shared<v0::Constant>(element::i64, Shape{1}, 0);
|
||||
auto result = make_shared<v1::VariadicSplit>(sorted_data, split_axis, split_legths);
|
||||
set_node_name(node.get_name(), result);
|
||||
return result->outputs();
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
//
|
||||
|
||||
#include "common_op_table.hpp"
|
||||
#include "openvino/opsets/opset8.hpp"
|
||||
#include "openvino/op/unsqueeze.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace ov::opset8;
|
||||
using namespace ov::op;
|
||||
|
||||
namespace ov {
|
||||
namespace frontend {
|
||||
@@ -17,7 +17,7 @@ OutputVector translate_expand_dims_op(const NodeContext& node) {
|
||||
default_op_checks(node, 2, {"ExpandDims"});
|
||||
auto input = node.get_input(0);
|
||||
auto axis = node.get_input(1);
|
||||
auto unsqueeze = make_shared<Unsqueeze>(input, axis);
|
||||
auto unsqueeze = make_shared<v0::Unsqueeze>(input, axis);
|
||||
set_node_name(node.get_name(), unsqueeze);
|
||||
return {unsqueeze};
|
||||
}
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
//
|
||||
|
||||
#include "common_op_table.hpp"
|
||||
#include "openvino/op/extractimagepatches.hpp"
|
||||
#include "openvino/op/util/attr_types.hpp"
|
||||
#include "openvino/opsets/opset8.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace ov::opset8;
|
||||
using namespace ov::op;
|
||||
|
||||
namespace ov {
|
||||
namespace frontend {
|
||||
@@ -41,7 +41,7 @@ OutputVector translate_extract_image_patches_op(const NodeContext& node) {
|
||||
// prepare input to ExtractImagePatches
|
||||
convert_nhwc_to_nchw(true, images);
|
||||
|
||||
Output<Node> extract_image_patches = make_shared<ExtractImagePatches>(images, sizes, strides, rates, auto_pad);
|
||||
Output<Node> extract_image_patches = make_shared<v3::ExtractImagePatches>(images, sizes, strides, rates, auto_pad);
|
||||
convert_nchw_to_nhwc(true, extract_image_patches);
|
||||
|
||||
set_node_name(node.get_name(), extract_image_patches.get_node_shared_ptr());
|
||||
|
||||
@@ -3,12 +3,22 @@
|
||||
//
|
||||
|
||||
#include "common_op_table.hpp"
|
||||
#include "openvino/opsets/opset10.hpp"
|
||||
#include "openvino/op/concat.hpp"
|
||||
#include "openvino/op/constant.hpp"
|
||||
#include "openvino/op/divide.hpp"
|
||||
#include "openvino/op/multiply.hpp"
|
||||
#include "openvino/op/mvn.hpp"
|
||||
#include "openvino/op/power.hpp"
|
||||
#include "openvino/op/range.hpp"
|
||||
#include "openvino/op/reduce_mean.hpp"
|
||||
#include "openvino/op/shape_of.hpp"
|
||||
#include "openvino/op/subtract.hpp"
|
||||
#include "openvino/op/unsqueeze.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace ov;
|
||||
using namespace ov::opset10;
|
||||
using namespace ov::op;
|
||||
|
||||
namespace ov {
|
||||
namespace frontend {
|
||||
@@ -16,18 +26,18 @@ namespace tensorflow {
|
||||
namespace op {
|
||||
namespace {
|
||||
void generate_axes_range_except_c(const Output<Node>& x_rank, bool is_nhwc, Output<Node>& axes_no_c) {
|
||||
auto const_one = make_shared<Constant>(element::i32, Shape{}, 1);
|
||||
auto const_one = make_shared<v0::Constant>(element::i32, Shape{}, 1);
|
||||
if (is_nhwc) {
|
||||
auto const_zero = make_shared<Constant>(element::i32, Shape{}, 0);
|
||||
auto rank_minus_one = make_shared<Subtract>(x_rank, const_one);
|
||||
axes_no_c = make_shared<Range>(const_zero, rank_minus_one, const_one, element::i32)->output(0);
|
||||
auto const_zero = make_shared<v0::Constant>(element::i32, Shape{}, 0);
|
||||
auto rank_minus_one = make_shared<v1::Subtract>(x_rank, const_one);
|
||||
axes_no_c = make_shared<v4::Range>(const_zero, rank_minus_one, const_one, element::i32)->output(0);
|
||||
} else {
|
||||
auto const_zero = make_shared<Constant>(element::i32, Shape{1}, 0);
|
||||
auto const_two = make_shared<Constant>(element::i32, Shape{}, 2);
|
||||
auto const_zero = make_shared<v0::Constant>(element::i32, Shape{1}, 0);
|
||||
auto const_two = make_shared<v0::Constant>(element::i32, Shape{}, 2);
|
||||
// in NCHW layout case
|
||||
axes_no_c = make_shared<Range>(const_two, x_rank, const_one, element::i32)->output(0);
|
||||
axes_no_c = make_shared<v4::Range>(const_two, x_rank, const_one, element::i32)->output(0);
|
||||
// add batch dimension as well
|
||||
axes_no_c = make_shared<Concat>(OutputVector{const_zero, axes_no_c}, 0);
|
||||
axes_no_c = make_shared<v0::Concat>(OutputVector{const_zero, axes_no_c}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +48,7 @@ void adjust_coeff(const Output<Node>& x_rank,
|
||||
bool is_nhwc) {
|
||||
// adjust types of the normalizing coefficients
|
||||
// they can vary for FusedBatchNormV2 and FusedBatchNormV3 operations
|
||||
adjusted_coeff = make_shared<ConvertLike>(coeff, x)->output(0);
|
||||
adjusted_coeff = make_shared<v1::ConvertLike>(coeff, x)->output(0);
|
||||
|
||||
if (is_nhwc) {
|
||||
return;
|
||||
@@ -47,12 +57,12 @@ void adjust_coeff(const Output<Node>& x_rank,
|
||||
// in case NCHW format, we need to unsqueeze the normalizing coefficient by lower dimensions
|
||||
// to have the coefficient of shape [C, 1, 1]
|
||||
// generate axes range for unsqueezing the coefficient
|
||||
auto const_one = make_shared<Constant>(element::i32, Shape{}, 1);
|
||||
auto x_rank_minus_one = make_shared<Subtract>(x_rank, const_one);
|
||||
auto axes = make_shared<Range>(const_one, x_rank_minus_one, const_one, element::i32);
|
||||
auto const_one = make_shared<v0::Constant>(element::i32, Shape{}, 1);
|
||||
auto x_rank_minus_one = make_shared<v1::Subtract>(x_rank, const_one);
|
||||
auto axes = make_shared<v4::Range>(const_one, x_rank_minus_one, const_one, element::i32);
|
||||
|
||||
// adjust shapes of the normalizing coefficients
|
||||
adjusted_coeff = make_shared<Unsqueeze>(adjusted_coeff, axes)->output(0);
|
||||
adjusted_coeff = make_shared<v0::Unsqueeze>(adjusted_coeff, axes)->output(0);
|
||||
}
|
||||
|
||||
void compute_batch_mean_and_variance(const Output<Node>& x,
|
||||
@@ -65,29 +75,29 @@ void compute_batch_mean_and_variance(const Output<Node>& x,
|
||||
generate_axes_range_except_c(x_rank, is_nhwc, reduce_axes);
|
||||
|
||||
// compute batch_mean
|
||||
batch_mean = make_shared<ReduceMean>(x, reduce_axes, false)->output(0);
|
||||
batch_mean = make_shared<v1::ReduceMean>(x, reduce_axes, false)->output(0);
|
||||
|
||||
// compute batch_variance
|
||||
auto unsqueezed_batch_mean = make_shared<Unsqueeze>(batch_mean, reduce_axes);
|
||||
batch_variance = make_shared<Subtract>(x, unsqueezed_batch_mean)->output(0);
|
||||
auto unsqueezed_batch_mean = make_shared<v0::Unsqueeze>(batch_mean, reduce_axes);
|
||||
batch_variance = make_shared<v1::Subtract>(x, unsqueezed_batch_mean)->output(0);
|
||||
auto const_two = create_same_type_const_scalar<float>(x, 2);
|
||||
batch_variance = make_shared<Power>(batch_variance, const_two);
|
||||
batch_variance = make_shared<ReduceMean>(batch_variance, reduce_axes)->output(0);
|
||||
batch_variance = make_shared<v1::Power>(batch_variance, const_two);
|
||||
batch_variance = make_shared<v1::ReduceMean>(batch_variance, reduce_axes)->output(0);
|
||||
|
||||
// for training mode, variance of FusedBatchNorm is computed with Bessel's correction
|
||||
// batch_variance must be multiplied by n / (n - 1), where n is a number of samples
|
||||
// to compute variance
|
||||
auto x_shape = make_shared<ShapeOf>(x, element::i32);
|
||||
auto gather_axis = make_shared<Constant>(element::i32, Shape{}, 0);
|
||||
auto needed_dim_values = make_shared<Gather>(x_shape, reduce_axes, gather_axis);
|
||||
auto n = make_shared<ReduceProd>(needed_dim_values, gather_axis, false)->output(0);
|
||||
n = make_shared<ConvertLike>(n, batch_variance)->output(0);
|
||||
auto x_shape = make_shared<v3::ShapeOf>(x, element::i32);
|
||||
auto gather_axis = make_shared<v0::Constant>(element::i32, Shape{}, 0);
|
||||
auto needed_dim_values = make_shared<v8::Gather>(x_shape, reduce_axes, gather_axis);
|
||||
auto n = make_shared<v1::ReduceProd>(needed_dim_values, gather_axis, false)->output(0);
|
||||
n = make_shared<v1::ConvertLike>(n, batch_variance)->output(0);
|
||||
auto const_one = create_same_type_const_scalar<float>(batch_variance, 1);
|
||||
auto bessel_correction = make_shared<Subtract>(n, const_one)->output(0);
|
||||
bessel_correction = make_shared<Divide>(n, bessel_correction);
|
||||
auto bessel_correction = make_shared<v1::Subtract>(n, const_one)->output(0);
|
||||
bessel_correction = make_shared<v1::Divide>(n, bessel_correction);
|
||||
|
||||
// adjust batch_variance by bessel correction
|
||||
batch_variance = make_shared<Multiply>(batch_variance, bessel_correction);
|
||||
batch_variance = make_shared<v1::Multiply>(batch_variance, bessel_correction);
|
||||
}
|
||||
|
||||
void compute_weighted_batch_mean_and_variance(const Output<Node>& x,
|
||||
@@ -106,14 +116,14 @@ void compute_weighted_batch_mean_and_variance(const Output<Node>& x,
|
||||
// (1 - exponential_avg_factor) * variance + exponential_avg_factor * batch_variance,
|
||||
// where batch_variance is the variance of the current batch in x.
|
||||
auto const_one = create_same_type_const_scalar<float>(exp_avg_factor_const, 1);
|
||||
auto one_minus_exp_avg_factor = make_shared<Subtract>(const_one, exp_avg_factor_const);
|
||||
auto one_minus_exp_avg_factor = make_shared<v1::Subtract>(const_one, exp_avg_factor_const);
|
||||
|
||||
// compute weighted_batch_mean
|
||||
// no need to weight in case of empty tensor mean
|
||||
if (mean.get_partial_shape().is_static() && shape_size(mean.get_shape()) > 0) {
|
||||
auto bt_mean_by_exp_avg = make_shared<Multiply>(batch_mean, exp_avg_factor_const);
|
||||
weighted_batch_mean = make_shared<Multiply>(mean, one_minus_exp_avg_factor)->output(0);
|
||||
weighted_batch_mean = make_shared<Add>(bt_mean_by_exp_avg, weighted_batch_mean);
|
||||
auto bt_mean_by_exp_avg = make_shared<v1::Multiply>(batch_mean, exp_avg_factor_const);
|
||||
weighted_batch_mean = make_shared<v1::Multiply>(mean, one_minus_exp_avg_factor)->output(0);
|
||||
weighted_batch_mean = make_shared<v1::Add>(bt_mean_by_exp_avg, weighted_batch_mean);
|
||||
} else {
|
||||
weighted_batch_mean = batch_mean;
|
||||
}
|
||||
@@ -121,9 +131,9 @@ void compute_weighted_batch_mean_and_variance(const Output<Node>& x,
|
||||
// compute weighted_batch_variance
|
||||
// no need to weight in case of empty tensor variance
|
||||
if (variance.get_partial_shape().is_static() && shape_size(variance.get_shape()) > 0) {
|
||||
auto bt_variance_by_exp_avg = make_shared<Multiply>(batch_variance, exp_avg_factor_const);
|
||||
weighted_batch_variance = make_shared<Multiply>(variance, one_minus_exp_avg_factor)->output(0);
|
||||
weighted_batch_variance = make_shared<Add>(bt_variance_by_exp_avg, weighted_batch_variance)->output(0);
|
||||
auto bt_variance_by_exp_avg = make_shared<v1::Multiply>(batch_variance, exp_avg_factor_const);
|
||||
weighted_batch_variance = make_shared<v1::Multiply>(variance, one_minus_exp_avg_factor)->output(0);
|
||||
weighted_batch_variance = make_shared<v1::Add>(bt_variance_by_exp_avg, weighted_batch_variance)->output(0);
|
||||
} else {
|
||||
weighted_batch_variance = batch_variance;
|
||||
}
|
||||
@@ -162,16 +172,16 @@ void compute_fused_batch_norm_inference(const NodeContext& node,
|
||||
|
||||
// perform the main part of the transformation
|
||||
// 1. subtract mean from the input
|
||||
auto x_minus_mean = make_shared<Subtract>(x, adjusted_mean);
|
||||
auto x_minus_mean = make_shared<v1::Subtract>(x, adjusted_mean);
|
||||
|
||||
// 2. normalize the input after the shifting
|
||||
auto var_plus_eps = make_shared<Add>(adjusted_variance, eps_const);
|
||||
auto root_sq_var = make_shared<Power>(var_plus_eps, half);
|
||||
auto normalized_x = make_shared<Divide>(x_minus_mean, root_sq_var);
|
||||
auto var_plus_eps = make_shared<v1::Add>(adjusted_variance, eps_const);
|
||||
auto root_sq_var = make_shared<v1::Power>(var_plus_eps, half);
|
||||
auto normalized_x = make_shared<v1::Divide>(x_minus_mean, root_sq_var);
|
||||
|
||||
// 3. scale the input after the normalization
|
||||
auto scaled_x = make_shared<Multiply>(normalized_x, adjusted_scale);
|
||||
fused_batch_norm = make_shared<Add>(scaled_x, adjusted_offset)->output(0);
|
||||
auto scaled_x = make_shared<v1::Multiply>(normalized_x, adjusted_scale);
|
||||
fused_batch_norm = make_shared<v1::Add>(scaled_x, adjusted_offset)->output(0);
|
||||
|
||||
// mean and variance go as outputs for batch_mean and batch_variance
|
||||
// exponential_avg_factor has no affect on it
|
||||
@@ -205,11 +215,11 @@ void compute_fused_batch_norm_training(const NodeContext& node,
|
||||
generate_axes_range_except_c(x_rank, is_nhwc, mvn_axes);
|
||||
|
||||
// perform mean-variance normalization
|
||||
auto mvn = make_shared<MVN>(x, mvn_axes, true, epsilon, ov::op::MVNEpsMode::INSIDE_SQRT);
|
||||
auto mvn = make_shared<v6::MVN>(x, mvn_axes, true, epsilon, ov::op::MVNEpsMode::INSIDE_SQRT);
|
||||
|
||||
// perform scaling and shifting
|
||||
fused_batch_norm = make_shared<Multiply>(mvn, adjusted_scale)->output(0);
|
||||
fused_batch_norm = make_shared<Add>(fused_batch_norm, adjusted_offset)->output(0);
|
||||
fused_batch_norm = make_shared<v1::Multiply>(mvn, adjusted_scale)->output(0);
|
||||
fused_batch_norm = make_shared<v1::Add>(fused_batch_norm, adjusted_offset)->output(0);
|
||||
|
||||
// compute two other outputs: batch_mean and batch_variance
|
||||
compute_batch_mean_and_variance(x, x_rank, is_nhwc, batch_mean, batch_variance);
|
||||
|
||||
@@ -2,11 +2,14 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
#include "openvino/op/gather.hpp"
|
||||
|
||||
#include "common_op_table.hpp"
|
||||
#include "openvino/opsets/opset8.hpp"
|
||||
#include "openvino/op/constant.hpp"
|
||||
#include "openvino/op/gather_nd.hpp"
|
||||
|
||||
using namespace std;
|
||||
using namespace ov::opset8;
|
||||
using namespace ov::op;
|
||||
|
||||
namespace ov {
|
||||
namespace frontend {
|
||||
@@ -17,7 +20,7 @@ OutputVector translate_basic_gather_op(const NodeContext& node, const ov::Output
|
||||
TENSORFLOW_OP_VALIDATION(node, node.get_input_size() >= 2, op_type + " must have at least two inputs.");
|
||||
auto params = node.get_input(0);
|
||||
auto indices = node.get_input(1);
|
||||
auto gather = make_shared<Gather>(params, indices, axis, batch_dims);
|
||||
auto gather = make_shared<v8::Gather>(params, indices, axis, batch_dims);
|
||||
set_node_name(node.get_name(), gather);
|
||||
return {gather};
|
||||
}
|
||||
@@ -26,7 +29,7 @@ OutputVector translate_gather_op(const NodeContext& node) {
|
||||
// Gather has two inputs: data and indices
|
||||
// axis by which data is sliced is always equal to 0, batch_dims is always equal to 0
|
||||
default_op_checks(node, 2, {"Gather"});
|
||||
auto axis = make_shared<Constant>(element::i64, Shape{}, 0);
|
||||
auto axis = make_shared<v0::Constant>(element::i64, Shape{}, 0);
|
||||
return translate_basic_gather_op(node, axis, 0);
|
||||
}
|
||||
|
||||
@@ -34,7 +37,7 @@ OutputVector translate_resource_gather_op(const NodeContext& node) {
|
||||
// ResourceGather has two inputs: data and indices
|
||||
// axis by which data is sliced is always equal to 0, batch_dims is an attribute and can vary
|
||||
default_op_checks(node, 2, {"ResourceGather"});
|
||||
auto axis = make_shared<Constant>(element::i64, Shape{}, 0);
|
||||
auto axis = make_shared<v0::Constant>(element::i64, Shape{}, 0);
|
||||
auto batch_dims = node.get_attribute<int64_t>("batch_dims", 0);
|
||||
return translate_basic_gather_op(node, axis, batch_dims);
|
||||
}
|
||||
@@ -55,7 +58,7 @@ OutputVector translate_gather_nd_op(const NodeContext& node) {
|
||||
auto input = node.get_input(0);
|
||||
auto input_indices = node.get_input(1);
|
||||
auto batch_dims = node.get_attribute<int64_t>("batch_dims", 0);
|
||||
auto gather_nd = make_shared<GatherND>(input, input_indices, batch_dims);
|
||||
auto gather_nd = make_shared<v8::GatherND>(input, input_indices, batch_dims);
|
||||
set_node_name(node.get_name(), gather_nd);
|
||||
return {gather_nd};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user