diff --git a/ethosu/regor/tflite/tflite_supported_operators.cpp b/ethosu/regor/tflite/tflite_supported_operators.cpp index 54047fe37cebd9f17e2edd76d20aee472a38f9f8..1485da80b7c0191c442dd1498df50003c63093c3 100644 --- a/ethosu/regor/tflite/tflite_supported_operators.cpp +++ b/ethosu/regor/tflite/tflite_supported_operators.cpp @@ -272,7 +272,7 @@ bool TfLiteSupportedOperators::ConstraintWeightsPrecision(const Operation *op) bool TfLiteSupportedOperators::ConstraintWeightSum(const Operation *op) { - std::string constraint = fmt::format( + static const std::string constraint = fmt::format( "The sum of absolute weights cannot exceed:\n" "\t{} for 8-bit IFM\n" "\t{} for 16-bit IFM", @@ -382,7 +382,7 @@ bool TfLiteSupportedOperators::ConstraintBias(const Operation *op) { if ( bias > _maxBias ) { - std::string constraint = fmt::format("Int64 bias must be smaller than {}", _maxBias); + static const std::string constraint = fmt::format("Int64 bias must be smaller than {}", _maxBias); Failure(op, fmt::format("Bias is out of range: {} > {}", bias, _maxBias), constraint); return false; } @@ -460,6 +460,97 @@ bool TfLiteSupportedOperators::ConstraintMaxPool(const Operation *op) return true; } +bool TfLiteSupportedOperators::ConstraintTCStrides(const Operation *op) +{ + static const std::string constraint = + "Stride values WxH must be:\n" + "\t1x1 OR 2x2\n" + "\tOR 2x1 if ifm height and kernel height = 1\n" + "\tOR 1x2 if ifm width and kernel width = 1"; + OpType opType = op->Type(); + if ( opType != OpType::TransposeConv2D ) + { + return true; + } + auto ifmConn = op->Input(TensorUsage::IFM); + auto kernel = op->Kernel(); + assert(ifmConn); + assert(kernel); + const auto &ifmShape = ifmConn->shape; + auto [kw, kh] = kernel->Size(); + auto stride = kernel->Stride(); + + if ( stride.x < 1 || stride.x > 2 || stride.y < 1 || stride.y > 2 ) + { + Failure(op, fmt::format("stride out of range: ({},{})", stride.x, stride.y), constraint); + return false; + } + if ( stride == Point2i(1, 2) && !(ifmShape.Height() == 1 && kh == 1) ) + { + Failure(op, fmt::format("unsupported stride combination: ({},{})", stride.x, stride.y), constraint); + return false; + } + if ( stride == Point2i(2, 1) && !(ifmShape.Width() == 1 && kw == 1) ) + { + Failure(op, fmt::format("unsupported stride combination: ({},{})", stride.x, stride.y), constraint); + return false; + } + return true; +} + +bool TfLiteSupportedOperators::ConstraintTCShapes(const Operation *op) +{ + static const std::string constraint = + "if PADDING=SAME\n" + "\tOFM must equal IFM * stride\n" + "if PADDING=VALID\n" + "\tOFM must equal IFM * stride + (kernel - stride)"; + OpType opType = op->Type(); + if ( opType != OpType::TransposeConv2D ) + { + return true; + } + auto ifmConn = op->Input(TensorUsage::IFM); + auto ofmConn = op->Output(TensorUsage::OFM); + auto kernel = op->Kernel(); + assert(ifmConn); + assert(ofmConn); + assert(kernel); + const auto &ifmShape = ifmConn->shape; + const auto &ofmShape = ofmConn->shape; + auto stride = kernel->Stride(); + assert(op->Passthrough()); + const tflite::Operator *passthrough = static_cast(op->Passthrough()); + const auto *opt = passthrough->builtin_options_as(); + assert(opt); + Point2i ifmWH(ifmShape.Width(), ifmShape.Height()); + Point2i ofmWH(ofmShape.Width(), ofmShape.Height()); + if ( opt->padding() == tflite::Padding::SAME ) + { + if ( ifmWH * stride != ofmWH ) + { + Failure(op, + fmt::format("(Padding::SAME) Unsupported IFM/OFM shapes. ifm:({},{}), ofm:({},{}), stride:({},{})", + ifmWH.x, ifmWH.y, ofmWH.x, ofmWH.y, stride.x, stride.y), + constraint); + return false; + } + } + else + { + Point2i diff = (kernel->Size() - stride); + if ( (ifmWH * stride + diff) != ofmWH ) + { + Failure(op, + fmt::format("(Padding::VALID) Unsupported IFM/OFM shapes. ifm:({},{}) ofm:({},{}), stride:({},{}), kernel:({},{})", + ifmWH.x, ifmWH.y, ofmWH.x, ofmWH.y, stride.x, stride.y, kernel->Size().x, kernel->Size().y), + constraint); + return false; + } + } + return true; +} + void TfLiteSupportedOperators::Failure(const Operation *op, const std::string &message, const std::string &constraint) { assert(op); @@ -504,6 +595,8 @@ TfLiteSupportedOperators::TfLiteSupportedOperators(IArchitectureConstraints *con &TfLiteSupportedOperators::ConstraintBias, &TfLiteSupportedOperators::ConstraintAvgPool, &TfLiteSupportedOperators::ConstraintMaxPool, + &TfLiteSupportedOperators::ConstraintTCStrides, + &TfLiteSupportedOperators::ConstraintTCShapes, }; } diff --git a/ethosu/regor/tflite/tflite_supported_operators.hpp b/ethosu/regor/tflite/tflite_supported_operators.hpp index 943203e67b4ba3dfc3dd693e20301af2e5996bc7..cd31817ba4d8cdff27465f2e9f69b64bcca2a5b8 100644 --- a/ethosu/regor/tflite/tflite_supported_operators.hpp +++ b/ethosu/regor/tflite/tflite_supported_operators.hpp @@ -65,5 +65,7 @@ private: bool ConstraintBias(const Operation *op); bool ConstraintAvgPool(const Operation *op); bool ConstraintMaxPool(const Operation *op); + bool ConstraintTCStrides(const Operation *op); + bool ConstraintTCShapes(const Operation *op); }; } // namespace regor diff --git a/ethosu/regor/tflite/tflite_supported_operators_u55.cpp b/ethosu/regor/tflite/tflite_supported_operators_u55.cpp index 33ba97faa8e3922388860aa9a2b354c3f62b2062..5d49a09c41e810611ddcd170c8359e205495d2cd 100644 --- a/ethosu/regor/tflite/tflite_supported_operators_u55.cpp +++ b/ethosu/regor/tflite/tflite_supported_operators_u55.cpp @@ -112,7 +112,7 @@ bool TfLiteSupportedOperatorsU55::Check(const Operation *op) bool TfLiteSupportedOperatorsU55::ConstraintBroadcastShapes(const Operation *op) { - const char *constraint = "One input-tensor must match the shape of the output-tensor."; + static const char *constraint = "One input-tensor must match the shape of the output-tensor."; if ( !IsElementwise(op->Type()) ) { // only applied to elementwise ops diff --git a/ethosu/regor/tflite/tflite_supported_operators_u85.cpp b/ethosu/regor/tflite/tflite_supported_operators_u85.cpp index f0575625f26c441ca11db9e5f3d46d907d8e28b7..5cb7a0aab51fc5d553ac955cd9a2e6ae5210fa4a 100644 --- a/ethosu/regor/tflite/tflite_supported_operators_u85.cpp +++ b/ethosu/regor/tflite/tflite_supported_operators_u85.cpp @@ -139,7 +139,7 @@ bool TfLiteSupportedOperatorsU85::Check(const Operation *op) bool TfLiteSupportedOperatorsU85::ConstraintResizeCommon(const Operation *op) { - const char *constraint = + static const char *constraint = "ALIGN_CORNERS and HALF_PIXEL_CENTERS are mutually exclusive.\n" "if ALIGN_CORNERS:\n" "\tScale-factor can be maximum 2048\n" @@ -230,7 +230,7 @@ bool TfLiteSupportedOperatorsU85::ConstraintResizeCommon(const Operation *op) bool TfLiteSupportedOperatorsU85::ConstraintResizeBilinear(const Operation *op) { - const char *constraint = + static const char *constraint = "if IFM HxW > 1x1\n" "\tand ALIGN_CORNERS:\n" "\t\tOFM W-1 and H-1 must be a power-of-two integer-multiple of IFM W-1 and H-1\n"