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