2 * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "OperationValidator.h"
21 #define OP_REQUIRES(EXP) \
25 throw std::runtime_error("OperationValidator failed at line " + std::to_string(__LINE__)); \
33 OperationValidator::OperationValidator(const Graph &graph)
34 : _operations{graph.operations()}, _operands{graph.operands()}
38 void OperationValidator::operator()()
40 _operations.iterate([&](const OperationIndex &, const Operation &node) { node.accept(*this); });
43 DataType OperationValidator::operandType(const OperandIndex &idx)
45 return _operands.at(idx).typeInfo().type();
48 bool OperationValidator::isConstant(const OperandIndex &idx)
50 return _operands.at(idx).isConstant();
53 bool OperationValidator::isSameType(const OperandIndex &idx1, const OperandIndex &idx2)
55 return operandType(idx1) == operandType(idx2);
58 bool OperationValidator::isValidType(const OperandIndex &idx, const DataType &type)
60 return operandType(idx) == type;
63 bool OperationValidator::isValidType(const OperandIndex &idx,
64 std::initializer_list<DataType> valid_types)
66 for (auto type_to_check : valid_types)
68 if (isValidType(idx, type_to_check))
77 void OperationValidator::visit(const operation::AddN &node)
79 int size = node.getInputs().size();
80 for (int i = 0; i < size; i++)
82 const auto input_index(node.getInputs().at(i));
83 OP_REQUIRES(isValidType(input_index, {DataType::FLOAT32, DataType::INT32}));
87 void OperationValidator::visit(const operation::BatchMatMul &node)
89 const auto lhs_index(node.getInputs().at(operation::BatchMatMul::Input::LHS));
90 const auto rhs_index(node.getInputs().at(operation::BatchMatMul::Input::RHS));
92 // Constant lhs and rhs is not implemented yet
93 OP_REQUIRES(!isConstant(lhs_index) && !isConstant(rhs_index));
96 void OperationValidator::visit(const operation::BatchToSpaceND &node)
98 const auto block_size_index{node.getInputs().at(operation::BatchToSpaceND::Input::BLOCK_SIZE)};
100 // Non-constant block_size is not implemented yet
101 OP_REQUIRES(isConstant(block_size_index));
104 void OperationValidator::visit(const operation::BinaryArithmetic &node)
106 const auto output_index{node.getOutputs().at(0)};
107 const auto lhs_index{node.getInputs().at(operation::BinaryArithmetic::Input::LHS)};
108 const auto rhs_index{node.getInputs().at(operation::BinaryArithmetic::Input::RHS)};
110 OP_REQUIRES(isSameType(lhs_index, rhs_index));
111 OP_REQUIRES(isSameType(lhs_index, output_index));
114 void OperationValidator::visit(const operation::Comparison &node)
116 const auto output_index{node.getOutputs().at(0)};
118 const auto lhs_index{node.getInputs().at(operation::Comparison::Input::INPUT0)};
119 const auto rhs_index{node.getInputs().at(operation::Comparison::Input::INPUT1)};
121 OP_REQUIRES(isSameType(lhs_index, rhs_index));
122 OP_REQUIRES(isValidType(output_index, DataType::BOOL8));
125 void OperationValidator::visit(const operation::DepthToSpace &node)
127 int32_t block_size = node.param().block_size;
129 OP_REQUIRES(block_size > 0);
132 void OperationValidator::visit(const operation::DepthwiseConv2D &node)
134 const auto input_index{node.getInputs().at(operation::DepthwiseConv2D::Input::INPUT)};
135 const auto output_index{node.getOutputs().at(0)};
137 uint32_t stride_horizontal = node.param().stride.horizontal;
138 uint32_t stride_vertical = node.param().stride.vertical;
139 uint32_t dilation_width = node.param().dilation.width_factor;
140 uint32_t dilation_height = node.param().dilation.height_factor;
142 OP_REQUIRES((stride_horizontal > 0) && (stride_vertical > 0));
143 OP_REQUIRES((dilation_width > 0) && (dilation_height > 0));
144 OP_REQUIRES(isSameType(input_index, output_index));
147 void OperationValidator::visit(const operation::ElementwiseActivation &node)
149 const auto output_index{node.getOutputs().at(0)};
150 const auto input_index{node.getInputs().at(0)};
152 // Check if I/O types match
153 OP_REQUIRES(isSameType(output_index, input_index));
156 void OperationValidator::visit(const operation::ElementwiseBinary &node)
158 const auto output_index{node.getOutputs().at(0)};
159 const auto lhs_index{node.getInputs().at(operation::ElementwiseBinary::Input::LHS)};
160 const auto rhs_index{node.getInputs().at(operation::ElementwiseBinary::Input::RHS)};
162 OP_REQUIRES(isSameType(lhs_index, rhs_index));
163 OP_REQUIRES(isSameType(lhs_index, output_index));
166 void OperationValidator::visit(const operation::ElementwiseUnary &node)
168 const auto output_index{node.getOutputs().at(0)};
169 const auto input_index{node.getInputs().at(operation::ElementwiseUnary::Input::INPUT)};
171 // Check if I/O types match
172 if (node.param().op_type == operation::ElementwiseUnary::Type::DEQUANTIZE)
174 // NNAPI allow QUANT_INT8_SYMM type input
175 OP_REQUIRES(isValidType(input_index, {DataType::QUANT_UINT8_ASYMM, DataType::QUANT_INT8_SYMM,
176 DataType::QUANT_INT8_ASYMM}));
177 OP_REQUIRES(isValidType(output_index, DataType::FLOAT32));
179 else if (node.param().op_type == operation::ElementwiseUnary::Type::QUANTIZE)
181 OP_REQUIRES(isValidType(input_index, DataType::FLOAT32));
182 OP_REQUIRES(isValidType(output_index, DataType::QUANT_UINT8_ASYMM));
184 else if (node.param().op_type == operation::ElementwiseUnary::Type::FLOOR)
186 OP_REQUIRES(isValidType(input_index, DataType::FLOAT32));
187 OP_REQUIRES(isSameType(output_index, input_index));
189 else if (node.param().op_type != operation::ElementwiseUnary::Type::CAST)
191 OP_REQUIRES(isSameType(output_index, input_index));
195 void OperationValidator::visit(const operation::EmbeddingLookup &node)
197 const auto lookups_index{node.getInputs().at(operation::EmbeddingLookup::Input::LOOKUPS)};
199 OP_REQUIRES(isValidType(lookups_index, DataType::INT32));
202 void OperationValidator::visit(const operation::ExpandDims &node)
204 const auto output_index{node.getOutputs().at(0)};
205 const auto input_index{node.getInputs().at(operation::ExpandDims::Input::INPUT)};
206 const auto axis_index{node.getInputs().at(operation::ExpandDims::Input::AXIS)};
208 OP_REQUIRES(isSameType(output_index, input_index));
209 OP_REQUIRES(isValidType(axis_index, DataType::INT32));
212 void OperationValidator::visit(const operation::HashtableLookup &node)
214 const auto hits_index{node.getOutputs().at(operation::HashtableLookup::Output::HITS)};
215 const auto lookups_index{node.getInputs().at(operation::HashtableLookup::Input::LOOKUPS)};
216 const auto keys_index{node.getInputs().at(operation::HashtableLookup::Input::KEYS)};
218 OP_REQUIRES(isValidType(lookups_index, DataType::INT32));
219 OP_REQUIRES(isValidType(keys_index, DataType::INT32));
220 OP_REQUIRES(isValidType(hits_index, DataType::QUANT_UINT8_ASYMM));
223 void OperationValidator::visit(const operation::Pack &node)
225 const auto num{node.param().num};
227 OP_REQUIRES(num == static_cast<int32_t>(node.getInputs().size()));
230 void OperationValidator::visit(const operation::Pad &node)
232 const auto pad_index{node.getInputs().at(operation::Pad::Input::PAD)};
234 OP_REQUIRES(isValidType(pad_index, DataType::INT32));
237 void OperationValidator::visit(const operation::Rank &node)
239 const auto output_index{node.getOutputs().at(0)};
241 OP_REQUIRES(isValidType(output_index, DataType::INT32));
244 void OperationValidator::visit(const operation::ResizeBilinear &node)
246 auto align_corners = node.param().align_corners;
247 auto half_pixel_centers = node.param().half_pixel_centers;
249 OP_REQUIRES(!align_corners || !half_pixel_centers);
252 void OperationValidator::visit(const operation::Reverse &node)
254 const auto output_index{node.getOutputs().at(0)};
255 const auto input_index{node.getInputs().at(operation::Reverse::Input::INPUT)};
256 const auto axis_index{node.getInputs().at(operation::Reverse::Input::AXIS)};
258 OP_REQUIRES(isValidType(axis_index, DataType::INT32));
259 OP_REQUIRES(isSameType(output_index, input_index));
262 void OperationValidator::visit(const operation::Select &node)
264 const auto condition_index{node.getInputs().at(operation::Select::Input::CONDITION)};
265 const auto input_true_index{node.getInputs().at(operation::Select::Input::INPUT_TRUE)};
266 const auto input_false_index{node.getInputs().at(operation::Select::Input::INPUT_FALSE)};
268 OP_REQUIRES(isValidType(condition_index, DataType::BOOL8));
269 OP_REQUIRES(isSameType(input_true_index, input_false_index));
272 void OperationValidator::visit(const operation::Shape &node)
274 const auto output_index{node.getOutputs().at(0)};
276 OP_REQUIRES(isValidType(output_index, {DataType::UINT32, DataType::INT32, DataType::INT64}));
279 void OperationValidator::visit(const operation::SpaceToBatchND &node)
281 const auto block_size_index{node.getInputs().at(operation::SpaceToBatchND::Input::BLOCK_SIZE)};
282 const auto paddings_index{node.getInputs().at(operation::SpaceToBatchND::Input::PADDINGS)};
284 // Non-constant block_size and padding is not implemented yet
285 OP_REQUIRES(isConstant(block_size_index));
286 OP_REQUIRES(isConstant(paddings_index));
289 void OperationValidator::visit(const operation::SpaceToDepth &node)
291 const auto block_size = node.param().block_size;
292 OP_REQUIRES(block_size >= 1);
295 void OperationValidator::visit(const operation::Split &node)
297 const auto num_splits = node.param().num_splits;
299 OP_REQUIRES(num_splits > 0 && num_splits <= 0xFFFF);
300 OP_REQUIRES(node.getOutputs().size() == static_cast<uint32_t>(num_splits));
303 void OperationValidator::visit(const operation::SquaredDifference &node)
305 const auto output_index{node.getOutputs().at(0)};
306 const auto lhs_index{node.getInputs().at(operation::SquaredDifference::Input::LHS)};
307 const auto rhs_index{node.getInputs().at(operation::SquaredDifference::Input::RHS)};
309 OP_REQUIRES(isSameType(output_index, lhs_index));
310 OP_REQUIRES(isSameType(lhs_index, rhs_index));
313 void OperationValidator::visit(const operation::StridedSlice &node)
315 const auto output_index{node.getOutputs().at(0)};
316 const auto input_index{node.getInputs().at(operation::StridedSlice::Input::INPUT)};
318 OP_REQUIRES(isSameType(output_index, input_index));
321 void OperationValidator::visit(const operation::TransposeConv &node)
323 OP_REQUIRES((node.param().padding.type == PaddingType::SAME) ||
324 (node.param().padding.type == PaddingType::VALID));
327 void OperationValidator::visit(const operation::Unpack &node)
329 const auto num{node.param().num};
330 OP_REQUIRES(num == static_cast<int32_t>(node.getOutputs().size()));
333 void OperationValidator::visit(const operation::While &node)
335 OP_REQUIRES(node.getInputs().size() == node.getOutputs().size());
338 } // namespace compiler