Skip to content

[export_cpp] Duplicate activation layer in model_forward for MobileNetV1 network

Problem description

When exporting to CPP a mobilenetV1 network from an onnx file, the model_forward function has too many activation_forward functions, and the names of the input and output arrays do not fit with those of the onnx file.

Reproducible example code

Here is the onnx file: MobileNetV1_CIFAR100.onnx

The code for the export is:

import aidge_core
import aidge_backend_cpu
import aidge_onnx
import aidge_export_cpp  
import os
import requests  

from pathlib import Path
MODEL_PATH = Path("models")

ONNX_NAME = "MobileNetV1_CIFAR100.onnx"
channels = 3
size = 32

ONNX_PATH = MODEL_PATH / ONNX_NAME
model = aidge_onnx.load_onnx(ONNX_PATH)  

# Remove Flatten node, useless in the CPP export
print('Removing flatten')
aidge_core.remove_flatten(model)
print(aidge_onnx.native_coverage_report(model))


# Freeze the model by setting constants to parameters producers
for node in model.get_nodes():
    if node.type() == "Producer":
#        node.get_operator().set_attr("Constant", True)
        node.get_operator().attr.constant = True

# Create Producer Node for the Graph
input_node = aidge_core.Producer([1, channels, size, size], "input")
input_node.add_child(model)
model.add(input_node)

# Configuration for the model + forward dimensions
print('Compiling model')
model.compile("cpu", aidge_core.dtype.float32)

# Generate scheduling of the model
print('Generating scheduler')
scheduler = aidge_core.SequentialScheduler(model)
scheduler.generate_scheduling()  
# model.save("test")  

# Export the model
exportFolder = ONNX_NAME.split('_')[0] + "_export_fp32"
print(f'Exporting model to folder: {exportFolder}')
aidge_export_cpp.export(exportFolder, model, scheduler)

And the generated model_forward function begins with:

void model_forward(const float* input, float* output)
{
    float* model_model_0_model_0_0_Conv_output_0 = (float*) mem + MODEL_MODEL_0_MODEL_0_0_CONV_OUTPUT_0_OFFSET;
    convolution_forward<MODEL_MODEL_0_MODEL_0_0_CONV_OUTPUT_0_NB_CHANNELS,
                    MODEL_MODEL_0_MODEL_0_0_CONV_OUTPUT_0_CHANNELS_HEIGHT,
                    MODEL_MODEL_0_MODEL_0_0_CONV_OUTPUT_0_CHANNELS_WIDTH,
                    MODEL_MODEL_0_MODEL_0_0_CONV_OUTPUT_0_NB_OUTPUTS,
                    MODEL_MODEL_0_MODEL_0_0_CONV_OUTPUT_0_OUTPUTS_HEIGHT,
                    MODEL_MODEL_0_MODEL_0_0_CONV_OUTPUT_0_OUTPUTS_WIDTH,
                    MODEL_MODEL_0_MODEL_0_0_CONV_OUTPUT_0_PADDING_Y,
                    MODEL_MODEL_0_MODEL_0_0_CONV_OUTPUT_0_PADDING_X,
                    MODEL_MODEL_0_MODEL_0_0_CONV_OUTPUT_0_STRIDE_Y,
                    MODEL_MODEL_0_MODEL_0_0_CONV_OUTPUT_0_STRIDE_X,
                    MODEL_MODEL_0_MODEL_0_0_CONV_OUTPUT_0_DILATION_Y,
                    MODEL_MODEL_0_MODEL_0_0_CONV_OUTPUT_0_DILATION_X,
                    MODEL_MODEL_0_MODEL_0_0_CONV_OUTPUT_0_KERNEL_HEIGHT,
                    MODEL_MODEL_0_MODEL_0_0_CONV_OUTPUT_0_KERNEL_WIDTH,
                    MODEL_MODEL_0_MODEL_0_0_CONV_OUTPUT_0_ACTIVATION>
                    (input, model_model_0_model_0_0_Conv_output_0, onnx__Conv_250, onnx__Conv_251, MODEL_MODEL_0_MODEL_0_0_CONV_OUTPUT_0_RESCALING);
    float* model_model_0_model_0_2_Relu = (float*) mem + MODEL_MODEL_0_MODEL_0_2_RELU_OFFSET;
    activation_forward<MODEL_MODEL_0_MODEL_0_2_RELU_NB_DATA,
                   MODEL_MODEL_0_MODEL_0_2_RELU_ACTIVATION>
                   (model_model_0_model_0_0_Conv_output_0, model_model_0_model_0_2_Relu, MODEL_MODEL_0_MODEL_0_2_RELU_RESCALING);
    float* model_model_1_model_1_2_Relu = (float*) mem + MODEL_MODEL_1_MODEL_1_2_RELU_OFFSET;
    activation_forward<MODEL_MODEL_1_MODEL_1_2_RELU_NB_DATA,
                   MODEL_MODEL_1_MODEL_1_2_RELU_ACTIVATION>
                   (model_model_1_model_1_0_Conv_output_0, model_model_1_model_1_2_Relu, MODEL_MODEL_1_MODEL_1_2_RELU_RESCALING);

The file is attached below: forward.cpp

Here is a view from Netron of the first activation layer: Capture

The first activation_forward call seems correct, except for the name of the output array, but the second call should definitely not exist.