1 /* Copyright 2017 The TensorFlow Authors. All Rights Reserved. 2 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 ==============================================================================*/ 15 #ifndef TENSORFLOW_LITE_TOCO_MODEL_H_ 16 #define TENSORFLOW_LITE_TOCO_MODEL_H_ 17 18 #include <algorithm> 19 #include <complex> 20 #include <functional> 21 #include <initializer_list> 22 #include <memory> 23 #include <optional> 24 #include <string> 25 #include <unordered_map> 26 #include <unordered_set> 27 #include <vector> 28 29 #include "absl/types/optional.h" 30 #include "tensorflow/core/platform/logging.h" 31 #include "tensorflow/lite/toco/model_flags.pb.h" 32 #include "tensorflow/lite/toco/runtime/types.h" 33 #include "tensorflow/lite/toco/toco_port.h" 34 #include "tensorflow/lite/toco/toco_types.h" 35 36 namespace toco { 37 38 using tflite::QuantizationParams; 39 40 enum class OperatorType : uint8 { 41 kNone, 42 // General-purpose neural network operators. 43 kAdd, 44 kAddN, 45 kAveragePool, 46 kBatchMatMul, 47 kBatchNormalization, 48 kCeil, 49 kConv, 50 kConcatenation, 51 kCos, 52 kDepthwiseConv, 53 kDepthToSpace, 54 kSpaceToDepth, 55 kDequantize, 56 kDiv, 57 kExp, 58 kExpandDims, 59 kFill, 60 kFloorDiv, 61 kFloorMod, 62 kFullyConnected, 63 kL2Normalization, 64 kL2Pool, 65 kLstmCell, 66 kUnidirectionalSequenceLstm, 67 kLocalResponseNormalization, 68 kLog, 69 kLogistic, 70 kMaxPool, 71 kFakeQuant, 72 kMul, 73 kOneHot, 74 kRandomUniform, 75 kRange, 76 kRank, 77 kRelu, 78 kRelu1, 79 kRelu6, 80 kPRelu, 81 kHardSwish, 82 kSoftmax, 83 kLogSoftmax, 84 kSub, 85 kTanh, 86 kTransposeConv, 87 kCast, 88 kFloor, 89 kRound, 90 kGather, 91 kResizeBilinear, 92 kSin, 93 kSpaceToBatchND, 94 kPack, 95 kBatchToSpaceND, 96 kPad, 97 kPadV2, 98 kReduceProd, // Reduction product 99 kStridedSlice, 100 kSlice, 101 kSqueeze, 102 kMean, 103 kArgMax, 104 // The SVDF Op is a decomposition of a densely connected Op into 105 // low rank filters. For details: 106 // https://research.google.com/pubs/pub43813.html 107 kSvdf, 108 // Special operators used for importing TensorFlow nodes. 109 // The general intent is to have some graph transformation either 110 // drop them or rewrite them as general-purpose operators. 111 kAll, 112 kAssert, 113 kConcat, 114 kConcatV2, 115 kGreater, 116 kGreaterEqual, 117 kIdentity, 118 kLess, 119 kLessEqual, 120 kReduceMax, // Reduction Max 121 kMaximum, // Element-wise Maximum 122 kReduceMin, // Reduction Min 123 kMinimum, // Element-wise Minimum 124 kMatMul, 125 kMerge, 126 kNeg, 127 kReshape, 128 kRsqrt, 129 kShape, 130 kSplit, 131 kSplitV, 132 kSqrt, 133 kSquare, 134 kSquaredDifference, 135 kSum, 136 kSwitch, 137 kTile, 138 kTranspose, 139 kTopK_V2, 140 kDynamicPartition, 141 kDynamicStitch, 142 // An unsupported TF operation. It's only needed to be able to represent TF 143 // graph internally and is expected to be dropped by graph transformations. 144 kUnsupported, 145 // Finally, TensorFlow uses different conventions for axes ordering, 146 // see AxesOrder, and this cannot always be resolved at the time of importing 147 // nodes, as TensorFlow parameters may be constant-expression subgraphs 148 // instead of being given as plain constant arrays. So we need to insert 149 // special nodes in the graph to shuffle axes. 150 kReorderAxes, 151 kSegmentSum, 152 kSelect, 153 kSelectV2, 154 kSparseToDense, 155 kEqual, 156 kNotEqual, 157 kPow, 158 kArgMin, 159 kAny, 160 kLogicalAnd, 161 kLogicalNot, 162 kLogicalOr, 163 kCTCBeamSearchDecoder, 164 kUnpack, 165 kZerosLike, 166 kResizeNearestNeighbor, 167 kLeakyRelu, 168 kAbs, 169 kMirrorPad, 170 kUnique, 171 kUnidirectionalSequenceRnn, 172 kBidirectionalSequenceLstm, 173 kReverseV2, 174 kBidirectionalSequenceRnn, 175 kGatherNd, 176 kWhere, 177 kElu, 178 kReverseSequence, 179 kMatrixDiag, 180 kMatrixSetDiag, 181 kMatrixDiagV2, 182 kMatrixSetDiagV2, 183 kMatrixDiagV3, 184 kMatrixSetDiagV3, 185 kScatterNd, 186 // Debugging operators. 187 kNumericVerify 188 }; 189 190 // Helper to deal with TensorFlow arrays using a different ordering of 191 // dimensions 192 // ("axes") than our own. 193 // TODO(benoitjacob): Ultimately, we shouldn't have any "ordering" of axes, 194 // we should have associative arrays mapping symbolic axes identifiers (like 195 // "output_depth") to dimensions. We would then not need this anymore. 196 enum class AxesOrder { 197 kOneAxis, // one-dimensional array, one unique axis. 198 kCR, // column-major matrix storage order. Our standard. 199 kRC, // row-major matrix storage order. TensorFlow default. 200 kOHWI, // Our standard for conv weights 201 kHWIO, // TensorFlow conv weights 202 k1HWO, // Our standard for DepthwiseConv weights 203 kHWIM, // TensorFlow DepthwiseConv weights 204 kNHWC, // TensorFlow activations 205 kHWOI, // TensorFlow back-prop conv weights 206 }; 207 208 // The type of the scalars in an array. 209 // Note that the type does not by itself tell whether the values in the array 210 // are non-quantized (can be accessed directly) or quantized (must be 211 // interpreted in conjunction with QuantizationParams). 212 // 213 // In practice though: 214 // float values are never quantized 215 // uint8 values are always quantized 216 // int32 values are sometimes quantized (depending on whether 217 // QuantizationParams are present). 218 // complex values are never quantized 219 // other types are never quantized at the moment. 220 // 221 // kNone means that we don't know the data type yet, or that we don't care 222 // because we'll be dropping the array anyway (e.g. some exotic array types 223 // may be involved only in debug-only subgraphs that we may not be interested 224 // in actually supporting). 225 enum class ArrayDataType : uint8 { 226 kNone, // 0 227 kBool, 228 kFloat, 229 kInt8, 230 kUint8, 231 kInt16, // 5 232 kUint16, 233 kInt32, 234 kUint32, 235 kInt64, 236 kUint64, // 10 237 kString, 238 kComplex64, 239 kFloat16, 240 kFloat64, 241 kComplex128, 242 }; 243 244 // Compile-time logic to map ArrayDataType to the corresponding C++ scalar type 245 template <ArrayDataType A> 246 struct DataTypeImpl {}; 247 template <> 248 struct DataTypeImpl<ArrayDataType::kNone> { 249 typedef int Type; 250 }; 251 template <> 252 struct DataTypeImpl<ArrayDataType::kBool> { 253 typedef bool Type; 254 }; 255 template <> 256 struct DataTypeImpl<ArrayDataType::kFloat> { 257 typedef float Type; 258 }; 259 template <> 260 struct DataTypeImpl<ArrayDataType::kInt8> { 261 typedef int8 Type; 262 }; 263 template <> 264 struct DataTypeImpl<ArrayDataType::kUint8> { 265 typedef uint8 Type; 266 }; 267 template <> 268 struct DataTypeImpl<ArrayDataType::kInt16> { 269 typedef int16 Type; 270 }; 271 template <> 272 struct DataTypeImpl<ArrayDataType::kUint16> { 273 typedef uint16 Type; 274 }; 275 template <> 276 struct DataTypeImpl<ArrayDataType::kInt32> { 277 typedef int32 Type; 278 }; 279 template <> 280 struct DataTypeImpl<ArrayDataType::kUint32> { 281 typedef uint32 Type; 282 }; 283 template <> 284 struct DataTypeImpl<ArrayDataType::kInt64> { 285 typedef int64_t Type; 286 }; 287 template <> 288 struct DataTypeImpl<ArrayDataType::kUint64> { 289 typedef uint64 Type; 290 }; 291 template <> 292 struct DataTypeImpl<ArrayDataType::kString> { 293 typedef std::string Type; 294 }; 295 template <> 296 struct DataTypeImpl<ArrayDataType::kComplex64> { 297 typedef std::complex<float> Type; 298 }; 299 300 template <ArrayDataType A> 301 using DataType = typename DataTypeImpl<A>::Type; 302 303 // Base class for type-specific buffer types. 304 struct GenericBuffer { 305 // Non-default-constructible: only ArrayDataType-specific subclass 306 // objects may be constructed. 307 GenericBuffer() = delete; 308 // Non-copyable-or-movable: we should only store pointers-to-Buffer 309 // in containers, not Operators themselves, so there should be no 310 // copy or move. 311 GenericBuffer(const GenericBuffer&) = delete; 312 GenericBuffer(const GenericBuffer&&) = delete; 313 314 // We need a virtual destructor so we can store pointers-to-Buffer 315 // in containers and have the containers call the right subclass destructor. 316 virtual ~GenericBuffer() {} 317 318 virtual int Length() const = 0; 319 320 const ArrayDataType type; 321 322 protected: 323 // Constructor used by subclasses for specific ArrayDataType's. 324 explicit GenericBuffer(ArrayDataType t) : type(t) {} 325 }; 326 327 // Type-specific buffer, containing type-specific storage. 328 template <ArrayDataType A> 329 struct Buffer : GenericBuffer { 330 Buffer() : GenericBuffer(A) {} 331 332 int Length() const override { return data.size(); } 333 334 std::vector<DataType<A>> data; 335 }; 336 337 class Shape { 338 public: 339 // For Shape, we stick to half-way encapsulation for now: 340 // we hide the raw dims_ member, but expose it raw by accessors 341 // because from some brainstorming, it's not at all easy to 342 // anticipate which flavor of more hermetic encapsulation would 343 // actually buy us future-proof-ness without being needlessly 344 // cumbersome. 345 Shape() {} 346 Shape(std::initializer_list<int> dim_list) : dims_(dim_list) {} 347 348 void ReplaceDims(std::initializer_list<int> dim_list) { 349 dims_ = std::vector<int>(dim_list); 350 } 351 352 const std::vector<int>& dims() const { return dims_; } 353 std::vector<int>* mutable_dims() { return &dims_; } 354 const int dimensions_count() const { return dims_.size(); } 355 356 // We still have that one convenience accessor to avoid 357 // the awkward double bracket issue: shape.dims()[i]. 358 int dims(int i) const { 359 // Always check for out-of-bounds accesses, even in optimized builds where 360 // standard assertions are disabled. Out-of-bounds access here is a common 361 // occurrence. 362 CHECK_GE(i, 0); 363 CHECK_GT(dims_.size(), i); 364 return dims_[i]; 365 } 366 367 bool operator==(const Shape& comp) const { 368 return (this->dims_ == comp.dims()); 369 } 370 371 bool operator!=(const Shape& comp) const { return !((*this) == comp); } 372 373 private: 374 std::vector<int> dims_; 375 }; 376 377 // Base class for all operator classes. 378 struct Operator { 379 // Non-default-constructible: only OperatorType-specific subclass 380 // objects may be constructed. 381 Operator() = delete; 382 // Non-copyable-or-movable: we should only store pointers-to-Operator 383 // in containers, not Operators themselves, so there should be no 384 // copy or move. 385 Operator(const Operator&) = delete; 386 Operator(const Operator&&) = delete; 387 388 // We need a virtual destructor so we can store pointers-to-Operator 389 // in containers and have the containers call the right subclass destructor. 390 virtual ~Operator() {} 391 392 // The specific type of operator. Corresponds 1:1 to subclasses. 393 const OperatorType type; 394 395 // The activation function that may be fused into this operator, 396 // or None if no activation function is fused. 397 FusedActivationFunctionType fused_activation_function; 398 399 // Input arrays: either activation arrays or constant array parameters. 400 // We refer to them by their name, not by their address; the mapping of 401 // names to addresses is given by the Model, which owns both Operator's and 402 // Array's. Thus, an Operator on its own doesn't contain much information, 403 // it is meant to be used in conjunction with the Model that owns it. 404 std::vector<std::string> inputs; 405 406 // Output activation arrays. Same comments as for inputs apply here too. 407 std::vector<std::string> outputs; 408 409 // If true, the operator has more outputs than are listed in the 'outputs' 410 // member. These need to be resolved by some graph transformation. 411 // This flag is only here to indicate that an operator should not be 412 // discarded as unused, even if from its 'outputs' member alone it 413 // looks unused. 414 bool unresolved_outputs = false; 415 416 // A serialized tensorflow::NodeDef string. 417 // The field is filled only when importing from TensorFlow. 418 // It's guaranteed to be filled for `TensorFlowUnsupportedOperator`. 419 // It's not guaranteed to be filled for other ops. Ops created by graph 420 // transformations won't have TensorFlow NodeDef. 421 std::string tensorflow_node_def; 422 423 protected: 424 // Constructor used by subclasses for specific OperatorType's. 425 explicit Operator(OperatorType t) 426 : type(t), 427 fused_activation_function(FusedActivationFunctionType::kNone) {} 428 }; 429 430 // Padding types for Conv-like operators. This is how padding is typically 431 // specified in model files. But for inference, we will need to resolve this 432 // to a FixedPadding, see below. 433 enum class PaddingType { kNone, kSame, kValid }; 434 435 // Padding as resolved for a specific layer shape, as needed for inference. 436 // For a given layer shape, a given padding type will resolve to a choice of 437 // a number of padding rows and columns, which we call the padding height and 438 // width respectively. 439 struct FixedPadding { 440 int width = 0; 441 int height = 0; 442 }; 443 444 // "Universal" padding struct containing both a generic PaddingType (as 445 // represented in a model file), and a FixedPadding (as needed for inference). 446 // The latter is resolved during the PropagateFixedSizes pass. 447 struct Padding { 448 FixedPadding& GetOrCreateFixedPadding() { 449 if (!fixed) { 450 FixedPadding* ptr = new FixedPadding; 451 fixed = std::unique_ptr<FixedPadding>(ptr); 452 } 453 return *fixed; 454 } 455 456 Padding() : type(PaddingType::kNone) {} 457 PaddingType type; 458 std::unique_ptr<FixedPadding> fixed; 459 }; 460 461 // "Convolutional" layer, as represented in model files. 462 // 463 // Inputs: 464 // inputs[0]: required: the input activations array 465 // inputs[1]: required: the Conv weights 466 // inputs[2]: optional: the bias vector, specifying the biases for each output 467 // channel. 468 // 469 // Outputs: 470 // outputs[0]: required: the output activations array 471 // outputs[1]: optional: the intermediate array of im2col-replicated input 472 // activations. Present when targeting implementations 473 // of Conv layers as Im2col+GEMM. 474 // 475 // TensorFlow equivalent: Conv2D 476 struct ConvOperator : Operator { 477 ConvOperator() : Operator(OperatorType::kConv) {} 478 Padding padding; 479 int stride_width = 0; 480 int stride_height = 0; 481 // A dilation_rate of 0 is invalid and this field is an optional attribute. 482 // Thus initializing it to 1 to allow default conv behavior when the 483 // attribute is not present. 484 int dilation_width_factor = 1; 485 int dilation_height_factor = 1; 486 }; 487 488 // CTCBeamSearchDecoder operator: 489 // 490 // Inputs: 491 // inputs[0]: required: the logits. 492 // inputs[1]: required: sequence length. 493 // inputs[2]: optional: beam width. 494 // inputs[3]: optional: top paths. 495 // inputs[4]: optional: merge repeated. 496 // 497 // Outputs: 498 // outputs[0]: decoded. 499 // outputs[1]: log probability. 500 // 501 // TensorFlow equivalent: CTCBeamSearchDecoder 502 struct CTCBeamSearchDecoderOperator : Operator { 503 CTCBeamSearchDecoderOperator() 504 : Operator(OperatorType::kCTCBeamSearchDecoder) {} 505 int beam_width; 506 int top_paths; 507 bool merge_repeated = true; 508 }; 509 510 // Depthwise-separable convolution operator. 511 // 512 // Inputs: 513 // inputs[0]: required: the input activations array 514 // inputs[1]: required: the DepthwiseConv weights 515 // inputs[2]: optional: the bias vector, specifying the biases for each output 516 // channel. 517 // 518 // TensorFlow equivalent: DepthwiseConv2dNative 519 struct DepthwiseConvOperator : Operator { 520 DepthwiseConvOperator() : Operator(OperatorType::kDepthwiseConv) {} 521 Padding padding; 522 int stride_height = 0; 523 int stride_width = 0; 524 int depth_multiplier = 0; 525 // A dilation_rate of 0 is invalid and this field is an optional attribute. 526 // Thus initializing it to 1 to allow default conv behavior when the 527 // attribute is not present. 528 int dilation_width_factor = 1; 529 int dilation_height_factor = 1; 530 }; 531 532 // Depth-to-space transform operator. 533 // 534 // Inputs: 535 // inputs[0]: required: the input activations array 536 // 537 // TensorFlow equivalent: DepthToSpace 538 struct DepthToSpaceOperator : Operator { 539 DepthToSpaceOperator() : Operator(OperatorType::kDepthToSpace) {} 540 int block_size = 0; 541 }; 542 543 // Space-to-depth transform operator. 544 // 545 // Inputs: 546 // inputs[0]: required: the input activations array 547 // 548 // TensorFlow equivalent: SpaceToDepth 549 struct SpaceToDepthOperator : Operator { 550 SpaceToDepthOperator() : Operator(OperatorType::kSpaceToDepth) {} 551 int block_size = 0; 552 }; 553 554 // Fully-connected operator. 555 // 556 // Inputs: 557 // inputs[0]: required: the input activations array 558 // inputs[1]: required: the FullyConnected weights 559 // inputs[2]: optional: the bias vector, specifying the biases for each output 560 // channel. 561 // 562 // TensorFlow equivalent: a pair consisting of a Reshape node reshaping the 563 // input activations as a matrix, followed by a MatMul node. 564 struct FullyConnectedOperator : Operator { 565 FullyConnectedOperator() : Operator(OperatorType::kFullyConnected) {} 566 FullyConnectedWeightsFormat weights_format = 567 FullyConnectedWeightsFormat::kDefault; 568 569 // `keep_num_dims` is supported in the FullyConnected kernel version 5, but 570 // it's never supported by Toco. 571 bool keep_num_dims = false; 572 }; 573 574 // Dequantization operator, converting a quantized array of integers with 575 // quantization parameters specifying how these integers correspond to real 576 // numbers 577 // (see QuantizationParams) to an output activations array of floating-point 578 // values. 579 // 580 // In floating-point image models, there is typically a Dequantization operator 581 // at the very beginning, converting the input image RGB data, consisting of 582 // uint8 integer values, to floating-point input activations. That is where 583 // image model parameters such as "mean_value" and "std_value" are typically 584 // handled. 585 // 586 // This is the only operator type that converts from quantized to 587 // floating-point, 588 // and there is at the moment no operator type at all to convert from 589 // floating-point 590 // to quantized. Every other operator does either float->float or 591 // quantized->quantized. 592 // 593 // Inputs: 594 // inputs[0]: required: the input quantized activations array 595 // 596 // TensorFlow equivalent: Dequantize 597 struct DequantizeOperator : Operator { 598 DequantizeOperator() : Operator(OperatorType::kDequantize) {} 599 }; 600 601 // Numeric verification operator, converting a quantized array of integers with 602 // quantization parameters specifying how these integers correspond to real 603 // numbers 604 // (see QuantizationParams) and verify them with an array of floating-point 605 // values. 606 607 // Inputs: 608 // inputs[0]: required: the input quantized activations array 609 // inputs[1]: required: the input reference activations array 610 // 611 // TensorFlow equivalent: Dequantize 612 struct NumericVerifyOperator : Operator { 613 NumericVerifyOperator() : Operator(OperatorType::kNumericVerify) {} 614 }; 615 616 // Batch-normalization operator. 617 // 618 // We only support batch-normalization using pre-learned moments, so this is 619 // just 620 // computing (input - mean) * multiplier + offset. As such, this can be 621 // expressed as a combination of Add and Mul nodes, and indeed this is how 622 // we break it down during tooling for the purpose of fusing it into 623 // other operators. 624 // 625 // Inputs: 626 // inputs[0]: required: the input activations array 627 // inputs[1]: required: the learned mean array 628 // inputs[2]: required: the learned multiplier array 629 // inputs[3]: required: the learned offset array 630 // 631 // TensorFlow equivalent: a combination of Add and Mul nodes 632 struct BatchNormalizationOperator : Operator { 633 BatchNormalizationOperator() 634 : Operator(OperatorType::kBatchNormalization), 635 global_normalization(false) {} 636 bool global_normalization; 637 }; 638 639 // L2-normalization operator. 640 // 641 // Inputs: 642 // inputs[0]: required: the input activations array 643 // 644 // TensorFlow equivalent: none. In TensorFlow, L2 normalization is implemented 645 // by a sub-graph of operators implementing L2-normalization 646 // from lower-level arithmetic nodes; during tooling, we identify such 647 // sub-graphs 648 // and replace them by L2NormalizationOperator's. See IdentifyL2Normalization. 649 struct L2NormalizationOperator : Operator { 650 L2NormalizationOperator() : Operator(OperatorType::kL2Normalization) {} 651 }; 652 653 // LSTM Cell operator. 654 // 655 // Inputs: 656 // inputs[0]: required: the input data array 657 // inputs[1]: required: the previous output activations array 658 // inputs[2]: required: the learned weights array 659 // inputs[3]: required: the learned biases array 660 // inputs[4]: required: the previous output state 661 // outputs[0]: required: the output activations array 662 // outputs[1]: required: the new state array 663 // 664 // TensorFlow equivalent: none. In TensorFlow, an LSTM is implemented 665 // with a sub-graph of lower-level arithmetic nodes; during tooling, we identify 666 // such sub-graphs and replace them with LstmCells. See IdentifyLstmCell(). 667 struct LstmCellOperator : Operator { 668 enum Inputs { 669 DATA_INPUT = 0, 670 PREV_ACTIV_INPUT = 1, 671 WEIGHTS_INPUT = 2, 672 BIASES_INPUT = 3, 673 PREV_STATE_INPUT = 4, 674 NUM_INPUTS = 5 675 }; 676 enum Outputs { 677 ACTIV_OUTPUT = 0, 678 STATE_OUTPUT = 1, 679 CONCAT_TEMP = 2, 680 ACTIV_TEMP = 3, 681 NUM_OUTPUTS = 4 682 }; 683 enum KernelType { 684 KERNEL_BASIC = 0, 685 KERNEL_FULL = 1, 686 }; 687 688 LstmCellOperator() 689 : Operator(OperatorType::kLstmCell), kernel_type(KERNEL_BASIC) {} 690 691 KernelType kernel_type; 692 }; 693 694 struct UnidirectionalSequenceLstmOperator : Operator { 695 UnidirectionalSequenceLstmOperator() 696 : Operator(OperatorType::kUnidirectionalSequenceLstm) {} 697 }; 698 699 struct BidirectionalSequenceLstmOperator : Operator { 700 BidirectionalSequenceLstmOperator() 701 : Operator(OperatorType::kBidirectionalSequenceLstm) {} 702 bool merge_outputs; 703 }; 704 705 struct BidirectionalSequenceRnnOperator : Operator { 706 BidirectionalSequenceRnnOperator() 707 : Operator(OperatorType::kBidirectionalSequenceRnn) {} 708 bool merge_outputs; 709 }; 710 711 // Element-wise multiplication operator. 712 // 713 // Inputs: 714 // inputs[0]: required: the left-hand side array 715 // inputs[1]: required: the right-hand side array 716 // 717 // TensorFlow equivalent: Mul 718 struct MulOperator : Operator { 719 MulOperator() : Operator(OperatorType::kMul) {} 720 }; 721 722 // Element-wise Abs operator: 723 // x -> abs(x) 724 // 725 // Inputs: 726 // inputs[0]: required: the input array 727 // 728 // TensorFlow equivalent: abs 729 struct AbsOperator : Operator { 730 AbsOperator() : Operator(OperatorType::kAbs) {} 731 }; 732 733 // Element-wise HardSwish operator: 734 // x -> x * relu6(x+3)/6 735 // 736 // Inputs: 737 // inputs[0]: required: the input array 738 // 739 // TensorFlow equivalent: hard_swish 740 struct HardSwishOperator : Operator { 741 HardSwishOperator() : Operator(OperatorType::kHardSwish) {} 742 }; 743 744 // Elu 745 // f(x) -> exp(x) - 1 for x < 0, x for x >= 0. 746 // 747 // Inputs: 748 // inputs[0]: required: the input array 749 // 750 // TensorFlow equivalent: Elu 751 struct EluOperator : Operator { 752 EluOperator() : Operator(OperatorType::kElu) {} 753 }; 754 755 // Element-wise Relu operator: 756 // x -> max(0, x) 757 // 758 // Inputs: 759 // inputs[0]: required: the input array 760 // 761 // TensorFlow equivalent: Relu 762 struct ReluOperator : Operator { 763 ReluOperator() : Operator(OperatorType::kRelu) {} 764 }; 765 766 // Element-wise Relu1 operator: 767 // x -> min(max(x, -1), 1) 768 // 769 // Inputs: 770 // inputs[0]: required: the input array 771 // 772 // TensorFlow equivalent: none. We can construct the operator with Minimum 773 // and Maximum operations 774 struct Relu1Operator : Operator { 775 Relu1Operator() : Operator(OperatorType::kRelu1) {} 776 }; 777 778 // Element-wise Relu6 operator: 779 // x -> max(0, min(6, x)) 780 // 781 // Inputs: 782 // inputs[0]: required: the input array 783 // 784 // TensorFlow equivalent: Relu6 785 struct Relu6Operator : Operator { 786 Relu6Operator() : Operator(OperatorType::kRelu6) {} 787 }; 788 789 // PRelu 790 // f(x) = alpha * x for x < 0, f(x) = x for x >= 0. 791 // 792 // Inputs: 793 // inputs[0]: required: the input array 794 // inputs[1]: required: the alpha array 795 // 796 // Equivalent to keras.layers.PReLU. 797 struct PReluOperator : Operator { 798 PReluOperator() : Operator(OperatorType::kPRelu) {} 799 }; 800 801 // LeakyRelu 802 // x -> max(x, alpha * x) 803 // 804 // Inputs: 805 // inputs[0]: required: the input array 806 // 807 // TensorFlow equivalent: LeakyRelu 808 struct LeakyReluOperator : Operator { 809 LeakyReluOperator() : Operator(OperatorType::kLeakyRelu) {} 810 811 float alpha = 0.2f; // 0.2 matches the default value for the TF op attribute. 812 }; 813 814 // Element-wise Logistic operator: 815 // x -> Logistic(x) = 1 / (1 + exp(-x)) 816 // 817 // Inputs: 818 // inputs[0]: required: the input array 819 // 820 // TensorFlow equivalent: Sigmoid 821 struct LogisticOperator : Operator { 822 LogisticOperator() : Operator(OperatorType::kLogistic) {} 823 }; 824 825 // Element-wise natural log operator: 826 // x -> ln(x) 827 // 828 // Inputs: 829 // inputs[0]: required: the input array 830 // 831 // TensorFlow equivalent: Log 832 struct LogOperator : Operator { 833 LogOperator() : Operator(OperatorType::kLog) {} 834 }; 835 836 // Element-wise Tanh operator: 837 // x -> Tanh(x) = (exp(x) - exp(-x)) / (exp(x) + exp(-x)) 838 // 839 // Inputs: 840 // inputs[0]: required: the input array 841 // 842 // TensorFlow equivalent: Tanh 843 struct TanhOperator : Operator { 844 TanhOperator() : Operator(OperatorType::kTanh) {} 845 }; 846 847 // Element-wise Sin operator: 848 // x -> Sin(x) = sin(x) 849 // 850 // Inputs: 851 // inputs[0]: required: the input array 852 // 853 // TensorFlow equivalent: Sin 854 struct SinOperator : Operator { 855 SinOperator() : Operator(OperatorType::kSin) {} 856 }; 857 858 // Element-wise addition operator. 859 // 860 // Inputs: 861 // inputs[0]: required: the left-hand side array 862 // inputs[1]: required: the right-hand side array 863 // 864 // TensorFlow equivalent: Add 865 struct AddOperator : Operator { 866 AddOperator() : Operator(OperatorType::kAdd) {} 867 }; 868 869 // Element-wise addition operator for N inputs. 870 // 871 // Inputs: 872 // inputs[i]: The i-th array to add together to form the output. 873 // 874 // TensorFlow equivalent: AddN 875 struct AddNOperator : Operator { 876 AddNOperator() : Operator(OperatorType::kAddN) {} 877 }; 878 879 // Concatenation operator: concatenates its inputs 880 // along the axis. 881 // 882 // Inputs: this operator accepts any number >= 1 of inputs. 883 // inputs[i]: the i-th array to concatenate. 884 // 885 // TensorFlow equivalent: Concat. 886 struct ConcatenationOperator : Operator { 887 ConcatenationOperator() : Operator(OperatorType::kConcatenation) {} 888 int axis = 0; 889 }; 890 891 // Reordering dimensions. Used only during tooling to transform graphs from 892 // the TensorFlow format. 893 // 894 // Inputs: 895 // inputs[0]: required: the input array 896 // 897 // TensorFlow equivalent: none. This is only useful to convert between formats. 898 struct ReorderAxesOperator : Operator { 899 ReorderAxesOperator() : Operator(OperatorType::kReorderAxes) {} 900 AxesOrder input_axes_order; 901 AxesOrder output_axes_order; 902 }; 903 904 // Average-pooling operator. 905 // 906 // Inputs: 907 // inputs[0]: required: the input array 908 // 909 // TensorFlow equivalent: AveragePool 910 struct AveragePoolOperator : Operator { 911 AveragePoolOperator() : Operator(OperatorType::kAveragePool) {} 912 Padding padding; 913 int stride_height = 0; 914 int stride_width = 0; 915 int kheight = 0; 916 int kwidth = 0; 917 }; 918 919 // Local response normalization operator. 920 // 921 // Inputs: 922 // inputs[0]: required: the input array 923 // 924 // TensorFlow equivalent: LRN 925 struct LocalResponseNormalizationOperator : Operator { 926 LocalResponseNormalizationOperator() 927 : Operator(OperatorType::kLocalResponseNormalization) {} 928 929 int range = 0; 930 float bias = 0.f; 931 float alpha = 0.f; 932 float beta = 0.f; 933 }; 934 935 // Max-pooling operator. 936 // 937 // Inputs: 938 // inputs[0]: required: the input array 939 // 940 // TensorFlow equivalent: MaxPool 941 struct MaxPoolOperator : Operator { 942 MaxPoolOperator() : Operator(OperatorType::kMaxPool) {} 943 Padding padding; 944 int stride_height = 0; 945 int stride_width = 0; 946 int kheight = 0; 947 int kwidth = 0; 948 }; 949 950 // L2-pooling operator. 951 // 952 // Inputs: 953 // inputs[0]: required: the input array 954 // 955 // TensorFlow equivalent: none. Can be shimmed by squaring+avgpool+sqrt. 956 struct L2PoolOperator : Operator { 957 L2PoolOperator() : Operator(OperatorType::kL2Pool) {} 958 Padding padding; 959 int stride_height = 0; 960 int stride_width = 0; 961 int kheight = 0; 962 int kwidth = 0; 963 }; 964 965 // The expected [min, max] range of values in a given array. 966 // Used for quantization only. 967 // This information typically comes from special nodes found in quantized 968 // models, see FakeQuantOperator, and is used during quantization to resolve 969 // actual quantization parameters (see QuantizationParams). 970 struct MinMax { 971 double min = 0.; 972 double max = 0.; 973 }; 974 975 inline bool operator==(const MinMax& m1, const MinMax& m2) { 976 return m1.min == m2.min && m1.max == m2.max; 977 } 978 979 inline bool operator!=(const MinMax& m1, const MinMax& m2) { 980 return m1.min != m2.min || m1.max != m2.max; 981 } 982 983 // Fake-quantization operator. This does two things: 984 // - Annotate its input and output arrays with MinMax information, 985 // - Arithmetic-wise, this operator rounds incoming activation values 986 // to the nearest representable value on the scale of 256 987 // values from the min to the max value dictated by its MinMax info. 988 // 989 // Inputs: 990 // inputs[0]: required: the input array 991 // inputs[1]: optional: the 'min' value, if it has not yet been resolved 992 // to a constant. 993 // inputs[2]: optional: the 'max' value, if it has not yet been resolved 994 // to a constant. 995 // 996 // TensorFlow equivalent: FakeQuantWithMinMaxVars, FakeQuantWithMinMaxArgs. 997 struct FakeQuantOperator : Operator { 998 FakeQuantOperator() : Operator(OperatorType::kFakeQuant) {} 999 std::unique_ptr<MinMax> minmax; 1000 int num_bits = 8; 1001 bool narrow_range = false; 1002 }; 1003 1004 // Element-wise division operator. 1005 // 1006 // Inputs: 1007 // inputs[0]: required: the left-hand side array 1008 // inputs[1]: required: the right-hand side array 1009 // 1010 // TensorFlow equivalent: Div 1011 struct DivOperator : Operator { 1012 DivOperator() : Operator(OperatorType::kDiv) {} 1013 }; 1014 1015 // Element-wise identity (x->x) operator. 1016 // 1017 // Inputs: 1018 // inputs[0]: required: the input array 1019 // 1020 // TensorFlow equivalent: Identity 1021 struct TensorFlowIdentityOperator : Operator { 1022 TensorFlowIdentityOperator() : Operator(OperatorType::kIdentity) {} 1023 }; 1024 1025 // Batch matrix multiplication operator. This comes from a tf.matmul where one 1026 // of the operands has rank 3 or more. 1027 // 1028 // Inputs: 1029 // inputs[0]: required: the left-hand side matrix 1030 // inputs[1]: required: the right-hand side matrix 1031 // 1032 // TensorFlow equivalent: MatMul 1033 struct BatchMatMulOperator : Operator { 1034 BatchMatMulOperator() : Operator(OperatorType::kBatchMatMul) {} 1035 bool adj_x = false; 1036 bool adj_y = false; 1037 }; 1038 1039 // General matrix multiplication operator. We don't want to support general 1040 // matrix multiplication at inference time, so we resolve it during tooling 1041 // to more specific operator types, namely, FullyConnected. 1042 // 1043 // Inputs: 1044 // inputs[0]: required: the left-hand side matrix 1045 // inputs[1]: required: the right-hand side matrix 1046 // 1047 // TensorFlow equivalent: MatMul 1048 struct TensorFlowMatMulOperator : Operator { 1049 TensorFlowMatMulOperator() : Operator(OperatorType::kMatMul) {} 1050 bool transpose_a = false; 1051 bool transpose_b = false; 1052 }; 1053 1054 // Padding operator. Pads a tensor with zeros. 1055 // 1056 // Inputs: 1057 // inputs[0]: required: the input array 1058 // inputs[1]: required: the padding array 1059 // 1060 // This operation pads a `input` with zeros according to the `paddings` you 1061 // specify. `paddings` is an integer tensor with shape `[Dn, 2]`, where n is the 1062 // rank of `input`. For each dimension D of `input`, `paddings[D, 0]` indicates 1063 // how many zeros to add before the contents of `input` in that dimension, and 1064 // `paddings[D, 1]` indicates how many zeros to add after the contents of 1065 // `input` in that dimension. 1066 // 1067 // TensorFlow equivalent: Pad 1068 struct PadOperator : Operator { 1069 PadOperator() : Operator(OperatorType::kPad) {} 1070 1071 std::vector<int> left_padding; 1072 std::vector<int> right_padding; 1073 }; 1074 1075 // PaddingV2 operator. Pads a tensor with the given constant value. 1076 // 1077 // Inputs: 1078 // inputs[0]: required: the input array 1079 // inputs[1]: required: the padding array 1080 // inputs[2]: required: the scalar constant_values 1081 // 1082 // This operation pads input according to the paddings and constant_values you 1083 // specify. paddings is an integer tensor with shape [Dn, 2], where n is the 1084 // rank of input. For each dimension D of input, paddings[D, 0] indicates how 1085 // many padding values to add before the contents of input in that dimension, 1086 // and paddings[D, 1] indicates how many padding values to add after the 1087 // contents of input in that dimension. constant_values is a scalar tensor of 1088 // the same type as input that indicates the value to use for padding input. 1089 // 1090 // TensorFlow equivalent: PadV2 1091 struct PadV2Operator : Operator { 1092 PadV2Operator() : Operator(OperatorType::kPadV2) {} 1093 1094 std::vector<int> left_padding; 1095 std::vector<int> right_padding; 1096 }; 1097 1098 // Strided slice operator. 1099 // 1100 // Inputs: 1101 // inputs[0]: required: the input array 1102 // inputs[1]: required: the begin array 1103 // inputs[2]: required: the end array 1104 // inputs[3]: optional: the strides array 1105 // 1106 // TensorFlow equivalent: StridedSlice 1107 struct StridedSliceOperator : Operator { 1108 StridedSliceOperator() : Operator(OperatorType::kStridedSlice) {} 1109 1110 std::vector<int> start_indices; 1111 std::vector<int> stop_indices; 1112 std::vector<int> strides; 1113 1114 int begin_mask; 1115 int ellipsis_mask; 1116 int end_mask; 1117 int new_axis_mask; 1118 int shrink_axis_mask; 1119 1120 StridedSliceOperator(const StridedSliceOperator& other) 1121 : Operator(OperatorType::kStridedSlice) { 1122 inputs = other.inputs; 1123 outputs = other.outputs; 1124 1125 start_indices = other.start_indices; 1126 stop_indices = other.stop_indices; 1127 strides = other.strides; 1128 1129 begin_mask = other.begin_mask; 1130 ellipsis_mask = other.ellipsis_mask; 1131 end_mask = other.end_mask; 1132 new_axis_mask = other.new_axis_mask; 1133 shrink_axis_mask = other.shrink_axis_mask; 1134 } 1135 1136 void PadIndices(int dim_count) { 1137 // Add indices and mask bits to fully include extra dimensions 1138 CHECK_GE(dim_count, start_indices.size()); 1139 CHECK_EQ(start_indices.size(), stop_indices.size()); 1140 CHECK_EQ(stop_indices.size(), strides.size()); 1141 1142 for (int i = start_indices.size(); i < dim_count; i++) { 1143 start_indices.push_back(0); 1144 stop_indices.push_back(0); 1145 strides.push_back(1); 1146 begin_mask |= 1 << i; 1147 end_mask |= 1 << i; 1148 } 1149 } 1150 1151 void ReverseIndices() { 1152 CHECK_EQ(start_indices.size(), stop_indices.size()); 1153 CHECK_EQ(stop_indices.size(), strides.size()); 1154 1155 std::reverse(start_indices.begin(), start_indices.end()); 1156 std::reverse(stop_indices.begin(), stop_indices.end()); 1157 std::reverse(strides.begin(), strides.end()); 1158 1159 begin_mask = toco::port::ReverseBits32(static_cast<uint32>(begin_mask)) >> 1160 (32 - start_indices.size()); 1161 ellipsis_mask = 1162 toco::port::ReverseBits32(static_cast<uint32>(ellipsis_mask)) >> 1163 (32 - start_indices.size()); 1164 end_mask = toco::port::ReverseBits32(static_cast<uint32>(end_mask)) >> 1165 (32 - start_indices.size()); 1166 new_axis_mask = 1167 toco::port::ReverseBits32(static_cast<uint32>(new_axis_mask)) >> 1168 (32 - start_indices.size()); 1169 shrink_axis_mask = 1170 toco::port::ReverseBits32(static_cast<uint32>(shrink_axis_mask)) >> 1171 (32 - start_indices.size()); 1172 } 1173 }; 1174 1175 // Reshaping operator, reshaping its input array to a two-dimensional shape 1176 // (a "matrix"). This is used in the TensorFlow format, in conjunction with 1177 // MatMul nodes, to implement fully-connected layers. 1178 // 1179 // Inputs: 1180 // inputs[0]: required: the input array 1181 // inputs[1]: optional: the output tensor shape 1182 // 1183 // TensorFlow equivalent: Reshape --- except that we only support a special case 1184 // here, where the output shape is a matrix (2D) shape. 1185 struct TensorFlowReshapeOperator : Operator { 1186 TensorFlowReshapeOperator() : Operator(OperatorType::kReshape) {} 1187 std::vector<int> shape; 1188 }; 1189 1190 // Removes dimensions of size 1 from the shape of a tensor. 1191 // https://www.tensorflow.org/api_docs/python/tf/squeeze 1192 // 1193 // Inputs: 1194 // inputs[0]: required: the input array 1195 // 1196 // TensorFlow equivalent: Squeeze 1197 struct SqueezeOperator : Operator { 1198 SqueezeOperator() : Operator(OperatorType::kSqueeze) {} 1199 1200 std::vector<int> squeeze_dims; 1201 }; 1202 1203 // Inputs: 1204 // inputs[0]: required: the output shape 1205 // inputs[1]: required: the weights 1206 // inputs[2]: required: the input activations array 1207 // inputs[3]: optional: the bias vector, specifying the biases for each output 1208 // channel. 1209 // NOTE: The input activations is NOT the first input. 1210 // 1211 // 1212 // Outputs: 1213 // outputs[0]: required: the output activations array 1214 // 1215 // TensorFlow equivalent: Conv2DBackpropInput 1216 struct TransposeConvOperator : Operator { 1217 enum Inputs { 1218 OUTPUT_SHAPE = 0, 1219 WEIGHTS = 1, 1220 DATA_INPUT = 2, 1221 BIAS = 3, 1222 }; 1223 1224 TransposeConvOperator() : Operator(OperatorType::kTransposeConv) {} 1225 Padding padding; 1226 int stride_width = 0; 1227 int stride_height = 0; 1228 // Dilation is possible with transpose convolution, but Tensorflow does not 1229 // currently support it, so we omit it. 1230 }; 1231 1232 // Given a tensor input, this operation calculates element-wise exponential 1233 // (y = e^x). 1234 // 1235 // Inputs: 1236 // inputs[0]: required: input tensor 1237 // 1238 // TensorFlow equivalent: Exp 1239 struct ExpOperator : Operator { 1240 ExpOperator() : Operator(OperatorType::kExp) {} 1241 }; 1242 1243 // Given a tensor input, this operation calculates element-wise exponential 1244 // (y = cos(x)). 1245 // 1246 // Inputs: 1247 // inputs[0]: required: input tensor 1248 // 1249 // TensorFlow equivalent: Cos 1250 struct CosOperator : Operator { 1251 CosOperator() : Operator(OperatorType::kCos) {} 1252 }; 1253 1254 // Given a tensor input, this operation inserts a dimension of 1 at the 1255 // dimension index axis of input's shape. The dimension index axis starts at 1256 // zero; if you specify a negative number for axis it is counted backward from 1257 // the end. 1258 // 1259 // Inputs: 1260 // inputs[0]: required: input tensor 1261 // inputs[1]: required: 0-D (scalar). Specifies the dimension index at which 1262 // to expand the shape of input 1263 // 1264 // TensorFlow equivalent: ExpandDims 1265 struct ExpandDimsOperator : Operator { 1266 ExpandDimsOperator() : Operator(OperatorType::kExpandDims) {} 1267 }; 1268 1269 // Creates a tensor of shape dims and fills it with the given scalar value. 1270 // Output type will be the same as the given scalar value. 1271 // 1272 // Inputs: 1273 // inputs[0]: required: 1-D (int32) - the shape of the output tensor 1274 // inputs[1]: required: 0-D (scalar) - value to fill the tensor with 1275 // 1276 // TensorFlow equivalent: Fill 1277 struct FillOperator : Operator { 1278 FillOperator() : Operator(OperatorType::kFill) {} 1279 }; 1280 1281 // Element-wise floor division operator. 1282 // 1283 // Inputs: 1284 // inputs[0]: required: the left-hand side array 1285 // inputs[1]: required: the right-hand side array 1286 // 1287 // TensorFlow equivalent: FloorDiv 1288 struct FloorDivOperator : Operator { 1289 FloorDivOperator() : Operator(OperatorType::kFloorDiv) {} 1290 }; 1291 1292 // Element-wise floor mod operator. 1293 // 1294 // Inputs: 1295 // inputs[0]: required: the left-hand side array 1296 // inputs[1]: required: the right-hand side array 1297 // 1298 // TensorFlow equivalent: FloorMod 1299 struct FloorModOperator : Operator { 1300 FloorModOperator() : Operator(OperatorType::kFloorMod) {} 1301 }; 1302 1303 struct RandomUniformOperator : Operator { 1304 RandomUniformOperator() : Operator(OperatorType::kRandomUniform) {} 1305 ArrayDataType dtype = ArrayDataType::kNone; 1306 int64_t seed; 1307 int64_t seed2; 1308 }; 1309 1310 // Creates a sequence of numbers that begins at start and extends by increments 1311 // of delta up to but not including limit. 1312 // 1313 // The dtype of the resulting tensor is inferred from the inputs unless it is 1314 // provided explicitly. 1315 // 1316 // Inputs: 1317 // inputs[0]: required: the start 1318 // inputs[1]: required: the limit 1319 // inputs[2]: required: the delta 1320 // 1321 // TensorFlow equivalent: Range 1322 struct RangeOperator : Operator { 1323 RangeOperator() : Operator(OperatorType::kRange) {} 1324 ArrayDataType dtype = ArrayDataType::kNone; 1325 }; 1326 1327 // Rank operator. Extracts the rank of the tensor. 1328 // 1329 // Inputs: 1330 // inputs[0]: required: the input array 1331 // 1332 // This operation outputs a 0-D int32 Tensor representing the rank of input. 1333 // 1334 // TensorFlow equivalent: Rank. 1335 struct TensorFlowRankOperator : Operator { 1336 TensorFlowRankOperator() : Operator(OperatorType::kRank) {} 1337 ArrayDataType output_data_type = ArrayDataType::kInt32; 1338 }; 1339 1340 // Element-wise negation (-x) operator. 1341 // 1342 // Inputs: 1343 // inputs[0]: required: the input array 1344 // 1345 // TensorFlow equivalent: Neg 1346 struct NegOperator : Operator { 1347 NegOperator() : Operator(OperatorType::kNeg) {} 1348 }; 1349 1350 // Element-wise select operator choosing elements from inputs[1] or input[2] 1351 // 1352 // Inputs: 1353 // inputs[0]: required: boolean mask per index 1354 // inputs[1]: required: tensor of values if true 1355 // inputs[2]: required: tensor of values if false 1356 // 1357 // TensorFlow equivalent: Select 1358 struct SelectOperator : Operator { 1359 SelectOperator() : Operator(OperatorType::kSelect) {} 1360 }; 1361 1362 // Element-wise reciprocal-square-root (x^-0.5) operator. 1363 // 1364 // Inputs: 1365 // inputs[0]: required: the input array 1366 // 1367 // TensorFlow equivalent: Rsqrt 1368 struct TensorFlowRsqrtOperator : Operator { 1369 TensorFlowRsqrtOperator() : Operator(OperatorType::kRsqrt) {} 1370 }; 1371 1372 // Stacks a list of rank-R tensors into one rank-(R+1) tensor. 1373 // 1374 // Packs the list of tensors in values into a tensor with rank one higher than 1375 // each tensor in values, by packing them along the axis dimension. Given a list 1376 // of length N of tensors of shape (A, B, C);. 1377 // 1378 // Inputs: this operator accepts any number >= 1 of inputs. 1379 // inputs[i]: the i-th array to merge. 1380 // 1381 // TensorFlow equivalent: Pack 1382 struct PackOperator : Operator { 1383 PackOperator() : Operator(OperatorType::kPack) {} 1384 int values_count; 1385 int axis = 0; 1386 ArrayDataType dtype = ArrayDataType::kNone; 1387 }; 1388 1389 // Shape operator. Extracts the shape of the tensor. 1390 // 1391 // Inputs: 1392 // inputs[0]: required: the input array 1393 // 1394 // This operation outputs a 1-D integer tensor representing the shape of 1395 // the input. 1396 // 1397 // TensorFlow equivalent: Shape. 1398 struct TensorFlowShapeOperator : Operator { 1399 TensorFlowShapeOperator() : Operator(OperatorType::kShape) {} 1400 ArrayDataType output_data_type = ArrayDataType::kInt32; 1401 }; 1402 1403 // Element-wise square-root (x^0.5) operator. 1404 // 1405 // Inputs: 1406 // inputs[0]: required: the input array 1407 // 1408 // TensorFlow equivalent: Sqrt 1409 struct TensorFlowSqrtOperator : Operator { 1410 TensorFlowSqrtOperator() : Operator(OperatorType::kSqrt) {} 1411 }; 1412 1413 // Element-wise square (x*x) operator. 1414 // 1415 // Inputs: 1416 // inputs[0]: required: the input array 1417 // 1418 // TensorFlow equivalent: Square 1419 struct TensorFlowSquareOperator : Operator { 1420 TensorFlowSquareOperator() : Operator(OperatorType::kSquare) {} 1421 }; 1422 1423 // Element-wise squared difference ((x-y)*(x-y)) operator. 1424 // 1425 // Inputs: 1426 // inputs[0]: required: the left-hand side array 1427 // inputs[1]: required: the right-hand side array 1428 // 1429 // TensorFlow equivalent: SquaredDifference 1430 struct SquaredDifferenceOperator : Operator { 1431 SquaredDifferenceOperator() : Operator(OperatorType::kSquaredDifference) {} 1432 }; 1433 1434 // Transposes a tensor. 1435 // 1436 // By default, this operation performs a regular matrix transpose on 2-D input 1437 // tensors. 1438 // 1439 // Inputs: 1440 // inputs[0]: required: the input array 1441 // 1442 // TensorFlow equivalent: Transpose 1443 struct TransposeOperator : Operator { 1444 TransposeOperator() : Operator(OperatorType::kTranspose) {} 1445 std::vector<int> perm; 1446 }; 1447 1448 // Element-wise subtraction operator. 1449 // 1450 // Inputs: 1451 // inputs[0]: required: the left-hand side array 1452 // inputs[1]: required: the right-hand side array 1453 // 1454 // TensorFlow equivalent: Sub 1455 struct SubOperator : Operator { 1456 SubOperator() : Operator(OperatorType::kSub) {} 1457 }; 1458 1459 // Sum reduction: computes the sum of all of entries across the axes. 1460 // 1461 // Inputs: 1462 // inputs[0]: required: the input array 1463 // 1464 // TensorFlow equivalent: Sum 1465 struct TensorFlowSumOperator : Operator { 1466 TensorFlowSumOperator() : Operator(OperatorType::kSum) {} 1467 std::vector<int> axis; 1468 bool keep_dims = false; 1469 }; 1470 1471 // Prod reduction: computes the product of all of entries across the axes. 1472 // 1473 // Inputs: 1474 // inputs[0]: required: the input array 1475 // 1476 // TensorFlow equivalent: Prod 1477 struct TensorFlowProdOperator : Operator { 1478 TensorFlowProdOperator() : Operator(OperatorType::kReduceProd) {} 1479 std::vector<int> axis; 1480 bool keep_dims = false; 1481 }; 1482 1483 // TensorFlow Tile equivalent. Refer to TensorFlow documentation for details. 1484 // 1485 // Inputs: 1486 // inputs[0]: required: the input array 1487 // inputs[1]: required: int array with length of rank(input[0]) 1488 struct TensorFlowTileOperator : Operator { 1489 TensorFlowTileOperator() : Operator(OperatorType::kTile) {} 1490 }; 1491 1492 // TensorFlow Slice equivalent. Refer to TensorFlow documentation for details. 1493 struct SliceOperator : Operator { 1494 SliceOperator() : Operator(OperatorType::kSlice) {} 1495 1496 std::vector<int> begin; 1497 std::vector<int> size; 1498 }; 1499 1500 // TensorFlow Split equivalent. Refer to TensorFlow documentation for details. 1501 // Not fully supported, just a placeholder to handle TensorFlow graphs and 1502 // support graph transformations to other operator types by matching sub-graphs. 1503 struct TensorFlowSplitOperator : Operator { 1504 TensorFlowSplitOperator() : Operator(OperatorType::kSplit) {} 1505 int num_split = 0; 1506 }; 1507 1508 // TensorFlow SplitV equivalent. Refer to TensorFlow documentation for details. 1509 struct TensorFlowSplitVOperator : Operator { 1510 TensorFlowSplitVOperator() : Operator(OperatorType::kSplitV) {} 1511 int num_split = 0; 1512 }; 1513 1514 // TensorFlow Concat equivalent. Refer to TensorFlow documentation for details. 1515 // Not fully supported, just a placeholder to handle TensorFlow graphs and 1516 // support graph transformations to other operator types by matching sub-graphs. 1517 // Concretely, once the concat dim becomes known, if it is the depth 1518 // dimension then we can change this op into a DepthConcatenation op. 1519 // Otherwise, we hope for some other graph transformation to drop this node. 1520 struct TensorFlowConcatOperator : Operator { 1521 TensorFlowConcatOperator() : Operator(OperatorType::kConcat) {} 1522 }; 1523 1524 // TensorFlow ConcatV2 equivalent. Refer to TensorFlow documentation for 1525 // details. 1526 // Not fully supported, just a placeholder to handle TensorFlow graphs and 1527 // support graph transformations to other operator types by matching sub-graphs. 1528 // Concretely, once the concat dim becomes known, if it is the depth 1529 // dimension then we can change this op into a DepthConcatenation op. 1530 // Otherwise, we hope for some other graph transformation to drop this node. 1531 struct TensorFlowConcatV2Operator : Operator { 1532 TensorFlowConcatV2Operator() : Operator(OperatorType::kConcatV2) {} 1533 }; 1534 1535 // TensorFlow Merge equivalent. Refer to TensorFlow documentation for details. 1536 // 1537 // Inputs: this operator accepts any number >= 1 of inputs. 1538 // inputs[i]: the i-th array to merge. 1539 // 1540 // It is expected that graph transformations will drop all but exactly one 1541 // of the inputs, at which point the Merge node will be equivalent to an 1542 // Identity node forwarding the remaining input. 1543 // 1544 // Note: We do not currently support runtime control flow: we only support 1545 // control flow that can be resolved at tooling time (independently of input 1546 // activations). 1547 struct TensorFlowMergeOperator : Operator { 1548 TensorFlowMergeOperator() : Operator(OperatorType::kMerge) {} 1549 }; 1550 1551 // TensorFlow Switch equivalent. Refer to TensorFlow documentation for details. 1552 // 1553 // Inputs: 1554 // inputs[0]: required: the input array 1555 // inputs[1]: required: the boolean predicate, given as an array of size 1 1556 // and of type kBool, will determine which output gets selected. 1557 // 1558 // Outputs: a TensorFlow Switch node always has exactly two outputs. Depending 1559 // on the boolean value that the input predicate resolves to (see note below), 1560 // one or the other of the outputs will be 'selected': the input array will be 1561 // forwarded to the 'selected output' as if by a Identity node, while the other 1562 // output will be discarded, and any graph edge connecting that discarded output 1563 // will be dropped. The rule for selecting outputs is as follows: 1564 // outputs[0] will be selected if the input predicate resolves to 'true'. 1565 // outputs[1] will be selected if the input predicate resolves to 'false'. 1566 // 1567 // Note: We do not currently support runtime control flow: we only support 1568 // control flow that can be resolved at tooling time (independently of input 1569 // activations). 1570 struct TensorFlowSwitchOperator : Operator { 1571 TensorFlowSwitchOperator() : Operator(OperatorType::kSwitch) {} 1572 }; 1573 1574 // TensorFlow All equivalent. Refer to TensorFlow documentation for details. 1575 // Not fully supported, just a placeholder to handle TensorFlow graphs and 1576 // support graph transformations to other operator types by matching sub-graphs. 1577 // Typically, this is only used as an input to an Assert node, so can be 1578 // removed as an unused node as we drop Assert nodes. 1579 struct TensorFlowAllOperator : Operator { 1580 TensorFlowAllOperator() : Operator(OperatorType::kAll) {} 1581 }; 1582 1583 // TensorFlow Assert equivalent. Refer to TensorFlow documentation for details. 1584 // Not fully supported, just a placeholder to handle TensorFlow graphs and 1585 // support graph transformations to other operator types by matching sub-graphs. 1586 // Typically, we just drop Assert nodes. 1587 struct TensorFlowAssertOperator : Operator { 1588 TensorFlowAssertOperator() : Operator(OperatorType::kAssert) {} 1589 }; 1590 1591 // TensorFlow Less equivalent. Refer to TensorFlow documentation for details. 1592 // Not fully supported, just a placeholder to handle TensorFlow graphs and 1593 // support graph transformations to other operator types by matching sub-graphs. 1594 // Typically, this is only used as an input to an Assert node, so can be 1595 // removed as an unused node as we drop Assert nodes. 1596 struct TensorFlowLessOperator : Operator { 1597 TensorFlowLessOperator() : Operator(OperatorType::kLess) {} 1598 }; 1599 1600 // TensorFlow LessEqual equivalent. Refer to TensorFlow documentation for 1601 // details. 1602 // Not fully supported, just a placeholder to handle TensorFlow graphs and 1603 // support graph transformations to other operator types by matching sub-graphs. 1604 // Typically, this is only used as an input to an Assert node, so can be 1605 // removed as an unused node as we drop Assert nodes. 1606 struct TensorFlowLessEqualOperator : Operator { 1607 TensorFlowLessEqualOperator() : Operator(OperatorType::kLessEqual) {} 1608 }; 1609 1610 // TensorFlow Less equivalent. Refer to TensorFlow documentation for details. 1611 // Not fully supported, just a placeholder to handle TensorFlow graphs and 1612 // support graph transformations to other operator types by matching sub-graphs. 1613 // Typically, this is only used as an input to an Assert node, so can be 1614 // removed as an unused node as we drop Assert nodes. 1615 struct TensorFlowGreaterOperator : Operator { 1616 TensorFlowGreaterOperator() : Operator(OperatorType::kGreater) {} 1617 }; 1618 1619 // TensorFlow GreaterEqual equivalent. Refer to TensorFlow documentation for 1620 // details. 1621 // Not fully supported, just a placeholder to handle TensorFlow graphs and 1622 // support graph transformations to other operator types by matching sub-graphs. 1623 // Typically, this is only used as an input to an Assert node, so can be 1624 // removed as an unused node as we drop Assert nodes. 1625 struct TensorFlowGreaterEqualOperator : Operator { 1626 TensorFlowGreaterEqualOperator() : Operator(OperatorType::kGreaterEqual) {} 1627 }; 1628 1629 // TensorFlow Equal equivalent. Refer to TensorFlow documentation for 1630 // details. 1631 // Not fully supported, just a placeholder to handle TensorFlow graphs and 1632 // support graph transformations to other operator types by matching sub-graphs. 1633 // Typically, this is only used as an input to an Assert node, so can be 1634 // removed as an unused node as we drop Assert nodes. 1635 struct TensorFlowEqualOperator : Operator { 1636 TensorFlowEqualOperator() : Operator(OperatorType::kEqual) {} 1637 }; 1638 1639 // TensorFlow Not Equal equivalent. Refer to TensorFlow documentation for 1640 // details. 1641 struct TensorFlowNotEqualOperator : Operator { 1642 TensorFlowNotEqualOperator() : Operator(OperatorType::kNotEqual) {} 1643 }; 1644 1645 // Max reduction: computes the max of all of entries across the axes. 1646 // 1647 // Inputs: 1648 // inputs[0]: required: the input array 1649 // 1650 // TensorFlow equivalent: Max 1651 struct TensorFlowMaxOperator : Operator { 1652 TensorFlowMaxOperator() : Operator(OperatorType::kReduceMax) {} 1653 std::vector<int> axis; 1654 bool keep_dims = false; 1655 }; 1656 1657 // Min reduction: computes the min of all of entries across the axes. 1658 // 1659 // Inputs: 1660 // inputs[0]: required: the input array 1661 // 1662 // TensorFlow equivalent: Min 1663 struct TensorFlowMinOperator : Operator { 1664 TensorFlowMinOperator() : Operator(OperatorType::kReduceMin) {} 1665 std::vector<int> axis; 1666 bool keep_dims = false; 1667 }; 1668 1669 // Element-wise maximum operator. Currently it only supports scalar as 1670 // the second operand. 1671 // 1672 // Inputs: 1673 // inputs[0]: required: the left-hand side array 1674 // inputs[1]: required: the right-hand side array 1675 // 1676 // TensorFlow equivalent: Maximum 1677 struct TensorFlowMaximumOperator : Operator { 1678 TensorFlowMaximumOperator() : Operator(OperatorType::kMaximum) {} 1679 }; 1680 1681 // Element-wise minimum operator. Currently it only supports scalar as 1682 // the second operand. 1683 // 1684 // Inputs: 1685 // inputs[0]: required: the left-hand side array 1686 // inputs[1]: required: the right-hand side array 1687 // 1688 // TensorFlow equivalent: Minimum 1689 struct TensorFlowMinimumOperator : Operator { 1690 TensorFlowMinimumOperator() : Operator(OperatorType::kMinimum) {} 1691 }; 1692 1693 // General TF operation, unsupported by tf.mini. Expected to be dropped by 1694 // graph transformations. 1695 struct TensorFlowUnsupportedOperator : Operator { 1696 TensorFlowUnsupportedOperator() : Operator(OperatorType::kUnsupported) {} 1697 1698 // The original TF operation type. Used for diagnostic purposes. 1699 std::string tensorflow_op; 1700 // A boolean indicating if the unsupported op should be treated as quantized. 1701 bool quantized = false; 1702 // A boolean indicating if the unsupported op output should allow float values 1703 // in quantized mode. 1704 bool support_output_type_float_in_quantized_op = false; 1705 // Output data types 1706 std::vector<ArrayDataType> output_data_types; 1707 // Output shapes. 1708 std::vector<Shape> output_shapes; 1709 }; 1710 1711 // Softmax activation function. 1712 // 1713 // Inputs: 1714 // inputs[0]: required: the input array 1715 // 1716 // TensorFlow equivalent: Softmax 1717 struct SoftmaxOperator : Operator { 1718 SoftmaxOperator() : Operator(OperatorType::kSoftmax) {} 1719 float beta = 0.f; 1720 }; 1721 1722 // LogSoftmax activation function. 1723 // 1724 // Inputs: 1725 // inputs[0]: required: the logits input array 1726 // 1727 // TensorFlow equivalent: LogSoftmax 1728 struct LogSoftmaxOperator : Operator { 1729 LogSoftmaxOperator() : Operator(OperatorType::kLogSoftmax) {} 1730 1731 // LogSoftmax can in principal have very large negative output, depending on 1732 // the input size. However, input x_i that is less than x_max-10 is 1733 // accumulated as exp(x_i-x_max), which is truncated to zero. 1734 // 1735 // Since we effectively disregard smallish inputs in the normalizing factor, 1736 // we also drop them in the output (set to minimum output), and in doing so 1737 // make better use of the quantization range / resolution. 1738 static constexpr float kOutputRangeMin = -16.0; 1739 }; 1740 1741 // Cast operator. 1742 // 1743 // Inputs: 1744 // inputs[0]: required: the input array 1745 // 1746 // TensorFlow equivalent: Cast 1747 struct CastOperator : Operator { 1748 CastOperator() : Operator(OperatorType::kCast) {} 1749 ArrayDataType src_data_type = ArrayDataType::kNone; 1750 ArrayDataType dst_data_type = ArrayDataType::kNone; 1751 }; 1752 1753 // Floor operator. 1754 // 1755 // Inputs: 1756 // inputs[0]: required: the input array 1757 // 1758 // TensorFlow equivalent: Floor 1759 struct FloorOperator : Operator { 1760 FloorOperator() : Operator(OperatorType::kFloor) {} 1761 }; 1762 1763 // Ceil operator. 1764 // 1765 // Inputs: 1766 // inputs[0]: required: the input array 1767 // 1768 // TensorFlow equivalent: Ceil 1769 struct CeilOperator : Operator { 1770 CeilOperator() : Operator(OperatorType::kCeil) {} 1771 }; 1772 1773 // Round operator. 1774 // 1775 // Inputs: 1776 // inputs[0]: required: the input array 1777 // 1778 // TensorFlow equivalent: Round 1779 struct RoundOperator : Operator { 1780 RoundOperator() : Operator(OperatorType::kRound) {} 1781 }; 1782 1783 // Gather operator. It gathers slices from params according to indices. 1784 // Only 1-D indices are supported at the moment. 1785 // 1786 // Inputs: 1787 // inputs[0]: required: the params array 1788 // inputs[1]: required: the indices to gather 1789 // inputs[2]: optional: axis 1790 // 1791 // TensorFlow equivalent: Gather 1792 struct GatherOperator : Operator { 1793 GatherOperator() : Operator(OperatorType::kGather) {} 1794 // Axis is populated explicitly or implicitly from the axis input by 1795 // ResolveGatherAttributes. An empty axis indicates that the axis has not yet 1796 // be resolved. 1797 std::optional<int> axis; 1798 1799 // This field is not used by the standard TF Lite export but it is still need 1800 // for legacy Gather implementations. 1801 int input_rank = 0; 1802 }; 1803 1804 // GatherNd operator. It gathers slices from params according to indices. 1805 // 1806 // Inputs: 1807 // inputs[0]: required: the params array 1808 // inputs[1]: required: the indices to gather 1809 // 1810 // TensorFlow equivalent: GatherNd 1811 struct GatherNdOperator : Operator { 1812 GatherNdOperator() : Operator(OperatorType::kGatherNd) {} 1813 }; 1814 1815 // ArgMax operator. It returns the index of the maximum value along axis. 1816 // 1817 // Inputs: 1818 // inputs[0]: required: the input tensor 1819 // inputs[1]: optional: 0-D (scalar) axis 1820 // 1821 // TensorFlow equivalent: ArgMax 1822 struct ArgMaxOperator : Operator { 1823 ArgMaxOperator() : Operator(OperatorType::kArgMax) {} 1824 ArrayDataType output_data_type = ArrayDataType::kInt64; 1825 }; 1826 1827 // ArgMin operator. It returns the index of the minimum value along axis. 1828 // 1829 // Inputs: 1830 // inputs[0]: required: the input tensor 1831 // inputs[1]: optional: 0-D (scalar) axis 1832 // 1833 // TensorFlow equivalent: ArgMin 1834 struct ArgMinOperator : Operator { 1835 ArgMinOperator() : Operator(OperatorType::kArgMin) {} 1836 ArrayDataType output_data_type = ArrayDataType::kInt64; 1837 }; 1838 1839 // ResizeBilinear operator. It resizes input images with bilinear interpolation. 1840 // It does not support align_corners at the moment. 1841 // 1842 // Inputs: 1843 // inputs[0]: required: the input array 1844 // inputs[1]: required: the new image size 1845 // 1846 // TensorFlow equivalent: ResizeBilinear 1847 struct ResizeBilinearOperator : Operator { 1848 ResizeBilinearOperator() : Operator(OperatorType::kResizeBilinear) {} 1849 1850 bool align_corners = false; 1851 bool half_pixel_centers = false; 1852 }; 1853 1854 // ResizeNearestNeighborOperator operator. It resizes input images with nearest 1855 // neighbor interpolation. It does not support align_corners at the moment. 1856 // 1857 // Inputs: 1858 // inputs[0]: required: the input array 1859 // inputs[1]: required: the new image size 1860 // 1861 // TensorFlow equivalent: ResizeNearestNeighbor 1862 struct ResizeNearestNeighborOperator : Operator { 1863 ResizeNearestNeighborOperator() 1864 : Operator(OperatorType::kResizeNearestNeighbor) {} 1865 1866 bool align_corners = false; 1867 bool half_pixel_centers = false; 1868 }; 1869 1870 // SpaceToBatchND operator. It divides spatial dimensions into a grid of 1871 // blocks and interleaves these blocks with the batch dimension. Currently, 1872 // only 2-d blocks are supported. 1873 // 1874 // Inputs: 1875 // inputs[0]: required: the input array 1876 // inputs[1]: required: the block shape 1877 // inputs[2]: required: the paddings 1878 // 1879 // TensorFlow equivalent: SpaceToBatchND 1880 struct SpaceToBatchNDOperator : Operator { 1881 SpaceToBatchNDOperator() : Operator(OperatorType::kSpaceToBatchND) {} 1882 1883 std::vector<int> block_shape; 1884 std::vector<int> before_paddings; 1885 std::vector<int> after_paddings; 1886 }; 1887 1888 // BatchToSpaceND operator. Rearranges data from batch into blocks of 1889 // spatial data. Currently, only 2-d blocks are supported. 1890 // 1891 // Inputs: 1892 // inputs[0]: required: the input array 1893 // inputs[1]: required: the block shape 1894 // inputs[2]: required: the crops 1895 // 1896 // TensorFlow equivalent: BatchToSpaceND 1897 struct BatchToSpaceNDOperator : Operator { 1898 BatchToSpaceNDOperator() : Operator(OperatorType::kBatchToSpaceND) {} 1899 1900 std::vector<int> block_shape; 1901 std::vector<int> before_crops; 1902 std::vector<int> after_crops; 1903 }; 1904 1905 // Mean operator. 1906 // 1907 // Inputs: 1908 // inputs[0]: required: the input array 1909 // 1910 // TensorFlow equivalent: Mean 1911 struct MeanOperator : Operator { 1912 MeanOperator() : Operator(OperatorType::kMean) {} 1913 1914 std::vector<int> axis; 1915 bool keep_dims = false; 1916 }; 1917 1918 // Svdf operator: 1919 // 1920 // Inputs: 1921 // inputs[0]: required: the input array 1922 // inputs[1]: required: weights_feature 1923 // inputs[2]: required: weights_time 1924 // inputs[3]: optional: bias 1925 struct SvdfOperator : Operator { 1926 SvdfOperator() : Operator(OperatorType::kSvdf) {} 1927 int rank; 1928 }; 1929 1930 // TopKV2 operator. 1931 // 1932 // Inputs: 1933 // input tensor and top_k scalar. 1934 struct TopKV2Operator : Operator { 1935 TopKV2Operator() : Operator(OperatorType::kTopK_V2) {} 1936 }; 1937 1938 // DynamicPartition operator: 1939 // 1940 // Inputs: 1941 // inputs[0]: required: data. 1942 // inputs[1]: required: partitions. 1943 // 1944 // TensorFlow equivalent: DynamicPartition 1945 struct DynamicPartitionOperator : Operator { 1946 DynamicPartitionOperator() : Operator(OperatorType::kDynamicPartition) {} 1947 int num_partitions; 1948 }; 1949 1950 // DynamicStitch operator: 1951 // 1952 // Inputs: 1953 // inputs[0,N): required: indices. 1954 // inputs[N,2N): required: data. 1955 // 1956 // TensorFlow equivalent: DynamicStitch/ParallelDynamicStitch 1957 struct DynamicStitchOperator : Operator { 1958 DynamicStitchOperator() : Operator(OperatorType::kDynamicStitch) {} 1959 int num_partitions; 1960 }; 1961 1962 // SparseToDense operator: 1963 // 1964 // Inputs: 1965 // Inputs[0]: required: sparse_indices. 1966 // Inputs[1]: required: output_shape. 1967 // Inputs[2]: required: sparse_values. 1968 // 1969 // TensorFlow equivalent: SparseToDense. 1970 struct SparseToDenseOperator : Operator { 1971 SparseToDenseOperator() : Operator(OperatorType::kSparseToDense) {} 1972 bool validate_indices; 1973 }; 1974 1975 // Pow operator: 1976 // 1977 // Inputs: 1978 // Inputs[0]: required: A tensor. 1979 // Inputs[1]: required: A tensor. 1980 // 1981 // TensorFlow equivalent: Pow. 1982 struct PowOperator : Operator { 1983 PowOperator() : Operator(OperatorType::kPow) {} 1984 }; 1985 1986 // Any operator: 1987 // 1988 // Inputs: 1989 // Inputs[0]: required: A boolean input tensor. 1990 // Inputs[1]: required: reduction_indices. 1991 // 1992 // TensorFlow equivalent: tf.reduce_any. 1993 struct TensorFlowAnyOperator : Operator { 1994 TensorFlowAnyOperator() : Operator(OperatorType::kAny) {} 1995 std::vector<int> axis; 1996 bool keep_dims = false; 1997 }; 1998 1999 // LogicalAnd operator: 2000 // 2001 // Inputs: 2002 // Inputs[0]: required: A boolean tensor. 2003 // Inputs[1]: required: A boolean tensor. 2004 // 2005 // TensorFlow equivalent: tf.logical_and. 2006 struct LogicalAndOperator : Operator { 2007 LogicalAndOperator() : Operator(OperatorType::kLogicalAnd) {} 2008 }; 2009 2010 // LogicalNot operator: 2011 // 2012 // Inputs: 2013 // Inputs[0]: required: A boolean tensor. 2014 // 2015 // TensorFlow equivalent: tf.logical_not. 2016 struct LogicalNotOperator : Operator { 2017 LogicalNotOperator() : Operator(OperatorType::kLogicalNot) {} 2018 }; 2019 2020 // OneHot operator: 2021 // 2022 // Inputs: 2023 // Inputs[0]: required: indices. 2024 // Inputs[1]: required: depth. 2025 // Inputs[2]: required: on_value. 2026 // Inputs[3]: required: off_value. 2027 // 2028 // TensorFlow equivalent: OneHot. 2029 struct OneHotOperator : Operator { 2030 enum Inputs { 2031 INDICES_INPUT = 0, 2032 DEPTH_INPUT = 1, 2033 ON_VALUE_INPUT = 2, 2034 OFF_VALUE_INPUT = 3, 2035 }; 2036 2037 OneHotOperator() : Operator(OperatorType::kOneHot) {} 2038 int axis = -1; 2039 }; 2040 2041 // LogicalOr operator: 2042 // 2043 // Inputs: 2044 // Inputs[0]: required: A Bool tensor. 2045 // Inputs[1]: required: A Bool tensor. 2046 // 2047 // TensorFlow equivalent: LogicalOr. 2048 struct LogicalOrOperator : Operator { 2049 LogicalOrOperator() : Operator(OperatorType::kLogicalOr) {} 2050 }; 2051 2052 // Unpack operator: 2053 // 2054 // Inputs: 2055 // Inputs[0]: required: A boolean input tensor. 2056 // Inputs[1]: required: reduction_indices. 2057 // 2058 // TensorFlow equivalent: tf.unstack. 2059 struct UnpackOperator : Operator { 2060 UnpackOperator() : Operator(OperatorType::kUnpack) {} 2061 int num; 2062 int axis; 2063 ArrayDataType dtype = ArrayDataType::kNone; 2064 }; 2065 2066 // ZerosLike operator: 2067 // 2068 // Inputs: 2069 // inputs[0]: required: the input array 2070 // 2071 // TensorFlow equivalent: tf.zeros_like 2072 struct TensorFlowZerosLikeOperator : Operator { 2073 TensorFlowZerosLikeOperator() : Operator(OperatorType::kZerosLike) {} 2074 }; 2075 2076 // ReverseV2 operator: 2077 // 2078 // Inputs: 2079 // Inputs[0]: required: the input array. 2080 // 2081 // TensorFlow equivalent: ReverseV2. 2082 struct ReverseV2Operator : Operator { 2083 ReverseV2Operator() : Operator(OperatorType::kReverseV2) {} 2084 }; 2085 2086 enum class MirrorPadMode { kNone, kSymmetric, kReflect }; 2087 2088 // MirrorPad Operator: 2089 // 2090 // Inputs: 2091 // Inputs[0]: required: input tensor to be padded. 2092 // Inputs[1]: required: 2 Column matrix specifying padding sizes. The number of 2093 // rows must be the same as the rank of the input. 2094 // Inputs[2]: required: REFLECT or SYMMETRIC. 2095 // 2096 // TensorFlow equivalent: MirrorPad. 2097 struct MirrorPadOperator : Operator { 2098 MirrorPadOperator() : Operator(OperatorType::kMirrorPad) {} 2099 // mode is either SYMMETRIC or REFLECT. 2100 MirrorPadMode mode; 2101 }; 2102 2103 // ReverseSequence operator: 2104 // 2105 // Inputs: 2106 // Inputs[0]: required: the input array. 2107 // Inputs[1]: required: the lengths of the elements to be reversed. 2108 // 2109 // TensorFlow equivalent: tf.reverse_sequence. 2110 struct ReverseSequenceOperator : Operator { 2111 ReverseSequenceOperator() : Operator(OperatorType::kReverseSequence) {} 2112 int seq_dim; 2113 int batch_dim = 0; 2114 }; 2115 2116 // Unique Operator: 2117 // 2118 // Inputs: 2119 // inputs[0]: required: the input array 2120 // 2121 // TensorFlow equivalent: Unique 2122 struct UniqueOperator : Operator { 2123 UniqueOperator() : Operator(OperatorType::kUnique) {} 2124 ArrayDataType idx_out_type = ArrayDataType::kInt32; 2125 }; 2126 2127 struct UnidirectionalSequenceRnnOperator : Operator { 2128 UnidirectionalSequenceRnnOperator() 2129 : Operator(OperatorType::kUnidirectionalSequenceRnn) {} 2130 bool time_major; 2131 FusedActivationFunctionType fused_activation_function; 2132 }; 2133 2134 // Where Operator: 2135 // Return the coordinates of the true values in condition tensor in row-major 2136 // order. 2137 // 2138 // Inputs: 2139 // inputs[0]: required: boolean condition tensor 2140 // 2141 // TensorFlow equivalent: Where 2142 struct WhereOperator : Operator { 2143 WhereOperator() : Operator(OperatorType::kWhere) {} 2144 }; 2145 2146 // Matrix Diag Operator: 2147 // Construct a batched diagonal tensor with given batched diagonal values. 2148 // Inputs: A tensor of values that will be on the diagonal of the returned 2149 // tensor. 2150 struct MatrixDiagOperator : Operator { 2151 MatrixDiagOperator() : Operator(OperatorType::kMatrixDiag) {} 2152 }; 2153 2154 // Matrix Diag Operator V2: 2155 // Construct a batched diagonal tensor with given batched diagonal values. 2156 // Not fully supported, contains 4 extra inputs compared to MatrixDiag. Behave 2157 // like MatrixDiag when default parameters are used. 2158 struct MatrixDiagV2Operator : Operator { 2159 MatrixDiagV2Operator() : Operator(OperatorType::kMatrixDiagV2) {} 2160 }; 2161 2162 // Matrix Diag Operator V3: 2163 // Construct a batched diagonal tensor with given batched diagonal values. 2164 // Not fully supported, contains 5 extra inputs compared to MatrixDiag. Behave 2165 // like MatrixDiag when default parameters are used. 2166 // V3 is only different from V2 because it has an extra attribute (align) which 2167 // controls the alignment of diagonals in the band matrix (compact) format. 2168 // The alignment in V2 contradicts with the default alignment in V3 so V2 is 2169 // skipped. (It has never been, and should never be, exposed in the public API.) 2170 struct MatrixDiagV3Operator : Operator { 2171 MatrixDiagV3Operator() : Operator(OperatorType::kMatrixDiagV3) {} 2172 }; 2173 2174 // Matrix Set Diag Operator: 2175 // Construct a batched diagonal tensor with given input and diagonal values. 2176 // Input is a rank (k+1) tensor of values. 2177 // diagonal is a rank (k) tensor of values that will be on the diagonal 2178 // of the returned output. Output is rank k+1. 2179 // tensor. 2180 struct MatrixSetDiagOperator : Operator { 2181 MatrixSetDiagOperator() : Operator(OperatorType::kMatrixSetDiag) {} 2182 }; 2183 2184 // Matrix Set Diag Operator V2: 2185 // Construct a batched diagonal tensor with given input and diagonal values. 2186 // Not fully supported, contains 1 extra inputs compared to MatrixSetDiag. 2187 // Behave like MatrixSetDiag when default parameters are used. 2188 struct MatrixSetDiagV2Operator : Operator { 2189 MatrixSetDiagV2Operator() : Operator(OperatorType::kMatrixSetDiagV2) {} 2190 }; 2191 2192 // Matrix Set Diag Operator V3: 2193 // Construct a batched diagonal tensor with given input and diagonal values. 2194 // Not fully supported, contains 2 extra inputs compared to MatrixSetDiag. 2195 // Behave like MatrixSetDiag when default parameters are used. 2196 // V3 is only different from V2 because it has an extra attribute (align) which 2197 // controls the alignment of diagonals in the band matrix (compact) format. 2198 // The alignment in V2 contradicts with the default alignment in V3 so V2 is 2199 // skipped. (It has never been, and should never be, exposed in the public API.) 2200 struct MatrixSetDiagV3Operator : Operator { 2201 MatrixSetDiagV3Operator() : Operator(OperatorType::kMatrixSetDiagV3) {} 2202 }; 2203 2204 struct ScatterNdOperator : Operator { 2205 ScatterNdOperator() : Operator(OperatorType::kScatterNd) {} 2206 }; 2207 2208 struct SegmentSumOperator : Operator { 2209 SegmentSumOperator() : Operator(OperatorType::kSegmentSum) {} 2210 }; 2211 2212 // Alloc's are used for transient arrays only. An Alloc specifies which interval 2213 // of the "transient_data" workspace buffer passed to inference functions, is to 2214 // be used for the transient array at hand. The 'start' and 'end' values are 2215 // offsets from the start of the workspace buffer, expressed in bytes. 2216 struct Alloc { 2217 int64_t start = 0; 2218 int64_t end = 0; 2219 }; 2220 2221 inline bool operator<(const Alloc& a, const Alloc& b) { 2222 return a.start < b.start; 2223 } 2224 2225 // Array represents an array (either a constant parameter array or an 2226 // activations array) in a Model. 2227 struct Array { 2228 template <ArrayDataType A> 2229 const Buffer<A>& GetBuffer() const { 2230 DCHECK(buffer); 2231 DCHECK(buffer->type == A); 2232 return *static_cast<const Buffer<A>*>(buffer.get()); 2233 } 2234 template <ArrayDataType A> 2235 Buffer<A>& GetMutableBuffer() { 2236 if (!buffer) { 2237 Buffer<A>* ptr = new Buffer<A>; 2238 buffer = std::unique_ptr<GenericBuffer>(ptr); 2239 } 2240 DCHECK(buffer); 2241 DCHECK(buffer->type == A); 2242 return *static_cast<Buffer<A>*>(buffer.get()); 2243 } 2244 Alloc& GetOrCreateAlloc() { 2245 if (!alloc) { 2246 alloc = std::make_unique<Alloc>(); 2247 } 2248 return *alloc; 2249 } 2250 MinMax& GetOrCreateMinMax() { 2251 if (!minmax) { 2252 minmax = std::make_unique<MinMax>(); 2253 } 2254 return *minmax; 2255 } 2256 MinMax& GetMinMax() const { 2257 DCHECK(minmax); 2258 return *minmax; 2259 } 2260 QuantizationParams& GetOrCreateQuantizationParams() { 2261 if (!quantization_params) { 2262 quantization_params = std::make_unique<QuantizationParams>(); 2263 } 2264 return *quantization_params; 2265 } 2266 QuantizationParams& GetQuantizationParams() const { 2267 DCHECK(quantization_params); 2268 return *quantization_params; 2269 } 2270 2271 // The data type of the actual elements of this array, that is: 2272 // - If there is a buffer (see 'buffer' member), it must be of the same 2273 // type. 2274 // - If there is no buffer, meaning that this is a runtime (i.e. activations) 2275 // array, then this specifies the type of elements that there will be 2276 // at runtime. 2277 // 2278 // Note that this only specifies the storage type of elements; this does 2279 // not specify whether these are to be treated as 'real' or 'quantized' 2280 // values. 2281 // That is decided by whether the 'quantization_params' member is null. 2282 ArrayDataType data_type = ArrayDataType::kNone; 2283 // The final value that data_type should have at the end of graph 2284 // transformations 2285 ArrayDataType final_data_type = ArrayDataType::kNone; 2286 // The dimensions of this array --- this specifies both sizes and strides 2287 // (the storage layout). 2288 // 2289 // Issues with shape handling that remain include: 2290 // - No way to distinguish between 0-dimensional dims and missing dims. 2291 // - No way to describe dims that may be runtime-variable. 2292 // - Addressing of dims by integer index differs in different graph formats 2293 // (TensorFlow vs. other frameworks vs. what we have informally grown 2294 // within toco). 2295 // This is currently quite messy; see ReorderAxesOperator which is how we 2296 // bridge some of these discrepancies at the moment. This is overdue for 2297 // a redesign; I'm thinking that it would be nice to have more flexible 2298 // dims that allow mapping 1:1, cleanly, dims as they are in various 2299 // formats, 2300 // then explicitly convert between different conventions. 2301 2302 // Proto-style accessors 2303 bool has_shape() const { return array_shape != nullptr; } 2304 const Shape& shape() const { 2305 CHECK(has_shape()); 2306 return *array_shape; 2307 } 2308 Shape* mutable_shape() { 2309 if (!array_shape) { 2310 array_shape = std::make_unique<Shape>(); 2311 } 2312 return array_shape.get(); 2313 } 2314 void copy_shape(const Shape& src_shape) { *mutable_shape() = src_shape; } 2315 void clear_shape() { array_shape = nullptr; } 2316 2317 // The constant buffer backing this array. This is non-null if and only if 2318 // this is a constant parameter array. Conversely, this is null for 2319 // activations arrays. 2320 // 2321 // Note that this buffer is pure storage. In the case of quantized values, 2322 // it only stores the quantized values, it does not know by itself about the 2323 // quantization parameters necessary to interprete these values, that is 2324 // in the separate 'quantization_params' field. In fact, this 'buffer' field 2325 // does no even know whether values are quantized. It only has a data_type, 2326 // which must equal the 'data_type' member here, and which only describes 2327 // the storage type of element, does not tell whether they are quantized i.e. 2328 // whether they are to be interpreted with quantization_params. 2329 std::unique_ptr<GenericBuffer> buffer; 2330 // Only for activation arrays (i.e. when 'buffer' is null). 2331 // Only for code generation. 2332 // 2333 // Describes the allocation of this array within the workspace buffer 2334 // allocated 2335 // for all transient arrays. 2336 std::unique_ptr<Alloc> alloc; 2337 // Describes the [min, max] range of values 2338 // to be assumed when determining quantization_params. 2339 // 2340 // Only used for quantization. In fact, only used for determining 2341 // quantization_params. 2342 // 2343 // Used for both constant arrays (those having a 'buffer') and non-constant 2344 // arrays (activations). Indeed, it is important to use the same min-max range 2345 // as was used during training, even if that min-max range is slightly wrong 2346 // w.r.t. actual buffer elements. Doing otherwise would defeat the point of 2347 // re-training for quantization. 2348 std::unique_ptr<MinMax> minmax; 2349 // Quantization parameters. The non-null-ness of this pointer is what 2350 // defines whether this array is quantized or not. 2351 // 2352 // If this is non-null, then these quantization parameters are to be used 2353 // to assign a meaning as real numbers to the elements of this array. 2354 std::unique_ptr<QuantizationParams> quantization_params; 2355 // narrow_range is a detail of how toco handles FakeQuant operators with 2356 // narrow_range, see 2357 // https://www.tensorflow.org/api_docs/python/tf/fake_quant_with_min_max_vars 2358 // 2359 // For more context about what that is useful for, see the big comment in 2360 // graph_transformations/ensure_uint8_weights_safe_for_fast_int8_kernels.cc 2361 // 2362 // The narrow_range flag applies only to quantized arrays, and changes 2363 // their quantization in the following way when it is set to 'true': 2364 // 1. The computation of {zero_point, scale} from {min, max} needs to be 2365 // amended so that the real min value will get quantized to 2366 // (min_quantized_value + 1) instead of just (min_quantized_value). 2367 // E.g. for uint8 quantization, the real min value should get quantized to 2368 // the uint8 value 1, not 0. 2369 // 2. Quantized values should get clamped to the interval 2370 // [min_quantized_value + 1, max_value]. Equivalently, the 2371 // min_quantized_value should get nudged to (min_quantized_value + 1). 2372 // The reason why 1. does not imply 2. is that real values may not belong to 2373 // the stated [min, max] interval. Concretely, weights recorded at the last 2374 // learning step may not fall in the [min, max] interval recorded over 2375 // previous learning steps, as the values evolve across learning steps. 2376 // 2377 // Rationale why this is directly a field on Array: 2378 // - This can't be just a field on FakeQuantOperator, because 2379 // FakeQuantOperators are gone (DropFakeQuant) before we get to using that 2380 // information (Quantize). We need a place to store that bit in the interim. 2381 // - This can't be in QuantizationParams because we need to record this 2382 // ahead of quantization, and QuantizationParams are only created during 2383 // quantization. 2384 // - This could be in MinMax, but that would be an abuse of what MinMax is 2385 // about, and would break existing code that assumes that a MinMax is just 2386 // a min and a max. Unlike MinMax which is agnostic as to the quantized 2387 // data type, narrow_range refers to values in the quantized data type. 2388 bool narrow_range = false; 2389 2390 private: 2391 std::unique_ptr<Shape> array_shape; 2392 }; 2393 2394 // Our Model struct, represents an entire model (our "top-level" struct). 2395 // Owns everything. 2396 class Model { 2397 public: 2398 using ArrayMap = std::unordered_map<std::string, std::unique_ptr<Array>>; 2399 2400 bool HasArray(const std::string& name) const { 2401 return arrays.count(name) > 0; 2402 } 2403 Array& GetArray(const std::string& name) const { 2404 DCHECK(HasArray(name)) << "Array not found: " << name; 2405 return *arrays.at(name); 2406 } 2407 Array& GetOrCreateArray(const std::string& name) { 2408 // Make sure name is not used by an optional array 2409 DCHECK(!optional_arrays.count(name)); 2410 if (!HasArray(name)) { 2411 Array* ptr = new Array; 2412 arrays[name] = std::unique_ptr<Array>(ptr); 2413 } 2414 Array& result = GetArray(name); 2415 return result; 2416 } 2417 void CreateOptionalArray(const std::string& name) { 2418 DCHECK(!arrays.count(name) && !optional_arrays.count(name)); 2419 optional_arrays.insert(name); 2420 } 2421 bool IsOptionalArray(const std::string& name) const { 2422 return optional_arrays.count(name); 2423 } 2424 2425 // Note that this invalidates all array iterators. 2426 void EraseArray(const std::string& name) { arrays.erase(name); } 2427 void EraseArrays(std::function<bool(const std::string&)> discardable) { 2428 for (auto it = arrays.begin(); it != arrays.end();) { 2429 if (discardable(it->first)) { 2430 it = arrays.erase(it); 2431 } else { 2432 ++it; 2433 } 2434 } 2435 } 2436 const ArrayMap& GetArrayMap() const { return arrays; } 2437 ArrayMap& GetMutableArrayMap() { return arrays; } 2438 2439 int64_t ArithmeticOpsCount() const { return ops_count; } 2440 2441 void AddInvalidInputArray(std::string invalid_input_array) { 2442 invalid_input_arrays_.insert(invalid_input_array); 2443 } 2444 2445 const std::unordered_set<std::string>& GetInvalidInputArrays() const { 2446 return invalid_input_arrays_; 2447 } 2448 2449 // Optional arrays are used for optional tensors, 2450 // these tensors do not have data, but with reserved names as op inputs. 2451 std::set<std::string> optional_arrays; 2452 2453 // The list of operators. Notice how it's a list of unique_ptr's, implying 2454 // that the Model is what owns Operator's and keeps them alive. 2455 std::vector<std::unique_ptr<Operator>> operators; 2456 2457 // Generic flags, a place where we combine information passed to us via 2458 // command-line parameters (e.g. --input_width=N) with information that 2459 // we may or may not find in the input model file. 2460 ModelFlags flags; 2461 // For code-generation only: required size of the transient_data buffer 2462 std::size_t transient_data_size = 0; 2463 // For code-generation only: required alignment of the transient_data buffer 2464 std::size_t transient_data_alignment = 0; 2465 // Arithmetic operations performed in the model. 2466 int64_t ops_count = 0; 2467 2468 private: 2469 // The associative array mapping names to Array's. 2470 // Notice how it's a container of unique_ptr's, implying 2471 // that the Model is what owns Array's and keeps them alive. 2472 // The Operator's refer to these Array's by their name strings, not by their 2473 // addresses. See Operator::inputs, Operator::outputs. 2474 std::unordered_map<std::string, std::unique_ptr<Array>> arrays; 2475 2476 // Invalid input arrays. 2477 std::unordered_set<std::string> invalid_input_arrays_; 2478 }; 2479 2480 // OperatorSignature contains the information required to making versioning 2481 // decisions. 2482 struct OperatorSignature { 2483 // The operator. 2484 const Operator* op; 2485 2486 // The model in which the operator resides. 2487 const Model* model; 2488 }; 2489 } // namespace toco 2490 2491 #endif // TENSORFLOW_LITE_TOCO_MODEL_H_ 2492