Files
2026-07-13 13:33:03 +08:00

147 lines
5.8 KiB
C++

//
// QNNFlatten.cpp
// MNN
//
// Created by MNN on b'2025/04/10'.
// Copyright © 2018, Alibaba Group Holding Limited
//
#include "QNNFlatten.hpp"
namespace MNN {
namespace QNN {
#ifdef ENABLE_QNN_ONLINE_FINALIZE
ErrorCode QNNFlatten::onEncode(const std::vector<Tensor *> &inputs, const std::vector<Tensor *> &outputs) {
Tensor::DimensionType inputDimType = inputs[0]->getDimensionType();
Tensor::DimensionType outputDimType = outputs[0]->getDimensionType();
MNN_ASSERT(inputDimType == outputDimType);
std::vector<uint32_t> inputQnnShape = getNHWCShape(inputs[0]);
std::vector<uint32_t> outputQnnShape = getNHWCShape(outputs[0]);
if(TensorUtils::getDescribe(inputs[0])->dimensionFormat == MNN_DATA_FORMAT_NC4HW4) {
if(inputQnnShape[inputs[0]->dimensions() - 1] != outputQnnShape[outputs[0]->dimensions() - 1]){
this->ReshapeTranspose(inputs, outputs);
return NO_ERROR;
}
}
mNodeType = "Reshape";
// this->addNodeCommon(inputs, outputs);
this->addNodeCommonReshape("Reshape", *(mBackend->getNativeTensor(inputs[0])), *(mBackend->getNativeTensor(outputs[0])));
return NO_ERROR;
}
void QNNFlatten::ReshapeTranspose(const std::vector<Tensor *> &inputs, const std::vector<Tensor *> &outputs) {
std::vector<uint32_t> inputShape = getNHWCShape(inputs[0]);
std::vector<uint32_t> outputShape = getNHWCShape(outputs[0]);
int inputDim = inputs[0]->shape().size();
int outputDim = outputs[0]->shape().size();
std::vector<uint32_t> inputReshape(inputShape);
std::vector<uint32_t> outputReshape(outputShape);
std::vector<uint32_t> inputPerm(inputDim, 0);
std::vector<uint32_t> outputPerm(outputDim, 0);
inputReshape[0] = inputShape[0];
outputReshape[0] = outputShape[0];
bool permuteInput = false;
bool permuteOutput = false;
int inputTempIndex, outputTempIndex;
int tempNum = 0;
if (inputDim > 2) {
permuteInput = true;
for (int i = 1; i < inputDim - 1; ++i) {
inputPerm[i + 1] = i;
inputReshape[i + 1] = inputShape[i];
}
inputPerm[1] = inputDim - 1;
inputReshape[1] = inputShape[inputDim - 1];
Qnn_DataType_t dataType = mBackend->getNativeTensor(inputs[0])->v1.dataType;
this->createStageTensor("permute_input", dataType, inputReshape, inputs[0]);
inputTempIndex = tempNum;
tempNum++;
}
if (outputDim > 2) {
permuteOutput = true;
for (int i = 1; i < outputDim - 1; ++i) {
outputPerm[i] = i + 1;
outputReshape[i + 1] = outputShape[i];
}
outputPerm[outputDim - 1] = 1;
outputReshape[1] = outputShape[outputDim - 1];
Qnn_DataType_t dataType = mBackend->getNativeTensor(outputs[0])->v1.dataType;
this->createStageTensor("permute_output", dataType, outputReshape, outputs[0]);
outputTempIndex = tempNum;
tempNum++;
}
// nhwc -> nchw
if (permuteInput) {
mNodeType = "Transpose";
std::string name = mNodeName + "_input_transpose";
mParams.clear();
mInputs.clear();
mOutputs.clear();
this->createParamTensor("perm", QNN_DATATYPE_UINT_32, {(uint32_t)inputPerm.size()}, (void*)inputPerm.data(),
"_input_transpose");
mParams.push_back(*(mParamTensorWrappers.back()->getNativeParam()));
mInputs.push_back(*(mBackend->getNativeTensor(inputs[0])));
mOutputs.push_back(*(mTempTensorWrappers[inputTempIndex]->getNativeTensor()));
mBackend->addNodeToGraph(mOpConfigVersion, name.c_str(), mPackageName.c_str(), mNodeType.c_str(), mParams,
mInputs, mOutputs);
}
// reshape
{
mNodeType = "Reshape";
std::string name = mNodeName;
mParams.clear();
mInputs.clear();
mOutputs.clear();
if (permuteInput) {
mInputs.push_back(*(mTempTensorWrappers[inputTempIndex]->getNativeTensor()));
} else {
mInputs.push_back(*(mBackend->getNativeTensor(inputs[0])));
}
if (permuteOutput) {
mOutputs.push_back(*(mTempTensorWrappers[outputTempIndex]->getNativeTensor()));
} else {
mOutputs.push_back(*(mBackend->getNativeTensor(outputs[0])));
}
mBackend->addNodeToGraph(mOpConfigVersion, name.c_str(), mPackageName.c_str(), mNodeType.c_str(), mParams,
mInputs, mOutputs);
}
// nchw -> nhwc
{
mNodeType = "Transpose";
std::string name = mNodeName + "_output_transpose";
mParams.clear();
mInputs.clear();
mOutputs.clear();
this->createParamTensor("perm", QNN_DATATYPE_UINT_32, {(uint32_t)outputPerm.size()}, (void*)outputPerm.data(),
"_output_transpose");
mParams.push_back(*(mParamTensorWrappers.back()->getNativeParam()));
mInputs.push_back(*(mTempTensorWrappers[outputTempIndex]->getNativeTensor()));
mOutputs.push_back(*(mBackend->getNativeTensor(outputs[0])));
mBackend->addNodeToGraph(mOpConfigVersion, name.c_str(), mPackageName.c_str(), mNodeType.c_str(), mParams,
mInputs, mOutputs);
}
}
class QNNFlattenCreator : public QnnBackend::Creator {
public:
virtual QNNCommonExecution * onCreate(const std::vector<Tensor*>& inputs, const std::vector<Tensor*>& outputs, const MNN::Op* op,
Backend* backend) const override {
return new QNNFlatten(backend, op);
}
};
REGISTER_QNN_OP_CREATOR(QNNFlattenCreator, OpType_Squeeze)
REGISTER_QNN_OP_CREATOR(QNNFlattenCreator, OpType_Unsqueeze)
REGISTER_QNN_OP_CREATOR(QNNFlattenCreator, OpType_Reshape)
REGISTER_QNN_OP_CREATOR(QNNFlattenCreator, OpType_Flatten)
#endif
} // end namespace QNN
} // end namespace MNN