Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Wait for #2725][Layer] add "divide layer" #2726

Merged
merged 1 commit into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions api/ccapi/include/layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ enum LayerType {
LAYER_ADD = ML_TRAIN_LAYER_TYPE_ADD, /**< Add Layer type */
LAYER_SUBTRACT = ML_TRAIN_LAYER_TYPE_SUBTRACT, /**< Subtract Layer type */
LAYER_MULTIPLY = ML_TRAIN_LAYER_TYPE_MULTIPLY, /**< Multiply Layer type */
LAYER_DIVIDE = ML_TRAIN_LAYER_TYPE_DIVIDE, /**< Divide Layer type */
LAYER_FC = ML_TRAIN_LAYER_TYPE_FC, /**< Fully Connected Layer type */
LAYER_SWIGLU = ML_TRAIN_LAYER_TYPE_SWIGLU, /**< Swiglu Layer type */
LAYER_BN = ML_TRAIN_LAYER_TYPE_BN, /**< Batch Normalization Layer type */
Expand Down Expand Up @@ -332,6 +333,14 @@ MultiplyLayer(const std::vector<std::string> &properties = {}) {
return createLayer(LayerType::LAYER_MULTIPLY, properties);
}

/**
* @brief Helper function to create divide layer
*/
inline std::unique_ptr<Layer>
DivideLayer(const std::vector<std::string> &properties = {}) {
return createLayer(LayerType::LAYER_DIVIDE, properties);
}

/**
* @brief Helper function to create fully connected layer
*/
Expand Down
1 change: 1 addition & 0 deletions api/nntrainer-api-common.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ typedef enum {
ML_TRAIN_LAYER_TYPE_ADD = 32, /**< Add Layer type (Since 9.0)*/
ML_TRAIN_LAYER_TYPE_SUBTRACT = 33, /**< Subtract Layer type (Since 9.0)*/
ML_TRAIN_LAYER_TYPE_MULTIPLY = 34, /**< Multiply Layer type (Since 9.0)*/
ML_TRAIN_LAYER_TYPE_DIVIDE = 35, /**< Divide Layer type (Since 9.0)*/
ML_TRAIN_LAYER_TYPE_PREPROCESS_FLIP =
300, /**< Preprocess flip Layer (Since 6.5) */
ML_TRAIN_LAYER_TYPE_PREPROCESS_TRANSLATE =
Expand Down
3 changes: 3 additions & 0 deletions nntrainer/app_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include <conv2d_layer.h>
#include <cross_entropy_sigmoid_loss_layer.h>
#include <cross_entropy_softmax_loss_layer.h>
#include <divide_layer.h>
#include <dropout.h>
#include <embedding.h>
#include <fc_layer.h>
Expand Down Expand Up @@ -262,6 +263,8 @@ static void add_default_object(AppContext &ac) {
LayerType::LAYER_SUBTRACT);
ac.registerFactory(nntrainer::createLayer<MultiplyLayer>, MultiplyLayer::type,
LayerType::LAYER_MULTIPLY);
ac.registerFactory(nntrainer::createLayer<DivideLayer>, DivideLayer::type,
LayerType::LAYER_DIVIDE);
ac.registerFactory(nntrainer::createLayer<FullyConnectedLayer>,
FullyConnectedLayer::type, LayerType::LAYER_FC);
ac.registerFactory(nntrainer::createLayer<BatchNormalizationLayer>,
Expand Down
52 changes: 52 additions & 0 deletions nntrainer/layers/divide_layer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-License-Identifier: Apache-2.0
/**
* Copyright (C) 2024 SeungBaek Hong <[email protected]>
*
* @file divide_layer.cpp
* @date 10 Oct 2024
* @see https://github.com/nnstreamer/nntrainer
* @author SeungBaek Hong <[email protected]>
* @bug No known bugs except for NYI items
* @brief This is div layer class (operation layer)
*
*/

#include <divide_layer.h>
#include <nntrainer_error.h>
#include <nntrainer_log.h>
#include <node_exporter.h>
#include <util_func.h>

#include <layer_context.h>

namespace nntrainer {

void DivideLayer::finalize(InitLayerContext &context) {
context.setOutputDimensions({context.getInputDimensions()[0]});
}

void DivideLayer::forwarding_operation(const Tensor &input0,
const Tensor &input1, Tensor &hidden) {
input0.divide(input1, hidden);
}

void DivideLayer::calcDerivative(RunLayerContext &context) {
context.getOutgoingDerivative(0).copy(
context.getIncomingDerivative(SINGLE_INOUT_IDX)
.divide(context.getInput(1)));

context.getOutgoingDerivative(1).copy(
context.getIncomingDerivative(SINGLE_INOUT_IDX)
.multiply(context.getInput(0).multiply(-1))
.divide(context.getInput(1).pow(2)));
}

void DivideLayer::setProperty(const std::vector<std::string> &values) {
auto remain_props = loadProperties(values, divide_props);
if (!remain_props.empty()) {
std::string msg = "[DivideLayer] Unknown Layer Properties count " +
std::to_string(values.size());
throw exception::not_supported(msg);
}
}
} /* namespace nntrainer */
102 changes: 102 additions & 0 deletions nntrainer/layers/divide_layer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// SPDX-License-Identifier: Apache-2.0
/**
* Copyright (C) 2024 SeungBaek Hong <[email protected]>
*
* @file divide_layer.h
* @date 10 Oct 2024
* @see https://github.com/nnstreamer/nntrainer
* @author SeungBaek Hong <[email protected]>
* @bug No known bugs except for NYI items
* @brief This is div layer class (operation layer)
*
*/

#ifndef __DIVIDE_LAYER_H__
#define __DIVIDE_LAYER_H__
#ifdef __cplusplus

#include <common_properties.h>
#include <layer_devel.h>
#include <operation_layer.h>

namespace nntrainer {

/**
* @class Divide Layer
* @brief Divide Layer
*/
class DivideLayer : public BinaryOperationLayer {
public:
/**
* @brief Constructor of Divide Layer
*/
DivideLayer() : BinaryOperationLayer(), divide_props(props::Print()) {}

/**
* @brief Destructor of Divide Layer
*/
~DivideLayer(){};

/**
* @brief Move constructor of Divide Layer.
* @param[in] DivideLayer &&
*/
DivideLayer(DivideLayer &&rhs) noexcept = default;

/**
* @brief Move assignment operator.
* @parma[in] rhs DivideLayer to be moved.
*/
DivideLayer &operator=(DivideLayer &&rhs) = default;

/**
* @copydoc Layer::finalize(InitLayerContext &context)
*/
void finalize(InitLayerContext &context) final;

/**
* @brief forwarding operation for add
*
* @param input0 input tensor 0
* @param input1 input tensor 1
* @param hidden tensor to store the result of addition
*/
void forwarding_operation(const Tensor &input0, const Tensor &input1,
Tensor &hidden) final;

/**
* @copydoc Layer::calcDerivative(RunLayerContext &context)
*/
void calcDerivative(RunLayerContext &context) final;

/**
* @copydoc bool supportBackwarding() const
*/
bool supportBackwarding() const final { return true; };

/**
* @copydoc Layer::exportTo(Exporter &exporter, ml::train::ExportMethods
* method)
*/
void exportTo(Exporter &exporter,
const ml::train::ExportMethods &method) const final {}

/**
* @copydoc Layer::setProperty(const std::vector<std::string> &values)
*/
void setProperty(const std::vector<std::string> &values) final;

/**
* @copydoc Layer::getType()
*/
const std::string getType() const final { return DivideLayer::type; };

std::tuple<props::Print> divide_props;

inline static const std::string type = "divide";
};

} // namespace nntrainer

#endif /* __cplusplus */
#endif /* __DIVIDE_LAYER_H__ */
1 change: 1 addition & 0 deletions nntrainer/layers/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ layer_sources = [
'add_layer.cpp',
'subtract_layer.cpp',
'multiply_layer.cpp',
'divide_layer.cpp',
'addition_layer.cpp',
'attention_layer.cpp',
'mol_attention_layer.cpp',
Expand Down
13 changes: 13 additions & 0 deletions test/input_gen/genModelTests_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,19 @@ def forward(self, inputs, labels):
return out, loss


class DivideOperation(torch.nn.Module):
def __init__(self):
super().__init__()
self.fc = torch.nn.Linear(2, 2)
self.loss = torch.nn.MSELoss()

def forward(self, inputs, labels):
out = self.fc(inputs[0])
out = inputs[0] / out
loss = self.loss(out, labels[0])
return out, loss


if __name__ == "__main__":
record_v2(
ReduceMeanLast(),
Expand Down
1 change: 1 addition & 0 deletions test/unittest/layers/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ test_target = [
'unittest_layers_add.cpp',
'unittest_layers_subtract.cpp',
'unittest_layers_multiply.cpp',
'unittest_layers_divide.cpp',
'unittest_layers_multiout.cpp',
'unittest_layers_rnn.cpp',
'unittest_layers_rnncell.cpp',
Expand Down
28 changes: 28 additions & 0 deletions test/unittest/layers/unittest_layers_divide.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: Apache-2.0
/**
* Copyright (C) 2024 SeungBaek Hong <[email protected]>
*
* @file unittest_layers_divide.cpp
* @date 30 August 2024
* @brief Divide Layer Test
* @see https://github.com/nnstreamer/nntrainer
* @author SeungBaek Hong <[email protected]>
* @bug No known bugs except for NYI items
*/
#include <tuple>

#include <gtest/gtest.h>

#include <divide_layer.h>
#include <layers_common_tests.h>

auto semantic_divide = LayerSemanticsParamType(
nntrainer::createLayer<nntrainer::DivideLayer>, nntrainer::DivideLayer::type,
{}, LayerCreateSetPropertyOptions::AVAILABLE_FROM_APP_CONTEXT, false, 1);

auto semantic_divide_multi = LayerSemanticsParamType(
nntrainer::createLayer<nntrainer::DivideLayer>, nntrainer::DivideLayer::type,
{}, LayerCreateSetPropertyOptions::AVAILABLE_FROM_APP_CONTEXT, false, 2);

GTEST_PARAMETER_TEST(Divide, LayerSemantics,
::testing::Values(semantic_divide, semantic_divide_multi));
21 changes: 21 additions & 0 deletions test/unittest/models/unittest_models.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -929,6 +929,25 @@ static std::unique_ptr<NeuralNetwork> makeMultiplyOperation() {
return nn;
}

static std::unique_ptr<NeuralNetwork> makeDivideOperation() {
std::unique_ptr<NeuralNetwork> nn(new NeuralNetwork());

auto outer_graph =
makeGraph({{"input", {"name=in", "input_shape=1:1:2"}},
{"fully_connected", {"name=fc", "unit=2", "input_layers=in"}},
{"divide", {"name=divide_layer", "input_layers=in,fc"}},
{"mse", {"name=loss", "input_layers=divide_layer"}}});

for (auto &node : outer_graph) {
nn->addLayer(node);
}

nn->setProperty({"batch_size=1"});
nn->setOptimizer(ml::train::createOptimizer("sgd", {"learning_rate=0.1"}));

return nn;
}

GTEST_PARAMETER_TEST(
model, nntrainerModelTest,
::testing::ValuesIn({
Expand Down Expand Up @@ -1005,6 +1024,8 @@ GTEST_PARAMETER_TEST(
ModelTestOption::ALL_V2),
mkModelTc_V2(makeMultiplyOperation, "multiply_operation",
ModelTestOption::ALL_V2),
mkModelTc_V2(makeDivideOperation, "divide_operation",
ModelTestOption::ALL_V2),
}),
[](const testing::TestParamInfo<nntrainerModelTest::ParamType> &info)
-> const auto & { return std::get<1>(info.param); });
Expand Down
Loading