Skip to content
Snippets Groups Projects
Commit 3f3be842 authored by Grégoire Kubler's avatar Grégoire Kubler
Browse files

Merge branch 'dev' into feat/release_pip

parents 151e3bf4 05fbdfb4
No related branches found
No related tags found
No related merge requests found
...@@ -90,13 +90,18 @@ def export(export_folder_name, graphview, scheduler): ...@@ -90,13 +90,18 @@ def export(export_folder_name, graphview, scheduler):
list_outputs_name.append((export_type, node.name())) list_outputs_name.append((export_type, node.name()))
# Generate forward file # Generate forward file
# TODO: for now the mem type is bound for all intermediate results, should change.
# Note that we may have all inputs constants, hence select output type
assert len(list_outputs_name) >= 1, f"TODO: requires some output to determine mem type"
mem_ctype = list_outputs_name[0][0]
generate_file( generate_file(
str(dnn_folder / "src" / "forward.cpp"), str(dnn_folder / "src" / "forward.cpp"),
str(ROOT / "templates" / "network" / "network_forward.jinja"), str(ROOT / "templates" / "network" / "network_forward.jinja"),
headers=list_configs, headers=list_configs,
actions=list_actions, actions=list_actions,
inputs= list_inputs_name, inputs= list_inputs_name,
outputs=list_outputs_name outputs=list_outputs_name,
mem_ctype=mem_ctype,
) )
# Generate dnn API # Generate dnn API
......
#ifndef __AIDGE_EXPORT_CPP_KERNELS_MATMUL__
#define __AIDGE_EXPORT_CPP_KERNELS_MATMUL__
#include "network/typedefs.hpp"
#include "kernels/activation.hpp"
// Generic function for matmul and activation
template<int M,
int K,
int N,
ActivationFunction_T ACTIVATION,
typename Input_T, typename Output_T,
typename Rescaling_T>
__attribute__((always_inline)) inline
void matmul_forward (
const Input_T* __restrict inputs1,
const Input_T* __restrict inputs2,
Output_T* __restrict outputs,
const Rescaling_T& __restrict rescaling)
{
for (int m = 0; m < M; ++m) {
for (int n = 0; n < N; ++n) {
Output_T sum = Output_T(0);
for (int k = 0; k < K; ++k) {
sum += inputs1[K*m + k] * inputs2[N*k + n];
}
outputs[N*m + n] = activation_forward_value<Output_T>(sum, 0/*not applicable*/, ACTIVATION, rescaling);
}
}
}
#endif // __AIDGE_EXPORT_CPP_KERNELS_MATMUL__
...@@ -238,6 +238,8 @@ class AddCPP(ExportNode): ...@@ -238,6 +238,8 @@ class AddCPP(ExportNode):
copyfile(str(ROOT / "kernels" / "elemwise.hpp"), copyfile(str(ROOT / "kernels" / "elemwise.hpp"),
str(export_folder / "include" / "kernels")) str(export_folder / "include" / "kernels"))
copyfile(str(ROOT / "kernels" / "activation.hpp"),
str(export_folder / "include" / "kernels"))
generate_file( generate_file(
str(export_folder / "layers" / f"{self.name}.h"), str(export_folder / "layers" / f"{self.name}.h"),
...@@ -251,13 +253,13 @@ class AddCPP(ExportNode): ...@@ -251,13 +253,13 @@ class AddCPP(ExportNode):
return list_configs return list_configs
def forward(self, list_actions:list): def forward(self, list_actions:list):
if not self.is_last:
list_actions.append(set_up_output(self.name, "float")) list_actions.append(set_up_output(self.name, "float"))
list_actions.append(generate_str( list_actions.append(generate_str(
str(ROOT / "templates" / "kernel_forward" / "elemwise_forward.jinja"), str(ROOT / "templates" / "kernel_forward" / "elemwise_forward.jinja"),
name=self.name, name=self.name,
inputs1_name=self.parents[0].name() if self.parents[0] else self.name + "_input1", inputs1_name=self.inputs[0].name() if self.inputs[0] else self.name + "_input1",
inputs2_name=self.parents[1].name() if self.parents[1] else self.name + "_input2", inputs2_name=self.inputs[1].name() if self.inputs[1] else self.name + "_input2",
output_name=self.name output_name=self.name
)) ))
return list_actions return list_actions
...@@ -272,6 +274,9 @@ class SubCPP(ExportNode): ...@@ -272,6 +274,9 @@ class SubCPP(ExportNode):
list_configs.append("kernels/elemwise.hpp") list_configs.append("kernels/elemwise.hpp")
copyfile(str(ROOT / "kernels" / "elemwise.hpp"), copyfile(str(ROOT / "kernels" / "elemwise.hpp"),
str(export_folder / "include" / "kernels")) str(export_folder / "include" / "kernels"))
copyfile(str(ROOT / "kernels" / "activation.hpp"),
str(export_folder / "include" / "kernels"))
generate_file( generate_file(
str(export_folder / "layers" / f"{self.name}.h"), str(export_folder / "layers" / f"{self.name}.h"),
str(ROOT / "templates" / "configuration" / "elemwise_config.jinja"), str(ROOT / "templates" / "configuration" / "elemwise_config.jinja"),
...@@ -284,8 +289,46 @@ class SubCPP(ExportNode): ...@@ -284,8 +289,46 @@ class SubCPP(ExportNode):
return list_configs return list_configs
def forward(self, list_actions:list): def forward(self, list_actions:list):
if not self.is_last:
list_actions.append(set_up_output(self.name, "float"))
list_actions.append(generate_str(
str(ROOT / "templates" / "kernel_forward" / "elemwise_forward.jinja"),
name=self.name,
inputs1_name=self.inputs[0].name() if self.inputs[0] else self.name + "_input1",
inputs2_name=self.inputs[1].name() if self.inputs[1] else self.name + "_input2",
output_name=self.name
))
return list_actions
@operator_register("Mul")
class MulCPP(ExportNode):
def __init__(self, node):
super().__init__(node)
def export(self, export_folder:str, list_configs:list):
list_configs.append(f"layers/{self.name}.h")
list_configs.append("kernels/elemwise.hpp")
copyfile(str(ROOT / "kernels" / "elemwise.hpp"),
str(export_folder / "include" / "kernels"))
copyfile(str(ROOT / "kernels" / "activation.hpp"),
str(export_folder / "include" / "kernels"))
generate_file(
str(export_folder / "layers" / f"{self.name}.h"),
str(ROOT / "templates" / "configuration" / "elemwise_config.jinja"),
name=self.name,
nb_elts=np.prod(self.inputs_dims[0]),
activation="Linear",
elemwise_op="Mul",
rescaling="NoScaling")
return list_configs
def forward(self, list_actions:list):
if not self.is_last:
list_actions.append(set_up_output(self.name, "float"))
list_actions.append(set_up_output(self.name, "float"))
list_actions.append(generate_str( list_actions.append(generate_str(
str(ROOT / "templates" / "kernel_forward" / "elemwise_forward.jinja"), str(ROOT / "templates" / "kernel_forward" / "elemwise_forward.jinja"),
name=self.name, name=self.name,
...@@ -410,3 +453,68 @@ class FcCPP(ExportNode): ...@@ -410,3 +453,68 @@ class FcCPP(ExportNode):
)) ))
return list_actions return list_actions
@operator_register("MatMul")
class MatMulCPP(ExportNode):
def __init__(self, node):
super().__init__(node)
dims0, dims1, outdims = [tuple(x) for x in [self.inputs_dims[0], self.inputs_dims[1], self.outputs_dims[0]]]
# TODO: MatMul aidge operator supports N-D multi broadcast dimensions where N > 2
assert len(dims0) <= 2 and len(dims1) <= 2, (
f"MatMul export do not support yet dimensions above 2D: inputs shapes are: {dims0}, {dims1}")
# Cast to at least 1D
# Note that from MatMul::forwardDims(), scalar inputs are supported
# which is actually more general than np.matmul
dims0 = dims0 if len(dims0) >= 1 else (1, 1)
dims1 = dims1 if len(dims1) >= 1 else (1, 1)
# Cast to at least 2D
dims0 = dims0 if len(dims0) >= 2 else (1, dims0[0])
dims1 = dims1 if len(dims1) >= 2 else (dims1[0], 1)
assert dims0[1] == dims1[0], (
f"MatMul input dimensions do no match, expected (m, k), (k, n): inputs shapes are: {dims0}, {dims1}")
outdims = outdims if len(outdims) > 0 else (1, 1)
assert outdims == (dims0[0], dims1[1]), (
f"MatMul output dimensions do no match, expected (m, n) for inputs (m, k) (k, n): output shape is: {outdims}, inputs shapes are: {dims0}, {dims1}")
self.matmul_inputs_dims = dims0, dims1
self.matmul_output_dims = outdims
def export(self, export_folder:Path, list_configs:list):
copyfile(str(ROOT / "kernels" / "matmul.hpp"),
str(export_folder / "include" / "kernels"))
copyfile(str(ROOT / "kernels" / "activation.hpp"),
str(export_folder / "include" / "kernels"))
# Add to config list the include of configurations
list_configs.append("kernels/matmul.hpp")
list_configs.append(f"layers/{self.name}.h")
# Export configuration file
generate_file(
str(export_folder / "layers" / f"{self.name}.h"),
str(ROOT / "templates" / "configuration" / "matmul_config.jinja"),
name=self.name,
inputs_dims=self.matmul_inputs_dims,
output_dims=self.matmul_output_dims,
activation="Linear",
rescaling="NoScaling",
)
return list_configs
def forward(self, list_actions:list):
if not self.is_last:
list_actions.append(set_up_output(self.name, "float"))
list_actions.append(generate_str(
str(ROOT / "templates" / "kernel_forward" / "matmul_forward.jinja"),
name=self.name,
inputs1_name=self.inputs[0].name() if self.inputs[0] else self.name + "_input1",
inputs2_name=self.inputs[1].name() if self.inputs[1] else self.name + "_input2",
outputs_name=self.name
))
return list_actions
{#- For name header -#}
#ifndef {{ name|upper }}_LAYER_H
#define {{ name|upper }}_LAYER_H
{# 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 }}_ACTIVATION {{ activation }}
static const {{ rescaling }} {{ name|upper }}_RESCALING = {};
{#- Calculate sizes #}
#endif /* {{ name|upper }}_LAYER_H */
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
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
{# mem has the datatype of the firt input #} {# mem has the datatype of the firt input #}
{#- Change here to improve it -#} {#- Change here to improve it -#}
static {{inputs[0][0]}} mem[MEMORY_SIZE]; static {{mem_ctype}} mem[MEMORY_SIZE];
{# Forward function #} {# Forward function #}
{#- Support multiple inputs with different datatypes and multiple outputs with different datatypes -#} {#- Support multiple inputs with different datatypes and multiple outputs with different datatypes -#}
......
0.1.1 0.1.2
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