From da6bf9e2eac374cd92147d3c60a8af8bd6bc5a37 Mon Sep 17 00:00:00 2001 From: Matthew Sloyan Date: Wed, 14 Dec 2022 10:16:27 +0000 Subject: IVGCVSW-7168 Support simple model in the TOSA Reference Backend * Fixed issue where duplicate tensors where being created. * Fixed issue where output name could be generated with the wrong id. * Updated bias tensor for Conv2d, so the size matches the channel. Signed-off-by: Matthew Sloyan Change-Id: I1de6947e036b3e629ec6446d24d69e50603a5593 --- .../operatorMappings/AdditionOperator.cpp | 33 +++++++++++++++------- .../AvgPool2DIgnoreValueOperator.cpp | 20 +++++++++---- .../tosaCommon/operatorMappings/Conv2dOperator.cpp | 26 +++++++++++------ .../operatorMappings/Pooling2DOperator.cpp | 22 ++++++++++----- .../operatorMappings/ReshapeOperator.cpp | 22 ++++++++++----- .../tosaCommon/operatorMappings/SliceOperator.cpp | 22 ++++++++++----- .../operatorMappings/TransposeConv2dOperator.cpp | 3 +- 7 files changed, 101 insertions(+), 47 deletions(-) diff --git a/src/backends/tosaCommon/operatorMappings/AdditionOperator.cpp b/src/backends/tosaCommon/operatorMappings/AdditionOperator.cpp index f1fb34c5e2..20ba146574 100644 --- a/src/backends/tosaCommon/operatorMappings/AdditionOperator.cpp +++ b/src/backends/tosaCommon/operatorMappings/AdditionOperator.cpp @@ -26,8 +26,7 @@ TosaSerializationBasicBlock* ConvertAdditionToTosaOperator(const Layer* layer, input1Name = GenerateUniqueName(connectedLayer1, 1); // Get the layer connected to the output slot and determine unique layer name. - Layer& connectedOutputLayer = layer->GetOutputSlot().GetConnection(0)->GetOwningLayer(); - outputName = GenerateUniqueName(connectedOutputLayer, 0); + outputName = GenerateUniqueOutputName(*layer, 0); } auto* op = new TosaSerializationOperator(Op_ADD, @@ -36,24 +35,38 @@ TosaSerializationBasicBlock* ConvertAdditionToTosaOperator(const Layer* layer, {input0Name, input1Name}, {outputName}); - std::vector inputShape0 = GetTosaTensorShape(inputs[0]->GetShape()); - DType inputDType0 = ArmNNToDType(inputs[0]->GetDataType()); - std::vector inputShape1 = GetTosaTensorShape(inputs[1]->GetShape()); - DType inputDType1 = ArmNNToDType(inputs[1]->GetDataType()); + std::vector tensors; + + // Only add input tensors if connected layer is an input layer. + // As intermediate or constant tensors will be created separately. + // There also can't be duplicate tensor. + if(input0Name.find("input0_") != std::string::npos) + { + std::vector inputShape0 = GetTosaTensorShape(inputs[0]->GetShape()); + DType inputDType0 = ArmNNToDType(inputs[0]->GetDataType()); + + tensors.push_back(new TosaSerializationTensor(input0Name, inputShape0, inputDType0, {})); + } + + if(input1Name.find("input1_") != std::string::npos) + { + std::vector inputShape1 = GetTosaTensorShape(inputs[1]->GetShape()); + DType inputDType1 = ArmNNToDType(inputs[1]->GetDataType()); + + tensors.push_back(new TosaSerializationTensor(input1Name, inputShape1, inputDType1, {})); + } std::vector outputShape0 = GetTosaTensorShape(outputs[0]->GetShape()); DType outputDType0 = ArmNNToDType(outputs[0]->GetDataType()); - auto* inputTensor0 = new TosaSerializationTensor(input0Name, inputShape0, inputDType0, {}); - auto* inputTensor1 = new TosaSerializationTensor(input1Name, inputShape1, inputDType1, {}); - auto* outputTensor0 = new TosaSerializationTensor(outputName, outputShape0, outputDType0, {}); + tensors.push_back(new TosaSerializationTensor(outputName, outputShape0, outputDType0, {})); // operatorInputNames/operatorOutputNames ends up being the same as // blockInputNames/blockOutputNames for one-to-one ArmNN to TOSA mappings return new TosaSerializationBasicBlock(blockName, // name {op}, // operators - {inputTensor0, inputTensor1, outputTensor0}, // tensors + tensors, // tensors {input0Name, input1Name}, // inputs {outputName}); // outputs } \ No newline at end of file diff --git a/src/backends/tosaCommon/operatorMappings/AvgPool2DIgnoreValueOperator.cpp b/src/backends/tosaCommon/operatorMappings/AvgPool2DIgnoreValueOperator.cpp index 7e7631dcef..d268c2faa4 100644 --- a/src/backends/tosaCommon/operatorMappings/AvgPool2DIgnoreValueOperator.cpp +++ b/src/backends/tosaCommon/operatorMappings/AvgPool2DIgnoreValueOperator.cpp @@ -24,8 +24,7 @@ TosaSerializationBasicBlock* ConvertAvgPool2DIgnoreValueToTosaOperator(const Lay padInputName = GenerateUniqueName(connectedInputLayer, 0); // Get the layer connected to the output slot and determine unique layer name. - Layer& connectedOutputLayer = layer->GetOutputSlot().GetConnection(0)->GetOwningLayer(); - poolOutputName = GenerateUniqueName(connectedOutputLayer, 0); + poolOutputName = GenerateUniqueOutputName(*layer, 0); } std::vector paddings; @@ -74,9 +73,19 @@ TosaSerializationBasicBlock* ConvertAvgPool2DIgnoreValueToTosaOperator(const Lay {padOutputName}, {poolOutputName}); + std::vector tensors; + std::vector inputShape = GetTosaTensorShape(inputs[0]->GetShape()); DType inputDType = ArmNNToDType(inputs[0]->GetDataType()); + // Only add input tensors if connected layer is an input layer. + // As intermediate or constant tensors will be created separately. + // There also can't be duplicate tensor. + if(padInputName.find("input0_") != std::string::npos) + { + tensors.push_back(new TosaSerializationTensor(padInputName, inputShape, inputDType, {})); + } + std::vector outputShape = GetTosaTensorShape(outputs[0]->GetShape()); DType outputDType = ArmNNToDType(outputs[0]->GetDataType()); @@ -96,15 +105,14 @@ TosaSerializationBasicBlock* ConvertAvgPool2DIgnoreValueToTosaOperator(const Lay inputShape[3] + paddings[6] + paddings[7]}; } - auto* inputTensor = new TosaSerializationTensor(padInputName, inputShape, inputDType, {}); - auto* intermediateTensor = new TosaSerializationTensor(padOutputName, intermediateShape, inputDType, {}); - auto* outputTensor = new TosaSerializationTensor(poolOutputName, outputShape, outputDType, {}); + tensors.push_back(new TosaSerializationTensor(padOutputName, intermediateShape, inputDType, {})); + tensors.push_back(new TosaSerializationTensor(poolOutputName, outputShape, outputDType, {})); // operatorInputNames/operatorOutputNames ends up being the same as // blockInputNames/blockOutputNames for one-to-one ArmNN to TOSA mappings return new TosaSerializationBasicBlock(blockName, // name {opPad, opPool}, // operators - {inputTensor, intermediateTensor, outputTensor}, // tensors + tensors, // tensors {padInputName}, // inputs {poolOutputName}); // outputs } \ No newline at end of file diff --git a/src/backends/tosaCommon/operatorMappings/Conv2dOperator.cpp b/src/backends/tosaCommon/operatorMappings/Conv2dOperator.cpp index 9c095d627f..dadd91b227 100644 --- a/src/backends/tosaCommon/operatorMappings/Conv2dOperator.cpp +++ b/src/backends/tosaCommon/operatorMappings/Conv2dOperator.cpp @@ -39,19 +39,23 @@ TosaSerializationBasicBlock* ConvertConv2dToTosaOperator(const Layer* layer, } // Get the layer connected to the output slot and determine unique layer name. - Layer& connectedLayer = layer->GetOutputSlot().GetConnection(0)->GetOwningLayer(); - - outputName = GenerateUniqueName(connectedLayer, 0); + outputName = GenerateUniqueOutputName(*layer, 0); } std::vector tensors; std::vector operators; // Setup input Tensor - std::vector inputShape0 = GetTosaTensorShape(inputs[0]->GetShape()); - DType inputDType0 = ArmNNToDType(inputs[0]->GetDataType()); + // Only add tensor if connected layer is an input layer. + // As intermediate or constant tensors will be created separately. + // There also can't be duplicate tensors. + if(inputNames[0].find("input0_") != std::string::npos) + { + std::vector inputShape0 = GetTosaTensorShape(inputs[0]->GetShape()); + DType inputDType0 = ArmNNToDType(inputs[0]->GetDataType()); - tensors.push_back(new TosaSerializationTensor(inputNames[0], inputShape0, inputDType0, {})); + tensors.push_back(new TosaSerializationTensor(inputNames[0], inputShape0, inputDType0, {})); + } // Only add input tensors if weights and bias are not constant or if running validation. // Constant tensors will be created in the ConvertConstantToTosaOperator function. @@ -80,12 +84,18 @@ TosaSerializationBasicBlock* ConvertConv2dToTosaOperator(const Layer* layer, operators.push_back(new TosaSerializationOperator(Op_CONST, Attribute_NONE, nullptr, {}, {constantName})); + // The size of the bias must match the channels dimension, so get the correct index. + unsigned int index = (conv2dDescriptor->m_DataLayout == DataLayout::NHWC) ? 3 : 1; + std::vector uint8Data; - std::vector data = { 0.0 }; + std::vector data(outputs[0]->GetShape()[index], 0.0f); TosaSerializationHandler::ConvertF32toU8(data, uint8Data); - tensors.push_back(new TosaSerializationTensor(constantName, {1}, DType_FP32, uint8Data)); + tensors.push_back(new TosaSerializationTensor(constantName, + {static_cast(outputs[0]->GetShape()[index])}, + DType_FP32, + uint8Data)); inputNames.emplace_back(constantName); } diff --git a/src/backends/tosaCommon/operatorMappings/Pooling2DOperator.cpp b/src/backends/tosaCommon/operatorMappings/Pooling2DOperator.cpp index 265901e1ae..ee02425c17 100644 --- a/src/backends/tosaCommon/operatorMappings/Pooling2DOperator.cpp +++ b/src/backends/tosaCommon/operatorMappings/Pooling2DOperator.cpp @@ -26,8 +26,7 @@ TosaSerializationBasicBlock* ConvertPooling2DToTosaOperator(const Layer* layer, input0Name = GenerateUniqueName(connectedInputLayer, 0); // Get the layer connected to the output slot and determine unique layer name. - Layer& connectedOutputLayer = layer->GetOutputSlot().GetConnection(0)->GetOwningLayer(); - outputName = GenerateUniqueName(connectedOutputLayer, 0); + outputName = GenerateUniqueOutputName(*layer, 0); } std::vector pad = {static_cast(poolDescriptor->m_PadTop), @@ -46,20 +45,29 @@ TosaSerializationBasicBlock* ConvertPooling2DToTosaOperator(const Layer* layer, {input0Name}, {outputName}); - std::vector inputShape0 = GetTosaTensorShape(inputs[0]->GetShape()); - DType inputDType0 = ArmNNToDType(inputs[0]->GetDataType()); + std::vector tensors; + + // Only add input tensors if connected layer is an input layer. + // As intermediate or constant tensors will be created separately. + // There also can't be duplicate tensor. + if(input0Name.find("input0_") != std::string::npos) + { + std::vector inputShape0 = GetTosaTensorShape(inputs[0]->GetShape()); + DType inputDType0 = ArmNNToDType(inputs[0]->GetDataType()); + + tensors.push_back(new TosaSerializationTensor(input0Name, inputShape0, inputDType0, {})); + } std::vector outputShape0 = GetTosaTensorShape(outputs[0]->GetShape()); DType outputDType0 = ArmNNToDType(outputs[0]->GetDataType()); - auto* inputTensor0 = new TosaSerializationTensor(input0Name, inputShape0, inputDType0, {}); - auto* outputTensor0 = new TosaSerializationTensor(outputName, outputShape0, outputDType0, {}); + tensors.push_back(new TosaSerializationTensor(outputName, outputShape0, outputDType0, {})); // operatorInputNames/operatorOutputNames ends up being the same as // blockInputNames/blockOutputNames for one-to-one ArmNN to TOSA mappings return new TosaSerializationBasicBlock(blockName, // name {op}, // operators - {inputTensor0, outputTensor0}, // tensors + tensors, // tensors {input0Name}, // inputs {outputName}); // outputs } \ No newline at end of file diff --git a/src/backends/tosaCommon/operatorMappings/ReshapeOperator.cpp b/src/backends/tosaCommon/operatorMappings/ReshapeOperator.cpp index b88a6ef894..3027e2ef42 100644 --- a/src/backends/tosaCommon/operatorMappings/ReshapeOperator.cpp +++ b/src/backends/tosaCommon/operatorMappings/ReshapeOperator.cpp @@ -23,8 +23,7 @@ TosaSerializationBasicBlock* ConvertReshapeToTosaOperator(const Layer* layer, inputName = GenerateUniqueName(connectedLayer, 0); // Get the layer connected to the output slot and determine unique layer name. - Layer& connectedOutputLayer = layer->GetOutputSlot().GetConnection(0)->GetOwningLayer(); - outputName = GenerateUniqueName(connectedOutputLayer, 0); + outputName = GenerateUniqueOutputName(*layer, 0); } TosaReshapeAttribute attribute(GetTosaTensorShape(reshapeDescriptor->m_TargetShape)); @@ -35,20 +34,29 @@ TosaSerializationBasicBlock* ConvertReshapeToTosaOperator(const Layer* layer, {inputName}, {outputName}); - std::vector inputShape = GetTosaTensorShape(inputs[0]->GetShape()); - DType inputDType = ArmNNToDType(inputs[0]->GetDataType()); + std::vector tensors; + + // Only add input tensors if connected layer is an input layer. + // As intermediate or constant tensors will be created separately. + // There also can't be duplicate tensor. + if(inputName.find("input0_") != std::string::npos) + { + std::vector inputShape = GetTosaTensorShape(inputs[0]->GetShape()); + DType inputDType = ArmNNToDType(inputs[0]->GetDataType()); + + tensors.push_back(new TosaSerializationTensor(inputName, inputShape, inputDType, {})); + } std::vector outputShape = GetTosaTensorShape(outputs[0]->GetShape()); DType outputDType = ArmNNToDType(outputs[0]->GetDataType()); - auto* inputTensor = new TosaSerializationTensor(inputName, inputShape, inputDType, {}); - auto* outputTensor = new TosaSerializationTensor(outputName, outputShape, outputDType, {}); + tensors.push_back(new TosaSerializationTensor(outputName, outputShape, outputDType, {})); // operatorInputNames/operatorOutputNames ends up being the same as // blockInputNames/blockOutputNames for one-to-one ArmNN to TOSA mappings return new TosaSerializationBasicBlock(blockName, // name {op}, // operators - {inputTensor, outputTensor}, // tensors + tensors, // tensors {inputName}, // inputs {outputName}); // outputs } \ No newline at end of file diff --git a/src/backends/tosaCommon/operatorMappings/SliceOperator.cpp b/src/backends/tosaCommon/operatorMappings/SliceOperator.cpp index fc2e40a95c..742ba88d73 100644 --- a/src/backends/tosaCommon/operatorMappings/SliceOperator.cpp +++ b/src/backends/tosaCommon/operatorMappings/SliceOperator.cpp @@ -23,8 +23,7 @@ TosaSerializationBasicBlock* ConvertSliceToTosaOperator(const Layer* layer, inputName = GenerateUniqueName(connectedLayer, 0); // Get the layer connected to the output slot and determine unique layer name. - Layer& connectedOutputLayer = layer->GetOutputSlot().GetConnection(0)->GetOwningLayer(); - outputName = GenerateUniqueName(connectedOutputLayer, 0); + outputName = GenerateUniqueOutputName(*layer, 0); } std::vector begin(sliceDescriptor->m_Begin.begin(), sliceDescriptor->m_Begin.end()); @@ -38,20 +37,29 @@ TosaSerializationBasicBlock* ConvertSliceToTosaOperator(const Layer* layer, {inputName}, {outputName}); - std::vector inputShape = GetTosaTensorShape(inputs[0]->GetShape()); - DType inputDType = ArmNNToDType(inputs[0]->GetDataType()); + std::vector tensors; + + // Only add input tensors if connected layer is an input layer. + // As intermediate or constant tensors will be created separately. + // There also can't be duplicate tensor. + if(inputName.find("input0_") != std::string::npos) + { + std::vector inputShape = GetTosaTensorShape(inputs[0]->GetShape()); + DType inputDType = ArmNNToDType(inputs[0]->GetDataType()); + + tensors.push_back(new TosaSerializationTensor(inputName, inputShape, inputDType, {})); + } std::vector outputShape = GetTosaTensorShape(outputs[0]->GetShape()); DType outputDType = ArmNNToDType(outputs[0]->GetDataType()); - auto* inputTensor = new TosaSerializationTensor(inputName, inputShape, inputDType, {}); - auto* outputTensor = new TosaSerializationTensor(outputName, outputShape, outputDType, {}); + tensors.push_back(new TosaSerializationTensor(outputName, outputShape, outputDType, {})); // operatorInputNames/operatorOutputNames ends up being the same as // blockInputNames/blockOutputNames for one-to-one ArmNN to TOSA mappings return new TosaSerializationBasicBlock(blockName, // name {op}, // operators - {inputTensor, outputTensor}, // tensors + tensors, // tensors {inputName}, // inputs {outputName}); // outputs } \ No newline at end of file diff --git a/src/backends/tosaCommon/operatorMappings/TransposeConv2dOperator.cpp b/src/backends/tosaCommon/operatorMappings/TransposeConv2dOperator.cpp index a0d58e2fa8..1ad8c9562f 100644 --- a/src/backends/tosaCommon/operatorMappings/TransposeConv2dOperator.cpp +++ b/src/backends/tosaCommon/operatorMappings/TransposeConv2dOperator.cpp @@ -94,8 +94,7 @@ TosaSerializationBasicBlock* ConvertTransposeConv2dToTosaOperator(const Layer* l { // If bias is disabled, create a constant bias tensor of 0's as three inputs are required. // The size of the bias must match the channels dimension, so get the correct index. - unsigned int index = (descriptor->m_DataLayout == DataLayout::NHWC) ? - outputs[0]->GetShape()[3] : outputs[0]->GetShape()[1]; + unsigned int index = (descriptor->m_DataLayout == DataLayout::NHWC) ? 3 : 1; std::vector uint8Data; std::vector data(outputs[0]->GetShape()[index], 0.0f); -- cgit v1.2.1