diff --git a/common/Shaper.cpp b/common/Shaper.cpp index 43eda00..5b64c53 100644 --- a/common/Shaper.cpp +++ b/common/Shaper.cpp @@ -243,8 +243,9 @@ void Shaper::Eltwise(const std::string &input1_name, const std::string &output_name) { auto shape1 = shape_map_.at(input1_name); auto shape2 = shape_map_.at(input2_name); + // TODO: broadcasting auto output_shape = - shape1.size() > shape2.size() ? shape1 : shape2; // broadcasting + shape1.size() >= shape2.size() ? shape1 : shape2; shape_map_[output_name] = output_shape; } diff --git a/generate_code.py b/generate_code.py index f28adb9..d19587e 100644 --- a/generate_code.py +++ b/generate_code.py @@ -98,14 +98,14 @@ def infer_cfg(cfg, target: Target): op['input'] = [] if 'base_input_num' not in op or op['base_input_num'] == 1: op['input'].insert(0, - {'name': 'input', 'nnapi_type': 'tensor', 'cpp_type': 'str', 'needed_by_shaper': True}) + {'name': 'input', 'nnapi_type': 'tensor', 'cpp_type': 'str', 'input': True, 'needed_by_shaper': True}) elif op['base_input_num'] == 2: - op['input'] = [{'name': 'input1', 'nnapi_type': 'tensor', 'cpp_type': 'str', 'needed_by_shaper': True}, - {'name': 'input2', 'nnapi_type': 'tensor', 'cpp_type': 'str', 'needed_by_shaper': True}] \ + op['input'] = [{'name': 'input1', 'nnapi_type': 'tensor', 'cpp_type': 'str', 'input': True, 'needed_by_shaper': True}, + {'name': 'input2', 'nnapi_type': 'tensor', 'cpp_type': 'str', 'input': True, 'needed_by_shaper': True}] \ + op['input'] elif op['base_input_num'] == 'n': op['input'].insert(0, - {'name': 'inputs', 'nnapi_type': 'tensor', 'cpp_type': 'str_list', + {'name': 'inputs', 'nnapi_type': 'tensor', 'cpp_type': 'str_list', 'input': True, 'needed_by_shaper': True}) elif op['base_input_num'] == 0: pass @@ -145,11 +145,12 @@ def infer_cfg(cfg, target: Target): ipt['name'] = 'bias' ipt['nnapi_type'] = 'tensor' ipt['cpp_type'] = 'optional_str' - ipt['learnable'] = True - if 'learnable' not in ipt: - ipt['learnable'] = False - if ipt['learnable'] and 'convert_func' not in ipt: + ipt['input'] = True ipt['convert_func'] = 'OnnxToNnapiIdentity' + if 'input' not in ipt: + ipt['input'] = False + if 'convert_func' not in ipt: + ipt['convert_func'] = 'OnnxToNnapiAxes0231' if 'needed_by_shaper' not in ipt: ipt['needed_by_shaper'] = False @@ -186,20 +187,28 @@ def generate_onnx_converter(): if op['fused']: cogoutl(f"const auto activation = FindActivation(model_proto_, output);") for x in op['input']: - if x['learnable']: - assert x['cpp_type'] in ['str', 'optional_str'] + if x['input']: if x['cpp_type'] == 'str': - cogoutl(f"""{{ -const auto name = {x['name']};""") + cogoutl(f""" + {{ + const auto name = {x['name']};""") elif x['cpp_type'] == 'optional_str': - cogoutl(f"""if ({x['name']}.has_value()) {{ -const auto name = {x['name']}.value();""") - cogoutl(f"""const auto &onnx_tensor = onnx_tensors_.at(name); -const auto new_tensor = {x['convert_func']}(onnx_tensor); -shaper_.AddShape(name, new_tensor.shape); -nnapi_tensors_[name] = new_tensor; -CreateTensorFb(name, new_tensor);""") - cogoutl("}") + cogoutl(f""" + if ({x['name']}.has_value()) {{ + const auto name = {x['name']}.value();""") + elif x['cpp_type'] == 'str_list': + cogoutl(f""" + for (const auto &name : {x['name']}) {{""") + cogoutl(f""" + if (onnx_tensors_.has(name)) {{ + const auto &onnx_tensor = onnx_tensors_.at(name); + const auto new_tensor = {x['convert_func']}(onnx_tensor); + shaper_.AddShape(name, new_tensor.shape); + nnapi_tensors_[name] = new_tensor; + CreateTensorFb(name, new_tensor); + }} + }} + """) if x['cpp_type'] == 'str_list': cogoutl(f"const auto {x['name']}_fb = FbStrVector({x['name']});") diff --git a/include/dnnlibrary/ModelBuilder.h b/include/dnnlibrary/ModelBuilder.h index 6b51bac..544f7bb 100644 --- a/include/dnnlibrary/ModelBuilder.h +++ b/include/dnnlibrary/ModelBuilder.h @@ -13,9 +13,9 @@ #include #include -#include #include #include +#include #include #include diff --git a/include/tools/onnx2daq/OnnxConverter.h b/include/tools/onnx2daq/OnnxConverter.h index 85d6577..1898425 100644 --- a/include/tools/onnx2daq/OnnxConverter.h +++ b/include/tools/onnx2daq/OnnxConverter.h @@ -158,16 +158,21 @@ class OnnxConverter { // OnnxConverter auto generated methods end /** + * transpose axes to [1, 2, 3, 0] + * for onnx dw conv weight to nnapi dw conv weight * onnx: [filter_out_channel, filter_in_channel / group, height, width] * nnapi: [1, height, width, depth_out] */ - Tensor OnnxToNnapiDwConvWeight(const Tensor &src); + Tensor OnnxToNnapiAxes1230(const Tensor &src); /** + * transpose axes to [0, 2, 3, 1] + * for nchw (onnx) -> nhwc (nnapi) + * or onnx conv weight to nnapi conv (not dw conv) weight: * onnx: [filter_out_channel, filter_in_channel, height, width] * nnapi: [depth_out, height, width, depth_in] */ - Tensor OnnxToNnapiVanillaConvWeight(const Tensor &src); + Tensor OnnxToNnapiAxes0231(const Tensor &src); /** * Just return the same tensor diff --git a/ops.yml b/ops.yml index b159c07..32d7cd4 100644 --- a/ops.yml +++ b/ops.yml @@ -7,9 +7,8 @@ - name: weight nnapi_type: tensor - # "learnable" stands for the tensor is read from serialized model file - learnable: true - convert_func: OnnxToNnapiVanillaConvWeight + # "input" stands for onnx input instead of attribute (TODO: a new name) + input: true cpp_type: str needed_by_shaper: true - @@ -202,9 +201,10 @@ - name: weight nnapi_type: tensor - learnable: true + input: true cpp_type: str needed_by_shaper: true + convert_func: OnnxToNnapiIdentity - predefined: optional_bias nnapi: FULLY_CONNECTED @@ -238,8 +238,8 @@ - name: weight nnapi_type: tensor - learnable: true - convert_func: OnnxToNnapiDwConvWeight + input: true + convert_func: OnnxToNnapiAxes1230 cpp_type: str needed_by_shaper: true - diff --git a/tools/onnx2daq/OnnxConverter.cpp b/tools/onnx2daq/OnnxConverter.cpp index f96d143..7208130 100644 --- a/tools/onnx2daq/OnnxConverter.cpp +++ b/tools/onnx2daq/OnnxConverter.cpp @@ -147,8 +147,7 @@ OnnxConverter::FbStrVector(const std::vector &std_str_vector) { * onnx: [filter_out_channel, filter_in_channel / group, height, width] * nnapi: [1, height, width, depth_out] */ -OnnxConverter::Tensor OnnxConverter::OnnxToNnapiDwConvWeight( - const Tensor &src) { +OnnxConverter::Tensor OnnxConverter::OnnxToNnapiAxes1230(const Tensor &src) { Tensor dest = src; size_t elemsize = 0; if (src.data_type == Tensor::DataType::UINT8) { @@ -180,8 +179,7 @@ OnnxConverter::Tensor OnnxConverter::OnnxToNnapiDwConvWeight( return dest; } -OnnxConverter::Tensor OnnxConverter::OnnxToNnapiVanillaConvWeight( - const Tensor &src) { +OnnxConverter::Tensor OnnxConverter::OnnxToNnapiAxes0231(const Tensor &src) { Tensor dest = src; size_t elemsize = 0; if (src.data_type == Tensor::DataType::UINT8) { @@ -317,22 +315,43 @@ void OnnxConverter::AddLayerConvImpl(const std::string &input, const std::vector &strides, const std::string &output) { const auto activation = FindActivation(model_proto_, output); + + { + const auto name = input; + + if (onnx_tensors_.has(name)) { + const auto &onnx_tensor = onnx_tensors_.at(name); + const auto new_tensor = OnnxToNnapiAxes0231(onnx_tensor); + shaper_.AddShape(name, new_tensor.shape); + nnapi_tensors_[name] = new_tensor; + CreateTensorFb(name, new_tensor); + } + } + { const auto name = weight; - const auto &onnx_tensor = onnx_tensors_.at(name); - const auto new_tensor = OnnxToNnapiVanillaConvWeight(onnx_tensor); - shaper_.AddShape(name, new_tensor.shape); - nnapi_tensors_[name] = new_tensor; - CreateTensorFb(name, new_tensor); + + if (onnx_tensors_.has(name)) { + const auto &onnx_tensor = onnx_tensors_.at(name); + const auto new_tensor = OnnxToNnapiAxes0231(onnx_tensor); + shaper_.AddShape(name, new_tensor.shape); + nnapi_tensors_[name] = new_tensor; + CreateTensorFb(name, new_tensor); + } } + if (bias.has_value()) { const auto name = bias.value(); - const auto &onnx_tensor = onnx_tensors_.at(name); - const auto new_tensor = OnnxToNnapiIdentity(onnx_tensor); - shaper_.AddShape(name, new_tensor.shape); - nnapi_tensors_[name] = new_tensor; - CreateTensorFb(name, new_tensor); + + if (onnx_tensors_.has(name)) { + const auto &onnx_tensor = onnx_tensors_.at(name); + const auto new_tensor = OnnxToNnapiIdentity(onnx_tensor); + shaper_.AddShape(name, new_tensor.shape); + nnapi_tensors_[name] = new_tensor; + CreateTensorFb(name, new_tensor); + } } + shaper_.Conv(m(input), m(weight), pads, strides, output); const auto param = DNN::CreateConv2DDirect( builder_, m(input).c_str(), m(weight).c_str(), @@ -348,6 +367,19 @@ void OnnxConverter::AddLayerAvePoolImpl( const std::vector &pads, const std::vector &strides, const std::string &output) { const auto activation = FindActivation(model_proto_, output); + + { + const auto name = input; + + if (onnx_tensors_.has(name)) { + const auto &onnx_tensor = onnx_tensors_.at(name); + const auto new_tensor = OnnxToNnapiAxes0231(onnx_tensor); + shaper_.AddShape(name, new_tensor.shape); + nnapi_tensors_[name] = new_tensor; + CreateTensorFb(name, new_tensor); + } + } + shaper_.Pool(m(input), kernel_shape, pads, strides, output); const auto param = DNN::CreateAvePoolDirect( builder_, m(input).c_str(), &kernel_shape, &pads, &strides, @@ -362,6 +394,19 @@ void OnnxConverter::AddLayerMaxPoolImpl( const std::vector &pads, const std::vector &strides, const std::string &output) { const auto activation = FindActivation(model_proto_, output); + + { + const auto name = input; + + if (onnx_tensors_.has(name)) { + const auto &onnx_tensor = onnx_tensors_.at(name); + const auto new_tensor = OnnxToNnapiAxes0231(onnx_tensor); + shaper_.AddShape(name, new_tensor.shape); + nnapi_tensors_[name] = new_tensor; + CreateTensorFb(name, new_tensor); + } + } + shaper_.Pool(m(input), kernel_shape, pads, strides, output); const auto param = DNN::CreateMaxPoolDirect( builder_, m(input).c_str(), &kernel_shape, &pads, &strides, @@ -373,6 +418,18 @@ void OnnxConverter::AddLayerMaxPoolImpl( void OnnxConverter::AddLayerReLU(const std::string &input, const std::string &output) { + { + const auto name = input; + + if (onnx_tensors_.has(name)) { + const auto &onnx_tensor = onnx_tensors_.at(name); + const auto new_tensor = OnnxToNnapiAxes0231(onnx_tensor); + shaper_.AddShape(name, new_tensor.shape); + nnapi_tensors_[name] = new_tensor; + CreateTensorFb(name, new_tensor); + } + } + shaper_.Relu(m(input), output); const auto param = DNN::CreateReluDirect(builder_, m(input).c_str(), output.c_str()); @@ -383,6 +440,18 @@ void OnnxConverter::AddLayerReLU(const std::string &input, void OnnxConverter::AddLayerSoftmax(const std::string &input, const std::string &output) { + { + const auto name = input; + + if (onnx_tensors_.has(name)) { + const auto &onnx_tensor = onnx_tensors_.at(name); + const auto new_tensor = OnnxToNnapiAxes0231(onnx_tensor); + shaper_.AddShape(name, new_tensor.shape); + nnapi_tensors_[name] = new_tensor; + CreateTensorFb(name, new_tensor); + } + } + shaper_.Softmax(m(input), output); const auto param = DNN::CreateSoftmaxDirect(builder_, m(input).c_str(), output.c_str()); @@ -396,22 +465,43 @@ void OnnxConverter::AddLayerFC(const std::string &input, const dnn::optional &bias, const std::string &output) { const auto activation = FindActivation(model_proto_, output); + + { + const auto name = input; + + if (onnx_tensors_.has(name)) { + const auto &onnx_tensor = onnx_tensors_.at(name); + const auto new_tensor = OnnxToNnapiAxes0231(onnx_tensor); + shaper_.AddShape(name, new_tensor.shape); + nnapi_tensors_[name] = new_tensor; + CreateTensorFb(name, new_tensor); + } + } + { const auto name = weight; - const auto &onnx_tensor = onnx_tensors_.at(name); - const auto new_tensor = OnnxToNnapiIdentity(onnx_tensor); - shaper_.AddShape(name, new_tensor.shape); - nnapi_tensors_[name] = new_tensor; - CreateTensorFb(name, new_tensor); + + if (onnx_tensors_.has(name)) { + const auto &onnx_tensor = onnx_tensors_.at(name); + const auto new_tensor = OnnxToNnapiIdentity(onnx_tensor); + shaper_.AddShape(name, new_tensor.shape); + nnapi_tensors_[name] = new_tensor; + CreateTensorFb(name, new_tensor); + } } + if (bias.has_value()) { const auto name = bias.value(); - const auto &onnx_tensor = onnx_tensors_.at(name); - const auto new_tensor = OnnxToNnapiIdentity(onnx_tensor); - shaper_.AddShape(name, new_tensor.shape); - nnapi_tensors_[name] = new_tensor; - CreateTensorFb(name, new_tensor); + + if (onnx_tensors_.has(name)) { + const auto &onnx_tensor = onnx_tensors_.at(name); + const auto new_tensor = OnnxToNnapiIdentity(onnx_tensor); + shaper_.AddShape(name, new_tensor.shape); + nnapi_tensors_[name] = new_tensor; + CreateTensorFb(name, new_tensor); + } } + shaper_.FC(m(input), m(weight), output); const auto param = DNN::CreateFCDirect( builder_, m(input).c_str(), m(weight).c_str(), @@ -426,6 +516,31 @@ void OnnxConverter::AddLayerAdd(const std::string &input1, const std::string &input2, const std::string &output) { const auto activation = FindActivation(model_proto_, output); + + { + const auto name = input1; + + if (onnx_tensors_.has(name)) { + const auto &onnx_tensor = onnx_tensors_.at(name); + const auto new_tensor = OnnxToNnapiAxes0231(onnx_tensor); + shaper_.AddShape(name, new_tensor.shape); + nnapi_tensors_[name] = new_tensor; + CreateTensorFb(name, new_tensor); + } + } + + { + const auto name = input2; + + if (onnx_tensors_.has(name)) { + const auto &onnx_tensor = onnx_tensors_.at(name); + const auto new_tensor = OnnxToNnapiAxes0231(onnx_tensor); + shaper_.AddShape(name, new_tensor.shape); + nnapi_tensors_[name] = new_tensor; + CreateTensorFb(name, new_tensor); + } + } + shaper_.Eltwise(m(input1), m(input2), output); const auto param = DNN::CreateAddDirect( builder_, m(input1).c_str(), m(input2).c_str(), @@ -437,6 +552,16 @@ void OnnxConverter::AddLayerAdd(const std::string &input1, void OnnxConverter::AddLayerConcat(const std::vector &inputs, int32_t axis, const std::string &output) { + for (const auto &name : inputs) { + if (onnx_tensors_.has(name)) { + const auto &onnx_tensor = onnx_tensors_.at(name); + const auto new_tensor = OnnxToNnapiAxes0231(onnx_tensor); + shaper_.AddShape(name, new_tensor.shape); + nnapi_tensors_[name] = new_tensor; + CreateTensorFb(name, new_tensor); + } + } + const auto inputs_fb = FbStrVector(inputs); shaper_.Concat(inputs, axis, output); const auto param = @@ -452,22 +577,43 @@ void OnnxConverter::AddLayerDepthwiseConvImpl( const std::vector &strides, int32_t depth_multiplier, const std::string &output) { const auto activation = FindActivation(model_proto_, output); + + { + const auto name = input; + + if (onnx_tensors_.has(name)) { + const auto &onnx_tensor = onnx_tensors_.at(name); + const auto new_tensor = OnnxToNnapiAxes0231(onnx_tensor); + shaper_.AddShape(name, new_tensor.shape); + nnapi_tensors_[name] = new_tensor; + CreateTensorFb(name, new_tensor); + } + } + { const auto name = weight; - const auto &onnx_tensor = onnx_tensors_.at(name); - const auto new_tensor = OnnxToNnapiDwConvWeight(onnx_tensor); - shaper_.AddShape(name, new_tensor.shape); - nnapi_tensors_[name] = new_tensor; - CreateTensorFb(name, new_tensor); + + if (onnx_tensors_.has(name)) { + const auto &onnx_tensor = onnx_tensors_.at(name); + const auto new_tensor = OnnxToNnapiAxes1230(onnx_tensor); + shaper_.AddShape(name, new_tensor.shape); + nnapi_tensors_[name] = new_tensor; + CreateTensorFb(name, new_tensor); + } } + if (bias.has_value()) { const auto name = bias.value(); - const auto &onnx_tensor = onnx_tensors_.at(name); - const auto new_tensor = OnnxToNnapiIdentity(onnx_tensor); - shaper_.AddShape(name, new_tensor.shape); - nnapi_tensors_[name] = new_tensor; - CreateTensorFb(name, new_tensor); + + if (onnx_tensors_.has(name)) { + const auto &onnx_tensor = onnx_tensors_.at(name); + const auto new_tensor = OnnxToNnapiIdentity(onnx_tensor); + shaper_.AddShape(name, new_tensor.shape); + nnapi_tensors_[name] = new_tensor; + CreateTensorFb(name, new_tensor); + } } + shaper_.DepthwiseConv(m(input), m(weight), pads, strides, output); const auto param = DNN::CreateDepthwiseConv2DDirect( builder_, m(input).c_str(), m(weight).c_str(), @@ -483,6 +629,18 @@ void OnnxConverter::AddLayerDepthwiseConvImpl( void OnnxConverter::AddLayerBatchToSpaceND( const std::string &input, const std::vector &block_sizes, const std::string &output) { + { + const auto name = input; + + if (onnx_tensors_.has(name)) { + const auto &onnx_tensor = onnx_tensors_.at(name); + const auto new_tensor = OnnxToNnapiAxes0231(onnx_tensor); + shaper_.AddShape(name, new_tensor.shape); + nnapi_tensors_[name] = new_tensor; + CreateTensorFb(name, new_tensor); + } + } + shaper_.BatchToSpace(m(input), block_sizes, output); const auto param = DNN::CreateBatchToSpaceDirect( builder_, m(input).c_str(), &block_sizes, output.c_str()); @@ -494,6 +652,18 @@ void OnnxConverter::AddLayerBatchToSpaceND( void OnnxConverter::AddLayerSpaceToBatchND( const std::string &input, const std::vector &block_sizes, const std::vector &pads, const std::string &output) { + { + const auto name = input; + + if (onnx_tensors_.has(name)) { + const auto &onnx_tensor = onnx_tensors_.at(name); + const auto new_tensor = OnnxToNnapiAxes0231(onnx_tensor); + shaper_.AddShape(name, new_tensor.shape); + nnapi_tensors_[name] = new_tensor; + CreateTensorFb(name, new_tensor); + } + } + shaper_.SpaceToBatch(m(input), block_sizes, pads, output); const auto param = DNN::CreateSpaceToBatchDirect( builder_, m(input).c_str(), &block_sizes, &pads, output.c_str()); @@ -509,6 +679,18 @@ void OnnxConverter::AddLayerStridedSlice(const std::string &input, int32_t begin_mask, int32_t end_mask, int32_t shrink_axis_mask, const std::string &output) { + { + const auto name = input; + + if (onnx_tensors_.has(name)) { + const auto &onnx_tensor = onnx_tensors_.at(name); + const auto new_tensor = OnnxToNnapiAxes0231(onnx_tensor); + shaper_.AddShape(name, new_tensor.shape); + nnapi_tensors_[name] = new_tensor; + CreateTensorFb(name, new_tensor); + } + } + shaper_.StridedSlice(m(input), starts, ends, strides, begin_mask, end_mask, shrink_axis_mask, output); const auto param = DNN::CreateStridedSliceDirect( @@ -523,6 +705,31 @@ void OnnxConverter::AddLayerMul(const std::string &input1, const std::string &input2, const std::string &output) { const auto activation = FindActivation(model_proto_, output); + + { + const auto name = input1; + + if (onnx_tensors_.has(name)) { + const auto &onnx_tensor = onnx_tensors_.at(name); + const auto new_tensor = OnnxToNnapiAxes0231(onnx_tensor); + shaper_.AddShape(name, new_tensor.shape); + nnapi_tensors_[name] = new_tensor; + CreateTensorFb(name, new_tensor); + } + } + + { + const auto name = input2; + + if (onnx_tensors_.has(name)) { + const auto &onnx_tensor = onnx_tensors_.at(name); + const auto new_tensor = OnnxToNnapiAxes0231(onnx_tensor); + shaper_.AddShape(name, new_tensor.shape); + nnapi_tensors_[name] = new_tensor; + CreateTensorFb(name, new_tensor); + } + } + shaper_.Eltwise(m(input1), m(input2), output); const auto param = DNN::CreateMulDirect( builder_, m(input1).c_str(), m(input2).c_str(), @@ -535,6 +742,19 @@ void OnnxConverter::AddLayerMul(const std::string &input1, void OnnxConverter::AddLayerAdd(const std::string &input, float scalar, const std::string &output) { const auto activation = FindActivation(model_proto_, output); + + { + const auto name = input; + + if (onnx_tensors_.has(name)) { + const auto &onnx_tensor = onnx_tensors_.at(name); + const auto new_tensor = OnnxToNnapiAxes0231(onnx_tensor); + shaper_.AddShape(name, new_tensor.shape); + nnapi_tensors_[name] = new_tensor; + CreateTensorFb(name, new_tensor); + } + } + shaper_.Eltwise(m(input), output); const auto param = DNN::CreateAddScalarDirect( builder_, m(input).c_str(), scalar, @@ -548,6 +768,19 @@ void OnnxConverter::AddLayerAdd(const std::string &input, float scalar, void OnnxConverter::AddLayerMul(const std::string &input, float scalar, const std::string &output) { const auto activation = FindActivation(model_proto_, output); + + { + const auto name = input; + + if (onnx_tensors_.has(name)) { + const auto &onnx_tensor = onnx_tensors_.at(name); + const auto new_tensor = OnnxToNnapiAxes0231(onnx_tensor); + shaper_.AddShape(name, new_tensor.shape); + nnapi_tensors_[name] = new_tensor; + CreateTensorFb(name, new_tensor); + } + } + shaper_.Eltwise(m(input), output); const auto param = DNN::CreateMulScalarDirect( builder_, m(input).c_str(), scalar, @@ -560,6 +793,18 @@ void OnnxConverter::AddLayerMul(const std::string &input, float scalar, void OnnxConverter::AddLayerDequantize(const std::string &input, const std::string &output) { + { + const auto name = input; + + if (onnx_tensors_.has(name)) { + const auto &onnx_tensor = onnx_tensors_.at(name); + const auto new_tensor = OnnxToNnapiAxes0231(onnx_tensor); + shaper_.AddShape(name, new_tensor.shape); + nnapi_tensors_[name] = new_tensor; + CreateTensorFb(name, new_tensor); + } + } + shaper_.Identity(m(input), output); const auto param = DNN::CreateDequantizeDirect(builder_, m(input).c_str(), output.c_str()); @@ -572,6 +817,18 @@ void OnnxConverter::AddLayerDequantize(const std::string &input, void OnnxConverter::AddLayerLRN(const std::string &input, int32_t radius, float bias, float alpha, float beta, const std::string &output) { + { + const auto name = input; + + if (onnx_tensors_.has(name)) { + const auto &onnx_tensor = onnx_tensors_.at(name); + const auto new_tensor = OnnxToNnapiAxes0231(onnx_tensor); + shaper_.AddShape(name, new_tensor.shape); + nnapi_tensors_[name] = new_tensor; + CreateTensorFb(name, new_tensor); + } + } + shaper_.Identity(m(input), output); const auto param = DNN::CreateLRNDirect(builder_, m(input).c_str(), radius, bias, alpha, beta, output.c_str());