LCOV - code coverage report
Current view: top level - nntrainer/layers - common_properties.cpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 92.3 % 169 156
Test Date: 2025-12-14 20:38:17 Functions: 91.0 % 67 61

            Line data    Source code
       1              : // SPDX-License-Identifier: Apache-2.0
       2              : /**
       3              :  * Copyright (C) 2021 Jihoon Lee <jhoon.it.lee@samsung.com>
       4              :  *
       5              :  * @file   common_properties.cpp
       6              :  * @date   14 May 2021
       7              :  * @brief  This file contains implementation of common properties widely used
       8              :  * across layers
       9              :  * @see    https://github.com/nnstreamer/nntrainer
      10              :  * @author Jihoon Lee <jhoon.it.lee@samsung.com>
      11              :  * @bug    No known bugs except for NYI items
      12              :  */
      13              : #include <base_properties.h>
      14              : #include <common_properties.h>
      15              : 
      16              : #include <nntrainer_error.h>
      17              : #include <nntrainer_log.h>
      18              : #include <stdexcept>
      19              : #include <tensor_dim.h>
      20              : 
      21              : #include <regex>
      22              : #include <sstream>
      23              : #include <sys/stat.h>
      24              : #include <utility>
      25              : #include <vector>
      26              : 
      27              : namespace nntrainer {
      28              : namespace props {
      29              : 
      30        17071 : Name::Name() : nntrainer::Property<std::string>() {}
      31              : 
      32        16421 : Name::Name(const std::string &value) { set(value); }
      33              : 
      34        37735 : void Name::set(const std::string &value) {
      35        37735 :   auto to_lower = [](const std::string &str) {
      36              :     std::string ret = str;
      37              :     std::transform(ret.begin(), ret.end(), ret.begin(),
      38       494929 :                    [](unsigned char c) { return std::tolower(c); });
      39        37735 :     return ret;
      40              :   };
      41        37735 :   nntrainer::Property<std::string>::set(to_lower(value));
      42        37710 : }
      43              : 
      44        37735 : bool Name::isValid(const std::string &v) const {
      45        37735 :   static std::regex allowed("[a-zA-Z0-9][-_./a-zA-Z0-9]*");
      46        75493 :   return !v.empty() && std::regex_match(v, allowed);
      47              : }
      48              : 
      49         1432 : Normalization::Normalization(bool value) { set(value); }
      50              : 
      51         1432 : Standardization::Standardization(bool value) { set(value); }
      52              : 
      53          216 : bool DropOutRate::isValid(const float &v) const { return v >= 0.0; }
      54              : 
      55            0 : void RandomTranslate::set(const float &value) {
      56            0 :   Property<float>::set(std::abs(value));
      57            0 : }
      58              : 
      59          220 : bool FilePath::isValid(const std::string &v) const {
      60          220 :   std::ifstream file(v, std::ios::binary | std::ios::ate);
      61          220 :   return file.good();
      62          220 : }
      63              : 
      64          220 : void FilePath::set(const std::string &v) {
      65          220 :   Property<std::string>::set(v);
      66          218 :   std::ifstream file(v, std::ios::binary | std::ios::ate);
      67          218 :   cached_pos_size = file.tellg();
      68          218 : }
      69              : 
      70          100 : std::ifstream::pos_type FilePath::file_size() { return cached_pos_size; }
      71              : 
      72         6178 : bool LossScaleForMixed::isValid(const float &value) const {
      73         6178 :   return (value != 0);
      74              : }
      75              : 
      76            0 : bool DirPath::isValid(const std::string &v) const {
      77              :   struct stat dir;
      78            0 :   return (stat(v.c_str(), &dir) == 0);
      79              : }
      80              : 
      81            0 : void DirPath::set(const std::string &v) { Property<std::string>::set(v); }
      82              : 
      83          209 : ReturnSequences::ReturnSequences(bool value) { set(value); }
      84              : 
      85           76 : Bidirectional::Bidirectional(bool value) { set(value); }
      86              : 
      87            4 : bool NumClass::isValid(const unsigned int &v) const { return v > 0; }
      88              : 
      89         6120 : InputConnection::InputConnection() : nntrainer::Property<Connection>() {}
      90           60 : InputConnection::InputConnection(const Connection &value) :
      91           60 :   nntrainer::Property<Connection>(value) {} /**< default value if any */
      92              : 
      93          250 : Epsilon::Epsilon(float value) { set(value); }
      94              : 
      95           40 : Exponent::Exponent(float value) { set(value); }
      96              : 
      97          421 : bool Epsilon::isValid(const float &value) const { return value > 0.0f; }
      98              : 
      99           58 : Momentum::Momentum(float value) { set(value); }
     100              : 
     101           81 : bool Momentum::isValid(const float &value) const {
     102           81 :   return value > 0.0f && value < 1.0f;
     103              : }
     104              : 
     105          180 : bool Axis::isValid(const unsigned int &value) const {
     106          180 :   return value < ml::train::TensorDim::MAXDIM;
     107              : }
     108              : 
     109          160 : StartDimension::StartDimension(unsigned int value) { set(value); }
     110              : 
     111          168 : bool StartDimension::isValid(const unsigned int &value) const {
     112          168 :   return value > 0 && value < ml::train::TensorDim::MAXDIM;
     113              : }
     114              : 
     115          160 : EndDimension::EndDimension(unsigned int value) { set(value); }
     116              : 
     117          164 : bool EndDimension::isValid(const unsigned int &value) const {
     118          164 :   return value > 0 && value < ml::train::TensorDim::MAXDIM;
     119              : }
     120              : 
     121           62 : bool SplitDimension::isValid(const unsigned int &value) const {
     122           62 :   return value > 0 && value < ml::train::TensorDim::MAXDIM;
     123              : }
     124              : 
     125           36 : PoolSize::PoolSize(unsigned int value) { set(value); }
     126              : 
     127         1010 : Stride::Stride(unsigned int value) { set(value); }
     128              : 
     129          548 : Dilation::Dilation(unsigned int value) { set(value); }
     130              : 
     131              : /**
     132              :  * @brief unsigned integer property, internally used to parse padding values
     133              :  *
     134              :  */
     135         1412 : class Padding_ : public nntrainer::Property<int> {
     136              : public:
     137              :   using prop_tag = int_prop_tag; /**< property type */
     138              : };
     139              : 
     140          196 : bool Padding2D::isValid(const std::string &v) const {
     141              : 
     142              :   /// case 1, 2: padding has string literal
     143          372 :   if (istrequal(v, "valid") || istrequal(v, "same")) {
     144              :     return true;
     145              :   }
     146              : 
     147              :   std::vector<props::Padding_> paddings;
     148          148 :   from_string(v, paddings);
     149              : 
     150              :   /// case 3, 4, 5: padding has a sequence of unsigned integer
     151              :   if (paddings.size() == 1 || paddings.size() == 2 || paddings.size() == 4) {
     152              :     /// check if every padding is non-negative integer
     153          491 :     for (const auto &padding : paddings) {
     154          348 :       if (padding.get() < 0) {
     155              :         return false;
     156              :       }
     157              :     }
     158              :     return true;
     159              :   }
     160              : 
     161              :   /// case else: false
     162              :   return false;
     163          148 : }
     164              : 
     165              : std::array<unsigned int, 4>
     166          219 : Padding2D::compute(const TensorDim &input, const TensorDim &kernel,
     167              :                    const std::array<unsigned int, 2> &strides,
     168              :                    const std::array<unsigned int, 2> &dilation) {
     169          219 :   auto &padding_repr = get(); /// padding representation
     170              : 
     171          438 :   if (istrequal(padding_repr, "valid")) {
     172           54 :     return {0, 0, 0, 0};
     173              :   }
     174              : 
     175              :   /// in the case of same padding, padding is distributed to each side if
     176              :   /// possible. otherwise pad_all_side / 2 is allocated to top | left and rest
     177              :   /// are assigned to the other side
     178          330 :   if (istrequal(padding_repr, "same")) {
     179              :     auto calculate_padding = [](unsigned input_, unsigned kernel_,
     180              :                                 unsigned stride, unsigned dilation) {
     181              :       /// ceil(input / stride)
     182           54 :       unsigned int eff_kernel = (kernel_ - 1) * dilation + 1;
     183           54 :       auto out = (input_ + stride - 1) / stride;
     184           54 :       auto req_input = (out - 1) * stride + eff_kernel;
     185           54 :       return req_input >= input_ ? req_input - input_ : 0;
     186              :     };
     187              : 
     188           27 :     auto pad_vertical = calculate_padding(input.height(), kernel.height(),
     189              :                                           strides[0], dilation[0]);
     190              :     auto pad_horizontal =
     191           27 :       calculate_padding(input.width(), kernel.width(), strides[1], dilation[1]);
     192              : 
     193           27 :     auto pad_top = pad_vertical / 2;
     194           27 :     auto pad_left = pad_horizontal / 2;
     195              : 
     196           27 :     return {pad_top, pad_vertical - pad_top, pad_left,
     197           27 :             pad_horizontal - pad_left};
     198              :   }
     199              : 
     200              :   /// case 3, 4, 5: padding has a sequence of unsigned integer
     201              :   std::vector<props::Padding_> paddings_;
     202          138 :   from_string(padding_repr, paddings_);
     203          138 :   std::vector<unsigned int> paddings(paddings_.begin(), paddings_.end());
     204              : 
     205          138 :   switch (paddings.size()) {
     206              :   case 1:
     207            5 :     return {paddings[0], paddings[0], paddings[0], paddings[0]};
     208              :   case 2:
     209          100 :     return {paddings[0], paddings[0], paddings[1], paddings[1]};
     210              :   case 4:
     211           33 :     return {paddings[0], paddings[1], paddings[2], paddings[3]};
     212            0 :   default:
     213            0 :     throw std::logic_error("[Padding2D] should not reach here");
     214              :   }
     215          138 : }
     216              : 
     217           18 : bool Padding1D::isValid(const std::string &v) const {
     218              : 
     219              :   /// case 1, 2, 3: padding has string literal
     220           44 :   if (istrequal(v, "valid") || istrequal(v, "same") || istrequal(v, "causal")) {
     221              :     return true;
     222              :   }
     223              : 
     224              :   std::vector<props::Padding_> paddings;
     225            6 :   from_string(v, paddings);
     226              : 
     227              :   /// case 4, 5: padding has a sequence of unsigned integer
     228            6 :   if (paddings.size() == 1 || paddings.size() == 2) {
     229              :     /// check if every padding is non-negative integer
     230           14 :     for (const auto &padding : paddings) {
     231            8 :       if (padding.get() < 0) {
     232              :         return false;
     233              :       }
     234              :     }
     235              :     return true;
     236              :   }
     237              : 
     238              :   /// case else: false
     239              :   return false;
     240            6 : }
     241              : 
     242           26 : std::array<unsigned int, 2> Padding1D::compute(const TensorDim &input_dim,
     243              :                                                const unsigned int &kernel,
     244              :                                                const unsigned int &stride,
     245              :                                                const unsigned int &dilation) {
     246           26 :   auto &padding_repr = get(); /// padding representation
     247              : 
     248              :   auto calculate_padding = [](unsigned input, unsigned kernel, unsigned stride,
     249              :                               unsigned dilation) {
     250              :     /// ceil(input / stride)
     251           10 :     unsigned int eff_kernel = (kernel - 1) * dilation + 1;
     252           10 :     auto out = (input + stride - 1) / stride;
     253           10 :     auto req_input = (out - 1) * stride + eff_kernel;
     254           10 :     return req_input >= input ? req_input - input : 0;
     255              :   };
     256              : 
     257           52 :   if (istrequal(padding_repr, "valid")) {
     258           10 :     return {0, 0};
     259           32 :   } else if (istrequal(padding_repr, "same")) {
     260              : 
     261              :     auto pad_horizontal =
     262            6 :       calculate_padding(input_dim.width(), kernel, stride, dilation);
     263              : 
     264            6 :     auto pad_left = pad_horizontal / 2;
     265              : 
     266            6 :     return {pad_left, pad_horizontal - pad_left};
     267           20 :   } else if (istrequal(padding_repr, "causal")) {
     268              :     auto pad_horizontal =
     269            4 :       calculate_padding(input_dim.width(), kernel, stride, dilation);
     270            4 :     return {pad_horizontal, 0};
     271              :   }
     272              : 
     273              :   /// case 4, 5: padding has a sequence of unsigned integer
     274              :   std::vector<props::Padding_> paddings_;
     275            6 :   from_string(padding_repr, paddings_);
     276            6 :   std::vector<unsigned int> paddings(paddings_.begin(), paddings_.end());
     277              : 
     278            6 :   switch (paddings.size()) {
     279              :   case 1:
     280            4 :     return {paddings[0], paddings[0]};
     281              :   case 2:
     282            2 :     return {paddings[0], paddings[1]};
     283            0 :   default:
     284            0 :     throw std::logic_error("[Padding1D] should not reach here");
     285              :   }
     286            6 : }
     287              : 
     288         6749 : BasicRegularizerConstant::BasicRegularizerConstant(float value) { set(value); }
     289              : 
     290         2086 : WeightRegularizerConstant::WeightRegularizerConstant(float value) :
     291         2086 :   BasicRegularizerConstant(value) {}
     292         2331 : WeightDecay::WeightDecay(float value) : BasicRegularizerConstant(value) {}
     293         2331 : BiasDecay::BiasDecay(float value) : BasicRegularizerConstant(value) {}
     294              : 
     295         1286 : PropsUserData::PropsUserData(void *user_data) { set(user_data); }
     296              : 
     297         9167 : bool BasicRegularizerConstant::isValid(const float &value) const {
     298         9167 :   return value >= 0.0f;
     299              : }
     300              : 
     301            0 : OutputLayer::OutputLayer() : Name() {}
     302            0 : OutputLayer::OutputLayer(const std::string &name) : Name(name) {}
     303              : 
     304           84 : LabelLayer::LabelLayer() : Name() {}
     305            0 : LabelLayer::LabelLayer(const std::string &name) : Name(name) {}
     306              : 
     307         1324 : HiddenStateActivation::HiddenStateActivation(ActivationTypeInfo::Enum value) {
     308         1324 :   set(value);
     309         1324 : };
     310              : 
     311         1132 : RecurrentActivation::RecurrentActivation(ActivationTypeInfo::Enum value) {
     312         1132 :   set(value);
     313         1132 : };
     314              : 
     315         2086 : WeightInitializer::WeightInitializer(Initializer value) { set(value); }
     316              : 
     317         2086 : BiasInitializer::BiasInitializer(Initializer value) { set(value); }
     318              : 
     319           56 : MuInitializer::MuInitializer(Initializer value) { set(value); }
     320              : 
     321           56 : VarInitializer::VarInitializer(Initializer value) { set(value); }
     322              : 
     323          245 : GammaInitializer::GammaInitializer(Initializer value) { set(value); }
     324              : 
     325          245 : BetaInitializer::BetaInitializer(Initializer value) { set(value); }
     326              : 
     327         2087 : BasicRegularizer::BasicRegularizer(nntrainer::WeightRegularizer value) {
     328         2087 :   set(value);
     329         2086 : }
     330              : 
     331         2086 : WeightRegularizer::WeightRegularizer(nntrainer::WeightRegularizer value) :
     332         2086 :   BasicRegularizer(value) {}
     333              : 
     334         2840 : bool BasicRegularizer::isValid(
     335              :   const nntrainer::WeightRegularizer &value) const {
     336         2840 :   return value != nntrainer::WeightRegularizer::UNKNOWN;
     337              : }
     338              : 
     339           33 : FlipDirection::FlipDirection(FlipDirectionInfo::Enum value) { set(value); }
     340              : 
     341         1861 : void GenericShape::set(const TensorDim &value) {
     342         1861 :   TensorDim ret = value;
     343         1861 :   ret.setDynDimFlag(0b1000);
     344         1861 :   if (ret.batch() != 1) {
     345           23 :     ml_logw("Batch size set with dimension %zu is ignored."
     346              :             "Use batchsize property for the model to update batchsize.",
     347              :             ret.batch());
     348           23 :     ret.batch(1);
     349              :   }
     350         1861 :   Property<TensorDim>::set(ret);
     351         1861 : }
     352              : 
     353           21 : ScaledDotProduct::ScaledDotProduct(bool value) { set(value); }
     354              : 
     355           21 : CausalMask::CausalMask(bool value) { set(value); }
     356              : 
     357          149 : NumHeads::NumHeads(unsigned int value) { set(value); }
     358              : 
     359          149 : ReturnAttentionWeight::ReturnAttentionWeight(
     360          149 :   ReturnAttentionWeightInfo::Enum value) {
     361          149 :   set(value);
     362          149 : }
     363              : 
     364              : } // namespace props
     365              : 
     366              : template <>
     367         3199 : std::string str_converter<props::connection_prop_tag, Connection>::to_string(
     368              :   const Connection &value) {
     369         3199 :   return value.toString();
     370              : }
     371              : 
     372              : template <>
     373         6562 : Connection str_converter<props::connection_prop_tag, Connection>::from_string(
     374              :   const std::string &value) {
     375         6562 :   return Connection(value);
     376              : }
     377              : 
     378              : } // namespace nntrainer
        

Generated by: LCOV version 2.0-1