<< FUNC_TAG << "section type is invalid for section name: " << sec_name;
auto properties = section2properties(ini, sec_name);
- std::shared_ptr<Layer> nntr_layer = ac.createObject<Layer>(layer_type);
-
- if (nntr_layer->getDistribute()) {
- ml_logd("This %s layer is going to distributed", sec_name.c_str());
- std::shared_ptr<Layer> dist_layer =
- nntrainer::createLayer(TimeDistLayer::type);
- std::dynamic_pointer_cast<TimeDistLayer>(dist_layer)
- ->setDistLayer(nntr_layer);
-
- nntr_layer = dist_layer;
- }
-
- auto layer = createLayerNode(nntr_layer, properties);
+ auto layer = createLayerNode(ac.createObject<Layer>(layer_type), properties);
return layer;
}
* @brief Get index of the node
*
*/
- virtual size_t getIndex() = 0;
+ virtual size_t getIndex() const = 0;
/**
* @brief Set index of the node
static const std::vector<std::string> in_place_layers = {
ActivationLayer::type, BatchNormalizationLayer::type};
-static std::shared_ptr<Layer> distributeLayer(std::shared_ptr<Layer> l) {
- std::shared_ptr<Layer> layer = nntrainer::createLayer(TimeDistLayer::type);
- std::dynamic_pointer_cast<TimeDistLayer>(layer)->setDistLayer(l);
-
- return layer;
-}
-
int NetworkGraph::compile(const LossType loss_type) {
int status = ML_ERROR_NONE;
skip_non_trainable_layers = graph.size();
}
-int NetworkGraph::realizeMultiInputType(Layer ¤t) {
+int NetworkGraph::realizeMultiInputType(
+ const std::shared_ptr<LayerNode> &in_node) {
+ Layer ¤t = *in_node->getObject();
int status = ML_ERROR_NONE;
+ /**
+ * Multi-input works with time distribution layer by itself
+ *
+ */
if (current.getNumInputs() == 1)
return ML_ERROR_NONE;
return status;
}
-int NetworkGraph::realizeFlattenType(Layer ¤t) {
+int NetworkGraph::realizeFlattenType(
+ const std::shared_ptr<LayerNode> &in_node) {
+ Layer ¤t = *in_node->getObject();
if (current.getType() == FlattenLayer::type) {
ml_loge(
"It is not allowed to realize flatten layer, possibly flatten layer is "
return ML_ERROR_NONE;
}
-int NetworkGraph::realizeActivationType(Layer ¤t) {
+int NetworkGraph::realizeActivationType(
+ const std::shared_ptr<LayerNode> &in_node) {
+ Layer ¤t = *in_node->getObject();
int status = ML_ERROR_NONE;
ActivationType act = current.getActivationType();
}
std::shared_ptr<LayerNode> lnode = createLayerNode(ActivationLayer::type);
- std::shared_ptr<Layer> layer = lnode->getObject();
-
- layer->setActivation(act);
graph.ensureName(*lnode, current.getName());
- if (current.getType() == TimeDistLayer::type) {
- std::string unit_str = layer->getName();
- graph.ensureName(*lnode, "", "_unit");
- layer = distributeLayer(layer);
- lnode = std::make_shared<LayerNode>(layer);
- layer->setName(unit_str);
+ if (in_node->getDistribute()) {
+ lnode->setProperty({"distribute=true"});
+ graph.ensureName(*lnode, "", "_distribute");
}
+ std::shared_ptr<Layer> layer = lnode->getObject();
+ layer->setActivation(act);
+
layer->setNumInputs(current.getNumInputs());
layer->input_layers.clear();
layer->input_layers.push_back(current.getName());
return status;
}
-int NetworkGraph::realizeMultiOutputType(Layer ¤t) {
+int NetworkGraph::realizeMultiOutputType(
+ const std::shared_ptr<LayerNode> &in_node) {
+ Layer ¤t = *in_node->getObject();
int status = ML_ERROR_NONE;
- if (current.output_layers.size() == 1)
+ /**
+ * Multi-input works with time distribution layer by itself
+ *
+ */
+
+ if (current.getNumOutputs() == 1)
return ML_ERROR_NONE;
std::shared_ptr<LayerNode> lnode = createLayerNode(OutputLayer::type);
/** TODO: this needs special attention */
int NetworkGraph::addLossLayer(const LossType loss_type) {
-
int status = ML_ERROR_NONE;
- auto const &last_node = graph.getSortedNode(graph.size() - 1);
+ auto const &last_node = LNODE(graph.getSortedNode(graph.size() - 1));
auto last_layer_node = getSortedLayerNode(graph.size() - 1);
if (last_node->getType() == LossLayer::type)
return status;
- if (last_node->getType() == TimeDistLayer::type) {
- if (std::static_pointer_cast<TimeDistLayer>(last_layer_node->getObject())
- ->getDistLayerType() == LossLayer::type)
- return status;
- }
-
if (loss_type == LossType::LOSS_NONE) {
return ML_ERROR_NONE;
}
if (updated_loss_type == LossType::LOSS_ENTROPY) {
auto type = last_node->getType();
- if (type == TimeDistLayer::type) {
- type =
- std::dynamic_pointer_cast<TimeDistLayer>(last_layer_node->getObject())
- ->getDistLayerType();
- }
if (type != "activation") {
ml_loge("Error: Cross Entropy need last layer to have softmax or sigmoid"
graph.removeLastNode();
- switch (last_layer_node->getObject()->getActivationType()) {
+ switch (last_layer_node->getActivationType()) {
case ActivationType::ACT_SIGMOID:
updated_loss_type = LossType::LOSS_ENTROPY_SIGMOID;
break;
std::string input_str = updated_last_node->getName();
- if (updated_last_node->getType() == TimeDistLayer::type) {
- std::string unit_str = layer->getName();
- graph.ensureName(*lnode, "", "_unit");
- layer = distributeLayer(layer);
- lnode = std::make_shared<LayerNode>(layer);
- layer->setName(unit_str);
+ if (updated_last_node->getDistribute()) {
+ lnode->setProperty({"distribute=true"});
+ graph.ensureName(*lnode, "", "_distribute");
}
last_layer_node = LNODE(updated_last_node);
if (l.getType() != AdditionLayer::type &&
l.getType() != ConcatLayer::type) {
- status = realizeMultiInputType(l);
+ status = realizeMultiInputType(lnode);
NN_RETURN_STATUS();
}
if (l.getType() != ActivationLayer::type) {
- status = realizeActivationType(l);
+ status = realizeActivationType(lnode);
NN_RETURN_STATUS();
}
// Flatten in TimeDistLayer is not supported.
- if (lnode->getFlatten() && l.getType() != TimeDistLayer::type) {
- status = realizeFlattenType(l);
+ if (lnode->getFlatten() && !lnode->getDistribute()) {
+ status = realizeFlattenType(lnode);
NN_RETURN_STATUS();
}
}
node_list = graph.getNodes();
for (unsigned int i = 0; i < num_nodes; ++i) {
- Layer &l = *LNODE(node_list[i])->getObject();
- if (l.getType() != OutputLayer::type && l.getType() != SplitLayer::type) {
- status = realizeMultiOutputType(l);
+ auto const &lnode = LNODE(node_list[i]);
+ if (lnode->getType() != OutputLayer::type &&
+ lnode->getType() != SplitLayer::type) {
+ status = realizeMultiOutputType(lnode);
NN_RETURN_STATUS();
}
}
auto layer_node = *iter;
auto &l = layer_node->getObject();
std::string l_type = l->getType();
- if (l_type == TimeDistLayer::type) {
- l_type = std::dynamic_pointer_cast<TimeDistLayer>(l)->getDistLayerType();
- }
if (l_type == layer_type &&
l->getActivationType() != ActivationType::ACT_SOFTMAX) {
auto const &lnode = getSortedLayerNode(idx);
auto &lptr = lnode->getObject();
ml_logd("layer name : %s", lptr->getName().c_str());
- std::string cur_type;
- if (lptr->getType() == TimeDistLayer::type) {
- cur_type =
- std::dynamic_pointer_cast<TimeDistLayer>(lptr)->getDistLayerType();
- } else {
- cur_type = lptr->getType();
- }
+ std::string cur_type = lptr->getType();
/**
* Set input dimension for all the layers.
* For input layer, as input dimension is known, set input tensor.
*/
if (!first) {
- std::string l_pre_type =
- getSortedLayerNode(idx - 1)->getObject()->getType();
- if (l_pre_type == TimeDistLayer::type) {
- l_pre_type = std::dynamic_pointer_cast<TimeDistLayer>(
- getSortedLayerNode(idx - 1)->getObject())
- ->getDistLayerType();
- }
+ std::string l_pre_type = getSortedLayerNode(idx - 1)->getType();
if (istrequal(l_pre_type, ActivationLayer::type) &&
istrequal(cur_type, ActivationLayer::type)) {
/**
* @brief check and add Multi Input Layer : addition or concat Layer
- * @param[in] current layer
+ * @param[in] in_node layernode
* @retval #ML_ERROR_NONE Successful.
* @retval #ML_ERROR_INVALID_PARAMETER invalid parameter.
*/
- int realizeMultiInputType(Layer ¤t);
+ int realizeMultiInputType(const std::shared_ptr<LayerNode> &in_node);
/**
* @brief check and add Multi output Layer : output Layer
- * @param[in] current layer
+ * @param[in] in_node layernode
* @retval #ML_ERROR_NONE Successful.
* @retval #ML_ERROR_INVALID_PARAMETER invalid parameter.
*/
- int realizeMultiOutputType(Layer ¤t);
+ int realizeMultiOutputType(const std::shared_ptr<LayerNode> &in_node);
/**
* @brief Realize act type to layer and insert it to layers
- * @param[in] current layer
+ * @param[in] in_node layernode
* @retval #ML_ERROR_NONE Successful.
* @retval #ML_ERROR_INVALID_PARAMETER invalid parameter.
*/
- int realizeActivationType(Layer ¤t);
+ int realizeActivationType(const std::shared_ptr<LayerNode> &in_node);
/**
* @brief Realize flatten type to layer and insert it to layers
- * @param[in] current layer
+ * @param[in] in_node layernode
* @retval #ML_ERROR_NONE Successful.
* @retval #ML_ERROR_INVALID_PARAMETER invalid parameter.
*/
- int realizeFlattenType(Layer ¤t);
+ int realizeFlattenType(const std::shared_ptr<LayerNode> &in_node);
/**
* @brief adding loss layer at last position
this->weight_regularizer_constant = l->weight_regularizer_constant;
this->weight_initializer = l->weight_initializer;
this->trainable = l->trainable;
- this->distribute = l->distribute;
}
sharedConstTensors Layer::forwarding_with_val(sharedConstTensors input,
throw_status(status);
}
break;
- case PropertyType::distribute:
- if (!value.empty()) {
- status = setBoolean(distribute, value);
- throw_status(status);
- }
- break;
default:
std::string msg =
"[Layer] Unknown Layer Property Key for value " + std::string(value);
void Layer::printProperties(std::ostream &out) {
out << "Trainable: " << trainable << std::endl;
- out << "Distributed: " << distribute << std::endl;
printIfValid(out, PropertyType::weight_regularizer,
static_cast<int>(weight_regularizer));
printIfValid(out, PropertyType::weight_regularizer_constant,
WeightInitializer weight_initializer_ =
WeightInitializer::WEIGHT_XAVIER_UNIFORM,
WeightInitializer bias_initializer_ = WeightInitializer::WEIGHT_ZEROS,
- bool trainable_ = true, bool flatten_ = false,
- bool distribute_ = false) :
+ bool trainable_ = true) :
layer_props(props::Name()),
loss(0.0f),
activation_type(activation_type_),
weight_regularizer_constant(weight_regularizer_constant_),
weight_initializer(weight_initializer_),
bias_initializer(bias_initializer_),
- trainable(trainable_),
- distribute(distribute_) {
+ trainable(trainable_) {
setNumInputs(1);
setNumOutputs(1);
}
/**
* @brief Activation Type Getter
* @retval Activation Type.
+ * @todo This function will soon be removed
*/
- ActivationType getActivationType() { return this->activation_type; }
+ virtual ActivationType getActivationType() { return this->activation_type; }
/**
* @brief Copy Layer
virtual bool getTrainable() noexcept { return trainable; }
/**
- * @brief set distribute for this layer
- * @param[in] dist to enable/disable distribute
- */
- virtual void setDistribute(bool dist) { distribute = dist; }
-
- /**
- * @brief get distribute for this layer
- * @retval dist to enable/disable distribute
- */
- virtual bool getDistribute() noexcept { return distribute; }
-
- /**
* @brief get all weights of the layer
* @retval vector of all params
*/
return output_layers;
}
+ /**
+ * @brief Activation Setter
+ * @param[in] activation activation type
+ * @throw std::invalid_argument when ActivationType is unknown
+ * @todo This function will soon be removed
+ */
+ virtual void setActivation(ActivationType activation);
+
protected:
/**
* @brief Print Options when printing layer info
*/
bool trainable;
- // TODO: remove this from here
- /**
- * @brief making this true will iterating along with time distribution
- */
- bool distribute;
-
/**
* @brief weight_list in this layer. This contains all weights of the
* layer.
*/
std::vector<Weight> weights;
- /**
- * @brief Activation Setter
- * @param[in] activation activation type
- * @throw std::invalid_argument when ActivationType is unknown
- */
- virtual void setActivation(ActivationType activation);
-
private:
// TODO: remove this from here
/**
#include <layer_node.h>
#include <nntrainer_error.h>
#include <nntrainer_log.h>
+#include <time_dist.h>
namespace nntrainer {
+LayerNode::LayerNode(std::shared_ptr<nntrainer::Layer> l, size_t idx) :
+ layer(l),
+ index(idx),
+ flatten(false),
+ distribute(false),
+ activation_type(ActivationType::ACT_NONE) {
+ if (layer->getType() == TimeDistLayer::type)
+ distribute = true;
+}
+
/**
* @brief Layer factory creator with constructor
*/
}
}
- status = layer->setProperty(remainder);
+ status = getLayer()->setProperty(remainder);
return status;
}
void LayerNode::setProperty(const nntrainer::Layer::PropertyType type,
const std::string &value) {
int status = ML_ERROR_NONE;
+ using PropertyType = nntrainer::Layer::PropertyType;
switch (type) {
- case nntrainer::Layer::PropertyType::flatten:
+ case PropertyType::flatten:
if (!value.empty()) {
status = setBoolean(flatten, value);
throw_status(status);
}
break;
+ case PropertyType::distribute:
+ if (!value.empty()) {
+ status = setBoolean(distribute, value);
+ throw_status(status);
+ if (distribute) {
+ auto &ac = nntrainer::AppContext::Global();
+ std::shared_ptr<nntrainer::Layer> dlayer =
+ ac.createObject<nntrainer::Layer>(TimeDistLayer::type);
+ std::dynamic_pointer_cast<TimeDistLayer>(dlayer)->setDistLayer(layer);
+ layer = dlayer;
+ }
+ }
+ break;
default:
throw std::invalid_argument("Unknown property.");
}
return out;
}
+std::string LayerNode::getDistLayerType() const {
+ if (distribute)
+ return std::dynamic_pointer_cast<TimeDistLayer>(layer)->getDistLayerType();
+ else
+ throw std::runtime_error(
+ "Get distribution layer type for non-distributed layer");
+}
+
+ActivationType LayerNode::getActivationType() {
+ return getLayer()->getActivationType();
+}
+
+const std::string LayerNode::getType() const { return getLayer()->getType(); }
+
+std::shared_ptr<nntrainer::Layer> &LayerNode::getObject() { return getLayer(); }
+
+const std::shared_ptr<nntrainer::Layer> &LayerNode::getObject() const {
+ return getLayer();
+}
+
+bool LayerNode::getTrainable() const noexcept {
+ return getLayer()->getTrainable();
+}
+
+const std::shared_ptr<nntrainer::Layer> &LayerNode::getLayer() const {
+ if (distribute)
+ return std::dynamic_pointer_cast<TimeDistLayer>(layer)->getDistLayer();
+ else
+ return layer;
+}
+
+std::shared_ptr<nntrainer::Layer> &LayerNode::getLayer() {
+ if (distribute)
+ return std::dynamic_pointer_cast<TimeDistLayer>(layer)->getDistLayer();
+ else
+ return layer;
+}
+
}; // namespace nntrainer
* @brief Constructor of LayerNode class
*
*/
- LayerNode(std::shared_ptr<nntrainer::Layer> l, size_t idx = 0) :
- layer(l),
- index(idx),
- flatten(false),
- activation_type(ActivationType::ACT_NONE) {}
+ LayerNode(std::shared_ptr<nntrainer::Layer> l, size_t idx = 0);
/**
* @brief Destructor of LayerNode Class
*
* @return const std::string type representation
*/
- const std::string getType() const { return layer->getType(); }
+ const std::string getType() const;
/**
* @brief set Property of layer
* @note This name might be changed once this layer is added to the model
* to keep the name unique to the model
*/
- const std::string getName() const noexcept { return layer->getName(); }
+ const std::string getName() const noexcept { return getLayer()->getName(); }
/**
* @brief Get name of the layer
* @note This name might be changed once this layer is added to the model
* to keep the name unique to the model
*/
- std::string getName() noexcept { return layer->getName(); }
+ std::string getName() noexcept { return getLayer()->getName(); }
/**
* Support all the interface requirements by GraphNode<nntrainer::Layer>
* @brief Get underlying object
*
*/
- std::shared_ptr<nntrainer::Layer> &getObject() { return layer; }
+ std::shared_ptr<nntrainer::Layer> &getObject();
/**
* @brief Get underlying object
*
*/
- const std::shared_ptr<nntrainer::Layer> &getObject() const { return layer; }
+ const std::shared_ptr<nntrainer::Layer> &getObject() const;
/**
* @brief Get index of the node
*
*/
- size_t getIndex() { return index; }
+ size_t getIndex() const { return index; }
/**
* @brief Get the trainable property of the underlying object
*
* @return boolean true if trainable, else false
*/
- bool getTrainable() noexcept { return layer->getTrainable(); }
+ bool getTrainable() const noexcept;
/**
* Support interfaces for the properties intercepted from layer
* @brief get if the output of this layer must be flatten
* @retval flatten value
*/
- bool getFlatten() { return flatten; }
+ bool getFlatten() const { return flatten; }
+
+ /**
+ * @brief get distribute for this layer
+ * @retval dist to enable/disable distribute
+ */
+ bool getDistribute() const noexcept { return distribute; }
+
+ /**
+ * @brief get distribute for this layer
+ * @retval dist to enable/disable distribute
+ */
+ std::string getDistLayerType() const;
+
+ /**
+ * @brief Activation Type Getter
+ * @retval Activation Type.
+ */
+ ActivationType getActivationType();
#ifdef PROFILE
int event_key;
std::vector<std::string> input_layers; /**< input layer names */
std::vector<std::string> output_layers; /**< output layer names */
- bool flatten; /**< flatten the output of this node */
+ bool flatten; /**< flatten the output of this node */
+ bool distribute; /**< to enable itearting along with time distribution */
ActivationType
activation_type; /**< activation applied to the output of this node */
- bool distribute;
/**
* These properties are set for the layer by the user but are intercepted
* the particular layer
* @exception std::invalid_argument invalid argument
*/
- virtual void setProperty(const nntrainer::Layer::PropertyType type,
- const std::string &value = "");
+ void setProperty(const nntrainer::Layer::PropertyType type,
+ const std::string &value = "");
+
+ /**
+ * @brief Get the effective layer managed by this layer node
+ *
+ * @details this is layer inside the distribution layer if this layer node
+ * is distributed.
+ */
+ const std::shared_ptr<nntrainer::Layer> &getLayer() const;
+
+ /**
+ * @brief Get the effective layer managed by this layer node
+ *
+ * @details this is layer inside the distribution layer if this layer node
+ * is distributed.
+ */
+ std::shared_ptr<nntrainer::Layer> &getLayer();
};
/**
* @brief get distribute layer
* @retval dist_layer std::shared_ptr<Layer>
*/
- std::shared_ptr<Layer> getDistLayer() { return dist_layer; };
+ std::shared_ptr<Layer> &getDistLayer() { return dist_layer; };
/**
* @brief get transposed Tensor according to time iteration axis
*/
void setProperty(const PropertyType type,
const std::string &value = "") override {
+ /**
+ * @note assumption: name of the dist_layer is set via setName() and not
+ * with setProperty()
+ */
dist_layer->setProperty(type, value);
}
#include <flatten_layer.h>
#include <input_layer.h>
#include <layer_internal.h>
+#include <layer_node.h>
#include <loss_layer.h>
#include <lstm.h>
#include <manager.h>
const nntrainer::TensorDim &dim) {
nntrainer::Tensor golden(dim);
loadFile(expected, golden);
- /** FIXME: golden.length() is possibly 0 many times, verify and fix this */
matchOutput(result, golden.getData(), golden.length());
}
}
/**
- * @brief Fully Connected Layer
- */
-TEST_F(nntrainer_FullyConnectedLayer, setDistribute_01_p) {
- status = layer.setProperty({"distribute=true"});
- EXPECT_EQ(status, ML_ERROR_NONE);
-}
-
-/**
* @brief FullyConnected Layer
*/
TEST_F(nntrainer_FullyConnectedLayer, checkValidation_01_p) {
}
/**
+ * @brief Layer Node
+ */
+TEST(nntrainer_LayerNode, setDistribute_01_p) {
+ int status = ML_ERROR_NONE;
+
+ auto lnode = nntrainer::createLayerNode(nntrainer::FullyConnectedLayer::type);
+
+ EXPECT_EQ(false, lnode->getDistribute());
+
+ status = lnode->setProperty({"distribute=true"});
+ EXPECT_EQ(status, ML_ERROR_NONE);
+
+ EXPECT_EQ(true, lnode->getDistribute());
+}
+
+/**
+ * @brief Layer Node
+ */
+TEST(nntrainer_LayerNode, setFlatten_01_p) {
+ int status = ML_ERROR_NONE;
+
+ auto lnode = nntrainer::createLayerNode(nntrainer::FullyConnectedLayer::type);
+ status = lnode->setProperty({"flatten=true"});
+ EXPECT_EQ(status, ML_ERROR_NONE);
+}
+
+/**
* @brief Main gtest
*/
int main(int argc, char **argv) {