From f1d564040ab11e2cc0cb44ac23315d3b36c9625c Mon Sep 17 00:00:00 2001 From: Gallas Gaye <gallasko@gmail.com> Date: Fri, 21 Feb 2025 10:22:47 +0100 Subject: [PATCH 1/4] feat: Add reshape export op --- aidge_export_cpp/kernels/reshape.hpp | 27 +++++++++++++++++++ aidge_export_cpp/operators.py | 13 +++++++++ .../configuration/reshape_config.jinja | 8 ++++++ .../kernel_forward/reshape_forward.jinja | 6 +++++ 4 files changed, 54 insertions(+) create mode 100644 aidge_export_cpp/kernels/reshape.hpp create mode 100644 aidge_export_cpp/templates/configuration/reshape_config.jinja create mode 100644 aidge_export_cpp/templates/kernel_forward/reshape_forward.jinja diff --git a/aidge_export_cpp/kernels/reshape.hpp b/aidge_export_cpp/kernels/reshape.hpp new file mode 100644 index 0000000..a5828da --- /dev/null +++ b/aidge_export_cpp/kernels/reshape.hpp @@ -0,0 +1,27 @@ +#ifndef __AIDGE_EXPORT_CPP_KERNELS_RESHAPE__ +#define __AIDGE_EXPORT_CPP_KERNELS_RESHAPE__ + +#include "network/typedefs.hpp" + +// Generic function for reshape and activation + +template<int M, + typename Input_T, typename Output_T> +__attribute__((always_inline)) inline +void reshape_forward ( + const Input_T* __restrict, // First input is useless as it only dictate the resulting layout of the reshape + const Input_T* __restrict inputs2, + Output_T* __restrict outputs) +{ + // If inputs and outputs pointers are the same, the memory manager has already optimized this function so it is a no-op ! + if (inputs2 == outputs) + return; + + // A reshape in c++ world should equal to a Noop + // We only need to copy the input buffer to the output + for (int m = 0; m < M; ++m) { + outputs[m] = inputs2[m]; + } +} + +#endif // __AIDGE_EXPORT_CPP_KERNELS_RESHAPE__ \ No newline at end of file diff --git a/aidge_export_cpp/operators.py b/aidge_export_cpp/operators.py index 54c3805..59ce94a 100644 --- a/aidge_export_cpp/operators.py +++ b/aidge_export_cpp/operators.py @@ -94,6 +94,19 @@ class ReLUCPP(ExportNodeCpp): str(ROOT / "kernels" / "rescaling.hpp") ] +@ExportLibCpp.register("Reshape", aidge_core.ImplSpec(aidge_core.IOSpec(aidge_core.dtype.float32))) +class ReshapeCPP(ExportNodeCpp): + def __init__(self, node, mem_info): + super().__init__(node, mem_info) + self.config_template = str( + ROOT / "templates" / "configuration" / "reshape_config.jinja") + self.forward_template = str( + ROOT / "templates" / "kernel_forward" / "reshape_forward.jinja") + self.include_list = [] + self.kernels_to_copy = [ + str(ROOT / "kernels" / "reshape.hpp"), + ] + @ExportLibCpp.register("Conv2D", aidge_core.ImplSpec(aidge_core.IOSpec(aidge_core.dtype.float32))) class ConvCPP(ExportNodeCpp): def __init__(self, node, mem_info): diff --git a/aidge_export_cpp/templates/configuration/reshape_config.jinja b/aidge_export_cpp/templates/configuration/reshape_config.jinja new file mode 100644 index 0000000..041cf8a --- /dev/null +++ b/aidge_export_cpp/templates/configuration/reshape_config.jinja @@ -0,0 +1,8 @@ +{#- For name header -#} +#ifndef {{ name|upper }}_LAYER_H +#define {{ name|upper }}_LAYER_H + +{% include "./_def_io.jinja" %} +{% include "./_meminfo.jinja" %} +{# For layer configuration -#} +#define {{ name|upper }}_NB_ELTS {{ in_dims[0]|join('*') }} diff --git a/aidge_export_cpp/templates/kernel_forward/reshape_forward.jinja b/aidge_export_cpp/templates/kernel_forward/reshape_forward.jinja new file mode 100644 index 0000000..f9752bc --- /dev/null +++ b/aidge_export_cpp/templates/kernel_forward/reshape_forward.jinja @@ -0,0 +1,6 @@ +{% filter indent(width=4, first=False) %} +{% include "./_mem_offset.jinja" %} +reshape_forward<{{name|upper}}_NB_ELTS> + ({{in_name[0]}}, {{in_name[1]}}, {{out_name[0]}}); +{% include "./_save_outputs.jinja" %} +{% endfilter %} -- GitLab From 534f5b3381aa7c1f9b088af1d28e97923de492cf Mon Sep 17 00:00:00 2001 From: Gallas Gaye <gallasko@gmail.com> Date: Fri, 21 Feb 2025 10:38:36 +0100 Subject: [PATCH 2/4] fix: Add Matmul export operator back Matmul op was removed and obsolote. Fixed wrong hyperparameters names in jinja Fixed impl in operator.py --- aidge_export_cpp/operators.py | 15 +++++++++++++++ .../templates/configuration/matmul_config.jinja | 9 ++++++--- .../templates/kernel_forward/matmul_forward.jinja | 6 +++++- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/aidge_export_cpp/operators.py b/aidge_export_cpp/operators.py index 59ce94a..0790877 100644 --- a/aidge_export_cpp/operators.py +++ b/aidge_export_cpp/operators.py @@ -107,6 +107,21 @@ class ReshapeCPP(ExportNodeCpp): str(ROOT / "kernels" / "reshape.hpp"), ] +@ExportLibCpp.register("MatMul", aidge_core.ImplSpec(aidge_core.IOSpec(aidge_core.dtype.float32))) +class MatMulCPP(ExportNodeCpp): + def __init__(self, node, mem_info): + super().__init__(node, mem_info) + self.attributes["activation"] = "Linear" + self.attributes["rescaling"] = "NoScaling" + self.config_template = str( + ROOT / "templates" / "configuration" / "matmul_config.jinja") + self.forward_template = str( + ROOT / "templates" / "kernel_forward" / "matmul_forward.jinja") + self.include_list = [] + self.kernels_to_copy = [ + str(ROOT / "kernels" / "matmul.hpp"), + ] + @ExportLibCpp.register("Conv2D", aidge_core.ImplSpec(aidge_core.IOSpec(aidge_core.dtype.float32))) class ConvCPP(ExportNodeCpp): def __init__(self, node, mem_info): diff --git a/aidge_export_cpp/templates/configuration/matmul_config.jinja b/aidge_export_cpp/templates/configuration/matmul_config.jinja index fece988..38316f2 100644 --- a/aidge_export_cpp/templates/configuration/matmul_config.jinja +++ b/aidge_export_cpp/templates/configuration/matmul_config.jinja @@ -2,10 +2,13 @@ #ifndef {{ name|upper }}_LAYER_H #define {{ name|upper }}_LAYER_H +{% include "./_def_io.jinja" %} +{% include "./_meminfo.jinja" %} + {# For layer configuration -#} -#define {{ name|upper }}_M {{ inputs_dims[0][0] }} -#define {{ name|upper }}_K {{ inputs_dims[0][1] }} -#define {{ name|upper }}_N {{ inputs_dims[1][1] }} +#define {{ name|upper }}_M {{ in_dims[0][0] }} +#define {{ name|upper }}_K {{ in_dims[0][1] }} +#define {{ name|upper }}_N {{ in_dims[1][1] }} #define {{ name|upper }}_ACTIVATION {{ activation }} static const {{ rescaling }} {{ name|upper }}_RESCALING = {}; diff --git a/aidge_export_cpp/templates/kernel_forward/matmul_forward.jinja b/aidge_export_cpp/templates/kernel_forward/matmul_forward.jinja index ce80ffd..64b3df3 100644 --- a/aidge_export_cpp/templates/kernel_forward/matmul_forward.jinja +++ b/aidge_export_cpp/templates/kernel_forward/matmul_forward.jinja @@ -1,5 +1,9 @@ +{% filter indent(width=4, first=False) %} +{% include "./_mem_offset.jinja" %} matmul_forward<{{name|upper}}_M, {{name|upper}}_K, {{name|upper}}_N, {{name|upper}}_ACTIVATION> - ({{inputs1_name}}, {{inputs2_name}}, {{outputs_name}}, {{name|upper}}_RESCALING); \ No newline at end of file + ({{in_name[0]}}, {{in_name[1]}}, {{out_name[0]}}, {{name|upper}}_RESCALING); +{% include "./_save_outputs.jinja" %} +{% endfilter %} -- GitLab From b957fede729a835fc0fbeff9e5e797580afe7a58 Mon Sep 17 00:00:00 2001 From: Gallas Gaye <gallasko@gmail.com> Date: Fri, 21 Feb 2025 10:43:48 +0100 Subject: [PATCH 3/4] chore: Refactor duplicate code in operators --- aidge_export_cpp/operators.py | 161 ++++++++++++++-------------------- 1 file changed, 64 insertions(+), 97 deletions(-) diff --git a/aidge_export_cpp/operators.py b/aidge_export_cpp/operators.py index 0790877..346928f 100644 --- a/aidge_export_cpp/operators.py +++ b/aidge_export_cpp/operators.py @@ -122,6 +122,27 @@ class MatMulCPP(ExportNodeCpp): str(ROOT / "kernels" / "matmul.hpp"), ] +def _setup_conv2D(conv): + """Common setup code for convolutions: Conv2D and PaddedConv2D.""" + + # If biases are not provided we set it as nullptr instead of None + if (len(conv.attributes["in_name"]) > 2 and conv.attributes["in_name"][2] is None): + conv.attributes["in_name"][2] = "nullptr" + + conv.attributes["activation"] = "Linear" + conv.attributes["rescaling"] = "NoScaling" + conv.config_template = str( + ROOT / "templates" / "configuration" / "convolution_config.jinja") + conv.forward_template = str( + ROOT / "templates" / "kernel_forward" / "convolution_forward.jinja") + conv.include_list = [] + conv.kernels_to_copy = [ + str(ROOT / "kernels" / "convolution.hpp"), + str(ROOT / "kernels" / "macs.hpp"), + str(ROOT / "kernels" / "activation.hpp"), + str(ROOT / "kernels" / "rescaling.hpp") + ] + @ExportLibCpp.register("Conv2D", aidge_core.ImplSpec(aidge_core.IOSpec(aidge_core.dtype.float32))) class ConvCPP(ExportNodeCpp): def __init__(self, node, mem_info): @@ -129,19 +150,8 @@ class ConvCPP(ExportNodeCpp): # No padding with Conv # Use PaddedConv to add padding attribute self.attributes["padding"] = [0, 0] - self.attributes["activation"] = "Linear" - self.attributes["rescaling"] = "NoScaling" - self.config_template = str( - ROOT / "templates" / "configuration" / "convolution_config.jinja") - self.forward_template = str( - ROOT / "templates" / "kernel_forward" / "convolution_forward.jinja") - self.include_list = [] - self.kernels_to_copy = [ - str(ROOT / "kernels" / "convolution.hpp"), - str(ROOT / "kernels" / "macs.hpp"), - str(ROOT / "kernels" / "activation.hpp"), - str(ROOT / "kernels" / "rescaling.hpp") - ] + + _setup_conv2D(self) @ExportLibCpp.register_metaop("PaddedConv2D", aidge_core.ImplSpec(aidge_core.IOSpec(aidge_core.dtype.float32))) class PaddedConvCPP(ExportNodeCpp): @@ -159,74 +169,60 @@ class PaddedConvCPP(ExportNodeCpp): ).attr.stride_dims self.attributes["dilation_dims"] = n.get_operator( ).attr.dilation_dims - self.attributes["activation"] = "Linear" - self.attributes["rescaling"] = "NoScaling" - self.config_template = str( - ROOT / "templates" / "configuration" / "convolution_config.jinja") - self.forward_template = str( - ROOT / "templates" / "kernel_forward" / "convolution_forward.jinja") - self.include_list = [] - self.kernels_to_copy = [ - str(ROOT / "kernels" / "convolution.hpp"), - str(ROOT / "kernels" / "macs.hpp"), - str(ROOT / "kernels" / "activation.hpp"), - str(ROOT / "kernels" / "rescaling.hpp") - ] + + _setup_conv2D(self) + +def _setup_elemwise_op(elemwise, op): + """Common code (template and kernel setup) shared across all the different elementWise operator (Add, Sub,...).""" + + elemwise.attributes["elemwise_op"] = op + elemwise.attributes["activation"] = "Linear" + elemwise.attributes["rescaling"] = "NoScaling" + elemwise.config_template = str( + ROOT / "templates" / "configuration" / "elemwise_config.jinja") + elemwise.forward_template = str( + ROOT / "templates" / "kernel_forward" / "elemwise_forward.jinja") + elemwise.include_list = [] + elemwise.kernels_to_copy = [ + str(ROOT / "kernels" / "elemwise.hpp"), + str(ROOT / "kernels" / "activation.hpp"), + str(ROOT / "kernels" / "rescaling.hpp") + ] @ExportLibCpp.register("Add", aidge_core.ImplSpec(aidge_core.IOSpec(aidge_core.dtype.float32))) class AddCPP(ExportNodeCpp): def __init__(self, node, mem_info): super().__init__(node, mem_info) - self.attributes["elemwise_op"] = "Add" - self.attributes["activation"] = "Linear" - self.attributes["rescaling"] = "NoScaling" - self.config_template = str( - ROOT / "templates" / "configuration" / "elemwise_config.jinja") - self.forward_template = str( - ROOT / "templates" / "kernel_forward" / "elemwise_forward.jinja") - self.include_list = [] - self.kernels_to_copy = [ - str(ROOT / "kernels" / "elemwise.hpp"), - str(ROOT / "kernels" / "activation.hpp"), - str(ROOT / "kernels" / "rescaling.hpp") - ] + + _setup_elemwise_op(self, "Add") @ExportLibCpp.register("Sub", aidge_core.ImplSpec(aidge_core.IOSpec(aidge_core.dtype.float32))) class SubCPP(ExportNodeCpp): def __init__(self, node, mem_info): super().__init__(node, mem_info) - self.attributes["elemwise_op"] = "Sub" - self.attributes["activation"] = "Linear" - self.attributes["rescaling"] = "NoScaling" - self.config_template = str( - ROOT / "templates" / "configuration" / "elemwise_config.jinja") - self.forward_template = str( - ROOT / "templates" / "kernel_forward" / "elemwise_forward.jinja") - self.include_list = [] - self.kernels_to_copy = [ - str(ROOT / "kernels" / "elemwise.hpp"), - str(ROOT / "kernels" / "activation.hpp"), - str(ROOT / "kernels" / "rescaling.hpp") - ] + _setup_elemwise_op(self, "Sub") @ExportLibCpp.register("Mul", aidge_core.ImplSpec(aidge_core.IOSpec(aidge_core.dtype.float32))) class MulCPP(ExportNodeCpp): def __init__(self, node, mem_info): super().__init__(node, mem_info) - self.attributes["elemwise_op"] = "Mul" - self.attributes["activation"] = "Linear" - self.attributes["rescaling"] = "NoScaling" - self.config_template = str( - ROOT / "templates" / "configuration" / "elemwise_config.jinja") - self.forward_template = str( - ROOT / "templates" / "kernel_forward" / "elemwise_forward.jinja") - self.include_list = [] - self.kernels_to_copy = [ - str(ROOT / "kernels" / "elemwise.hpp"), - str(ROOT / "kernels" / "activation.hpp"), - str(ROOT / "kernels" / "rescaling.hpp") - ] + + _setup_elemwise_op(self, "Mul") + +def _setup_pooling(pooling): + """Common code (template and kernel setup) shared across all the different pooling operator.""" + + pooling.config_template = str( + ROOT / "templates" / "configuration" / "pooling_config.jinja") + pooling.forward_template = str( + ROOT / "templates" / "kernel_forward" / "pooling_forward.jinja") + pooling.include_list = [] + pooling.kernels_to_copy = [ + str(ROOT / "kernels" / "pooling.hpp"), + str(ROOT / "kernels" / "activation.hpp"), + str(ROOT / "kernels" / "rescaling.hpp") + ] @ExportLibCpp.register("MaxPooling2D", aidge_core.ImplSpec(aidge_core.IOSpec(aidge_core.dtype.float32))) class MaxPoolCPP(ExportNodeCpp): @@ -239,17 +235,7 @@ class MaxPoolCPP(ExportNodeCpp): self.attributes["pool_type"] = "Max" self.attributes["activation"] = "Linear" - self.config_template = str( - ROOT / "templates" / "configuration" / "pooling_config.jinja") - self.forward_template = str( - ROOT / "templates" / "kernel_forward" / "pooling_forward.jinja") - self.include_list = [] - self.kernels_to_copy = [ - str(ROOT / "kernels" / "pooling.hpp"), - str(ROOT / "kernels" / "activation.hpp"), - str(ROOT / "kernels" / "rescaling.hpp") - ] - + _setup_pooling(self) @ExportLibCpp.register_metaop("PaddedMaxPooling2D", aidge_core.ImplSpec(aidge_core.IOSpec(aidge_core.dtype.float32))) class PaddedMaxPoolCPP(ExportNodeCpp): @@ -267,17 +253,7 @@ class PaddedMaxPoolCPP(ExportNodeCpp): self.attributes["pool_type"] = "Max" self.attributes["activation"] = "Linear" - self.config_template = str( - ROOT / "templates" / "configuration" / "pooling_config.jinja") - self.forward_template = str( - ROOT / "templates" / "kernel_forward" / "pooling_forward.jinja") - self.include_list = [] - self.kernels_to_copy = [ - str(ROOT / "kernels" / "pooling.hpp"), - str(ROOT / "kernels" / "activation.hpp"), - str(ROOT / "kernels" / "rescaling.hpp") - ] - + _setup_pooling(self) @ExportLibCpp.register("GlobalAveragePooling", aidge_core.ImplSpec(aidge_core.IOSpec(aidge_core.dtype.float32))) class GlobalAveragePoolCPP(ExportNodeCpp): @@ -295,16 +271,7 @@ class GlobalAveragePoolCPP(ExportNodeCpp): self.attributes["pool_type"] = "Average" self.attributes["activation"] = "Linear" - self.config_template = str( - ROOT / "templates" / "configuration" / "pooling_config.jinja") - self.forward_template = str( - ROOT / "templates" / "kernel_forward" / "pooling_forward.jinja") - self.include_list = [] - self.kernels_to_copy = [ - str(ROOT / "kernels" / "pooling.hpp"), - str(ROOT / "kernels" / "activation.hpp"), - str(ROOT / "kernels" / "rescaling.hpp") - ] + _setup_pooling(self) @ExportLibCpp.register("FC", aidge_core.ImplSpec(aidge_core.IOSpec(aidge_core.dtype.float32))) class FcCPP(ExportNodeCpp): -- GitLab From e98d3eeee881e880f0f33304c6e2ddebc36dd0fa Mon Sep 17 00:00:00 2001 From: Gallas Gaye <gallasko@gmail.com> Date: Fri, 21 Feb 2025 10:46:39 +0100 Subject: [PATCH 4/4] fix: conv2D export failure when no biases given --- aidge_export_cpp/kernels/convolution.hpp | 45 ++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/aidge_export_cpp/kernels/convolution.hpp b/aidge_export_cpp/kernels/convolution.hpp index efc7ee7..6ea9f05 100644 --- a/aidge_export_cpp/kernels/convolution.hpp +++ b/aidge_export_cpp/kernels/convolution.hpp @@ -65,8 +65,8 @@ void convolution_forward( int oOffset = NB_OUTPUTS * oPos; // <-- - - Bias_T weightedSum = biases[output]; + // Check if the biases are defined + Bias_T weightedSum = biases ? biases[output] : 0; for (int sy = 0; sy < KERNEL_HEIGHT; ++sy) { if ((PADDING_Y != 0 @@ -116,4 +116,45 @@ void convolution_forward( } } +// Template specialization when biases are not given to the convolution +template<int NB_CHANNELS, + int CHANNELS_HEIGHT, int CHANNELS_WIDTH, + int NB_OUTPUTS, + int OUTPUTS_HEIGHT, int OUTPUTS_WIDTH, + int PADDING_Y, int PADDING_X, + int STRIDE_Y, int STRIDE_X, + int DILATION_Y, int DILATION_X, + int KERNEL_HEIGHT, int KERNEL_WIDTH, + ActivationFunction_T ACTIVATION, + typename Input_T, typename Output_T, + typename Weight_T, + typename Rescaling_T> +__attribute__((always_inline)) inline +void convolution_forward( + const Input_T* __restrict inputs, + Output_T* __restrict outputs, + const Weight_T* __restrict weights, + std::nullptr_t __restrict, + const Rescaling_T& __restrict rescaling) +{ + const float* b = nullptr; + + convolution_forward<NB_CHANNELS, + CHANNELS_HEIGHT, + CHANNELS_WIDTH, + NB_OUTPUTS, + OUTPUTS_HEIGHT, + OUTPUTS_WIDTH, + PADDING_Y, + PADDING_X, + STRIDE_Y, + STRIDE_X, + DILATION_Y, + DILATION_X, + KERNEL_HEIGHT, + KERNEL_WIDTH, + ACTIVATION> + (inputs, outputs, weights, b, rescaling); +} + #endif // __AIDGE_EXPORT_CPP_KERNELS_CONVOLUTION__ -- GitLab