diff --git a/compiler/luci/service/include/luci/Service/CircleShapeInference.h b/compiler/luci/service/include/luci/Service/CircleShapeInference.h index 6c16cb6d210..2edbbe1a0d4 100644 --- a/compiler/luci/service/include/luci/Service/CircleShapeInference.h +++ b/compiler/luci/service/include/luci/Service/CircleShapeInference.h @@ -58,11 +58,11 @@ class Algorithm final : public luci::CircleNodeVisitor // loco::TensorShape visit(const luci::CircleCeil *node) final; loco::TensorShape visit(const luci::CircleConcatenation *node) final; // loco::TensorShape visit(const luci::CircleConst *node) final; - // loco::TensorShape visit(const luci::CircleConv2D *node) final; + loco::TensorShape visit(const luci::CircleConv2D *node) final; // loco::TensorShape visit(const luci::CircleCos *node) final; // loco::TensorShape visit(const luci::CircleCustom *node) final; // loco::TensorShape visit(const luci::CircleDepthToSpace *node) final; - // loco::TensorShape visit(const luci::CircleDepthwiseConv2D *node) final; + loco::TensorShape visit(const luci::CircleDepthwiseConv2D *node) final; // loco::TensorShape visit(const luci::CircleDequantize *node) final; loco::TensorShape visit(const luci::CircleDiv *node) final; // loco::TensorShape visit(const luci::CircleElu *node) final; diff --git a/compiler/luci/service/src/CircleShapeInferenceRule.cpp b/compiler/luci/service/src/CircleShapeInferenceRule.cpp index cd27a6149a1..c5b164c2831 100644 --- a/compiler/luci/service/src/CircleShapeInferenceRule.cpp +++ b/compiler/luci/service/src/CircleShapeInferenceRule.cpp @@ -411,57 +411,6 @@ loco::NodeShape infer_batch_to_space_nd(const luci::CircleBatchToSpaceND *node) return loco::NodeShape{shape_output}; } -struct OutputSize -{ - uint32_t height = 0; - uint32_t width = 0; -}; - -template OutputSize infer_conv2d_type(const Conv2DType *node) -{ - auto ifm_shape = luci::shape_get(node->input()).template as(); - auto ker_shape = luci::shape_get(node->filter()).template as(); - assert(ifm_shape.rank() == 4); - assert(ker_shape.rank() == 4); - assert(ifm_shape.dim(1).known()); - assert(ifm_shape.dim(2).known()); - assert(ker_shape.dim(1).known()); - assert(ker_shape.dim(2).known()); - - uint32_t input_height = ifm_shape.dim(1).value(); - uint32_t input_width = ifm_shape.dim(2).value(); - uint32_t stride_height = node->stride()->h(); - uint32_t stride_width = node->stride()->w(); - uint32_t ker_height = ker_shape.dim(1).value(); - uint32_t ker_width = ker_shape.dim(2).value(); - uint32_t dilation_height = node->dilation()->h(); - uint32_t dilation_width = node->dilation()->w(); - uint32_t effective_ker_height = dilation_height * (ker_height - 1) + 1; - uint32_t effective_ker_width = dilation_width * (ker_width - 1) + 1; - - uint32_t output_height = 0; - uint32_t output_width = 0; - - if (node->padding() == luci::Padding::VALID) - { - LUCI_ASSERT(input_height + stride_height > effective_ker_height, "Invalid shape"); - LUCI_ASSERT(input_width + stride_width > effective_ker_width, "Invalid shape"); - output_height = (input_height + stride_height - effective_ker_height) / stride_height; - output_width = (input_width + stride_width - effective_ker_width) / stride_width; - } - else if (node->padding() == luci::Padding::SAME) - { - output_height = (input_height + stride_height - 1) / stride_height; - output_width = (input_width + stride_width - 1) / stride_width; - } - else - LUCI_ASSERT(false, "Wrong padding type"); - - OutputSize os{output_height, output_width}; - - return os; -} - loco::NodeShape infer_broadcast_to(const luci::CircleBroadcastTo *node) { const loco::DataType S32 = loco::DataType::S32; @@ -492,34 +441,6 @@ loco::NodeShape infer_broadcast_to(const luci::CircleBroadcastTo *node) return loco::NodeShape{shape_by_input}; } -loco::NodeShape infer_conv2d(const luci::CircleConv2D *node) -{ - LOGGER(l); - - auto ifm_shape = luci::shape_get(node->input()).as(); // in NHWC - auto ker_shape = luci::shape_get(node->filter()).as(); // in OHWI - - assert(ifm_shape.rank() == 4); - assert(ker_shape.rank() == 4); - assert(ifm_shape.dim(3) == ker_shape.dim(3)); - - auto os = infer_conv2d_type(node); - - loco::TensorShape ofm_shape; - ofm_shape.rank(4); - ofm_shape.dim(0) = ifm_shape.dim(0); - ofm_shape.dim(1) = os.height; - ofm_shape.dim(2) = os.width; - ofm_shape.dim(3) = ker_shape.dim(0); - - INFO(l) << "[luci] CircleConv2D ShapeInf ifm(" << ifm_shape.rank() << ") ker(" << ker_shape.rank() - << ") output(" << ofm_shape.dim(0).value() << "," << ofm_shape.dim(1).value() << "," - << ofm_shape.dim(2).value() << "," << ofm_shape.dim(3).value() << ") " << node->name() - << std::endl; - - return loco::NodeShape{ofm_shape}; -} - loco::NodeShape infer_depth_to_space(const luci::CircleDepthToSpace *node) { auto input_shape = luci::shape_get(node->input()).as(); @@ -552,28 +473,6 @@ loco::NodeShape infer_depth_to_space(const luci::CircleDepthToSpace *node) return loco::NodeShape{output_shape}; } -loco::NodeShape infer_depthwise_conv2d(const luci::CircleDepthwiseConv2D *node) -{ - auto ifm_shape = luci::shape_get(node->input()).as(); // in NHWC - auto ker_shape = luci::shape_get(node->filter()).as(); // in 1 H W CM - - assert(ifm_shape.rank() == 4); - assert(ker_shape.rank() == 4); - assert(ker_shape.dim(0).value() == 1); - assert(ifm_shape.dim(3).value() * node->depthMultiplier() == ker_shape.dim(3).value()); - - auto os = infer_conv2d_type(node); - - loco::TensorShape ofm_shape; - ofm_shape.rank(4); - ofm_shape.dim(0) = ifm_shape.dim(0); - ofm_shape.dim(1) = os.height; - ofm_shape.dim(2) = os.width; - ofm_shape.dim(3) = ker_shape.dim(3); - - return loco::NodeShape{ofm_shape}; -} - loco::NodeShape infer_expand_dims(const luci::CircleExpandDims *node) { const loco::DataType S32 = loco::DataType::S32; @@ -1815,8 +1714,6 @@ class ShapeInferenceAlgorithm final : public luci::CircleNodeVisitorinput()).as(); diff --git a/compiler/luci/service/src/HelperConv2Ds.h b/compiler/luci/service/src/HelperConv2Ds.h new file mode 100644 index 00000000000..6404dbb0bbc --- /dev/null +++ b/compiler/luci/service/src/HelperConv2Ds.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Check.h" +#include "CircleShapeInferenceHelper.h" + +namespace luci +{ + +namespace sinf +{ + +struct OutputSize +{ + uint32_t height = 0; + uint32_t width = 0; +}; + +template OutputSize infer_conv2d_type(const Conv2DType *node) +{ + auto ifm_shape = luci::shape_get(node->input()).template as(); + auto ker_shape = luci::shape_get(node->filter()).template as(); + assert(ifm_shape.rank() == 4); + assert(ker_shape.rank() == 4); + assert(ifm_shape.dim(1).known()); + assert(ifm_shape.dim(2).known()); + assert(ker_shape.dim(1).known()); + assert(ker_shape.dim(2).known()); + + uint32_t input_height = ifm_shape.dim(1).value(); + uint32_t input_width = ifm_shape.dim(2).value(); + uint32_t stride_height = node->stride()->h(); + uint32_t stride_width = node->stride()->w(); + uint32_t ker_height = ker_shape.dim(1).value(); + uint32_t ker_width = ker_shape.dim(2).value(); + uint32_t dilation_height = node->dilation()->h(); + uint32_t dilation_width = node->dilation()->w(); + uint32_t effective_ker_height = dilation_height * (ker_height - 1) + 1; + uint32_t effective_ker_width = dilation_width * (ker_width - 1) + 1; + + uint32_t output_height = 0; + uint32_t output_width = 0; + + if (node->padding() == luci::Padding::VALID) + { + LUCI_ASSERT(input_height + stride_height > effective_ker_height, "Invalid shape"); + LUCI_ASSERT(input_width + stride_width > effective_ker_width, "Invalid shape"); + output_height = (input_height + stride_height - effective_ker_height) / stride_height; + output_width = (input_width + stride_width - effective_ker_width) / stride_width; + } + else if (node->padding() == luci::Padding::SAME) + { + output_height = (input_height + stride_height - 1) / stride_height; + output_width = (input_width + stride_width - 1) / stride_width; + } + else + LUCI_ASSERT(false, "Wrong padding type"); + + OutputSize os{output_height, output_width}; + + return os; +} + +} // namespace sinf + +} // namespace luci diff --git a/compiler/luci/service/src/Nodes/CircleConv2D.cpp b/compiler/luci/service/src/Nodes/CircleConv2D.cpp index bd2a28988b4..7eeed99c4b8 100644 --- a/compiler/luci/service/src/Nodes/CircleConv2D.cpp +++ b/compiler/luci/service/src/Nodes/CircleConv2D.cpp @@ -14,7 +14,13 @@ * limitations under the License. */ +#include "HelperConv2Ds.h" +#include "luci/Service/CircleShapeInference.h" + #include "CircleCloneNode.h" +#include "CircleShapeInferenceHelper.h" + +#include namespace luci { @@ -39,4 +45,37 @@ luci::CircleNode *CloneNodeLet::visit(const luci::CircleConv2D *node) return cloned; } +namespace sinf +{ + +loco::TensorShape Algorithm::visit(const luci::CircleConv2D *node) +{ + LOGGER(l); + + auto ifm_shape = luci::shape_get(node->input()).as(); // in NHWC + auto ker_shape = luci::shape_get(node->filter()).as(); // in OHWI + + assert(ifm_shape.rank() == 4); + assert(ker_shape.rank() == 4); + assert(ifm_shape.dim(3) == ker_shape.dim(3)); + + auto os = infer_conv2d_type(node); + + loco::TensorShape ofm_shape; + ofm_shape.rank(4); + ofm_shape.dim(0) = ifm_shape.dim(0); + ofm_shape.dim(1) = os.height; + ofm_shape.dim(2) = os.width; + ofm_shape.dim(3) = ker_shape.dim(0); + + INFO(l) << "[luci] CircleConv2D ShapeInf ifm(" << ifm_shape.rank() << ") ker(" << ker_shape.rank() + << ") output(" << ofm_shape.dim(0).value() << "," << ofm_shape.dim(1).value() << "," + << ofm_shape.dim(2).value() << "," << ofm_shape.dim(3).value() << ") " << node->name() + << std::endl; + + return ofm_shape; +} + +} // namespace sinf + } // namespace luci diff --git a/compiler/luci/service/src/Nodes/CircleDepthwiseConv2D.cpp b/compiler/luci/service/src/Nodes/CircleDepthwiseConv2D.cpp index ba34a221c80..1d7468b7034 100644 --- a/compiler/luci/service/src/Nodes/CircleDepthwiseConv2D.cpp +++ b/compiler/luci/service/src/Nodes/CircleDepthwiseConv2D.cpp @@ -14,7 +14,11 @@ * limitations under the License. */ +#include "HelperConv2Ds.h" +#include "luci/Service/CircleShapeInference.h" + #include "CircleCloneNode.h" +#include "CircleShapeInferenceHelper.h" namespace luci { @@ -40,4 +44,31 @@ luci::CircleNode *CloneNodeLet::visit(const luci::CircleDepthwiseConv2D return cloned; } +namespace sinf +{ + +loco::TensorShape Algorithm::visit(const luci::CircleDepthwiseConv2D *node) +{ + auto ifm_shape = luci::shape_get(node->input()).as(); // in NHWC + auto ker_shape = luci::shape_get(node->filter()).as(); // in 1 H W CM + + assert(ifm_shape.rank() == 4); + assert(ker_shape.rank() == 4); + assert(ker_shape.dim(0).value() == 1); + assert(ifm_shape.dim(3).value() * node->depthMultiplier() == ker_shape.dim(3).value()); + + auto os = infer_conv2d_type(node); + + loco::TensorShape ofm_shape; + ofm_shape.rank(4); + ofm_shape.dim(0) = ifm_shape.dim(0); + ofm_shape.dim(1) = os.height; + ofm_shape.dim(2) = os.width; + ofm_shape.dim(3) = ker_shape.dim(3); + + return ofm_shape; +} + +} // namespace sinf + } // namespace luci