diff --git a/source/backend/qnn/backend/QNNBackend.cpp b/source/backend/qnn/backend/QNNBackend.cpp index 7dcae6d583..d41997535e 100644 --- a/source/backend/qnn/backend/QNNBackend.cpp +++ b/source/backend/qnn/backend/QNNBackend.cpp @@ -2432,9 +2432,19 @@ class QnnRuntimeCreator : public RuntimeCreator { } if (op->main_as_Convolution2D() && op->main_as_Convolution2D()->weight() != nullptr) { return false; - } else { - return true; } + // Guard against promoting a Conv that carries no quantized weight + // data (e.g. a Conv listed in skip_quant_op_names but still + // surrounded by int8 tensors): the QNN Conv execution would later + // dereference a missing weight and crash. + { + auto conv2d = op->main_as_Convolution2D(); + if (conv2d->quanParameter() == nullptr && + (conv2d->symmetricQuan() == nullptr || conv2d->symmetricQuan()->weight() == nullptr)) { + return false; + } + } + return true; case OpType_ReLU: if ((op->main_as_Relu() == nullptr) || op->main_as_Relu()->slope() == 0.f) { return true; diff --git a/source/backend/qnn/execution/QNNConvDepthwise.cpp b/source/backend/qnn/execution/QNNConvDepthwise.cpp index 45124a3d7b..7839c4c2a3 100644 --- a/source/backend/qnn/execution/QNNConvDepthwise.cpp +++ b/source/backend/qnn/execution/QNNConvDepthwise.cpp @@ -29,7 +29,7 @@ void QNNConvDepthwise::isWeightQuantSupported(const Tensor *input, const int oc) } std::shared_ptr quanCommon = ConvolutionCommon::load(mOp, this->backend(), false, true); - if(quanCommon->asymmetric || dataType == QNN_DATATYPE_FLOAT_16 || dataType == QNN_DATATYPE_FLOAT_32){ + if (nullptr == quanCommon || quanCommon->asymmetric || dataType == QNN_DATATYPE_FLOAT_16 || dataType == QNN_DATATYPE_FLOAT_32) { // not support asymmetric and mBlockSize > 1 results incorrect now mWeightQuant = false; return; @@ -194,7 +194,9 @@ ErrorCode QNNConvDepthwise::onEncode(const std::vector &inputs, const this->createParamTensor("pad_amount", QNN_DATATYPE_UINT_32, {2, 2}, (void *)padAmountData.data()); this->createParamTensor("dilation", QNN_DATATYPE_UINT_32, {2}, (void *)dilationData.data()); - this->createWeightAndBias(dataType, inputs[0], oc, kernelH, kernelW); + if (!this->createWeightAndBias(dataType, inputs[0], oc, kernelH, kernelW)) { + return NOT_SUPPORT; + } // dequant input and quant output if(mWeightQuant == false && dataType != QNN_DATATYPE_FLOAT_16 && dataType != QNN_DATATYPE_FLOAT_32){ return this->onEncodeQuantDequantDepthConv(inputs[0], outputs[0], n, ic, oc); @@ -261,6 +263,11 @@ void QNNConvDepthwise::createWeightAndBias(Qnn_DataType_t dataType, const Tensor if(mWeightQuant){ Qnn_QuantizeParams_t weightQuantize{}; std::shared_ptr quanCommon = ConvolutionCommon::load(mOp, this->backend(), false, true); + if (nullptr == quanCommon) { + MNN_ERROR("QNNConvDepthwise: op '%s' has no quantized weight data\n", + mOp->name() ? mOp->name()->c_str() : "unknown"); + return; + } // [TODO] Support asymmetric and other quantBits. MNN_ASSERT(!quanCommon->asymmetric); @@ -376,6 +383,11 @@ void QNNConvDepthwise::createWeightAndBias(Qnn_DataType_t dataType, const Tensor int weightElementNum = 0; std::shared_ptr quanWeight; ConvolutionCommon::getConvParameters(&quanWeight, mBackend, mOp, &source, &weightElementNum); + if (nullptr == source || weightElementNum <= 0) { + MNN_ERROR("QNNConvDepthwise: op '%s' has no weight data\n", + mOp->name() ? mOp->name()->c_str() : "unknown"); + return; + } // oc ic h w ---> h w ic oc weightData.resize(weightElementNum); convertWeight(source, (float *) weightData.data(), oc, kernelH, kernelW); diff --git a/source/backend/qnn/execution/QNNConvolution.cpp b/source/backend/qnn/execution/QNNConvolution.cpp index ae3ca145ab..a65b490037 100644 --- a/source/backend/qnn/execution/QNNConvolution.cpp +++ b/source/backend/qnn/execution/QNNConvolution.cpp @@ -41,6 +41,10 @@ void QNNConvolution::isWeightQuantSupported(const Tensor *input, const int ic, c } std::shared_ptr quanCommon = ConvolutionCommon::load(mOp, this->backend(), false, true); + if (nullptr == quanCommon) { + mWeightQuant = false; + return; + } int totalCount = quanCommon->alpha.size(); mBlockSize = totalCount / oc; if(quanCommon->asymmetric){ @@ -118,7 +122,9 @@ ErrorCode QNNConvolution::onEncode(const std::vector &inputs, const st this->createParamScalar("group", (uint32_t)group); } - this->createWeightAndBias(dataType, inputs[0], oc, ic, kernelH, kernelW, group); + if (!this->createWeightAndBias(dataType, inputs[0], oc, ic, kernelH, kernelW, group)) { + return NOT_SUPPORT; + } // dequant input and quant output if(mWeightQuant == false && dataType != QNN_DATATYPE_FLOAT_16 && dataType != QNN_DATATYPE_FLOAT_32){ return this->onEncodeQuantDequantConv(inputs[0], outputs[0], n, ic, oc); @@ -562,6 +568,11 @@ bool QNNConvolution::createWeightAndBias(Qnn_DataType_t dataType, const Tensor * if(mWeightQuant){ Qnn_QuantizeParams_t weightQuantize{}; std::shared_ptr quanCommon = ConvolutionCommon::load(mOp, this->backend(), false, true); + if (nullptr == quanCommon) { + MNN_ERROR("QNNConvolution: op '%s' has no quantized weight data\n", + mOp->name() ? mOp->name()->c_str() : "unknown"); + return false; + } if(quanCommon->asymmetric) { MNN_ERROR("[Error]: Qnn weight quant only support symmetric currently\n"); return false; @@ -676,6 +687,11 @@ bool QNNConvolution::createWeightAndBias(Qnn_DataType_t dataType, const Tensor * int weightElementNum = 0; std::shared_ptr quanWeight; ConvolutionCommon::getConvParameters(&quanWeight, mBackend, mOp, &source, &weightElementNum); + if (nullptr == source || weightElementNum <= 0) { + MNN_ERROR("QNNConvolution: op '%s' has no weight data\n", + mOp->name() ? mOp->name()->c_str() : "unknown"); + return false; + } // oc ic h w ---> h w ic oc weightData.resize(weightElementNum); convertWeight(source, (float *) weightData.data(), oc, ic/group, kernelH, kernelW);