743 lines
35 KiB
C++
743 lines
35 KiB
C++
#include "QNNConvertor.hpp"
|
|
#include "core/MNNFileUtils.h"
|
|
#include <cctype>
|
|
|
|
#define APPEND_VECTOR(vec1, vec2) (vec1.insert(vec1.end(), std::make_move_iterator(vec2.begin()), std::make_move_iterator(vec2.end())))
|
|
#define TENSOR_NAME_SYMBOL(cName) ("tensor_" + std::string(cName))
|
|
#define PARAM_NAME_SYMBOL(cName) ("param_" + std::string(cName) + "_" + nodeName)
|
|
|
|
namespace MNN {
|
|
namespace QNN {
|
|
#ifdef ENABLE_QNN_ONLINE_FINALIZE
|
|
|
|
std::string QNNConvertor::OutputDir = "";
|
|
std::string QNNTranslator::GraphNameSymbol = "";
|
|
FILE * QNNConvertor::CppFilePointer = nullptr;
|
|
std::string QNNConvertor::CppBuffer = "";
|
|
const uint32_t QNNConvertor::CppBufferSize = 4096; // 4KB
|
|
|
|
std::string GetLastDirName(const std::string& path) {
|
|
if (path.empty()) {
|
|
MNN_ERROR("MNN_QNN: Invalid output dir for QNNConvertor. original path: %s\n", path.c_str());
|
|
return "";
|
|
}
|
|
|
|
std::string result = path;
|
|
|
|
// Remove '/' and '\\' at the end.
|
|
while (!result.empty() && (result.back() == '/' || result.back() == '\\')) {
|
|
result.pop_back();
|
|
}
|
|
if (result.empty()) {
|
|
MNN_ERROR("MNN_QNN: Invalid output dir for QNNConvertor. result path: %s\n", result.c_str());
|
|
return "";
|
|
}
|
|
|
|
size_t lastSeparator = result.find_last_of("/\\");
|
|
// No '/' and '\\' in the path.
|
|
if (lastSeparator != std::string::npos) {
|
|
result = result.substr(lastSeparator + 1);
|
|
}
|
|
|
|
// Check whether result is a legal cpp symbol.
|
|
if (std::isdigit(result[0])) {
|
|
MNN_ERROR("MNN_QNN: Invalid cache path. result path: %s\n", result.c_str());
|
|
return "";
|
|
}
|
|
for (size_t i = 0; i < result.size(); ++i) {
|
|
if (!(std::isalpha(result[i]) || std::isdigit(result[i]) || result[i] == '_')) {
|
|
MNN_ERROR("MNN_QNN: Invalid cache path. result path: %s\n", result.c_str());
|
|
return "";
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void QNNConvertor::RecordBegin(const char* graphName) {
|
|
MNN_ASSERT(!(QNNConvertor::OutputDir.empty()));
|
|
QNNTranslator::GraphNameSymbol = GetLastDirName(QNNConvertor::OutputDir);
|
|
MNN_ASSERT(!(QNNTranslator::GraphNameSymbol.empty()));
|
|
|
|
QNNConvertor::CppBuffer.reserve(QNNConvertor::CppBufferSize);
|
|
|
|
std::string cppFilePath = MNNFilePathConcat(QNNConvertor::OutputDir, QNNTranslator::GraphNameSymbol + ".cpp");
|
|
QNNConvertor::CppFilePointer = std::fopen(cppFilePath.c_str(), "w");
|
|
if (!QNNConvertor::CppFilePointer) {
|
|
MNN_ERROR("MNN_QNN: Failed to open file %s.\n", cppFilePath.c_str());
|
|
return;
|
|
}
|
|
|
|
QNNCommand cmd = {};
|
|
cmd.type = QNNCommandTypeBegin;
|
|
|
|
QNNConvertor::Translate(cmd);
|
|
|
|
return;
|
|
}
|
|
|
|
void QNNConvertor::RecordTensor(const Qnn_Tensor_t * tensor) {
|
|
QNNCommand cmd;
|
|
|
|
cmd.type = QNNCommandTypeTensor;
|
|
|
|
const Qnn_TensorV1_t & t = tensor->v1;
|
|
cmd.commandTensor.name = t.name;
|
|
switch (t.type) {
|
|
case QNN_TENSOR_TYPE_APP_WRITE:
|
|
cmd.commandTensor.type = TENSOR_INPUT;
|
|
break;
|
|
case QNN_TENSOR_TYPE_APP_READ:
|
|
cmd.commandTensor.type = TENSOR_OUTPUT;
|
|
break;
|
|
case QNN_TENSOR_TYPE_NATIVE:
|
|
cmd.commandTensor.type = TENSOR_NATIVE;
|
|
break;
|
|
case QNN_TENSOR_TYPE_STATIC: {
|
|
std::string sname(t.name);
|
|
bool isParam = false;
|
|
if (sname.size() >= 5) {
|
|
isParam = (sname.compare(sname.size() - 5, 5, gParamMarker) == 0);
|
|
}
|
|
cmd.commandTensor.type = isParam ? TENSOR_PARAM : TENSOR_STATIC;
|
|
break;
|
|
}
|
|
default:
|
|
MNN_ERROR("MNN_QNN: Unknown Qnn_Convertor_Tensor_t.\n");
|
|
return;
|
|
}
|
|
cmd.commandTensor.dataType = t.dataType;
|
|
cmd.commandTensor.quantizeParams = t.quantizeParams;
|
|
cmd.commandTensor.rank = t.rank;
|
|
cmd.commandTensor.dimensions = t.dimensions;
|
|
cmd.commandTensor.clientBuf = t.clientBuf;
|
|
|
|
QNNConvertor::Translate(cmd);
|
|
|
|
if (cmd.commandTensor.type == Qnn_Convertor_Tensor_t::TENSOR_STATIC) {
|
|
QNNConvertor::DumpBuffer(cmd.commandTensor.name, cmd.commandTensor.clientBuf.data, cmd.commandTensor.clientBuf.dataSize);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void QNNConvertor::RecordNode(const Qnn_OpConfig_t & opConfig) {
|
|
QNNCommand cmd;
|
|
|
|
cmd.type = QNNCommandTypeNode;
|
|
|
|
const Qnn_OpConfigV1_t & op = opConfig.v1;
|
|
|
|
cmd.commandNode.name = op.name;
|
|
cmd.commandNode.packageName = op.packageName;
|
|
cmd.commandNode.typeName = op.typeName;
|
|
cmd.commandNode.numOfParams = op.numOfParams;
|
|
cmd.commandNode.params = op.params;
|
|
cmd.commandNode.numOfInputs = op.numOfInputs;
|
|
cmd.commandNode.inputTensors = op.inputTensors;
|
|
cmd.commandNode.numOfOutputs = op.numOfOutputs;
|
|
cmd.commandNode.outputTensors = op.outputTensors;
|
|
|
|
QNNConvertor::Translate(cmd);
|
|
|
|
return;
|
|
}
|
|
|
|
void QNNConvertor::RecordEnd() {
|
|
QNNCommand cmd = {};
|
|
cmd.type = QNNCommandTypeEnd;
|
|
|
|
QNNConvertor::Translate(cmd);
|
|
|
|
if (std::fclose(QNNConvertor::CppFilePointer) != 0) {
|
|
MNN_ERROR("MNN_QNN: Failed to close the cpp file for QNNConvertor.\n");
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void QNNConvertor::Translate(const QNNCommand & cmd) {
|
|
std::vector<std::string> cppLines = QNNTranslator::TranslateCommand(cmd);
|
|
for (const std::string& line : cppLines) {
|
|
QNNConvertor::CppBuffer.append(line);
|
|
QNNConvertor::CppBuffer.push_back('\n');
|
|
}
|
|
size_t written = std::fwrite(QNNConvertor::CppBuffer.data(), 1, QNNConvertor::CppBuffer.size(), QNNConvertor::CppFilePointer);
|
|
if (written != QNNConvertor::CppBuffer.size()) {
|
|
MNN_ERROR("MNN_QNN: Failed to write to the Cpp File of QNNConvertor.\n");
|
|
}
|
|
QNNConvertor::CppBuffer.clear();
|
|
return;
|
|
}
|
|
|
|
void QNNConvertor::DumpBuffer(const char * name, const void * buffer, size_t size) {
|
|
std::string dataPath = MNNFilePathConcat(QNNConvertor::OutputDir, std::string(name) + ".raw");
|
|
|
|
FILE* fp = std::fopen(dataPath.c_str(), "wb");
|
|
if (!fp) {
|
|
MNN_ERROR("MNN_QNN: Failed to open file %s.\n", dataPath.c_str());
|
|
return;
|
|
}
|
|
|
|
size_t written = std::fwrite(buffer, 1, size, fp);
|
|
if (written != size) {
|
|
MNN_ERROR("MNN_QNN: Failed to write to file %s. Written: %zu, Expected: %zu\n", dataPath.c_str(), written, size);
|
|
}
|
|
|
|
int code = std::fclose(fp);
|
|
if (code != 0) {
|
|
MNN_ERROR("MNN_QNN: Failed to close file %s.\n", dataPath.c_str());
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
std::vector<std::string> QNNTranslator::TranslateCommand(const QNNCommand & cmd) {
|
|
switch (cmd.type) {
|
|
case QNNCommandTypeBegin:
|
|
return QNNTranslator::TranslateBegin();
|
|
case QNNCommandTypeTensor:
|
|
return QNNTranslator::TranslateTensor(cmd.commandTensor);
|
|
case QNNCommandTypeNode:
|
|
return QNNTranslator::TranslateNode(cmd.commandNode);
|
|
case QNNCommandTypeEnd:
|
|
return QNNTranslator::TranslateEnd();
|
|
default:
|
|
MNN_PRINT("MNN_QNN: Unknown QNNCommandType.\n");
|
|
return {};
|
|
}
|
|
}
|
|
|
|
std::vector<std::string> QNNTranslator::TranslateBegin() {
|
|
std::vector<std::string> result;
|
|
|
|
result.push_back("#include \"QnnModel.hpp\"");
|
|
result.push_back("#include \"QnnOpDef.h\"");
|
|
result.push_back("");
|
|
result.push_back("// Flag to determine if Backend should node validation for each opNode added");
|
|
result.push_back("#define DO_GRAPH_NODE_VALIDATIONS 1");
|
|
result.push_back("");
|
|
result.push_back("using namespace qnn_wrapper_api;");
|
|
result.push_back("extern \"C\" {");
|
|
result.push_back("QNN_API");
|
|
result.push_back("ModelError_t QnnModel_composeGraphs(Qnn_BackendHandle_t backendHandle,");
|
|
result.push_back(" QNN_INTERFACE_VER_TYPE interface,");
|
|
result.push_back(" Qnn_ContextHandle_t contextHandle,");
|
|
result.push_back(" const GraphConfigInfo_t** graphsConfigInfo,");
|
|
result.push_back(" const uint32_t numGraphsConfigInfo,");
|
|
result.push_back(" GraphInfoPtr_t** graphsInfo,");
|
|
result.push_back(" uint32_t* numGraphsInfo,");
|
|
result.push_back(" bool debug,");
|
|
result.push_back(" QnnLog_Callback_t logCallback,");
|
|
result.push_back(" QnnLog_Level_t maxLogLevel) {");
|
|
result.push_back(" ModelError_t err = MODEL_NO_ERROR;");
|
|
result.push_back("");
|
|
result.push_back(" /* model/graph for " + QNNTranslator::GraphNameSymbol + "*/");
|
|
result.push_back(" QnnModel " + QNNTranslator::GraphNameSymbol + ";");
|
|
result.push_back(" const QnnGraph_Config_t** graphConfigs = nullptr;");
|
|
result.push_back(" VALIDATE(getQnnGraphConfigFromInfo(");
|
|
result.push_back(" \"" + QNNTranslator::GraphNameSymbol + "\", graphsConfigInfo, numGraphsConfigInfo, graphConfigs),");
|
|
result.push_back(" err);");
|
|
result.push_back(" VALIDATE(" + QNNTranslator::GraphNameSymbol + ".initialize(backendHandle,");
|
|
result.push_back(" interface,");
|
|
result.push_back(" contextHandle,");
|
|
result.push_back(" \"" + QNNTranslator::GraphNameSymbol + "\",");
|
|
result.push_back(" debug,");
|
|
result.push_back(" DO_GRAPH_NODE_VALIDATIONS,");
|
|
result.push_back(" graphConfigs),");
|
|
result.push_back(" err);");
|
|
result.push_back("");
|
|
|
|
return result;
|
|
}
|
|
|
|
std::vector<std::string> QNNTranslator::TranslateTensor(const QNNCommandTensor& cmdT) {
|
|
std::string sName = cmdT.name;
|
|
std::string tensorNameSymbol = TENSOR_NAME_SYMBOL(cmdT.name);
|
|
std::string dimensionsNameSymbol = "dimensions_" + sName;
|
|
std::string dataNameSymbol = "data_" + sName;
|
|
|
|
bool isParam = (cmdT.type == Qnn_Convertor_Tensor_t::TENSOR_PARAM) ? true : false;
|
|
bool hasClientBuf = (cmdT.clientBuf.data != nullptr) ? true : false;
|
|
bool hasQuant = (cmdT.quantizeParams.encodingDefinition == QNN_DEFINITION_DEFINED) ? true : false;
|
|
bool shouldBeAdded = (cmdT.type == Qnn_Convertor_Tensor_t::TENSOR_INPUT) || (cmdT.type == Qnn_Convertor_Tensor_t::TENSOR_STATIC);
|
|
|
|
std::vector<std::string> result;
|
|
|
|
result.push_back("");
|
|
result.push_back(" // Adding Tensor for " + sName + ".");
|
|
result.push_back(QNNTranslator::TranslateDimensionsArray(dimensionsNameSymbol, cmdT.rank, cmdT.dimensions));
|
|
if (isParam) {
|
|
result.push_back(QNNTranslator::TranslateParamDataArray(dataNameSymbol, cmdT.dataType, cmdT.clientBuf));
|
|
}
|
|
if(hasQuant){
|
|
std::vector<std::string> linesQuantScaleOffset = TranslateQuantizeScaleOffsetDataArray(tensorNameSymbol, cmdT.quantizeParams, cmdT.rank, cmdT.dimensions);
|
|
APPEND_VECTOR(result, linesQuantScaleOffset);
|
|
}
|
|
result.push_back(" Qnn_Tensor_t " + tensorNameSymbol + " = QNN_TENSOR_INIT;");
|
|
result.push_back(" {");
|
|
result.push_back(" " + tensorNameSymbol + ".version = QNN_TENSOR_VERSION_1;");
|
|
result.push_back(" " + tensorNameSymbol + ".v1.id = 0;");
|
|
result.push_back(" " + tensorNameSymbol + ".v1.name = \"" + sName +"\";");
|
|
result.push_back(" " + tensorNameSymbol + ".v1.type = " + QNNTranslator::MapTensorType(cmdT.type) + ";");
|
|
result.push_back(" " + tensorNameSymbol + ".v1.dataFormat = QNN_TENSOR_DATA_FORMAT_FLAT_BUFFER;");
|
|
result.push_back(" " + tensorNameSymbol + ".v1.dataType = " + QNNTranslator::MapDataType(cmdT.dataType) + ";");
|
|
std::vector<std::string> linesQuant = QNNTranslator::TranslateTensorQuantizeParams(tensorNameSymbol, cmdT.quantizeParams);
|
|
APPEND_VECTOR(result, linesQuant);
|
|
result.push_back(" " + tensorNameSymbol + ".v1.rank = " + std::to_string(cmdT.rank) + ";");
|
|
result.push_back(" " + tensorNameSymbol + ".v1.dimensions = " + dimensionsNameSymbol + ";");
|
|
result.push_back(" " + tensorNameSymbol + ".v1.memType = QNN_TENSORMEMTYPE_RAW;");
|
|
std::vector<std::string> linesClientBuf = QNNTranslator::TranslateTensorClientBuf(tensorNameSymbol, dataNameSymbol, sName, cmdT.clientBuf, hasClientBuf, isParam);
|
|
APPEND_VECTOR(result, linesClientBuf);
|
|
result.push_back(" }");
|
|
|
|
if (shouldBeAdded) {
|
|
result.push_back(" VALIDATE(" + QNNTranslator::GraphNameSymbol + ".addTensor(\"" + sName + "\", " + tensorNameSymbol + "), err);");
|
|
}
|
|
|
|
result.push_back("");
|
|
|
|
return result;
|
|
}
|
|
|
|
std::vector<std::string> QNNTranslator::TranslateNode(const QNNCommandNode& cmdN) {
|
|
std::string sName = cmdN.name;
|
|
std::string paramArraySymbol = "params_" + sName;
|
|
std::string inputArraySymbol = "inputs_" + sName;
|
|
std::string outputArraySymbol = "outputs_" + sName;
|
|
|
|
std::vector<std::string> result;
|
|
|
|
result.push_back("");
|
|
result.push_back(" // Adding Node for " + sName + ".");
|
|
|
|
std::vector<std::string> linesParamArray = QNNTranslator::TranslateNodeParamArray(sName, paramArraySymbol, cmdN.numOfParams, cmdN.params);
|
|
APPEND_VECTOR(result, linesParamArray);
|
|
std::vector<std::string> linesInputArray = QNNTranslator::TranslateNodeInputArray(inputArraySymbol, cmdN.numOfInputs, cmdN.inputTensors);
|
|
APPEND_VECTOR(result, linesInputArray);
|
|
std::vector<std::string> linesOutputArray = QNNTranslator::TranslateNodeOutputArray(outputArraySymbol, cmdN.numOfOutputs, cmdN.outputTensors);
|
|
APPEND_VECTOR(result, linesOutputArray);
|
|
result.push_back(" VALIDATE(" + QNNTranslator::GraphNameSymbol + ".addNode(QNN_OPCONFIG_VERSION_1, \"" + sName + "\", \"" + std::string(cmdN.packageName) + "\", \"" + std::string(cmdN.typeName) + "\",");
|
|
result.push_back(" " + paramArraySymbol + ", " + std::to_string(cmdN.numOfParams) + ",");
|
|
result.push_back(" " + inputArraySymbol + ", " + std::to_string(cmdN.numOfInputs) + ",");
|
|
result.push_back(" " + outputArraySymbol + ", " + std::to_string(cmdN.numOfOutputs) + "),");
|
|
result.push_back(" err);");
|
|
|
|
result.push_back("");
|
|
|
|
return result;
|
|
}
|
|
|
|
std::vector<std::string> QNNTranslator::TranslateEnd() {
|
|
std::vector<std::string> result;
|
|
|
|
result.push_back(" // Add all models to array to get graphsInfo");
|
|
result.push_back(" QnnModel* models[] = {&" + GraphNameSymbol + "};");
|
|
result.push_back(" uint32_t numModels = 1;");
|
|
result.push_back("");
|
|
result.push_back(" // Populate the constructed graphs in provided output variables");
|
|
result.push_back(" VALIDATE(getGraphInfoFromModels(*models, numModels, graphsInfo), err);");
|
|
result.push_back(" *numGraphsInfo = numModels;");
|
|
result.push_back("");
|
|
result.push_back(" return err;");
|
|
result.push_back("");
|
|
result.push_back("} // PREPARE_GRAPHS");
|
|
result.push_back("");
|
|
result.push_back("QNN_API");
|
|
result.push_back("ModelError_t QnnModel_freeGraphsInfo(GraphInfoPtr_t** graphs, uint32_t numGraphsInfo) {");
|
|
result.push_back(" return qnn_wrapper_api::freeGraphsInfo(graphs, numGraphsInfo);");
|
|
result.push_back("} // FREEGRAPHINFO");
|
|
result.push_back("}");
|
|
|
|
return result;
|
|
}
|
|
|
|
std::string QNNTranslator::MapTensorType(Qnn_Convertor_Tensor_t type) {
|
|
switch (type) {
|
|
case TENSOR_INPUT: return "QNN_TENSOR_TYPE_APP_WRITE";
|
|
case TENSOR_STATIC: return "QNN_TENSOR_TYPE_STATIC";
|
|
case TENSOR_PARAM: return "QNN_TENSOR_TYPE_STATIC";
|
|
case TENSOR_NATIVE: return "QNN_TENSOR_TYPE_NATIVE";
|
|
case TENSOR_OUTPUT: return "QNN_TENSOR_TYPE_APP_READ";
|
|
default: return "UNKNOWN_QNN_TENSOR_TYPE_T";
|
|
}
|
|
}
|
|
|
|
std::string QNNTranslator::MapDataType(Qnn_DataType_t dataType) {
|
|
switch (dataType) {
|
|
case QNN_DATATYPE_INT_8: return "QNN_DATATYPE_INT_8";
|
|
case QNN_DATATYPE_INT_16: return "QNN_DATATYPE_INT_16";
|
|
case QNN_DATATYPE_INT_32: return "QNN_DATATYPE_INT_32";
|
|
case QNN_DATATYPE_INT_64: return "QNN_DATATYPE_INT_64";
|
|
case QNN_DATATYPE_UINT_8: return "QNN_DATATYPE_UINT_8";
|
|
case QNN_DATATYPE_UINT_16: return "QNN_DATATYPE_UINT_16";
|
|
case QNN_DATATYPE_UINT_32: return "QNN_DATATYPE_UINT_32";
|
|
case QNN_DATATYPE_UINT_64: return "QNN_DATATYPE_UINT_64";
|
|
case QNN_DATATYPE_FLOAT_16: return "QNN_DATATYPE_FLOAT_16";
|
|
case QNN_DATATYPE_FLOAT_32: return "QNN_DATATYPE_FLOAT_32";
|
|
case QNN_DATATYPE_FLOAT_64: return "QNN_DATATYPE_FLOAT_64";
|
|
case QNN_DATATYPE_SFIXED_POINT_4: return "QNN_DATATYPE_SFIXED_POINT_4";
|
|
case QNN_DATATYPE_SFIXED_POINT_8: return "QNN_DATATYPE_SFIXED_POINT_8";
|
|
case QNN_DATATYPE_SFIXED_POINT_16: return "QNN_DATATYPE_SFIXED_POINT_16";
|
|
case QNN_DATATYPE_SFIXED_POINT_32: return "QNN_DATATYPE_SFIXED_POINT_32";
|
|
case QNN_DATATYPE_UFIXED_POINT_4: return "QNN_DATATYPE_UFIXED_POINT_4";
|
|
case QNN_DATATYPE_UFIXED_POINT_8: return "QNN_DATATYPE_UFIXED_POINT_8";
|
|
case QNN_DATATYPE_UFIXED_POINT_16: return "QNN_DATATYPE_UFIXED_POINT_16";
|
|
case QNN_DATATYPE_UFIXED_POINT_32: return "QNN_DATATYPE_UFIXED_POINT_32";
|
|
case QNN_DATATYPE_BOOL_8: return "QNN_DATATYPE_BOOL_8";
|
|
case QNN_DATATYPE_STRING: return "QNN_DATATYPE_STRING";
|
|
case QNN_DATATYPE_UNDEFINED: return "QNN_DATATYPE_UNDEFINED";
|
|
default:
|
|
MNN_ERROR("MNN_QNN: Unknown data type.\n");
|
|
return "";
|
|
}
|
|
}
|
|
|
|
std::string QNNTranslator::TranslateDimensionsArray(const std::string & dimensionsNameSymbol, uint32_t rank, const uint32_t * dimensions) {
|
|
std::string result = " uint32_t ";
|
|
result += dimensionsNameSymbol;
|
|
result += "[] = {";
|
|
for (uint32_t i = 0; i < rank; ++i) {
|
|
result += std::to_string(dimensions[i]);
|
|
if (i + 1 < rank) {
|
|
result += ", ";
|
|
}
|
|
}
|
|
result += "};";
|
|
return result;
|
|
}
|
|
|
|
std::string QNNTranslator::TranslateParamDataArray(const std::string & dataNameSymbol, Qnn_DataType_t dataType, const Qnn_ClientBuffer_t & clientBuf) {
|
|
std::string result = " ";
|
|
|
|
std::string dataTypeSymbol;
|
|
switch (dataType) {
|
|
case QNN_DATATYPE_UINT_32:
|
|
dataTypeSymbol = "uint32_t";
|
|
break;
|
|
case QNN_DATATYPE_INT_32:
|
|
dataTypeSymbol = "int";
|
|
break;
|
|
default:
|
|
MNN_ERROR("MNN_QNN: Unknown data type for param tensor.\n");
|
|
return "";
|
|
}
|
|
result += dataTypeSymbol;
|
|
|
|
result += " ";
|
|
result += dataNameSymbol;
|
|
result += "[] = {";
|
|
|
|
switch (dataType) {
|
|
case QNN_DATATYPE_UINT_32: {
|
|
const uint32_t * source = (const uint32_t *)clientBuf.data;
|
|
uint32_t numEle = clientBuf.dataSize / sizeof(uint32_t);
|
|
for (uint32_t i = 0; i < numEle; i++) {
|
|
result += std::to_string(source[i]);
|
|
if (i < numEle - 1) {
|
|
result += ", ";
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case QNN_DATATYPE_INT_32: {
|
|
const int * source = (const int *)clientBuf.data;
|
|
uint32_t numEle = clientBuf.dataSize / sizeof(int);
|
|
for (uint32_t i = 0; i < numEle; i++) {
|
|
result += std::to_string(source[i]);
|
|
if (i < numEle - 1) {
|
|
result += ", ";
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
MNN_ERROR("MNN_QNN: Unknown data type for param tensor.\n");
|
|
return "";
|
|
}
|
|
|
|
result += "};";
|
|
|
|
return result;
|
|
}
|
|
|
|
std::vector<std::string> QNNTranslator::TranslateQuantizeScaleOffsetDataArray(const std::string & tensorNameSymbol, const Qnn_QuantizeParams_t & quantizeParams, uint32_t rank, const uint32_t * dimensions){
|
|
std::vector<std::string> result;
|
|
if(quantizeParams.encodingDefinition == QNN_DEFINITION_DEFINED && quantizeParams.quantizationEncoding == QNN_QUANTIZATION_ENCODING_AXIS_SCALE_OFFSET){
|
|
result.push_back(" Qnn_ScaleOffset_t " + tensorNameSymbol + "_axis_scale_offset[] = {");
|
|
int totalnum = (quantizeParams.axisScaleOffsetEncoding.numScaleOffsets + 3) / 4;
|
|
for(int i = 0; i < totalnum; ++i){
|
|
std::string line = " ";
|
|
for(int j = 0; j < 4; ++j){
|
|
int index = i * 4 + j;
|
|
if(index >= quantizeParams.axisScaleOffsetEncoding.numScaleOffsets)
|
|
break;
|
|
line += "{.scale= " + std::to_string(quantizeParams.axisScaleOffsetEncoding.scaleOffset[index].scale) + ", .offset= " + std::to_string(quantizeParams.axisScaleOffsetEncoding.scaleOffset[index].offset) + "}, ";
|
|
}
|
|
result.push_back(line);
|
|
}
|
|
result.push_back(" };");
|
|
}
|
|
|
|
if(quantizeParams.encodingDefinition == QNN_DEFINITION_DEFINED && quantizeParams.quantizationEncoding == QNN_QUANTIZATION_ENCODING_BW_AXIS_SCALE_OFFSET){
|
|
result.push_back(" float " + tensorNameSymbol + "_bwaxis_scale[] = {");
|
|
int totalnum = (quantizeParams.bwAxisScaleOffsetEncoding.numElements + 3) / 4;
|
|
for(int i = 0; i < totalnum; ++i){
|
|
std::string line = " ";
|
|
for(int j = 0; j < 4; ++j){
|
|
int index = i * 4 + j;
|
|
if(index >= quantizeParams.bwAxisScaleOffsetEncoding.numElements)
|
|
break;
|
|
line += std::to_string(quantizeParams.bwAxisScaleOffsetEncoding.scales[index]) + ", ";
|
|
}
|
|
result.push_back(line);
|
|
}
|
|
result.push_back(" };");
|
|
if(quantizeParams.bwAxisScaleOffsetEncoding.offsets != nullptr){
|
|
result.push_back(" int32_t " + tensorNameSymbol + "_bwaxis_offset[] = {");
|
|
for(int i = 0; i < totalnum; ++i){
|
|
std::string line = " ";
|
|
for(int j = 0; j < 4; ++j){
|
|
int index = i * 4 + j;
|
|
if(index >= quantizeParams.bwAxisScaleOffsetEncoding.numElements)
|
|
break;
|
|
line += std::to_string(quantizeParams.bwAxisScaleOffsetEncoding.offsets[index]) + ", ";
|
|
}
|
|
result.push_back(line);
|
|
}
|
|
result.push_back(" };");
|
|
}
|
|
}
|
|
|
|
if(quantizeParams.encodingDefinition == QNN_DEFINITION_DEFINED && quantizeParams.quantizationEncoding == QNN_QUANTIZATION_ENCODING_BLOCKWISE_EXPANSION){
|
|
int axis = quantizeParams.blockwiseExpansion->axis;
|
|
int oc = dimensions[axis];
|
|
int blockSize = quantizeParams.blockwiseExpansion->numBlocksPerAxis;
|
|
result.push_back(" Qnn_BlockwiseExpansion_t " + tensorNameSymbol + "_blockwiseExpansion = QNN_BLOCKWISE_EXPANSION_INIT;");
|
|
|
|
result.push_back(" Qnn_ScaleOffset_t " + tensorNameSymbol + "_blockwiseExpansionScaleOffset[] = {");
|
|
int totalnum = (oc + 3) / 4;
|
|
for(int i = 0; i < totalnum; ++i){
|
|
std::string line = " ";
|
|
for(int j = 0; j < 4; ++j){
|
|
int index = i * 4 + j;
|
|
if(index >= oc)
|
|
break;
|
|
line += "{.scale= " + std::to_string(quantizeParams.blockwiseExpansion->scaleOffsets[index].scale) + ", .offset= " + std::to_string(quantizeParams.blockwiseExpansion->scaleOffsets[index].offset) + "}, ";
|
|
}
|
|
result.push_back(line);
|
|
}
|
|
result.push_back(" };");
|
|
if(quantizeParams.blockwiseExpansion->blockScaleStorageType == QNN_BLOCKWISE_EXPANSION_BITWIDTH_SCALE_STORAGE_8){
|
|
result.push_back(" uint8_t " + tensorNameSymbol + "_blockwiseExpansionBlockScale[] = {");
|
|
totalnum = (oc * blockSize + 3) / 4;
|
|
for(int i = 0; i < totalnum; ++i){
|
|
std::string line = " ";
|
|
for(int j = 0; j < 4; ++j){
|
|
int index = i * 4 + j;
|
|
if(index >= oc * blockSize)
|
|
break;
|
|
line += std::to_string(quantizeParams.blockwiseExpansion->blocksScale8[index]) + ", ";
|
|
}
|
|
result.push_back(line);
|
|
}
|
|
result.push_back(" };");
|
|
}else{
|
|
result.push_back(" uint16_t " + tensorNameSymbol + "_blockwiseExpansionBlockScale[] = {");
|
|
totalnum = (oc * blockSize + 3) / 4;
|
|
for(int i = 0; i < totalnum; ++i){
|
|
std::string line = " ";
|
|
for(int j = 0; j < 4; ++j){
|
|
int index = i * 4 + j;
|
|
if(index >= oc * blockSize)
|
|
break;
|
|
line += std::to_string(quantizeParams.blockwiseExpansion->blocksScale16[index]) + ", ";
|
|
}
|
|
result.push_back(line);
|
|
}
|
|
result.push_back(" };");
|
|
}
|
|
result.push_back(" " + tensorNameSymbol + "_blockwiseExpansion.axis = " + std::to_string(quantizeParams.blockwiseExpansion->axis) + ";");
|
|
result.push_back(" " + tensorNameSymbol + "_blockwiseExpansion.scaleOffsets = " + tensorNameSymbol + "_blockwiseExpansionScaleOffset;");
|
|
result.push_back(" " + tensorNameSymbol + "_blockwiseExpansion.numBlocksPerAxis = " + std::to_string(quantizeParams.blockwiseExpansion->numBlocksPerAxis) + ";");
|
|
result.push_back(" " + tensorNameSymbol + "_blockwiseExpansion.blockScaleBitwidth = " + std::to_string(quantizeParams.blockwiseExpansion->blockScaleBitwidth) + ";");
|
|
if(quantizeParams.blockwiseExpansion->blockScaleStorageType == QNN_BLOCKWISE_EXPANSION_BITWIDTH_SCALE_STORAGE_8){
|
|
result.push_back(" " + tensorNameSymbol + "_blockwiseExpansion.blockScaleStorageType = QNN_BLOCKWISE_EXPANSION_BITWIDTH_SCALE_STORAGE_8;");
|
|
result.push_back(" " + tensorNameSymbol + "_blockwiseExpansion.blocksScale8 = " + tensorNameSymbol + "_blockwiseExpansionBlockScale;");
|
|
}else{
|
|
result.push_back(" " + tensorNameSymbol + "_blockwiseExpansion.blockScaleStorageType = QNN_BLOCKWISE_EXPANSION_BITWIDTH_SCALE_STORAGE_16;");
|
|
result.push_back(" " + tensorNameSymbol + "_blockwiseExpansion.blocksScale16 = " + tensorNameSymbol + "_blockwiseExpansionBlockScale;");
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// Currently, only support QNN_QUANTIZATION_ENCODING_UNDEFINED, QNN_QUANTIZATION_ENCODING_SCALE_OFFSET.
|
|
std::vector<std::string> QNNTranslator::TranslateTensorQuantizeParams(const std::string tensorNameSymbol, const Qnn_QuantizeParams_t & quantizeParams) {
|
|
std::vector<std::string> result;
|
|
|
|
if (quantizeParams.encodingDefinition == QNN_DEFINITION_UNDEFINED) {
|
|
result.push_back(" " + tensorNameSymbol + ".v1.quantizeParams.encodingDefinition = QNN_DEFINITION_UNDEFINED;");
|
|
result.push_back(" " + tensorNameSymbol + ".v1.quantizeParams.quantizationEncoding = QNN_QUANTIZATION_ENCODING_UNDEFINED;");
|
|
result.push_back(" " + tensorNameSymbol + ".v1.quantizeParams.scaleOffsetEncoding.scale = 0.0f;");
|
|
result.push_back(" " + tensorNameSymbol + ".v1.quantizeParams.scaleOffsetEncoding.offset = 0;");
|
|
return result;
|
|
}
|
|
|
|
if (quantizeParams.encodingDefinition == QNN_DEFINITION_DEFINED && quantizeParams.quantizationEncoding == QNN_QUANTIZATION_ENCODING_SCALE_OFFSET) {
|
|
result.push_back(" " + tensorNameSymbol + ".v1.quantizeParams.encodingDefinition = QNN_DEFINITION_DEFINED;");
|
|
result.push_back(" " + tensorNameSymbol + ".v1.quantizeParams.quantizationEncoding = QNN_QUANTIZATION_ENCODING_SCALE_OFFSET;");
|
|
result.push_back(" " + tensorNameSymbol + ".v1.quantizeParams.scaleOffsetEncoding.scale = " + std::to_string(quantizeParams.scaleOffsetEncoding.scale) + ";");
|
|
result.push_back(" " + tensorNameSymbol + ".v1.quantizeParams.scaleOffsetEncoding.offset = " + std::to_string(quantizeParams.scaleOffsetEncoding.offset) + ";");
|
|
return result;
|
|
}
|
|
|
|
if(quantizeParams.encodingDefinition == QNN_DEFINITION_DEFINED && quantizeParams.quantizationEncoding == QNN_QUANTIZATION_ENCODING_AXIS_SCALE_OFFSET){
|
|
result.push_back(" " + tensorNameSymbol + ".v1.quantizeParams.encodingDefinition = QNN_DEFINITION_DEFINED;");
|
|
result.push_back(" " + tensorNameSymbol + ".v1.quantizeParams.quantizationEncoding = QNN_QUANTIZATION_ENCODING_AXIS_SCALE_OFFSET;");
|
|
result.push_back(" " + tensorNameSymbol + ".v1.quantizeParams.axisScaleOffsetEncoding.axis = " + std::to_string(quantizeParams.axisScaleOffsetEncoding.axis) + ";");
|
|
result.push_back(" " + tensorNameSymbol + ".v1.quantizeParams.axisScaleOffsetEncoding.numScaleOffsets = " + std::to_string(quantizeParams.axisScaleOffsetEncoding.numScaleOffsets) + ";");
|
|
result.push_back(" " + tensorNameSymbol + ".v1.quantizeParams.axisScaleOffsetEncoding.scaleOffset = " + tensorNameSymbol + "_axis_scale_offset;");
|
|
return result;
|
|
}
|
|
|
|
if(quantizeParams.encodingDefinition == QNN_DEFINITION_DEFINED && quantizeParams.quantizationEncoding == QNN_QUANTIZATION_ENCODING_BW_AXIS_SCALE_OFFSET){
|
|
result.push_back(" " + tensorNameSymbol + ".v1.quantizeParams.encodingDefinition = QNN_DEFINITION_DEFINED;");
|
|
result.push_back(" " + tensorNameSymbol + ".v1.quantizeParams.quantizationEncoding = QNN_QUANTIZATION_ENCODING_BW_AXIS_SCALE_OFFSET;");
|
|
result.push_back(" " + tensorNameSymbol + ".v1.quantizeParams.bwAxisScaleOffsetEncoding.axis = " + std::to_string(quantizeParams.bwAxisScaleOffsetEncoding.axis) + ";");
|
|
result.push_back(" " + tensorNameSymbol + ".v1.quantizeParams.bwAxisScaleOffsetEncoding.bitwidth = " + std::to_string(quantizeParams.bwAxisScaleOffsetEncoding.bitwidth) + ";");
|
|
result.push_back(" " + tensorNameSymbol + ".v1.quantizeParams.bwAxisScaleOffsetEncoding.numElements = " + std::to_string(quantizeParams.bwAxisScaleOffsetEncoding.numElements) + ";");
|
|
result.push_back(" " + tensorNameSymbol + ".v1.quantizeParams.bwAxisScaleOffsetEncoding.scales = " + tensorNameSymbol + "_bwaxis_scale;");
|
|
if(quantizeParams.bwAxisScaleOffsetEncoding.offsets != nullptr)
|
|
result.push_back(" " + tensorNameSymbol + ".v1.quantizeParams.bwAxisScaleOffsetEncoding.offset = " + tensorNameSymbol + "_bwaxis_offset;");
|
|
return result;
|
|
}
|
|
|
|
if(quantizeParams.encodingDefinition == QNN_DEFINITION_DEFINED && quantizeParams.quantizationEncoding == QNN_QUANTIZATION_ENCODING_BLOCKWISE_EXPANSION){
|
|
result.push_back(" " + tensorNameSymbol + ".v1.quantizeParams.encodingDefinition = QNN_DEFINITION_DEFINED;");
|
|
result.push_back(" " + tensorNameSymbol + ".v1.quantizeParams.quantizationEncoding = QNN_QUANTIZATION_ENCODING_BLOCKWISE_EXPANSION;");
|
|
result.push_back(" " + tensorNameSymbol + ".v1.quantizeParams.blockwiseExpansion = &" + tensorNameSymbol + "_blockwiseExpansion;");
|
|
return result;
|
|
}
|
|
|
|
|
|
MNN_ERROR("MNN_QNN: Unknown QuantizeParams.\n");
|
|
|
|
return result;
|
|
}
|
|
|
|
std::vector<std::string> QNNTranslator::TranslateTensorClientBuf(const std::string & tensorNameSymbol, const std::string & dataNameSymbol, const std::string & sname, const Qnn_ClientBuffer_t & clientBuf, bool hasClientBuf, bool isParam) {
|
|
std::vector<std::string> result;
|
|
|
|
if (!hasClientBuf) {
|
|
result.push_back(" " + tensorNameSymbol + ".v1.clientBuf.data = nullptr;");
|
|
result.push_back(" " + tensorNameSymbol + ".v1.clientBuf.dataSize = 0;");
|
|
return result;
|
|
}
|
|
|
|
if (isParam) {
|
|
result.push_back(" " + tensorNameSymbol + ".v1.clientBuf.data = " + dataNameSymbol + ";");
|
|
result.push_back(" " + tensorNameSymbol + ".v1.clientBuf.dataSize = " + std::to_string(clientBuf.dataSize) + ";");
|
|
return result;
|
|
}
|
|
|
|
if (hasClientBuf && (!isParam)) {
|
|
result.push_back(" " + tensorNameSymbol + ".v1.clientBuf.data = BINVARSTART(" + sname + ");");
|
|
result.push_back(" " + tensorNameSymbol + ".v1.clientBuf.dataSize = BINLEN(" + sname + ");");
|
|
return result;
|
|
}
|
|
|
|
MNN_ERROR("MNN_QNN: Illegal ClientBuf setting.\n");
|
|
|
|
return result;
|
|
}
|
|
|
|
std::vector<std::string> QNNTranslator::TranslateNodeParamArray(const std::string & nodeName, const std::string & paramArraySymbol, uint32_t numOfParams, const Qnn_Param_t * params) {
|
|
std::vector<std::string> result;
|
|
|
|
for (uint32_t i = 0; i < numOfParams; i++) {
|
|
Qnn_Param_t param = params[i];
|
|
std::string paramNameSymbol = PARAM_NAME_SYMBOL(param.name);
|
|
result.push_back(" Qnn_Param_t " + paramNameSymbol + " = QNN_PARAM_INIT;");
|
|
result.push_back(" {");
|
|
if (param.paramType == QNN_PARAMTYPE_SCALAR) {
|
|
result.push_back(" " + paramNameSymbol + ".paramType = QNN_PARAMTYPE_SCALAR;");
|
|
result.push_back(" " + paramNameSymbol + ".name = \"" + std::string(param.name) + "\";");
|
|
result.push_back(" " + paramNameSymbol + ".scalarParam.dataType = " + MapDataType(param.scalarParam.dataType) + ";");
|
|
switch (param.scalarParam.dataType) {
|
|
case QNN_DATATYPE_BOOL_8:
|
|
result.push_back(" " + paramNameSymbol + ".scalarParam.bool8Value = " + std::to_string(param.scalarParam.bool8Value) + ";");
|
|
break;
|
|
case QNN_DATATYPE_UINT_32:
|
|
result.push_back(" " + paramNameSymbol + ".scalarParam.uint32Value = " + std::to_string(param.scalarParam.uint32Value) + ";");
|
|
break;
|
|
case QNN_DATATYPE_INT_32:
|
|
result.push_back(" " + paramNameSymbol + ".scalarParam.int32Value = " + std::to_string(param.scalarParam.int32Value) + ";");
|
|
break;
|
|
case QNN_DATATYPE_FLOAT_32:
|
|
result.push_back(" " + paramNameSymbol + ".scalarParam.floatValue = " + std::to_string(param.scalarParam.floatValue) + ";");
|
|
break;
|
|
default:
|
|
MNN_ERROR("MNN_QNN: Unkown dataType.\n");
|
|
return {};
|
|
}
|
|
} else {
|
|
result.push_back(" " + paramNameSymbol + ".paramType = QNN_PARAMTYPE_TENSOR;");
|
|
result.push_back(" " + paramNameSymbol + ".name = \"" + std::string(param.name) + "\";");
|
|
result.push_back(" " + paramNameSymbol + ".tensorParam = " + TENSOR_NAME_SYMBOL(param.tensorParam.v1.name) + ";");
|
|
}
|
|
result.push_back(" }");
|
|
}
|
|
|
|
std::string str = " Qnn_Param_t " + paramArraySymbol + "[] = {";
|
|
for (uint32_t i = 0; i < numOfParams; i++) {
|
|
str += PARAM_NAME_SYMBOL(params[i].name);
|
|
if (i < numOfParams - 1) {
|
|
str += ", ";
|
|
}
|
|
}
|
|
str += "};";
|
|
result.push_back(str);
|
|
|
|
return result;
|
|
}
|
|
|
|
std::vector<std::string> QNNTranslator::TranslateNodeInputArray(const std::string & inputArraySymbol, uint32_t numOfInputs, const Qnn_Tensor_t * inputs) {
|
|
std::vector<std::string> result;
|
|
|
|
std::string str = " const char * " + inputArraySymbol + "[] = {";
|
|
for (uint32_t i = 0; i < numOfInputs; i++) {
|
|
str += "\"";
|
|
str += std::string(inputs[i].v1.name);
|
|
str += "\"";
|
|
if (i < numOfInputs - 1) {
|
|
str += ", ";
|
|
}
|
|
}
|
|
str += "};";
|
|
|
|
result.push_back(str);
|
|
|
|
return result;
|
|
}
|
|
|
|
std::vector<std::string> QNNTranslator::TranslateNodeOutputArray(const std::string & outputArraySymbol, uint32_t numOfOutputs, const Qnn_Tensor_t * outputs) {
|
|
std::vector<std::string> result;
|
|
|
|
std::string str = " Qnn_Tensor_t " + outputArraySymbol + "[] = {";
|
|
for (uint32_t i = 0; i < numOfOutputs; i++) {
|
|
str += TENSOR_NAME_SYMBOL(outputs[i].v1.name);
|
|
if (i < numOfOutputs - 1) {
|
|
str +=", ";
|
|
}
|
|
}
|
|
str += "};";
|
|
|
|
result.push_back(str);
|
|
|
|
return result;
|
|
}
|
|
#endif
|
|
} // end namespace MNN
|
|
} // end namespace QNN
|