[LPT] integration branch: Reshape fix, Concat generalization, runtime info usage...
[platform/upstream/dldt.git] / inference-engine / tests / ngraph_functions / src / low_precision_transformations / concat_function.cpp
1 // Copyright (C) 2020 Intel Corporation
2 // SPDX-License-Identifier: Apache-2.0
3 //
4
5 #include "ngraph_functions/low_precision_transformations/concat_function.hpp"
6
7 #include <ngraph/opsets/opset1.hpp>
8 #include "ngraph_ops/type_relaxed.hpp"
9 #include "low_precision/network_helper.hpp"
10
11 #include "ngraph_functions/subgraph_builders.hpp"
12 #include "ngraph_functions/low_precision_transformations/common/fake_quantize_on_data.hpp"
13 #include "ngraph_functions/low_precision_transformations/common/dequantization_operations.hpp"
14 #include "ngraph_functions/low_precision_transformations/common/builders.hpp"
15
16 namespace ngraph {
17 namespace builder {
18 namespace subgraph {
19
20 using namespace ngraph::pass;
21
22 std::shared_ptr<ngraph::Function> ConcatFunction::getOriginal(
23     const ngraph::element::Type precision,
24     const ngraph::Shape& inputShape,
25     const FakeQuantizeOnData& fqOnData1,
26     const FakeQuantizeOnData& fqOnData2) {
27     const auto input1 = std::make_shared<ngraph::opset1::Parameter>(precision, inputShape);
28     input1->set_friendly_name("input1");
29     const auto fakeQuantize1 = makeFakeQuantize(input1, precision, fqOnData1);
30
31     const std::vector<size_t> inputShape2 = inputShape;
32     const auto input2 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape2));
33     input2->set_friendly_name("input2");
34     const auto fakeQuantize2 = makeFakeQuantize(input2, precision, fqOnData2);
35
36     const std::shared_ptr<ngraph::opset1::Concat> concat = std::make_shared<ngraph::opset1::Concat>(
37         ngraph::OutputVector{ fakeQuantize1->output(0), fakeQuantize2->output(0) }, 1);
38     concat->set_friendly_name("output");
39     auto& rtInfo = concat->get_rt_info();
40     rtInfo["Variant::std::string"] = std::make_shared<VariantWrapper<std::string>>("concat");
41
42     ngraph::ResultVector results{ std::make_shared<ngraph::opset1::Result>(concat) };
43     std::shared_ptr<ngraph::Function> function = std::make_shared<ngraph::Function>(
44         results,
45         ngraph::ParameterVector{ input1, input2 },
46         "ConcatTransformation");
47
48     return function;
49 }
50
51 std::shared_ptr<ngraph::Function> ConcatFunction::getOriginal(
52     const ngraph::element::Type precision,
53     const ngraph::Shape& inputShape,
54     const FakeQuantizeOnDataWithConstant& fqOnData1,
55     const FakeQuantizeOnDataWithConstant& fqOnData2) {
56     const auto input1 = std::make_shared<ngraph::opset1::Parameter>(precision, inputShape);
57     input1->set_friendly_name("input1");
58     const auto fakeQuantize1 = makeFakeQuantize(input1, precision, fqOnData1);
59
60     const std::vector<size_t> inputShape2 = inputShape;
61     const auto input2 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape2));
62     input2->set_friendly_name("input2");
63     const auto fakeQuantize2 = makeFakeQuantize(input2, precision, fqOnData2);
64
65     const std::shared_ptr<ngraph::opset1::Concat> concat = std::make_shared<ngraph::opset1::Concat>(
66         ngraph::OutputVector{ fakeQuantize1->output(0), fakeQuantize2->output(0) }, 1);
67     concat->set_friendly_name("output");
68
69     auto& rtInfo = concat->get_rt_info();
70     rtInfo["Variant::std::string"] = std::make_shared<VariantWrapper<std::string>>("concat");
71
72     ngraph::ResultVector results{ std::make_shared<ngraph::opset1::Result>(concat) };
73     std::shared_ptr<ngraph::Function> function = std::make_shared<ngraph::Function>(
74         results,
75         ngraph::ParameterVector{ input1, input2 },
76         "ConcatTransformation");
77
78     return function;
79 }
80
81 std::shared_ptr<ngraph::Function> ConcatFunction::getOriginalWithNeighbors(
82     const ngraph::element::Type precision,
83     const ngraph::Shape& inputShape,
84     const FakeQuantizeOnData& fqOnData1,
85     const FakeQuantizeOnData& fqOnData2,
86     const FakeQuantizeOnData& fqOnData3) {
87     const auto input1 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape));
88     input1->set_friendly_name("input1");
89     const auto fakeQuantize1 = makeFakeQuantize(input1, precision, fqOnData1);
90     fakeQuantize1->set_friendly_name("fakeQuantize1");
91
92     const auto input2 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape));
93     input2->set_friendly_name("input2");
94     const auto fakeQuantize2 = makeFakeQuantize(input2, precision, fqOnData2);
95     fakeQuantize2->set_friendly_name("fakeQuantize2");
96
97     const auto input3 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape));
98     input3->set_friendly_name("input3");
99     const auto fakeQuantize3 = makeFakeQuantize(input3, precision, fqOnData3);
100     fakeQuantize3->set_friendly_name("fakeQuantize3");
101
102     const auto concat1 = std::make_shared<ngraph::opset1::Concat>(
103         ngraph::OutputVector { fakeQuantize1->output(0), fakeQuantize2->output(0) },
104         1ull);
105     concat1->set_friendly_name("concat1");
106
107     auto& rtInfo1 = concat1->get_rt_info();
108     rtInfo1["Variant::std::string"] = std::make_shared<VariantWrapper<std::string>>("concat1");
109
110     const auto concat2 = std::make_shared<ngraph::opset1::Concat>(
111         ngraph::OutputVector { fakeQuantize2->output(0), fakeQuantize3->output(0) },
112         1ull);
113     concat2->set_friendly_name("concat2");
114
115     auto& rtInfo2 = concat2->get_rt_info();
116     rtInfo2["Variant::std::string"] = std::make_shared<VariantWrapper<std::string>>("concat2");
117
118     const ngraph::ResultVector results {
119         std::make_shared<ngraph::opset1::Result>(concat1),
120         std::make_shared<ngraph::opset1::Result>(concat2)
121     };
122
123     std::shared_ptr<ngraph::Function> function = std::make_shared<ngraph::Function>(
124         results,
125         ngraph::ParameterVector { input1, input2, input3 },
126         "ConcatWithNeighborsTransformation");
127
128     return function;
129 }
130
131 std::shared_ptr<ngraph::Function> ConcatFunction::getOriginalWithIntermediate(
132     const ngraph::element::Type precision,
133     const ngraph::Shape& inputShape,
134     const bool transparentIntermediate,
135     const FakeQuantizeOnData& fqOnData1,
136     const FakeQuantizeOnData& fqOnData2) {
137     const std::vector<size_t> inputShape1 = {
138         inputShape[0],
139         inputShape[1],
140         inputShape[2] - (transparentIntermediate ? 2 : 0),
141         inputShape[3] - (transparentIntermediate ? 2 : 0)
142     };
143
144     const auto input1 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape1));
145     input1->set_friendly_name("input1");
146     const auto fakeQuantize1 = makeFakeQuantize(input1, precision, fqOnData1);
147     fakeQuantize1->set_friendly_name("fakeQuantize1");
148
149     const std::vector<size_t> inputShape2 = { inputShape[0], inputShape[1], inputShape[2], inputShape[3] };
150     const auto input2 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape2));
151     input2->set_friendly_name("input2");
152
153     const auto fakeQuantize2 = makeFakeQuantize(input2, precision, fqOnData2);
154     fakeQuantize2->set_friendly_name("fakeQuantize2");
155
156     const std::vector<size_t> kernel = { 3, 3 };
157     const std::vector<size_t> stride = { 1, 1 };
158     const std::vector<size_t> padBegin = { 0, 0 };
159     const std::vector<size_t> padEnd = { 0, 0 };
160     const ngraph::op::PadType padType = ngraph::op::PadType::NOTSET;
161     const ngraph::op::RoundingType roundingType = ngraph::op::RoundingType::FLOOR;
162     std::shared_ptr<ngraph::op::Op> intermediateOp;
163
164     if (transparentIntermediate) {
165         intermediateOp = std::make_shared<ngraph::opset1::MaxPool>(
166             fakeQuantize2->output(0),
167             stride,
168             padBegin,
169             padEnd,
170             kernel,
171             roundingType,
172             padType);
173     } else {
174         auto weights = ngraph::opset1::Constant::create(
175             precision,
176             ngraph::Shape{ inputShape[1], inputShape[1], 1, 1 },
177             std::vector<float>(inputShape[1] * inputShape[1], 1));
178
179         intermediateOp = std::make_shared<ngraph::opset1::Convolution>(
180             fakeQuantize2->output(0),
181             weights,
182             ngraph::Strides{ 1, 1 },
183             ngraph::CoordinateDiff{ 0, 0 },
184             ngraph::CoordinateDiff{ 0, 0 },
185             ngraph::Strides{ 1, 1 });
186     }
187
188     intermediateOp->set_friendly_name("intermediate");
189
190     const std::shared_ptr<ngraph::opset1::Concat> concat = std::make_shared<ngraph::opset1::Concat>(
191         ngraph::OutputVector{ fakeQuantize1->output(0), intermediateOp->output(0) }, 1);
192     concat->set_friendly_name("concat");
193
194     auto& rtInfo = concat->get_rt_info();
195     rtInfo["Variant::std::string"] = std::make_shared<VariantWrapper<std::string>>("concat");
196
197     auto weights = ngraph::opset1::Constant::create(precision, ngraph::Shape{ inputShape[1], inputShape[1], 1, 1 }, { 1 });
198     auto convolution = std::make_shared<ngraph::opset1::Convolution>(
199         intermediateOp,
200         weights,
201         ngraph::Strides { 1, 1 },
202         ngraph::CoordinateDiff { 0, 0 },
203         ngraph::CoordinateDiff { 0, 0 },
204         ngraph::Strides { 1, 1 });
205     convolution->set_friendly_name("convolution");
206
207     ngraph::ResultVector results {
208         std::make_shared<ngraph::opset1::Result>(concat),
209         std::make_shared<ngraph::opset1::Result>(convolution)
210     };
211
212     std::shared_ptr<ngraph::Function> function = std::make_shared<ngraph::Function>(
213         results,
214         ngraph::ParameterVector{ input1, input2 },
215         "ConcatWithIntermediateTransformation");
216
217     return function;
218 }
219
220 std::shared_ptr<ngraph::Function> ConcatFunction::getOriginalWithSplitedIntermediate(
221     const ngraph::element::Type precision,
222     const ngraph::Shape& inputShape,
223     const FakeQuantizeOnData& fqOnData1,
224     const FakeQuantizeOnData& fqOnData2) {
225     size_t numSplit = 2;
226     size_t splitedAxis = 1;
227
228
229     const std::vector<size_t> inputShape1 = {
230         inputShape[0],
231         inputShape[1] / numSplit,
232         inputShape[2],
233         inputShape[3]
234     };
235
236     const auto input1 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape1));
237     input1->set_friendly_name("input1");
238     const auto fakeQuantize1 = makeFakeQuantize(input1, precision, fqOnData1);
239     fakeQuantize1->set_friendly_name("fakeQuantize1");
240
241     const std::vector<size_t> inputShape2 = { inputShape[0], inputShape[1], inputShape[2], inputShape[3] };
242     const auto input2 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape2));
243     input2->set_friendly_name("input2");
244
245     const auto fakeQuantize2 = makeFakeQuantize(input2, precision, fqOnData2);
246     fakeQuantize2->set_friendly_name("fakeQuantize2");
247
248     std::shared_ptr<ngraph::op::Op> intermediateOp;
249
250     const auto constant = std::make_shared<ngraph::opset1::Constant>(element::i64, Shape{ }, splitedAxis);
251     intermediateOp = std::make_shared<ngraph::opset1::Split>(fakeQuantize2->output(0), constant, numSplit);
252
253     intermediateOp->set_friendly_name("intermediate");
254
255     const std::shared_ptr<ngraph::opset1::Concat> concat = std::make_shared<ngraph::opset1::Concat>(
256         ngraph::OutputVector{ fakeQuantize1->output(0), intermediateOp->output(0) }, splitedAxis);
257     concat->set_friendly_name("concat");
258
259     auto& rtInfo = concat->get_rt_info();
260     rtInfo["Variant::std::string"] = std::make_shared<VariantWrapper<std::string>>("concat");
261
262     auto weights = ngraph::opset1::Constant::create(precision, ngraph::Shape{ inputShape[1] / numSplit, inputShape[1] / numSplit, 1, 1 }, { 1 });
263     auto convolution = std::make_shared<ngraph::opset1::Convolution>(
264         intermediateOp->output(1),
265         weights,
266         ngraph::Strides{ 1, 1 },
267         ngraph::CoordinateDiff{ 0, 0 },
268         ngraph::CoordinateDiff{ 0, 0 },
269         ngraph::Strides{ 1, 1 });
270     convolution->set_friendly_name("convolution");
271
272     ngraph::ResultVector results{
273         std::make_shared<ngraph::opset1::Result>(concat),
274         std::make_shared<ngraph::opset1::Result>(convolution),
275     };
276
277     std::shared_ptr<ngraph::Function> function = std::make_shared<ngraph::Function>(
278         results,
279         ngraph::ParameterVector{ input1, input2 },
280         "ConcatWithIntermediateTransformation");
281
282     return function;
283 }
284
285 std::shared_ptr<ngraph::Function> ConcatFunction::getOriginalSelectionWithIntermediate(
286     const ngraph::element::Type precision,
287     const ngraph::Shape& inputShape,
288     const bool transparentIntermediate,
289     const FakeQuantizeOnData& fqOnData1,
290     const FakeQuantizeOnData& fqOnData2) {
291     const std::vector<size_t> inputShape1 = {
292         inputShape[0],
293         inputShape[1],
294         inputShape[2] - (transparentIntermediate ? 2 : 0),
295         inputShape[3] - (transparentIntermediate ? 2 : 0)
296     };
297
298     const auto input1 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape1));
299     input1->set_friendly_name("input1");
300     const auto fakeQuantize1 = makeFakeQuantize(input1, precision, fqOnData1);
301     fakeQuantize1->set_friendly_name("fakeQuantize1");
302
303     const std::vector<size_t> inputShape2 = { inputShape[0], inputShape[1], inputShape[2], inputShape[3] };
304     const auto input2 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape2));
305     input2->set_friendly_name("input2");
306
307     const auto fakeQuantize2 = makeFakeQuantize(input2, precision, fqOnData2);
308     fakeQuantize2->set_friendly_name("fakeQuantize2");
309
310     const std::vector<size_t> kernel = { 3, 3 };
311     const std::vector<size_t> stride = { 1, 1 };
312     const std::vector<size_t> padBegin = { 0, 0 };
313     const std::vector<size_t> padEnd = { 0, 0 };
314     const ngraph::op::PadType padType = ngraph::op::PadType::NOTSET;
315     const ngraph::op::RoundingType roundingType = ngraph::op::RoundingType::FLOOR;
316     std::shared_ptr<ngraph::op::Op> intermediateOp;
317
318     if (transparentIntermediate) {
319         intermediateOp = std::make_shared<ngraph::opset1::MaxPool>(
320             fakeQuantize2->output(0),
321             stride,
322             padBegin,
323             padEnd,
324             kernel,
325             roundingType,
326             padType);
327     } else {
328         auto weights = ngraph::opset1::Constant::create(
329             precision,
330             ngraph::Shape{ inputShape[1], inputShape[1], 1, 1 },
331             std::vector<float>(inputShape[1] * inputShape[1], 1));
332
333         intermediateOp = std::make_shared<ngraph::opset1::Convolution>(
334             fakeQuantize2->output(0),
335             weights,
336             ngraph::Strides{ 1, 1 },
337             ngraph::CoordinateDiff{ 0, 0 },
338             ngraph::CoordinateDiff{ 0, 0 },
339             ngraph::Strides{ 1, 1 });
340     }
341
342     intermediateOp->set_friendly_name("intermediate");
343
344     const std::shared_ptr<ngraph::opset1::Concat> concat = std::make_shared<ngraph::opset1::Concat>(
345         ngraph::OutputVector{ fakeQuantize1->output(0), intermediateOp->output(0) }, 1);
346     concat->set_friendly_name("concat");
347
348     auto& rtInfo = concat->get_rt_info();
349     rtInfo["Variant::std::string"] = std::make_shared<VariantWrapper<std::string>>("concat");
350
351     auto weights = ngraph::opset1::Constant::create(precision, ngraph::Shape{ inputShape[1], inputShape[1], 1, 1 }, { 1 });
352     auto convolution = std::make_shared<ngraph::opset1::Convolution>(
353         intermediateOp,
354         weights,
355         ngraph::Strides { 1, 1 },
356         ngraph::CoordinateDiff { 0, 0 },
357         ngraph::CoordinateDiff { 0, 0 },
358         ngraph::Strides { 1, 1 });
359     convolution->set_friendly_name("convolution");
360
361     ngraph::ResultVector results {
362         std::make_shared<ngraph::opset1::Result>(concat),
363         std::make_shared<ngraph::opset1::Result>(convolution)
364     };
365
366     std::shared_ptr<ngraph::Function> function = std::make_shared<ngraph::Function>(
367         results,
368         ngraph::ParameterVector{ input1, input2 },
369         "ConcatWithIntermediateTransformation");
370
371     return function;
372 }
373
374 std::shared_ptr<ngraph::Function> ConcatFunction::getOriginalWithDifferentPrecisionOnChilds(
375     const ngraph::element::Type precision,
376     const ngraph::Shape& inputShape,
377     const FakeQuantizeOnData& fqOnData1,
378     const FakeQuantizeOnData& fqOnData2) {
379     const auto input1 = std::make_shared<ngraph::opset1::Parameter>(precision, inputShape);
380     input1->set_friendly_name("input1");
381     const auto fakeQuantize1 = makeFakeQuantize(input1, precision, fqOnData1);
382
383     const std::vector<size_t> inputShape2 = inputShape;
384     const auto input2 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape2));
385     input2->set_friendly_name("input2");
386     const auto fakeQuantize2 = makeFakeQuantize(input2, precision, fqOnData2);
387
388     const std::shared_ptr<ngraph::opset1::Concat> concat = std::make_shared<ngraph::opset1::Concat>(
389         ngraph::OutputVector{ fakeQuantize1->output(0), fakeQuantize2->output(0) }, 1);
390
391     auto& rtInfo = concat->get_rt_info();
392     rtInfo["Variant::std::string"] = std::make_shared<VariantWrapper<std::string>>("concat");
393
394     const std::vector<size_t> kernel = { 3, 3 };
395     const std::vector<size_t> stride = { 1, 1 };
396     const std::vector<size_t> padBegin = { 0, 0 };
397     const std::vector<size_t> padEnd = { 0, 0 };
398     const ngraph::op::PadType padType = ngraph::op::PadType::NOTSET;
399     const ngraph::op::RoundingType roundingType = ngraph::op::RoundingType::FLOOR;
400
401     const auto avgPool = std::make_shared<ngraph::opset1::AvgPool>(
402         concat->output(0),
403         stride,
404         padBegin,
405         padEnd,
406         kernel,
407         true,
408         roundingType,
409         padType);
410     avgPool->set_friendly_name("AvgPool");
411
412     const auto maxPool = std::make_shared<ngraph::opset1::MaxPool>(
413         concat->output(0),
414         stride,
415         padBegin,
416         padEnd,
417         kernel,
418         roundingType,
419         padType);
420     maxPool->set_friendly_name("MaxPool");
421
422     ngraph::ResultVector results;
423     results.push_back(std::make_shared<ngraph::opset1::Result>(avgPool));
424     results.push_back(std::make_shared<ngraph::opset1::Result>(maxPool));
425
426     std::shared_ptr<ngraph::Function> function = std::make_shared<ngraph::Function>(
427         results,
428         ngraph::ParameterVector{ input1, input2 },
429         "ConcatWithDifferentChildsTransformation");
430
431     return function;
432 }
433
434 std::shared_ptr<ngraph::Function> ConcatFunction::getOriginalWithIntermediateWithConstant(
435     const ngraph::element::Type precision,
436     const ngraph::Shape& inputShape,
437     const bool transparentIntermediate,
438     const FakeQuantizeOnData& fqOnData1,
439     const FakeQuantizeOnData& fqOnData2) {
440     const auto input1 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape));
441     input1->set_friendly_name("input");
442     const auto fakeQuantize1 = makeFakeQuantizeTypeRelaxed(input1, precision, fqOnData1);
443     fakeQuantize1->set_friendly_name("fakeQuantize1");
444
445     const auto input2 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape));
446     input2->set_friendly_name("input");
447     const auto fakeQuantize2 = makeFakeQuantizeTypeRelaxed(input2, precision, fqOnData2);
448     fakeQuantize2->set_friendly_name("fakeQuantize2");
449
450
451     std::shared_ptr<ngraph::op::Op> intermediateOp;
452
453     if (transparentIntermediate) {
454         const std::vector<size_t> kernel = { 3, 3 };
455         const std::vector<size_t> stride = { 1, 1 };
456         const std::vector<size_t> padBegin = { 0, 0 };
457         const std::vector<size_t> padEnd = { 0, 0 };
458         const ngraph::op::PadType padType = ngraph::op::PadType::NOTSET;
459         const ngraph::op::RoundingType roundingType = ngraph::op::RoundingType::FLOOR;
460
461         const auto pooling = std::make_shared<ngraph::opset1::MaxPool>(
462             fakeQuantize1->output(0),
463             stride,
464             padBegin,
465             padEnd,
466             kernel,
467             roundingType,
468             padType);
469
470         ngraph::op::v0::InterpolateAttrs attributes;
471         attributes.axes = ngraph::AxisSet{ 2, 3 };
472         attributes.mode = "nearest";
473         attributes.align_corners = false;
474         attributes.antialias = false;
475         attributes.pads_begin = { 0 };
476         attributes.pads_end = { 0 };
477         const auto outputShape = op::Constant::create(
478             ngraph::element::i64, ngraph::Shape{ 2 },
479             ngraph::Shape{ inputShape[2], inputShape[3] });
480         intermediateOp = std::make_shared<ngraph::opset1::Interpolate>(pooling->output(0), outputShape, attributes);
481         intermediateOp->set_friendly_name("intermediate");
482     } else {
483         intermediateOp = fakeQuantize1;
484     }
485
486     const std::shared_ptr<ngraph::opset1::Concat> concat = std::make_shared<ngraph::opset1::Concat>(
487         ngraph::OutputVector{ fakeQuantize2->output(0), intermediateOp->output(0) }, 1);
488     concat->set_friendly_name("concat");
489
490     auto& rtInfo = concat->get_rt_info();
491     rtInfo["Variant::std::string"] = std::make_shared<VariantWrapper<std::string>>("concat");
492
493     ngraph::ResultVector results{
494         std::make_shared<ngraph::opset1::Result>(concat),
495     };
496
497     std::shared_ptr<ngraph::Function> function = std::make_shared<ngraph::Function>(
498         results,
499         ngraph::ParameterVector{ input1, input2 },
500         "ConcatWithIntermediateWithConstantTransformation");
501
502     return function;
503 }
504
505 std::shared_ptr<ngraph::Function> ConcatFunction::getReference(
506     const ngraph::element::Type precision,
507     const ngraph::Shape& inputShape,
508     const FakeQuantizeOnData& fqOnData1,
509     const FakeQuantizeOnData& fqOnData2,
510     const DequantizationOperations& dequantizationOperations) {
511     const auto input1 = std::make_shared<ngraph::opset1::Parameter>(precision, inputShape);
512     input1->set_friendly_name("input1");
513     const auto fakeQuantize1 = ngraph::builder::subgraph::makeFakeQuantizeTypeRelaxed(input1, precision, fqOnData1);
514
515     const std::vector<size_t> inputShape2 = inputShape;
516     const auto input2 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape2));
517     input2->set_friendly_name("input2");
518     const auto fakeQuantize2 = ngraph::builder::subgraph::makeFakeQuantizeTypeRelaxed(input2, precision, fqOnData2);
519
520     const std::shared_ptr<ngraph::opset1::Concat> concat = std::make_shared<ngraph::op::TypeRelaxed<ngraph::opset1::Concat>>(
521         ngraph::OutputVector{ fakeQuantize1->output(0), fakeQuantize2->output(0) }, 1);
522     auto& rtInfo = concat->get_rt_info();
523     rtInfo["Variant::std::string"] = std::make_shared<VariantWrapper<std::string>>("concat");
524
525     const std::shared_ptr<ngraph::Node> lastDequantization = makeDequantization(concat, dequantizationOperations);
526     lastDequantization->set_friendly_name("output");
527
528     ngraph::ResultVector results{ std::make_shared<ngraph::opset1::Result>(lastDequantization) };
529     std::shared_ptr<ngraph::Function> function = std::make_shared<ngraph::Function>(
530         results,
531         ngraph::ParameterVector{ input1, input2 },
532         "ConcatTransformation");
533
534     if (fqOnData1.outputPrecision != fqOnData2.outputPrecision) {
535         THROW_IE_EXCEPTION << "FakeQuantize expected precisions are different";
536     }
537     const ngraph::element::Type fqOnDataPrecision = fqOnData1.outputPrecision;
538     if (fqOnDataPrecision != ngraph::element::undefined) {
539         if (fakeQuantize1->get_output_element_type(0) != fakeQuantize2->get_output_element_type(0)) {
540             THROW_IE_EXCEPTION << "FakeQuantize operation precisions are different";
541         }
542         const ngraph::element::Type fakeQuantizePrecision = fakeQuantize1->get_output_element_type(0);
543
544         if (fqOnDataPrecision != fakeQuantizePrecision) {
545             ngraph::pass::low_precision::NetworkHelper::setOutDataPrecision(fakeQuantize1, fqOnDataPrecision);
546             ngraph::pass::low_precision::NetworkHelper::setOutDataPrecision(fakeQuantize2, fqOnDataPrecision);
547             ngraph::pass::low_precision::NetworkHelper::setOutDataPrecision(concat, fqOnDataPrecision);
548         }
549     }
550
551     return function;
552 }
553
554 std::shared_ptr<ngraph::Function> ConcatFunction::getReference(
555     const ngraph::element::Type precision,
556     const ngraph::Shape& inputShape,
557     const FakeQuantizeOnDataWithConstant& fqOnData1,
558     const FakeQuantizeOnDataWithConstant& fqOnData2,
559     const DequantizationOperations& dequantizationOperations) {
560     const auto input1 = std::make_shared<ngraph::opset1::Parameter>(precision, inputShape);
561     input1->set_friendly_name("input1");
562     const auto fakeQuantize1 = ngraph::builder::subgraph::makeFakeQuantizeTypeRelaxed(input1, precision, fqOnData1);
563
564     const std::vector<size_t> inputShape2 = inputShape;
565     const auto input2 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape2));
566     input2->set_friendly_name("input2");
567     const auto fakeQuantize2 = ngraph::builder::subgraph::makeFakeQuantizeTypeRelaxed(input2, precision, fqOnData2);
568
569     const std::shared_ptr<ngraph::opset1::Concat> concat = std::make_shared<ngraph::op::TypeRelaxed<ngraph::opset1::Concat>>(
570         ngraph::OutputVector{ fakeQuantize1->output(0), fakeQuantize2->output(0) }, 1);
571
572     auto& rtInfo = concat->get_rt_info();
573     rtInfo["Variant::std::string"] = std::make_shared<VariantWrapper<std::string>>("concat");
574
575     const std::shared_ptr<ngraph::Node> lastDequantization = makeDequantization(concat, dequantizationOperations);
576     lastDequantization->set_friendly_name("output");
577
578     ngraph::ResultVector results{ std::make_shared<ngraph::opset1::Result>(lastDequantization) };
579     std::shared_ptr<ngraph::Function> function = std::make_shared<ngraph::Function>(
580         results,
581         ngraph::ParameterVector{ input1, input2 },
582         "ConcatTransformation");
583
584     if (fqOnData1.outputPrecision != fqOnData2.outputPrecision) {
585         THROW_IE_EXCEPTION << "FakeQuantize expected precisions are different";
586     }
587     const ngraph::element::Type fqOnDataPrecision = fqOnData1.outputPrecision;
588     if (fqOnDataPrecision != ngraph::element::undefined) {
589         if (fakeQuantize1->get_output_element_type(0) != fakeQuantize2->get_output_element_type(0)) {
590             THROW_IE_EXCEPTION << "FakeQuantize operation precisions are different";
591         }
592         const ngraph::element::Type fakeQuantizePrecision = fakeQuantize1->get_output_element_type(0);
593
594         if (fqOnDataPrecision != fakeQuantizePrecision) {
595             ngraph::pass::low_precision::NetworkHelper::setOutDataPrecision(fakeQuantize1, fqOnDataPrecision);
596             ngraph::pass::low_precision::NetworkHelper::setOutDataPrecision(fakeQuantize2, fqOnDataPrecision);
597             ngraph::pass::low_precision::NetworkHelper::setOutDataPrecision(concat, fqOnDataPrecision);
598         }
599     }
600
601     return function;
602 }
603
604 std::shared_ptr<ngraph::Function> ConcatFunction::getReferenceWithNeighbors(
605     const ngraph::element::Type precision,
606     const ngraph::Shape& inputShape,
607     const FakeQuantizeOnData& fqOnData1,
608     const FakeQuantizeOnData& fqOnData2,
609     const FakeQuantizeOnData& fqOnData3,
610     const DequantizationOperations& dequantizationOperations1,
611     const DequantizationOperations& dequantizationOperations2) {
612     const auto input1 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape));
613     input1->set_friendly_name("input1");
614     const auto fakeQuantize1 = makeFakeQuantizeTypeRelaxed(input1, precision, fqOnData1);
615     fakeQuantize1->set_friendly_name("fakeQuantize1");
616
617     const auto input2 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape));
618     input2->set_friendly_name("input2");
619     const auto fakeQuantize2 = makeFakeQuantizeTypeRelaxed(input2, precision, fqOnData2);
620     fakeQuantize2->set_friendly_name("fakeQuantize2");
621
622     const auto input3 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape));
623     input3->set_friendly_name("input3");
624     const auto fakeQuantize3 = makeFakeQuantizeTypeRelaxed(input3, precision, fqOnData3);
625     fakeQuantize3->set_friendly_name("fakeQuantize3");
626
627     const auto concat1 = std::make_shared<ngraph::opset1::Concat>(
628         ngraph::OutputVector { fakeQuantize1->output(0), fakeQuantize2->output(0) },
629         1ull);
630     concat1->set_friendly_name("concat1");
631
632     auto& rtInfo1 = concat1->get_rt_info();
633     rtInfo1["Variant::std::string"] = std::make_shared<VariantWrapper<std::string>>("concat1");
634
635     const auto concat2 = std::make_shared<ngraph::opset1::Concat>(
636         ngraph::OutputVector { fakeQuantize2->output(0), fakeQuantize3->output(0) },
637         1ull);
638     concat2->set_friendly_name("concat2");
639
640     auto& rtInfo2 = concat2->get_rt_info();
641     rtInfo2["Variant::std::string"] = std::make_shared<VariantWrapper<std::string>>("concat2");
642
643     const std::shared_ptr<ngraph::Node> lastDequantization1 = makeDequantization(concat1, dequantizationOperations1);
644     lastDequantization1->set_friendly_name("concat1");
645
646     const std::shared_ptr<ngraph::Node> lastDequantization2 = makeDequantization(concat2, dequantizationOperations2);
647     lastDequantization2->set_friendly_name("concat2");
648
649     const ngraph::ResultVector results {
650         std::make_shared<ngraph::opset1::Result>(lastDequantization1),
651         std::make_shared<ngraph::opset1::Result>(lastDequantization2)
652     };
653
654     std::shared_ptr<ngraph::Function> function = std::make_shared<ngraph::Function>(
655         results,
656         ngraph::ParameterVector { input1, input2, input3 },
657         "ConcatWithNeighborsTransformation");
658
659     if ((fqOnData1.outputPrecision != fqOnData2.outputPrecision) || (fqOnData2.outputPrecision != fqOnData3.outputPrecision)) {
660         THROW_IE_EXCEPTION << "FakeQuantize expected precisions are different";
661     }
662     const ngraph::element::Type fqOnDataPrecision = fqOnData1.outputPrecision;
663     if (fqOnDataPrecision != ngraph::element::undefined) {
664         if ((fakeQuantize1->get_output_element_type(0) != fakeQuantize2->get_output_element_type(0)) ||
665             (fakeQuantize2->get_output_element_type(0) != fakeQuantize3->get_output_element_type(0))) {
666             THROW_IE_EXCEPTION << "FakeQuantize operation precisions are different";
667         }
668         const ngraph::element::Type fakeQuantizePrecision = fakeQuantize1->get_output_element_type(0);
669
670         if (fqOnDataPrecision != fakeQuantizePrecision) {
671             ngraph::pass::low_precision::NetworkHelper::setOutDataPrecision(fakeQuantize1, fqOnDataPrecision);
672             ngraph::pass::low_precision::NetworkHelper::setOutDataPrecision(fakeQuantize2, fqOnDataPrecision);
673             ngraph::pass::low_precision::NetworkHelper::setOutDataPrecision(fakeQuantize3, fqOnDataPrecision);
674             ngraph::pass::low_precision::NetworkHelper::setOutDataPrecision(concat1, fqOnDataPrecision);
675             ngraph::pass::low_precision::NetworkHelper::setOutDataPrecision(concat2, fqOnDataPrecision);
676         }
677     }
678
679     return function;
680 }
681
682 std::shared_ptr<ngraph::Function> ConcatFunction::getReferenceWithIntermediate(
683     const ngraph::element::Type precision,
684     const ngraph::Shape& inputShape,
685     const bool transparentIntermediate,
686     const FakeQuantizeOnData& fqOnData1,
687     const FakeQuantizeOnData& fqOnData2,
688     const DequantizationOperations& dequantizationOperations1,
689     const DequantizationOperations& dequantizationOperations2) {
690     const std::vector<size_t> inputShape1 = {
691         inputShape[0],
692         inputShape[1],
693         inputShape[2] - (transparentIntermediate ? 2 : 0),
694         inputShape[3] - (transparentIntermediate ? 2 : 0)
695     };
696
697     const auto input1 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape1));
698     input1->set_friendly_name("input1");
699     const auto fakeQuantize1 = makeFakeQuantizeTypeRelaxed(input1, precision, fqOnData1);
700     fakeQuantize1->set_friendly_name("fakeQuantize1");
701
702     const std::vector<size_t> inputShape2 = { inputShape[0], inputShape[1], inputShape[2], inputShape[3] };
703     const auto input2 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape2));
704     input2->set_friendly_name("input2");
705
706     const auto fakeQuantize2 = makeFakeQuantizeTypeRelaxed(input2, precision, fqOnData2);
707     fakeQuantize2->set_friendly_name("fakeQuantize2");
708
709     const std::vector<size_t> kernel = { 3, 3 };
710     const std::vector<size_t> stride = { 1, 1 };
711     const std::vector<size_t> padBegin = { 0, 0 };
712     const std::vector<size_t> padEnd = { 0, 0 };
713     const ngraph::op::PadType padType = ngraph::op::PadType::NOTSET;
714     const ngraph::op::RoundingType roundingType = ngraph::op::RoundingType::FLOOR;
715     std::shared_ptr<Node> intermediateOp;
716
717     if (transparentIntermediate) {
718         intermediateOp = std::make_shared<ngraph::opset1::MaxPool>(
719             fakeQuantize2->output(0),
720             stride,
721             padBegin,
722             padEnd,
723             kernel,
724             roundingType,
725             padType);
726     } else {
727         auto weights = ngraph::opset1::Constant::create(
728             precision,
729             ngraph::Shape{ inputShape[1], inputShape[1], 1, 1 },
730             std::vector<float>(inputShape[1] * inputShape[1], 1));
731
732         intermediateOp = std::make_shared<ngraph::opset1::Convolution>(
733             fakeQuantize2->output(0),
734             weights,
735             ngraph::Strides{ 1, 1 },
736             ngraph::CoordinateDiff{ 0, 0 },
737             ngraph::CoordinateDiff{ 0, 0 },
738             ngraph::Strides{ 1, 1 });
739     }
740
741     intermediateOp->set_friendly_name("intermediate");
742
743     const std::shared_ptr<ngraph::opset1::Concat> concat = std::make_shared<ngraph::opset1::Concat>(
744         ngraph::OutputVector { fakeQuantize1->output(0), intermediateOp->output(0) },
745         1);
746     concat->set_friendly_name("concat");
747
748     auto& rtInfo = concat->get_rt_info();
749     rtInfo["Variant::std::string"] = std::make_shared<VariantWrapper<std::string>>("concat");
750
751     const std::shared_ptr<ngraph::Node> lastDequantization1 = dequantizationOperations1.empty() ?
752         concat :
753         makeDequantization(concat, dequantizationOperations1);
754     lastDequantization1->set_friendly_name("concat");
755
756     const std::shared_ptr<ngraph::Node> lastDequantization2 = dequantizationOperations2.empty() ?
757         nullptr :
758         makeDequantization(intermediateOp, dequantizationOperations2);
759
760     auto weights = ngraph::opset1::Constant::create(precision, ngraph::Shape{ inputShape[1], inputShape[1], 1, 1 }, { 1 });
761     auto convolution = std::make_shared<ngraph::opset1::Convolution>(
762         lastDequantization2 == nullptr ? intermediateOp : lastDequantization2,
763         weights,
764         ngraph::Strides{ 1, 1 },
765         ngraph::CoordinateDiff{ 0, 0 },
766         ngraph::CoordinateDiff{ 0, 0 },
767         ngraph::Strides{ 1, 1 });
768     convolution->set_friendly_name("convolution");
769
770     ngraph::ResultVector results {
771         std::make_shared<ngraph::opset1::Result>(lastDequantization1),
772         std::make_shared<ngraph::opset1::Result>(convolution)
773     };
774
775     std::shared_ptr<ngraph::Function> function = std::make_shared<ngraph::Function>(
776         results,
777         ngraph::ParameterVector{ input1, input2 },
778         "ConcatWithIntermediateTransformation");
779
780     if ((fqOnData1.outputPrecision != fqOnData2.outputPrecision)) {
781         THROW_IE_EXCEPTION << "FakeQuantize expected precisions are different";
782     }
783     const ngraph::element::Type fqOnDataPrecision = fqOnData1.outputPrecision;
784     if (fqOnDataPrecision != ngraph::element::undefined) {
785         if (fakeQuantize1->get_output_element_type(0) != fakeQuantize2->get_output_element_type(0)) {
786             THROW_IE_EXCEPTION << "FakeQuantize operation precisions are different";
787         }
788         const ngraph::element::Type fakeQuantizePrecision = fakeQuantize1->get_output_element_type(0);
789
790         if (fqOnDataPrecision != fakeQuantizePrecision) {
791             ngraph::pass::low_precision::NetworkHelper::setOutDataPrecision(fakeQuantize1, fqOnDataPrecision);
792             ngraph::pass::low_precision::NetworkHelper::setOutDataPrecision(fakeQuantize2, fqOnDataPrecision);
793             ngraph::pass::low_precision::NetworkHelper::setOutDataPrecision(concat, fqOnDataPrecision);
794
795             auto intermediateOpTr = std::dynamic_pointer_cast<ngraph::op::TypeRelaxedBase>(intermediateOp);
796             if (intermediateOpTr != nullptr) {
797                 ngraph::pass::low_precision::NetworkHelper::setOutDataPrecisionForTypeRelaxed(intermediateOp, fqOnDataPrecision);
798             } else {
799                 // set precision to explicitly to have updated precision during transformation
800                 for (size_t i = 0; i < intermediateOp->get_output_size(); ++i) {
801                     intermediateOp->set_output_type(i, fqOnDataPrecision, intermediateOp->get_output_partial_shape(i));
802                 }
803             }
804         }
805     }
806
807     return function;
808 }
809
810 std::shared_ptr<ngraph::Function> ConcatFunction::getReferenceWithSplitedIntermediate(
811     const ngraph::element::Type precision,
812     const ngraph::Shape& inputShape,
813     const FakeQuantizeOnData& fqOnData1,
814     const FakeQuantizeOnData& fqOnData2,
815     const DequantizationOperations& dequantizationOperations1,
816     const DequantizationOperations& dequantizationOperations2) {
817     size_t numSplit = 2;
818     size_t splitedAxis = 1;
819
820     const std::vector<size_t> inputShape1 = {
821         inputShape[0],
822         inputShape[1] / numSplit,
823         inputShape[2],
824         inputShape[3]
825     };
826
827     const auto input1 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape1));
828     input1->set_friendly_name("input1");
829     const auto fakeQuantize1 = makeFakeQuantizeTypeRelaxed(input1, precision, fqOnData1);
830     fakeQuantize1->set_friendly_name("fakeQuantize1");
831
832
833     const std::vector<size_t> inputShape2 = { inputShape[0], inputShape[1], inputShape[2], inputShape[3] };
834     const auto input2 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape2));
835     input2->set_friendly_name("input2");
836     const auto fakeQuantize2 = makeFakeQuantizeTypeRelaxed(input2, precision, fqOnData2);
837     fakeQuantize2->set_friendly_name("fakeQuantize2");
838
839     const ngraph::element::Type fqOnDataPrecision = fqOnData1.outputPrecision;
840     if (fqOnDataPrecision != ngraph::element::undefined) {
841         ngraph::pass::low_precision::NetworkHelper::setOutDataPrecision(fakeQuantize1, fqOnDataPrecision);
842         ngraph::pass::low_precision::NetworkHelper::setOutDataPrecision(fakeQuantize2, fqOnDataPrecision);
843     }
844
845     std::shared_ptr<ngraph::op::Op> intermediateOp;
846
847     const auto constant = std::make_shared<ngraph::opset1::Constant>(element::i64, Shape{ }, splitedAxis);
848     intermediateOp = std::make_shared<ngraph::opset1::Split>(fakeQuantize2->output(0), constant, numSplit);
849
850     intermediateOp->set_friendly_name("intermediate");
851
852     const std::shared_ptr<ngraph::opset1::Concat> concat = std::make_shared<ngraph::opset1::Concat>(
853         ngraph::OutputVector{ fakeQuantize1->output(0), intermediateOp->output(0) }, splitedAxis);
854     concat->set_friendly_name("concat");
855
856     auto& rtInfo = concat->get_rt_info();
857     rtInfo["Variant::std::string"] = std::make_shared<VariantWrapper<std::string>>("concat");
858
859     const std::shared_ptr<ngraph::Node> lastDequantization1 = dequantizationOperations1.empty() ?
860         concat :
861         makeDequantization(concat, dequantizationOperations1);
862
863     const std::shared_ptr<ngraph::Node> lastDequantization2 = dequantizationOperations2.empty() ?
864         nullptr :
865         makeDequantization(intermediateOp->output(1), dequantizationOperations2);
866
867     auto weights = ngraph::opset1::Constant::create(
868         precision,
869         ngraph::Shape{ inputShape[1] / numSplit, inputShape[1] / numSplit, 1, 1 }, { 1 });
870
871     auto convolution = std::make_shared<ngraph::opset1::Convolution>(
872         lastDequantization2 == nullptr ? intermediateOp : lastDequantization2,
873         weights,
874         ngraph::Strides{ 1, 1 },
875         ngraph::CoordinateDiff{ 0, 0 },
876         ngraph::CoordinateDiff{ 0, 0 },
877         ngraph::Strides{ 1, 1 });
878     convolution->set_friendly_name("convolution");
879
880     ngraph::ResultVector results{
881         std::make_shared<ngraph::opset1::Result>(lastDequantization1),
882         std::make_shared<ngraph::opset1::Result>(convolution)
883     };
884
885     std::shared_ptr<ngraph::Function> function = std::make_shared<ngraph::Function>(
886         results,
887         ngraph::ParameterVector{ input1, input2 },
888         "ConcatWithIntermediateTransformation");
889
890     if ((fqOnData1.outputPrecision != fqOnData2.outputPrecision)) {
891         THROW_IE_EXCEPTION << "FakeQuantize expected precisions are different";
892     }
893     if (fqOnDataPrecision != ngraph::element::undefined) {
894         if (fakeQuantize1->get_output_element_type(0) != fakeQuantize2->get_output_element_type(0)) {
895             THROW_IE_EXCEPTION << "FakeQuantize operation precisions are different";
896         }
897     }
898
899     return function;
900 }
901
902 std::shared_ptr<ngraph::Function> ConcatFunction::getReferenceSelectionWithIntermediate(
903     const ngraph::element::Type precision,
904     const ngraph::Shape& inputShape,
905     const bool transparentIntermediate,
906     const FakeQuantizeOnData& fqOnData1,
907     const FakeQuantizeOnData& fqOnData2,
908     const DequantizationOperations& dequantizationOperations1,
909     const DequantizationOperations& dequantizationOperations2) {
910     const std::vector<size_t> inputShape1 = {
911         inputShape[0],
912         inputShape[1],
913         inputShape[2] - (transparentIntermediate ? 2 : 0),
914         inputShape[3] - (transparentIntermediate ? 2 : 0)
915     };
916
917     const auto input1 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape1));
918     input1->set_friendly_name("input1");
919     const auto fakeQuantize1 = makeFakeQuantizeTypeRelaxed(input1, precision, fqOnData1);
920     fakeQuantize1->set_friendly_name("fakeQuantize1");
921
922     const std::vector<size_t> inputShape2 = { inputShape[0], inputShape[1], inputShape[2], inputShape[3] };
923     const auto input2 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape2));
924     input2->set_friendly_name("input2");
925
926     const auto fakeQuantize2 = makeFakeQuantizeTypeRelaxed(input2, precision, fqOnData2);
927     fakeQuantize2->set_friendly_name("fakeQuantize2");
928
929     const std::vector<size_t> kernel = { 3, 3 };
930     const std::vector<size_t> stride = { 1, 1 };
931     const std::vector<size_t> padBegin = { 0, 0 };
932     const std::vector<size_t> padEnd = { 0, 0 };
933     const ngraph::op::PadType padType = ngraph::op::PadType::NOTSET;
934     const ngraph::op::RoundingType roundingType = ngraph::op::RoundingType::FLOOR;
935     std::shared_ptr<ngraph::op::Op> intermediateOp;
936
937     if (transparentIntermediate) {
938         intermediateOp = std::make_shared<ngraph::opset1::MaxPool>(
939             fakeQuantize2->output(0),
940             stride,
941             padBegin,
942             padEnd,
943             kernel,
944             roundingType,
945             padType);
946     } else {
947         auto weights = ngraph::opset1::Constant::create(
948             precision,
949             ngraph::Shape{ inputShape[1], inputShape[1], 1, 1 },
950             std::vector<float>(inputShape[1] * inputShape[1], 1));
951
952         intermediateOp = std::make_shared<ngraph::opset1::Convolution>(
953             fakeQuantize2->output(0),
954             weights,
955             ngraph::Strides{ 1, 1 },
956             ngraph::CoordinateDiff{ 0, 0 },
957             ngraph::CoordinateDiff{ 0, 0 },
958             ngraph::Strides{ 1, 1 });
959     }
960
961     intermediateOp->set_friendly_name("intermediate");
962
963     const std::shared_ptr<ngraph::opset1::Concat> concat = std::make_shared<ngraph::opset1::Concat>(
964         ngraph::OutputVector { fakeQuantize1->output(0), intermediateOp->output(0) },
965         1);
966     concat->set_friendly_name("concat");
967
968     auto& rtInfo = concat->get_rt_info();
969     rtInfo["Variant::std::string"] = std::make_shared<VariantWrapper<std::string>>("concat");
970
971     const std::shared_ptr<ngraph::Node> lastDequantization1 = dequantizationOperations1.empty() ?
972         concat :
973         makeDequantization(concat, dequantizationOperations1);
974     lastDequantization1->set_friendly_name("concat");
975
976     const std::shared_ptr<ngraph::Node> lastDequantization2 = dequantizationOperations2.empty() ?
977         nullptr :
978         makeDequantization(intermediateOp, dequantizationOperations2);
979
980     auto weights = ngraph::opset1::Constant::create(precision, ngraph::Shape{ inputShape[1], inputShape[1], 1, 1 }, { 1 });
981     auto convolution = std::make_shared<ngraph::opset1::Convolution>(
982         lastDequantization2 == nullptr ? intermediateOp : lastDequantization2,
983         weights,
984         ngraph::Strides{ 1, 1 },
985         ngraph::CoordinateDiff{ 0, 0 },
986         ngraph::CoordinateDiff{ 0, 0 },
987         ngraph::Strides{ 1, 1 });
988     convolution->set_friendly_name("convolution");
989
990     ngraph::ResultVector results {
991         std::make_shared<ngraph::opset1::Result>(lastDequantization1),
992         std::make_shared<ngraph::opset1::Result>(convolution)
993     };
994
995     std::shared_ptr<ngraph::Function> function = std::make_shared<ngraph::Function>(
996         results,
997         ngraph::ParameterVector{ input1, input2 },
998         "ConcatWithIntermediateTransformation");
999
1000     if ((fqOnData1.outputPrecision != fqOnData2.outputPrecision)) {
1001         THROW_IE_EXCEPTION << "FakeQuantize expected precisions are different";
1002     }
1003     const ngraph::element::Type fqOnDataPrecision = fqOnData1.outputPrecision;
1004     if (fqOnDataPrecision != ngraph::element::undefined) {
1005         if (fakeQuantize1->get_output_element_type(0) != fakeQuantize2->get_output_element_type(0)) {
1006             THROW_IE_EXCEPTION << "FakeQuantize operation precisions are different";
1007         }
1008         const ngraph::element::Type fakeQuantizePrecision = fakeQuantize1->get_output_element_type(0);
1009
1010         if (fqOnDataPrecision != fakeQuantizePrecision) {
1011             ngraph::pass::low_precision::NetworkHelper::setOutDataPrecision(fakeQuantize1, fqOnDataPrecision);
1012             ngraph::pass::low_precision::NetworkHelper::setOutDataPrecision(fakeQuantize2, fqOnDataPrecision);
1013             ngraph::pass::low_precision::NetworkHelper::setOutDataPrecision(concat, fqOnDataPrecision);
1014
1015             auto intermediateOpTr = std::dynamic_pointer_cast<ngraph::op::TypeRelaxedBase>(intermediateOp);
1016             if (intermediateOpTr != nullptr) {
1017                 ngraph::pass::low_precision::NetworkHelper::setOutDataPrecisionForTypeRelaxed(intermediateOp, fqOnDataPrecision);
1018             }
1019         }
1020     }
1021
1022     return function;
1023 }
1024
1025 std::shared_ptr<ngraph::Function> ConcatFunction::getReferenceWithDifferentPrecisionOnChilds(
1026     const ngraph::element::Type precision,
1027     const ngraph::Shape& inputShape,
1028     const bool multiChannel,
1029     const FakeQuantizeOnData& fqOnData1,
1030     const FakeQuantizeOnData& fqOnData2,
1031     const DequantizationOperations& dequantizationOperations1,
1032     const DequantizationOperations& dequantizationOperations2) {
1033     const auto input1 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape));
1034     input1->set_friendly_name("input1");
1035     const auto fakeQuantize1 = makeFakeQuantizeTypeRelaxed(input1, precision, fqOnData1);
1036     fakeQuantize1->set_friendly_name("fakeQuantize1");
1037
1038     const auto input2 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape));
1039     input2->set_friendly_name("input2");
1040     const auto fakeQuantize2 = makeFakeQuantizeTypeRelaxed(input2, precision, fqOnData2);
1041     fakeQuantize2->set_friendly_name("fakeQuantize2");
1042
1043     const ngraph::element::Type fqOnDataPrecision = fqOnData1.outputPrecision;
1044     if (fqOnDataPrecision != ngraph::element::undefined) {
1045         ngraph::pass::low_precision::NetworkHelper::setOutDataPrecision(fakeQuantize1, fqOnDataPrecision);
1046         ngraph::pass::low_precision::NetworkHelper::setOutDataPrecision(fakeQuantize2, fqOnDataPrecision);
1047     }
1048
1049     const std::shared_ptr<ngraph::opset1::Concat> concat = std::make_shared<ngraph::opset1::Concat>(
1050         ngraph::OutputVector{ fakeQuantize1->output(0), fakeQuantize2->output(0) }, 1);
1051     concat->set_friendly_name("concat");
1052
1053     auto& rtInfo = concat->get_rt_info();
1054     rtInfo["Variant::std::string"] = std::make_shared<VariantWrapper<std::string>>("concat");
1055
1056     const auto lastDequantization1 = makeDequantization(concat->output(0), dequantizationOperations1);
1057
1058     const std::vector<size_t> kernel = { 3, 3 };
1059     const std::vector<size_t> stride = { 1, 1 };
1060     const std::vector<size_t> padBegin = { 0, 0 };
1061     const std::vector<size_t> padEnd = { 0, 0 };
1062     const ngraph::op::PadType padType = ngraph::op::PadType::NOTSET;
1063     const ngraph::op::RoundingType roundingType = ngraph::op::RoundingType::FLOOR;
1064
1065     const auto avgPool = std::make_shared<ngraph::opset1::AvgPool>(
1066         lastDequantization1,
1067         stride,
1068         padBegin,
1069         padEnd,
1070         kernel,
1071         true,
1072         roundingType,
1073         padType);
1074     avgPool->set_friendly_name("AvgPool");
1075
1076     ngraph::ResultVector results;
1077     results.push_back(std::make_shared<ngraph::opset1::Result>(avgPool));
1078
1079     if (!dequantizationOperations2.empty()) {
1080         const std::shared_ptr<ngraph::opset1::MaxPool> maxPool = std::make_shared<ngraph::opset1::MaxPool>(
1081             concat->output(0),
1082             stride,
1083             padBegin,
1084             padEnd,
1085             kernel,
1086             roundingType,
1087             padType);
1088
1089         const std::shared_ptr<ngraph::Node> lastDequantization2 = makeDequantization(maxPool, dequantizationOperations2);
1090         lastDequantization2->set_friendly_name("MaxPool");
1091         results.push_back(std::make_shared<ngraph::opset1::Result>(lastDequantization2));
1092     }
1093
1094     std::shared_ptr<ngraph::Function> function = std::make_shared<ngraph::Function>(
1095         results,
1096         ngraph::ParameterVector{ input1, input2 },
1097         "ConcatWithDifferentChildsTransformation");
1098
1099     if ((fqOnData1.outputPrecision != fqOnData2.outputPrecision)) {
1100         THROW_IE_EXCEPTION << "FakeQuantize expected precisions are different";
1101     }
1102     if (fqOnDataPrecision != ngraph::element::undefined) {
1103         if (fakeQuantize1->get_output_element_type(0) != fakeQuantize2->get_output_element_type(0)) {
1104             THROW_IE_EXCEPTION << "FakeQuantize operation precisions are different";
1105         }
1106     }
1107
1108     return function;
1109 }
1110
1111 std::shared_ptr<ngraph::Function> ConcatFunction::getReferenceWithIntermediateWithConstant(
1112     const ngraph::element::Type precision,
1113     const ngraph::Shape& inputShape,
1114     const bool transparentIntermediate,
1115     const FakeQuantizeOnData& fqOnData1,
1116     const FakeQuantizeOnData& fqOnData2,
1117     const ngraph::element::Type precisionBeforeOp,
1118     const DequantizationOperations& dequantizationBefore,
1119     const ngraph::element::Type precisionAfterOperation,
1120     const DequantizationOperations& dequantizationAfter,
1121     const ngraph::element::Type precisionAfterDequantization) {
1122     const auto input1 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape));
1123     input1->set_friendly_name("input");
1124     const auto fakeQuantize1 = makeFakeQuantizeTypeRelaxed(input1, precision, fqOnData1);
1125     fakeQuantize1->set_friendly_name("fakeQuantize1");
1126     ngraph::pass::low_precision::NetworkHelper::setOutDataPrecision(fakeQuantize1, precisionBeforeOp);
1127
1128     const auto input2 = std::make_shared<ngraph::opset1::Parameter>(precision, ngraph::Shape(inputShape));
1129     input2->set_friendly_name("input");
1130     const auto fakeQuantize2 = makeFakeQuantizeTypeRelaxed(input2, precision, fqOnData2);
1131     fakeQuantize2->set_friendly_name("fakeQuantize2");
1132     ngraph::pass::low_precision::NetworkHelper::setOutDataPrecision(fakeQuantize2, precisionBeforeOp);
1133
1134     std::shared_ptr<Node> intermediateOp;
1135
1136     if (transparentIntermediate) {
1137         const auto deqBefore = makeDequantization(fakeQuantize1->output(0), dequantizationBefore);
1138         const std::vector<size_t> kernel = { 3, 3 };
1139         const std::vector<size_t> stride = { 1, 1 };
1140         const std::vector<size_t> padBegin = { 0, 0 };
1141         const std::vector<size_t> padEnd = { 0, 0 };
1142         const ngraph::op::PadType padType = ngraph::op::PadType::NOTSET;
1143         const ngraph::op::RoundingType roundingType = ngraph::op::RoundingType::FLOOR;
1144
1145         const auto pooling = std::make_shared<ngraph::opset1::MaxPool>(
1146             fakeQuantize1->output(0),
1147             stride,
1148             padBegin,
1149             padEnd,
1150             kernel,
1151             roundingType,
1152             padType);
1153
1154         ngraph::op::v0::InterpolateAttrs attributes;
1155         attributes.axes = ngraph::AxisSet{ 2, 3 };
1156         attributes.mode = "nearest";
1157         attributes.align_corners = false;
1158         attributes.antialias = false;
1159         attributes.pads_begin = { 0 };
1160         attributes.pads_end = { 0 };
1161
1162         const auto outputShape = op::Constant::create(
1163             ngraph::element::i64, ngraph::Shape{ 2 },
1164             ngraph::Shape{ inputShape[2], inputShape[3] });
1165         intermediateOp = std::make_shared<ngraph::opset1::Interpolate>(pooling->output(0), outputShape, attributes);
1166         intermediateOp->set_friendly_name("intermediate");
1167     } else {
1168         intermediateOp = fakeQuantize1;
1169     }
1170
1171     const std::shared_ptr<ngraph::opset1::Concat> concat = std::make_shared<ngraph::opset1::Concat>(
1172         ngraph::OutputVector{ fakeQuantize2->output(0), intermediateOp->output(0) },
1173         1);
1174     concat->set_friendly_name("concat");
1175     ngraph::pass::low_precision::NetworkHelper::setOutDataPrecision(concat, precisionAfterOperation);
1176
1177     auto& rtInfo = concat->get_rt_info();
1178     rtInfo["Variant::std::string"] = std::make_shared<VariantWrapper<std::string>>("concat");
1179
1180     const auto deqAfter = makeDequantization(concat->output(0), dequantizationAfter);
1181     deqAfter->set_friendly_name("concat");
1182
1183     ngraph::ResultVector results{
1184         std::make_shared<ngraph::opset1::Result>(deqAfter)
1185     };
1186
1187     std::shared_ptr<ngraph::Function> function = std::make_shared<ngraph::Function>(
1188         results,
1189         ngraph::ParameterVector{ input1, input2 },
1190         "ConcatWithIntermediateTransformation");
1191
1192     return function;
1193 }
1194
1195 }  // namespace subgraph
1196 }  // namespace builder
1197 }  // namespace ngraph