LCOV - code coverage report
Current view: top level - nntrainer/utils - node_exporter.h (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 96.4 % 55 53
Test Date: 2025-12-14 20:38:17 Functions: 82.8 % 803 665

            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 node_exporter.h
       6              :  * @date 09 April 2021
       7              :  * @brief NNTrainer Node exporter
       8              :  * @see https://github.com/nnstreamer/nntrainer
       9              :  * @author Jihoon Lee <jhoon.it.lee@samsung.com>
      10              :  * @author Donghak Park <donghak.park@samsung.com>
      11              :  * @bug No known bugs except for NYI items
      12              :  */
      13              : #ifndef __NODE_EXPORTER_H__
      14              : #define __NODE_EXPORTER_H__
      15              : 
      16              : #include <memory>
      17              : #include <regex>
      18              : #include <string>
      19              : #include <tuple>
      20              : #include <utility>
      21              : #include <vector>
      22              : 
      23              : #include <base_properties.h>
      24              : #include <common.h>
      25              : #include <common_properties.h>
      26              : #include <layer.h>
      27              : #include <nntrainer_error.h>
      28              : #include <util_func.h>
      29              : 
      30              : #ifdef ENABLE_TFLITE_INTERPRETER
      31              : #include <flatbuffers/flatbuffers.h>
      32              : #endif
      33              : 
      34              : namespace nntrainer {
      35              : 
      36              : /**
      37              :  * @brief Forward declaration of TfOpNode
      38              :  *
      39              :  */
      40              : class TfOpNode;
      41              : 
      42              : namespace {
      43              : 
      44              : /**
      45              :  * @brief meta function that return return_type when a method is being called
      46              :  *
      47              :  * @tparam method returned when certain method is being called
      48              :  */
      49              : template <ml::train::ExportMethods method> struct return_type {
      50              :   using type = void;
      51              : };
      52              : 
      53              : /**
      54              :  * @brief meta function to check return type when the method is string vector
      55              :  *
      56              :  * @tparam specialized so not given
      57              :  */
      58              : template <> struct return_type<ml::train::ExportMethods::METHOD_STRINGVECTOR> {
      59              :   using type = std::vector<std::pair<std::string, std::string>>;
      60              : };
      61              : 
      62              : /**
      63              :  * @brief meta function to check return type when the method is string vector
      64              :  *
      65              :  * @tparam specialized so not given
      66              :  */
      67              : template <> struct return_type<ml::train::ExportMethods::METHOD_TFLITE> {
      68              :   using type = TfOpNode;
      69              : };
      70              : 
      71              : /**
      72              :  * @brief Create a empty ptr if null
      73              :  *
      74              :  * @tparam T type to create
      75              :  * @param[in/out] ptr ptr to create
      76              :  */
      77         6869 : template <typename T> void createIfNull(std::unique_ptr<T> &ptr) {
      78         6869 :   if (ptr == nullptr) {
      79         3050 :     ptr = std::make_unique<T>();
      80              :   }
      81         6869 : }
      82              : 
      83              : } // namespace
      84              : 
      85              : /**
      86              :  * @brief Exporter class helps to exports the node information in a predefined
      87              :  * way. because each method will require complete different methods, this class
      88              :  * exploits visitor pattern to make a custom defined saving method
      89              :  *
      90              :  */
      91              : class Exporter {
      92              : public:
      93              :   /**
      94              :    * @brief Construct a new Exporter object
      95              :    *
      96              :    */
      97              :   Exporter();
      98              : 
      99              : #ifdef ENABLE_TFLITE_INTERPRETER
     100              :   /**
     101              :    * @brief Construct a new Exporter object with flatbuffer builder
     102              :    *
     103              :    */
     104              :   Exporter(flatbuffers::FlatBufferBuilder *fbb);
     105              : 
     106              :   flatbuffers::FlatBufferBuilder *getFlatbufferBuilder() { return fbb; }
     107              : #endif
     108              : 
     109              :   /**
     110              :    * @brief Destroy the Exporter object
     111              :    *
     112              :    */
     113              :   ~Exporter();
     114              : 
     115              :   /**
     116              :    * @brief this function iterates over the property and process the property in
     117              :    * a designated way.
     118              :    *
     119              :    * @tparam Ts type of elements
     120              :    * @tparam NodeType NodeType element
     121              :    * @param props tuple that contains properties
     122              :    * @param method method to export
     123              :    * @param self this pointer to the layer which is being exported
     124              :    */
     125              :   template <typename... Ts, typename NodeType = void>
     126         6878 :   void saveResult(const std::tuple<Ts...> &props,
     127              :                   ml::train::ExportMethods method,
     128              :                   const NodeType *self = nullptr) {
     129         6878 :     switch (method) {
     130         6825 :     case ml::train::ExportMethods::METHOD_STRINGVECTOR: {
     131         6825 :       createIfNull(stored_result);
     132              : 
     133              :       /**
     134              :        * @brief function to pass to the iterate_prop, this saves the property
     135              :        * to stored_result
     136              :        *
     137              :        * @param prop property property to pass
     138              :        * @param index index of the current property
     139              :        */
     140        82018 :       auto callable = [this](auto &&prop, size_t index) {
     141        46894 :         if (!prop.empty()) {
     142        28299 :           std::string key = getPropKey(prop);
     143        82053 :           stored_result->emplace_back(std::move(key), to_string(prop));
     144              :         }
     145              :       };
     146         2423 :       iterate_prop(callable, props);
     147         4772 :     } break;
     148           52 :     case ml::train::ExportMethods::METHOD_TFLITE:
     149           52 :       saveTflResult(props, self);
     150           52 :       break;
     151            1 :     case ml::train::ExportMethods::METHOD_UNDEFINED:
     152              :     /// fall through intended
     153              :     default:
     154            2 :       throw exception::not_supported("given method is not supported yet");
     155              :     }
     156              : 
     157         6877 :     is_exported = true;
     158         6877 :   }
     159              : 
     160              :   /**
     161              :    * @brief Get the result object
     162              :    * @note @a unique_ptr here will be a member of @a this. The ownership is
     163              :    * passed to the caller, thus after getResult, the target member is cleared.
     164              :    * This is intended design choice to mimic single function call, between @a
     165              :    * saveResult and @a getResult
     166              :    *
     167              :    * @tparam methods method to get
     168              :    * @tparam T appropriate return type regarding the export method
     169              :    * @return std::unique_ptr<T> predefined return type according to the method.
     170              :    * @retval nullptr not exported
     171              :    */
     172              :   template <ml::train::ExportMethods methods,
     173              :             typename T = typename return_type<methods>::type>
     174              :   std::unique_ptr<T> getResult();
     175              : 
     176              : private:
     177              :   /**
     178              :    * @brief ProtoType to enable saving result to tfnode
     179              :    *
     180              :    * @tparam PropsType propsType PropsType to receive with self
     181              :    * @tparam NodeType NodeType of current layer.
     182              :    * @param props properties to get with @a self
     183              :    * @param self @a this of the current layer
     184              :    */
     185              :   template <typename PropsType, typename NodeType>
     186              :   void saveTflResult(const PropsType &props, const NodeType *self);
     187              : 
     188              : #ifdef ENABLE_TFLITE_INTERPRETER
     189              :   std::unique_ptr<TfOpNode> tf_node;   /**< created node from the export */
     190              :   flatbuffers::FlatBufferBuilder *fbb; /**< flatbuffer builder */
     191              : #endif
     192              : 
     193              :   std::unique_ptr<std::vector<std::pair<std::string, std::string>>>
     194              :     stored_result; /**< stored result */
     195              : 
     196              :   /// consider changing this to a promise / future if there is a async function
     197              :   /// involved to `saveResult`
     198              :   bool is_exported; /**< boolean to check if exported */
     199              : };
     200              : 
     201              : /**
     202              :  * @brief ProtoType to enable saving result to tfnode
     203              :  *
     204              :  * @tparam PropsType propsType PropsType to receive with self
     205              :  * @tparam NodeType NodeType of current layer.
     206              :  * @param props properties to get with @a self
     207              :  * @param self @a this of the current layer
     208              :  */
     209              : template <typename PropsType, typename NodeType>
     210            0 : void Exporter::saveTflResult(const PropsType &props, const NodeType *self) {
     211            0 :   NNTR_THROW_IF(true, nntrainer::exception::not_supported)
     212              :     << "given node cannot be converted to tfnode, type: "
     213              :     << typeid(self).name();
     214              : }
     215              : 
     216              : #ifdef ENABLE_TFLITE_INTERPRETER
     217              : namespace props {
     218              : class Name;
     219              : class Unit;
     220              : class Flatten;
     221              : class Distribute;
     222              : class Trainable;
     223              : class InputShape;
     224              : class WeightRegularizer;
     225              : class WeightRegularizerConstant;
     226              : class WeightInitializer;
     227              : class WeightDecay;
     228              : class BiasDecay;
     229              : class BiasInitializer;
     230              : class SharedFrom;
     231              : class InputConnection;
     232              : class ClipGradByGlobalNorm;
     233              : class DisableBias;
     234              : class Activation;
     235              : class BatchNormalization;
     236              : class Packed;
     237              : class LossScaleForMixed;
     238              : class InPlaceProp;
     239              : class InPlaceDirectionProp;
     240              : class Exponent;
     241              : class StartIndex;
     242              : class EndIndex;
     243              : } // namespace props
     244              : 
     245              : class LayerNode;
     246              : /**
     247              :  * @copydoc template <typename PropsType, typename NodeType> void
     248              :  * Exporter::saveTflResult(const PropsType &props, const NodeType *self);
     249              :  */
     250              : template <>
     251              : void Exporter::saveTflResult(
     252              :   const std::tuple<
     253              :     props::Name, props::Distribute, props::Trainable,
     254              :     std::vector<props::InputConnection>, std::vector<props::InputShape>,
     255              :     props::SharedFrom, props::ClipGradByGlobalNorm, props::Packed,
     256              :     props::WeightDtype, props::LossScaleForMixed, props::ComputeEngine> &props,
     257              :   const LayerNode *self);
     258              : 
     259              : class BatchNormalizationLayer;
     260              : /**
     261              :  * @copydoc template <typename PropsType, typename NodeType> void
     262              :  * Exporter::saveTflResult(const PropsType &props, const NodeType *self);
     263              :  */
     264              : template <>
     265              : void Exporter::saveTflResult(
     266              :   const std::tuple<props::Epsilon, props::MuInitializer, props::VarInitializer,
     267              :                    props::BetaInitializer, props::GammaInitializer,
     268              :                    props::Momentum, props::Axis, props::WeightDecay,
     269              :                    props::BiasDecay> &props,
     270              :   const BatchNormalizationLayer *self);
     271              : 
     272              : class LayerImpl;
     273              : 
     274              : /**
     275              :  * @copydoc template <typename PropsType, typename NodeType> void
     276              :  * Exporter::saveTflResult(const PropsType &props, const NodeType *self);
     277              :  */
     278              : template <>
     279              : void Exporter::saveTflResult(
     280              :   const std::tuple<props::WeightRegularizer, props::WeightRegularizerConstant,
     281              :                    props::WeightInitializer, props::WeightDecay,
     282              :                    props::BiasDecay, props::BiasInitializer, props::DisableBias,
     283              :                    props::Print> &props,
     284              :   const LayerImpl *self);
     285              : 
     286              : class FullyConnectedLayer;
     287              : /**
     288              :  * @copydoc template <typename PropsType, typename NodeType> void
     289              :  * Exporter::saveTflResult(const PropsType &props, const NodeType *self);
     290              :  */
     291              : template <>
     292              : void Exporter::saveTflResult(
     293              :   const std::tuple<props::Unit, props::LoraRank, props::LoraAlpha> &props,
     294              :   const FullyConnectedLayer *self);
     295              : 
     296              : class ActivationLayer;
     297              : /**
     298              :  * @copydoc template <typename PropsType, typename NodeType> void
     299              :  * Exporter::saveTflResult(const PropsType &props, const NodeType *self);
     300              :  */
     301              : template <>
     302              : void Exporter::saveTflResult(const std::tuple<props::Activation> &props,
     303              :                              const ActivationLayer *self);
     304              : 
     305              : class Conv2DLayer;
     306              : /**
     307              :  * @copydoc template <typename PropsType, typename NodeType> void
     308              :  * Exporter::saveTflResult(const PropsType &props, const NodeType *self);
     309              :  */
     310              : template <>
     311              : void Exporter::saveTflResult(
     312              :   const std::tuple<props::FilterSize, std::array<props::KernelSize, 2>,
     313              :                    std::array<props::Stride, 2>, props::Padding2D,
     314              :                    std::array<props::Dilation, 2>> &props,
     315              :   const Conv2DLayer *self);
     316              : 
     317              : class InputLayer;
     318              : /**
     319              :  * @copydoc template <typename PropsType, typename NodeType> void
     320              :  * Exporter::saveTflResult(const PropsType &props, const NodeType *self);
     321              :  */
     322              : template <>
     323              : void Exporter::saveTflResult(
     324              :   const std::tuple<props::Normalization, props::Standardization> &props,
     325              :   const InputLayer *self);
     326              : 
     327              : class Pooling2DLayer;
     328              : /**
     329              :  * @copydoc template <typename PropsType, typename NodeType> void
     330              :  * Exporter::saveTflResult(const PropsType &props, const NodeType *self);
     331              :  */
     332              : template <>
     333              : void Exporter::saveTflResult(
     334              :   const std::tuple<props::PoolingType, std::vector<props::PoolSize>,
     335              :                    std::array<props::Stride, 2>, props::Padding2D> &props,
     336              :   const Pooling2DLayer *self);
     337              : 
     338              : class ReshapeLayer;
     339              : /**
     340              :  * @copydoc template <typename PropsType, typename NodeType> void
     341              :  * Exporter::saveTflResult(const PropsType &props, const NodeType *self);
     342              :  */
     343              : template <>
     344              : void Exporter::saveTflResult(const std::tuple<props::TargetShape> &props,
     345              :                              const ReshapeLayer *self);
     346              : 
     347              : class FlattenLayer;
     348              : /**
     349              :  * @copydoc template <typename PropsType, typename NodeType> void
     350              :  * Exporter::saveTflResult(const PropsType &props, const NodeType *self);
     351              :  */
     352              : template <>
     353              : void Exporter::saveTflResult(const std::tuple<props::TargetShape> &props,
     354              :                              const FlattenLayer *self);
     355              : 
     356              : class AdditionLayer;
     357              : /**
     358              :  * @copydoc template <typename PropsType, typename NodeType> void
     359              :  * Exporter::saveTflResult(const PropsType &props, const NodeType *self);
     360              :  */
     361              : template <>
     362              : void Exporter::saveTflResult(const std::tuple<> &props,
     363              :                              const AdditionLayer *self);
     364              : #endif
     365              : 
     366              : /**
     367              :  * @brief base case of iterate_prop, iterate_prop iterates the given tuple
     368              :  *
     369              :  * @tparam I size of tuple(automated)
     370              :  * @tparam Callable generic lambda to be called during iteration
     371              :  * @tparam Ts types from tuple
     372              :  * @param c callable generic lambda
     373              :  * @param tup tuple to be iterated
     374              :  * @return void
     375              :  */
     376              : template <size_t I = 0, typename Callable, typename... Ts>
     377              : typename std::enable_if<I == sizeof...(Ts), void>::type
     378              : iterate_prop(Callable &&c, const std::tuple<Ts...> &tup) {
     379              :   // end of recursion;
     380              : }
     381              : 
     382              : /**
     383              :  * @brief base case of iterate_prop, iterate_prop iterates the given tuple
     384              :  *
     385              :  * @tparam I size of tuple(automated)
     386              :  * @tparam Callable generic lambda to be called during iteration
     387              :  * @tparam Ts types from tuple
     388              :  * @param c callable generic lambda
     389              :  * @param tup tuple to be iterated
     390              :  * @return not used
     391              :  */
     392              : template <size_t I = 0, typename Callable, typename... Ts>
     393              : typename std::enable_if<(I < sizeof...(Ts)), void>::type
     394        21316 : iterate_prop(Callable &&c, const std::tuple<Ts...> &tup) {
     395        25718 :   c(std::get<I>(tup), I);
     396              : 
     397        18893 :   iterate_prop<I + 1>(c, tup);
     398        21316 : }
     399              : 
     400              : /**
     401              :  * @copydoc  template <size_t I = 0, typename Callable, typename... Ts>
     402              : typename std::enable_if<(I < sizeof...(Ts)), void>::type iterate_prop(Callable
     403              : &&c, const std::tuple<Ts...> &tup)
     404              :  */
     405              : template <size_t I = 0, typename Callable, typename... Ts>
     406              : typename std::enable_if<(I < sizeof...(Ts)), void>::type
     407       221040 : iterate_prop(Callable &&c, std::tuple<Ts...> &tup) {
     408       267701 :   c(std::get<I>(tup), I);
     409              : 
     410       175552 :   iterate_prop<I + 1>(c, tup);
     411       261085 : }
     412              : 
     413              : /**
     414              :  * @brief load property from the api formatted string ({"key=value",
     415              :  * "key1=value1"})
     416              :  *
     417              :  * @tparam Tuple tuple type
     418              :  * @param string_vector api formatted string;
     419              :  * @param[out] props props to be iterated
     420              :  * @return std::vector<std::string> vector of string that is not used while
     421              :  * setting the property
     422              :  */
     423              : template <typename Tuple>
     424              : std::vector<std::string>
     425        92255 : loadProperties(const std::vector<std::string> &string_vector, Tuple &&props) {
     426              :   std::vector<std::string> string_vector_splited;
     427        92255 :   string_vector_splited.reserve(string_vector.size());
     428       195115 :   for (auto &item : string_vector) {
     429       102860 :     auto splited = split(item, std::regex("\\|"));
     430       102860 :     string_vector_splited.insert(string_vector_splited.end(), splited.begin(),
     431              :                                  splited.end());
     432              :   }
     433              : 
     434              :   std::vector<std::pair<std::string, std::string>> left;
     435        92255 :   left.reserve(string_vector_splited.size());
     436        92255 :   std::transform(string_vector_splited.begin(), string_vector_splited.end(),
     437       102876 :                  std::back_inserter(left), [](const std::string &property) {
     438              :                    std::string key, value;
     439       102876 :                    int status = getKeyValue(property, key, value);
     440       102982 :                    NNTR_THROW_IF(status != ML_ERROR_NONE, std::invalid_argument)
     441              :                      << "parsing property failed, original format: \""
     442              :                      << property << "\"";
     443       102770 :                    return std::make_pair(key, value);
     444              :                  });
     445              : 
     446       580844 :   auto callable = [&left](auto &&prop, size_t index) {
     447       488731 :     std::string prop_key = getPropKey(prop);
     448              : 
     449       953568 :     for (auto iter = left.begin(); iter < left.end();) {
     450       464873 :       if (istrequal(prop_key, iter->first) == true) {
     451        60408 :         from_string(iter->second, prop);
     452        60372 :         iter = left.erase(iter);
     453              :       } else {
     454              :         iter++;
     455              :       }
     456              :     }
     457              :   };
     458              : 
     459        45488 :   iterate_prop(callable, props);
     460              : 
     461              :   std::vector<std::string> remainder;
     462        92113 :   remainder.reserve(left.size());
     463              : 
     464        92113 :   std::transform(left.begin(), left.end(), std::back_inserter(remainder),
     465        42356 :                  [](const decltype(left)::value_type &v) {
     466        84712 :                    return v.first + "=" + v.second;
     467              :                  });
     468              : 
     469        92113 :   return remainder;
     470        92397 : }
     471              : 
     472              : } // namespace nntrainer
     473              : #endif // __NODE_EXPORTER_H__
        

Generated by: LCOV version 2.0-1