diff --git a/onnxruntime/core/providers/acl/nn/conv.cc b/onnxruntime/core/providers/acl/nn/conv.cc index c191e27ed9..a4a42c908d 100644 --- a/onnxruntime/core/providers/acl/nn/conv.cc +++ b/onnxruntime/core/providers/acl/nn/conv.cc @@ -24,8 +24,14 @@ #include "arm_compute/runtime/NEON/functions/NEConvolutionLayer.h" #include "arm_compute/runtime/NEON/functions/NEDepthwiseConvolutionLayer.h" +#ifdef ACL_1902 +#include "arm_compute/core/NEON/kernels/NEDepthwiseConvolutionLayer3x3Kernel.h" +#else +#include "arm_compute/runtime/NEON/functions/assembly/NEDepthwiseConvolutionAssemblyDispatch.h" +#endif + #define CONV_ACL -#define DEPTHWISE_CPU +#undef DEPTHWISE_CPU #define PREF_DIM 4 @@ -36,7 +42,7 @@ template thread_local std::map Conv::convLayers; template -arm_compute::TensorShape Conv::ACLReshapeWeightsDepthwise(arm_compute::Tensor* kernel) { +arm_compute::TensorShape Conv::ACLReshapeWeightsDepthwise(arm_compute::Tensor* kernel) const { arm_compute::TensorShape shape = arm_compute::TensorShape(kernel->info()->tensor_shape()); shape[2] = shape[2] * shape[3]; shape[3] = 1; @@ -49,6 +55,16 @@ template Status Conv::Compute(OpKernelContext* context) const { size_t num_inputs = OpKernel::Node().InputDefs().size(); + ACLNEConv* pConv; + ConvLayersIterator it = Conv::convLayers.find((OpKernel*)this); + if (it != Conv::convLayers.end()) { + pConv = &it->second; + if(pConv->isDepthwiseCPU == true) { + Status s = onnxruntime::Conv::Compute(context); + return s; + } + } + const Tensor* X = context->Input(0); const Tensor* W = context->Input(1); const Tensor* B = num_inputs == 3 ? context->Input(2) : nullptr; @@ -109,9 +125,8 @@ Status Conv::Compute(OpKernelContext* context) const { ORT_NOT_IMPLEMENTED("Not implemented fused activation: ", conv_attrs_.activation); } - ACLNEConv* pConv; - ConvLayersIterator it = Conv::convLayers.find((OpKernel*)this); if (it == Conv::convLayers.end()) { + auto mm_layer = ACLCreateMemoryManager(); ACLNEConv tconv; @@ -133,6 +148,7 @@ Status Conv::Compute(OpKernelContext* context) const { const arm_compute::DataLayout data_layout = tconv.in->info()->data_layout(); const int idx_channel = arm_compute::get_data_layout_dimension_index(data_layout, arm_compute::DataLayoutDimension::CHANNEL); bool isDepthwise = (1 == tconv.k->info()->tensor_shape()[idx_channel]); + tconv.isDepthwiseCPU = isDepthwise; std::vector aclStrides(2); aclStrides[0] = (strides.size() == 2) ? strides[1] : 1; @@ -160,29 +176,71 @@ Status Conv::Compute(OpKernelContext* context) const { arm_compute::PadStrideInfo aclPadStride = arm_compute::PadStrideInfo(aclStrides[0], aclStrides[1], aclPads[0], aclPads[1], aclPads[2], aclPads[3], arm_compute::DimensionRoundingType::FLOOR); + unsigned int aclDilation0 = (dilations.size() == 2) ? dilations[1] : 1; if (isDepthwise) { #ifdef DEPTHWISE_CPU Status s = onnxruntime::Conv::Compute(context); + std::pair ret; + ret = Conv::convLayers.insert(std::pair((OpKernel*)this, tconv)); return s; #else - auto layer = std::make_shared(); tconv.k->info()->set_tensor_shape(ACLReshapeWeightsDepthwise(tconv.k.get())); - layer->configure(tconv.in.get(), tconv.k.get(), (B != nullptr) ? tconv.b.get() : nullptr, tconv.out.get(), - aclPadStride, 1 /* depth multiplier */, - acl_activ_enabled ? arm_compute::ActivationLayerInfo(acl_activ_func, conv_attrs_.alpha) : arm_compute::ActivationLayerInfo()); - tconv.layer = std::move(layer); + + // in the configure function for NEDepthwiseConvolutionLayer3x3, there is a separation based on the optimization +#ifdef ACL_1902 + bool optimizable = + arm_compute::NEDepthwiseConvolutionLayer3x3Kernel::is_optimized_execution_possible(tconv.in->info()->tensor_shape(), + aclPadStride, + tconv.in->info()->data_type(), + 1 /* depth multiplier */, + tconv.in->info()->data_layout()); +#else + bool optimizable = + arm_compute::NEDepthwiseConvolutionAssemblyDispatch::is_optimized_supported(tconv.in->info(), + tconv.k->info(), + aclPadStride, + 1 /* depth multiplier */, + arm_compute::Size2D(aclDilation0, dilations[0])); +#endif + if(optimizable) { + //optimized depthwise convolution + auto layer = std::make_shared(); +#ifdef ACL_1902 + layer->configure(tconv.in.get(), tconv.k.get(), (B != nullptr) ? tconv.b.get() : nullptr, tconv.out.get(), + aclPadStride, 1 /* depth multiplier */, + acl_activ_enabled ? arm_compute::ActivationLayerInfo(acl_activ_func, conv_attrs_.alpha) : arm_compute::ActivationLayerInfo()); +#else + layer->configure(tconv.in.get(), tconv.k.get(), (B != nullptr) ? tconv.b.get() : nullptr, tconv.out.get(), + aclPadStride, 1 /* depth multiplier */, + acl_activ_enabled ? arm_compute::ActivationLayerInfo(acl_activ_func, conv_attrs_.alpha) : arm_compute::ActivationLayerInfo(), + arm_compute::Size2D(aclDilation0, dilations[0])); +#endif + tconv.layer = std::move(layer); + tconv.isDepthwiseCPU = false; + } else { + // cpu depthwise convolution + Status s = onnxruntime::Conv::Compute(context); + std::pair ret; + ret = Conv::convLayers.insert(std::pair((OpKernel*)this, tconv)); + return s; + } #endif } else { - unsigned int aclDilation0 = (dilations.size() == 2) ? dilations[1] : 1; - - auto layer = std::make_shared(mm_layer); - layer->configure(tconv.in.get(), tconv.k.get(), (B != nullptr) ? tconv.b.get() : nullptr, tconv.out.get(), - aclPadStride, - arm_compute::WeightsInfo(), arm_compute::Size2D(aclDilation0, dilations[0]), - acl_activ_enabled ? arm_compute::ActivationLayerInfo(acl_activ_func, conv_attrs_.alpha) : arm_compute::ActivationLayerInfo(), - false, conv_attrs_.group); - tconv.layer = std::move(layer); + if(tconv.k->info()->tensor_shape()[0] == 1 && tconv.k->info()->tensor_shape()[1] == 1) { + //pointwise convolution + Status s = onnxruntime::Conv::Compute(context); + return s; + } else { + //convolution + auto layer = std::make_shared(mm_layer); + layer->configure(tconv.in.get(), tconv.k.get(), (B != nullptr) ? tconv.b.get() : nullptr, tconv.out.get(), + aclPadStride, + arm_compute::WeightsInfo(), arm_compute::Size2D(aclDilation0, dilations[0]), + acl_activ_enabled ? arm_compute::ActivationLayerInfo(acl_activ_func, conv_attrs_.alpha) : arm_compute::ActivationLayerInfo(), + false, conv_attrs_.group); + tconv.layer = std::move(layer); + } } tconv.out->info()->set_format(tconv.in->info()->format()); @@ -224,6 +282,7 @@ Status Conv::Compute(OpKernelContext* context) const { pConv->b->allocator()->free(); pConv->out->allocator()->free(); + return Status::OK(); } #else diff --git a/onnxruntime/core/providers/acl/nn/conv.h b/onnxruntime/core/providers/acl/nn/conv.h index 218fe9173d..e4e413e454 100644 --- a/onnxruntime/core/providers/acl/nn/conv.h +++ b/onnxruntime/core/providers/acl/nn/conv.h @@ -30,7 +30,7 @@ typedef struct std::shared_ptr k; std::shared_ptr b; std::shared_ptr out; - bool isDeptwise; + bool isDepthwiseCPU; } ACLNEConv; typedef std::map::iterator ConvLayersIterator; @@ -54,7 +54,7 @@ class Conv final : public onnxruntime::Conv { ConvAttributes conv_attrs_; ACLExecutionProvider* provider_; - arm_compute::TensorShape ACLReshapeWeightsDepthwise(arm_compute::Tensor* kernel); + arm_compute::TensorShape ACLReshapeWeightsDepthwise(arm_compute::Tensor* kernel) const; }; } // namespace mkl_dnn } // namespace onnxruntime