From: hyeonseok lee Date: Thu, 9 Sep 2021 06:15:49 +0000 (+0900) Subject: [pooling2d layer] Maintain pooling2d layer property with props X-Git-Tag: accepted/tizen/unified/20210916.123506~18 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=dc8969f37a5036b8e3f572f973a832f70aef65d5;p=platform%2Fcore%2Fml%2Fnntrainer.git [pooling2d layer] Maintain pooling2d layer property with props - All pooling2d layer property will be maintain with props **Self evaluation:** 1. Build test: [X]Passed [ ]Failed [ ]Skipped 2. Run test: [X]Passed [ ]Failed [ ]Skipped Signed-off-by: hyeonseok lee --- diff --git a/nntrainer/layers/common_properties.cpp b/nntrainer/layers/common_properties.cpp index ab648c4..62eb92c 100644 --- a/nntrainer/layers/common_properties.cpp +++ b/nntrainer/layers/common_properties.cpp @@ -108,6 +108,8 @@ bool SplitDimension::isValid(const unsigned int &value) const { return value > 0 && value < ml::train::TensorDim::MAXDIM; } +PoolSize::PoolSize(unsigned int value) { set(value); } + Stride::Stride(unsigned int value) { set(value); } /** diff --git a/nntrainer/layers/common_properties.h b/nntrainer/layers/common_properties.h index 33e8435..9d99bd0 100644 --- a/nntrainer/layers/common_properties.h +++ b/nntrainer/layers/common_properties.h @@ -285,6 +285,27 @@ public: }; /** + * @brief PoolSize property, pool size is used to measure the pooling size + * + */ +class PoolSize : public nntrainer::PositiveIntegerProperty { +public: + /** + * @brief Construct a new PoolSize object + * + */ + PoolSize() {} + + /** + * @brief Construct a new PoolSize object with default value + * + */ + PoolSize(unsigned int value); + static constexpr const char *key = "pool_size"; /**< unique key to access */ + using prop_tag = uint_prop_tag; /**< property type */ +}; + +/** * @brief Stride property, stride is used to measure how much it will be slide * the filter * @@ -488,6 +509,38 @@ public: }; /** + * @brief Enumeration of pooling type + */ +struct PoolingTypeInfo { + /** + * @brief Pooling operation type class + */ + enum class Enum { + max = 0, + average = 1, + global_max = 2, + global_average = 3, + unknown = 4 + }; + static constexpr std::initializer_list EnumList = { + Enum::max, Enum::average, Enum::global_max, Enum::global_average, + Enum::unknown}; + + static constexpr const char *EnumStr[] = {"max", "average", "global_max", + "global_average", "unknown"}; +}; + +/** + * @brief Pooling Type Enumeration Information + * + */ +class PoolingType final : public EnumProperty { +public: + using prop_tag = enum_class_prop_tag; + static constexpr const char *key = "pooling"; +}; + +/** * @brief Enumeration of flip direction */ struct FlipDirectionInfo { diff --git a/nntrainer/layers/pooling2d_layer.cpp b/nntrainer/layers/pooling2d_layer.cpp index 494f7b9..cc65b3d 100644 --- a/nntrainer/layers/pooling2d_layer.cpp +++ b/nntrainer/layers/pooling2d_layer.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,15 @@ namespace nntrainer { static constexpr size_t SINGLE_INOUT_IDX = 0; +Pooling2DLayer::Pooling2DLayer( + const std::array &padding_) : + Layer(), + padding(padding_), + pooling2d_props(props::PoolingType(), std::vector(), + std::array(), + props::Padding2D()), + pool_helper_idx(0) {} + void Pooling2DLayer::finalize(InitLayerContext &context) { if (context.getNumInputs() != 1) { throw std::invalid_argument( @@ -34,23 +44,29 @@ void Pooling2DLayer::finalize(InitLayerContext &context) { const TensorDim &in_dim = context.getInputDimensions()[SINGLE_INOUT_IDX]; TensorDim out_dim; - if (pooling_type == PoolingType::global_max || - pooling_type == PoolingType::global_average) { - if (pool_size[0] != 0 || pool_size[1] != 0) { - throw std::invalid_argument( - "[Pooling2D] global_max, global_average does not accept pool size"); - } - pool_size[0] = in_dim.height(); - pool_size[1] = in_dim.width(); + auto &pool_size = std::get>(pooling2d_props); + NNTR_THROW_IF(!(pool_size.empty() || pool_size.size() == 2), + std::invalid_argument) + << "[Pooling2D] the number of pool size should be 0 or 2"; + auto &stride = + std::get>(pooling2d_props); + auto &pooling_type = std::get(pooling2d_props).get(); + + if (pooling_type == props::PoolingTypeInfo::Enum::global_max || + pooling_type == props::PoolingTypeInfo::Enum::global_average) { + NNTR_THROW_IF(!pool_size.empty(), std::invalid_argument) + << "[Pooling2D] global_max, global_average does not accept pool size"; + pool_size.emplace_back(props::PoolSize(in_dim.height())); + pool_size.emplace_back(props::PoolSize(in_dim.width())); } - padding = std::get(pool2d_props) + padding = std::get(pooling2d_props) .compute(in_dim, {pool_size[0], pool_size[1]}); auto [pt, pb, pl, pr] = padding; - if (pooling_type == PoolingType::global_max || - pooling_type == PoolingType::global_average) { + if (pooling_type == props::PoolingTypeInfo::Enum::global_max || + pooling_type == props::PoolingTypeInfo::Enum::global_average) { if (pt + pb + pl + pr != 0) { throw std::invalid_argument( "[Pooling2D] global_max, global_average does not accept padding"); @@ -97,7 +113,7 @@ void Pooling2DLayer::finalize(InitLayerContext &context) { * = 12 / 4 = 3 * // clang-format on */ - if (pooling_type == PoolingType::global_max) { + if (pooling_type == props::PoolingTypeInfo::Enum::global_max) { pool_helper_idx = context.requestTensor( in_dim, context.getName() + ":helper_idx", Tensor::Initializer::NONE, false, ITERATION_LIFESPAN); @@ -125,6 +141,11 @@ void Pooling2DLayer::forwarding(RunLayerContext &context, bool training) { } void Pooling2DLayer::calcDerivative(RunLayerContext &context) { + auto &pool_size = std::get>(pooling2d_props); + auto &stride = + std::get>(pooling2d_props); + auto &pooling_type = std::get(pooling2d_props).get(); + Tensor &deriv = context.getIncomingDerivative(SINGLE_INOUT_IDX); Tensor &result = context.getOutgoingDerivative(SINGLE_INOUT_IDX); Tensor &pool_helper = context.getTensor(pool_helper_idx); @@ -148,7 +169,7 @@ void Pooling2DLayer::calcDerivative(RunLayerContext &context) { unsigned int in_map_size = height * width; switch (pooling_type) { - case PoolingType::max: { + case props::PoolingTypeInfo::Enum::max: { const int *iter = pool_helper.getData(); const float *deriv_data = deriv.getData(); for (unsigned int b = 0; b < batch; ++b) { @@ -166,8 +187,8 @@ void Pooling2DLayer::calcDerivative(RunLayerContext &context) { } } } break; - case PoolingType::global_average: - case PoolingType::average: { + case props::PoolingTypeInfo::Enum::global_average: + case props::PoolingTypeInfo::Enum::average: { int heigth_stride_end = height - p_height + pb; int width_stride_end = width - p_width + pr; const int *iter = pool_helper.getData(); @@ -197,7 +218,7 @@ void Pooling2DLayer::calcDerivative(RunLayerContext &context) { } } } break; - case PoolingType::global_max: { + case props::PoolingTypeInfo::Enum::global_max: { float *deriv_data = deriv.getData(); for (unsigned int b = 0; b < batch; b++) { for (unsigned int c = 0; c < channel; c++) { @@ -219,70 +240,26 @@ void Pooling2DLayer::calcDerivative(RunLayerContext &context) { } } -void Pooling2DLayer::setProperty(const std::vector &values) { - /// @todo: deprecate this in favor of loadProperties - for (unsigned int i = 0; i < values.size(); ++i) { - std::string key; - std::string value; - std::stringstream ss; - - if (getKeyValue(values[i], key, value) != ML_ERROR_NONE) { - throw std::invalid_argument("Error parsing the property: " + values[i]); - } - - if (value.empty()) { - ss << "value is empty: key: " << key << ", value: " << value; - throw std::invalid_argument(ss.str()); - } - - /// @note this calls derived setProperty if available - setProperty(key, value); - } +void Pooling2DLayer::exportTo(Exporter &exporter, + const ExportMethods &method) const { + exporter.saveResult(pooling2d_props, method, this); } -void Pooling2DLayer::setProperty(const std::string &type_str, - const std::string &value) { - using PropertyType = nntrainer::Layer::PropertyType; - int status = ML_ERROR_NONE; - nntrainer::Layer::PropertyType type = - static_cast(parseLayerProperty(type_str)); - - switch (type) { - case PropertyType::pooling: - pooling_type = (PoolingType)parseType(value, TOKEN_POOLING); - if (pooling_type == PoolingType::unknown) { - throw std::invalid_argument("[Pooling2d_layer]: Unknown pooling type"); - } - break; - case PropertyType::pool_size: - status = getValues(POOLING2D_DIM, value, (int *)(pool_size.data())); - throw_status(status); - if (pool_size[0] == 0 || pool_size[1] == 0) { - throw std::invalid_argument( - "[Pooling2d_layer] pool_size must be greater than 0"); - } - break; - case PropertyType::stride: - status = getValues(POOLING2D_DIM, value, (int *)(stride.data())); - throw_status(status); - if (stride[0] == 0 || stride[1] == 0) { - throw std::invalid_argument( - "[Pooling2d_layer] stride must be greater than 0"); - } - break; - case PropertyType::padding: - from_string(value, std::get(pool2d_props)); - break; - default: - std::string msg = "[Pooling2DLayer] Unknown Layer Property Key for value " + - std::string(value); - throw exception::not_supported(msg); - } +void Pooling2DLayer::setProperty(const std::vector &values) { + auto remain_props = loadProperties(values, pooling2d_props); + NNTR_THROW_IF(!remain_props.empty(), std::invalid_argument) + << "[Pooling2dLayer] Unknown Layer Properties count " + + std::to_string(values.size()); } void Pooling2DLayer::pooling2d(Tensor &in, bool training, Tensor &output, Tensor &pool_helper, int batch_idx) { + auto &pool_size = std::get>(pooling2d_props); + auto &stride = + std::get>(pooling2d_props); + auto &pooling_type = std::get(pooling2d_props).get(); + unsigned int channel = in.channel(); auto [pt, pb, pl, pr] = padding; @@ -307,7 +284,7 @@ void Pooling2DLayer::pooling2d(Tensor &in, bool training, Tensor &output, unsigned int max_idx_count = 0; switch (pooling_type) { - case PoolingType::max: { + case props::PoolingTypeInfo::Enum::max: { pool_fn = [&, this](const float *in_data, int channel_idx, int start_h, int start_w) { int end_h = start_h + patch_height; @@ -340,7 +317,7 @@ void Pooling2DLayer::pooling2d(Tensor &in, bool training, Tensor &output, }; break; } - case PoolingType::global_max: { + case props::PoolingTypeInfo::Enum::global_max: { pool_fn = [&, this](const float *in_data, int channel_idx, int start_h, int start_w) { int end_h = start_h + patch_height; @@ -370,8 +347,8 @@ void Pooling2DLayer::pooling2d(Tensor &in, bool training, Tensor &output, }; break; } - case PoolingType::global_average: - case PoolingType::average: { + case props::PoolingTypeInfo::Enum::global_average: + case props::PoolingTypeInfo::Enum::average: { pool_fn = [&, this](const float *in_data, int channel_idx, int start_h, int start_w) { int end_h = start_h + patch_height; @@ -398,7 +375,7 @@ void Pooling2DLayer::pooling2d(Tensor &in, bool training, Tensor &output, }; break; } - case PoolingType::unknown: + case props::PoolingTypeInfo::Enum::unknown: default: throw std::invalid_argument("unknown pooling type given"); break; diff --git a/nntrainer/layers/pooling2d_layer.h b/nntrainer/layers/pooling2d_layer.h index d8e257b..38c4d7c 100644 --- a/nntrainer/layers/pooling2d_layer.h +++ b/nntrainer/layers/pooling2d_layer.h @@ -32,17 +32,6 @@ constexpr const unsigned int POOLING2D_DIM = 2; class Pooling2DLayer : public Layer { public: /** - * @brief Pooling operation type class - */ - enum class PoolingType { - max = 0, - average = 1, - global_max = 2, - global_average = 3, - unknown = 4, - }; - - /** * @brief PaddingType Class * @todo support keras type of padding */ @@ -56,19 +45,8 @@ public: /** * @brief Constructor of Pooling 2D Layer */ - Pooling2DLayer( - PoolingType pooling_type_ = PoolingType::average, - const std::array &pool_size_ = {0, 0}, - const std::array &stride_ = {1, 1}, - const std::array &padding_ = {0, 0, 0, - 0}) : - Layer(), - pool_size(pool_size_), - stride(stride_), - padding(padding_), - pool2d_props(), - pool_helper_idx(0), - pooling_type(pooling_type_) {} + Pooling2DLayer(const std::array &padding_ = { + 0, 0, 0, 0}); /** * @brief Destructor of Pooling 2D Layer @@ -105,10 +83,7 @@ public: /** * @copydoc Layer::exportTo(Exporter &exporter, ExportMethods method) */ - void exportTo(Exporter &exporter, - const ExportMethods &method) const override { - Layer::exportTo(exporter, method); - } + void exportTo(Exporter &exporter, const ExportMethods &method) const override; /** * @copydoc Layer::getType() @@ -132,7 +107,9 @@ public: */ void setBatch(InitLayerContext &context, unsigned int batch) override { context.updateTensorSpec(pool_helper_idx, batch); - if (pooling_type == PoolingType::global_max) + props::PoolingTypeInfo::Enum pooling_type = + std::get(pooling2d_props).get(); + if (pooling_type == props::PoolingTypeInfo::Enum::global_max) pool_helper_size.resize(batch * context.getInputDimensions()[0].channel()); } @@ -142,21 +119,22 @@ public: */ void setBatch(RunLayerContext &context, unsigned int batch) override { context.updateTensor(pool_helper_idx, batch); - if (pooling_type == PoolingType::global_max) + props::PoolingTypeInfo::Enum pooling_type = + std::get(pooling2d_props).get(); + if (pooling_type == props::PoolingTypeInfo::Enum::global_max) pool_helper_size.resize(batch * context.getInput(0).channel()); } private: - std::array pool_size; - std::array stride; std::array padding; - std::tuple pool2d_props; + std::tuple, + std::array, props::Padding2D> + pooling2d_props; unsigned int pool_helper_idx; /**< helper tensor idx */ std::vector pool_helper_size; /**< helper size for each elements in the case of global_max pooling */ - PoolingType pooling_type; /** * @brief calculation convolution @@ -168,16 +146,6 @@ private: */ void pooling2d(Tensor &in, bool training, Tensor &output, Tensor &pool_helper, int batch_idx); - - /** - * @brief setProperty by type and value separated - * @param[in] type property type to be passed - * @param[in] value value to be passed - * @exception exception::not_supported when property type is not valid for - * the particular layer - * @exception std::invalid_argument invalid argument - */ - void setProperty(const std::string &type_str, const std::string &value); }; } // namespace nntrainer diff --git a/nntrainer/utils/parse_util.cpp b/nntrainer/utils/parse_util.cpp index 176e4e0..f168e90 100644 --- a/nntrainer/utils/parse_util.cpp +++ b/nntrainer/utils/parse_util.cpp @@ -168,7 +168,7 @@ unsigned int parseType(std::string ll, InputType t) { return (i); } } - ret = (unsigned int)Pooling2DLayer::PoolingType::unknown; + ret = (unsigned int)props::PoolingTypeInfo::Enum::unknown; break; case TOKEN_UNKNOWN: default: