lnode->setProperty({"distribute=true"});
}
- lnode->setProperty({"activation=" + ActivationTypeStr[(unsigned int)act]});
+ props::Activation act_prop;
+ act_prop.set(act);
+ lnode->setProperty({"activation=" + to_string(act_prop)});
in_node->setProperty({"activation=none"});
lnode->setInputLayers({in_node->getName()});
}
void NetworkGraph::setOutputLayers() {
-
for (auto iter_idx = cbegin(); iter_idx != cend(); iter_idx++) {
auto &layer_idx = *iter_idx;
for (auto iter_i = cbegin(); iter_i != cend(); iter_i++) {
}
int NetworkGraph::realizeGraph() {
-
int status = ML_ERROR_NONE;
addDefaultInputLayers();
/**
* invariant: the new realized nodes are added to the end,
- * otherwise this iteration becomes invalid. So, every iteration must be fresh
- * iterator as vector resize invalidates all the iterators.
+ * otherwise this iteration becomes invalid. So, every iteration must be
+ * fresh iterator as vector resize invalidates all the iterators.
*/
for (unsigned int i = 0; i < graph.size(); ++i) {
auto const &lnode = LNODE(*(cbegin() + i));
void NetworkGraph::extendGraph(std::vector<std::shared_ptr<LayerNode>> ex_graph,
std::string &prefix) {
-
if (compiled)
throw std::runtime_error("Cannot modify graph after compile");
#define __ACTI_FUNC_H__
#ifdef __cplusplus
+#include <common_properties.h>
#include <tensor.h>
namespace nntrainer {
-/**
- * @brief Enumeration of activation function type
- */
-enum class ActivationType {
- ACT_TANH, /** tanh */
- ACT_SIGMOID, /** sigmoid */
- ACT_RELU, /** ReLU */
- ACT_SOFTMAX, /** softmax */
- ACT_NONE, /** no op */
- ACT_UNKNOWN /** unknown */
-};
-
/**
* @brief Activation enum to string map
*/
#include <activation_layer.h>
#include <blas_interface.h>
+#include <common_properties.h>
#include <lazy_tensor.h>
#include <nntrainer_error.h>
#include <nntrainer_log.h>
+#include <node_exporter.h>
#include <parse_util.h>
#include <tensor.h>
#include <util_func.h>
namespace nntrainer {
+ActivationLayer::ActivationLayer() :
+ Layer(),
+ activation_props(new PropTypes(props::Activation())) {
+ acti_func.setActiFunc(ActivationType::ACT_NONE);
+}
static constexpr size_t SINGLE_INOUT_IDX = 0;
void ActivationLayer::finalize(InitLayerContext &context) {
+ auto &act = std::get<props::Activation>(*activation_props);
+ NNTR_THROW_IF(act.empty(), std::invalid_argument)
+ << "activation has not been set!";
+ acti_func.setActiFunc(act.get());
context.setOutputDimensions(context.getInputDimensions());
}
acti_func.run_prime_fn(out, ret, deriv);
}
-void ActivationLayer::setProperty(const std::vector<std::string> &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 ActivationLayer::setProperty(const std::string &type_str,
- const std::string &value) {
- using PropertyType = nntrainer::Layer::PropertyType;
- nntrainer::Layer::PropertyType type =
- static_cast<nntrainer::Layer::PropertyType>(parseLayerProperty(type_str));
-
- switch (type) {
- case PropertyType::activation: {
- acti_func.setActiFunc((ActivationType)parseType(value, TOKEN_ACTI));
- } break;
- default:
- std::string msg =
- "[Layer] Unknown Layer Property Key for value " + std::string(value);
- throw exception::not_supported(msg);
- }
-}
-
-int ActivationLayer::setActivation(
- std::function<Tensor &(Tensor const &, Tensor &)> const &activation_fn,
- std::function<Tensor &(Tensor &, Tensor &, Tensor const &)> const
- &activation_prime_fn) {
- acti_func.setActivation(activation_fn, activation_prime_fn);
-
- return ML_ERROR_NONE;
+void ActivationLayer::exportTo(Exporter &exporter,
+ const ExportMethods &method) const {
+ exporter.saveResult(*activation_props, method, this);
}
-int ActivationLayer::setActivation(
- std::function<Tensor &(Tensor const &, Tensor &)> const &activation_fn,
- std::function<Tensor &(Tensor &, Tensor &)> const &activation_prime_fn) {
-
- acti_func.setActivation(activation_fn, activation_prime_fn);
-
- return ML_ERROR_NONE;
-}
-
-int ActivationLayer::setActivation(
- std::function<float(float const)> const &activation_fn,
- std::function<float(float const)> const &activation_prime_fn) {
-
- acti_func.setActivation(activation_fn, activation_prime_fn);
-
- return ML_ERROR_NONE;
+void ActivationLayer::setProperty(const std::vector<std::string> &values) {
+ auto left = loadProperties(values, *activation_props);
+ NNTR_THROW_IF(!left.empty(), std::invalid_argument)
+ << "Failed to set property";
}
}; // namespace nntrainer
#define __ACTIVATION_LAYER_H__
#ifdef __cplusplus
+#include <memory>
+
#include <acti_func.h>
#include <layer_devel.h>
namespace nntrainer {
+namespace props {
+class ActivationType;
+
+} // namespace props
+
/**
* @class Activation Layer
* @brief Activation Layer
/**
* @brief Constructor of Activation Layer
*/
- ActivationLayer() : Layer() {
- acti_func.setActiFunc(ActivationType::ACT_NONE);
- }
+ ActivationLayer();
/**
* @brief Destructor of Activation Layer
/**
* @copydoc Layer::exportTo(Exporter &exporter, ExportMethods method)
*/
- void exportTo(Exporter &exporter,
- const ExportMethods &method) const override {}
+ void exportTo(Exporter &exporter, const ExportMethods &method) const override;
/**
* @copydoc Layer::getType()
inline static const std::string type = "activation";
private:
- ActiFunc
- acti_func; /**< activation function designating the activation operation */
+ using PropTypes = std::tuple<props::Activation>;
- /**
- * @brief setActivation by custom activation function
- * @note apply derivative as this activation_prime_fn does not utilize
- * derivative
- * @param[in] std::function<Tensor(Tensor const &, Tensor &)> activation_fn
- * activation function to be used
- * @param[in] std::function<Tensor(Tensor const &, Tensor &)>
- * activation_prime_fn activation_prime_function to be used
- * @retval #ML_ERROR_NONE when successful
- */
- int setActivation(
- std::function<Tensor &(Tensor const &, Tensor &)> const &activation_fn,
- std::function<Tensor &(Tensor &, Tensor &)> const &activation_prime_fn);
+ std::unique_ptr<PropTypes> activation_props; /**< activation props */
- /**
- * @brief setActivation by custom activation function
- * @note derivative not applied here as this activation_prime_fn applies
- * derivative itself
- * @param[in] std::function<Tensor(Tensor const &, Tensor &)> activation_fn
- * activation function to be used
- * @param[in] std::function<Tensor(Tensor const &, Tensor &, Tensor const &)>
- * activation_prime_fn activation_prime_function to be used
- * @retval #ML_ERROR_NONE when successful
- */
- int setActivation(
- std::function<Tensor &(Tensor const &, Tensor &)> const &activation_fn,
- std::function<Tensor &(Tensor &, Tensor &, Tensor const &)> const
- &activation_prime_fn);
-
- /**
- * @brief setActivation by custom activation function
- * @note apply derivative as this activation_prime_fn does not utilize
- * derivative
- * @param[in] std::function<float(float const &)> activation_fn activation
- * function to be used
- * @param[in] std::function<float(float const &)> activation_prime_fn
- * activation_prime_function to be used
- * @retval #ML_ERROR_NONE when successful
- */
- int setActivation(
- std::function<float(float const)> const &activation_fn,
- std::function<float(float const)> const &activation_prime_fn);
-
- /**
- * @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, const std::string &value);
+ ActiFunc acti_func; /**< activation function from activation type */
};
} // namespace nntrainer
* @bug No known bugs except for NYI items
*
*/
-
#ifndef __CENTROID_KNN_H__
#define __CENTROID_KNN_H__
#include <string>
* @author Jihoon Lee <jhoon.it.lee@samsung.com>
* @bug No known bugs except for NYI items
*/
-
-#include <string>
+#ifndef __COMMON_PROPERTIES_H__
+#define __COMMON_PROPERTIES_H__
#include <array>
-#include <base_properties.h>
#include <fstream>
+#include <string>
-#ifndef __COMMON_PROPERTIES_H__
-#define __COMMON_PROPERTIES_H__
+#include <base_properties.h>
namespace nntrainer {
+/**
+ * @brief Enumeration of activation function type
+ * @note Upon changing this enum, ActivationTypeInfo must be changed
+ * accordingly
+ */
+enum class ActivationType {
+ ACT_TANH, /** tanh */
+ ACT_SIGMOID, /** sigmoid */
+ ACT_RELU, /** ReLU */
+ ACT_SOFTMAX, /** softmax */
+ ACT_NONE, /** no op */
+ ACT_UNKNOWN /** unknown */
+};
+
namespace props {
/**
*/
bool isValid(const unsigned int &v) const override;
};
+
+/******** below section is for enumerations ***************/
+/**
+ * @brief Enumeration of activation function type
+ */
+struct ActivationTypeInfo {
+ using Enum = nntrainer::ActivationType;
+ static constexpr std::initializer_list<Enum> EnumList = {
+ Enum::ACT_TANH, Enum::ACT_SIGMOID, Enum::ACT_RELU,
+ Enum::ACT_SOFTMAX, Enum::ACT_NONE, Enum::ACT_UNKNOWN};
+
+ static constexpr const char *EnumStr[] = {"tanh", "sigmoid", "relu",
+ "softmax", "none", "unknown"};
+};
+
+/**
+ * @brief Activation Enumeration Information
+ *
+ */
+class Activation final : public EnumProperty<ActivationTypeInfo> {
+public:
+ using prop_tag = enum_class_prop_tag;
+ static constexpr const char *key = "activation";
+};
} // namespace props
} // namespace nntrainer
namespace nntrainer {
namespace props {
-class ActivationType;
/**
* @brief Flatten property, true if needs flatten layer afterwards
Distribute() : Property<bool>() {}
static constexpr const char *key = "distribute";
using prop_tag = bool_prop_tag;
- bool isValid(const bool &v) const {
- return empty() || !get();
- } /**< distribute=true can be set strictly one time */
};
/**
LayerNode::LayerNode(std::unique_ptr<nntrainer::Layer> &&l) :
layer(std::move(l)),
- activation_type(ActivationType::ACT_NONE),
run_context(nullptr),
- layer_node_props(new PropsType(props::Name(), props::Flatten(),
- props::Distribute(), props::Trainable(), {},
- {})),
+ layer_node_props(new PropsType(props::Name(), props::Distribute(),
+ props::Trainable(), {}, {})),
+ layer_node_props_realization(
+ new RealizationPropsType(props::Flatten(), props::Activation())),
loss(new props::Loss()),
regularization_loss(0.0f),
exec_order({0, 0, 0}) {
}
void LayerNode::setProperty(const std::vector<std::string> &properties) {
- bool already_distributed =
- !std::get<props::Distribute>(*layer_node_props).empty() &&
- std::get<props::Distribute>(*layer_node_props).get();
auto left_properties = loadProperties(properties, *layer_node_props);
-
- /// note that setting distribute is only allowed for one time.
- /// until we have layerNode::finalize and must not except timedist layer
- if (getDistribute() && !already_distributed) {
- auto &ac = nntrainer::AppContext::Global();
- std::unique_ptr<nntrainer::Layer> dlayer =
- ac.createObject<nntrainer::Layer>(TimeDistLayer::type);
- if (dlayer.get() == nullptr)
- throw std::invalid_argument("Error creating time distribution layer");
- auto *time_dist_layer = dynamic_cast<TimeDistLayer *>(dlayer.get());
- if (time_dist_layer == nullptr)
- throw std::invalid_argument("Error casting to time distribution layer");
- time_dist_layer->setDistLayer(std::move(layer));
- layer = std::move(dlayer);
- }
-
- std::vector<std::string> remainder;
- /// @todo: deprecate this in favor of loadProperties
- for (unsigned int i = 0; i < left_properties.size(); ++i) {
-
- std::string key;
- std::string value;
- std::stringstream ss;
-
- if (getKeyValue(left_properties[i], key, value) != ML_ERROR_NONE) {
- throw std::invalid_argument("Error parsing the property: " +
- left_properties[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
- if (!setProperty(key, value)) {
- remainder.push_back(left_properties[i]);
- }
- }
-
- layer->setProperty(remainder);
-}
-
-bool LayerNode::setProperty(const std::string &key, const std::string &value) {
- using PropertyType = nntrainer::Layer::PropertyType;
-
- PropertyType type = static_cast<PropertyType>(parseLayerProperty(key));
- switch (type) {
- case PropertyType::activation: {
- setActivation((ActivationType)parseType(value, TOKEN_ACTI));
- if (getType() == ActivationLayer::type) {
- ml_logi("Set property delegated to activation layer");
- return false;
- }
- break;
- }
- case PropertyType::num_inputs: {
- ml_logw("Deprecated property: %s", key.c_str());
- break;
- }
- default:
- return false;
- }
-
- return true;
+ left_properties =
+ loadProperties(left_properties, *layer_node_props_realization);
+ layer->setProperty(left_properties);
}
const std::string LayerNode::getName() const noexcept {
return out;
}
-ActivationType LayerNode::getActivationType() const { return activation_type; }
+ActivationType LayerNode::getActivationType() const {
+ auto &act_prop = std::get<props::Activation>(*layer_node_props_realization);
+ if (act_prop.empty()) {
+ return ActivationType::ACT_NONE;
+ }
+
+ return act_prop;
+}
unsigned int LayerNode::getNumInputConnections() const {
auto &input_layers =
if (getType() == ActivationLayer::type)
return ActivationType::ACT_NONE;
else
- return activation_type;
-}
-
-void LayerNode::setActivation(ActivationType activation) {
- if (activation == ActivationType::ACT_UNKNOWN) {
- throw std::invalid_argument("Error:have to specify activation function");
- }
- activation_type = activation;
+ return getActivationType();
}
const std::string LayerNode::getType() const { return getLayer()->getType(); }
}
bool LayerNode::getFlatten() const {
- auto &flatten = std::get<props::Flatten>(*layer_node_props);
+ auto &flatten = std::get<props::Flatten>(*layer_node_props_realization);
if (flatten.empty()) {
return false;
}
}
const nntrainer::Layer *LayerNode::getLayer() const {
- if (getDistribute())
- return ((TimeDistLayer *)(layer.get()))->getDistLayer();
+ if (run_context && getDistribute())
+ return static_cast<TimeDistLayer *>(layer.get())->getDistLayer();
else
return layer.get();
}
nntrainer::Layer *LayerNode::getLayer() {
- if (getDistribute())
- return ((TimeDistLayer *)(layer.get()))->getDistLayer();
+ if (run_context && getDistribute())
+ return static_cast<TimeDistLayer *>(layer.get())->getDistLayer();
else
return layer.get();
}
* @brief Finalize creating the layer node
*/
InitLayerContext LayerNode::finalize(const std::vector<TensorDim> &input_dims) {
+ /** Create init context right before finalize */
+ if (run_context)
+ throw std::runtime_error("Finalizing a layer which is already finalized");
+
std::vector<TensorDim> actual_input_dims;
auto &prop_dims = std::get<std::vector<props::InputShape>>(*layer_node_props);
+ /** prepare input dimensions */
if (!input_dims.empty()) {
actual_input_dims = input_dims;
if (hasInputShapeProperty()) {
NNTR_THROW_IF(!hasInputShapeProperty(), std::invalid_argument)
<< "if input dims not given, input shapes must be given by the user as "
"property";
+ /// arguably, below check can go away
NNTR_THROW_IF(prop_dims.size() != 1, std::invalid_argument)
<< "input shapes must be one if connection is not given but given "
"dimesions size of: "
if (run_context)
throw std::runtime_error("Finalizing a layer which is already finalized");
+ /** manipulate layers if required */
+ if (getType() == ActivationLayer::type) {
+ auto &act_prop = std::get<props::Activation>(*layer_node_props_realization);
+ if (!act_prop.empty()) {
+ layer->setProperty({"activation=" + to_string(act_prop)});
+ }
+ }
+ if (getType() != TimeDistLayer::type && getDistribute()) {
+ std::unique_ptr<TimeDistLayer> dlayer(new TimeDistLayer());
+ NNTR_THROW_IF(!dlayer, std::invalid_argument)
+ << "Error creating time distribution layer";
+ dlayer->setDistLayer(std::move(layer));
+ layer = std::move(dlayer);
+ }
+
+ /// remove flatten and activation since it's already realized
+ layer_node_props_realization = std::make_unique<RealizationPropsType>(
+ props::Flatten(), props::Activation());
+
auto num_outputs = output_layers.size();
if (output_layers.empty()) {
num_outputs = 1;
#include <tuple>
#include <vector>
-#include <acti_func.h>
#include <graph_node.h>
#include <layer.h>
#include <layer_context.h>
class Name;
class Distribute;
class Flatten;
-class ActivationType;
class Loss;
class InputLayer;
class InputShape;
+class Activation;
} // namespace props
/**
layer; /**< The actual object in the graph node */
std::vector<std::string> output_layers; /**< output layer names */
- ActivationType
- activation_type; /**< activation applied to the output of this node */
std::unique_ptr<RunLayerContext>
run_context; /**< context required for running/execution of the layer. This
properties in the context/graph unless intended. */
using PropsType =
- std::tuple<props::Name, props::Flatten, props::Distribute, props::Trainable,
+ std::tuple<props::Name, props::Distribute, props::Trainable,
std::vector<props::InputLayer>, std::vector<props::InputShape>>;
+
+ using RealizationPropsType = std::tuple<props::Flatten, props::Activation>;
+ /** these realization properties results in addition of new layers, hence
+ * skipped in generation of model architecture as the correspondingly layer
+ * itself is added. Distribute is also a property which is realized, but as it
+ * doesn't add new layer, it is saved. */
+
/**
* These properties are set for the layer by the user but are intercepted
* and used in the node which forms the basic element of the graph.
*/
std::unique_ptr<PropsType> layer_node_props; /**< properties for the node */
- std::unique_ptr<props::Loss> loss; /**< loss */
+ std::unique_ptr<RealizationPropsType>
+ layer_node_props_realization; /**< properties for the node */
+ std::unique_ptr<props::Loss> loss; /**< loss */
float regularization_loss;
ExecutionOrder exec_order; /**< order/location of execution for this node
in forward and backwarding operations */
- /**
- * @brief setProperty by PropertyType
- * @note By passing empty string, this can validate if @a type is valid
- * @param[in] key property type to be passed
- * @param[in] value value to be passed, if empty string is passed, do nothing
- * but throws error when @a type is invalid
- * @return true if the property can be captured, else false
- * @exception std::invalid_argument invalid argument
- */
- bool setProperty(const std::string &key, const std::string &value);
-
/**
* @brief Get the effective layer managed by this layer node
*
*/
nntrainer::Layer *getLayer();
- /**
- * @brief Activation Setter
- * @param[in] activation activation type
- * @throw std::invalid_argument when ActivationType is unknown
- */
- void setActivation(ActivationType activation);
-
/**
* @brief anchor point to override if PRINT_SHAPE_INFO is enabled for
* Layer::print()
* @author Jihoon Lee <jhoon.it.lee@samsung.com>
* @bug No known bugs except for NYI items
*/
+#ifndef __BASE_PROPERTIES_H__
+#define __BASE_PROPERTIES_H__
+
#include <array>
#include <memory>
#include <regex>
#include <props_util.h>
#include <tensor_dim.h>
-#ifndef __BASE_PROPERTIES_H__
-#define __BASE_PROPERTIES_H__
-
/** base and predefined structures */
namespace nntrainer {