Publishing 2019 R1 content
[platform/upstream/dldt.git] / inference-engine / thirdparty / clDNN / src / graph_optimizer / handle_input_padding.cpp
1 /*
2 // Copyright (c) 2018 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16
17 ///////////////////////////////////////////////////////////////////////////////////////////////////
18
19 #include "pass_manager.h"
20 #include "border_inst.h"
21 #include "convolution_inst.h"
22 #include "error_handler.h"
23
24 using namespace cldnn;
25
26 //Some primitives support padding for input.
27 //There are 2 types of padding: symmetric and asymettric.
28 //Symmetric padding can be done using input_offset parameter for primitives.
29 //Asymmetric padding can be done by adding border primitive before them. It's safe way without modyfing optimized kernels.
30 void handle_input_padding::run(program_impl& p)
31 {
32     auto processing_order = p.get_processing_order();
33
34     for (auto& node : processing_order)
35     {
36         if (node->is_type<convolution>()
37             && (node->as<convolution>().get_primitive()->padding_above.spatial[0] != 0 || node->as<convolution>().get_primitive()->padding_above.spatial[1] != 0
38                 || node->as<convolution>().get_primitive()->padding_below.spatial[0] != 0 || node->as<convolution>().get_primitive()->padding_below.spatial[1] != 0))
39         {
40             auto conv = node->as<convolution>().get_primitive();
41             auto conv_primitive = const_cast<convolution*>(&(*conv));
42
43             //Asymmetric padding
44             if (node->as<convolution>().get_primitive()->padding_above.spatial[0] != node->as<convolution>().get_primitive()->padding_below.spatial[0]
45                 || node->as<convolution>().get_primitive()->padding_above.spatial[1] != node->as<convolution>().get_primitive()->padding_below.spatial[1])
46             {
47                 primitive_id conv_id = conv_primitive->id;
48                 primitive_id input_id = conv_primitive->input[0];
49
50                 auto padding_above = conv_primitive->padding_above;
51                 auto padding_below = conv_primitive->padding_below;
52
53                 CLDNN_ERROR_NOT_EQUAL(node->as<convolution>().id(), "Padding above feature", padding_above.feature[0], "", 0, "Padding above in feature is not supported");
54                 CLDNN_ERROR_NOT_EQUAL(node->as<convolution>().id(), "Padding above batch", padding_above.batch[0], "", 0, "Padding above in batch is not supported");
55                 CLDNN_ERROR_NOT_EQUAL(node->as<convolution>().id(), "Padding below feature", padding_below.feature[0], "", 0, "Padding below in feature is not supported");
56                 CLDNN_ERROR_NOT_EQUAL(node->as<convolution>().id(), "Padding below batch", padding_below.batch[0], "", 0, "Padding below in batch is not supported");
57                 
58                 CLDNN_ERROR_LESS_THAN(node->as<convolution>().id(), "Padding above X", padding_above.spatial[0], "", 0, "Padding above in X cannot be negative");
59                 CLDNN_ERROR_LESS_THAN(node->as<convolution>().id(), "Padding above Y", padding_above.spatial[1], "", 0, "Padding above in Y cannot be negative");
60                 CLDNN_ERROR_LESS_THAN(node->as<convolution>().id(), "Padding below X", padding_below.spatial[0], "", 0, "Padding below in X cannot be negative");
61                 CLDNN_ERROR_LESS_THAN(node->as<convolution>().id(), "Padding below Y", padding_below.spatial[1], "", 0, "Padding below in Y cannot be negative");
62
63                 //set padding_above/padding_below to zeros - border primitive do the job
64                 conv_primitive->padding_above = tensor(0, 0, 0, 0);
65                 conv_primitive->padding_below = tensor(0, 0, 0, 0);
66
67                 //create border primitive
68                 primitive_id border_id = input_id + "_border_" + conv_id;
69                 auto b_prim = std::make_shared<border>(border_id, input_id,
70                     padding_above,
71                     padding_below,
72                     border_type::constant, 0.0f);
73
74                 auto& b_prim_node = p.get_or_create(b_prim);
75
76                 p.add_intermediate(b_prim_node, *node, 0, true);
77
78                 continue;
79             }
80             //Symmetric padding
81             else
82             {
83                 //set input_offset
84                 conv_primitive->input_offset = conv_primitive->padding_above.negate().add(conv_primitive->input_offset);
85
86                 //set padding_above/padding_below to zeros - input_offset do the job
87                 conv_primitive->padding_above = tensor(0, 0, 0, 0);
88                 conv_primitive->padding_below = tensor(0, 0, 0, 0);
89
90                 node->as<convolution>().recalc_output_layout(true);
91             }
92         }
93     }
94 }