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