|
| 1 | +/******************************************************************************* |
| 2 | +* Copyright 2017-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 | +#include <CPP/batch_norm.hpp> |
| 18 | +#include <CPP/concatenation.hpp> |
| 19 | +#include <CPP/scale.hpp> |
| 20 | +#include <CPP/split.hpp> |
| 21 | + |
| 22 | +#include "ngraph/runtime/intelgpu/intelgpu_op_batchnorm.hpp" |
| 23 | + |
| 24 | +#include "ngraph/op/batch_norm.hpp" |
| 25 | + |
| 26 | +using namespace std; |
| 27 | +using namespace ngraph; |
| 28 | + |
| 29 | +// This function converts Shape dimension id into cldnn::concatenation id |
| 30 | +static cldnn::concatenation::concatenation_axis get_cldnn_axis(size_t tensor_channel) |
| 31 | +{ |
| 32 | + switch (tensor_channel) |
| 33 | + { |
| 34 | + case 0: return cldnn::concatenation::along_b; |
| 35 | + case 1: return cldnn::concatenation::along_f; |
| 36 | + case 2: return cldnn::concatenation::along_y; |
| 37 | + case 3: return cldnn::concatenation::along_x; |
| 38 | + default: throw invalid_argument("intelgpu::get_cldnn_axis() wrong input tensor channel."); |
| 39 | + } |
| 40 | +} |
| 41 | + |
| 42 | +static string do_matrix_split(cldnn::topology& topology, |
| 43 | + const string& name, |
| 44 | + const vector<pair<cldnn::primitive_id, cldnn::tensor>>& offsets) |
| 45 | +{ |
| 46 | + const string result = name + "_split"; |
| 47 | + |
| 48 | + const cldnn::split op_split(result, name, offsets); |
| 49 | + topology.add(op_split); |
| 50 | + return result; |
| 51 | +} |
| 52 | + |
| 53 | +static string get_batch_norm_mean(cldnn::topology& topology, const string& input_name) |
| 54 | +{ |
| 55 | + throw invalid_argument( |
| 56 | + "intelgpu::get_batch_norm_mean() Calculation matrix mean is not yet supported."); |
| 57 | +} |
| 58 | + |
| 59 | +static string get_batch_norm_variance(cldnn::topology& topology, |
| 60 | + const string& input_name, |
| 61 | + const string& mean_name) |
| 62 | +{ |
| 63 | + throw invalid_argument( |
| 64 | + "intelgpu::get_batch_norm_variance() Calculation matrix variance is not yet supported."); |
| 65 | +} |
| 66 | + |
| 67 | +void runtime::intelgpu::do_batch_norm_operation(cldnn::topology& topology, |
| 68 | + const string& output_name, |
| 69 | + double eps, |
| 70 | + const string& input_name, |
| 71 | + const Shape& input_shape, |
| 72 | + const string& gamma_name, |
| 73 | + const string& beta_name, |
| 74 | + const string& mean_name_inp, |
| 75 | + const string& variance_name_inp) |
| 76 | +{ |
| 77 | + vector<pair<cldnn::primitive_id, cldnn::tensor>> split_offsets; |
| 78 | + vector<pair<cldnn::primitive_id, cldnn::tensor>> vec_offsets; |
| 79 | + vector<cldnn::primitive_id> dim_set; |
| 80 | + |
| 81 | + if (input_shape.size() < 2 || input_shape.size() > 4) |
| 82 | + { |
| 83 | + throw invalid_argument("intelgpu::do_batch_norm_operation() wrong input shape."); |
| 84 | + } |
| 85 | + |
| 86 | + // According to the documentation, input data channel is always being axis 1 |
| 87 | + // Assumed the second dimension from the left. Example {0, 1, 0, 0} or {0, 1} |
| 88 | + // Also, input data must be at least 2D array |
| 89 | + const size_t shape_channel = 1; |
| 90 | + const size_t cldnn_channel = 4 - input_shape.size() + shape_channel; |
| 91 | + |
| 92 | + const size_t split_arr_count = input_shape.at(shape_channel); |
| 93 | + for (size_t i = 0; i < split_arr_count; ++i) |
| 94 | + { |
| 95 | + const string str_i = to_string(i); |
| 96 | + const cldnn::tensor vec_offset(0, 0, i, 0); |
| 97 | + vec_offsets.push_back(pair<cldnn::primitive_id, cldnn::tensor>(str_i, vec_offset)); |
| 98 | + |
| 99 | + vector<cldnn::tensor::value_type> offset({0, 0, 0, 0}); // No action by default |
| 100 | + offset.at(cldnn_channel) = i; |
| 101 | + |
| 102 | + cout << "Splitted to " << i << " with " << vector_to_string(offset) << "\n"; |
| 103 | + const cldnn::tensor input_offset(offset.at(0), offset.at(1), offset.at(3), offset.at(2)); |
| 104 | + split_offsets.push_back(pair<cldnn::primitive_id, cldnn::tensor>(str_i, input_offset)); |
| 105 | + } |
| 106 | + |
| 107 | + string mean_name = mean_name_inp; |
| 108 | + if (mean_name_inp.empty()) |
| 109 | + { |
| 110 | + mean_name = get_batch_norm_mean(topology, input_name); |
| 111 | + } |
| 112 | + |
| 113 | + string variance_name = variance_name_inp; |
| 114 | + if (variance_name_inp.empty()) |
| 115 | + { |
| 116 | + variance_name = get_batch_norm_variance(topology, input_name, mean_name); |
| 117 | + } |
| 118 | + |
| 119 | + const string input_split_name = do_matrix_split(topology, input_name, split_offsets); |
| 120 | + const string mean_split_name = do_matrix_split(topology, mean_name, vec_offsets); |
| 121 | + const string variance_split_name = do_matrix_split(topology, variance_name, vec_offsets); |
| 122 | + const string gamma_split_name = do_matrix_split(topology, gamma_name, vec_offsets); |
| 123 | + const string beta_split_name = do_matrix_split(topology, beta_name, vec_offsets); |
| 124 | + |
| 125 | + for (size_t i = 0; i < split_arr_count; ++i) |
| 126 | + { |
| 127 | + const string suf = ':' + to_string(i); |
| 128 | + const string out_bn_name = output_name + "_out_bn"; |
| 129 | + |
| 130 | + const cldnn::batch_norm cldd_batchnorm(out_bn_name + suf, |
| 131 | + input_split_name + suf, |
| 132 | + mean_split_name + suf, |
| 133 | + variance_split_name + suf, |
| 134 | + eps); |
| 135 | + topology.add(cldd_batchnorm); |
| 136 | + |
| 137 | + const cldnn::scale op_scale( |
| 138 | + output_name + suf, out_bn_name + suf, gamma_split_name + suf, beta_split_name + suf); |
| 139 | + topology.add(op_scale); |
| 140 | + |
| 141 | + dim_set.push_back(output_name + suf); |
| 142 | + } |
| 143 | + |
| 144 | + const cldnn::concatenation op_concat(output_name, dim_set, get_cldnn_axis(cldnn_channel)); |
| 145 | + topology.add(op_concat); |
| 146 | +} |
0 commit comments