ONE - On-device Neural Engine
Loading...
Searching...
No Matches
MirrorPad.cpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
3 * Copyright 2019 The TensorFlow Authors. All Rights Reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include "kernels/MirrorPad.h"
19
20#include "kernels/Utils.h"
21
22#include <algorithm>
23
24namespace luci_interpreter
25{
26namespace kernels
27{
28
29MirrorPad::MirrorPad(const Tensor *input, const Tensor *paddings, Tensor *output,
30 const MirrorPadParams &params)
31 : KernelWithParams<MirrorPadParams>({input, paddings}, {output}, params)
32{
33}
34
36{
37 const Shape &input_shape = input()->shape();
38 const int num_dims = input_shape.num_dims();
39
40 if (num_dims > 4)
41 throw std::runtime_error("Unsupported number of dimensions.");
42
43 LUCI_INTERPRETER_CHECK(output()->element_type() == input()->element_type());
44 LUCI_INTERPRETER_CHECK(paddings()->element_type() == DataType::S32);
45 // Paddings shape should be [N, 2].
46 LUCI_INTERPRETER_CHECK(paddings()->shape().num_dims() == 2);
47 LUCI_INTERPRETER_CHECK(paddings()->shape().dim(0) == num_dims);
48 LUCI_INTERPRETER_CHECK(paddings()->shape().dim(1) == 2);
49
50 Shape output_shape(num_dims);
51 const auto *paddings_data = getTensorData<int32_t>(paddings());
52 for (int i = 0; i < num_dims; ++i)
53 {
54 const int32_t padding_before = paddings_data[i * 2];
55 const int32_t padding_after = paddings_data[i * 2 + 1];
56 LUCI_INTERPRETER_CHECK(padding_before >= 0 && padding_after >= 0);
57 output_shape.dim(i) = input_shape.dim(i) + padding_before + padding_after;
58 }
59
61}
62
63namespace
64{
65
66// Helper method that fills the left and right pads.
67template <typename T>
68inline void getPadding(const T *data, int offset, int64_t *left_pad, int64_t *right_pad)
69{
70 *left_pad = static_cast<int64_t>(*(data + offset * 2));
71 *right_pad = static_cast<int64_t>(*(data + offset * 2 + 1));
72}
73
74// Given dimension index and the left/right padding.
75// Returns the corresponding dimension in the input array.
76inline int getInputDimension(int padded_dimension, int left_pad, int right_pad, int input_dim_size,
77 int offset)
78{
79 (void)right_pad;
80
81 if (padded_dimension < left_pad)
82 {
83 const int original_ind = left_pad + offset - 1;
84 return original_ind - (std::min(padded_dimension, original_ind - offset));
85 }
86 padded_dimension -= left_pad;
87 if (padded_dimension >= input_dim_size)
88 {
89 padded_dimension -= input_dim_size;
90 const int original_ind = input_dim_size - (1 + offset);
91 return original_ind - std::min(padded_dimension, original_ind);
92 }
93 return padded_dimension;
94}
95
96// Given and index in output array, returns the index of the value
97// in input array.
98int getFlatIndex(int index, int num_dims, const DataType padding_matrix_type,
99 const uint8_t *padding_matrix_data, const int32_t *input_dims,
100 int *output_dims_num_elements, int *input_dims_num_elements, const int offset)
101{
102 int flat_index = 0;
103 int64_t left_pad = 0, right_pad = 0, dimension_index, index_in_input;
104
105 for (int i = 0; i < num_dims; ++i)
106 {
107 switch (padding_matrix_type)
108 {
109 case DataType::S32:
110 getPadding(reinterpret_cast<const int32_t *>(padding_matrix_data), i, &left_pad,
111 &right_pad);
112 break;
113 case DataType::S64:
114 getPadding(reinterpret_cast<const int64_t *>(padding_matrix_data), i, &left_pad,
115 &right_pad);
116 break;
117 default:
118 break;
119 }
120 dimension_index = index / output_dims_num_elements[i];
121
122 index_in_input = getInputDimension(dimension_index, left_pad, right_pad, input_dims[i], offset);
123
124 flat_index += index_in_input * input_dims_num_elements[i];
125 index %= output_dims_num_elements[i];
126 }
127
128 return flat_index;
129}
130
131template <typename T>
132void eval(const DataType padding_matrix_type, const uint8_t *padding_matrix_data,
133 const int32_t *input_dims, int *output_dims_num_elements, int *input_dims_num_elements,
134 const T *input_data, T *output_data, const int offset, const int num_dims,
135 const int output_size)
136{
137 for (int i = 0; i < output_size; ++i)
138 {
139 int index = getFlatIndex(i, num_dims, padding_matrix_type, padding_matrix_data, input_dims,
140 output_dims_num_elements, input_dims_num_elements, offset);
142 }
143}
144
145} // namespace
146
148{
149 const Tensor &t_input = *input();
150 const Tensor &t_paddings = *paddings();
151 Tensor &t_output = *output();
152
153 const auto offset = params().mode != MirrorPadMode::REFLECT ? 0 : 1;
154 const auto input_dims = t_input.shape().num_dims();
155 const auto output_size = t_output.shape().num_elements();
156
157 int output_dims_num_elements[5];
158 int input_dims_num_elements[5];
159 int32_t input_shape_dim[5];
160
161 for (int i = 0; i < input_dims; i++)
162 {
163 output_dims_num_elements[i] = 1;
164 input_dims_num_elements[i] = 1;
165 input_shape_dim[i] = t_input.shape().dim(i);
166 }
167
168 for (int i = input_dims - 2; i >= 0; i--)
169 {
170 output_dims_num_elements[i] = output_dims_num_elements[i + 1] * t_output.shape().dim(i + 1);
171 input_dims_num_elements[i] = input_dims_num_elements[i + 1] * t_input.shape().dim(i + 1);
172 }
173
174 switch (t_input.element_type())
175 {
176 case DataType::FLOAT32:
177 eval(t_paddings.element_type(), t_paddings.data<uint8_t>(), input_shape_dim,
178 output_dims_num_elements, input_dims_num_elements, t_input.data<float>(),
179 t_output.data<float>(), offset, input_dims, output_size);
180 break;
181
182 case DataType::U8:
183 eval(t_paddings.element_type(), t_paddings.data<uint8_t>(), input_shape_dim,
184 output_dims_num_elements, input_dims_num_elements, t_input.data<uint8_t>(),
185 t_output.data<uint8_t>(), offset, input_dims, output_size);
186 break;
187
188 default:
189 throw std::runtime_error("luci-intp MirrorPad Unsupported type.");
190 }
191}
192
193} // namespace kernels
194} // namespace luci_interpreter
const MirrorPadParams & params() const
Definition Kernel.h:67
int32_t dim(int i) const
Definition Tensor.h:41
int32_t num_elements() const
Definition Tensor.h:53
int num_dims() const
Definition Tensor.h:39
void resize(const Shape &new_shape)
Definition Tensor.cpp:56
const Shape & shape() const
Definition Tensor.h:107
const T * data() const
Definition Tensor.h:127
DataType element_type() const
Definition Tensor.h:105
MirrorPad(const Tensor *input, const Tensor *paddings, Tensor *output, const MirrorPadParams &params)
Definition MirrorPad.cpp:29
const Tensor * input() const
Definition MirrorPad.h:34
const Tensor * paddings() const
Definition MirrorPad.h:35
#define LUCI_INTERPRETER_CHECK(cond)
Definition Utils.h:36
__global uchar * offset(const Image *img, int x, int y)
Definition helpers.h:540
const luci_interpreter::RuntimeShape output_shape
const T * data(const std::vector< T, Alloc > &v)
list input_data
Definition infer.py:29
DataType
"scalar" value type
Definition DataType.h:27
loco::GraphInputIndex index(const TFPlaceholder *node)
Definition TFNode.cpp:54