Skip to content
Snippets Groups Projects
Commit 678c51ce authored by Maxence Naud's avatar Maxence Naud
Browse files

Move MetaOp PaddedAvgPooling and LSTM definition to cpp files

parent 75062905
No related branches found
No related tags found
No related merge requests found
...@@ -12,22 +12,26 @@ ...@@ -12,22 +12,26 @@
#ifndef AIDGE_CORE_OPERATOR_METAOPERATORDEFS_H_ #ifndef AIDGE_CORE_OPERATOR_METAOPERATORDEFS_H_
#define AIDGE_CORE_OPERATOR_METAOPERATORDEFS_H_ #define AIDGE_CORE_OPERATOR_METAOPERATORDEFS_H_
#include <array>
#include <memory>
#include <string>
#include "aidge/graph/GraphView.hpp"
#include "aidge/graph/Node.hpp"
#include "aidge/graph/OpArgs.hpp" // Sequential
#include "aidge/operator/MetaOperator.hpp" #include "aidge/operator/MetaOperator.hpp"
#include "aidge/operator/AvgPooling.hpp" #include "aidge/operator/AvgPooling.hpp"
#include "aidge/operator/MaxPooling.hpp" #include "aidge/operator/MaxPooling.hpp"
#include "aidge/operator/Conv.hpp" #include "aidge/operator/Conv.hpp"
#include "aidge/operator/ConvDepthWise.hpp" #include "aidge/operator/ConvDepthWise.hpp"
#include "aidge/operator/Pad.hpp" #include "aidge/operator/Pad.hpp"
#include "aidge/operator/Memorize.hpp"
#include "aidge/operator/Add.hpp"
#include "aidge/operator/Mul.hpp"
#include "aidge/operator/FC.hpp"
#include "aidge/operator/Identity.hpp"
#include "aidge/operator/Concat.hpp"
#include "aidge/operator/Tanh.hpp"
#include "aidge/operator/Sigmoid.hpp" #include "aidge/operator/Sigmoid.hpp"
#include "aidge/utils/ArrayHelpers.hpp"
#include "aidge/utils/Types.h"
namespace Aidge { namespace Aidge {
template <std::array<DimSize_t, 1>::size_type DIM> template <std::array<DimSize_t, 1>::size_type DIM>
inline std::shared_ptr<Node> PaddedConv(DimSize_t in_channels, inline std::shared_ptr<Node> PaddedConv(DimSize_t in_channels,
DimSize_t out_channels, DimSize_t out_channels,
...@@ -40,7 +44,7 @@ inline std::shared_ptr<Node> PaddedConv(DimSize_t in_channels, ...@@ -40,7 +44,7 @@ inline std::shared_ptr<Node> PaddedConv(DimSize_t in_channels,
{ {
// Construct micro-graph // Construct micro-graph
auto pad = Pad<DIM>(padding_dims, (!name.empty()) ? name + "_pad" : "", PadBorderType::Constant, 0.0); auto pad = Pad<DIM>(padding_dims, (!name.empty()) ? name + "_pad" : "", PadBorderType::Constant, 0.0);
auto conv = std::make_shared<Node>(std::make_shared<Conv_Op<static_cast<DimIdx_t>(DIM)>>(in_channels, out_channels, kernel_dims, stride_dims, dilation_dims, no_bias), (!name.empty()) ? name + "_conv" : ""); auto conv = std::make_shared<Node>(std::make_shared<Conv_Op<static_cast<DimIdx_t>(DIM)>>(kernel_dims, stride_dims, dilation_dims, no_bias), (!name.empty()) ? name + "_conv" : "");
auto metaOp = MetaOperator("PaddedConv", Sequential({pad, conv}), name); auto metaOp = MetaOperator("PaddedConv", Sequential({pad, conv}), name);
addProducer(metaOp, 1, append(out_channels, append(in_channels, kernel_dims)), "w"); addProducer(metaOp, 1, append(out_channels, append(in_channels, kernel_dims)), "w");
...@@ -48,6 +52,20 @@ inline std::shared_ptr<Node> PaddedConv(DimSize_t in_channels, ...@@ -48,6 +52,20 @@ inline std::shared_ptr<Node> PaddedConv(DimSize_t in_channels,
return metaOp; return metaOp;
} }
template <std::array<DimSize_t, 1>::size_type DIM>
inline std::shared_ptr<MetaOperator_Op> PaddedConv_Op(
const std::array<DimSize_t, DIM> &kernel_dims,
const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1),
const std::array<DimSize_t, 2*DIM> &padding_dims = create_array<DimSize_t,2*DIM>(0),
const std::array<DimSize_t, DIM> &dilation_dims = create_array<DimSize_t,DIM>(1),
bool no_bias = false)
{
auto pad = Pad<DIM>(padding_dims, "", PadBorderType::Constant, 0.0);
auto conv = std::make_shared<Node>(std::make_shared<Conv_Op<static_cast<DimIdx_t>(DIM)>>(kernel_dims, stride_dims, dilation_dims, no_bias), "");
return std::make_shared<MetaOperator_Op>("PaddedConv", Sequential({pad, conv}));
}
// helper with C-style array instead of std::array for kernel_dims to allow automatic template DIM deduction // helper with C-style array instead of std::array for kernel_dims to allow automatic template DIM deduction
template <DimSize_t DIM> template <DimSize_t DIM>
inline std::shared_ptr<Node> PaddedConv( inline std::shared_ptr<Node> PaddedConv(
...@@ -63,6 +81,8 @@ inline std::shared_ptr<Node> PaddedConv( ...@@ -63,6 +81,8 @@ inline std::shared_ptr<Node> PaddedConv(
return PaddedConv(in_channels, out_channels, to_array(kernel_dims), name, stride_dims, padding_dims, dilation_dims, no_bias); return PaddedConv(in_channels, out_channels, to_array(kernel_dims), name, stride_dims, padding_dims, dilation_dims, no_bias);
} }
////////////////////////////////////////////////////////////////////////////////
template <std::array<DimSize_t, 1>::size_type DIM> template <std::array<DimSize_t, 1>::size_type DIM>
inline std::shared_ptr<Node> PaddedConvDepthWise(const DimSize_t nb_channels, inline std::shared_ptr<Node> PaddedConvDepthWise(const DimSize_t nb_channels,
const std::array<DimSize_t, DIM> &kernel_dims, const std::array<DimSize_t, DIM> &kernel_dims,
...@@ -74,7 +94,7 @@ inline std::shared_ptr<Node> PaddedConvDepthWise(const DimSize_t nb_channels, ...@@ -74,7 +94,7 @@ inline std::shared_ptr<Node> PaddedConvDepthWise(const DimSize_t nb_channels,
{ {
// Construct micro-graph // Construct micro-graph
auto pad = Pad<DIM>(padding_dims, (!name.empty()) ? name + "_pad" : "", PadBorderType::Constant, 0.0); auto pad = Pad<DIM>(padding_dims, (!name.empty()) ? name + "_pad" : "", PadBorderType::Constant, 0.0);
auto conv = std::make_shared<Node>(std::make_shared<ConvDepthWise_Op<static_cast<DimIdx_t>(DIM)>>(nb_channels, kernel_dims, stride_dims, dilation_dims, no_bias), (!name.empty()) ? name + "_conv" : ""); auto conv = std::make_shared<Node>(std::make_shared<ConvDepthWise_Op<static_cast<DimIdx_t>(DIM)>>(kernel_dims, stride_dims, dilation_dims, no_bias), (!name.empty()) ? name + "_conv" : "");
auto metaOp = MetaOperator("PaddedConvDepthWise", Sequential({pad, conv}), name); auto metaOp = MetaOperator("PaddedConvDepthWise", Sequential({pad, conv}), name);
addProducer(metaOp, 1, append(nb_channels, append(DimSize_t(1), kernel_dims)), "w"); addProducer(metaOp, 1, append(nb_channels, append(DimSize_t(1), kernel_dims)), "w");
...@@ -82,6 +102,20 @@ inline std::shared_ptr<Node> PaddedConvDepthWise(const DimSize_t nb_channels, ...@@ -82,6 +102,20 @@ inline std::shared_ptr<Node> PaddedConvDepthWise(const DimSize_t nb_channels,
return metaOp; return metaOp;
} }
template <std::array<DimSize_t, 1>::size_type DIM>
inline std::shared_ptr<MetaOperator_Op> PaddedConvDepthWise_Op(
const std::array<DimSize_t, DIM> &kernel_dims,
const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1),
const std::array<DimSize_t, 2*DIM> &padding_dims = create_array<DimSize_t,2*DIM>(0),
const std::array<DimSize_t, DIM> &dilation_dims = create_array<DimSize_t,DIM>(1),
bool no_bias = false)
{
auto pad = Pad<DIM>(padding_dims, "", PadBorderType::Constant, 0.0);
auto conv = std::make_shared<Node>(std::make_shared<ConvDepthWise_Op<static_cast<DimIdx_t>(DIM)>>(kernel_dims, stride_dims, dilation_dims, no_bias), "");
return std::make_shared<MetaOperator_Op>("PaddedConvDepthWise", Sequential({pad, conv}));
}
// helper with C-style array instead of std::array for kernel_dims to allow automatic template DIM deduction // helper with C-style array instead of std::array for kernel_dims to allow automatic template DIM deduction
template <DimSize_t DIM> template <DimSize_t DIM>
inline std::shared_ptr<Node> PaddedConvDepthWise( inline std::shared_ptr<Node> PaddedConvDepthWise(
...@@ -96,30 +130,29 @@ inline std::shared_ptr<Node> PaddedConvDepthWise( ...@@ -96,30 +130,29 @@ inline std::shared_ptr<Node> PaddedConvDepthWise(
return PaddedConvDepthWise(nb_channels, to_array(kernel_dims), name, stride_dims, padding_dims, dilation_dims, no_bias); return PaddedConvDepthWise(nb_channels, to_array(kernel_dims), name, stride_dims, padding_dims, dilation_dims, no_bias);
} }
////////////////////////////////////////////////////////////////////////////////
template <std::array<DimSize_t, 1>::size_type DIM> template <std::array<DimSize_t, 1>::size_type DIM>
inline std::shared_ptr<Node> PaddedAvgPooling(const std::array<DimSize_t, DIM> &kernel_dims, extern std::shared_ptr<Node> PaddedAvgPooling(const std::array<DimSize_t, DIM> &kernel_dims,
const std::string& name = "", const std::string& name = "",
const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1), const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1),
const std::array<DimSize_t, 2*DIM> &padding_dims = create_array<DimSize_t,2*DIM>(0)) const std::array<DimSize_t, 2*DIM> &padding_dims = create_array<DimSize_t,2*DIM>(0));
{
auto graph = Sequential({
Pad<DIM>(padding_dims, (!name.empty()) ? name + "_pad" : ""),
AvgPooling(kernel_dims, (!name.empty()) ? name + "_avgpooling" : "", stride_dims)
});
return MetaOperator("PaddedAvgPooling", graph, name);
} template <std::array<DimSize_t, 1>::size_type DIM>
extern std::shared_ptr<MetaOperator_Op> PaddedAvgPooling_Op(const std::array<DimSize_t, DIM> &kernel_dims,
const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1),
const std::array<DimSize_t, 2*DIM> &padding_dims = create_array<DimSize_t,2*DIM>(0));
// helper with C-style array instead of std::array for kernel_dims to allow automatic template DIM deduction // helper with C-style array instead of std::array for kernel_dims to allow automatic template DIM deduction
template <DimSize_t DIM> template <DimSize_t DIM>
inline std::shared_ptr<Node> PaddedAvgPooling( extern std::shared_ptr<Node> PaddedAvgPooling(DimSize_t const (&kernel_dims)[DIM],
DimSize_t const (&kernel_dims)[DIM],
const std::string& name = "", const std::string& name = "",
const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1), const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1),
const std::array<DimSize_t, 2*DIM> &padding_dims = create_array<DimSize_t,2*DIM>(0)) const std::array<DimSize_t, 2*DIM> &padding_dims = create_array<DimSize_t,2*DIM>(0));
{
return PaddedAvgPooling(to_array(kernel_dims), name, stride_dims, padding_dims); ////////////////////////////////////////////////////////////////////////////////
}
template <std::array<DimSize_t, 1>::size_type DIM> template <std::array<DimSize_t, 1>::size_type DIM>
inline std::shared_ptr<Node> PaddedMaxPooling(const std::array<DimSize_t, DIM> &kernel_dims, inline std::shared_ptr<Node> PaddedMaxPooling(const std::array<DimSize_t, DIM> &kernel_dims,
...@@ -136,6 +169,20 @@ inline std::shared_ptr<Node> PaddedMaxPooling(const std::array<DimSize_t, DIM> & ...@@ -136,6 +169,20 @@ inline std::shared_ptr<Node> PaddedMaxPooling(const std::array<DimSize_t, DIM> &
return MetaOperator("PaddedMaxPooling", graph, name); return MetaOperator("PaddedMaxPooling", graph, name);
} }
template <std::array<DimSize_t, 1>::size_type DIM>
inline std::shared_ptr<MetaOperator_Op> PaddedMaxPooling_Op(const std::array<DimSize_t, DIM> &kernel_dims,
const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1),
const std::array<DimSize_t, 2*DIM> &padding_dims = create_array<DimSize_t,2*DIM>(0),
bool ceil_mode = false)
{
auto graph = Sequential({
Pad<DIM>(padding_dims, ""),
MaxPooling(kernel_dims, "", stride_dims, ceil_mode)
});
return std::make_shared<MetaOperator_Op>("PaddedMaxPooling", graph);
}
// helper with C-style array instead of std::array for kernel_dims to allow automatic template DIM deduction // helper with C-style array instead of std::array for kernel_dims to allow automatic template DIM deduction
template <DimSize_t DIM> template <DimSize_t DIM>
inline std::shared_ptr<Node> PaddedMaxPooling( inline std::shared_ptr<Node> PaddedMaxPooling(
...@@ -148,115 +195,17 @@ inline std::shared_ptr<Node> PaddedMaxPooling( ...@@ -148,115 +195,17 @@ inline std::shared_ptr<Node> PaddedMaxPooling(
return PaddedMaxPooling(to_array(kernel_dims), name, stride_dims, padding_dims, ceil_mode); return PaddedMaxPooling(to_array(kernel_dims), name, stride_dims, padding_dims, ceil_mode);
} }
inline std::shared_ptr<Node> LSTM(DimSize_t in_channels, ////////////////////////////////////////////////////////////////////////////////
DimSize_t hidden_channels,
DimSize_t seq_length, std::shared_ptr<Node> LSTM(DimSize_t in_channels,
bool noBias = false, DimSize_t hidden_channels,
const std::string& name = "") DimSize_t seq_length,
{ bool noBias = false,
// Construct micro-graph const std::string& name = "");
auto input = Identity((!name.empty()) ? name + "_input" : "");
auto hiddenState = Memorize(seq_length, (!name.empty()) ? name + "_hidden_state" : ""); std::shared_ptr<MetaOperator_Op> LSTM_Op(DimSize_t seq_length,
auto cellState = Memorize(seq_length, (!name.empty()) ? name + "_cell_state" : ""); bool noBias = false);
auto add = Add(2, (!name.empty()) ? name + "_add" : "");
// Forget gate
auto forgetGateX = std::make_shared<Node>(std::make_shared<FC_Op>(hidden_channels, noBias), (!name.empty()) ? name + "_forgetGateX" : "");
input->addChild(forgetGateX, 0, 0);
auto forgetGateH = std::make_shared<Node>(std::make_shared<FC_Op>(hidden_channels, noBias), (!name.empty()) ? name + "_forgetGateH" : "");
hiddenState->addChild(forgetGateH, 1, 0);
auto forgetGate = Add(2, (!name.empty()) ? name + "_forgetGate" : "");
forgetGateX->addChild(forgetGate, 0, 0);
forgetGateH->addChild(forgetGate, 0, 1);
auto forgetGateAct = Sigmoid((!name.empty()) ? name + "_forgetGateAct" : "");
auto forgetGateMul = Mul((!name.empty()) ? name + "_forgetGateMul" : "");
forgetGate->addChild(forgetGateAct, 0, 0);
forgetGateAct->addChild(forgetGateMul, 0, 0);
forgetGateMul->addChild(add, 0, 0);
cellState->addChild(forgetGateMul, 1, 1);
// Input gate
auto inputGateX = std::make_shared<Node>(std::make_shared<FC_Op>(hidden_channels, noBias), (!name.empty()) ? name + "_inputGateX" : "");
input->addChild(inputGateX, 0, 0);
auto inputGateH = std::make_shared<Node>(std::make_shared<FC_Op>(hidden_channels, noBias), (!name.empty()) ? name + "_inputGateH" : "");
hiddenState->addChild(inputGateH, 1, 0);
auto inputGate = Add(2, (!name.empty()) ? name + "_inputGate" : "");
inputGateX->addChild(inputGate, 0, 0);
inputGateH->addChild(inputGate, 0, 1);
auto inputGateAct = Sigmoid((!name.empty()) ? name + "_inputGateAct" : "");
auto inputGateMul = Mul((!name.empty()) ? name + "_inputGateMul" : "");
inputGate->addChild(inputGateAct, 0, 0);
inputGateAct->addChild(inputGateMul, 0, 0);
inputGateMul->addChild(add, 0, 1);
// Candidate for cell update
auto cellCandidateX = std::make_shared<Node>(std::make_shared<FC_Op>(hidden_channels, noBias), (!name.empty()) ? name + "_cellCandidateX" : "");
input->addChild(cellCandidateX, 0, 0);
auto cellCandidateH = std::make_shared<Node>(std::make_shared<FC_Op>(hidden_channels, noBias), (!name.empty()) ? name + "_cellCandidateH" : "");
hiddenState->addChild(cellCandidateH, 1, 0);
auto cellCandidate = Add(2, (!name.empty()) ? name + "_cellCandidate" : "");
cellCandidateX->addChild(cellCandidate, 0, 0);
cellCandidateH->addChild(cellCandidate, 0, 1);
auto cellCandidateAct = Tanh((!name.empty()) ? name + "_cellCandidateAct" : "");
cellCandidate->addChild(cellCandidateAct, 0, 0);
cellCandidateAct->addChild(inputGateMul, 0, 1);
// Output gate
auto outputGateX = std::make_shared<Node>(std::make_shared<FC_Op>(hidden_channels, noBias), (!name.empty()) ? name + "_outputGateX" : "");
input->addChild(outputGateX, 0, 0);
auto outputGateH = std::make_shared<Node>(std::make_shared<FC_Op>(hidden_channels, noBias), (!name.empty()) ? name + "_outputGateH" : "");
hiddenState->addChild(outputGateH, 1, 0);
auto outputGate = Add(2, (!name.empty()) ? name + "_outputGate" : "");
outputGateX->addChild(outputGate, 0, 0);
outputGateH->addChild(outputGate, 0, 1);
auto outputGateAct = Sigmoid((!name.empty()) ? name + "_outputGateAct" : "");
auto outputGateMul = Mul((!name.empty()) ? name + "_outputGateMul" : "");
outputGate->addChild(outputGateAct, 0, 0);
outputGateAct->addChild(outputGateMul, 0, 0);
// Updated cell state to help determine new hidden state
auto cellUpdatedAct = Tanh((!name.empty()) ? name + "_cellUpdatedAct" : "");
add->addChild(cellUpdatedAct, 0, 0);
cellUpdatedAct->addChild(outputGateMul, 0, 1);
outputGateMul->addChild(hiddenState, 0, 0);
add->addChild(cellState, 0, 0);
std::shared_ptr<GraphView> microGraph = std::make_shared<GraphView>();
microGraph->add(input);
microGraph->add({hiddenState, cellState, add,
forgetGateX, forgetGateH, forgetGate, forgetGateAct, forgetGateMul,
inputGateX, inputGateH, inputGate, inputGateAct, inputGateMul,
cellCandidateX, cellCandidateH, cellCandidate, cellCandidateAct,
outputGateX, outputGateH, outputGate, outputGateAct, outputGateMul,
cellUpdatedAct}, false);
microGraph->setOrderedInputs({{input, 0},
{inputGateX, 1}, {outputGateX, 1}, {forgetGateX, 1}, {cellCandidateX, 1},
{inputGateH, 1}, {outputGateH, 1}, {forgetGateH, 1}, {cellCandidateH, 1},
{inputGateX, 2}, {outputGateX, 2}, {forgetGateX, 2}, {cellCandidateX, 2},
{inputGateH, 2}, {outputGateH, 2}, {forgetGateH, 2}, {cellCandidateH, 2},
{hiddenState, 1}, {cellState, 1}});
microGraph->setOrderedOutputs({{hiddenState, 0}, {cellState, 0}});
auto metaOp = MetaOperator("LSTM", microGraph, name);
addProducer(metaOp, 1, {hidden_channels, in_channels}, "wi");
addProducer(metaOp, 2, {hidden_channels, in_channels}, "wo");
addProducer(metaOp, 3, {hidden_channels, in_channels}, "wf");
addProducer(metaOp, 4, {hidden_channels, in_channels}, "wc");
addProducer(metaOp, 5, {hidden_channels, hidden_channels}, "ri");
addProducer(metaOp, 6, {hidden_channels, hidden_channels}, "ro");
addProducer(metaOp, 7, {hidden_channels, hidden_channels}, "rf");
addProducer(metaOp, 8, {hidden_channels, hidden_channels}, "rc");
addProducer(metaOp, 9, {(noBias ? 0 : hidden_channels)}, "wbi");
addProducer(metaOp, 10, {(noBias ? 0 : hidden_channels)}, "wbo");
addProducer(metaOp, 11, {(noBias ? 0 : hidden_channels)}, "wbf");
addProducer(metaOp, 12, {(noBias ? 0 : hidden_channels)}, "wbc");
addProducer(metaOp, 13, {(noBias ? 0 : hidden_channels)}, "rbi");
addProducer(metaOp, 14, {(noBias ? 0 : hidden_channels)}, "rbo");
addProducer(metaOp, 15, {(noBias ? 0 : hidden_channels)}, "rbf");
addProducer(metaOp, 16, {(noBias ? 0 : hidden_channels)}, "rbc");
return metaOp;
}
} // namespace Aidge } // namespace Aidge
#endif /* AIDGE_CORE_OPERATOR_METAOPERATORDEFS_H_ */ #endif /* AIDGE_CORE_OPERATOR_METAOPERATORDEFS_H_ */
/********************************************************************************
* Copyright (c) 2023 CEA-List
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
#include "aidge/operator/MetaOperatorDefs.hpp"
#include <array>
#include <memory>
#include <string>
#include "aidge/operator/Memorize.hpp"
#include "aidge/operator/Add.hpp"
#include "aidge/operator/Mul.hpp"
#include "aidge/operator/FC.hpp"
#include "aidge/operator/Identity.hpp"
#include "aidge/operator/Concat.hpp"
#include "aidge/operator/Tanh.hpp"
namespace Aidge {
std::shared_ptr<Node> LSTM(const DimSize_t inChannel,
const DimSize_t hiddenChannel,
const DimSize_t seqLength,
bool noBias,
const std::string& name)
{
// Construct micro-graph
auto input = Identity((!name.empty()) ? name + "_input" : "");
auto hiddenState = Memorize(seqLength, (!name.empty()) ? name + "_hidden_state" : "");
auto cellState = Memorize(seqLength, (!name.empty()) ? name + "_cell_state" : "");
auto add = Add(2, (!name.empty()) ? name + "_add" : "");
// Forget gate
auto forgetGateX = std::make_shared<Node>(std::make_shared<FC_Op>(noBias), (!name.empty()) ? name + "_forgetGateX" : "");
input->addChild(forgetGateX, 0, 0);
auto forgetGateH = std::make_shared<Node>(std::make_shared<FC_Op>(noBias), (!name.empty()) ? name + "_forgetGateH" : "");
hiddenState->addChild(forgetGateH, 1, 0);
auto forgetGate = Add(2, (!name.empty()) ? name + "_forgetGate" : "");
forgetGateX->addChild(forgetGate, 0, 0);
forgetGateH->addChild(forgetGate, 0, 1);
auto forgetGateAct = Sigmoid((!name.empty()) ? name + "_forgetGateAct" : "");
auto forgetGateMul = Mul((!name.empty()) ? name + "_forgetGateMul" : "");
forgetGate->addChild(forgetGateAct, 0, 0);
forgetGateAct->addChild(forgetGateMul, 0, 0);
forgetGateMul->addChild(add, 0, 0);
cellState->addChild(forgetGateMul, 1, 1);
// Input gate
auto inputGateX = std::make_shared<Node>(std::make_shared<FC_Op>(noBias), (!name.empty()) ? name + "_inputGateX" : "");
input->addChild(inputGateX, 0, 0);
auto inputGateH = std::make_shared<Node>(std::make_shared<FC_Op>(noBias), (!name.empty()) ? name + "_inputGateH" : "");
hiddenState->addChild(inputGateH, 1, 0);
auto inputGate = Add(2, (!name.empty()) ? name + "_inputGate" : "");
inputGateX->addChild(inputGate, 0, 0);
inputGateH->addChild(inputGate, 0, 1);
auto inputGateAct = Sigmoid((!name.empty()) ? name + "_inputGateAct" : "");
auto inputGateMul = Mul((!name.empty()) ? name + "_inputGateMul" : "");
inputGate->addChild(inputGateAct, 0, 0);
inputGateAct->addChild(inputGateMul, 0, 0);
inputGateMul->addChild(add, 0, 1);
// Candidate for cell update
auto cellCandidateX = std::make_shared<Node>(std::make_shared<FC_Op>(noBias), (!name.empty()) ? name + "_cellCandidateX" : "");
input->addChild(cellCandidateX, 0, 0);
auto cellCandidateH = std::make_shared<Node>(std::make_shared<FC_Op>(noBias), (!name.empty()) ? name + "_cellCandidateH" : "");
hiddenState->addChild(cellCandidateH, 1, 0);
auto cellCandidate = Add(2, (!name.empty()) ? name + "_cellCandidate" : "");
cellCandidateX->addChild(cellCandidate, 0, 0);
cellCandidateH->addChild(cellCandidate, 0, 1);
auto cellCandidateAct = Tanh((!name.empty()) ? name + "_cellCandidateAct" : "");
cellCandidate->addChild(cellCandidateAct, 0, 0);
cellCandidateAct->addChild(inputGateMul, 0, 1);
// Output gate
auto outputGateX = std::make_shared<Node>(std::make_shared<FC_Op>(noBias), (!name.empty()) ? name + "_outputGateX" : "");
input->addChild(outputGateX, 0, 0);
auto outputGateH = std::make_shared<Node>(std::make_shared<FC_Op>(noBias), (!name.empty()) ? name + "_outputGateH" : "");
hiddenState->addChild(outputGateH, 1, 0);
auto outputGate = Add(2, (!name.empty()) ? name + "_outputGate" : "");
outputGateX->addChild(outputGate, 0, 0);
outputGateH->addChild(outputGate, 0, 1);
auto outputGateAct = Sigmoid((!name.empty()) ? name + "_outputGateAct" : "");
auto outputGateMul = Mul((!name.empty()) ? name + "_outputGateMul" : "");
outputGate->addChild(outputGateAct, 0, 0);
outputGateAct->addChild(outputGateMul, 0, 0);
// Updated cell state to help determine new hidden state
auto cellUpdatedAct = Tanh((!name.empty()) ? name + "_cellUpdatedAct" : "");
add->addChild(cellUpdatedAct, 0, 0);
cellUpdatedAct->addChild(outputGateMul, 0, 1);
outputGateMul->addChild(hiddenState, 0, 0);
add->addChild(cellState, 0, 0);
std::shared_ptr<GraphView> microGraph = std::make_shared<GraphView>();
microGraph->add(input);
microGraph->add({hiddenState, cellState, add,
forgetGateX, forgetGateH, forgetGate, forgetGateAct, forgetGateMul,
inputGateX, inputGateH, inputGate, inputGateAct, inputGateMul,
cellCandidateX, cellCandidateH, cellCandidate, cellCandidateAct,
outputGateX, outputGateH, outputGate, outputGateAct, outputGateMul,
cellUpdatedAct}, false);
microGraph->setOrderedInputs({{input, 0},
{inputGateX, 1}, {outputGateX, 1}, {forgetGateX, 1}, {cellCandidateX, 1},
{inputGateH, 1}, {outputGateH, 1}, {forgetGateH, 1}, {cellCandidateH, 1},
{inputGateX, 2}, {outputGateX, 2}, {forgetGateX, 2}, {cellCandidateX, 2},
{inputGateH, 2}, {outputGateH, 2}, {forgetGateH, 2}, {cellCandidateH, 2},
{hiddenState, 1}, {cellState, 1}});
microGraph->setOrderedOutputs({{hiddenState, 0}, {cellState, 0}});
auto metaOp = MetaOperator("LSTM", microGraph, name);
addProducer(metaOp, 1, {hiddenChannel, inChannel}, "wi");
addProducer(metaOp, 2, {hiddenChannel, inChannel}, "wo");
addProducer(metaOp, 3, {hiddenChannel, inChannel}, "wf");
addProducer(metaOp, 4, {hiddenChannel, inChannel}, "wc");
addProducer(metaOp, 5, {hiddenChannel, hiddenChannel}, "ri");
addProducer(metaOp, 6, {hiddenChannel, hiddenChannel}, "ro");
addProducer(metaOp, 7, {hiddenChannel, hiddenChannel}, "rf");
addProducer(metaOp, 8, {hiddenChannel, hiddenChannel}, "rc");
addProducer(metaOp, 9, {(noBias ? 0 : hiddenChannel)}, "wbi");
addProducer(metaOp, 10, {(noBias ? 0 : hiddenChannel)}, "wbo");
addProducer(metaOp, 11, {(noBias ? 0 : hiddenChannel)}, "wbf");
addProducer(metaOp, 12, {(noBias ? 0 : hiddenChannel)}, "wbc");
addProducer(metaOp, 13, {(noBias ? 0 : hiddenChannel)}, "rbi");
addProducer(metaOp, 14, {(noBias ? 0 : hiddenChannel)}, "rbo");
addProducer(metaOp, 15, {(noBias ? 0 : hiddenChannel)}, "rbf");
addProducer(metaOp, 16, {(noBias ? 0 : hiddenChannel)}, "rbc");
return metaOp;
}
std::shared_ptr<MetaOperator_Op> LSTM_Op(const DimSize_t seqLength,
bool noBias)
{
// Construct micro-graph
auto input = Identity("");
auto hiddenState = Memorize(seqLength, "");
auto cellState = Memorize(seqLength, "");
auto add = Add(2, "");
// Forget gate
auto forgetGateX = std::make_shared<Node>(std::make_shared<FC_Op>(noBias), "");
input->addChild(forgetGateX, 0, 0);
auto forgetGateH = std::make_shared<Node>(std::make_shared<FC_Op>(noBias), "");
hiddenState->addChild(forgetGateH, 1, 0);
auto forgetGate = Add(2, "");
forgetGateX->addChild(forgetGate, 0, 0);
forgetGateH->addChild(forgetGate, 0, 1);
auto forgetGateAct = Sigmoid("");
auto forgetGateMul = Mul("");
forgetGate->addChild(forgetGateAct, 0, 0);
forgetGateAct->addChild(forgetGateMul, 0, 0);
forgetGateMul->addChild(add, 0, 0);
cellState->addChild(forgetGateMul, 1, 1);
// Input gate
auto inputGateX = std::make_shared<Node>(std::make_shared<FC_Op>(noBias), "");
input->addChild(inputGateX, 0, 0);
auto inputGateH = std::make_shared<Node>(std::make_shared<FC_Op>(noBias), "");
hiddenState->addChild(inputGateH, 1, 0);
auto inputGate = Add(2, "");
inputGateX->addChild(inputGate, 0, 0);
inputGateH->addChild(inputGate, 0, 1);
auto inputGateAct = Sigmoid("");
auto inputGateMul = Mul("");
inputGate->addChild(inputGateAct, 0, 0);
inputGateAct->addChild(inputGateMul, 0, 0);
inputGateMul->addChild(add, 0, 1);
// Candidate for cell update
auto cellCandidateX = std::make_shared<Node>(std::make_shared<FC_Op>(noBias), "");
input->addChild(cellCandidateX, 0, 0);
auto cellCandidateH = std::make_shared<Node>(std::make_shared<FC_Op>(noBias), "");
hiddenState->addChild(cellCandidateH, 1, 0);
auto cellCandidate = Add(2, "");
cellCandidateX->addChild(cellCandidate, 0, 0);
cellCandidateH->addChild(cellCandidate, 0, 1);
auto cellCandidateAct = Tanh("");
cellCandidate->addChild(cellCandidateAct, 0, 0);
cellCandidateAct->addChild(inputGateMul, 0, 1);
// Output gate
auto outputGateX = std::make_shared<Node>(std::make_shared<FC_Op>(noBias), "");
input->addChild(outputGateX, 0, 0);
auto outputGateH = std::make_shared<Node>(std::make_shared<FC_Op>(noBias), "");
hiddenState->addChild(outputGateH, 1, 0);
auto outputGate = Add(2,"");
outputGateX->addChild(outputGate, 0, 0);
outputGateH->addChild(outputGate, 0, 1);
auto outputGateAct = Sigmoid("");
auto outputGateMul = Mul("");
outputGate->addChild(outputGateAct, 0, 0);
outputGateAct->addChild(outputGateMul, 0, 0);
// Updated cell state to help determine new hidden state
auto cellUpdatedAct = Tanh("");
add->addChild(cellUpdatedAct, 0, 0);
cellUpdatedAct->addChild(outputGateMul, 0, 1);
outputGateMul->addChild(hiddenState, 0, 0);
add->addChild(cellState, 0, 0);
std::shared_ptr<GraphView> microGraph = std::make_shared<GraphView>();
microGraph->add(input);
microGraph->add({hiddenState, cellState, add,
forgetGateX, forgetGateH, forgetGate, forgetGateAct, forgetGateMul,
inputGateX, inputGateH, inputGate, inputGateAct, inputGateMul,
cellCandidateX, cellCandidateH, cellCandidate, cellCandidateAct,
outputGateX, outputGateH, outputGate, outputGateAct, outputGateMul,
cellUpdatedAct}, false);
microGraph->setOrderedInputs({{input, 0},
{inputGateX, 1}, {outputGateX, 1}, {forgetGateX, 1}, {cellCandidateX, 1},
{inputGateH, 1}, {outputGateH, 1}, {forgetGateH, 1}, {cellCandidateH, 1},
{inputGateX, 2}, {outputGateX, 2}, {forgetGateX, 2}, {cellCandidateX, 2},
{inputGateH, 2}, {outputGateH, 2}, {forgetGateH, 2}, {cellCandidateH, 2},
{hiddenState, 1}, {cellState, 1}});
microGraph->setOrderedOutputs({{hiddenState, 0}, {cellState, 0}});
return std::make_shared<MetaOperator_Op>("LSTM", microGraph);
}
} // namespace Aidge
/********************************************************************************
* Copyright (c) 2023 CEA-List
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
#include "aidge/operator/MetaOperatorDefs.hpp"
#include <array>
#include <memory>
#include <string>
#include "aidge/graph/GraphView.hpp"
#include "aidge/graph/Node.hpp"
#include "aidge/graph/OpArgs.hpp"
#include "aidge/operator/AvgPooling.hpp"
#include "aidge/operator/MetaOperator.hpp"
#include "aidge/operator/Pad.hpp"
#include "aidge/utils/ArrayHelpers.hpp"
#include "aidge/utils/Types.h"
namespace Aidge {
//////////////////////////////////
// Node functions
//////////////////////////////////
template <std::array<DimSize_t, 1>::size_type DIM>
std::shared_ptr<Node> PaddedAvgPooling(const std::array<DimSize_t, DIM> &kernel_dims,
const std::string& name,
const std::array<DimSize_t, DIM> &stride_dims,
const std::array<DimSize_t, 2*DIM> &padding_dims)
{
auto graph = Sequential({
Pad<DIM>(padding_dims, (!name.empty()) ? name + "_pad" : ""),
AvgPooling(kernel_dims, (!name.empty()) ? name + "_avgpooling" : "", stride_dims)
});
return MetaOperator("PaddedAvgPooling", graph, name);
}
template std::shared_ptr<Node> PaddedAvgPooling<1>(const std::array<DimSize_t,1>&, const std::string&, const std::array<DimSize_t,1>&, const std::array<DimSize_t,2>&);
template std::shared_ptr<Node> PaddedAvgPooling<2>(const std::array<DimSize_t,2>&, const std::string&, const std::array<DimSize_t,2>&, const std::array<DimSize_t,4>&);
template std::shared_ptr<Node> PaddedAvgPooling<3>(const std::array<DimSize_t,3>&, const std::string&, const std::array<DimSize_t,3>&, const std::array<DimSize_t,6>&);
template std::shared_ptr<Node> PaddedAvgPooling<4>(const std::array<DimSize_t,4>&, const std::string&, const std::array<DimSize_t,4>&, const std::array<DimSize_t,8>&);
// helper with C-style array instead of std::array for kernel_dims to allow automatic template DIM deduction
template <DimSize_t DIM>
std::shared_ptr<Node> PaddedAvgPooling(const DimSize_t (&kernel_dims)[DIM],
const std::string& name,
const std::array<DimSize_t, DIM> &stride_dims,
const std::array<DimSize_t, 2*DIM> &padding_dims)
{
return PaddedAvgPooling(to_array(kernel_dims), name, stride_dims, padding_dims);
}
template std::shared_ptr<Node> PaddedAvgPooling<1>(const DimSize_t (&kernel_dims)[1], const std::string&, const std::array<DimSize_t,1>&, const std::array<DimSize_t,2>&);
template std::shared_ptr<Node> PaddedAvgPooling<2>(const DimSize_t (&kernel_dims)[2], const std::string&, const std::array<DimSize_t,2>&, const std::array<DimSize_t,4>&);
template std::shared_ptr<Node> PaddedAvgPooling<3>(const DimSize_t (&kernel_dims)[3], const std::string&, const std::array<DimSize_t,3>&, const std::array<DimSize_t,6>&);
template std::shared_ptr<Node> PaddedAvgPooling<4>(const DimSize_t (&kernel_dims)[4], const std::string&, const std::array<DimSize_t,4>&, const std::array<DimSize_t,8>&);
//////////////////////////////////
// Operator functions
//////////////////////////////////
template <std::array<DimSize_t, 1>::size_type DIM>
inline std::shared_ptr<MetaOperator_Op> PaddedAvgPooling_Op(const std::array<DimSize_t, DIM> &kernel_dims,
const std::array<DimSize_t, DIM> &stride_dims,
const std::array<DimSize_t, 2*DIM> &padding_dims)
{
auto graph = Sequential({
Pad<DIM>(padding_dims, ""),
AvgPooling(kernel_dims, "", stride_dims)
});
return std::make_shared<MetaOperator_Op>("PaddedAvgPooling", graph);
}
template std::shared_ptr<MetaOperator_Op> PaddedAvgPooling_Op<1>(const std::array<DimSize_t,1>&, const std::array<DimSize_t,1>&, const std::array<DimSize_t,2>&);
template std::shared_ptr<MetaOperator_Op> PaddedAvgPooling_Op<2>(const std::array<DimSize_t,2>&, const std::array<DimSize_t,2>&, const std::array<DimSize_t,4>&);
template std::shared_ptr<MetaOperator_Op> PaddedAvgPooling_Op<3>(const std::array<DimSize_t,3>&, const std::array<DimSize_t,3>&, const std::array<DimSize_t,6>&);
template std::shared_ptr<MetaOperator_Op> PaddedAvgPooling_Op<4>(const std::array<DimSize_t,4>&, const std::array<DimSize_t,4>&, const std::array<DimSize_t,8>&);
} // namespace Aidge
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment