From acb3bb6c62191c5426552348345fde6e83957c8c Mon Sep 17 00:00:00 2001 From: xiaying Date: Sun, 30 Oct 2022 08:44:24 +0800 Subject: [PATCH] [Sync] Sync Internal Gitlab 2.2.0 --- CMakeLists.txt | 1 + README.md | 5 +- README_CN.md | 7 +- .../images/intro/releases/2_2_0_bfmmla1.png | Bin 0 -> 54516 bytes .../images/intro/releases/2_2_0_bfmmla2.png | Bin 0 -> 62661 bytes .../intro/releases/2_2_0_bianryrelu.png | Bin 0 -> 45044 bytes .../images/intro/releases/2_2_0_cuda.png | Bin 0 -> 58052 bytes .../images/intro/releases/2_2_0_nnapi1.png | Bin 0 -> 45839 bytes .../images/intro/releases/2_2_0_nnapi2.png | Bin 0 -> 61836 bytes .../images/intro/releases/2_2_0_smmla1.png | Bin 0 -> 44242 bytes .../images/intro/releases/2_2_0_smmla2.png | Bin 0 -> 44194 bytes docs/faq.md | 11 + docs/inference/session.md | 6 +- docs/intro/about.md | 5 +- docs/intro/releases.md | 47 +- docs/pymnn/Interpreter.md | 2 +- docs/tools/test.md | 13 +- include/MNN/MNNDefine.h | 4 +- include/MNN/MNNForwardType.h | 2 +- project/ios/MNN.xcodeproj/project.pbxproj | 4 + .../MNNQuant/test_mnn_offline_quant.py | 1 + pymnn/src/MNN.cc | 22 +- pymnn/src/expr.h | 5 +- pymnn/src/nn.h | 5 +- schema/current/CaffeOp_generated.h | 44 +- schema/default/CaffeOp.fbs | 2 + .../coreml/execution/CoreMLActivation.cpp | 2 +- .../backend/coreml/execution/CoreMLInterp.cpp | 1 + .../backend/coreml/execution/CoreMLRaster.cpp | 54 +- source/backend/cpu/CPUBackend.cpp | 2 +- source/backend/cpu/CPURuntime.cpp | 28 +- source/backend/cpu/CPURuntime.hpp | 9 +- source/backend/cpu/arm/CMakeLists.txt | 7 +- source/backend/cpu/arm/CommonNeonBF16.cpp | 88 +- source/backend/cpu/arm/FunctionSummary.hpp | 8 +- .../MNNGemmInt8AddBiasScale_ARMV82_Unit.S | 106 +- .../MNNGemmInt8AddBiasScale_ARMV86_Unit.S | 582 +++++ .../bf16/ARMV86_MNNPackedMatMulRemain_BF16.S | 564 +++++ .../arm64/bf16/ARMV86_MNNPackedMatMul_BF16.S | 284 +++ source/backend/cpu/bf16/BF16Functions.cpp | 15 + source/backend/cpu/bf16/CMakeLists.txt | 1 - source/backend/cpu/bf16/VecHalf.hpp | 6 + .../backend/cpu/compute/CommonOptFunction.cpp | 3 +- .../backend/cpu/compute/CommonOptFunction.h | 1 + .../cpu/compute/ConvInt8TiledExecutor.cpp | 8 - .../backend/cpu/compute/Int8FunctionsOpt.cpp | 167 +- source/backend/nnapi/CMakeLists.txt | 6 +- source/backend/nnapi/backend/NNAPIBackend.cpp | 239 +- source/backend/nnapi/backend/NNAPIBackend.hpp | 23 +- .../nnapi/backend/NNAPINeuralNetworks.h | 2177 +++++++++++++++-- .../backend/nnapi/backend/NNAPIOPRegister.cpp | 30 +- source/backend/nnapi/backend/NNAPISymbol.cpp | 4 + source/backend/nnapi/backend/NNAPISymbol.hpp | 4 + .../nnapi/execution/NNAPIActivation.cpp | 74 + .../nnapi/execution/NNAPIActivation.hpp | 26 + .../backend/nnapi/execution/NNAPIArgMax.cpp | 33 + .../backend/nnapi/execution/NNAPIArgMax.hpp | 26 + .../backend/nnapi/execution/NNAPIBinary.cpp | 26 +- .../nnapi/execution/NNAPICommonExecution.cpp | 20 + .../nnapi/execution/NNAPICommonExecution.hpp | 3 + .../nnapi/execution/NNAPIConvolution.cpp | 14 +- .../backend/nnapi/execution/NNAPIGather.cpp | 39 + .../backend/nnapi/execution/NNAPIGather.hpp | 26 + .../backend/nnapi/execution/NNAPIInterp.cpp | 47 + .../backend/nnapi/execution/NNAPIInterp.hpp | 26 + source/backend/nnapi/execution/NNAPIPool.cpp | 27 +- .../backend/nnapi/execution/NNAPIRaster.cpp | 200 ++ .../backend/nnapi/execution/NNAPIRaster.hpp | 35 + .../nnapi/execution/NNAPIReduction.cpp | 56 + .../nnapi/execution/NNAPIReduction.hpp | 25 + source/backend/nnapi/execution/NNAPIScale.cpp | 37 + source/backend/nnapi/execution/NNAPIScale.hpp | 26 + .../backend/nnapi/execution/NNAPISoftmax.cpp | 38 - .../backend/nnapi/execution/NNAPISoftmax.hpp | 26 - source/backend/nnapi/execution/NNAPIUnary.cpp | 2 +- source/core/TensorUtils.cpp | 63 + source/core/TensorUtils.hpp | 3 + source/shape/ShapeConvTranspose3D.cpp | 12 +- test.sh | 81 +- test/grad/GradList.md | 51 +- test/grad/MatrixBandPartGradTest.cpp | 76 + test/grad/ScaleGradTest.cpp | 54 + test/grad/SeluGradTest.cpp | 54 + test/grad/TopKV2GradTest.cpp | 70 + .../source/common/FullQuantAndCoding.cpp | 2 +- .../optimizer/merge/ConvertMatMulToConv2D.cpp | 1 + .../onnxextra/OnnxConvolutionMerge.cpp | 10 + .../optimizer/tflitextra/TflitePrelu.cpp | 45 + tools/converter/source/tflite/ReluTflite.cpp | 18 + tools/cpp/getPerformance.cpp | 8 + tools/cpp/timeProfile.cpp | 9 + tools/script/arm_assembly.py | 96 + tools/train/source/grad/BroadcastToGrad.cpp | 77 + .../train/source/grad/MatrixBandPartGrad.cpp | 49 + tools/train/source/grad/ReduceGrad.cpp | 6 +- tools/train/source/grad/ReshapeGrad.cpp | 7 +- tools/train/source/grad/ScaleGrad.cpp | 39 + tools/train/source/grad/SeluGrad.cpp | 45 + tools/train/source/grad/StridedSliceGrad.cpp | 46 + tools/train/source/grad/TopKV2Grad.cpp | 37 + .../train/source/transformer/OpConverter.cpp | 4 +- 101 files changed, 5760 insertions(+), 640 deletions(-) create mode 100644 docs/_static/images/intro/releases/2_2_0_bfmmla1.png create mode 100644 docs/_static/images/intro/releases/2_2_0_bfmmla2.png create mode 100644 docs/_static/images/intro/releases/2_2_0_bianryrelu.png create mode 100644 docs/_static/images/intro/releases/2_2_0_cuda.png create mode 100644 docs/_static/images/intro/releases/2_2_0_nnapi1.png create mode 100644 docs/_static/images/intro/releases/2_2_0_nnapi2.png create mode 100644 docs/_static/images/intro/releases/2_2_0_smmla1.png create mode 100644 docs/_static/images/intro/releases/2_2_0_smmla2.png create mode 100644 source/backend/cpu/arm/arm64/MNNGemmInt8AddBiasScale_ARMV86_Unit.S create mode 100644 source/backend/cpu/arm/arm64/bf16/ARMV86_MNNPackedMatMulRemain_BF16.S create mode 100644 source/backend/cpu/arm/arm64/bf16/ARMV86_MNNPackedMatMul_BF16.S create mode 100644 source/backend/nnapi/execution/NNAPIActivation.cpp create mode 100644 source/backend/nnapi/execution/NNAPIActivation.hpp create mode 100644 source/backend/nnapi/execution/NNAPIArgMax.cpp create mode 100644 source/backend/nnapi/execution/NNAPIArgMax.hpp create mode 100644 source/backend/nnapi/execution/NNAPIGather.cpp create mode 100644 source/backend/nnapi/execution/NNAPIGather.hpp create mode 100644 source/backend/nnapi/execution/NNAPIInterp.cpp create mode 100644 source/backend/nnapi/execution/NNAPIInterp.hpp create mode 100644 source/backend/nnapi/execution/NNAPIRaster.cpp create mode 100644 source/backend/nnapi/execution/NNAPIRaster.hpp create mode 100644 source/backend/nnapi/execution/NNAPIReduction.cpp create mode 100644 source/backend/nnapi/execution/NNAPIReduction.hpp create mode 100644 source/backend/nnapi/execution/NNAPIScale.cpp create mode 100644 source/backend/nnapi/execution/NNAPIScale.hpp delete mode 100644 source/backend/nnapi/execution/NNAPISoftmax.cpp delete mode 100644 source/backend/nnapi/execution/NNAPISoftmax.hpp create mode 100644 test/grad/MatrixBandPartGradTest.cpp create mode 100644 test/grad/ScaleGradTest.cpp create mode 100644 test/grad/SeluGradTest.cpp create mode 100644 test/grad/TopKV2GradTest.cpp create mode 100644 tools/converter/source/optimizer/tflitextra/TflitePrelu.cpp create mode 100644 tools/script/arm_assembly.py create mode 100644 tools/train/source/grad/BroadcastToGrad.cpp create mode 100644 tools/train/source/grad/MatrixBandPartGrad.cpp create mode 100644 tools/train/source/grad/ScaleGrad.cpp create mode 100644 tools/train/source/grad/SeluGrad.cpp create mode 100644 tools/train/source/grad/StridedSliceGrad.cpp create mode 100644 tools/train/source/grad/TopKV2Grad.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index dab02ccd3..37f2c1c87 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -491,6 +491,7 @@ ENDIF() # NNAPI IF(MNN_NNAPI) + add_definitions(-DMNN_NNAPI_ENABLED=1) add_subdirectory(${CMAKE_CURRENT_LIST_DIR}/source/backend/nnapi/) list(APPEND MNN_DEPS MNN_NNAPI) list(APPEND MNN_OBJECTS_TO_LINK $) diff --git a/README.md b/README.md index 09632a778..dc04778d1 100644 --- a/README.md +++ b/README.md @@ -73,13 +73,14 @@ The Architecture / Precision MNN supported is shown below: | | x86/x64-AVX2 | S | B | B | A | | | x86/x64-AVX512 | S | B | B | S | | | ARMv7a | S | S (ARMv8.2) | S | S | -| | ARMv8 | S | S (ARMv8.2) | S | S | +| | ARMv8 | S | S (ARMv8.2) | S(ARMv8.6) | S | | GPU | OpenCL | A | S | C | C | | | Vulkan | A | A | C | C | | | Metal | A | S | C | C | | | CUDA | A | S | C | C | -| NPU | CoreML | B | C | C | C | +| NPU | CoreML | B | B | C | C | | | HIAI | B | C | C | B | +| | NNAPI | B | B | C | C | diff --git a/README_CN.md b/README_CN.md index f89943cb4..b958f82cc 100644 --- a/README_CN.md +++ b/README_CN.md @@ -45,7 +45,7 @@ MNN文档: - 支持 Tensorflow、Caffe、ONNX、Torchscripts 等主流模型文件格式,支持CNN / RNN / GAN / Transformer 等主流网络结构。 - 支持多输入多输出,支持任意维度的输入输出,支持动态输入(输入大小可变),支持带控制流的模型 - 算子丰富,支持 178 个Tensorflow Op、52个 Caffe Op、163个 Torchscipts Op、158 个 ONNX Op(ONNX 基本完整支持) -- 支持 服务器 / 个人电脑 / 手机 及具有POSIX接口的嵌入式设备,支持使用设备的 CPU / GPU 计算,支持部分设备的 NPU 计算(IOS 11 + CoreML / Huawei + HIAI) +- 支持 服务器 / 个人电脑 / 手机 及具有POSIX接口的嵌入式设备,支持使用设备的 CPU / GPU 计算,支持部分设备的 NPU 计算(IOS 11 + CoreML / Huawei + HIAI / Android + NNAPI) - 支持 Windows / iOS 8.0+ / Android 4.3+ / Linux  及具有POSIX接口的操作系统 ### 高性能 @@ -77,13 +77,14 @@ MNN适配的硬件架构与精度详见下表: | | x86/x64-AVX2 | S | B | B | A | | | x86/x64-AVX512 | S | B | B | S | | | ARMv7a | S | S (ARMv8.2) | S | S | -| | ARMv8 | S | S (ARMv8.2) | S | S | +| | ARMv8 | S | S (ARMv8.2) | S(ARMv8.6) | S | | GPU | OpenCL | A | S | C | C | | | Vulkan | A | A | C | C | | | Metal | A | S | C | C | | | CUDA | A | S | C | C | -| NPU | CoreML | B | C | C | C | +| NPU | CoreML | B | B | C | C | | | HIAI | B | C | C | B | +| | NNAPI | B | B | C | C | ## 工具 diff --git a/docs/_static/images/intro/releases/2_2_0_bfmmla1.png b/docs/_static/images/intro/releases/2_2_0_bfmmla1.png new file mode 100644 index 0000000000000000000000000000000000000000..c71986788c5837dece6e87926ed1f2d08e1af3f0 GIT binary patch literal 54516 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 literal 0 HcmV?d00001 diff --git a/docs/_static/images/intro/releases/2_2_0_bfmmla2.png b/docs/_static/images/intro/releases/2_2_0_bfmmla2.png new file mode 100644 index 0000000000000000000000000000000000000000..c0f1ab1d9ac533b77d19b12c6997b10c873a5dea GIT binary patch literal 62661 zcmeFac{r7O7e0h+H456Y-ndey~ zGm&i`zUxuvJ=N|v{r6ti?>*-_+S+?R&-0nqy4St#wN8N2WhpXJI#N75JTe(+aTPo~ zLQy=tJtV|`!Qad@uxY~|_;xB%m+-P0k4(ZZca5*em?$XValmV0JR*E5ygkTA;9op^ zIy|D?*LZlc`1JpIt%A??<1++!cz))1gg-uW75+s2c?AE#w}1S(Cm#RbE5;N2^JzlS z_&xu;-a~?X&BFa!0Q^C6Q(DUo5091#`48VTt`&xW#*+~jRlAKpGeGjRLw##!q3KP| z{h3nBJsd&TgHgnRDM^GJccbs#l`%=vx)G)3@sWpGA}H*gPn-#d!C_HcqO>k1JNoxYw*8o!;R=Fp<4r{&BHP{3=PgX)b~eW|C4=dFEQPn0RJAMI%g&p(R$b;F zqb}O%erdS8SkI-swT{h%P3O2i`J7gObAaBSqSR@=@GmmDD;gRa4?HMTsH(vA^ucp>ITzMRbE#%{h9Pn!LDG4Qm`tLAm=wCO;pQxS(c z=}yd~qR0BfQYL=K$ySyL9^*o*!Pm|jnODzSv?ThtWEndeaNgbBSZIFO0PN#?-;5pD zJwt5!@XO+xVg$Rc7FwE{#<@8TvuM7!V(?5d*mfhUbWVW&%r#GK_sQhQ{*?$#JuObr zP!_pI-C`6%pY?ieipLI3cVuV|Z&{3fX?QZ*p{eg6>VG*#Aeov_tH?TLcA&H?M&wgK zQ1`8g=A*Q1y+t;0r}fMGvr48oN|$>r_A#6_{ILHd8{19%XemZ#<`YVbgD&&ME)y`S zgwfWQ2CYdlg%(|$7F}5}LaW1fk{wC-w?}9zZqCIBIu&kjZAA7K^B?$r#*&YsDU*1p z`S&8fqU#7S2JQN_8JgL#i)Te?9AXuP*Q&}aJF;{IQ)PX6HLh|7(8WA_IO?ct-y)%r zp^^FKM)``=K#9X_;K{6;4off8c81^HVJ~Z*>&dG=arvoPNo*r+`|)@BIzkth=Z9?e zk{`)=VqH?3o0oU|tv~F6^&5w_T)!2TN4<;8 z9?Cq^CSD@6T2{sO`rXSn{Jc@5XPjw;oQRn9TxQP~DXchjYMHKS%k>rQFf`ALX^Rx71*#5Nq}={nn9 zJKG6jmQvx3om}&_lwt$f-fTQ?-^FkV%BmgV8h)*{agiN!kL_=9x&;r8OC56dXsOT_ za#@ylys>!D)J1)|b8zZt;>eyO)+}!+ zhA!_g=v!6aXRv;VVPADwa!A+6oT63T*2s?B+;ol97Ms<}GYMY%B<8WvH*`!a(EgH# z;?8Qdh&=z*_R32V{FmClN%G6P+8il5K3APtGsLJxXkB5dQ9d>aKdCq_u+VgpgmosP?fv_onc4 zT?o?W!Qv_Nxsj#CQ|qH;&UQQ$tJJ5yro=^r9cd1_W$&#t)F%3cRAu7ugt7LV0B?y| zg@{JkCAFnHDnL(UrMRhBb<&-ht+@bOYL_b^ zq%nAVl&tHHgeYTyYJg#cpo9sj??kUvUtw@@xb34q=6NB@ILU$VT3_y({f3YCTJV&EN)(|Z;eJf+ z-9q#OF0R=$S{BleeS4@^Uf0gOU11EYFv%UIn$={a#so088VK&1wGue%N!pLU?e6UG zXip~L=2YcpHD3c%1f6RxFZJ6s73-0bdQSMLa>a5eifrY(IBP123GwpW72|%Gs_CZ} z@3J)U$r4L7U(XV$GeW>ocQo-eDm~*9^FkTg)on*N4COD2uoS z53(`QPo2L+WwH7-rWpvWv%N`*Ql=(+5Sj8pJ-#Y3BfGqp2!)o6<> zl6>r%puNq4*J(0?R!1W3c0t+7r#wPA1ShunSEnbmot4$vPmaYn4c@BeNXx`*h_CeC zijZCK!!+Ha=WFE2m#VP%fz*E8)|Ut{&Z^l&I|Nr#-+Az@_8+dDde4+?K!`D4DrOm3 zneJVueqQY@A|=o?n|)yG^hqL~C0lK^_&4JwN+F~~qD!_}iLpm}pVPYTL~d1Vj&T*< z=t!TaCp^KY?k%q$uC|0&1$~F1so(?wQuKs?@YlqPM}%LdaB$!qx3Oy5SHd*1&|u@v z{lzsc%XM?1IxC$iYc!;E*n6K2rFg9*4PnbxT21o`>4F1x_Ri6kK5A)y&XSdCCXaq1 zbiVG}L@=KlE$XDFPc~BusRlM4(9c(ROC!YELw5Kab9rE?O#}0{?Tz`;L6(*s^35^} zQlp0G&wW=Xm~YWj;{|aBq$u9cQVlZ}8c$Pw-W$%Y+W&0_p2o0_Ay}QDs}peb!UTSnB4WY?Cpi^1rZ_N?N6knNKo5tWY-VZ#4<6 z=IZLuG2RLSOtUQ)FrsOn?!bAmu<|IS{EL|b}9|OVYR@HtD&XDGI-BHA~F)Pt9oC#1{ zw-kNLs8F5prf(nD>){ld<&7;%ne`YYE^2IkvycQuC9Ln(Mw3acGFL>lJ2t~Q<;a#` z8)e*m20=;9lM%*bd9B#QJ&L)l`^5=GWqlq$+>K1A#b8;^=A;H9&`k+LfME}0v`yfi zmQZ6VJ2LrRjqBFb%lM;YEfV+#h|ajS?0dR>Jv&m|ZRs4J^P&+g<$}XfCauKSt!BAm zjI^27_@V^Y!umw^)Pl!=;&|~E_D=cv@Jn2+3ld!KNEywE-)ojH(zHSu4BNIgti z_80G~SJ!G4-A4%UFds0!5)JpL_%B$CHZ`qyH-Dui5^z;Ui-}27Gq+Igr(y9{U}5sX z^sEktip1@7emqIaV^$b0F8Y_gW>;k7qUVJ3q~3YK`zaGxG4*__>CVhKN+R3v43<3RfTEgn$FEjh#n*|NDT50B0ZFLdTV1P zWN@rET~Bgnd!^!dA8Z5Hws~*w)7vXtxetFtaCK;y?87KKl3j23jzAbMF;b<0Dsk9P zZ)WMz%=5!#lPOQ+*F@UI&|F(n{7Onn!vu@~>+M)O>Thp`5)tvY9~YPKFz=Kq!(UQv z(Qm;Lq{LFL*B5&elw_I2weXHfH-DvUSURBJ>O8kxJWhA_imzpz1? zH!~e6)qMOY4YN|n-}(U8zWAzag5!7eLRIJvRcs8*6S&+K?+PFnmayr{^}RkZ8k7>E zu6&aP^VnyG#>jv0OGt~IMoYZ|heVkx&s}l+ka(kXz9HAVje)f>E|1B}&t3R?5~uB_ z+H2=tf4kg8o>@&%pdv_pqN5iW+H*dvZeq^j>xBd8bH3@AjHNz@0dFD2rB$KZ8}$ z-exa0d_hdkbzs#-mpdX+Zx5*@yEKi^9)(=Pt)=X3K`l4HQ_3N}@rjYvL`SJ9o4=`j zP0SA@FkPoscjcn*XqnF>*h4Bku`;w5lRuaw^YF2$ay$R|efJ2C(rG-~WL{@j@Io=& zZJjS7(4Fc@I;xZo=%-9`vx3!wvp`fRJF#zaWs-5p=IV~S>a5jB$Qb=@obP2%LP;nS zd1_n&f%$AIXw`nny=XNp-Ot!#*_$M?-X%u0VQ*Y%C1O`A1Rb^~XnC<0l@v)uEYTik zyQtG!Y9$JW_KNb{J*q4-UObw8IL?&^Q-M)oBTh{GBp@mw!>`_cd8{Zj0CRxNEHS>> zZDnA5dD_oJUS>IWefSPV$v721+goo8Hg&>TlHzcS(8SmU;Vxg1V9aH+$1?WWjdc*;?T5OM#kDTM!vzJ`nKAOs^ONfIw@u-aZmqQ-MhDJ}6FdRG~e^X5S^Fp^_ zNO9CP*R2uPjE1_kgz@Jd$IG337kgF{Q9%S^q~58T;frO2Sn5Tr>e?f_bRlzlw}wL1 zr|c1`#e1i|Gc`AJ0nA_42p!!GUS*j>Q=L5Z*4?ONL|Ck4I4ODBFBMa{w$zu$F}$~F z)1Pw7L3<2bR)g~<-nG=%aZpT1kmnTZI^!LTnVJ7xU#!`yyS8W9r2Mv{vj-0-3Sqfs($d*8T*O7IK1ZWJi2qz_&y*V{b5IUhnX zBR;RWq2|hPdSj!jy-GHfPM7+{V-b&XU55^Jl5ARCeNiUt-0iUl&0~3At60@K_H)yb zCKs~t`Gt)=GCqo@@~Bs5AF@kO>Ok|P$tqJIzr@QEQu}{pS!Wrt5saFTH;Qc;Z`02{ zuaHHsf18CD?D}Qp<}g{dRMYwr-Mm?8vsJ6>@0ao$HHJEjy@k zTC`G~8m&a25;s2raTg}RfP=1N^x#8?{o2MpDxGWU@9%#scTzbOb48qXz)2?1_w8ze zf^5wbwpYu2L)(STlQdVpu4tQ$d+?d1cc}$Zc#BgED2K3)l_jaZb<#}4HwMx?wvW#PA9#EZ**o7sRe&)Amlu<2b0s^}qwZ1aN2DY?k zmXG^*)6#Xu)85$f8B(M_;&GbHOX)rZ_I9)7i3RSDW)mS?Q%9f0hhXllCY-FRO-!V9 z+!=Wx;Lgzz|HgAMV3pQZWS@V9?~X>O9LW`R_ti?Kl21qL+HTF4t*mp*X$v`o+= z8!J`{xwraB_3YlHSBZKT*BKth&3{UWJ#ixv6I_Gdp!xj3hJ!>RBA-{7IAwI}#rf^d z&0-#L$*wl}ld>P^WAY@p)7ZSyn`S?SkgYE_y_;|2)>v$rNOV0y%FF&LG0HdmV}$p2 zV#fFoidZEoPS^^GV9qI_O8mSQ#niqe>K&YlNx<{>RcE6Oz=*BVT95GsG){iX4BtDN z?Xi`it5xngH_n2`33|_B1|!Oz=d>l(X26C@hy0qOcc=v5rWDGIlCn zJT~)c0f#-Ud%EJRzsJi{YW$z+!@stU4=XW}U?-%LQ~7)`_GV^^iH7#pEFEf!58_b) zO~DCAj(z*maME5Y?xDEQ$wWV=iR38Ox z#*J388j_Wm#y!;(vtM#;uYbQnMUu{xuh1s613TEZbnewCIqi~4t~NGzL3MF`)SgU8 z40}e|R+SX-Lcj}Xfm1SeU(aVijIET{(B>CD-s@HVkJ;tUXQsz3s*!M?myT43{RGphgE13H8En^5;04w>MyDr;bc6`oE01lDIRG1XHo&0cxKvXuE!l&X zZ>owEL~P!Hm|GJpd;(3L_tB^vJxZ1H?7w?X%=LWiO;VN=8CdFJV#;Fqmar z%u4EMCP{}4B_So9yh8MW2m4}*Ju=8wI*sjG>bDzz#fxlyqDZ-$W!&N-S!@{VvF*IE zTvRb@GIWdY;X8^k;g+uqWTI1T&lTS-r`+U7|Lzr(PJtPGKazNE7gCs$@BsTtB&_GY zX57YFl5aiGOP1z8sBt(lB2*3k7+H~0SmSDs3iXBN<*@L)MuGaJ0IoXLM3i5hLzk{; zonXS}47z11hVTFpPWP=RLz^j+s%pv>PNf^f(Xqhf{`@Yoz>;v`9r)mF-iOw7`K>K6S{ z+F4Q<2nDCdi_z52+5A%&nWxSsc`Cftztt$Ai(pWE!ocH7$rmEhf_4qWn_A-4D5<4) z+&9|Ux`IUnCX=@b1~W9dN_Vz5baQJ~E!G(Ew*}oRL@EmRZm|eqwCx8bzOBwKbbals zU+*WSG^-KIe;Ag;;dvIbG$CyhGO-b4t$6DZjivKQ0Birz=m3ez8{uZELg$ti%N%EW zN1om&+O3? z-Pq(MlUbBllc#>&+Dy-cr#$$0iNU!l~!o_bfYBNKOcqJ=eURSyJuM{u~IER97VLHx7yE4cY{jk zlvLJ~`7=*%-&pGB6HWr+0gsn# zX|_iG)>j-4X=O|CGosW|b?8!09? zqxsk0?l;5=^^HAlcE{osFMOas-bjj<+U2#qp1oeNW4Y?B*BNpAGjK}h$t)HnYULu{ zsDBXkEsx#lTvH3*mjVe2ce~-DIsLbETia~Jp{c8$zBbuYRz11z-Ity*u?R5d>I#K= z%Z4xt%`^(mpUSV-uWuTDX2H=E+&gdT88G*trO-*{Z%U3Luhd4&~$%R{qPuL|rK6!ldq3s{rH4AZ+^ziioyH9GT}%@jI^|jzMm0%=y1l#9$>!ZBI@#Xz zkqQSrh~qw6=ebEvW1FgbViquI9)rYW|!wF#z zBx%QPKaf+Fa5lGpK_E1hcHVxX`7tjMLx$d|sg_*Gj?msFNgusqvEPTJ)qsB20tz5B zp=zYvcLF^0D8aUIpNGYj`aKjEhxKlDWQYmv52RCh7PTdd%f!g|Ve`CH2_#W;c$S#O2h;yRYr#?VApG=$N}&_&bkFo)nM=Y^(}gY*#4iI! zZBJ}8nG`26txLB`&LEI9O84~O?i=`obz0YeZslAF#Hg%p9+I_8qg{*tbgHqF4)sEl~ZD8|6NL_h}v3Zv$lSVFHoTL76(Oo0F z`$L7+pWOS5g!PnlyEtOQc1_ohA6}$@Qp+ymgmC&63o^1Q+Tk!-4 zVf}_8L>qy7zh18$SwCwDg!BQwP(WMxpZWOriX1tB21qx* zzH-31p0qB&o+*w04e7sOmC%kv*k@89y(8~~GTpbx8sEtcS=@cp5yG*zSquq1vfhCz=Rt1^qi?iz5E_e>|%!Rkp(~TSI6zc z>va()t=`=wDKu|8QD0x5ci^}rHHMnoxC2d}A(;LC}%8 zeJID^PMY53%l8M|H)fXsi1$KP#>8c1t^lt8fuYE>iIH9ilg}XR+6^J0HO0lRp4j=J zAxO$ugHA)?wzcC=H`u+4C%T7NZ5>tfLMu-v=X!gpGRgZ6)z7O7qX;Xk-4rXNP$tM( zv1x13|LP^;iNMvHKq!$1>GPiRT{?zt8_NaDvweNoE`6KlF^z~fh{iXU$lB}=T&h(NMnTxV=76p-5Zf>qlBL$X`AKR{)DI392Xx4H} z^SM+A<6Pg)L~lVxCS*zw`p)+5>a6Q`EByWOzpqCRDU89N099MZKmODZz;S`okXzT- z<}1hwSi<~j6x>kXSnsNsBiGDTBa*tBZ+5`0#H1m**nuqO2O#+Qa%&{WbEY+0IMTB4 z&9%d#b3(7lvqn8D=JTDet>9-FsH0sJ;lc(p9OT96PkR@-#i+#bndx^Of8m7fyR zZ^lXN$~ zHSkIKzP6w4Y(R7o5Fr%352AhIeFSoU=M&`Ljw(lomWT4pXT zF5CXvQxIdU8vmy<%ZHgjR zWf*Mk35DqHK$?>?vqeLWmDd^trcVhv&OBC#5$G`a_}GAmh=|k1pWqlwYp&Oxy(Q+i zPtMvLCi~rYp!N{v+EV}`70H^n4=HOoe=d{lWts_wgrg3dz?@2Y^Yv1z9Ir*^DZ$%c zuO;1p9Q5q^baoLuU8xnQED9Dzt4j^e_9_)w>rMmfOU8Kdg6;l49Ck;7sjB$J9zj

zJ+C~*-}Y{j%hk9fK2cmnmH&ZMs=ND@P= zpOSU8&ogO|bv?EBSm(l~%3rLtIA1RPRNcr0QAp zt;t?9OUE2CA2|w7c(owh3;z4;v1V5QX}k_oY9M*@pV7Sg4N*U6>lfUJ2tLgH0d!?d zJwy5CstC;j0z&58U|dVc=HeyGL>L7DX~W~QmFb$EkXkc;KgL`zC63Y=CEIGceljWN@WLXI<65Sl9RqKM#c4i?f1Wdsqz z#OJ_GOb=C5=(;YvCvovi9k15kUZmxl83Ssfpu}OiKATt&(A1Q# zcVu53Dt8+wL_ijJGfV7LN8zneNxq9G%0eFI;X(r|10$!itER8iW($ ztCH}dV!{i^eht8?C=Gzs+0qin*{ROR)7ppfVrYK%vy^PwUa~_6lR$$h^FCriO~P5I z-Oi}~(P@oRN2^G5fp(GgqlgG&P+U3=O)*gEx@vqbb6JtJF**Dja)CJVN_^{HQI!Ra za*BwdtvRPT?J`Mn#)}h=Xb6j^vr2U?hsF;w3)fJ^oa$hxp}>6*RoG(eH<|ctt2)*} zs%WOE?^bZ$toe=b_Nt-F>L)*|Pw#vRjcTci^ktMsc-+ zD|l(JD@ZkE^(06%*ne?l=o9P09)i2DyMAklJEsfGcfF3_TzvGuE)2o2;bwfvA zRx{d7&zEmx)f2S>VsDe$cz!wN1`^|VdlOgyoZaU?(_2vg7x|G1f};@|n!%mFZ%L){ z-Mw$s%TwRf6mroA(0LD{o54VEp-U-VsmrtHBck`i+)0&^hPdm6)BGT>>*`HSO)-!t!9;>U6e&e$5Znc1>;QT+V4OUvLmda$#Pu!<(sd{+hRP$yHY14Y85FM z1dQqy9+-Wg#d5Szmju(DPoHQQ+x~e^#D|f}NAsjron{iSHwy?ELleqsUwa=&GZzl# z>tp(okZ52~#vlV^r+JbUOP*udr`EsAdj7LmV7|QG5vY^eT;KOS`|_ zlqi@_JRb$zH~zOc|682@f|G+1yr!MpZ@)C5to{1-%Z_aQAzM4UAfE05i%1CTTWoD@ zXFzovl$P-)0CiUS#qYF^5;?)^7!Tia+cDWEXAHcpdh=@+7Z)w7{11>YNr;Mi4S4Kq zEkkNWTSMc~)+Y)N|90J>i6Hq#Ktpl~250^+D5v=;gl{5?lfmF~{5}Pq=w3n&H*hf55RMESi)`TL zyM0_xK2km7OK;7l=G2lXVXY0>l~vQXlB=9}3}Jfdk)x-t=KJ?_0f$&r4({vmEY5-e&xUYR(j5JD-xd&AagJ$tffC=>W)+w_zu=y*lgWiHqaT9P)RPYVVx^TX6TB`8Kj=!#*_R;Z zmtQzi)rYytrFu&-ONS{MD-j1Nv3w=5{7k@3DZAju5^z-~!Wxyq?3Io|Ere8I%*RX3 zp-&$2GgTwS1piKb^657&a^^v{<*ige_lxH`fBWJHGLjNKrWW-$=P!p5j&^J5xyX5< z3xn<(R@x=@X$?`_tW<>juB$obQ#xZrwe|Hu!mq39VS{ikygc$NV-oHINXR(h<9XR* zN|Sd`+@_8BKx9TS<)!p9J!DmM*WP6(GQEds{yxiOukfydCS{sj>_ibSF zkcK1lL{t+00id}a$aCqUlA2|@e;L8cIx&tn#f5JoB?e+XNcyiVyl?pEf- z%n>q|NL~q~if2Ud3e0z^%#^zA*I`i$;M)@1EPuu+P}1W41~hfDu1^54o)Qqvjm?|1Tx4s zjy8aIIy1FRwY0Q4QxxbeI?~k>Fak}z1r}C-0<0^hj7=+bhy%%fKdRv`@odK9ys~wQ zTTjS8z6M!}+}E!!(x1I9{?Tyt^Fzg%u8Qq~4BE0$00H^h*2V9MB=X(h;=Cpw|L&{s z@JPA}cG?P(cAa1zYj}U*q;@@V{0tG`38Rs!0A47v%mBH@B{w3z&TM@fO`Tgl4s-oI zg_b?nxyqKp%GSO-aRdRH_WWR(6@z=(>ifLK3^RT`23nZgpC#B7Y{4st;9R6LKs zqka?ukN9M?y8EEk3@yn_*)q zK2eP`f;Y9hsk--LeNYK2w7ohycZLO>310a#wQL}r{^rfY|F6(d;?T>smNOuEQ&JBV zQysG&DCq!3!wkwE?;X*7ewl$!?B0}-Y1}oe5IXT;x+FQrTW_itD!+I*FZn~mWh@Wl zE}IN#`;jxWV(zdGcD7-n0zDSNulBsUHEIcEqt?8SK^IlUBP)6zXv`i!rXR;il!+8F zGg@EC-tJ@hrx(C2!xgt&5pUoAr!)Ngj6WNFN;U=jL2X&phjtMu;AW_KLZF5figA-p zU&(n>;xum!JSq{v5&bVhs= z6Ahi1w1PY*R$8|r{+bM&%vq?7dI=!4Z>A@2fU|*-+pHNyfAMxsb{(!W4S$G!lvV1w zwm7+eaO z>X2Nw`g$xXIXL5+xon)h;`GD&8(*IOZg}o$#mhdXm+JdvJA7X~24AWP@2d@c-et#?!C z2*7xaCrZin7I)(ABK51OOkBa=OQCno-j5&uKOc(GhL8M~FyxPC`-|I_XL=05bL4?f z(uSZWQasCgGz)cnIgmY<9E#g#-41L4WLFG9 zN}VND11V!9M=Z zKKQyAE>PbnykQ9e!~=wD&&^Zp{{o#8W*;gFpT+*|ytB1pwY|BPRb2xyiz$-l2FXAa z>vvi0FPM{>>cRnCw)~74UNf_LPy9VPUyt+g71iuJiAs!RT1P5cd5vl)5jD;}-_#=F zKXoFZs_{qFK&ynq_BQM`NaupdAL96*w=5qDkcZdC)RUqsYi{0#r$aR-Q>Qo^)TK)$9j)n|!eHz4s1t_gkJF zyPcs!hjSV^{LzwsiSig{`Bvsz_OzbmU`sSO1MtTYR=O`aQtyVQu0w= z4OTy!uie>3JChoHzWEp`_O3!qk0?xd_J1kp(z7c=w{s^+1RZLWb5J8^5}qml18+`D z%@X=Rlycx^wqBXeS1~btwf22R&GDkvS|Uj5sHi{RyzNhT2+vEL;4nR*@;g;Br?n=J z?NN-6E3_;q1Rdck$Is*A$aZ=GNs0$YxdZ5G9C2q4jeNc3W~7bVw6>RG8nn4st~nlZ z<<4JZ1S@$5aHfgUpSGqOCA}FenXQ?o^8T_AwtYh3)bHsAfD#gGd%l>yi~?TgPtg`?$N0&!Y2%*5(OZSs|X+C4$3;30s;Y zL8Ng7fZOcby-fKa(4j54#fyV)@Ce=?NL6`SXROXADA<>-o?!xX0Slgr#)Qt^-zLZ_ zbf1xtB4xvN>vKh>C*Zvs06ub-&g6!Q{1xr@^P!ATA1>=yW3gTzSIp2HG32N8s$)ZT zfRI06lWq{T&GwkaIfxlfb!O79x@Nr^AvN(M2{$P8mO#o4mye{Y+K{oZ@C7<9Bou2vGUA ze-oMhL4oH`ovgz8iKrWw7%-=;sX_T)-9kEdU_Um`oS8f&P(eTkq@(QZC}6*e6ZpGy z?1HhgeO=J>#imQ&qb$a;*SyerK%no{t!Mvtm;H3+h68vU1))o=LP%zKLI8pK{$)re zSg}|pQLZaX*9u81TlSojOTNG8uY`k2;$4x$u?SIA$tTw9GUGF6NIjWPBH3RVEo~6f zsTP36vvz}U=aFp8<2zb7y`muP3TL+_$Ds0hSmE3q!+4!Lhf2n&fjgIzFK_Y(mbwqW@fu-N zNtmLIi09Q3qvNxF`hs-hCk6=mS*4US8BMwQOnvgpKMM_CE?d+iey>G}sW|q~LZw1r z+u~{M!tS?s_Ug8_jvR@U9RP~-RV*Wv)O~BxUEk1901;%dB8NxE zP>DlEL!8JELx$E>`tGLdxdFk1`O_2O<8MxcheSyJCovg;9^To0bv4Y_teNTmfi!~x<_#SwISVLqM|YjD{D1qAWUd=Zh8rprw)Z4t`BWh`5{06$R@F&4 zs<|0<)VQ}%i3DUpyQ8`gu5t)LLFQmm^lSiHW+87xTCC|z_mAcZ8xcLLVAFm z%t~`YqTxGY+_^JD6+_UTDQHWX(ip(sGSofxf%l_pmn{6xqW`-OHQ;MY`w?ORkq8UB zt%pxMcnuDCxmskqg-DghaQ`2$o-n*b}(wTs#6%g2OEbnYTYc zGQq;84Eu<^OG=3!f#%R1YYaaPxC89mKp*1zlJW`(V}gDZ@%`jnmH3g#%(WZ83|l?A zBTcnhh=@q2ydcm+Go5)h9 z;KFT1fmBJqG8nsf!b^>?PKbEKX7O2waBhFU4&O$QiMO)yV%x+bthZEl$zekTtKxxB1ANX>QyDRUqkV0%>+B zl*?s8ph7a8v*$Np3n{B2bn#!J?Hi*O`Ww;Ea;^`VS7$1O^+FP{kSagkM|B#?dIbw_ ze!BDoN=MzG(br|Q;Msre(T`V3wJ@K=t&piL9SJ;1DnvjeT4FzW9T>yY`CRUm&^*M5 zum9$qOs%{V?zGc5U-v|dqeiKoNzR?JHUJ`YIY@u=9d_M+P+dvsn$-OxFM%->|C0!g z(*FRm!_GQ|T|?^Pc#Z3*H#UZLtmE9*(~xXGc)mkvZZq9y>7i?uu5B&L11ns*7LQ{zpk0;&HLp-L5bqDXI0HO~-Rxmr%PTUy?|*_B|I7^f9%8L{ z-p|JEY?{{B*1nvXu>`I$yKFgnqpIJkKQJsYy}AayHVM*7ZWyTAL)gD;64?#A-YGZk}6YAFlVZQ|&dWm}oi3y2~#1$!t_|?k4 z#mrxUr#@a(Y(J^uGVHZ?=8?AbSr&9Kr{cwhyJ@U7P>*w7IC>t;_xe|(JfxCjaHjg0nmsz#?B0`h|kseFSt5GU(6CeKtj0Zj*9|`>4vl2u2j73k-Rg z7c~H+8b=qK0NgwqIp2{HIpEl5_295ocq%sSd2BAw-rOmJzGe+dtC+W8w0gJS5~0_ZCP!07I@(`1UHo=$3r?wH znOY$x+Z5S*y}p6kt<~qc*qp=CFo-n0LHr*B@W4{!1Sw$ZU`2J_j(}kwyFs|n&Ro_`|c^U z<8%ZTuGo%4I*}^wl)5NgfdL$B>l#G?Z=Sh#o4C2}V?^gbdh>Z;$H~;)yE}80ABQ!}?Iph@ax-O+wt^>$i!w&<7=sgiAW9kn<2HlQ zMlJ9X6hcd(2!}jZGR+y;ug2YZk4a>3&}~Jx?c-Ubvy_~F`X2A?ml@@t!||G~Jv7FW zK)CPP!I^g&|1n2iUrB$&c<(lzP{uxTfL^ef!L`7W0&OWDCx0sXu;kjs@~=Kz;wDbD zwY9f|(AFiBCuoUV+%^m@(DPdQoBMhngJP&0Xtj9W#6?CEgyQP0VqzXgcoRITcqsof z9@J%&>JG)zv=y4_>KiQ7K*UN19Xc)V<+ExFem_#~xVwv1mc^8I#Hw@(#+R+hZ$AB* zmSMXukT<1KMsz%8!}ndFj7(Q(jD|h96`Wk_1qHSyF9kNHlfnN%Ask+B)~Slle!r3W zbu;q)!RX?>qSO?)Xyfs%|riOXrdY$?27uZ{#+llGLm zZ3y5g2yKAjYy%^1MyqT8V2zPxEb&{9L`SJu-W#@+YHy-_{ZcE5bGm!}+Mffx3IuE| zpd~_pvct}eNU8)5t?AQ6{ntTc9N2D%TMk&KhX6%@4R%7T;XL^e{-#7}0##uN$3CxU z$h{8d4bJ&2mhOnl9Pa4v2A9DDua4t(g+Y#xOg z&=Ot9lW|h`V?0y;&{~_#0|8!aW@jN^h6Fo8>l4qG2j<oINlqg@Sx#=BQ=%;~{pC|~@=l|0{=4X(FRwg*y zaWE;BzC&0+lwOy|I5VYH{kqy8LP4c)^am^<`;^J(3Oin6k0Fo4EHG#^W*q&niX}bQc{azu zT+cnT0xjXqIHdj%(zlkdUkj0{=seSq7%<=|QATV(P1TQqp&^ArBs%E&O~D1*p?PQS ze6GUV`;hmDHVK{_EGsRr85#ujz>S`s!(C5ng#JLQj-3p>rF;j2ozg<8o1r^0XR0zV zFaVjN>o*dHrGNq>aSWfI->><5kQ0B26u>RwU&&P}wY}?r#C-wYOtiH74`B>5HCtCz zYTe39s6u%BL^V6)xYYeB%Wo(59Xgf61TBGifoG}+_*15b#mjb<1YDZrMo*Lb7mTA> zcTiwh>>+CEZfKx>A`yr!VEyU-;=FqN z#Hed(JOi_hF@gi~T+xe;fTpsFYCtP8;7%l?2c^DKVacq3N^jeKo(SXVLQ@i_a(A7Af=A=gV(DpLl z29P=i2uoNxU)~4R)t~PF=~;nG$_h}vV=XOa#Iq6P`!3aNjkaRdXP@WlI@CJlKqd1| zo)hCWNA-@O!MDvm;_PeatAzLmlG2wbb6Q9Snh7}Wo{$LDOO_^4KoeYIJEs2N{&gN{ z8fEk|o;?rHXFS83Ey|sXc7$S!?Vf*b6dLa@UKwb5*zY)1`sHcfvQ2iuGXAIdJLIHX z<*U~(fEhGgl3pLsB#}lFP=$IDGNbVS^HNDBK0%z4G!e@9J@x}dX?Ml)<@WU$1~%EWUswJeFMSZ5t4tLRSrdqW%QAp8XbC z#U`56BI-sE4wak2>mo7i;zVBkf+0&Pzr84m6(qz-}8b z@%K3+>5JuuxlP26eug^)$EEGNG!O!rNJp)eJLdL&Wb_)do12$$1_xIXCrA!NWtXqt zxIG@@^bSI|@z9i-u~bIPL;|@oL)>Z=>pK`9?d=%D`}_irt>1X!zx1C1us{Q%ra1D7 zHPJs^lo`2b{pli|S3vU#5~Bct%5{Uzyb?OVKfZr9klFCVy#VgYdr*S2wXyW&?!n9c zEypJFvi~^JFm#%aa==K9r030>NtH@N$NMy{nkS>(LSZ$yYL9$)B@pIIpQw z)E44?^xwt%cO83)!|6y=%<)b9)_}aKgnci#DNeVaNXcWRbm)D1B)LeT8_L!w!RJu= zW^dCUpCbk>7J$lY;MHD*CakS#b9<#qKl##s@Bn;!Lu7SH5}*0OS9RRk@X8|Q2`7Fh zs&SCNWTQOe;J1w|l8XY9*es8kPmwf{Gp800ADu5_<;0n3v(p5Ds7zyH~3y9gg^BoIH%Firj#xECo&;!4 zGA7rrqE~Kz@~MRENsqbQ?g@jI{*^%ajLw6Toy)(c|0i>U%&p#{-e~qWPjh%*m%vy7~$J zw*~v@ZC>A6tl%dyq(OylXcWoNAXz}7?> zb^qGTT9{4(%K0+EvW)p8`0w}HOrS?zb-4pLE+^c}FDpVX3QoNK^o&_G4OO6?MU!OW zx9^UP33)`ABhUd*;i2zuPySjhzb#eC6Wl1=#Xue;4Wx_B5p)2$G|2J8W}HsbbK zylFysp5wLT1g!0r?dSqRyyyBS4zrW}`Pg_ylrA;5DVE9j?^fW?3$UbsO+nm<6h%m< zkp0MitQLW!55F>Sm_5`^A4WxzWb8glj@MjJM5Z}vmF2r5**gFt>Q_r^iJuPj|Ft3L z0uM;ROA2Jwn(0gV;T|it6TZmlQxCL2T6At3ld*()fm~3Hf(KoUwm`0w&0^K&ZtDIK z07ZJbX5CDxSB@V(l#cds_)1;Vp!D16k*y1hUcwPvavtm)-Ht%VE!qF5Qjm+I=^$y7 zIvgkzC(|`@Zrgd5%Jc(3J5fjmA0;VmgR0038(a`m^jA80_p_ndg5s9lHMdYC_v8b;g z)X09r)Mr(GQDY7S7cu;DBSIEpiL7IM6sn%x`tsKl0jJ8xz6a>XQoo`+4GruRM3ZmX36^5B&tFz&{&E zGLqCr{M2abecNe1<=z&Vl$TlhMS&5z2s)^L%ZO{gYRlnT11$(6s^9zoyn$Kv{%Me) z5uE_*e+F!+3n1qc*`~P$P#SKa0{5Y(ZX_}CjC~$Q3hna%W5A4Pxyef9*SL0+g~O((QVrYk`NAAD-XL|m=DjrG7vqs-q_J1AN;1{EVCB#Z#zZ8k^nYdeC5~VGj8P>@)j=Z#X6Cszi;mEN6S_OQzF;rZu0lP z{IgM>$b(hIx3#Kw#>QkIxWM6Jy?XP%zuH8vH}Mh=zTeOfE7kq=wv;9CL>i3Jpx62B z$^X3i7o0%B4?ibcNQ_U97QdbLZO5K41YV^#6;^pn-q-(MJ|=X!WP5{K{rYR;EGIM# z1D^hW|L&i6_veQC-+B4p_42#b_;VlOygMB=`S&5>Mz=nO856wjQ8za1rb=K5d`?T# ztsg%DAF~;#4j=);G59sW|H1&|P}6VsyT=AOaaVxYz=Z9UhX2~TUo>%PsP7yu5|bZduX_V5(|E%-)$cCUep_dG zZy|_VxTyqPpe=ya8_>(^ol)=p{Qt9o zluX(&uARpF<*~@r8J6#sC}jD#3(47RIV*a^y~%I5SPt^Dgen_a#>)vGiGSj#zyNqo zLO$*__0uzs`|n_G7V#cx>SqGK_Vu8yVTii#l9tXe9U(@bo$7%r=m~(yEd~{$cM7M@ zd<=6qa4+#c1E17=50F)9F5U5%SqELa@;*Jozd(-g&m*_Hi>AON-C_67O6{RiPc4C5 zt<|$#t?jMAUz0%{c>(Xk863a&j`RJ=!LnI2{}3GN zIW^liaGDK@Bltx(JJ8Mo&yCXocSTp_S*m08=Rg5+p_^VOi0Yl!jLb=Yp zWJlnU-k+XI;jw7WmI|I#2l2|sYb0{<$tHd`D-* z4H~|Yvm~V1g-rlhp^T;jaMLHvD69PRK(jb|WB!WCiqu`+-D>f}tXkh4_eJ0vPG$yw z`pv!?N0EEw{>HJ^J$zake~PseQ%v>d=j7yd(KUGmoEU~ ztAmevT`Yjn!a%JTQ@Y3OBMqt?J+@vnU7tE0{gep1f&Mw zAsTCMmrI=nb#Avw7Xc#Q#lM^}gRZkowlW>?b8xoEboJSHX0sdLU%*vhrK5~Iw{{Q`Qjg1Mr zYpaJh0*Ny{i`1>Tm%j`iRMxZq8^`d1AdZ@Rqf$1=A-l7EIO(?!Ib`E<#{b5{zA(cI zTDAzX&KQUBiwSi6UB2m=e#Vq;Jp$96wO(6(#=AHU0pIzTJ!xk>V@|W6LH|F$U}NKn zOEyj6e{LrG3W3T~ffDsXe#?$H@shR9zwbXg5nR18p-SvOE7(Q|2Kaz${X76FE>~ZE z_s_%FFoAjb=ZC+WK*{qUh_yBQ=Dqayuz&e!fw~a#q&&1^^zZ%k$6gJIUMv3h8#93B zl3joN!5PRCH?SR-1nLXVK%SVu5maL7*z<1)?n^URxCSG8nQ#B~cEAi=aCr83+sH7g z(Vo;!Vy0<%u)fq@`L9R#D>RXTP$kI2+g1ip$KbPMY{P%c#jM)8V6nz{t zPyYKGUq|P zR2_7ZJS`eO3y-D;-|^+^i?W;%qb;eLn$`&}?EHBz(TdZ(O0R}}^w_W6DEgoHW41F` zKzuQrq9lI|(-Ge&HLw2CbNSy$CHQ3uQNK|2y5bp6*bxujc#PB6$}?sy8ak|;9cJRs za3$i<*!Dql@L^SG5wSdO1l1{algEH)Xm@9r?DsYIr3kD5FWXd*))W*4rJ*wbPCE}p z(t38q&zeE!27R}mKunBZbbszK1kRg%WJ#Yoi(6R_Kn+p zWyA^a6Kee1p8{ilHHw@kx8@imJESw7R`iyve zCI0jqUxOS$&3QTwNo{zQ6hs7k^ZxWVd;iyazeNP*nBt8(0Q}#B)(>TpY>Pa65jlOA z^eyA}(oUYhz9nMP7#74B)q^gi zNyRCWU%FSD@P+Q7*gFUHHKa+W!}g@VSk3L)lGCe=(ryUb-0i zjy!pxoNYp~PO)H9E&rnzfL8J5_WpfpC64|*cVM0*MeiH7+9Y00=$gd58v|EAl&*9e zGWJ@mKYF&+rG(74mj8K^&d&&Rr!`xjZkhp18NZj?@qQ|{Jc9%M5JWtLfLzbMS^frq z%%$_cGK?i#t~>R*_e!Hihj{g#3`~x+XntFJt8Bik;g1_g3gbLj7O2wluS##{4E(@+ ztLN}$-o5ke1HVQnrk>N7WkUN+3Bs$1tux$oRjl`$i2V?kfEP$)e_iH+BcRVy*DIhr zLF~~2@{bcUhXxYdI`^l>0XUcIa{6lE{j<|jz1q5ZhtmG)%u-+bjB1_30wXQhaf0N7 zJ2>0#cKH)Dp7!fT%f1nB&&^nB=`B&r_9PfsyE1tB^nK>;^XKDz689%1X8c^OPP_XT z6!48cBYazMG(Ywf<^c!wieOc*l4#-=I4B>#zWP>6l-_AtI6dD!d zX!Nwcps?qFLr0Lc-(}ql_739o*&u`f2Q)VEy#a!d#5EHxH-!LP*#a{4vrlRtPB<&1 z09wSi`O26xm!>*6>F|Hh0={56QF0p~$L{ZOz3T+`Ln()-9|tnuIA=MbG5w2H!@uhO zPun_h_hrRripZRu*Lp{(qb3mP>UF=GNZbF52RdhpQ}C&TBR#F<-bDTxWAjQuP@!pU z(SN?no*{TIkh3F0_5RNPu!{@$U?Cg?#*51S$IeK;0=cjE!;$U=P9srjCi@|O4{dW5 zrWQZ0GPGrMhJjds;J;*>qqDqVE6BG*5pY@iDkB2{aW_?kS()27F*LWmNn&_5uA^vV|l?z|o+)UBH~2$>uLD0N}u- z4ZFz^@Dcvu_x_Mcbz89Gf3+O(n`_{U2J<24SIQZf#K;XevS~fuK*{2dAK9Q__oK$^ ze#q=^ZTJ^^8sGj6v|OMBuFJuPo~qyN=AUVg1!m|iKFSeQIm25xfN<3NM@DC*9{nJ6 zG>g2m<+ls{JrVbzLI1BV*vRT~_&@)UBK!~IFP;X73phCkfQzyb)H?N8|=JquYEfw0-$4Z$-WKP@z1kz3V5Sv`Lg z4yAR|)NR|C@CX08hksCE8(lC+x1D~^iz!l}g`-FOSuGhBL(l)`TYx49_!cT*wz{9Z z?)>&v|N7_(JrZ^p?HQW{T%e$Z@5Nm)u0Qu$Bi!8 zx|dGF&dt9b#tZnReZ1&o=-Ri)14CCU$>f`;m9oWgC&_EPyD1O;SS(-flxolbp*}<3JL_q)hL@k?Z`@E2cJ^7P+(!{^{<8-)kh*QEp zo2zJ7{%uf!?2nBDKcdm;-So^gFu z7g$KArNP`s?<9WzS~0s9u1A{R%Q3rg#+}5S$3{!JG%d;hw&f1Qu$OheTQ!4@5QFc3 z{w$7rRzJ^ z43_Rv|3OHJ!_TDVTkp^Wd^q6e!iF1wb94d7rV&9Y@JNnw#Xs0Gje+K+yjFtDzmIfE z;^FG?lQFcr$k%un91jOf*xvJQeB+?yeUB61Pho&x^1}DU`D<@Xg=WLi&9L(vUrsXa z|MpyeePqc53o9c9P~pVVUHg;*72`DW5T4|yTr+b>r#3;v$T z4xA<6Tj3CI%X5ka$F&3$pfP{@3ZjG=@SlqyS#7)rT1C**8~~!1z#qW@=pZozoVCbB z9=EZKr@x;Sk~z5PZH2ccR#jlUa;AU;&RgZpwl&x zq0!w$om}|l-nUrxAXmC?`2S|j;p8JVfn00eGS_W6iJJA7gZ>L`HHn9(rX4PIdM}pc*lGkp@ZnnL zMBJc#kG*S%hpjMdP~^l2|1-6q(66i|Tjrg~%Z57TgKE@2_00pC!8sO#z0e zP&%ltGJC8lK#43zr^_XR`;UJ3dWBO#Ess;K-&H0Ds=6c*IM{^~u60LVJ9U zI8Eu(*UDN+oUf7>ka|O;F%WPi_h(ML{M(mHuj+)8B{iu|5BEVNb|?d?o{ zMt~S685$6x!OQK#{@V%h=SRt35cG0q+{@};Gl>0X4rlM*WFxx3A56fiy|3Qx`sXA%p>LWz7sYI_`P^Mefb7 zsfKH$*baB0%Y9MCg#;GX!Iw-bsn?$+ssZRs@*XazB=`yi!V}eNp-kXM5U*z)l7Q)B zo%brmdGPfuWpd*wGDXzWMF`M1o1q$>y>8IGhZf@3tpj4XpwE(4R)SVALNfheQQe9>}b|)}7=u4)UTM&(sH3da7Go9?OE{LqWmVx4%{^5FHT=+>Ov%yjBPqR?j zTff)F6$%P5Lm|G=2hO(!G`N{Qn;+MK#0Lf>odjaL-*pQkv-8|R3%F3|Hp~D$D5k#E zz`jJMu;g8;7fB=6X&aXxvOq0^;&>Afz%hY1KWT;@JDb#OgBUXmFq?ReKy4Kv#Jbw^ zKV3TwsoR|t;i#QU@crs~^VKQAXFt$bQ7mZ~$g#y}$;&VYJ^a25pCv_bG zarx{Hlz4FhiZ)?@t0I1Zg0HCb(A9!h9cvysr->&VfSMNtZTQH1Mb@zcbnIIB1((KC zV$*~+?04Tcx1MG<*;h^h+yB9MGUX~I_NqVB{mDWhzuV;?#R}JcFq%;6!^=9LTU&){Y^d{_U`%fs8=D`bXdIj>6ypS*r5n!f;qetYE zc98d|Z_j%*Pl3$P_h#pI>dOLOUHjJoj-(Lp2XZ~pCtlPK=L_r@1E!rpfmR6cEZV}K z1MWNX*f}0@N^^F@H3CaHgniIf=F^))idb%*0P9<1bV1znX+Ghj=-awaYv zx($OomZynv23>}bAI{1UgmrG&{3~nAfP7R*~7$jpr)`;Z->Ch=? z2Y%Oo$Cm*2&6+bcQbQS+3W)36@v@#t3X^R z0*Bpo(&0OaWZe9TAn0St4Qzggu373iw)@$Xu?Kw)t!0s&5NO$IYWNcb zady`8X?2W}X=KEr%`0r#03H1ufXz5i%|NmHg+h zg&k0(#vps#4EjBmAo|Fy7I#=6UgLs80+9?#y~^9HhH||fv=RK$k6m=t<<_euz}k(4 zo#5J3n|pt0qPkuMZa#{n@5CGEwidjvDO2_^fEl6PX9)Rm!50!ZNeH8`!5 zwTI#m3DF$^;VqTOJp)L;m0_~4@p4$>!#@blYks@$UV}_+h}g~uTK;;HlgH}jDcnhH zW?82iqL0b9=(AKMsH{mmCF=Lq1$zN|v-o4lhYjYa$ld@4^gs%b1vK^(Y~Z|En6e8I z9_gswmv0=G)J#%D;xHtPbTUf{Uy%#Zy2l?vxoGs@_!jpU3i|KkMVoL$kh6f`sO4iJ z7a6+?FmCsX#G6=QS^8#*-ui$JCPKFK!z*u(N&|m_m>n(ODRwY4CX$zPlcP-b0-nNq zhN>X*nEXKlbUx3?C6=Na4kNFL7ApY1-&m!L?jSi$WY33`SuN@mLXAfj??vU^FUgy} zB8yKs6Y+sVJm1(!Rf9as%eU)ETa^Al$hU(EGWCEarE_(lFch$6$f zlu6TK0r%GQ2H+?}{>fi5Kxv$dNDKl&`n>6;y=66DVN1 zU^LC^kOI`s=tAFS{Uw=cPy=c=)e8v^IQ6RvhScqhv46Ib@Idubsv2*^gZ^B)#eX$*_N!|9+KZYgf zIDDaO8v>CtuhhzN5zqx3t%pfO?GM^M5iaQr?*@gamt|sD8Q4E-Fu=oR$DY&(sD781QE?B9N7+K+vX17M%NQDX4Yd-?Nbfq3l8^=q>LQnkS2Nte4IiKv%{rvmb|WV!aS-k2ATm~Z zcGQz7t@t+6L$@0ocHe1DBdM{s+lrpaES-;LXfe`CoH^=}v}RA1bbpneeaE%Ft{4C zfK>slVHxh5(uLPNa`&o2^OT6V%n9;_!l+!rXATD?zaM>tn6C==$W`Bgc73yz)9~AH z20jcTLWG1yje?ZuYM!8xA-GAzB{gkqY3`oFmtPb=^D`vs?0qUzRrgkvh6i&Rsq;mY z@&+fB=)v->uS+ImYK&Z^ta}_2nwy?)q%F^1Fy-5wjKv$tP50_r5z+xwD{JD4 zPGf*$^9qno6LU zVvJ4XR=Qp7Ef4D6JJ^;#e&!AH|LQWz3&NU-#SrrnJ|>fNQUtZd6Dj9AI}D!Jt8erJ zYc9gA!7$C4TP&yEQ-_)2Cda+IUXk#%kwxHI$M#>czRl=JN>3Y~`6Ly@Q4;dmR>>Q_&baG! zSJEw~BM&X@E=0uVD$N++#mV0NaVLY?>W4?ID;Z4tT0ve^g?gZB>jmwPw8skyJR#&VFleA9#_TTNnErZo7UCSI$Rwv$(U> zD?Ps=jvJ5PrD6^iUj2=VJM;_*gpVnDAB~_Wd7e4no^#aW^oH&E z@i9z585_B)iv@J zoC>9HzNEtzGzDHFPvOP3KG=i0Z)xqCt`~|fZ#3c%=EiN)&<%i z7VjfrpL2aCE{bN8io(wSi8emEnX_UImaEEbw)BoKcRbd$}? z+b@(jX7&4!GiUHArZVwieo3vh@O_~;BMG6$QA2d=vkPbgp69{8q{9Nz@K8#3hj1CB z`W9^L6WD*etkqrMpmiJ2D0@xSOz*k+^+q&mQJy;oo!t7uJf_-hx7l^sNTw?RlP8g* zy7f~DZg!=WE%SE%>{utgT7zm0@PBvYeXZgx*iyFZz zBNU<6MH)xYN@?4A-BWsQ1cPHHdRQnWExF9$NSz7vm33*Ge9~Bi`HN@}DLYOWy||1E z>N0FCgD(m!pngh~imI{Bw8h|V!K^+Jmp>gOLrB+lOyKPMMM=X6rYzVLP1%|#r?V3YOPLQXMx@nf5}!)}2UIUenMZ@?GY6{IcVc)Bn6Zau~>$WdW zxg-tSCHLjpH$gtz)hd3r8?`)#m^J21i>5dSk9LI-2`^-)95k!Agg=5aRhtuNd&|!# zK-@s*ofn-p#H)$$?L=|2GKHU$B-l$q>npQY+9a8RAB$EfvVZfGA2WS^Ibmp{svg%g zv#;yXoZOsZ)+i~ggV=wsMMy75jLp#fxO3`gLIh?Tno+$_g?;sCH%9*^R|u~X`K8Zr zHp|=5qh>@x(*YxaYM;2TNBol3+YH2~DZ)xL4zmDp0kQEz@g@=yAJq4f2~Sogg3xEtSuagg>8ym zyvIb4bb#P|{|{gZfbJIfbjLsJ%WzY$BU#64>&v4LDVxdM;vw*%@g*a3hO4H^@h`8= z1hyYyi%M`xl=dqJ5RKoBVxW5)ahF^+ryz3CGBJO1U!`y#a9|=>lLtPU85r&rCgCEM z8gvNhIAj#Y?b&+ScF7Du1DKyP<5MT@-uVI<_j3t7bY}$F0_N<|eHOc*Ts0-8^@1qi z2&=pSg_~m!({K?-5m3|QpHtRTmUxeW-r}q1#>O$-2PL}n0Sist@i2eBYa>8hv$((O zoa;gg%PjGHB9-K4W%Tyhg#MEtfoI=|Ei8+ ze%f$BF+BaCh4uvTpqP~=-4UFg6b}oi^U(qD;^5S0+FjlZlCSaI9xP<*2w)JJY>1cP z40oTq7dDmTKbf*7w7t&BT#t(s%D>z9W*3Page4tOP{IRuD)~~r&45@zO0MH=w7;mb z9JXuNH}-{pp_N84!k(TWf};m|m3{(~U`wTU12iNM*+VTpG+9;$`PSv0O55s=qOCH= z{na^w7#cBQ_cYISjfp3etT(dx*e>%H3K24Ywyfqc4}NT6DV3z`w|2#oel6oOKR-Gp zlN_6kf75l5>Q-x)?ltV^OIjD=lz)zdXjBgnd^7vlF$MvBt5R=w6$4O&s}G_SNki3} zOjjLIrxp<%AONqEk-Fi>T$6Tarb~ykcE;@}yxJV`nKGlYQ&?w$c2VzvgfM~D$|_I6qq7YosR_Xt!7E`T`{YeaR7^szd|2L_&rRD@NxVy zUh*r-d_9s#pyC5~zxF)Q7qWt;JTB?nys`Xq$GCJ27g4Z&82*x3H46J~>5GB&{UQ6O zRT^3J$dB{F;zk%NS0++WmeX(_0D0Hyw)#ej{eS?E#W76SQi#)a zxDI)i%_}0#b*urX`?MJ8K9&@H3^ungahG3+n2$W!{n*u=@a&tF_;R+za&iYGZTuUb zkSnY~_t~==fm*it93_r1ya7d`R^4>FN4_uFzp~pC7bLH3hu>zA3F^@JDXo~|Yws11 z(-F7xeLA1P|G;%Qrs2m$7nwE<`sg55`bAvJkhnC#l?XScMwz%GnAJn6y+$>Zi;A?O z@xvb6048=>aOkfr19fRd;6nNk#3jhq!L39jR}>dXSSc{Q4!IXJEo5Vs zV_hpyzKMRn_)TB~DW(B26j-Vj+r$G1a!h}~676XHv zt(I~hpy!NA!9QMGK6D|7q81Uj!wkg9J=1Ssmd|_BW3=VjlDzXv>K-0w%X$NrjIgsQ z9_8JTxS;~Au2J?NR7>sDS_n61u0(=Nsv6unay#b=3Wtl+AeR-Z;o2$CxII9+rqf^YgN-46a3j@fZZ~OVF~Mc2z>8x_&zg_dX5GLKrjvc|(yGH8oNuCAMHt~lLH%U0OF`^ET`=fG5Mu}?Gs=I`H z+RHxi4WCq#kxx;ps>cZ7hsA1&T7fp}kEI4oLvfbMxgX$#oTNnK7iOtRl1LYstOJy? zP52xfjk3JHRjT)Gb`I3cjs|XBE~OWSMd|+HBA^#V>_=-j%5p{sUw>}F9)?8?lO?tz zy``Pvq+77XD4HGv+u5I(7r*?#y98S^CfbSRHUNdW0T3qi7|$I3S)v-vMr7!G|0PG9 z!ROxU)jP-xk8983d`r=*fv&jWgiSG`4SRJi2D?MgbXQVOK~LFmx!PLyH!*K^dviXB z>(gVrM8fs=C}j0@evw6rZ4OOP1}DJj_X4Mmeh7~Hy4cWhuwkAYK5WV-L5be2zP|d< zh?y03jey=rA$)glUiKq>C`-_swV+(w(TKoc(jyi{v*J-w3vuW4)2(S4EPCzq{SVG} z9NI`s^V6QPXxRa|AhsB_Z|`sQ+&$hNj?Lp|`5ZNiXbM(MEd_F9mpOJM4Snv5VtJBl z8r_57;aq%a{EPsUP6$HU6?+Ht62APc{1PwwE^!zI-N5~(Q3bvUQ1oL?O(1Q6e2ECU z!r3;elIv8fF!9zq>=bA*kgs`gFWiRjb9fc!r2vy}7I$WCA|u3afvuXL@W z^O>ry?;YDnroGI#LxgVtf~LYte_1v<{tt?;ETznOo>f;SwjHi%OvJoQpp`NIzU|Dy*Gal{(iO#C^_2}TVAvgrXyV3zqaNHjv zTAdL!q~1qB!*C4k`B+^_mRs&U@r}7Sq8=vUQKS3%lt~W;x@&IxoXg~zXlL`q)@*~a zW!0CbPR54oFZrzp)3#noE@wonT_FefEJ#jz{5Up`oqMSH6w9slItTl+TXC0K*qc%(w(G0e6C; zG0UWQ%{Us?&paq+w9QH7Efm!mI1+o+tezFA{6cR5xRfhqSnD~N<`J^yGtFYuv(J}i zMTQl2?u25w06l|tZ?m*InDE49q_hB#s}ga*JF2z(*}9q{ckN=@dg|1pP#IkM5RONh zBafHE{f!Lu$ICNI$YG*+30zWqvw(m=iiZ&XQu)!5^}6hPGcASZk!4EmTt*Um9{Gc_ z{-mmsW^M(#AbRXA>_~Vy<*oTNRqB!AQyF5h%Hx9>ae1%vQ%#xH10Zcj>AL~U_X|J# z>7)Z$h#-b}<$2p`2uG9cO`}qAhXB=6AcceeQRAFLik*vHC(|d1i zU3H7FgC58jXAInE#BNKam-_)EW$b#^fDJNuxQrn{FEPl{lbkFlNJPlp0v(#Z!1?GU}~!HKFYF=B3mgz=xEBDV)kX5EU-}#IJkBX1&$Cn%#ixeKhLa?5rS`mRQs)-sl z@_n!Ia`B6AqE7O774F*JArSe|q)5bo76CD4oV--v4S9?3qilI>^e8+Wm1e=Fqj?R^ zTF@`)_K>jm3Z7bm08C6D3WQ=E#hfAkTqX}}pjej#_-(DG2X zmMVqvrz{;MK`y+HKz-R)ir-zhOGUNa<|47wHJj!Icz>?mrJVLfSm-S;n`)X8;0xv6 z#>_qrl1;Q_t0i?;!50~Hq~}W@qNIN;^bAfn(x*#>y_W@LajWp!G4_N~$gl(rN?{x$ z`;iFyNFp4v9RlMjfL$L_5it&5F#iT6O{;+eyGP6ND1zp>CI1y0H3S!{Z zq1$qy?p=U$cUrM$VX;<@;KxUNrs7T5h|1-8GutKleLNg3>Cryll5CodnMcl|hA-z0 zhtrGJ^zlY4#6bx0L147=xo%HX{w;)@+>(Pb`lhuqCjxh-(?+A!qm;8$B;rAVH+|1_ zLmu4q^W=Q=zDf2GQrFHkhMyScs`6Rhx^TFD3;?)qRqflLBizD{)Vz7jK%FEVz%gFr za}qn9liTq(m8G!Uu3iDAy9ep4~N9UnR z+hz(^Tj#1_(WA@7DS1v@V#vLPyx3VW;-*~yene5*u7&_HwG~?(f39#WYR6n62pMTp zqu6cY{Varzct60d$omUXpe_p!Hs88fBx3d{3yWVr9458UeW{MQ97T_L%aMpgdiUaOBvW$kDw94( zAW)gTzWTa*mj~pwg7hk z?(zl}d6~ZLv&7uDT`WXvwYAsTBB-_W>^Bs~-+If+%3{*E&7@WG8a)|XQ{ zKiq0M;V?M+QQcf5Z=5vJ{AjClA$~UIt=q2b9M>>uZ{FTR(Lzma9pz~H&L`&87oy?| zWGfTng})znTcV{5aQ_l0K z02kHx9fi-=%r9lYS`~7qqd@qshT6&-p@pHe+^!Qwn<~C|pPAAdlp8IY*Y)b!XZe*! zaLv-fo8wkDrYRUY1JwA4`~Xmo_bgA6`RVPx&IR~L*|i~E*CeEWZDFs*r%RWu)^VN7 zG~ui}@UMnRSOR8<1oLKi#03Wp{FpTl0s6jgviZ}`^ZzOf3Yxf?(- z#l?T*hLK&3v@M`n^L(UM`znI&`{wws)x7fvBN#05b|au0}U$XVr9{(i~T6XTH%GO0^3aSTu0}`}?AV<{&$n zTTU?ez%R!~_L(r3VHm~lj!@iFVe(rF8i}B9RODw(!7N%(Hn%t*C{>wS(NGMNB6Vf& zAjzbkVDmDp*8!{J`kZw&nE|PE{7tNfeu)xE2I9<>AnMv`2kVWZGk?*%2&^Zh$fyvWSGDhSQlt()`rIU-;>$9~rFt0pKH(pxOexcvE z*0u7j<+aB+onPFGPYYKP$0`J}TU3SEsYUEoZgmU+hJgHw#e8b_5i<>z)_BV&q{tKC z?z7KlPuMfVWZjGaLR}_*o?5`?;;OIci_ZO?M!A&Hjlkkjx2aX|OZH(q*Et{0 zaE)y;I{~~_ZX<~ywW~RJA%3Z@>|w6xn^JN_%kItK_>u5=o$nmi_i4+#J4mMM!|tnP z5ZDDqym}7azpoA)!1q+=5EUKw$+@|BL5hR@l;+kNNBV%+JW&ewWC22ilyScXe zK$d}!jzIC_E1~$Pd)K{^`eMnY&xT z>a8muFSieoi#wOZ$1hyjf0ofrcPD%)imyu~ijyf-l(^1TZx50ej?O(Tl^ z+m5@Z*EWn8zNZeTL=0KwDZY@yOkXC^&+fUMo-smNTn2GS(j{Tegbh^wL{ov4&-g?x zR6SShwz2x%M7nELje-74#aww<{N%VqVvh!Qb$?jLB6;ASJVS9S9rPLS3keb z$}l>ho)6`dOjiMz2>EC}uc|nIyl_;)^;sn^6%q_`^UASGR-~Bp zZW5gC1FtvUFrge(D&XERUVM!xRkt&J{ykynR~0#Iz{A1{#OEk4E7K5b)NWNKCeA$O zOPyo@O2VP#LD*K;&+74OL`9a1+JyA^_65?Dqu+h9Xt8s>AIYXq2=HFPVT9N3`E8XI zWp((*4P4gzxK50eBY$c6fgCNlS#guoP#3p2#6aRsSY#qTy&C#5E3tIq$p>DR=R7k9 zDrIj$$(0=b6W%JgORnB7J|g*4nVX9$aRGR8HV6}JNw43eG?siJ2@PBiR;lE|d5 zR?3-aIE+Ak%X61lr3FPK?H~rh@Es+|_L1z@6>B6jsX{_LpG$EC3?#5H5&Z<*+pox< zx>jA*JVY#&5mdxj;voun3vfQOu;yihLx=7bk9jn$R0)-x$}~>jXhEYG*!X%l`Fe+z zyP>LzPp30OPZc!oF(BDRJ_EqnlW>kb$ddKPVJ5b6ffciA(i29jnI`q@6XXfCoc(x# zp<~u9*v!Lk(Sk9^=tTFfUB$0n_n~U`P)$-!nKpBjmF69f5$9e2kXV=scZ$xjDYQGW zI8&sC1jSs*;C6AZ{g|MhqM9QKr+*uUpEDD;KN3%Y6xuayVU zTiX8ePVgCZP6GOX3HV-L+>b$V`b3}BGC@9a(H!xHX=E`%Gu84A~wMSLt6*BvjIN>l*hyXa2HYAUyR zF5VmRVm4Ly<&1e{dJHAkjNzcLPY8|E`IRWoDFVuZiu81EHE&QR$zz#Vtn+B37A#Nm zc#a4ha}kRDy2Tj<1wf}T|M*=(-iqZQtTEmy-&6s!Yy!wS&TMMJ*!d~FJQnAW7^K0F znkdTc8agTTfQub7;WlhsMrwL7&Rn(C&E>-t>&oGmK@!8LU7^)j6|s(r2pa?gxe}=? zRY6Lg*2PQK?80C2Z6Q8;uR0x`6{NE^d(Ldy6-MJR9mowjw2gRvJ5l5#<~QOPOUcSm zJf9bLb!Kl=pOw6-fLt6&JCG+`B>jfD`AHzD!OoSt7vqi`2EHae%Fd;MYmBm9e>!TK zfM}*8$1x9YDNJ`!jw1(Id_z)%&H&9kZWHORGueu7uHlfPqI-a0Vd-pXk9 zjxCVI0~O|!Z7iC{P6r!g3kbx1phOwadH*n=nrSZ^0twksxqgv~!TfMw$o16H=zfVv zaFE52P2DD>b1lDOl+$m8G5;+8yxgj@u%V;7%x z1gj(IT**C5%f+jh9QKi>uIHGMBF@p;q|&ePG1ZALHdr7PeCURex8k@OlP@n0Wi<110~akNFj*>`7P| z3lJHzjI{c*@UkotPylEcFm%fCn({=V)ta}uhQ;$A^)4V<8qyHbeDGjHc(_Vk8iS-> zEL`E7!8)<3PLN_*G>aAkzGBvQ15Z$ck=LQ*|%s5-OP2&4w?#FP+1f-p?nM&1r}q^t|_#&tSLwwXmqu;nKgZEFV44+ zPn_jz7b3bklOV)p^gh&i5YK-w8bRR$t^w=xLCt~R7m zaz2QoEH@!@Hm;XFGR1u?YQOp5(Lo0xeK;*95Ur-cN;My{9LaZG*jh+1DlGxugj4<9 zHT*?+#xJo1x43^n^0@KZ@71fs-uNM80D^JAMnIo#CvfzJHp{C)#8uPOV>NEGy)vV? zr7N7jhhBITWQzPolnlSyTiJynk)4tRvz+nofc3~!;%HfMaqTL~3w8`gSj9z2z3N2% z^ogA)VTM8J$Co|r0YfB?y^W|E=JF>ot^&DXQvlX$(X(&_eE;*}QE7^84V);>5&MVpIOXog=JLj~pc1U@3!i2WzW9*N@=7_jkrwu=^*N z!V0rx?u~xs4hqF;Zi$Y+)k;LAjzP!|l0W-Ez+@MO&(NUtHDk&XG3zr1M7x%7%X1mj z`~_x%`OBr@JzUNIPkV0}7G>AA4FeJb2+RAR$OM0wO8h2mg$@vDu zZvl-$qk^d}NqR&$ZhN14%ietW!Hf z7^DV9PH^gD==~x)S!~6K^4@U_C9C)lQfz3JR=6@xMU2GdbDDJvM|Nbc!A})YYEdlU zd`C}#7*3gW0AYzCyRdLmk3A%|F@zTEhpC6vL+xpu(}*S^S(43Gx6(W<_~WO(xW8R~ zd*HUcy^3Q=zVa6BJbiJP+I)Fbq2N#4lD>hD8M3NNDh&-{pH+)U<-1yTOuu&w8i(-4 z;%j>l*V*p~M@A`*Q0224MHX+>uMfw4hOrO??sB^*e|-LhhYH3p`fH(JIujZ{%+o8P zeA3v>7%8g|(j5Z;L^hx)X$)U;^EI^|IqB!U)x>l90fZ=KVyEWFgXeG91DL6QwJdT1 z7_mgSIF=bjCXeXE^=$aD2V01B;qNUS2NIR)v8dJ%Bzhnta?W?fuCuxqq zT}1~@m-<5Fs%=Q6cX5g-qR%SDzr)-1lAr3 z(fOD;BwJpLP}TXkXFHr-G$Hc^skD>D^Cy-Hu2nPpAF&NmG1|qz&ek5~HzV+HDQBx5 zyQYNmvMCZ`^VCBw>wLiP`2A#D!4pjxS^IvMpzAC5LrwL24?!Q(y*v{G>nY@~}`+mso&BTV||~`W#(FAk0|Qj28^N-w38FTs9F8 z8NZ?kT|zf?(S)-q2noZpsb#FF*a$T1U}c6`HU2!R()B@KJ{fFAWr6?neSPs%wA z48B?=St;F1TL0gBl_>e%4ghGNlzUOI+A)>)J~ISLLuMC1el_vw?NcBTWw{xkg%Nw# zN%R_;m>O_Ncza`ZF$1@s+2q#V@0{{mL)uEQR?wG2wr{lhB;`4-53pj(gM&hEj8S@* ztw_KWoXK+5;fL^_FF;U;Y{#{^EBh!;JW1QUo_>*y&Z!mC6bRss`*Dt|(jF&;5SPDS zA1UlI5S_v~&AcQZD0MTo^gr>v0-bZi{`PuDidmrMe+pe{s|S6iU2)djn)_v5&;mwK ze!GYGh5RZ4W32Uo><*#~_;KR3^N7B?Lv+HZWeInoOF0T{yctR5AQ@o3tevWzI0~^xl4sMktd>-))tba=deU1hIF0+ zX?{FZT2yRk_Ie4GolA8Zxg>CS5;HE*Vj&^~PHZyC>n<*BMLf zg(6gRM5b`WkT@ zZ-yZFD@|G&E#Msp3vAT%W1COfHv7v9N8bIc9_2Rts}U6Q%z19h+dCPoMGXbYK&0MD zUk3$RieJvMWyJ{Erm}zmX;_X6*?DppXY0s21{RaTZZwJ{$Dq5Ay zFJ=zW2^wz1w09Uu-rXGWK|8IVQw3cn-NEvG8)X&OVCV%2-92G> zpIDP_9Fg@Ld8wL&-*B=EY~wR?w)Zb~!OO1)!rSxTS(ZTVr`$-0Q<8G-6oT$h83cnp!P zQ4A>rI`@Q1&`?0C3((p#64uvRyS0L(*XHSOMx0L%ZevE=B`vN;`?Be~A9Ag^Xt8l0 z4R<4kMA6M1tvd_i)|{^}w8Ft16@x(Nh`OIf8F+1;7>3>UW|fqPA;c|`+(EN%s4@9A z=I=cqWOP@)!CB)i0DVh{p;aqv`I}`UAPlxCSe&g^jmTBlNi|vojX;lF z?rA`&HY5iZ0)yACpm!mOgHnGuP_^z9>41qU`nFA}7T-yfhLA|POgI4~0u*?qZrS07 zPs;b~e*~U@>hEVQ&1bDPXETRs#^WcyVBq&rM&^;DQsxzt(bde-3E{Y=y=G}15mdi5 zuxKF*n>rN%t1zq`YP+|v5jH2m;<{i|kAQ3$ZIZ~3D85C$sA%KksWDTOU-wH;jPcrW zgS^9|wF)Uh_ij%|cSB{NAsmeEVZy3FeK3j!qmytLlm%+O;^AE?26?U7OrXOQZq;+NmM2<=Q5S zU5X@~sk51pCxI9w0@}C3Af~!V*q|;GvqKUgG?Xl`<1kq^|8#;m=fLM6fxbTOizcJ7gKfpf>>Obq|4HJT(()Hn-hX;cj3acm1ALqFT(-sDR0Aa{fIb zA?S54MAIs?QJ3w_b2INHy$6s=T*c;Ngx$s?n8lMvc;EfJ6)=|L*>yBT*YnhMtnznt zxh+bXbWEqU0_L3iUD;{6z`-N*`?O0UIwyA14pf+8n({tLzJ@S4Omzp}i|KOkR0|jq zpnl)J(5G2{{hUX-wMIb}!gn_L$1Sb*fJ!Q&vdJW;C(&{u<94OavOk*0)P)&5mWnT`Jce$kJ-#6Q_3Ex1OjllR{Wg>#S93nP=(P}eOQDue zru-p!Fc;+E=oK89VD}Y3GENhCz595&Is$t(VRzq?F5(@1LR4H#>9twLm7$kh}3RVa)1mU%$jD&`tTkseeaNAuU4^ z+?chE1gEW0DI36^qZ37wHs&1xT3R&f5nreNEJ+HEDFCtARme!bW@IOylGhyrtn!ps zPg_nvGfI(b$mtu=zR7Sa%AAF~2ZK=mN3ZofY6o4^VCDp>t zQ+Q9){_z?|=S;+Xvpc!&^+_DJPVQ|-jw&$XT&s+DL`_@tmN{|W>P+R-1+teIx0e@Z z8nZMHs|gl<`TXgUqo1HnHJ5+THQSB1v|ma)UuO?KB&vxo84Bs)iI<7y{vMO3;{?;G zq#YYZrznZ`!ixu;3?MI=?GuA)et%+}HPW%Yj)PS>B-Ffze0V!Cy$V!}fKhUVmtDUV z``~jQIpQ)b(v3jd_PW^(T1Ojj+nMh7J@@op2iOw zmMe=mU5%nxzL~NXc>7A1Ce4Zhw4y!$o;0H@fW?Txc+kCar>fGg+jl-qptvz%*z5wh z5>WqGt5MJ>JuCi0aZh2BZjTb0i;y>*I;G1YxC-)@eUQ4Xt;F6k0Ne~X@4*=8N58T0 zZef5yeF$1mRMUOb+4uB1W5NSVboOc(VfeM+6QDed&}$TqW=S^Uy&I$!O7w{*vfC4g zjS3^#a>|6W+!i$NawdM|7F?fjXO#TTxj&QoEK*a{KA0*(@x&BIiVVnn@jTYt~B=j6OoX|KJK<~2FveP-|6?$%Njs8 zbSxsg=H<_Uh1VlA__+Kdo*)e!EHAA?BAef z0AKG9-IDpU@jB5A@?45&2_^w_!@+MPITc;XR9rnV=Pw2!EZG34v}%b;EswTLqLV1* z=&TY_E0CNqwfO+henNN>qYM#IfQk9gdZq{{6H$_9#V=P%ABJeE>%cR{Frfm6A=)pzkM$o+Wn!#h_UwDz~2W?oUq zVBB){b>h-mCAu{jhFjoAaU$j8+3~_>pFCeJqMFf{N07t&4qD*zUWnj#yMTE8sqya3 zET`M@*TPugY)B|KolnsNfJs4W)h#G5p`@>k(WA|N>8lT*G6Lbe zEI$b6TaA6LhC-3D_Po233Qb?cJbH&9D!%FBmd7F>LxJ7zt5=Vc+Nh#BfcKS5K$6 ztJ9R>TM*5LZpHE&@9pq7M%^hkxA^pmvgcUB$Uf?z`(Yi$w>{*D5vcsyef(H$`ENId z<2ZDT-X#EL<+W4{hEvtj7a$9$phd?P{~6)_l;r}@P<-BXl0I+HpN?Q^U0ZSVJ4hD} zkmfO<{wjXOfszk@;ImaT(GGfG@)b=o!bP{j+tWtRT5lxUsN6$Qxm6}A1T>Q7W%0o< zheS@vK#y_DAAE$J??N4)2&TIc)L#k7Kq`Bc`!JnBSu1N9SmvnUM@mJ?3V~FrGJ^mv zS#Y~EMz&DE?fCuvi@nV)}OJ9ZWeiA(gt96=jc3hSNM%nLjtUhe;QP=5VM7 zgb+WX?yN(ocvuKJ4y$DIX7z1rcAYFZ_-)B8ZV?ko=bD)%MeMK)reb`Rfa%GyEE+A! z7QE*DsWPbb!%y*thV-O9N;CmlI7|11} zTZM18s*AeqFB`@@Xs}Wxx)Cv*K$^fPUZoHMm6nCXF%rNZ@s|CXYcC=)^K>Z;$7MK- zgJJG_^%yc`q{s*IHM6-z?qrab34e++N4FBf z`8~PUt9~gIlEO^oT-&~3pFlg{ZlCEAbz8)&Rr>+DghuJM1P%2Sr?6wQU4!NWDW{av zO(|w(ZCD#YR`e=mE*?(kO;xZ1?aYjmgNa2IbHuH5c+6=Sx#fa%%sE3 zO5EGw9GwFTLX6+3tQoc%41PLHzp3biKEWUrb1H*XCPd^EeEdPlYnWOlfS-4GQj1R( zt%J?J?ifH!O^LAK7G})Tfto4!Vm*8N2s1>+!q!OiNAa$CrJxm`aA|X7ASs$It0@ykJ|gm9fIp4&Oh1|6p)BgGy@3F zTX(=372(0PjXzNrYRrsg<5T@I~W%D z(c}@%1#|^oc?%Rwxo+6+XoU>vGK6`Sn6$5dIgD7m;-|{I1o&<$sNg#?qRQYik+4ug zu4>JwYH4QErB|^^5l|rb6c~*SWEPJQ2wvbT-qWHFyJcjeim%iyKIHV>TAA?#48m19Nm8zFX)+&j=! z61wBFDi%miWw|W134e)S`KFq({Ro|56iyVYaevDhcQsGUcn4<-DD~YyIn`gmlv>^2 z12UJ6LrVgp!mt=OS&-6~U{jvyE|D$ZdCd6|$`)^Zz3H_tc?6urFd&TB((@5eWLO*x zT6dzNeX@kR`jXL2_)QCd66a!o7;8d%uzfP$I219>zGSo&F+Fm zoAO|%oM$Ss+rKKS@>qnVU?s~hQH*%=X3`$N|C4%!pDhj^%t{T)Jw!`Rn%ETF|)kfN=%b+ZPY4oiIWsuqxdiN=yDy*{9aiG=CR{vZap*N5+)qJ2g@neRFg zIg5o>cK*Ve=G-aCYdurh|k32#27dXDZp4{^@|2;<6DdM)kA#c;Ma z5VWjFsHUTIWF-;BT;(H=?NcKisH!*mb$-dX?dNEPn3u#;)M2`0D1z ziRqXlk*ooco%iG3Hsmqs(m5w&1hGX~hjIk|sGu!2ZnP zMY1Q-u}*toxeVv3dIYsuA8L9Y?=X<7jwUCiMnm@A1Uq0u5sxu<6rn+I%#(yU*`L8F z;=&sw%#MuLwgdRbY)ayr8-_H^aB>b`$p&(&6%XQV$_7GxRTg|@5()_3d<_mbQ*t~V z6FOT_4PPeL9L2kaTu>s13<*uY#Y({QQP&#AdT~%;M4Bn)8EuHGPgy=6qdeJ78vFf{ z%DPkdW6YqY50Y`W0_(loy7oCzP^R_MI@<+un4ADd;_PI{@ru>PqT=!y`-x$$WSEP# zwK5lr5hhUc_QpR-mVinV$2y&dPQ$w80^o|=FT8}uaik9;bzP@4iuPzhf565Cio0i2_m;9n+_xy7ETa&|rjN@&+QH2-pbA`CTZ?_FM z7YvluAml9pj}@r*z88eElf*x`G2}*gzYqrBPPh5!HMqv<8{mo}intVcA(m~7MtNRV?^ojDU95L#-k`VCN zc1kS-3J5~hRCt?Dm07!fK*;L?gdi@G&O$YAhK0L+b?$}jaE z_OC|MirGsWu*e|Rk5ivP6I9!d_2MoIAjhwSl%=3Ys51qB)a)&n zwFnJKCWRw$<2H7jn(;D2t6M$QRf`*(1|gDO*eS$1bT#*Af6&8nB{HtR>?3<7qK=y7 zOna~gD4M4Il^F}yZL9ZngSN~sd=>0FFEDTpbrj} z0HekC_LqX^;uXd1C-?%g`jQoFNEaRW;|fleucK?2Ty-VuPYudcD+IW9ihV=@_gOen zK5Sc0phzVjM2(o_hQv5mR zBmVgyR?pjqd}pi%rN;;-caUlQEdH=G=C!UX(69E;4NDSa&3TdI&2;fgph_3@mft{u zGr`6pv2ItWx3o(uW_+&1GPUFu7#sh=nwuby z2Kz8gYcIxPB-EOV$PeV0s3;*lIn>1cTCK|%Lt!M2N;e>T+n+r4AbEr#rIBc{qNEe-81kosbtvsZ3&AG|!$qOSU_Mby7Ac-`1lM{4mZ^hZt%ngbnh<{R~Z z+-<7}lW414J73wp@H6t(%sSazG0)tpxmXn}EWjlI^aplEx9&y%93)p$8#~lM;^%4U z#@7U-Q=^t@UO3oT*Z@(&_u?dYe-yfxxEC^sWz0rr?~BNU6RaU4;?3CSL#_-*NIxzq zK2AE54_}$CvFq~rrg#iT5^FC2-AsPF@wYt6VI^anALJUMUmHDC3O)J|Z?D}B)69LQ z)}uRU3-~*pQss8`2poNI3DAttm-J$OMMD3~wLVrS_xX8v5<`F_Xmk@*?fmIj zegiE)o*jgbNXgOC;ZD{nDZXQ1tfWMH)aKn9fVqT$ziTC@^Q3w|g|M-y_zra(iU$4+ zyx;5KSi0NGo-?L!cD$wH(vNW-Uh+rmJ(nF!>XTxu^)W-)Urly66DHTj{b#en?>%=O zH?_$7T&EEpjD`#i$53l!=Pv6{RG2u5dTd%J5G7!bRbd~`0~xT*HJJ%|>b;z$S!!6W z#W#Qus&R=a4Fllv;zQ<%K#<0U2LvccmNve9SlPaU zG31g#@a#G$L7!w-6jikn}tr`8RTP}Hs{eeje5+qx3WzB=W8wM6T&gwelO+RXe;TC^?Qu~#PTfzWR0S}PGfx;o$n4+mFvS@|)qI#^8dHYrUY(?a z#&ql?j62SfRgj-K5=GsnPcz=vY@^v9rJlIXRB=t(l+zaqM22||`Ig*(NQ1s!06$36GsQ2UlN!7aQ%%l9(T#tFhA`X>_+c z0GXUruY;9NgS@9s`sGG8)fqfG=4Q9;|7>x1EM;J?=$A{D1NpUa7L5@>9Q1YrH;*uU zGVtcU2StiJl6q<>&3$9MhN%2OS(?pQNg^%LKFA+WwswKB^?^#L+QCY{+R65}tx(6U z-z({k)4m&HrTVj!xAw+uM9kE*sCmpn`mg1F8L}o(^L^Cp)8GXvbA2UxrG2#yGxnOY zDvKNs^P9(dd43jxa2YY~2wTnm_2=D%U~^_20 z-vUK4nTCtX?I=2f8#jT@ZugA`P1QdEPp3uU6U2b*e6#Ns0yYtGv@wwm>|s;W>DCuvl)-HdwBH&GdNm1M?bg3MyKZqqZXGA)ubg)1rd` z1N&#eEZ7!|X;*eURi|hN=KlT&u8ECBji2jZs$Wqn6@x=~W73AA2@WP*lYScu*|hFfFIQyH2G`a!q&q0 zV#3cD67-+OUj_%TVV6r@$b?WIMrs{{QGSXp>CPMm>XDO)%(4imCyIgMt~qaZ;UJ3J+3@(h1fA2 z{a08Z3Qz7Q;k6sT{oZ5CfX{Zc=z5HW(BJn2+N}pJQ65AS^Jk`#ageu$bziwFrgLQQ zTstZBI|@FND;-#WmcW{+a})x&hsqv1klA){Y?JzDB2Tatqo||!YX0t)zw7_^S`e(c zj-uOw^wM~mEdRV5|9%MjjwF=%xvT9ToA_rl|MOoU6dMv05}=;=&%5*Q6`>!1O|O zhS3r@xt73ecY35Q+iHkA^o|Aa<1N4U%^&uhdaNK$G~%Y8T6pltv3A0!fI-fUZDymp z(3JIh=UlVJM65$oLS|?ec!>hFDT>|_-n#dE7xHbqSVuvK{Eq=}A@~ibaaXpRb_7QX zHH5%<$K!px$%95_Jg_os@%xBA2d3Vc2H!9D*qV0k;%waqv^!IhD*4KZs$~W>i^ocb zlH${=_ba9WZo6)J!+xSX^Q5@jVfD)jAW`QB1&Csz>$HF;8J`v?Wtler-d8yQ>FIQ! zoH|6~(#=p{J63{!;!d(s>bvcOo|2J*sLa{d3pZ?6!%g4hfnyw|Gf%FmYO!t)ElRL| zp#`lP5*HSwS$9p_yRUt+hq$AU`h3=1z;l$QmM)kISURCW|0C>z}MN z@1HR7H(p8knkkkJ$Pn8QlR3VCyqVz~bGk_{ zlib1)1oBlp2Y~i8?RaY@9j*Ntz1&G@!Vl*5frzGo4R~FSfMr?AQ|P;c_;m7GNB*E^ zW4UTMQzC(HNN>@a~&i>weiYPN5uGIR^^qov#k4vtD-OYX>zCr+#gcAlnHMxi% zn%he2iupPiIPY_Syx$D84{TbdPV^4}Sxzdw-)S3=c&8`;$GZo*g;{%ni3@@NbwiT9uK5_h~c~4wzOj5}xzGq5|bAK(;(@T4k z;?!c~@W$`V<^T}(rlQaD@4t=~HmBbA1KLMBfRuualmmy<|J^_4R%==Gkn?{4xEluM)`u{+}0Y5N${0 zH9A446oqwl(!C#*CSbK$?0n9C=T(7-Zn@EvALj)SVDG|WKp)0vkVro!9?g^BTQAh< zL)_;Rf$xz9T*yh?(g*$GqaVCn#d4o~j=Cwhn*;Bz?4q+%2zp-F4Ft#TtN=!CL2$SW z76-xCrwg?>ZJWej?@ZTx;kTb0oYOaVGfu0`5iC55-6?+x{0Bk(F!_qLd#N-(qPcdq zj*BNO+}5t53`pxtMAO}T3(0KHMgW*D;R zZU*Q@)M17I!P9hr{ODLY)1-qWqTPP>+kkB={$mzGGkYO8LR`3Xjq2hc=@YS7-`o+d z?uP+8v4mqAi}nZ#PWv|mv^o`!@AJ8>X&wMcf>g@K&)YV?HBI0;fXK`4D`@N6BGo64 zO}*z;1&YraW+P;;H>A7VHpaQ0U70>5U@G{EIzebpq8XGioV(x zuz24@PC6Y_6{@9M>LZ7K0Li>SwT$98`fzc6U@^a;B`;R`h32d089DAKR^_(7R0i>0 z!j>7YO;&t^ZGJK!mF~-MYRC6D2TZWmF`%vw91=PrsAnI{8&d6kpF5$?A(I*0e4vcmVjShWs)ukqpZ&82t|H?z9u5k7 zCskL}^=KbxNhcr<{%dr}2y7cu9DZ#XFVWX6GV_-iK8FKT)6-OI^np^VkIRNJsQ1y8>WszOV0#f#vyv zo!^YVKAM1Oe{46JN&d3Imu&t`Ko(5dPOJ`X5*dJ@AeT;bMSD;9*oRURYQ{q&jTHgy zAiy*CuCpF$N7Hs5f7%1NjIG0)zUgISroW|#aSQ>249xp276tX?PQ(MaR%<)O^1fzy zgsz<9>u=iYX=x+bQrA#|&kLJr0Jr5aIdyS-k@aZkCA)uEe66hnmrBW^_%54h`6T_9 zyq#g=;CBtqf#2qH_v`3D1M!fDxfkEw%(BqG0?~;VEJ$Pe?PTBYiyxUQV=KtDMO3 zjL!owI{9BsImy(RYy5tnV>d*e_4G^9l)~YP;e2N z z7rlBQ{RAWM0hKC2XO!J^5Dwwy3ZNNx05agmGxd&TN32GrRfv>qj4=5p_W-t1zK6f2 zqz`m)ZK&&$*QJT0a^YcySPyz0pdJq&8M97IynV#ilpcTkMdX=wK9B{N3%xcU{bK&t zxiv_^j^Cv(KQuP=r-}TyLon6c-h1hLT+~te*2zejdr<3dVSm?culrEJ8})SIm3V zWG2;^#hU@_wN&7W^vp)w2P=yOsdjkGSy-wIZ&$P1%~EWD*FO7Z3;d|3S=v>@ZNYdm zFuE7nhIP*@fjJc%{2r~Bjq==?TLCKIH6&gKKGrNZ{f9ywk}KM;GPc=lv+OFG+`Cw& zC)B<<)ooLGmg+q_EJGD^tYwkvaae_yKWYn*PP&$!kutJQW?Ug=+Soker)>SRpl7W) z$u1LAHUu5M-Z+YU5RfYDoI7LRGo<6MpROyYlQC&$eJ+ zGdTO-*u5C9E586|Th2wQYefafd?b1Ku6KkR9SZxhy>v;MHvZzZ(4x~CQM2Q6G3C!MRJf7anLRxigkQ;!CWH4R>7XijVt`0lkw>Gt9ro zZCxyj7eC_}W5lZC}B-(SeO zD*ZQX|2KpV%%uRijUf*rA{lfh)_O2I@Fu@?tPRk+EjH4A*+6_&-tHzq8Szh?Od$*6 zW}J0vZZb^lcCx|P71aktkcyY18L9!zDy*M={3ni<xIQ6@1F-fC2HJBOm-tJpPUQ|J+M5 z30Tl7Y;#YvJN$p$E35#F!20;sKl$zd@yo#5=;H$a^Y;I~4IHWlMliG~WPtpCCi0(q zJt6=bnKbI#e~&s1j39T)u^Rni{NH1!B8NlbS*V)+d(`}31hVhvt^Y~t{EvZHpqEGG zu7|?^81SD92U>#>gj==@+5Yd_K)bcU@+3XkjQ+1t4}lSo{=a@ePT6%+VxHTFb5C#m z*PNh;n}NJiu^`Wz)c4Yv;eU+$pJx`J--;{6p;vO)a(=v(-gq_dvy<>o!uUUH`R9+c qC@1MpQYeq?vM>JoB9fo6u1G>iyC`|sas)BJKP5SJ*>dS8LH`Fe%581{ literal 0 HcmV?d00001 diff --git a/docs/_static/images/intro/releases/2_2_0_bianryrelu.png b/docs/_static/images/intro/releases/2_2_0_bianryrelu.png new file mode 100644 index 0000000000000000000000000000000000000000..f42291551715d784ba43b08f505f28d19bdb8626 GIT binary patch literal 45044 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 literal 0 HcmV?d00001 diff --git a/docs/_static/images/intro/releases/2_2_0_cuda.png b/docs/_static/images/intro/releases/2_2_0_cuda.png new file mode 100644 index 0000000000000000000000000000000000000000..0f002acc516efde8767da324c44234df441eda8b GIT binary patch literal 58052 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 B60-mR literal 0 HcmV?d00001 diff --git a/docs/_static/images/intro/releases/2_2_0_nnapi1.png b/docs/_static/images/intro/releases/2_2_0_nnapi1.png new file mode 100644 index 0000000000000000000000000000000000000000..661a8dbe45154e839da1ed029148d8afedecff7c GIT binary patch literal 45839 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 l2(Xe2BfkIu literal 0 HcmV?d00001 diff --git a/docs/_static/images/intro/releases/2_2_0_nnapi2.png b/docs/_static/images/intro/releases/2_2_0_nnapi2.png new file mode 100644 index 0000000000000000000000000000000000000000..57aab7e73e57ca7313606d1ef54db64b9e77f28e GIT binary patch literal 61836 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 literal 0 HcmV?d00001 diff --git a/docs/_static/images/intro/releases/2_2_0_smmla1.png b/docs/_static/images/intro/releases/2_2_0_smmla1.png new file mode 100644 index 0000000000000000000000000000000000000000..ed2fbe036d5fa9dcf7f07054899267cfefbd3a1b GIT binary patch literal 44242 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%0DF?m@d@vCS0#81431H6Z$PaNWd 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 literal 0 HcmV?d00001 diff --git a/docs/_static/images/intro/releases/2_2_0_smmla2.png b/docs/_static/images/intro/releases/2_2_0_smmla2.png new file mode 100644 index 0000000000000000000000000000000000000000..d5f74e89ba0bc99b69cd5f6e7b52921e05cd6787 GIT binary patch literal 44194 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ÓkO42) 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 %s\n", #success, #log); \ #define STR_IMP(x) #x #define STR(x) STR_IMP(x) #define MNN_VERSION_MAJOR 2 -#define MNN_VERSION_MINOR 1 -#define MNN_VERSION_PATCH 2 +#define MNN_VERSION_MINOR 2 +#define MNN_VERSION_PATCH 0 #define MNN_VERSION STR(MNN_VERSION_MAJOR) "." STR(MNN_VERSION_MINOR) "." STR(MNN_VERSION_PATCH) #endif /* MNNDefine_h */ diff --git a/include/MNN/MNNForwardType.h b/include/MNN/MNNForwardType.h index 37ea3926f..5ecb4b10f 100644 --- a/include/MNN/MNNForwardType.h +++ b/include/MNN/MNNForwardType.h @@ -76,7 +76,7 @@ struct BackendConfig { PowerMode power = Power_Normal; - enum PrecisionMode { Precision_Normal = 0, Precision_High, Precision_Low }; + enum PrecisionMode { Precision_Normal = 0, Precision_High, Precision_Low, Precision_Low_BF16 }; PrecisionMode precision = Precision_Normal; diff --git a/project/ios/MNN.xcodeproj/project.pbxproj b/project/ios/MNN.xcodeproj/project.pbxproj index 959e28187..a8e446fd1 100644 --- a/project/ios/MNN.xcodeproj/project.pbxproj +++ b/project/ios/MNN.xcodeproj/project.pbxproj @@ -340,6 +340,7 @@ 4D9A93D426255ECD00F9B43C /* CoreML.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D9A93D326255ECD00F9B43C /* CoreML.framework */; }; 4D9A93EB26255FB000F9B43C /* models in Resources */ = {isa = PBXBuildFile; fileRef = 4D9A93EA26255FB000F9B43C /* models */; }; 4DAE9B9E2799488C00449DC4 /* structural.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4DAE9B9D2799488C00449DC4 /* structural.cpp */; }; + 4DCC792328FEC5CB00C9BA9E /* MNNGemmInt8AddBiasScale_ARMV86_Unit.S in Sources */ = {isa = PBXBuildFile; fileRef = 4DCC792228FEC5CB00C9BA9E /* MNNGemmInt8AddBiasScale_ARMV86_Unit.S */; }; 4DCF538A2892B15200B5B393 /* histograms.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4DCF53892892B15200B5B393 /* histograms.cpp */; }; 4DCF538D2892B16400B5B393 /* CPUHistogram.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4DCF538B2892B16300B5B393 /* CPUHistogram.cpp */; }; 4DCF538E2892B16400B5B393 /* CPUHistogram.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 4DCF538C2892B16400B5B393 /* CPUHistogram.hpp */; }; @@ -1119,6 +1120,7 @@ 4D9A93D326255ECD00F9B43C /* CoreML.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreML.framework; path = System/Library/Frameworks/CoreML.framework; sourceTree = SDKROOT; }; 4D9A93EA26255FB000F9B43C /* models */ = {isa = PBXFileReference; lastKnownFileType = folder; path = models; sourceTree = ""; }; 4DAE9B9D2799488C00449DC4 /* structural.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = structural.cpp; sourceTree = ""; }; + 4DCC792228FEC5CB00C9BA9E /* MNNGemmInt8AddBiasScale_ARMV86_Unit.S */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = MNNGemmInt8AddBiasScale_ARMV86_Unit.S; sourceTree = ""; }; 4DCF53892892B15200B5B393 /* histograms.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = histograms.cpp; sourceTree = ""; }; 4DCF538B2892B16300B5B393 /* CPUHistogram.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CPUHistogram.cpp; sourceTree = ""; }; 4DCF538C2892B16400B5B393 /* CPUHistogram.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = CPUHistogram.hpp; sourceTree = ""; }; @@ -2480,6 +2482,7 @@ 92FF017C23AA0B4E00AC97F6 /* arm64 */ = { isa = PBXGroup; children = ( + 4DCC792228FEC5CB00C9BA9E /* MNNGemmInt8AddBiasScale_ARMV86_Unit.S */, 4844603C2726558B00F7EABA /* MNNConvWinoSourceTransformUnit6x6FP16.S */, 4AF4FB27269ED243005BA97B /* MNNPackedSparseQuantMatMulEpx1.S */, 4AF4FB28269ED244005BA97B /* MNNPackedSparseQuantMatMulEpx4.S */, @@ -3487,6 +3490,7 @@ 92FF037E23AA0B5A00AC97F6 /* CPUDetectionPostProcess.cpp in Sources */, 4D4CF4682760946500A36D9F /* geometric.cpp in Sources */, 92FF045023AA0B7100AC97F6 /* ShapeCropAndResize.cpp in Sources */, + 4DCC792328FEC5CB00C9BA9E /* MNNGemmInt8AddBiasScale_ARMV86_Unit.S in Sources */, 92FF03D023AA0B5A00AC97F6 /* CPUTensorConvert.cpp in Sources */, CE482F42288536DA007CD935 /* md5.c in Sources */, 92FF02C023AA0B5A00AC97F6 /* MNNAddC4WithStride.S in Sources */, diff --git a/pymnn/examples/MNNQuant/test_mnn_offline_quant.py b/pymnn/examples/MNNQuant/test_mnn_offline_quant.py index 88451a509..ae16d5dc7 100644 --- a/pymnn/examples/MNNQuant/test_mnn_offline_quant.py +++ b/pymnn/examples/MNNQuant/test_mnn_offline_quant.py @@ -9,6 +9,7 @@ nn = MNN.nn F = MNN.expr +F.lazy_eval(True) # adapted from pycaffe diff --git a/pymnn/src/MNN.cc b/pymnn/src/MNN.cc index 6d2533efe..e45ec50e5 100644 --- a/pymnn/src/MNN.cc +++ b/pymnn/src/MNN.cc @@ -658,6 +658,10 @@ static std::pair> MNN_PRINT("MNN use low precision\n"); backendConfig->precision = MNN::BackendConfig::Precision_Low; } + if (!obj_name.compare("Low_BF16")) { + MNN_PRINT("MNN use lowBF precision\n"); + backendConfig->precision = MNN::BackendConfig::Precision_Low_BF16; + } if (!obj_name.compare("high")) { MNN_PRINT("MNN use high precision\n"); backendConfig->precision = MNN::BackendConfig::Precision_High; @@ -2192,12 +2196,22 @@ std::vector toPoints(PyObject* obj) { } if (isVar(obj)) { auto vals = toVar(obj); - auto size = vals->getInfo()->size; + auto info = vals->getInfo(); + auto size = info->size; MNN_ASSERT(size % 2 == 0); std::vector points(size / 2); - auto ptr = vals->readMap(); - for (int i = 0; i < points.size(); i++) { - points[i].set(ptr[i*2], ptr[i*2+1]); + if (info->type == halide_type_of()) { + auto ptr = vals->readMap(); + for (int i = 0; i < points.size(); i++) { + points[i].set(ptr[i*2], ptr[i*2+1]); + } + } else if (info->type == halide_type_of()) { + auto ptr = vals->readMap(); + for (int i = 0; i < points.size(); i++) { + points[i].set(ptr[i*2], ptr[i*2+1]); + } + } else { + PyMNN_ERROR_LOG("Point data type must be int32 or float32."); } return points; } diff --git a/pymnn/src/expr.h b/pymnn/src/expr.h index a8d7495ec..1a596b787 100644 --- a/pymnn/src/expr.h +++ b/pymnn/src/expr.h @@ -57,7 +57,8 @@ def_enum(PowerMode, PowerMode, def_enum(PrecisionMode, PrecisionMode, PrecisionMode::Precision_Normal, "Normal", PrecisionMode::Precision_High, "High", - PrecisionMode::Precision_Low, "Low" + PrecisionMode::Precision_Low, "Low", + PrecisionMode::Precision_Low_BF16, "Low_BF16" ) // class Var typedef struct { @@ -1534,7 +1535,7 @@ static PyObject* PyMNNExpr_crop_and_resize(PyObject *self, PyObject *args) { *method = nullptr /* BILINEAR */; float extrapolation_value = 0.0f; if (PyArg_ParseTuple(args, "OOOO|Of", &image, &boxes, &box_ind, - &crop_size, &method, extrapolation_value) + &crop_size, &method, &extrapolation_value) && isVar(image) && isVar(boxes) && isVar(box_ind) && isVar(crop_size) && (method == nullptr || isInterp_Method(method))) { diff --git a/pymnn/src/nn.h b/pymnn/src/nn.h index 12ae4d517..206b47e11 100644 --- a/pymnn/src/nn.h +++ b/pymnn/src/nn.h @@ -361,7 +361,10 @@ static std::pair> MNN_PRINT("MNN use low precision\n"); backendConfig->precision = MNN::BackendConfig::Precision_Low; } - + if (!obj_name.compare("Low_BF16")) { + MNN_PRINT("MNN use lowBF precision\n"); + backendConfig->precision = MNN::BackendConfig::Precision_Low_BF16; + } if (!obj_name.compare("high")) { MNN_PRINT("MNN use high precision\n"); backendConfig->precision = MNN::BackendConfig::Precision_High; diff --git a/schema/current/CaffeOp_generated.h b/schema/current/CaffeOp_generated.h index 61e42fa53..259f0d369 100644 --- a/schema/current/CaffeOp_generated.h +++ b/schema/current/CaffeOp_generated.h @@ -700,13 +700,16 @@ struct Convolution3DCommonT : public flatbuffers::NativeTable { bool relu; bool relu6; int32_t group; + std::vector outPads; + bool hasOutputShape; Convolution3DCommonT() : padMode(PadMode_CAFFE), inputCount(0), outputCount(0), relu(false), relu6(false), - group(1) { + group(1), + hasOutputShape(false) { } }; @@ -745,6 +748,12 @@ struct Convolution3DCommon FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table int32_t group() const { return GetField(22, 1); } + const flatbuffers::Vector *outPads() const { + return GetPointer *>(24); + } + bool hasOutputShape() const { + return GetField(26, 0) != 0; + } bool Verify(flatbuffers::Verifier &verifier) const { return VerifyTableStart(verifier) && VerifyOffset(verifier, 4) && @@ -761,6 +770,9 @@ struct Convolution3DCommon FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table VerifyField(verifier, 18) && VerifyField(verifier, 20) && VerifyField(verifier, 22) && + VerifyOffset(verifier, 24) && + verifier.VerifyVector(outPads()) && + VerifyField(verifier, 26) && verifier.EndTable(); } Convolution3DCommonT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const; @@ -801,6 +813,12 @@ struct Convolution3DCommonBuilder { void add_group(int32_t group) { fbb_.AddElement(22, group, 1); } + void add_outPads(flatbuffers::Offset> outPads) { + fbb_.AddOffset(24, outPads); + } + void add_hasOutputShape(bool hasOutputShape) { + fbb_.AddElement(26, static_cast(hasOutputShape), 0); + } explicit Convolution3DCommonBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); @@ -824,8 +842,11 @@ inline flatbuffers::Offset CreateConvolution3DCommon( int32_t outputCount = 0, bool relu = false, bool relu6 = false, - int32_t group = 1) { + int32_t group = 1, + flatbuffers::Offset> outPads = 0, + bool hasOutputShape = false) { Convolution3DCommonBuilder builder_(_fbb); + builder_.add_outPads(outPads); builder_.add_group(group); builder_.add_outputCount(outputCount); builder_.add_inputCount(inputCount); @@ -833,6 +854,7 @@ inline flatbuffers::Offset CreateConvolution3DCommon( builder_.add_kernels(kernels); builder_.add_strides(strides); builder_.add_dilates(dilates); + builder_.add_hasOutputShape(hasOutputShape); builder_.add_relu6(relu6); builder_.add_relu(relu); builder_.add_padMode(padMode); @@ -4235,6 +4257,8 @@ inline void Convolution3DCommon::UnPackTo(Convolution3DCommonT *_o, const flatbu { auto _e = relu(); _o->relu = _e; }; { auto _e = relu6(); _o->relu6 = _e; }; { auto _e = group(); _o->group = _e; }; + { auto _e = outPads(); if (_e) { _o->outPads.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->outPads[_i] = _e->Get(_i); } } }; + { auto _e = hasOutputShape(); _o->hasOutputShape = _e; }; } inline flatbuffers::Offset Convolution3DCommon::Pack(flatbuffers::FlatBufferBuilder &_fbb, const Convolution3DCommonT* _o, const flatbuffers::rehasher_function_t *_rehasher) { @@ -4255,6 +4279,8 @@ inline flatbuffers::Offset CreateConvolution3DCommon(flatbu auto _relu = _o->relu; auto _relu6 = _o->relu6; auto _group = _o->group; + auto _outPads = _o->outPads.size() ? _fbb.CreateVector(_o->outPads) : 0; + auto _hasOutputShape = _o->hasOutputShape; return MNN::CreateConvolution3DCommon( _fbb, _dilates, @@ -4266,7 +4292,9 @@ inline flatbuffers::Offset CreateConvolution3DCommon(flatbu _outputCount, _relu, _relu6, - _group); + _group, + _outPads, + _hasOutputShape); } inline SparseCommonT *SparseCommon::UnPack(const flatbuffers::resolver_function_t *_resolver) const { @@ -5766,7 +5794,9 @@ inline const flatbuffers::TypeTable *Convolution3DCommonTypeTable() { { flatbuffers::ET_INT, 0, -1 }, { flatbuffers::ET_BOOL, 0, -1 }, { flatbuffers::ET_BOOL, 0, -1 }, - { flatbuffers::ET_INT, 0, -1 } + { flatbuffers::ET_INT, 0, -1 }, + { flatbuffers::ET_INT, 1, -1 }, + { flatbuffers::ET_BOOL, 0, -1 } }; static const flatbuffers::TypeFunction type_refs[] = { PadModeTypeTable @@ -5781,10 +5811,12 @@ inline const flatbuffers::TypeTable *Convolution3DCommonTypeTable() { "outputCount", "relu", "relu6", - "group" + "group", + "outPads", + "hasOutputShape" }; static const flatbuffers::TypeTable tt = { - flatbuffers::ST_TABLE, 10, type_codes, type_refs, nullptr, names + flatbuffers::ST_TABLE, 12, type_codes, type_refs, nullptr, names }; return &tt; } diff --git a/schema/default/CaffeOp.fbs b/schema/default/CaffeOp.fbs index 9e74a7820..550cddd89 100644 --- a/schema/default/CaffeOp.fbs +++ b/schema/default/CaffeOp.fbs @@ -37,6 +37,8 @@ table Convolution3DCommon { relu:bool = false; relu6:bool = false; group:int = 1; + outPads:[int]; + hasOutputShape:bool = false; } enum SparseAlgo : byte { diff --git a/source/backend/coreml/execution/CoreMLActivation.cpp b/source/backend/coreml/execution/CoreMLActivation.cpp index db3f9dcfc..10b8d1958 100644 --- a/source/backend/coreml/execution/CoreMLActivation.cpp +++ b/source/backend/coreml/execution/CoreMLActivation.cpp @@ -91,7 +91,7 @@ ErrorCode CoreMLActivation::onResize(const std::vector &inputs, const core_ml__specification__activation_sigmoid__init(mLayer_->activation->sigmoid); break; default: - break; + return NOT_SUPPORT; } } setLayerInputsAndOutputs(mLayer_, {inputName}, {mCoreMLBackend->getTensorName(outputs[0])}); diff --git a/source/backend/coreml/execution/CoreMLInterp.cpp b/source/backend/coreml/execution/CoreMLInterp.cpp index 984b4f852..a4a02dcf9 100644 --- a/source/backend/coreml/execution/CoreMLInterp.cpp +++ b/source/backend/coreml/execution/CoreMLInterp.cpp @@ -63,6 +63,7 @@ ErrorCode CoreMLInterp::onResize(const std::vector &inputs, const std: CORE_ML__SPECIFICATION__UPSAMPLE_LAYER_PARAMS__LINEAR_UPSAMPLE_MODE__ALIGN_CORNERS_FALSE; } else { MNN_ERROR("[CoreML] Interp Don't support [Cubic, NearestneighborRound] mode."); + return NOT_SUPPORT; } #endif setLayerInputsAndOutputs(mLayer_, {mCoreMLBackend->getTensorName(inputs[0])}, diff --git a/source/backend/coreml/execution/CoreMLRaster.cpp b/source/backend/coreml/execution/CoreMLRaster.cpp index 36ba3478e..058e8b693 100644 --- a/source/backend/coreml/execution/CoreMLRaster.cpp +++ b/source/backend/coreml/execution/CoreMLRaster.cpp @@ -15,56 +15,6 @@ CoreMLRaster::CoreMLRaster(MNN::Backend *b, const MNN::Op *op, const std::vector initLayer(); } -static bool isTranspose(const Tensor::InsideDescribe::Region& region) { - int srcOne = -1, dstOne = -1; - for (int i = 0; i < 3; i++) { - if (region.src.stride[i] == 1 && region.size[i] != 1) { - if (srcOne >= 0 || region.size[i] < 4) { - return false; - } - srcOne = i; - } - if (region.dst.stride[i] == 1 && region.size[i] != 1) { - if (dstOne >= 0 || region.size[i] < 4) { - return false; - } - dstOne = i; - } - } - return srcOne >= 0 && dstOne >= 0 && srcOne != dstOne; -} - -static bool isDepthToSpace(const Tensor* output) { - const auto& regions = TensorUtils::getDescribe(output)->regions; - auto input = regions[0].origin; - for (const auto region : regions) { - if (region.origin != input) { - return false; - } - } - auto ic = input->channel(); - auto ih = input->height(); - auto iw = input->width(); - auto oc = output->channel(); - auto oh = output->height(); - auto ow = output->width(); - if (ic * ih * iw != oc * oh * ow) { - return false; - } - int hblock = oh / ih; - int wblock = ow / iw; - if (hblock != wblock) { - return false; - } - if (hblock * wblock * oc != ic) { - return false; - } - if (regions.size() != hblock * wblock) { - return false; - } - return true; -} - bool CoreMLRaster::buildReshape(CoreML__Specification__NeuralNetworkLayer* layer, const Tensor* input, const Tensor* output) { mCoreMLBackend->setLayerName(layer, "Reshape"); layer->layer_case = CORE_ML__SPECIFICATION__NEURAL_NETWORK_LAYER__LAYER_RESHAPE_STATIC; @@ -295,7 +245,7 @@ bool CoreMLRaster::rasterOptimization(const std::vector &inputs, const return buildReshape(mLayer_, region.origin, outputs[0]); } // transpose - if (isTranspose(region)) { + if (TensorUtils::isTransposeRegion(region)) { return buildPermute(mLayer_, region.origin, outputs[0]); } } @@ -312,7 +262,7 @@ bool CoreMLRaster::rasterOptimization(const std::vector &inputs, const } return false; } - if (isDepthToSpace(outputs[0])) { + if (TensorUtils::isDepthToSpaceRegions) { return buildDepthToSpace(mLayer_, region.origin, outputs[0]); } // region_size > 1: concat diff --git a/source/backend/cpu/CPUBackend.cpp b/source/backend/cpu/CPUBackend.cpp index fbee3e971..c7cb57dee 100644 --- a/source/backend/cpu/CPUBackend.cpp +++ b/source/backend/cpu/CPUBackend.cpp @@ -120,7 +120,7 @@ Backend* CPURuntime::onCreate(const BackendConfig* config) const { } #endif #ifdef MNN_SUPPORT_BF16 - if (precision == BackendConfig::Precision_Low && BF16Functions::get()) { + if (precision == BackendConfig::Precision_Low_BF16 && BF16Functions::get()) { return new BF16Backend(this); } #endif diff --git a/source/backend/cpu/CPURuntime.cpp b/source/backend/cpu/CPURuntime.cpp index 9aa583d19..58073a738 100644 --- a/source/backend/cpu/CPURuntime.cpp +++ b/source/backend/cpu/CPURuntime.cpp @@ -18,7 +18,6 @@ #endif #include "core/Macro.h" -#ifdef MNN_USE_ARMV82 #ifdef __ANDROID__ #include @@ -26,8 +25,6 @@ #include #endif // __ANDROID__ -#endif // MNN_USE_ARMV82 - #if __APPLE__ #include "TargetConditionals.h" #if __aarch64__ @@ -376,9 +373,6 @@ float MNNGetCPUFlops(uint32_t number) { // cpuinfo // Reference from: https://github.com/pytorch/cpuinfo - -#ifdef MNN_USE_ARMV82 - #ifdef __ANDROID__ #define CPUINFO_ARM_MIDR_IMPLEMENTER_MASK UINT32_C(0xFF000000) @@ -406,6 +400,10 @@ float MNNGetCPUFlops(uint32_t number) { #define CPUINFO_ARM_LINUX_FEATURE_FPHP UINT32_C(0x00000200) #define CPUINFO_ARM_LINUX_FEATURE_ASIMDHP UINT32_C(0x00000400) #define CPUINFO_ARM_LINUX_FEATURE_ASIMDDP UINT32_C(0x00100000) +// ref: https://cs.android.com/android/platform/superproject/+/master:bionic/libc/kernel/uapi/asm-arm64/asm/hwcap.h;drc=04da58f5b3bc40dbbafb4f8422aa2991479d9e1e;l=70 +#define CPUINFO_ARM_LINUX_FEATURE_I8MM UINT32_C(0x00002000) +#define CPUINFO_ARM_LINUX_FEATURE_SVE UINT32_C(0x00400000) +#define CPUINFO_ARM_LINUX_FEATURE_SVE2 UINT32_C(0x00000002) #else #define CPUINFO_ARM_LINUX_FEATURE_HALF UINT32_C(0x00000002) #define CPUINFO_ARM_LINUX_FEATURE_NEON UINT32_C(0x00001000) @@ -1400,6 +1398,14 @@ void cpuinfo_arm_init(struct cpuinfo_arm_isa* cpuinfo_isa) { cpuinfo_isa->fp16arith = true; } } + if (isa_features & CPUINFO_ARM_LINUX_FEATURE_I8MM) { + cpuinfo_isa->i8mm = true; + } + /* + if (isa_features & CPUINFO_ARM_LINUX_FEATURE_SVE2) { + // MNN_PRINT("Support SVE2\n"); + } + */ #else // pytorch/cpuinfo: src/arm/linux/aarch32-isa.c uint32_t architecture_version = 0; @@ -1550,10 +1556,12 @@ void cpuinfo_arm_init(struct cpuinfo_arm_isa* cpuinfo_isa) { cpuinfo_isa->fp16arith = true; } + if (isa_features & HWCAP2_I8MM) { + cpuinfo_isa->i8mm = true; + } + #endif /* __linux__ && __aarch64__ */ #endif - MNN_PRINT("The device support dot:%d, support fp16:%d\n", cpuinfo_isa->dot, cpuinfo_isa->fp16arith); -} - -#endif // MNN_USE_ARMV82 + MNN_PRINT("The device support dot:%d, support fp16:%d, support i8mm: %d\n", cpuinfo_isa->dot, cpuinfo_isa->fp16arith, cpuinfo_isa->i8mm); +} \ No newline at end of file diff --git a/source/backend/cpu/CPURuntime.hpp b/source/backend/cpu/CPURuntime.hpp index 2ce52090d..4376553c7 100644 --- a/source/backend/cpu/CPURuntime.hpp +++ b/source/backend/cpu/CPURuntime.hpp @@ -10,12 +10,11 @@ #include #include "core/Macro.h" -#ifdef MNN_USE_ARMV82 struct cpuinfo_arm_isa { bool fp16arith; bool dot; + bool i8mm; }; -#endif /* CPU thread mode, only effective on HMP(Heterogeneous Multi-Processing)arch CPUs @@ -33,13 +32,7 @@ typedef enum { } MNNCPUThreadsMode; int MNNSetCPUThreadsMode(MNNCPUThreadsMode mode); -// float MNNGetCPUFlops(uint32_t number); - -#ifdef MNN_USE_ARMV82 - void cpuinfo_arm_init(struct cpuinfo_arm_isa* cpuinfo_isa); -#endif // __aarch64__ - #endif /* CPUInfo_hpp */ diff --git a/source/backend/cpu/arm/CMakeLists.txt b/source/backend/cpu/arm/CMakeLists.txt index 010cfb538..c61c79b7a 100644 --- a/source/backend/cpu/arm/CMakeLists.txt +++ b/source/backend/cpu/arm/CMakeLists.txt @@ -11,11 +11,6 @@ if (MNN_SUPPORT_BF16) FILE(GLOB MNN_AArch64_SRC ${MNN_AArch64_SRC} ${CMAKE_CURRENT_LIST_DIR}/arm64/bf16/*.[sS]) endif() -# remove the armv82 extension assemblies file -if(NOT MNN_ARM82) - list(REMOVE_ITEM MNN_AArch64_SRC ${CMAKE_CURRENT_LIST_DIR}/arm64/MNNGemmInt8AddBiasScale_ARMV82_Unit.S) -endif() - if(CMAKE_SYSTEM_PROCESSOR MATCHES "^armv7" OR ARCHS MATCHES "^armv7(;armv7s)?") message(STATUS "Enabling AArch32 Assemblies") add_library(MNNARM32 OBJECT ${MNN_AArch32_SRC} ${MNN_NEON_SRC}) @@ -41,7 +36,7 @@ elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^aarch64" OR ARCHS STREQUAL "arm64") if(MNN_ARM82) message(STATUS "Enable INT8 SDOT") - target_compile_options(MNNARM64 PRIVATE -march=armv8.2-a+dotprod -DENABLE_ARMV82) + target_compile_options(MNNARM64 PRIVATE -DENABLE_ARMV82) endif() else() diff --git a/source/backend/cpu/arm/CommonNeonBF16.cpp b/source/backend/cpu/arm/CommonNeonBF16.cpp index e76fd4f6c..abb1bb1be 100644 --- a/source/backend/cpu/arm/CommonNeonBF16.cpp +++ b/source/backend/cpu/arm/CommonNeonBF16.cpp @@ -18,6 +18,90 @@ void NEON_MNNGetMatMulPackMode_BF16(int* eP, int* lP, int* hP) { } #ifdef __aarch64__ +#define EP 12 +#define HP 8 +#define LP 4 +void ARMV86_MNNGetMatMulPackMode_BF16(int* eP, int* lP, int* hP) { + *eP = EP; + *hP = HP; + *lP = LP; +} +void ARMV86_MNNPackForMatMul_B_BF16(float* destF, const float* sourceF, size_t h, size_t l, bool transpose) { + // [l, h] -> [h/hp, l/lp, hp, lp] + auto dest = (int16_t*)destF; + auto source = (const int16_t*)sourceF; + auto lCP = UP_DIV(l, LP); + auto hCP = UP_DIV(h, HP); + int sYstride = 1; + int sXstride = h; + if (transpose) { + sYstride = l; + sXstride = 1; + } + ::memset(dest, 0, lCP * hCP * sizeof(int16_t) * HP * LP); + for (int y = 0; y < h; ++y) { + int yC = y / HP; + int yR = y % HP; + for (int x = 0; x < l; ++x) { + int xC = x / LP; + int xR = x % LP; + dest[xR + yR * LP + xC * HP * LP + yC * HP * LP * lCP] = source[sXstride * x + sYstride * y]; + } + } +} +void ARMV86_MNNPackC4ForMatMul_A_BF16(float* destOrigin, float const** sourceGroup, const int32_t* info, const int32_t* el) { + // [l/4, e, 4] -> [l/4, ep, 4] + int number = info[0]; + int eReal = info[1]; + int eDest = info[2]; + int offset = info[3]; + if (1 == number) { + int l = el[1]; + if (l % 8 != 0) { + auto lAigin = UP_DIV(l, LP) * LP; + ::memset(destOrigin, 0, eDest * lAigin * sizeof(int16_t)); + } + } + + for (int n=0; n [l/4, ep, 4] + for (int x = 0; x < lDiv; ++x) { + auto destX = (int64_t*)(dest + x * eDest * 4); + auto srcX = (int64_t*)(source + x * eReal * 4); + for (int y = 0; y < e; ++y) { + destX[y] = srcX[y * offset]; + } + } + continue; + } + for (int x = 0; x < l; ++x) { + auto dl = lOR + x; + auto dlC = dl / LP; + auto dlR = dl % LP; + auto xC = x / LP; + auto xR = x % LP; + auto destX = dest + dlC * eDest * LP + dlR; + auto srcX = source + xC * eReal * LP + xR; + for (int y = 0; y < e; ++y) { + destX[y * 4] = srcX[y * 4 * offset]; + } + } + } +} +#undef EP +#undef HP +#undef LP void NEON_MNNPackForMatMul_B_BF16(float* destFloat, const float* sourceFloat, size_t h, size_t l, bool transpose) { auto hP = (int)h / 8; auto hR = (int)hP * 8; @@ -63,8 +147,6 @@ void NEON_MNNPackForMatMul_B_BF16(float* destFloat, const float* sourceFloat, si dest[x * 8 + yR + yC * 8 * l] = source[x + y * l]; } } - - } #else @@ -100,6 +182,6 @@ void NEON_MNNPackForMatMul_B_BF16(float* destFloat, const float* sourceFloat, si }; MNNPackC4_BF16(destFloat, sourceFloat, l, h, offset); } -#endif +#endif // __aarch64__ #endif // MNN_SUPPORT_BF16 diff --git a/source/backend/cpu/arm/FunctionSummary.hpp b/source/backend/cpu/arm/FunctionSummary.hpp index efb92df0b..e656a8705 100644 --- a/source/backend/cpu/arm/FunctionSummary.hpp +++ b/source/backend/cpu/arm/FunctionSummary.hpp @@ -46,8 +46,14 @@ void NEON_MNNAxByClampBroadcastC4_BF16(float* C, const float* A, const float* B, void MNNPackC4_BF16(float* dest, const float* source, size_t area, size_t depth, int32_t* areaOffset); #ifdef __aarch64__ void MNNPackC8_BF16(float* dest, const float* source, size_t l, size_t h); +void ARMV86_MNNGetMatMulPackMode_BF16(int* eP, int* lP, int* hP); +void ARMV86_MNNPackForMatMul_B_BF16(float* dest, const float* source, size_t h, size_t l, bool transpose); +void ARMV86_MNNPackC4ForMatMul_A_BF16(float* destOrigin, float const** sourceGroup, const int32_t* info, const int32_t* el); +void ARMV86_MNNPackedMatMul_BF16(float* C, const float* A, const float* B, const size_t* parameter, + const float* postParameters, const float* bias); +void ARMV86_MNNPackedMatMulRemain_BF16(float* C, const float* A, const float* B, size_t eSize, const size_t* parameter, + const float* postParameters, const float* bias); #endif - #endif #ifdef __cplusplus diff --git a/source/backend/cpu/arm/arm64/MNNGemmInt8AddBiasScale_ARMV82_Unit.S b/source/backend/cpu/arm/arm64/MNNGemmInt8AddBiasScale_ARMV82_Unit.S index 64273c791..a7596747f 100644 --- a/source/backend/cpu/arm/arm64/MNNGemmInt8AddBiasScale_ARMV82_Unit.S +++ b/source/backend/cpu/arm/arm64/MNNGemmInt8AddBiasScale_ARMV82_Unit.S @@ -6,7 +6,7 @@ // Copyright © 2018, Alibaba Group Holding Limited // -#if defined(__aarch64__) && defined(ENABLE_ARMV82) +#if defined(__aarch64__) #include "MNNAsmGlobal.h" .text @@ -18,12 +18,6 @@ mov \d2\().16b, \s\().16b mov \d3\().16b, \s\().16b .endm -.macro COMPUTE s0, s1, d0, d1, d2, d3 - sdot \d0\().4s, \s0\().16b, \s1\().4b[0] - sdot \d1\().4s, \s0\().16b, \s1\().4b[1] - sdot \d2\().4s, \s0\().16b, \s1\().4b[2] - sdot \d3\().4s, \s0\().16b, \s1\().4b[3] -.endm .macro Int32ToFloat z0, z1, z2, z3 scvtf \z0\().4s, \z0\().4s scvtf \z1\().4s, \z1\().4s @@ -115,15 +109,33 @@ L8LoopDz_TILE_12: L8LoopSz_TILE_12: ld1 {v3.16b}, [x2], x15 // weight ld1 {v0.16b, v1.16b, v2.16b}, [x11], #48 // src - COMPUTE v3, v0, v8, v9, v10, v11 + .inst 0x4f80e068 // sdot v8.4s, v3.16b, v0.4b[0] + .inst 0x4fa0e069 // sdot v9.4s, v3.16b, v0.4b[1] + .inst 0x4f80e86a // sdot v10.4s, v3.16b, v0.4b[2] + .inst 0x4fa0e86b // sdot v11.4s, v3.16b, v0.4b[3] ld1 {v4.16b}, [x2], #16 - COMPUTE v3, v1, v12, v13, v14, v15 - COMPUTE v3, v2, v16, v17, v18, v19 - COMPUTE v4, v0, v20, v21, v22, v23 + .inst 0x4f81e06c // sdot v12.4s, v3.16b, v1.4b[0] + .inst 0x4fa1e06d // sdot v13.4s, v3.16b, v1.4b[1] + .inst 0x4f81e86e // sdot v14.4s, v3.16b, v1.4b[2] + .inst 0x4fa1e86f // sdot v15.4s, v3.16b, v1.4b[3] + .inst 0x4f82e070 // sdot v16.4s, v3.16b, v2.4b[0] + .inst 0x4fa2e071 // sdot v17.4s, v3.16b, v2.4b[1] + .inst 0x4f82e872 // sdot v18.4s, v3.16b, v2.4b[2] + .inst 0x4fa2e873 // sdot v19.4s, v3.16b, v2.4b[3] + .inst 0x4f80e094 // sdot v20.4s, v4.16b, v0.4b[0] + .inst 0x4fa0e095 // sdot v21.4s, v4.16b, v0.4b[1] + .inst 0x4f80e896 // sdot v22.4s, v4.16b, v0.4b[2] + .inst 0x4fa0e897 // sdot v23.4s, v4.16b, v0.4b[3] sub x2, x2, x15 - COMPUTE v4, v1, v24, v25, v26, v27 + .inst 0x4f81e098 // sdot v24.4s, v4.16b, v1.4b[0] + .inst 0x4fa1e099 // sdot v25.4s, v4.16b, v1.4b[1] + .inst 0x4f81e89a // sdot v26.4s, v4.16b, v1.4b[2] + .inst 0x4fa1e89b // sdot v27.4s, v4.16b, v1.4b[3] subs x13, x13, #1 - COMPUTE v4, v2, v28, v29, v30, v31 + .inst 0x4f82e09c // sdot v28.4s, v4.16b, v2.4b[0] + .inst 0x4fa2e09d // sdot v29.4s, v4.16b, v2.4b[1] + .inst 0x4f82e89e // sdot v30.4s, v4.16b, v2.4b[2] + .inst 0x4fa2e89f // sdot v31.4s, v4.16b, v2.4b[3] bne L8LoopSz_TILE_12 L8LoopSzEnd_TILE_12: @@ -205,10 +217,19 @@ L4LoopDz_TILE_12: L4LoopSz_TILE_12: ld1 {v3.16b}, [x2], #16 // weight ld1 {v0.16b, v1.16b, v2.16b}, [x1], #48 // src - COMPUTE v3, v0, v8, v9, v10, v11 - COMPUTE v3, v1, v12, v13, v14, v15 + .inst 0x4f80e068 // sdot v8.4s, v3.16b, v0.4b[0] + .inst 0x4fa0e069 // sdot v9.4s, v3.16b, v0.4b[1] + .inst 0x4f80e86a // sdot v10.4s, v3.16b, v0.4b[2] + .inst 0x4fa0e86b // sdot v11.4s, v3.16b, v0.4b[3] + .inst 0x4f81e06c // sdot v12.4s, v3.16b, v1.4b[0] + .inst 0x4fa1e06d // sdot v13.4s, v3.16b, v1.4b[1] + .inst 0x4f81e86e // sdot v14.4s, v3.16b, v1.4b[2] + .inst 0x4fa1e86f // sdot v15.4s, v3.16b, v1.4b[3] subs x3, x3, #1 - COMPUTE v3, v2, v16, v17, v18, v19 + .inst 0x4f82e070 // sdot v16.4s, v3.16b, v2.4b[0] + .inst 0x4fa2e071 // sdot v17.4s, v3.16b, v2.4b[1] + .inst 0x4f82e872 // sdot v18.4s, v3.16b, v2.4b[2] + .inst 0x4fa2e873 // sdot v19.4s, v3.16b, v2.4b[3] bne L4LoopSz_TILE_12 L4LoopSzEnd_TILE_12: @@ -271,13 +292,25 @@ L8LoopDz_TILE_8: L8LoopSz_TILE_8: ld1 {v3.16b}, [x12], x15 // weight ld1 {v0.16b, v1.16b}, [x11], x22 // src - COMPUTE v3, v0, v8, v9, v10, v11 + .inst 0x4f80e068 // sdot v8.4s, v3.16b, v0.4b[0] + .inst 0x4fa0e069 // sdot v9.4s, v3.16b, v0.4b[1] + .inst 0x4f80e86a // sdot v10.4s, v3.16b, v0.4b[2] + .inst 0x4fa0e86b // sdot v11.4s, v3.16b, v0.4b[3] ld1 {v4.16b}, [x12], #16 - COMPUTE v3, v1, v12, v13, v14, v15 + .inst 0x4f81e06c // sdot v12.4s, v3.16b, v1.4b[0] + .inst 0x4fa1e06d // sdot v13.4s, v3.16b, v1.4b[1] + .inst 0x4f81e86e // sdot v14.4s, v3.16b, v1.4b[2] + .inst 0x4fa1e86f // sdot v15.4s, v3.16b, v1.4b[3] sub x12, x12, x15 - COMPUTE v4, v0, v16, v17, v18, v19 + .inst 0x4f80e090 // sdot v16.4s, v4.16b, v0.4b[0] + .inst 0x4fa0e091 // sdot v17.4s, v4.16b, v0.4b[1] + .inst 0x4f80e892 // sdot v18.4s, v4.16b, v0.4b[2] + .inst 0x4fa0e893 // sdot v19.4s, v4.16b, v0.4b[3] subs x13, x13, #1 - COMPUTE v4, v1, v20, v21, v22, v23 + .inst 0x4f81e094 // sdot v20.4s, v4.16b, v1.4b[0] + .inst 0x4fa1e095 // sdot v21.4s, v4.16b, v1.4b[1] + .inst 0x4f81e896 // sdot v22.4s, v4.16b, v1.4b[2] + .inst 0x4fa1e897 // sdot v23.4s, v4.16b, v1.4b[3] bne L8LoopSz_TILE_8 L8LoopSzEnd_TILE_8: @@ -343,9 +376,15 @@ L4LoopDz_TILE_8: L4LoopSz_TILE_8: ld1 {v3.16b}, [x12], #16 // weight ld1 {v0.16b, v1.16b}, [x11], x22 // src - COMPUTE v3, v0, v8, v9, v10, v11 + .inst 0x4f80e068 // sdot v8.4s, v3.16b, v0.4b[0] + .inst 0x4fa0e069 // sdot v9.4s, v3.16b, v0.4b[1] + .inst 0x4f80e86a // sdot v10.4s, v3.16b, v0.4b[2] + .inst 0x4fa0e86b // sdot v11.4s, v3.16b, v0.4b[3] subs x13, x13, #1 - COMPUTE v3, v1, v12, v13, v14, v15 + .inst 0x4f81e06c // sdot v12.4s, v3.16b, v1.4b[0] + .inst 0x4fa1e06d // sdot v13.4s, v3.16b, v1.4b[1] + .inst 0x4f81e86e // sdot v14.4s, v3.16b, v1.4b[2] + .inst 0x4fa1e86f // sdot v15.4s, v3.16b, v1.4b[3] bne L4LoopSz_TILE_8 L4LoopSzEnd_TILE_8: @@ -402,10 +441,16 @@ L8LoopDz_TILE_4: ld1 {v3.16b}, [x12], x15 // weight ld1 {v0.16b}, [x11], x22 // src ld1 {v4.16b}, [x12], #16 // weight - COMPUTE v3, v0, v8, v9, v10, v11 + .inst 0x4f80e068 // sdot v8.4s, v3.16b, v0.4b[0] + .inst 0x4fa0e069 // sdot v9.4s, v3.16b, v0.4b[1] + .inst 0x4f80e86a // sdot v10.4s, v3.16b, v0.4b[2] + .inst 0x4fa0e86b // sdot v11.4s, v3.16b, v0.4b[3] subs x13, x13, #1 sub x12, x12, x15 - COMPUTE v4, v0, v12, v13, v14, v15 + .inst 0x4f80e08c // sdot v12.4s, v4.16b, v0.4b[0] + .inst 0x4fa0e08d // sdot v13.4s, v4.16b, v0.4b[1] + .inst 0x4f80e88e // sdot v14.4s, v4.16b, v0.4b[2] + .inst 0x4fa0e88f // sdot v15.4s, v4.16b, v0.4b[3] bne L8LoopSz_TILE_4 L8LoopSzEnd_TILE_4: @@ -451,7 +496,10 @@ L4LoopDz_TILE_4: ld1 {v3.16b}, [x12], #16 // weight ld1 {v0.16b}, [x11], x22 // src subs x13, x13, #1 - COMPUTE v3, v0, v8, v9, v10, v11 + .inst 0x4f80e068 // sdot v8.4s, v3.16b, v0.4b[0] + .inst 0x4fa0e069 // sdot v9.4s, v3.16b, v0.4b[1] + .inst 0x4f80e86a // sdot v10.4s, v3.16b, v0.4b[2] + .inst 0x4fa0e86b // sdot v11.4s, v3.16b, v0.4b[3] bne L4LoopSz_TILE_4 L4LoopSzEnd_TILE_4: @@ -495,10 +543,10 @@ L8LoopDz_TILE_1: ld1 {v3.16b}, [x12], x15 // weight ld1 {v0.s}[0], [x11], x22 // src ld1 {v4.16b}, [x12], #16 // weight - sdot v8.4s, v3.16b, v0.4b[0] + .inst 0x4f80e068 // sdot v8.4s, v3.16b, v0.4b[0] subs x13, x13, #1 sub x12, x12, x15 - sdot v9.4s, v4.16b, v0.4b[0] + .inst 0x4f80e089 // sdot v9.4s, v4.16b, v0.4b[0] bne L8LoopSz_TILE_1 L8LoopSzEnd_TILE_1: @@ -541,7 +589,7 @@ L4LoopDz_TILE_1: ld1 {v3.16b}, [x12], #16 // weight ld1 {v0.s}[0], [x11], x22 // src subs x13, x13, #1 - sdot v8.4s, v3.16b, v0.4b[0] + .inst 0x4f80e068 // sdot v8.4s, v3.16b, v0.4b[0] bne L4LoopSz_TILE_1 L4LoopSzEnd_TILE_1: @@ -576,4 +624,4 @@ ldp d12, d13, [sp, #(16 * 1)] ldp d14, d15, [sp], #(16 * 6) ret -#endif // MNN_USE_ARMV82 +#endif // __aarch64__ diff --git a/source/backend/cpu/arm/arm64/MNNGemmInt8AddBiasScale_ARMV86_Unit.S b/source/backend/cpu/arm/arm64/MNNGemmInt8AddBiasScale_ARMV86_Unit.S new file mode 100644 index 000000000..37ae702fd --- /dev/null +++ b/source/backend/cpu/arm/arm64/MNNGemmInt8AddBiasScale_ARMV86_Unit.S @@ -0,0 +1,582 @@ +// +// MNNGemmInt8AddBiasScale_ARMV86_Unit.S +// MNN +// +// Created by MNN on 2022/09/26. +// Copyright © 2018, Alibaba Group Holding Limited +// + +#if defined(__aarch64__) +#include "MNNAsmGlobal.h" + +.text +.align 5 + +.macro SET_BIAS s, d0, d1, d2, d3 + mov \d0\().4s, \s\().4s + mov \d1\().4s, \s\().4s + mov \d2\().4s, \s\().4s + mov \d3\().4s, \s\().4s +.endm +.macro Int32ToFloat z0, z1, z2, z3 + scvtf \z0\().4s, \z0\().4s + scvtf \z1\().4s, \z1\().4s + scvtf \z2\().4s, \z2\().4s + scvtf \z3\().4s, \z3\().4s +.endm +.macro MUL_SCALE s, d0, d1, d2, d3 + fmul \d0\().4s, \d0\().4s, \s\().4s + fmul \d1\().4s, \d1\().4s, \s\().4s + fmul \d2\().4s, \d2\().4s, \s\().4s + fmul \d3\().4s, \d3\().4s, \s\().4s +.endm +.macro FloatToInt32 z0, z1, z2, z3 + fcvtas \z0\().4s, \z0\().4s + fcvtas \z1\().4s, \z1\().4s + fcvtas \z2\().4s, \z2\().4s + fcvtas \z3\().4s, \z3\().4s +.endm +.macro Int32ToInt16 s0, s1, s2, s3, d0, d1 + sqxtn \d0\().4h, \s0\().4s + sqxtn2 \d0\().8h, \s1\().4s + sqxtn \d1\().4h, \s2\().4s + sqxtn2 \d1\().8h, \s3\().4s +.endm +.macro Int16ToInt8_ONE s0, s1, d0 + sqxtn \d0\().8b, \s0\().8h + sqxtn2 \d0\().16b, \s1\().8h +.endm +.macro Int16ToInt8 s0, s1, s2, s3, d0, d1 + Int16ToInt8_ONE \s0, \s1, \d0 + Int16ToInt8_ONE \s2, \s3, \d1 +.endm + +asm_function MNNGemmInt8AddBiasScale_ARMV86_Unit + +//struct QuanPostTreatParameters { +// const float* scale; +// const int32_t* bias; +// int32_t maxValue; +// int32_t minValue; +//}; + +//void MNNGemmInt8AddBiasScale_ARMV86_Unit(int8_t* dst, const int8_t* src, +// const int8_t* weight, size_t src_depth_quad, size_t dst_step, size_t dst_depth_quad, +// const QuanPostTreatParameters* parameters, size_t realDstCount); + +//Auto: x0:dst, x1:src, x2:weight, x3:src_depth_quad, x4:dst_step +//x5:dst_depth_quad, x6: parameters, x7: realDstCount + +//Load from x7: x8: scale, x9: bias, w12: maxValue, w13: minValue +ldr x8, [x6, #0] +ldr x9, [x6, #8] +ldr w10, [x6, #16] +ldr w14, [x6, #20] + +stp d14, d15, [sp, #(-16 * 6)]! +stp d12, d13, [sp, #(16 * 1)] +stp d10, d11, [sp, #(16 * 2)] +stp d8, d9, [sp, #(16 * 3)] +stp x21, x22, [sp, #(16 * 4)] +stp x19, x20, [sp, #(16 * 5)] + +mov x21, #4 // sizeof(int8_t) * UNIT +mov x22, #160 // GEMM_INT8_DST_XUNIT * GEMM_INT8_SRC_UNIT = 20 * 8 = 160 +cbnz x8, Start +mov x21, #16 // sizeof(float) * UNIT + +Start: +lsl x15, x3, #5 // x15 = src_depth_quad * UNIT * UNIT_SRC = src_depth_quad * 32 = src_depth_quad << 5 + +TILE_20: + cmp x7, #20 + blt TILE_16 +LoopDz_TILE_20: + ld1 {v0.4s}, [x9], #16 // bias + mov x11, x1 // src + mov x12, x2 // weight + mov x13, x3 // src_depth_quad + mov v1.4s, v0.4s + uzp1 v12.2d, v0.2d, v1.2d // bias_0, bias_1, bias_0, bias_1 + uzp2 v13.2d, v0.2d, v1.2d // bias_2, bias_3, bias_2, bias_3 + mov v14.4s, v12.4s + mov v15.4s, v13.4s + SET_BIAS v14, v16, v18, v20, v22 + SET_BIAS v14, v24, v26, v28, v30 + SET_BIAS v15, v17, v19, v21, v23 + SET_BIAS v15, v25, v27, v29, v31 +LoopSz_TILE_20: + // src : 10 x [2 x 8] : v2-11 + // weight : 2 x [2 x 8] : v0-1 + // dst : 10 x 2 x [4] : v12-v31 + ld1 {v0.16b, v1.16b}, [x12], #32 // weight + ld1 {v2.16b, v3.16b, v4.16b, v5.16b}, [x11], #64 // src + .inst 0x4e80a44c // smmla v12.4s, v2.16b, v0.16b + .inst 0x4e81a44d // smmla v13.4s, v2.16b, v1.16b + .inst 0x4e80a46e // smmla v14.4s, v3.16b, v0.16b + .inst 0x4e81a46f // smmla v15.4s, v3.16b, v1.16b + ld1 {v6.16b, v7.16b, v8.16b, v9.16b}, [x11], #64 + .inst 0x4e80a490 // smmla v16.4s, v4.16b, v0.16b + .inst 0x4e81a491 // smmla v17.4s, v4.16b, v1.16b + .inst 0x4e80a4b2 // smmla v18.4s, v5.16b, v0.16b + .inst 0x4e81a4b3 // smmla v19.4s, v5.16b, v1.16b + ld1 {v10.16b, v11.16b}, [x11], #32 + .inst 0x4e80a4d4 // smmla v20.4s, v6.16b, v0.16b + .inst 0x4e81a4d5 // smmla v21.4s, v6.16b, v1.16b + .inst 0x4e80a4f6 // smmla v22.4s, v7.16b, v0.16b + .inst 0x4e81a4f7 // smmla v23.4s, v7.16b, v1.16b + .inst 0x4e80a518 // smmla v24.4s, v8.16b, v0.16b + .inst 0x4e81a519 // smmla v25.4s, v8.16b, v1.16b + .inst 0x4e80a53a // smmla v26.4s, v9.16b, v0.16b + .inst 0x4e81a53b // smmla v27.4s, v9.16b, v1.16b + .inst 0x4e80a55c // smmla v28.4s, v10.16b, v0.16b + .inst 0x4e81a55d // smmla v29.4s, v10.16b, v1.16b + subs x13, x13, #1 + .inst 0x4e80a57e // smmla v30.4s, v11.16b, v0.16b + .inst 0x4e81a57f // smmla v31.4s, v11.16b, v1.16b + bne LoopSz_TILE_20 +LoopSzEnd_TILE_20: + add x2, x2, x15 // weight += dz * src_depth_quad * (GEMM_INT8_UNIT * GEMM_INT8_SRC_UNIT); + sub x5, x5, #1 // dz-- + // transpose + uzp1 v11.2d, v12.2d, v13.2d + uzp2 v12.2d, v12.2d, v13.2d + uzp1 v13.2d, v14.2d, v15.2d + uzp2 v14.2d, v14.2d, v15.2d + uzp1 v15.2d, v16.2d, v17.2d + uzp2 v16.2d, v16.2d, v17.2d + uzp1 v17.2d, v18.2d, v19.2d + uzp2 v18.2d, v18.2d, v19.2d + uzp1 v19.2d, v20.2d, v21.2d + uzp2 v20.2d, v20.2d, v21.2d + uzp1 v21.2d, v22.2d, v23.2d + uzp2 v22.2d, v22.2d, v23.2d + uzp1 v23.2d, v24.2d, v25.2d + uzp2 v24.2d, v24.2d, v25.2d + uzp1 v25.2d, v26.2d, v27.2d + uzp2 v26.2d, v26.2d, v27.2d + uzp1 v27.2d, v28.2d, v29.2d + uzp2 v28.2d, v28.2d, v29.2d + uzp1 v29.2d, v30.2d, v31.2d + uzp2 v30.2d, v30.2d, v31.2d + Int32ToFloat v11, v12, v13, v14 + Int32ToFloat v15, v16, v17, v18 + Int32ToFloat v19, v20, v21, v22 + Int32ToFloat v23, v24, v25, v26 + Int32ToFloat v27, v28, v29, v30 + cbnz x8, Tile20Quan + sub x4, x4, #256 + st1 {v11.4s, v12.4s, v13.4s, v14.4s}, [x0], #64 + st1 {v15.4s, v16.4s, v17.4s, v18.4s}, [x0], #64 + st1 {v19.4s, v20.4s, v21.4s, v22.4s}, [x0], #64 + st1 {v23.4s, v24.4s, v25.4s, v26.4s}, [x0], #64 + st1 {v27.4s, v28.4s, v29.4s, v30.4s}, [x0], x4 + add x4, x4, #256 + b Tile20LoopCheck +Tile20Quan: + ld1 {v0.4s}, [x8], #16 // scale + MUL_SCALE v0, v11, v12, v13, v14 + MUL_SCALE v0, v15, v16, v17, v18 + MUL_SCALE v0, v19, v20, v21, v22 + MUL_SCALE v0, v23, v24, v25, v26 + MUL_SCALE v0, v27, v28, v29, v30 + FloatToInt32 v11, v12, v13, v14 + FloatToInt32 v15, v16, v17, v18 + FloatToInt32 v19, v20, v21, v22 + FloatToInt32 v23, v24, v25, v26 + FloatToInt32 v27, v28, v29, v30 + Int32ToInt16 v11, v12, v13, v14, v0, v1 + Int32ToInt16 v15, v16, v17, v18, v2, v3 + Int32ToInt16 v19, v20, v21, v22, v4, v5 + Int32ToInt16 v23, v24, v25, v26, v6, v7 + Int32ToInt16 v27, v28, v29, v30, v8, v9 + Int16ToInt8 v0, v1, v2, v3, v16, v17 + Int16ToInt8 v4, v5, v6, v7, v18, v19 + Int16ToInt8_ONE v8, v9, v20 + dup v11.16b, w10 // max + dup v10.16b, w14 // min + smax v16.16b, v10.16b, v16.16b + smax v17.16b, v10.16b, v17.16b + smax v18.16b, v10.16b, v18.16b + smax v19.16b, v10.16b, v19.16b + smax v20.16b, v10.16b, v20.16b + smin v16.16b, v11.16b, v16.16b + smin v17.16b, v11.16b, v17.16b + smin v18.16b, v11.16b, v18.16b + smin v19.16b, v11.16b, v19.16b + smin v20.16b, v11.16b, v20.16b + sub x4, x4, #64 + st1 {v16.16b, v17.16b, v18.16b, v19.16b}, [x0], #64 + st1 {v20.16b}, [x0], x4 // dst += dz * dst_step; + add x4, x4, #64 +Tile20LoopCheck: + cmp x5, #1 + bge LoopDz_TILE_20 + b End + +TILE_16: + dup v11.16b, w10 // max + dup v10.16b, w14 // min + sub x10, x22, #64 + cmp x7, #16 + blt TILE_8 + mov x16, x5 // dst_depth_quad + mov x17, x0 // dst + mov x18, x2 // weight + mov x19, x8 // scale + mov x20, x9 // bias +LoopDz_TILE_16: // while (dz = dst_depth_quad) + ld1 {v0.4s}, [x20], #16 // bias + mov x11, x1 // src + mov x12, x18 // weight + mov x13, x3 // src_depth_quad + mov v1.4s, v0.4s + uzp1 v2.2d, v0.2d, v1.2d // bias_0, bias_1, bias_0, bias_1 + uzp2 v3.2d, v0.2d, v1.2d // bias_2, bias_3, bias_2, bias_3 + SET_BIAS v2, v16, v18, v20, v22 + SET_BIAS v2, v24, v26, v28, v30 + SET_BIAS v3, v17, v19, v21, v23 + SET_BIAS v3, v25, v27, v29, v31 +LoopSz_TILE_16: + // src : 8 x [2 x 8] : v2-9 + // weight : 2 x [2 x 8] : v0-1 + // dst : 8 x 2 x [4] : v16-v31 + ld1 {v0.16b, v1.16b}, [x12], #32 // weight + ld1 {v2.16b, v3.16b, v4.16b, v5.16b}, [x11], #64 // src + .inst 0x4e80a450 // smmla v16.4s, v2.16b, v0.16b + .inst 0x4e81a451 // smmla v17.4s, v2.16b, v1.16b + .inst 0x4e80a472 // smmla v18.4s, v3.16b, v0.16b + .inst 0x4e81a473 // smmla v19.4s, v3.16b, v1.16b + ld1 {v6.16b, v7.16b, v8.16b, v9.16b}, [x11], x10 + .inst 0x4e80a494 // smmla v20.4s, v4.16b, v0.16b + .inst 0x4e81a495 // smmla v21.4s, v4.16b, v1.16b + .inst 0x4e80a4b6 // smmla v22.4s, v5.16b, v0.16b + .inst 0x4e81a4b7 // smmla v23.4s, v5.16b, v1.16b + .inst 0x4e80a4d8 // smmla v24.4s, v6.16b, v0.16b + .inst 0x4e81a4d9 // smmla v25.4s, v6.16b, v1.16b + .inst 0x4e80a4fa // smmla v26.4s, v7.16b, v0.16b + .inst 0x4e81a4fb // smmla v27.4s, v7.16b, v1.16b + subs x13, x13, #1 + .inst 0x4e80a51c // smmla v28.4s, v8.16b, v0.16b + .inst 0x4e81a51d // smmla v29.4s, v8.16b, v1.16b + .inst 0x4e80a53e // smmla v30.4s, v9.16b, v0.16b + .inst 0x4e81a53f // smmla v31.4s, v9.16b, v1.16b + bne LoopSz_TILE_16 +LoopSzEnd_TILE_16: + add x18, x18, x15 // weight += dz * src_depth_quad * (GEMM_INT8_UNIT * GEMM_INT8_SRC_UNIT); + sub x16, x16, #1 // dz-- + // transpose + uzp1 v15.2d, v16.2d, v17.2d + uzp2 v16.2d, v16.2d, v17.2d + uzp1 v17.2d, v18.2d, v19.2d + uzp2 v18.2d, v18.2d, v19.2d + uzp1 v19.2d, v20.2d, v21.2d + uzp2 v20.2d, v20.2d, v21.2d + uzp1 v21.2d, v22.2d, v23.2d + uzp2 v22.2d, v22.2d, v23.2d + uzp1 v23.2d, v24.2d, v25.2d + uzp2 v24.2d, v24.2d, v25.2d + uzp1 v25.2d, v26.2d, v27.2d + uzp2 v26.2d, v26.2d, v27.2d + uzp1 v27.2d, v28.2d, v29.2d + uzp2 v28.2d, v28.2d, v29.2d + uzp1 v29.2d, v30.2d, v31.2d + uzp2 v30.2d, v30.2d, v31.2d + Int32ToFloat v15, v16, v17, v18 + Int32ToFloat v19, v20, v21, v22 + Int32ToFloat v23, v24, v25, v26 + Int32ToFloat v27, v28, v29, v30 + cbnz x8, Tile16Quan + sub x4, x4, #192 + st1 {v15.4s, v16.4s, v17.4s, v18.4s}, [x17], #64 + st1 {v19.4s, v20.4s, v21.4s, v22.4s}, [x17], #64 + st1 {v23.4s, v24.4s, v25.4s, v26.4s}, [x17], #64 + st1 {v27.4s, v28.4s, v29.4s, v30.4s}, [x17], x4 + add x4, x4, #192 + b Tile16LoopCheck +Tile16Quan: + ld1 {v0.4s}, [x19], #16 // scale + MUL_SCALE v0, v15, v16, v17, v18 + MUL_SCALE v0, v19, v20, v21, v22 + MUL_SCALE v0, v23, v24, v25, v26 + MUL_SCALE v0, v27, v28, v29, v30 + FloatToInt32 v15, v16, v17, v18 + FloatToInt32 v19, v20, v21, v22 + FloatToInt32 v23, v24, v25, v26 + FloatToInt32 v27, v28, v29, v30 + Int32ToInt16 v15, v16, v17, v18, v0, v1 + Int32ToInt16 v19, v20, v21, v22, v2, v3 + Int32ToInt16 v23, v24, v25, v26, v4, v5 + Int32ToInt16 v27, v28, v29, v30, v6, v7 + Int16ToInt8 v0, v1, v2, v3, v16, v17 + Int16ToInt8 v4, v5, v6, v7, v18, v19 + smax v16.16b, v10.16b, v16.16b + smax v17.16b, v10.16b, v17.16b + smax v18.16b, v10.16b, v18.16b + smax v19.16b, v10.16b, v19.16b + smin v16.16b, v11.16b, v16.16b + smin v17.16b, v11.16b, v17.16b + smin v18.16b, v11.16b, v18.16b + smin v19.16b, v11.16b, v19.16b + st1 {v16.16b, v17.16b, v18.16b, v19.16b}, [x17], x4 // dst += dz * dst_step; +Tile16LoopCheck: + cmp x16, #1 + bge LoopDz_TILE_16 +Tile16End: + sub x7, x7, #16 + add x0, x0, x21, LSL #4 + add x1, x1, #128 + +TILE_8: + cmp x7, #8 + blt TILE_4 + mov x16, x5 // dst_depth_quad + mov x17, x0 // dst + mov x18, x2 // weight + mov x19, x8 // scale + mov x20, x9 // bias +LoopDz_TILE_8: + ld1 {v0.4s}, [x20], #16 // bias + mov x11, x1 // src + mov x12, x18 // weight + mov x13, x3 // src_depth_quad + mov v1.4s, v0.4s + uzp1 v2.2d, v0.2d, v1.2d // bias_0, bias_1, bias_0, bias_1 + uzp2 v3.2d, v0.2d, v1.2d // bias_2, bias_3, bias_2, bias_3 + SET_BIAS v2, v24, v26, v28, v30 + SET_BIAS v3, v25, v27, v29, v31 +LoopSz_TILE_8: + // src : 4 x [2 x 8] : v2-5 + // weight : 2 x [2 x 8] : v0-1 + // dst : 4 x 2 x [4] : v24-v31 + ld1 {v0.16b, v1.16b}, [x12], #32 // weight + ld1 {v2.16b, v3.16b, v4.16b, v5.16b}, [x11], x22 // src + .inst 0x4e80a458 // smmla v24.4s, v2.16b, v0.16b + .inst 0x4e81a459 // smmla v25.4s, v2.16b, v1.16b + .inst 0x4e80a47a // smmla v26.4s, v3.16b, v0.16b + .inst 0x4e81a47b // smmla v27.4s, v3.16b, v1.16b + .inst 0x4e80a49c // smmla v28.4s, v4.16b, v0.16b + .inst 0x4e81a49d // smmla v29.4s, v4.16b, v1.16b + .inst 0x4e80a4be // smmla v30.4s, v5.16b, v0.16b + .inst 0x4e81a4bf // smmla v31.4s, v5.16b, v1.16b + subs x13, x13, #1 + bne LoopSz_TILE_8 +LoopSzEnd_TILE_8: + add x18, x18, x15 + sub x16, x16, #1 + uzp1 v23.2d, v24.2d, v25.2d + uzp2 v24.2d, v24.2d, v25.2d + uzp1 v25.2d, v26.2d, v27.2d + uzp2 v26.2d, v26.2d, v27.2d + uzp1 v27.2d, v28.2d, v29.2d + uzp2 v28.2d, v28.2d, v29.2d + uzp1 v29.2d, v30.2d, v31.2d + uzp2 v30.2d, v30.2d, v31.2d + Int32ToFloat v23, v24, v25, v26 + Int32ToFloat v27, v28, v29, v30 + cbnz x8, Tile8Quan + sub x4, x4, #64 + st1 {v23.4s, v24.4s, v25.4s, v26.4s}, [x17], #64 + st1 {v27.4s, v28.4s, v29.4s, v30.4s}, [x17], x4 + add x4, x4, #64 + b Tile8LoopCheck +Tile8Quan: + ld1 {v0.4s}, [x19], #16 // scale + MUL_SCALE v0, v23, v24, v25, v26 + MUL_SCALE v0, v27, v28, v29, v30 + FloatToInt32 v23, v24, v25, v26 + FloatToInt32 v27, v28, v29, v30 + Int32ToInt16 v23, v24, v25, v26, v4, v5 + Int32ToInt16 v27, v28, v29, v30, v6, v7 + Int16ToInt8 v4, v5, v6, v7, v18, v19 + smax v18.16b, v10.16b, v18.16b + smax v19.16b, v10.16b, v19.16b + smin v18.16b, v11.16b, v18.16b + smin v19.16b, v11.16b, v19.16b + st1 {v18.16b, v19.16b}, [x17], x4 // dst += dz * dst_step +Tile8LoopCheck: + cmp x16, #1 + bge LoopDz_TILE_8 +Tile8End: + sub x7, x7, #8 + add x0, x0, x21, LSL #3 + add x1, x1, #64 + +TILE_4: + cmp x7, #4 + blt TILE_2 + mov x16, x5 // dst_depth_quad + mov x17, x0 // dst + mov x18, x2 // weight + mov x19, x8 // scale + mov x20, x9 // bias +LoopDz_TILE_4: + ld1 {v0.4s}, [x20], #16 // bias + mov x11, x1 // src + mov x12, x18 // weight + mov x13, x3 // src_depth_quad + mov v1.4s, v0.4s + uzp1 v28.2d, v0.2d, v1.2d // bias_0, bias_1, bias_0, bias_1 + uzp2 v29.2d, v0.2d, v1.2d // bias_2, bias_3, bias_2, bias_3 + mov v30.4s, v28.4s + mov v31.4s, v29.4s +LoopSz_TILE_4: + // src : 2 x [2 x 8] : v2-3 + // weight : 2 x [2 x 8] : v0-1 + // dst : 2 x 2 x [4] : v28-v31 + ld1 {v0.16b, v1.16b}, [x12], #32 // weight + ld1 {v2.16b, v3.16b}, [x11], x22 // src + .inst 0x4e80a45c // smmla v28.4s, v2.16b, v0.16b + .inst 0x4e81a45d // smmla v29.4s, v2.16b, v1.16b + .inst 0x4e80a47e // smmla v30.4s, v3.16b, v0.16b + .inst 0x4e81a47f // smmla v31.4s, v3.16b, v1.16b + subs x13, x13, #1 + bne LoopSz_TILE_4 +LoopSzEnd_TILE_4: + add x18, x18, x15 + sub x16, x16, #1 + uzp1 v27.2d, v28.2d, v29.2d + uzp2 v28.2d, v28.2d, v29.2d + uzp1 v29.2d, v30.2d, v31.2d + uzp2 v30.2d, v30.2d, v31.2d + Int32ToFloat v27, v28, v29, v30 + cbnz x8, Tile4Quan + st1 {v27.4s, v28.4s, v29.4s, v30.4s}, [x17], x4 + b Tile4LoopCheck +Tile4Quan: + ld1 {v0.4s}, [x19], #16 // scale + MUL_SCALE v0, v27, v28, v29, v30 + FloatToInt32 v27, v28, v29, v30 + Int32ToInt16 v27, v28, v29, v30, v6, v7 + Int16ToInt8_ONE v6, v7, v19 + smax v19.16b, v10.16b, v19.16b + smin v19.16b, v11.16b, v19.16b + st1 {v19.16b}, [x17], x4 // dst += dz * dst_step +Tile4LoopCheck: + cmp x16, #1 + bge LoopDz_TILE_4 +Tile4End: + sub x7, x7, #4 + add x0, x0, x21, LSL #2 + add x1, x1, #32 + +TILE_2: + cmp x7, #2 + blt TILE_1 + mov x16, x5 // dst_depth_quad + mov x17, x0 // dst + mov x18, x2 // weight + mov x19, x8 // scale + mov x20, x9 // bias +LoopDz_TILE_2: + ld1 {v0.4s}, [x20], #16 // bias + mov x11, x1 // src + mov x12, x18 // weight + mov x13, x3 // src_depth_quad + mov v1.4s, v0.4s + uzp1 v30.2d, v0.2d, v1.2d // bias_0, bias_1, bias_0, bias_1 + uzp2 v31.2d, v0.2d, v1.2d // bias_2, bias_3, bias_2, bias_3 +LoopSz_TILE_2: + // src : 1 x [2 x 8] : v2 + // weight : 2 x [2 x 8] : v0-1 + // dst : 1 x 2 x [4] : v30-v31 + ld1 {v0.16b, v1.16b}, [x12], #32 // weight + ld1 {v2.16b}, [x11], x22 // src + .inst 0x4e80a45e // smmla v30.4s, v2.16b, v0.16b + .inst 0x4e81a45f // smmla v31.4s, v2.16b, v1.16b + subs x13, x13, #1 + bne LoopSz_TILE_2 +LoopSzEnd_TILE_2: + add x18, x18, x15 + sub x16, x16, #1 + uzp1 v29.2d, v30.2d, v31.2d + uzp2 v30.2d, v30.2d, v31.2d + scvtf v29.4s, v29.4s + scvtf v30.4s, v30.4s + cbnz x8, Tile2Quan + st1 {v29.4s, v30.4s}, [x17], x4 + b Tile2LoopCheck +Tile2Quan: + ld1 {v0.4s}, [x19], #16 // scale + fmul v29.4s, v29.4s, v0.4s + fmul v30.4s, v30.4s, v0.4s + fcvtas v29.4s, v29.4s + fcvtas v30.4s, v30.4s + sqxtn v6.4h, v29.4s + sqxtn2 v6.8h, v30.4s + sqxtn v19.8b, v6.8h + smax v19.16b, v10.16b, v19.16b + smin v19.16b, v11.16b, v19.16b + st1 {v19.8b}, [x17], x4 // dst += dz * dst_step + +Tile2LoopCheck: + cmp x16, #1 + bge LoopDz_TILE_2 +Tile2End: + sub x7, x7, #2 + add x0, x0, x21, LSL #1 + add x1, x1, #16 + +TILE_1: + cmp x7, #1 + blt End + mov x16, x5 // dst_depth_quad + mov x17, x0 // dst + mov x18, x2 // weight + mov x19, x8 // scale + mov x20, x9 // bias +LoopDz_TILE_1: + ld1 {v0.4s}, [x20], #16 // bias + mov x11, x1 // src + mov x12, x18 // weight + mov x13, x3 // src_depth_quad + mov v1.4s, v0.4s + uzp1 v30.2d, v0.2d, v1.2d // bias_0, bias_1, bias_0, bias_1 + uzp2 v31.2d, v0.2d, v1.2d // bias_2, bias_3, bias_2, bias_3 +LoopSz_TILE_1: + // src : 1 x [1 x 8] : v2 + // weight : 2 x [2 x 8] : v0-1 + // dst : 1 x 2 x [2] : v30-v31 + ld1 {v0.16b, v1.16b}, [x12], #32 // weight + ld1 {v2.8b}, [x11], x22 // src + .inst 0x4e80a45e // smmla v30.4s, v2.16b, v0.16b + .inst 0x4e81a45f // smmla v31.4s, v2.16b, v1.16b + subs x13, x13, #1 + bne LoopSz_TILE_1 +LoopSzEnd_TILE_1: + add x18, x18, x15 + sub x16, x16, #1 + uzp1 v29.2d, v30.2d, v31.2d + uzp2 v30.2d, v30.2d, v31.2d + scvtf v29.4s, v29.4s + scvtf v30.4s, v30.4s + cbnz x8, Tile1Quan + st1 {v29.4s, v30.4s}, [x17], x4 + b Tile1LoopEnd +Tile1Quan: + ld1 {v0.4s}, [x19], #16 // scale + fmul v29.4s, v29.4s, v0.4s + fmul v30.4s, v30.4s, v0.4s + fcvtas v29.4s, v29.4s + fcvtas v30.4s, v30.4s + sqxtn v6.4h, v29.4s + sqxtn2 v6.8h, v30.4s + sqxtn v19.8b, v6.8h + smax v19.16b, v10.16b, v19.16b + smin v19.16b, v11.16b, v19.16b + st1 {v19.s}[0], [x17], x4 // dst += dz * dst_step + +Tile1LoopEnd: + cmp x16, #1 + bge LoopDz_TILE_1 + +End: +ldp x19, x20, [sp, #(16 * 5)] +ldp x21, x22, [sp, #(16 * 4)] +ldp d8, d9, [sp, #(16 * 3)] +ldp d10, d11, [sp, #(16 * 2)] +ldp d12, d13, [sp, #(16 * 1)] +ldp d14, d15, [sp], #(16 * 6) +ret + +#endif // __aarch64__ diff --git a/source/backend/cpu/arm/arm64/bf16/ARMV86_MNNPackedMatMulRemain_BF16.S b/source/backend/cpu/arm/arm64/bf16/ARMV86_MNNPackedMatMulRemain_BF16.S new file mode 100644 index 000000000..54ffb5a1a --- /dev/null +++ b/source/backend/cpu/arm/arm64/bf16/ARMV86_MNNPackedMatMulRemain_BF16.S @@ -0,0 +1,564 @@ +// +// ARMV86_MNNPackedMatMulRemain_BF16.S +// MNN +// +// Created by MNN on 2022/10/09. +// Copyright © 2018-2021 Alibaba Group Holding Limited +// + +#ifdef __aarch64__ + +#include "MNNAsmGlobal.h" + +.text +.align 5 +.macro SET_ZERO d0, d1, d2, d3 + movi \d0\().4s, #0 + movi \d1\().4s, #0 + movi \d2\().4s, #0 + movi \d3\().4s, #0 +.endm + +.macro Float32ToBf16 d0, d1, d2, d3 + shrn \d0\().4h, \d0\().4s, #16 + shrn \d1\().4h, \d1\().4s, #16 + shrn \d2\().4h, \d2\().4s, #16 + shrn \d3\().4h, \d3\().4s, #16 +.endm + +.macro FMAX s, d0, d1, d2, d3 + fmax \d0\().4s, \d0\().4s, \s\().4s + fmax \d1\().4s, \d1\().4s, \s\().4s + fmax \d2\().4s, \d2\().4s, \s\().4s + fmax \d3\().4s, \d3\().4s, \s\().4s +.endm + +.macro FMIN s, d0, d1, d2, d3 + fmin \d0\().4s, \d0\().4s, \s\().4s + fmin \d1\().4s, \d1\().4s, \s\().4s + fmin \d2\().4s, \d2\().4s, \s\().4s + fmin \d3\().4s, \d3\().4s, \s\().4s +.endm + +.macro SET_BIAS s, d0, d1, d2 + mov \d0\().4s, \s\().4s + mov \d1\().4s, \s\().4s + mov \d2\().4s, \s\().4s +.endm + +// 12 * 8 * 4 MatMul +asm_function ARMV86_MNNPackedMatMulRemain_BF16 +//void ARMV86_MNNPackedMatMulRemain_BF16(float* C, const float* A, const float* B, size_t eSize, const size_t* parameter, const float* postParameters, const float* bias); +//Auto x0: C, x1:A, x2:B, x3:eSize, x4:parameter, x5:postParameters, x6:bias +sub sp, sp, #32 +str x19, [sp, #0] +str x20, [sp, #8] +str x21, [sp, #16] +ldr x11, [x4, #0] // aStride +ldr x9, [x4, #8] // l +ldr x10, [x4, #16] // h +lsl x11, x11, #2 // aStride * 4 +mov x16, #64 // B_stride = LP * HP = 4 * 8 * sizeof(int16_t) + +ldr x7, [x4, #24] // cStride +ldr x19, [x4, #40] // bExtraStride + +add x10, x10, #3 +lsr x10, x10, #2 +add x9, x9, #3 +lsr x9, x9, #2 + +cbz x5, Start +ld1 {v5.4s}, [x5] +dup v9.4s, v5.s[2] // Min Value +dup v10.4s, v5.s[3] // Max Value + +Start: + +E8: +cmp x3, #8 +blt E4 + +LoopE8: // e, TILE_BLOCK size is 8 + mov x20, x6 // bias + mov x8, x10 // updiv(h, 4) + mov x21, x0 // dest, C + mov x13, x2 // weight, B + + LH8: + cmp x8, #2 // h/4 > 2 + blt LH4 + sub x14, x7, #64 // cStride - 64 + LoopH8x8: + mov x15, x1 // src, A + mov x12, x9 // l + cbz x5, NoBiasLH8 + ld1 {v0.4h, v1.4h}, [x20], #16 // 8 * sizeof(int16_t) + shll v0.4s, v0.4h, #16 + shll v1.4s, v1.4h, #16 + mov v2.4s, v0.4s + mov v3.4s, v1.4s + uzp1 v16.2d, v0.2d, v2.2d // bias_0, bias_1, bias_0, bias_1 + uzp2 v17.2d, v0.2d, v2.2d // bias_2, bias_3, bias_2, bias_3 + uzp1 v24.2d, v1.2d, v3.2d // bias_0, bias_1, bias_0, bias_1 + uzp2 v25.2d, v1.2d, v3.2d // bias_2, bias_3, bias_2, bias_3 + SET_BIAS v16, v18, v20, v22 + SET_BIAS v17, v19, v21, v23 + SET_BIAS v24, v26, v28, v30 + SET_BIAS v25, v27, v29, v31 + b LoopL + NoBiasLH8: + SET_ZERO v16, v17, v18, v19 + SET_ZERO v20, v21, v22, v23 + SET_ZERO v24, v25, v26, v27 + SET_ZERO v28, v29, v30, v31 + LoopL: + // A [8, 4, bf16] : rn = 4 : v4 - v7 + // B [8, 4, bf16] : rn = 4 : v0 - v3 + // C [8, 8, fp32] : rn = 16 : v16 - v31 + ld1 {v4.8h, v5.8h, v6.8h, v7.8h}, [x15], x11 // A: 8 * 4 * sizeof(int16_t) + ld1 {v0.8h, v1.8h, v2.8h, v3.8h}, [x13], x16 // B: 8 * 4 * sizeof(int16_t) + .inst 0x6e40ec90 // bfmmla v16.4s, v4.8h, v0.8h + .inst 0x6e41ec91 // bfmmla v17.4s, v4.8h, v1.8h + .inst 0x6e40ecb2 // bfmmla v18.4s, v5.8h, v0.8h + .inst 0x6e41ecb3 // bfmmla v19.4s, v5.8h, v1.8h + .inst 0x6e40ecd4 // bfmmla v20.4s, v6.8h, v0.8h + .inst 0x6e41ecd5 // bfmmla v21.4s, v6.8h, v1.8h + .inst 0x6e40ecf6 // bfmmla v22.4s, v7.8h, v0.8h + .inst 0x6e41ecf7 // bfmmla v23.4s, v7.8h, v1.8h + .inst 0x6e42ec98 // bfmmla v24.4s, v4.8h, v2.8h + .inst 0x6e43ec99 // bfmmla v25.4s, v4.8h, v3.8h + .inst 0x6e42ecba // bfmmla v26.4s, v5.8h, v2.8h + .inst 0x6e43ecbb // bfmmla v27.4s, v5.8h, v3.8h + .inst 0x6e42ecdc // bfmmla v28.4s, v6.8h, v2.8h + .inst 0x6e43ecdd // bfmmla v29.4s, v6.8h, v3.8h + .inst 0x6e42ecfe // bfmmla v30.4s, v7.8h, v2.8h + .inst 0x6e43ecff // bfmmla v31.4s, v7.8h, v3.8h + subs x12, x12, #1 + bgt LoopL + LoopLEnd: + uzp1 v15.2d, v16.2d, v17.2d + uzp2 v16.2d, v16.2d, v17.2d + uzp1 v17.2d, v18.2d, v19.2d + uzp2 v18.2d, v18.2d, v19.2d + uzp1 v19.2d, v20.2d, v21.2d + uzp2 v20.2d, v20.2d, v21.2d + uzp1 v21.2d, v22.2d, v23.2d + uzp2 v22.2d, v22.2d, v23.2d + uzp1 v23.2d, v24.2d, v25.2d + uzp2 v24.2d, v24.2d, v25.2d + uzp1 v25.2d, v26.2d, v27.2d + uzp2 v26.2d, v26.2d, v27.2d + uzp1 v27.2d, v28.2d, v29.2d + uzp2 v28.2d, v28.2d, v29.2d + uzp1 v29.2d, v30.2d, v31.2d + uzp2 v30.2d, v30.2d, v31.2d + cbz x5, StoreLH8 + PostTreatLH8: + FMAX v9, v15, v16, v17, v18 + FMAX v9, v19, v20, v21, v22 + FMAX v9, v23, v24, v25, v26 + FMAX v9, v27, v28, v29, v30 + FMIN v10, v15, v16, v17, v18 + FMIN v10, v19, v20, v21, v22 + FMIN v10, v23, v24, v25, v26 + FMIN v10, v27, v28, v29, v30 + StoreLH8: + Float32ToBf16 v15, v16, v17, v18 + Float32ToBf16 v19, v20, v21, v22 + Float32ToBf16 v23, v24, v25, v26 + Float32ToBf16 v27, v28, v29, v30 + st1 {v15.4h, v16.4h, v17.4h, v18.4h}, [x0], #32 // 16 * sizeof(int16_t) + st1 {v19.4h, v20.4h, v21.4h, v22.4h}, [x0], #32 // 16 * sizeof(int16_t) + add x0, x0, x14 + st1 {v23.4h, v24.4h, v25.4h, v26.4h}, [x0], #32 // 16 * sizeof(int16_t) + st1 {v27.4h, v28.4h, v29.4h, v30.4h}, [x0], #32 // 16 * sizeof(int16_t) + add x0, x0, x14 + add x13, x13, x19 // weight stride + sub x8, x8, #2 + cmp x8, #2 + bge LoopH8x8 + LH4: + cbz x8, E8End + LoopHRemain: + mov x15, x1 + mov x12, x9 + cbz x5, NoBiasHRemain + ld1 {v0.4h}, [x20] + shll v0.4s, v0.4h, #16 + mov v2.4s, v0.4s + uzp1 v16.2d, v0.2d, v2.2d // bias_0, bias_1, bias_0, bias_1 + uzp2 v17.2d, v0.2d, v2.2d // bias_2, bias_3, bias_2, bias_3 + SET_BIAS v16, v18, v20, v22 + SET_BIAS v17, v19, v21, v23 + b LoopLR + NoBiasHRemain: + SET_ZERO v16, v17, v18, v19 + SET_ZERO v20, v21, v22, v23 + LoopLR: + // A [8, 4, bf16] : rn = 4 : v4 - v7 + // B [4, 4, bf16] : rn = 2 : v0 - v1 + // C [8, 4, fp32] : rn = 8 : v16 - v23 + ld1 {v4.8h, v5.8h, v6.8h, v7.8h}, [x15], x11 // A: 8 * 4 * sizeof(int16_t) + ld1 {v0.8h, v1.8h}, [x13], x16 // B: 4 * 4 * sizeof(int16_t) + .inst 0x6e40ec90 // bfmmla v16.4s, v4.8h, v0.8h + .inst 0x6e41ec91 // bfmmla v17.4s, v4.8h, v1.8h + .inst 0x6e40ecb2 // bfmmla v18.4s, v5.8h, v0.8h + .inst 0x6e41ecb3 // bfmmla v19.4s, v5.8h, v1.8h + .inst 0x6e40ecd4 // bfmmla v20.4s, v6.8h, v0.8h + .inst 0x6e41ecd5 // bfmmla v21.4s, v6.8h, v1.8h + .inst 0x6e40ecf6 // bfmmla v22.4s, v7.8h, v0.8h + .inst 0x6e41ecf7 // bfmmla v23.4s, v7.8h, v1.8h + subs x12, x12, #1 + bne LoopLR + LoopLREnd: + uzp1 v15.2d, v16.2d, v17.2d + uzp2 v16.2d, v16.2d, v17.2d + uzp1 v17.2d, v18.2d, v19.2d + uzp2 v18.2d, v18.2d, v19.2d + uzp1 v19.2d, v20.2d, v21.2d + uzp2 v20.2d, v20.2d, v21.2d + uzp1 v21.2d, v22.2d, v23.2d + uzp2 v22.2d, v22.2d, v23.2d + cbz x5, StoreLH8x4 + PostTreatLH8x4: + FMAX v9, v15, v16, v17, v18 + FMAX v9, v19, v20, v21, v22 + FMIN v10, v15, v16, v17, v18 + FMIN v10, v19, v20, v21, v22 + StoreLH8x4: + Float32ToBf16 v15, v16, v17, v18 + Float32ToBf16 v19, v20, v21, v22 + st1 {v15.4h, v16.4h, v17.4h, v18.4h}, [x0], #32 // 16 * sizeof(int16_t) + st1 {v19.4h, v20.4h, v21.4h, v22.4h}, [x0], #32 // 16 * sizeof(int16_t) + E8End: + sub x3, x3, #8 + cmp x3, #8 + add x0, x21, #64 // move dest address of 8 * 4 * sizeof(int16_t) + add x1, x1, #64 // move A matrix address of 8 * 4 * sizeof(int16_t) + bge LoopE8 + +E4: +cmp x3, #4 +mov x20, x6 +blt E2 + +mov x8, x10 +mov x21, x0 +mov x13, x2 + +cmp x8, #2 +blt E4LH4 +E4LH8: + E4LoopH8: + mov x15, x1 + mov x12, x9 + cbz x5, NoBiasE4 + ld1 {v0.4h, v1.4h}, [x20], #16 // 8 * sizeof(int16_t) + shll v0.4s, v0.4h, #16 + shll v1.4s, v1.4h, #16 + mov v2.4s, v0.4s + mov v3.4s, v1.4s + uzp1 v16.2d, v0.2d, v2.2d // bias_0, bias_1, bias_0, bias_1 + uzp2 v17.2d, v0.2d, v2.2d // bias_2, bias_3, bias_2, bias_3 + uzp1 v20.2d, v1.2d, v3.2d // bias_0, bias_1, bias_0, bias_1 + uzp2 v21.2d, v1.2d, v3.2d // bias_2, bias_3, bias_2, bias_3 + mov v18.4s, v16.4s + mov v19.4s, v17.4s + mov v22.4s, v20.4s + mov v23.4s, v21.4s + b E4LoopL + NoBiasE4: + SET_ZERO v16, v17, v18, v19 + SET_ZERO v20, v21, v22, v23 + E4LoopL: + // A [4, 4, bf16] : rn = 4 : v4 - v5 + // B [8, 4, bf16] : rn = 4 : v0 - v3 + // C [4, 8, fp32] : rn = 8 : v16 - v23 + ld1 {v4.8h, v5.8h}, [x15], x11 // A: 4 * 4 * sizeof(int16_t) + ld1 {v0.8h, v1.8h, v2.8h, v3.8h}, [x13], x16 // B: 8 * 4 * sizeof(int16_t) + .inst 0x6e40ec90 // bfmmla v16.4s, v4.8h, v0.8h + .inst 0x6e41ec91 // bfmmla v17.4s, v4.8h, v1.8h + .inst 0x6e40ecb2 // bfmmla v18.4s, v5.8h, v0.8h + .inst 0x6e41ecb3 // bfmmla v19.4s, v5.8h, v1.8h + .inst 0x6e42ec94 // bfmmla v20.4s, v4.8h, v2.8h + .inst 0x6e43ec95 // bfmmla v21.4s, v4.8h, v3.8h + .inst 0x6e42ecb6 // bfmmla v22.4s, v5.8h, v2.8h + .inst 0x6e43ecb7 // bfmmla v23.4s, v5.8h, v3.8h + subs x12, x12, #1 + bgt E4LoopL + E4LoopLEnd: + uzp1 v15.2d, v16.2d, v17.2d + uzp2 v16.2d, v16.2d, v17.2d + uzp1 v17.2d, v18.2d, v19.2d + uzp2 v18.2d, v18.2d, v19.2d + uzp1 v19.2d, v20.2d, v21.2d + uzp2 v20.2d, v20.2d, v21.2d + uzp1 v21.2d, v22.2d, v23.2d + uzp2 v22.2d, v22.2d, v23.2d + cbz x5, StoreLH4x8 + PostTreatLH4x8: + FMAX v9, v15, v16, v17, v18 + FMAX v9, v19, v20, v21, v22 + FMIN v10, v15, v16, v17, v18 + FMIN v10, v19, v20, v21, v22 + StoreLH4x8: + Float32ToBf16 v15, v16, v17, v18 + Float32ToBf16 v19, v20, v21, v22 + st1 {v15.4h, v16.4h, v17.4h, v18.4h}, [x0], x7 // 16 * sizeof(int16_t) + st1 {v19.4h, v20.4h, v21.4h, v22.4h}, [x0], x7 // 16 * sizeof(int16_t) + add x13, x13, x19 // weight stride + sub x8, x8, #2 + cmp x8, #2 + bge E4LoopH8 + E4LH4: + cbz x8, E4End + mov x15, x1 + mov x12, x9 + cbz x5, NoBiasE4R + ld1 {v0.4h}, [x20] + shll v0.4s, v0.4h, #16 + mov v2.4s, v0.4s + uzp1 v16.2d, v0.2d, v2.2d // bias_0, bias_1, bias_0, bias_1 + uzp2 v17.2d, v0.2d, v2.2d // bias_2, bias_3, bias_2, bias_3 + mov v18.4s, v16.4s + mov v19.4s, v17.4s + b E4LoopLR + NoBiasE4R: + SET_ZERO v16, v17, v18, v19 + E4LoopLR: + // A [4, 4, bf16] : rn = 4 : v4 - v5 + // B [4, 4, bf16] : rn = 4 : v0 - v1 + // C [4, 4, fp32] : rn = 4 : v16 - v19 + ld1 {v4.8h, v5.8h}, [x15], x11 // A: 4 * 4 * sizeof(int16_t) + ld1 {v0.8h, v1.8h}, [x13], x16 // B: 4 * 4 * sizeof(int16_t) + .inst 0x6e40ec90 // bfmmla v16.4s, v4.8h, v0.8h + .inst 0x6e41ec91 // bfmmla v17.4s, v4.8h, v1.8h + .inst 0x6e40ecb2 // bfmmla v18.4s, v5.8h, v0.8h + .inst 0x6e41ecb3 // bfmmla v19.4s, v5.8h, v1.8h + subs x12, x12, #1 + bgt E4LoopLR + E4LoopLREnd: + uzp1 v15.2d, v16.2d, v17.2d + uzp2 v16.2d, v16.2d, v17.2d + uzp1 v17.2d, v18.2d, v19.2d + uzp2 v18.2d, v18.2d, v19.2d + cbz x5, StoreLH4x4 + PostTreatLH4x4: + FMAX v9, v15, v16, v17, v18 + FMIN v10, v19, v20, v21, v22 + StoreLH4x4: + Float32ToBf16 v15, v16, v17, v18 + st1 {v15.4h, v16.4h, v17.4h, v18.4h}, [x0] // 16 * sizeof(int16_t) + E4End: + sub x3, x3, #4 + add x0, x21, #32 // move dest address of 4 * 4 * sizeof(int16_t) + add x1, x1, #32 // move dest address of 4 * 4 * sizeof(int16_t) + +E2: +cmp x3, #2 +mov x20, x6 +blt E1 + +mov x8, x10 +mov x21, x0 +mov x13, x2 + +cmp x8, #2 +blt E2LH4 +E2LH8: + E2LoopH8: + mov x15, x1 + mov x12, x9 + cbz x5, NoBiasE2 + ld1 {v0.4h, v1.4h}, [x20], #16 + shll v0.4s, v0.4h, #16 + shll v1.4s, v1.4h, #16 + mov v2.4s, v0.4s + mov v3.4s, v1.4s + uzp1 v16.2d, v0.2d, v2.2d // bias_0, bias_1, bias_0, bias_1 + uzp2 v17.2d, v0.2d, v2.2d // bias_2, bias_3, bias_2, bias_3 + uzp1 v18.2d, v1.2d, v3.2d // bias_0, bias_1, bias_0, bias_1 + uzp2 v19.2d, v1.2d, v3.2d // bias_2, bias_3, bias_2, bias_3 + b E2LoopL + NoBiasE2: + SET_ZERO v16, v17, v18, v19 + E2LoopL: + // A [2, 4, bf16] : rn = 1 : v4 + // B [8, 4, bf16] : rn = 2 : v0 - v3 + // C [2, 8, fp32] : rn = 4 : v16 - v19 + ld1 {v4.8h}, [x15], x11 // A: 2 * 4 * sizeof(int16_t) + ld1 {v0.8h, v1.8h, v2.8h, v3.8h}, [x13], x16 // B: 8 * 4 * sizeof(int16_t) + .inst 0x6e40ec90 // bfmmla v16.4s, v4.8h, v0.8h + .inst 0x6e41ec91 // bfmmla v17.4s, v4.8h, v1.8h + .inst 0x6e42ec92 // bfmmla v18.4s, v4.8h, v2.8h + .inst 0x6e43ec93 // bfmmla v19.4s, v4.8h, v3.8h + subs x12, x12, #1 + bgt E2LoopL + E2LoopLEnd: + uzp1 v15.2d, v16.2d, v17.2d + uzp2 v16.2d, v16.2d, v17.2d + uzp1 v17.2d, v18.2d, v19.2d + uzp2 v18.2d, v18.2d, v19.2d + cbz x5, StoreLH2x8 + PostTreatLH2x8: + FMAX v9, v15, v16, v17, v18 + FMIN v10, v15, v16, v17, v18 + StoreLH2x8: + Float32ToBf16 v15, v16, v17, v18 + st1 {v15.4h, v16.4h}, [x0], x7 // 8 * sizeof(int16_t) + st1 {v17.4h, v18.4h}, [x0], x7 // 8 * sizeof(int16_t) + add x13, x13, x19 // weight stride + sub x8, x8, #2 + cmp x8, #2 + bge E2LoopH8 + E2LH4: + cbz x8, E2End + mov x15, x1 + mov x12, x9 + cbz x5, NoBiasE2R + ld1 {v0.4h}, [x20] + shll v0.4s, v0.4h, #16 + mov v2.4s, v0.4s + uzp1 v16.2d, v0.2d, v2.2d // bias_0, bias_1, bias_0, bias_1 + uzp2 v17.2d, v0.2d, v2.2d // bias_2, bias_3, bias_2, bias_3 + b E2LoopLR + NoBiasE2R: + movi v16.4s, #0 + movi v17.4s, #0 + E2LoopLR: + // A [2, 4, bf16] : rn = 1 : v4 + // B [4, 4, bf16] : rn = 2 : v0 - v1 + // C [2, 4, fp32] : rn = 2 : v16 - v17 + ld1 {v4.8h}, [x15], x11 // A: 2 * 4 * sizeof(int16_t) + ld1 {v0.8h, v1.8h}, [x13], x16 // B: 4 * 4 * sizeof(int16_t) + .inst 0x6e40ec90 // bfmmla v16.4s, v4.8h, v0.8h + .inst 0x6e41ec91 // bfmmla v17.4s, v4.8h, v1.8h + subs x12, x12, #1 + bgt E2LoopLR + E2LoopLREnd: + uzp1 v15.2d, v16.2d, v17.2d + uzp2 v16.2d, v16.2d, v17.2d + cbz x5, StoreLH2x4 + PostTreatLH2x4: + fmax v15.4s, v15.4s, v9.4s + fmax v16.4s, v16.4s, v9.4s + fmin v15.4s, v15.4s, v10.4s + fmin v16.4s, v16.4s, v10.4s + StoreLH2x4: + shrn v15.4h, v15.4s, #16 + shrn v16.4h, v16.4s, #16 + st1 {v15.4h, v16.4h}, [x0] // 8 * sizeof(int16_t) + E2End: + sub x3, x3, #2 + add x0, x21, #16 // move dest address of 2 * 4 * sizeof(int16_t) + add x1, x1, #16 // move dest address of 2 * 4 * sizeof(int16_t) + +E1: +cmp x3, #0 +beq End + +LoopE1: + mov x20, x6 + mov x8, x10 + mov x21, x0 + mov x13, x2 + + cmp x8, #2 + blt E1LH4 + + E1LH8: + E1LoopH8: + mov x15, x1 + mov x12, x9 + cbz x5, NoBiasE1 + ld1 {v0.4h, v1.4h}, [x20], #16 + shll v0.4s, v0.4h, #16 + shll v1.4s, v1.4h, #16 + mov v2.4s, v0.4s + mov v3.4s, v1.4s + uzp1 v16.2d, v0.2d, v2.2d // bias_0, bias_1, bias_0, bias_1 + uzp2 v17.2d, v0.2d, v2.2d // bias_2, bias_3, bias_2, bias_3 + uzp1 v18.2d, v1.2d, v3.2d // bias_0, bias_1, bias_0, bias_1 + uzp2 v19.2d, v1.2d, v3.2d // bias_2, bias_3, bias_2, bias_3 + b E1LoopL + NoBiasE1: + SET_ZERO v16, v17, v18, v19 + E1LoopL: + // A [1, 4, bf16] : rn = 1 : v4 + // B [8, 4, bf16] : rn = 4 : v0 - v3 + // C [1, 8, fp32] : rn = 4 : v16 - v19 + ld1 {v4.4h}, [x15], x11 // A: 1 * 4 * sizeof(int16_t) + ld1 {v0.8h, v1.8h, v2.8h, v3.8h}, [x13], x16 // B: 8 * 4 * sizeof(int16_t) + .inst 0x6e40ec90 // bfmmla v16.4s, v4.8h, v0.8h + .inst 0x6e41ec91 // bfmmla v17.4s, v4.8h, v1.8h + .inst 0x6e42ec92 // bfmmla v18.4s, v4.8h, v2.8h + .inst 0x6e43ec93 // bfmmla v19.4s, v4.8h, v3.8h + subs x12, x12, #1 + bgt E1LoopL + E1LoopLEnd: + // v16-v19: [r0, r1, 0, 0] + uzp1 v15.2d, v16.2d, v17.2d + uzp1 v16.2d, v18.2d, v19.2d + cbz x5, StoreLH1x8 + PostTreatLH1x8: + fmax v15.4s, v15.4s, v9.4s + fmax v16.4s, v16.4s, v9.4s + fmin v15.4s, v15.4s, v10.4s + fmin v16.4s, v16.4s, v10.4s + StoreLH1x8: + shrn v15.4h, v15.4s, #16 + shrn v16.4h, v16.4s, #16 + st1 {v15.4h}, [x0], x7 + st1 {v16.4h}, [x0], x7 + add x13, x13, x19 + sub x8, x8, #2 + cmp x8, #2 + bge E1LoopH8 + + E1LH4: + cbz x8, E1End + mov x15, x1 + mov x12, x9 + cbz x5, NoBiasE1R + ld1 {v0.4h}, [x20] + shll v0.4s, v0.4h, #16 + mov v2.4s, v0.4s + uzp1 v16.2d, v0.2d, v2.2d // bias_0, bias_1, bias_0, bias_1 + uzp2 v17.2d, v0.2d, v2.2d // bias_2, bias_3, bias_2, bias_3 + b E1LoopLR + NoBiasE1R: + movi v16.4s, #0 + movi v17.4s, #0 + E1LoopLR: + // A [1, 4, bf16] : rn = 1 : v4 + // B [4, 4, bf16] : rn = 2 : v0 - v1 + // C [1, 8, fp32] : rn = 4 : v16 - v17 + ld1 {v4.4h}, [x15], x11 // A: 1 * 4 * sizeof(int16_t) + ld1 {v0.8h, v1.8h}, [x13], x16 // B: 4 * 4 * sizeof(int16_t) + .inst 0x6e40ec90 // bfmmla v16.4s, v4.8h, v0.8h + .inst 0x6e41ec91 // bfmmla v17.4s, v4.8h, v1.8h + subs x12, x12, #1 + bgt E1LoopLR + E1LoopLREnd: + uzp1 v15.2d, v16.2d, v17.2d + cbz x5, StoreLH1x4 + PostTreatLH1x4: + fmax v15.4s, v15.4s, v9.4s + fmin v15.4s, v15.4s, v10.4s + StoreLH1x4: + shrn v15.4h, v15.4s, #16 + st1 {v15.4h}, [x0] + E1End: + subs x3, x3, #1 + add x0, x21, #8 + add x1, x1, #8 + bne LoopE1 +End: +ldr x19, [sp, #0] +ldr x20, [sp, #8] +ldr x21, [sp, #16] +add sp, sp, #32 + +ret +#endif \ No newline at end of file diff --git a/source/backend/cpu/arm/arm64/bf16/ARMV86_MNNPackedMatMul_BF16.S b/source/backend/cpu/arm/arm64/bf16/ARMV86_MNNPackedMatMul_BF16.S new file mode 100644 index 000000000..b3379311d --- /dev/null +++ b/source/backend/cpu/arm/arm64/bf16/ARMV86_MNNPackedMatMul_BF16.S @@ -0,0 +1,284 @@ +// +// ARMV86_MNNPackedMatMul_BF16.S +// MNN +// +// Created by MNN on 2022/10/09. +// Copyright © 2018-2021 Alibaba Group Holding Limited +// +#ifdef __aarch64__ + +#include "MNNAsmGlobal.h" + +.text +.align 5 + +.macro SET_ZERO d0, d1, d2, d3 + movi \d0\().4s, #0 + movi \d1\().4s, #0 + movi \d2\().4s, #0 + movi \d3\().4s, #0 +.endm + +.macro Float32ToBf16 d0, d1, d2, d3 + shrn \d0\().4h, \d0\().4s, #16 + shrn \d1\().4h, \d1\().4s, #16 + shrn \d2\().4h, \d2\().4s, #16 + shrn \d3\().4h, \d3\().4s, #16 +.endm + +.macro FMAX s, d0, d1, d2, d3 + fmax \d0\().4s, \d0\().4s, \s\().4s + fmax \d1\().4s, \d1\().4s, \s\().4s + fmax \d2\().4s, \d2\().4s, \s\().4s + fmax \d3\().4s, \d3\().4s, \s\().4s +.endm + +.macro FMIN s, d0, d1, d2, d3 + fmin \d0\().4s, \d0\().4s, \s\().4s + fmin \d1\().4s, \d1\().4s, \s\().4s + fmin \d2\().4s, \d2\().4s, \s\().4s + fmin \d3\().4s, \d3\().4s, \s\().4s +.endm + +.macro SET_BIAS s, d0, d1, d2, d3 + mov \d0\().4s, \s\().4s + mov \d1\().4s, \s\().4s + mov \d2\().4s, \s\().4s + mov \d3\().4s, \s\().4s +.endm + +// 12 * 8 * 4 MatMul +asm_function ARMV86_MNNPackedMatMul_BF16 +//void ARMV86_MNNPackedMatMul_BF16(float* C, const float* A, const float* B, const size_t* parameter, const float* postParameters, const float* bias); +// x0: C, x1:A, x2:B, x3:parameter, x4: postParameters, x5:bias +stp d14, d15, [sp, #-64]! +stp d12, d13, [sp, #16] +stp d10, d11, [sp, #32] +stp d8, d9, [sp, #48] + +//ldr x8, [x3, #0] // deprecated +ldr x9, [x3, #8] // l +ldr x10, [x3, #16] // h +mov x11, #64 // B_stride = LP * HP = 4 * 8 * sizeof(int16_t) + +ldr x13, [x3, #24] // cStride +ldr x7, [x3, #40] // bExtraStride + +add x10, x10, #3 +lsr x10, x10, #2 +add x9, x9, #3 +lsr x9, x9, #2 + +cbz x4, Start +ld1 {v5.4s}, [x4] +mov w17, v5.s[2] // min value +mov w18, v5.s[3] // max value + +Start: + cmp x10, #2 + blt LH4 +LH8: + sub x14, x13, #96 // cStride - 96 +LoopH: + mov x15, x1 + mov x12, x9 + cbz x5, NoBiasH8 + ld1 {v0.4h, v1.4h}, [x5], #16 // 8 * sizeof(int16_t) + shll v0.4s, v0.4h, #16 + shll v1.4s, v1.4h, #16 + mov v2.4s, v0.4s + mov v3.4s, v1.4s + uzp1 v18.2d, v0.2d, v2.2d // bias_0, bias_1, bias_0, bias_1 + uzp2 v19.2d, v0.2d, v2.2d // bias_2, bias_3, bias_2, bias_3 + uzp1 v30.2d, v1.2d, v3.2d // bias_0, bias_1, bias_0, bias_1 + uzp2 v31.2d, v1.2d, v3.2d // bias_2, bias_3, bias_2, bias_3 + SET_BIAS v18, v8, v10, v12, v14 + mov v16.4s, v18.4s + SET_BIAS v19, v9, v11, v13, v15 + mov v17.4s, v19.4s + SET_BIAS v30, v20, v22, v24, v26 + mov v28.4s, v30.4s + SET_BIAS v31, v21, v23, v25, v27 + mov v29.4s, v31.4s + b LoopL + NoBiasH8: + SET_ZERO v8, v9, v10, v11 + SET_ZERO v12, v13, v14, v15 + SET_ZERO v16, v17, v18, v19 + SET_ZERO v20, v21, v22, v23 + SET_ZERO v24, v25, v26, v27 + SET_ZERO v28, v29, v30, v31 + LoopL: + // A [12, 4, bf16] : rn = 6 : v2 - v7 + // B [ 8, 4, bf16] : rn = 2 : v0 - v1 + // C [12, 8, fp32] : rn = 24 : v8 - v31 + ld1 {v2.8h, v3.8h, v4.8h, v5.8h}, [x15], #64 // A: 8 * 4 * sizeof(int16_t) + ld1 {v6.8h, v7.8h}, [x15], #32 // A: 4 * 4 * sizeof(int16_t) + ld1 {v0.8h, v1.8h}, [x2], #32 // B: 4 * 4 * sizeof(int16_t) + .inst 0x6e40ec48 // bfmmla v8.4s, v2.8h, v0.8h + .inst 0x6e41ec49 // bfmmla v9.4s, v2.8h, v1.8h + .inst 0x6e40ec6a // bfmmla v10.4s, v3.8h, v0.8h + .inst 0x6e41ec6b // bfmmla v11.4s, v3.8h, v1.8h + .inst 0x6e40ec8c // bfmmla v12.4s, v4.8h, v0.8h + .inst 0x6e41ec8d // bfmmla v13.4s, v4.8h, v1.8h + .inst 0x6e40ecae // bfmmla v14.4s, v5.8h, v0.8h + .inst 0x6e41ecaf // bfmmla v15.4s, v5.8h, v1.8h + .inst 0x6e40ecd0 // bfmmla v16.4s, v6.8h, v0.8h + .inst 0x6e41ecd1 // bfmmla v17.4s, v6.8h, v1.8h + .inst 0x6e40ecf2 // bfmmla v18.4s, v7.8h, v0.8h + .inst 0x6e41ecf3 // bfmmla v19.4s, v7.8h, v1.8h + ld1 {v0.8h, v1.8h}, [x2], #32 // B: 4 * 4 * sizeof(int16_t) + .inst 0x6e40ec54 // bfmmla v20.4s, v2.8h, v0.8h + .inst 0x6e41ec55 // bfmmla v21.4s, v2.8h, v1.8h + .inst 0x6e40ec76 // bfmmla v22.4s, v3.8h, v0.8h + .inst 0x6e41ec77 // bfmmla v23.4s, v3.8h, v1.8h + .inst 0x6e40ec98 // bfmmla v24.4s, v4.8h, v0.8h + .inst 0x6e41ec99 // bfmmla v25.4s, v4.8h, v1.8h + .inst 0x6e40ecba // bfmmla v26.4s, v5.8h, v0.8h + .inst 0x6e41ecbb // bfmmla v27.4s, v5.8h, v1.8h + .inst 0x6e40ecdc // bfmmla v28.4s, v6.8h, v0.8h + .inst 0x6e41ecdd // bfmmla v29.4s, v6.8h, v1.8h + .inst 0x6e40ecfe // bfmmla v30.4s, v7.8h, v0.8h + .inst 0x6e41ecff // bfmmla v31.4s, v7.8h, v1.8h + subs x12, x12, #1 + bgt LoopL + LoopLEnd: + uzp1 v7.2d, v8.2d, v9.2d + uzp2 v8.2d, v8.2d, v9.2d + uzp1 v9.2d, v10.2d, v11.2d + uzp2 v10.2d, v10.2d, v11.2d + uzp1 v11.2d, v12.2d, v13.2d + uzp2 v12.2d, v12.2d, v13.2d + uzp1 v13.2d, v14.2d, v15.2d + uzp2 v14.2d, v14.2d, v15.2d + uzp1 v15.2d, v16.2d, v17.2d + uzp2 v16.2d, v16.2d, v17.2d + uzp1 v17.2d, v18.2d, v19.2d + uzp2 v18.2d, v18.2d, v19.2d + uzp1 v19.2d, v20.2d, v21.2d + uzp2 v20.2d, v20.2d, v21.2d + uzp1 v21.2d, v22.2d, v23.2d + uzp2 v22.2d, v22.2d, v23.2d + uzp1 v23.2d, v24.2d, v25.2d + uzp2 v24.2d, v24.2d, v25.2d + uzp1 v25.2d, v26.2d, v27.2d + uzp2 v26.2d, v26.2d, v27.2d + uzp1 v27.2d, v28.2d, v29.2d + uzp2 v28.2d, v28.2d, v29.2d + uzp1 v29.2d, v30.2d, v31.2d + uzp2 v30.2d, v30.2d, v31.2d + cbz x4, StoreLH8 + PostTreatLH8: + dup v5.4s, w17 + dup v6.4s, w18 + FMAX v5, v7, v8, v9, v10 + FMAX v5, v11, v12, v13, v14 + FMAX v5, v15, v16, v17, v18 + FMAX v5, v19, v20, v21, v22 + FMAX v5, v23, v24, v25, v26 + FMAX v5, v27, v28, v29, v30 + FMIN v6, v7, v8, v9, v10 + FMIN v6, v11, v12, v13, v14 + FMIN v6, v15, v16, v17, v18 + FMIN v6, v19, v20, v21, v22 + FMIN v6, v23, v24, v25, v26 + FMIN v6, v27, v28, v29, v30 + StoreLH8: + Float32ToBf16 v7, v8, v9, v10 + Float32ToBf16 v11, v12, v13, v14 + Float32ToBf16 v15, v16, v17, v18 + Float32ToBf16 v19, v20, v21, v22 + Float32ToBf16 v23, v24, v25, v26 + Float32ToBf16 v27, v28, v29, v30 + st1 {v7.4h, v8.4h, v9.4h, v10.4h}, [x0], #32 // 16 * sizeof(int16_t) + st1 {v11.4h, v12.4h, v13.4h, v14.4h}, [x0], #32 // 16 * sizeof(int16_t) + st1 {v15.4h, v16.4h, v17.4h, v18.4h}, [x0], #32 // 16 * sizeof(int16_t) + add x0, x0, x14 + st1 {v19.4h, v20.4h, v21.4h, v22.4h}, [x0], #32 // 16 * sizeof(int16_t) + st1 {v23.4h, v24.4h, v25.4h, v26.4h}, [x0], #32 // 16 * sizeof(int16_t) + st1 {v27.4h, v28.4h, v29.4h, v30.4h}, [x0], #32 // 16 * sizeof(int16_t) + add x0, x0, x14 + add x2, x2, x7 // weight stride + sub x10, x10, #2 + cmp x10, #2 + bge LoopH +LH4: +cbz x10, End +LoopHR: + mov x15, x1 + mov x12, x9 + cbz x5, NoBiasH4 + ld1 {v0.4h}, [x5], #8 // 8 * sizeof(int16_t) + shll v0.4s, v0.4h, #16 + mov v2.4s, v0.4s + uzp1 v18.2d, v0.2d, v2.2d // bias_0, bias_1, bias_0, bias_1 + uzp2 v19.2d, v0.2d, v2.2d // bias_2, bias_3, bias_2, bias_3 + SET_BIAS v18, v8, v10, v12, v14 + mov v16.4s, v18.4s + SET_BIAS v19, v9, v11, v13, v15 + mov v17.4s, v19.4s + b LoopLR + NoBiasH4: + SET_ZERO v8, v9, v10, v11 + SET_ZERO v12, v13, v14, v15 + SET_ZERO v16, v17, v18, v19 + LoopLR: + // A [12, 4, bf16] : rn = 6 : v2 - v7 + // B [ 4, 4, bf16] : rn = 2 : v0 - v1 + // C [12, 4, fp32] : rn = 12 : v8 - v19 + ld1 {v2.8h, v3.8h, v4.8h, v5.8h}, [x15], #64 // A: 8 * 4 * sizeof(int16_t) + ld1 {v6.8h, v7.8h}, [x15], #32 // A: 4 * 4 * sizeof(int16_t) + ld1 {v0.8h, v1.8h}, [x2], x11 // B: 4 * 4 * sizeof(int16_t) + .inst 0x6e40ec48 // bfmmla v8.4s, v2.8h, v0.8h + .inst 0x6e41ec49 // bfmmla v9.4s, v2.8h, v1.8h + .inst 0x6e40ec6a // bfmmla v10.4s, v3.8h, v0.8h + .inst 0x6e41ec6b // bfmmla v11.4s, v3.8h, v1.8h + .inst 0x6e40ec8c // bfmmla v12.4s, v4.8h, v0.8h + .inst 0x6e41ec8d // bfmmla v13.4s, v4.8h, v1.8h + .inst 0x6e40ecae // bfmmla v14.4s, v5.8h, v0.8h + .inst 0x6e41ecaf // bfmmla v15.4s, v5.8h, v1.8h + .inst 0x6e40ecd0 // bfmmla v16.4s, v6.8h, v0.8h + .inst 0x6e41ecd1 // bfmmla v17.4s, v6.8h, v1.8h + .inst 0x6e40ecf2 // bfmmla v18.4s, v7.8h, v0.8h + .inst 0x6e41ecf3 // bfmmla v19.4s, v7.8h, v1.8h + subs x12, x12, #1 + bgt LoopLR + LoopLREnd: + add x2, x2, x7 // weight stride + uzp1 v7.2d, v8.2d, v9.2d + uzp2 v8.2d, v8.2d, v9.2d + uzp1 v9.2d, v10.2d, v11.2d + uzp2 v10.2d, v10.2d, v11.2d + uzp1 v11.2d, v12.2d, v13.2d + uzp2 v12.2d, v12.2d, v13.2d + uzp1 v13.2d, v14.2d, v15.2d + uzp2 v14.2d, v14.2d, v15.2d + uzp1 v15.2d, v16.2d, v17.2d + uzp2 v16.2d, v16.2d, v17.2d + uzp1 v17.2d, v18.2d, v19.2d + uzp2 v18.2d, v18.2d, v19.2d + cbz x4, StoreLH4 + PostTreatLH4: + dup v5.4s, w17 + dup v6.4s, w18 + FMAX v5, v7, v8, v9, v10 + FMAX v5, v11, v12, v13, v14 + FMAX v5, v15, v16, v17, v18 + FMIN v6, v7, v8, v9, v10 + FMIN v6, v11, v12, v13, v14 + FMIN v6, v15, v16, v17, v18 + StoreLH4: + Float32ToBf16 v7, v8, v9, v10 + Float32ToBf16 v11, v12, v13, v14 + Float32ToBf16 v15, v16, v17, v18 + st1 {v7.4h, v8.4h, v9.4h, v10.4h}, [x0], #32 // 16 * sizeof(int16_t) + st1 {v11.4h, v12.4h, v13.4h, v14.4h}, [x0], #32 // 16 * sizeof(int16_t) + st1 {v15.4h, v16.4h, v17.4h, v18.4h}, [x0], #32 // 16 * sizeof(int16_t) +End: +ldp d8, d9, [sp, #48] +ldp d10, d11, [sp, #32] +ldp d12, d13, [sp, #16] +ldp d14, d15, [sp], #64 +ret + +#endif diff --git a/source/backend/cpu/bf16/BF16Functions.cpp b/source/backend/cpu/bf16/BF16Functions.cpp index 76413b4f3..ea5a75af9 100644 --- a/source/backend/cpu/bf16/BF16Functions.cpp +++ b/source/backend/cpu/bf16/BF16Functions.cpp @@ -14,6 +14,7 @@ #include "WinogradOptFunctionHalf.hpp" #include "../compute/CommonOptFunction.h" #include "../CPUPool.hpp" +#include "../CPURuntime.hpp" #include "VecHalf.hpp" #include "math/Vec.hpp" #include "BF16Binary.hpp" @@ -890,6 +891,20 @@ bool BF16Functions::init() { gInstance->MNNConvRunForLineDepthwise = NEON_MNNConvRunForLineDepthwise_BF16; gInstance->MNNConvRunForUnitDepthWise = NEON_MNNConvRunForUnitDepthWise_BF16; gInstance->MNNAxByClampBroadcastUnit = NEON_MNNAxByClampBroadcastC4_BF16; +#ifdef __aarch64__ + cpuinfo_arm_isa gCPUInfo; + cpuinfo_arm_init(&gCPUInfo); + gInstance->supportFp16arith = gCPUInfo.fp16arith; + gInstance->supportSDot = gCPUInfo.dot; + gInstance->supportI8mm = gCPUInfo.i8mm; + if (gInstance->supportI8mm) { + gInstance->MNNPackForMatMul_B = ARMV86_MNNPackForMatMul_B_BF16; + gInstance->MNNPackC4ForMatMul_A = ARMV86_MNNPackC4ForMatMul_A_BF16; + gInstance->MNNGetMatMulPackMode = ARMV86_MNNGetMatMulPackMode_BF16; + gInstance->MNNPackedMatMul = ARMV86_MNNPackedMatMul_BF16; + gInstance->MNNPackedMatMulRemain = ARMV86_MNNPackedMatMulRemain_BF16; + } +#endif return true; #endif // TODO: raw cpu version of bf16 diff --git a/source/backend/cpu/bf16/CMakeLists.txt b/source/backend/cpu/bf16/CMakeLists.txt index a61d8d9a0..b533bec6f 100644 --- a/source/backend/cpu/bf16/CMakeLists.txt +++ b/source/backend/cpu/bf16/CMakeLists.txt @@ -9,7 +9,6 @@ add_library( ${MNN_BF16_SRCS} ) target_compile_options(MNN_BF16 PRIVATE -DMNN_SUPPORT_BF16) - if(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64)|(X86_64)|(x64)|(X64)|(amd64)|(AMD64)|(i686)") if (MNN_USE_SSE) target_compile_options(MNN_BF16 PRIVATE -DMNN_USE_SSE) diff --git a/source/backend/cpu/bf16/VecHalf.hpp b/source/backend/cpu/bf16/VecHalf.hpp index ee93b4879..d5fe3a69f 100644 --- a/source/backend/cpu/bf16/VecHalf.hpp +++ b/source/backend/cpu/bf16/VecHalf.hpp @@ -93,6 +93,12 @@ struct VecHalf { } } + VecHalf(float v0, float v1, float v2, float v3) { + value[0] = v0; + value[1] = v1; + value[2] = v2; + value[3] = v3; + } VecHalf(std::array&& v) { value = std::move(v); } diff --git a/source/backend/cpu/compute/CommonOptFunction.cpp b/source/backend/cpu/compute/CommonOptFunction.cpp index d8220c755..a5455b652 100644 --- a/source/backend/cpu/compute/CommonOptFunction.cpp +++ b/source/backend/cpu/compute/CommonOptFunction.cpp @@ -2875,12 +2875,11 @@ void MNNCoreFunctionInit() { gCoreFunction->MNNC3ToFloatC3 = MNNC3ToFloatC3; gCoreFunction->MNNC3ToFloatRGBA = MNNC3ToFloatRGBA; -#ifdef MNN_USE_ARMV82 cpuinfo_arm_isa gCPUInfo; cpuinfo_arm_init(&gCPUInfo); gCoreFunction->supportFp16arith = gCPUInfo.fp16arith; gCoreFunction->supportSDot = gCPUInfo.dot; -#endif + gCoreFunction->supportI8mm = gCPUInfo.i8mm; MNNCoreInt8FunctionInit(); MNNFunctionInit(); } diff --git a/source/backend/cpu/compute/CommonOptFunction.h b/source/backend/cpu/compute/CommonOptFunction.h index 760cc31ae..257e7a4f7 100644 --- a/source/backend/cpu/compute/CommonOptFunction.h +++ b/source/backend/cpu/compute/CommonOptFunction.h @@ -168,6 +168,7 @@ struct CoreFunctions { // cpu feature bool supportFp16arith = false; bool supportSDot = false; + bool supportI8mm = false; /**MatMul Pack and Functions*/ void(*MNNGetMatMulPackMode)(int* eP, int *lP, int* hP); void(*MNNGetSparseMatMulPackMode)(int* eP, int *lP, int* hP); diff --git a/source/backend/cpu/compute/ConvInt8TiledExecutor.cpp b/source/backend/cpu/compute/ConvInt8TiledExecutor.cpp index e16057e53..5fecb4721 100644 --- a/source/backend/cpu/compute/ConvInt8TiledExecutor.cpp +++ b/source/backend/cpu/compute/ConvInt8TiledExecutor.cpp @@ -74,14 +74,6 @@ ErrorCode ConvInt8TiledExecutor::onResize(const std::vector& inputs, co return NO_ERROR; } -// -// DenseConvInt8TiledExecutor.cpp -// MNN -// -// Created by MNN on 2019/5/17. -// Copyright © 2018, Alibaba Group Holding Limited -// - static bool reorderWeight(Backend* bn, const Convolution2DCommon* common, const std::shared_ptr& weightOrigin, std::shared_ptr& weight) { diff --git a/source/backend/cpu/compute/Int8FunctionsOpt.cpp b/source/backend/cpu/compute/Int8FunctionsOpt.cpp index 333568818..c374e8303 100644 --- a/source/backend/cpu/compute/Int8FunctionsOpt.cpp +++ b/source/backend/cpu/compute/Int8FunctionsOpt.cpp @@ -23,10 +23,12 @@ void MNNGemmInt8AddBiasScale_16x4_Unit_FAST(int8_t* dst, const int8_t* src, cons const QuanPostTreatParameters* post, size_t realCount); void MNNLineDepthWiseInt8AddBiasScaleUnit(int8_t* dst, const int8_t* src, const int8_t* weight, const QuanPostTreatParameters* parameters, size_t width, size_t src_w_step, size_t fw, size_t fh, size_t dilateX_step, size_t dilateY_step); -#if defined(__aarch64__) && defined(MNN_USE_ARMV82) // aarch32 sdot workaround +#if defined(__aarch64__) // aarch32 sdot workaround void MNNGemmInt8AddBiasScale_ARMV82_Unit(int8_t* dst, const int8_t* src, const int8_t* weight, size_t src_depth_quad, size_t dst_step, size_t dst_depth_quad, const QuanPostTreatParameters* post, size_t realDstCount); -#endif // __aarch64__ && MNN_USE_ARMV82 +void MNNGemmInt8AddBiasScale_ARMV86_Unit(int8_t* dst, const int8_t* src, const int8_t* weight, size_t src_depth_quad, size_t dst_step, size_t dst_depth_quad, + const QuanPostTreatParameters* post, size_t realDstCount); +#endif // __aarch64__ } #endif // MNN_USE_NEON @@ -1425,7 +1427,6 @@ static int8_t MNNInt32ToInt8(int data, int bias, float scale, float maxValue, fl static void MNNGemmInt8AddBiasScale_16x4_Unit(int8_t* dst, const int8_t* src, const int8_t* weight, size_t src_depth_quad, size_t dst_step, size_t dst_depth_quad, const QuanPostTreatParameters* post, size_t realCount) { - const int bytes = (post->scale != nullptr ? 1 : 4); for (int dz = 0; dz < dst_depth_quad; ++dz) { const auto weight_dz = weight + dz * src_depth_quad * (GEMM_INT8_UNIT * GEMM_INT8_SRC_UNIT); @@ -1777,10 +1778,160 @@ static void MNNGetGemmUnitSdot(int* UNIT, int* SRC_UNIT, int* DST_XUNIT) { *DST_XUNIT = GEMM_INT8_DST_XUNIT; } +#undef GEMM_INT8_UNIT +#undef GEMM_INT8_SRC_UNIT +#undef GEMM_INT8_DST_XUNIT /* End */ + + +/* CPU with i8mm */ +#define GEMM_INT8_UNIT 4 +#define GEMM_INT8_SRC_UNIT 8 +#define GEMM_INT8_DST_XUNIT 20 + +// icDiv4 % 2 == 0 will call this function +static void _im2colCommonI8mm(int8_t* colAddr, const int8_t* src, int32_t inputZeroPoint, + const MNN::ConvolutionCommon::Im2ColParameter* im2colParameter, size_t xIndexStart, + size_t realDstCount) { + const int col_buffer_size = im2colParameter->kernelCountUnit * GEMM_INT8_DST_XUNIT * GEMM_INT8_SRC_UNIT * sizeof(int8_t); + ::memset(colAddr, inputZeroPoint, col_buffer_size); // the padding process, since per-channel is removed, this is all right + auto ih = im2colParameter->ih; + auto iw = im2colParameter->iw; + auto kh = im2colParameter->kernelY; + auto kw = im2colParameter->kernelX; + auto dilateX = im2colParameter->dilateX; + auto dilateY = im2colParameter->dilateY; + auto icDiv4 = im2colParameter->icDiv4; + auto srcZStep = im2colParameter->srcZStep; + auto srcYStep = im2colParameter->srcYStep; + constexpr int dstXStepInt32 = GEMM_INT8_SRC_UNIT * GEMM_INT8_DST_XUNIT / sizeof(int32_t); + constexpr int SRC_DIV_UNIT = GEMM_INT8_SRC_UNIT / GEMM_INT8_UNIT; // 2 + auto icDiv8 = icDiv4 / 2; + for (int i = 0; i < realDstCount; ++i) { + int xIndex = (int)xIndexStart + i; + int ox = xIndex % im2colParameter->ow; + int oy = xIndex / im2colParameter->ow; + int sx = ox * im2colParameter->strideX - im2colParameter->padX; + int sy = oy * im2colParameter->strideY - im2colParameter->padY; + int sfy = ALIMAX(0, (UP_DIV(-sy, im2colParameter->dilateY))); + int efy = ALIMIN(kh, UP_DIV(ih - sy, im2colParameter->dilateY)); + int sfx = ALIMAX(0, (UP_DIV(-sx, im2colParameter->dilateX))); + int efx = ALIMIN(kw, UP_DIV(iw - sx, im2colParameter->dilateX)); + int fyC = efy - sfy; + int fxC = efx - sfx; + auto colAddrI = colAddr + GEMM_INT8_SRC_UNIT * i; + auto inputOffset = src + (sy + sfy * dilateY) * srcYStep + (sx + sfx * dilateX) * GEMM_INT8_UNIT; + auto indexOffset = (sfy * kw + sfx) * icDiv8; + for (int fy = 0; fy < fyC; ++fy) { + for (int fx = 0; fx < fxC; ++fx) { + auto inputK = inputOffset + fy * dilateY * srcYStep + fx * dilateX * GEMM_INT8_UNIT; + auto indexStart = indexOffset + (fy * kw + fx) * icDiv8; + for (int sz = 0; sz < icDiv8; ++sz) { + const int yIndex = indexStart + sz; + auto dstK0 = (int32_t*)colAddrI + yIndex * dstXStepInt32; + dstK0[0] = *((int32_t*)inputK); + dstK0[1] = *((int32_t*)(inputK + srcZStep)); + inputK += 2 * srcZStep; + } + } + } + } +} + +static void _slowIm2ColI8mm(int8_t* colAddr, const int8_t* src, int32_t inputZeroPoint, + const MNN::ConvolutionCommon::Im2ColParameter* im2colParameter, size_t xIndexStart, + size_t realDstCount) { + const int col_buffer_size = im2colParameter->kernelCountUnit * GEMM_INT8_DST_XUNIT * GEMM_INT8_SRC_UNIT * sizeof(int8_t); + ::memset(colAddr, inputZeroPoint, col_buffer_size); // the padding process, since per-channel is removed, this is all right + auto ih = im2colParameter->ih; + auto iw = im2colParameter->iw; + auto kh = im2colParameter->kernelY; + auto kw = im2colParameter->kernelX; + auto dilateX = im2colParameter->dilateX; + auto dilateY = im2colParameter->dilateY; + auto icDiv4 = im2colParameter->icDiv4; + auto srcZStep = im2colParameter->srcZStep; + auto srcYStep = im2colParameter->srcYStep; + constexpr int dstXStepInt32 = GEMM_INT8_SRC_UNIT * GEMM_INT8_DST_XUNIT / sizeof(int32_t); + constexpr int SRC_DIV_UNIT = GEMM_INT8_SRC_UNIT / GEMM_INT8_UNIT; + + for (int i = 0; i < realDstCount; ++i) { + int xIndex = (int)xIndexStart + i; + int ox = xIndex % im2colParameter->ow; + int oy = xIndex / im2colParameter->ow; + int sx = ox * im2colParameter->strideX - im2colParameter->padX; + int sy = oy * im2colParameter->strideY - im2colParameter->padY; + int sfy = ALIMAX(0, (UP_DIV(-sy, im2colParameter->dilateY))); + int efy = ALIMIN(kh, UP_DIV(ih - sy, im2colParameter->dilateY)); + int sfx = ALIMAX(0, (UP_DIV(-sx, im2colParameter->dilateX))); + int efx = ALIMIN(kw, UP_DIV(iw - sx, im2colParameter->dilateX)); + int fyC = efy - sfy; + int fxC = efx - sfx; + auto colAddrI = colAddr + GEMM_INT8_SRC_UNIT * i; + auto inputOffset = src + (sy + sfy * dilateY) * srcYStep + (sx + sfx * dilateX) * GEMM_INT8_UNIT; + auto indexOffset = (sfy * kw + sfx) * icDiv4; + for (int fy = 0; fy < fyC; ++fy) { + for (int fx = 0; fx < fxC; ++fx) { + auto inputK = inputOffset + fy * dilateY * srcYStep + fx * dilateX * GEMM_INT8_UNIT; + auto indexStart = indexOffset + (fy * kw + fx) * icDiv4; + for (int sz = 0; sz < icDiv4; ++sz) { + const int yIndex = indexStart + sz; + const int ySubOutside = yIndex / SRC_DIV_UNIT; + const int ySubInside = yIndex % SRC_DIV_UNIT; + auto dstK0 = (int32_t*)colAddrI + ySubOutside * dstXStepInt32 + ySubInside; + dstK0[0] = *((int32_t*)inputK); + inputK += srcZStep; + } + } + } + } +} + +static void _fastIm2ColI8mm(int8_t* colAddr, const int8_t* inputOrigin, int32_t inputZeroPoint, + const MNN::ConvolutionCommon::Im2ColParameter* im2colParameter, size_t xIndexStart, + size_t realDstCount) { + const int col_buffer_size = im2colParameter->kernelCountUnit * GEMM_INT8_DST_XUNIT * GEMM_INT8_SRC_UNIT * sizeof(int8_t); + ::memset(colAddr, inputZeroPoint, col_buffer_size); + const int icDiv4 = im2colParameter->icDiv4; + const int srcZStep = im2colParameter->iw * im2colParameter->ih * GEMM_INT8_UNIT; + inputOrigin += xIndexStart * GEMM_INT8_UNIT; + for (int i = 0; i < realDstCount; ++i) { + auto colAddrI = colAddr + GEMM_INT8_UNIT * i; + auto inputK = inputOrigin + GEMM_INT8_UNIT * i; + for (int sz = 0; sz < icDiv4; ++sz) { + auto inputZ0 = inputK + srcZStep * sz; + auto dstK0 = colAddrI + sz * GEMM_INT8_UNIT * GEMM_INT8_DST_XUNIT; + *((int32_t*)dstK0) = *((int32_t*)inputZ0); + } + } +} + +static MNN::CoreInt8Functions::Im2ColFunc chooseIm2ColI8mm(const MNN::ConvolutionCommon::Im2ColParameter* im2colParam, size_t inputChannel) { + bool fastIm2Col = im2colParam->kernelX == 1 && im2colParam->kernelY == 1 && im2colParam->icDiv4 % 2 == 0 && + im2colParam->strideX == 1 && im2colParam->strideY == 1 && im2colParam->padX == 0 && + im2colParam->padY == 0; + int ih = im2colParam->ih, iw = im2colParam->iw; + fastIm2Col &= (im2colParam->srcYStep == iw * GEMM_INT8_UNIT && im2colParam->srcZStep == ih * iw * GEMM_INT8_UNIT); + if (fastIm2Col) { + return _fastIm2ColI8mm; + } else { + if (im2colParam->icDiv4 % 2) { + return _slowIm2ColI8mm; + } else { + return _im2colCommonI8mm; + } + } +} + +static void MNNGetGemmUnitI8mm(int* UNIT, int* SRC_UNIT, int* DST_XUNIT) { + *UNIT = GEMM_INT8_UNIT; + *SRC_UNIT = GEMM_INT8_SRC_UNIT; + *DST_XUNIT = GEMM_INT8_DST_XUNIT; +} #undef GEMM_INT8_UNIT #undef GEMM_INT8_SRC_UNIT #undef GEMM_INT8_DST_XUNIT +/* End */ namespace MNN { @@ -1808,7 +1959,7 @@ void MNNCoreInt8FunctionInit() { gCoreFunc->MNNPackedSparseQuantMatMulEpx4 = MNNPackedSparseQuantMatMulEpx4; gCoreFunc->MNNSparseQuantIm2col = MNNSparseQuantIm2col; -#if defined(__aarch64__) && defined(MNN_USE_ARMV82) +#if defined(__aarch64__) auto core = MNNGetCoreFunctions(); if (core->supportSDot) { // MatMul @@ -1818,6 +1969,14 @@ void MNNCoreInt8FunctionInit() { // Im2Col gCoreFunc->chooseIm2Col = chooseIm2ColSdot; } + if (core->supportI8mm) { + // MatMul + gCoreFunc->Int8GemmKernel = MNNGemmInt8AddBiasScale_ARMV86_Unit; + gCoreFunc->Int8GemmKernelFast = MNNGemmInt8AddBiasScale_ARMV86_Unit; + gCoreFunc->MNNGetGemmUnit = MNNGetGemmUnitI8mm; + // Im2Col + gCoreFunc->chooseIm2Col = chooseIm2ColI8mm; + } #endif MNNInt8FunctionInit(); } diff --git a/source/backend/nnapi/CMakeLists.txt b/source/backend/nnapi/CMakeLists.txt index 07e66fc42..1301330aa 100644 --- a/source/backend/nnapi/CMakeLists.txt +++ b/source/backend/nnapi/CMakeLists.txt @@ -12,7 +12,11 @@ add_library( ${MNN_NNAPI_SRCS} ) -target_compile_options(MNN_NNAPI PRIVATE -DMNN_NNAPI_ENABLED=1) +IF (MNN_ARM82) + target_compile_options(MNN_NNAPI PRIVATE -DMNN_NNAPI_ENABLED=1 -DENABLE_ARMV82) +ELSE() + target_compile_options(MNN_NNAPI PRIVATE -DMNN_NNAPI_ENABLED=1) +ENDIF() target_include_directories(MNN_NNAPI PRIVATE ${CMAKE_CURRENT_LIST_DIR}/backend diff --git a/source/backend/nnapi/backend/NNAPIBackend.cpp b/source/backend/nnapi/backend/NNAPIBackend.cpp index 6c24027ae..e32860ef4 100644 --- a/source/backend/nnapi/backend/NNAPIBackend.cpp +++ b/source/backend/nnapi/backend/NNAPIBackend.cpp @@ -13,16 +13,40 @@ #include #include #include -// #define NNAPI_DEBUG + +#ifdef MNN_USE_ARMV82 +// FP32 <--> FP16 Function +#include "backend/arm82/Arm82OptFunc.hpp" +#define FLOAT_TO_HALF MNNQuantizeFP16 +#define HALF_TO_FLOAT MNNDequantizeFP16 +#else +#define FLOAT_TO_HALF(...) +#define HALF_TO_FLOAT(...) +#endif // MNN_USE_ARMV82 + +// #define NNAPI_DEBUG_DEVICE +// #define NNAPI_DEBUG_OP +// #define NNAPI_PROFILE // #define USE_NCHW +#ifdef NNAPI_DEBUG_OP + #define NNAPI_OP_LOG MNN_PRINT +#else + #define NNAPI_OP_LOG(...) +#endif +#ifdef NNAPI_DEBUG_DEVICE + #define NNAPI_DEVICE_LOG MNN_PRINT +#else + #define NNAPI_DEVICE_LOG(...) +#endif #define CHECK(func, ...) \ do { \ const auto _status = (func(__VA_ARGS__)); \ if (_status != ANEURALNETWORKS_NO_ERROR) { \ const auto ENUM_TO_STR = NNAPIEnumToString(_status); \ - MNN_PRINT("[NNAPI] Error: %s when call " #func " at line %d.\n", \ + MNN_ERROR("[NNAPI] Error: %s when call " #func " at line %d.\n", \ ENUM_TO_STR.c_str(), __LINE__); \ + exit(0);\ } \ } while (0) @@ -55,10 +79,17 @@ namespace MNN { #undef ENUM_TO_STR } } + + static uint16_t fp32to16(float val) { + uint32_t x = *((uint32_t*)&val); + uint16_t h = ((x>>16)&0x8000)|((((x&0x7f800000)-0x38000000)>>13)&0x7c00)|((x>>13)&0x03ff); + return h; + } + bool NNAPIBackend::addCreator(OpType t, Creator* c) { auto map = getCreatorMap(); if (map->find(t) != map->end()) { - MNN_PRINT("Error: %d type has be added\n", t); + MNN_ERROR("Error: %d type has be added\n", t); return false; } map->insert(std::make_pair(t, c)); @@ -73,7 +104,7 @@ namespace MNN { #else mNCHW = false; #endif - MNN_PRINT("[NNAPI] DimensionFormat is %s\n", mNCHW ? "NCHW" : "NHWC"); + NNAPI_DEVICE_LOG("[NNAPI] DimensionFormat is %s\n", mNCHW ? "NCHW" : "NHWC"); if (mNNAPIModel == nullptr) { CHECK(ANeuralNetworksModel_create_27, &mNNAPIModel); } @@ -81,12 +112,12 @@ namespace MNN { uint32_t numDevices = 0; CHECK(ANeuralNetworks_getDeviceCount_29, &numDevices); mNNAPIDevices.resize(numDevices); - MNN_PRINT("[NNAPI] numDevices = %d\n", numDevices); + NNAPI_DEVICE_LOG("[NNAPI] numDevices = %d\n", numDevices); for (int i = 0; i < numDevices; i++) { CHECK(ANeuralNetworks_getDevice_29, i, &mNNAPIDevices[i].device); CHECK(ANeuralNetworksDevice_getName_29, mNNAPIDevices[i].device, &mNNAPIDevices[i].name); CHECK(ANeuralNetworksDevice_getType_29, mNNAPIDevices[i].device, &mNNAPIDevices[i].type); - MNN_PRINT("[NNAPI] device %d is : %s, %d\n", i, mNNAPIDevices[i].name, mNNAPIDevices[i].type); + NNAPI_DEVICE_LOG("[NNAPI] device %d is : %s, %d\n", i, mNNAPIDevices[i].name, mNNAPIDevices[i].type); } } } @@ -99,13 +130,14 @@ namespace MNN { Execution* NNAPIBackend::onCreate(const std::vector& inputs, const std::vector& outputs, const MNN::Op* op) { auto map = getCreatorMap(); auto iter = map->find(op->type()); + NNAPI_OP_LOG("### op: %s, %s\n", MNN::EnumNameOpType(op->type()), op->name() ? op->name()->c_str() : "NoName"); if (iter == map->end()) { - MNN_PRINT("[NNAPI] Don't support type %s.\n", MNN::EnumNameOpType(op->type())); + MNN_ERROR("[NNAPI] Don't support type %s.\n", MNN::EnumNameOpType(op->type())); return nullptr; } auto exe = iter->second->onCreate(inputs, outputs, op, this); if (nullptr == exe) { - MNN_PRINT("[NNAPI] The Creator Don't support type %s.\n", MNN::EnumNameOpType(op->type())); + MNN_ERROR("[NNAPI] The Creator Don't support type %s.\n", MNN::EnumNameOpType(op->type())); return nullptr; } return exe; @@ -121,7 +153,15 @@ namespace MNN { Backend::MemObj* NNAPIBackend::onAcquire(const Tensor* tensor, StorageType storageType) { bool isInputCopy = TensorUtils::getDescribe(tensor)->usage==Tensor::InsideDescribe::Usage::INPUT; bool isOutputCopy = TensorUtils::getDescribe(tensor)->usage==Tensor::InsideDescribe::Usage::OUTPUT; - std::unique_ptr tensor_(new Tensor(tensor, mNCHW ? Tensor::DimensionType::CAFFE : Tensor::DimensionType::TENSORFLOW, true)); + std::unique_ptr tensor_; + auto format = mNCHW ? Tensor::DimensionType::CAFFE : Tensor::DimensionType::TENSORFLOW; + if (bytes() == 2 && tensor->getType() == halide_type_of()) { + const_cast(tensor)->buffer().type = halide_type_t(halide_type_float, 16); + tensor_.reset(new Tensor(tensor, format, true)); + const_cast(tensor)->buffer().type = halide_type_of(); + } else { + tensor_.reset(new Tensor(tensor, format, true)); + } if(isInputCopy){ mInputTensors.push_back(tensor); mInputContentTensors.push_back(std::move(tensor_)); @@ -135,7 +175,9 @@ namespace MNN { // const_cast(tensor->buffer()).host = (uint8_t*)MNNMemoryAllocAlign(tensor->size(), MNN_MEMORY_ALIGN_DEFAULT); // MNN_ASSERT(tensor->buffer().host != nullptr); } - getTensorIdx(tensor); + if (isInputCopy || isOutputCopy) { + getTensorIdx(tensor); + } // Don't need release return new Backend::MemObj; } @@ -149,61 +191,97 @@ namespace MNN { mOutputIdxMap.clear(); return true; } - + void NNAPIBackend::onCopyBuffer(const Tensor* srcTensor, const Tensor* dstTensor) const { bool isInputCopy = TensorUtils::getDescribe(dstTensor)->usage==Tensor::InsideDescribe::Usage::INPUT; bool isOutputCopy = TensorUtils::getDescribe(srcTensor)->usage==Tensor::InsideDescribe::Usage::OUTPUT; bool isConst = TensorUtils::getDescribe(srcTensor)->usage==Tensor::InsideDescribe::Usage::CONSTANT || TensorUtils::getDescribe(dstTensor)->usage==Tensor::InsideDescribe::Usage::CONSTANT; - if(isConst){ return; } + if (isConst) { return; } + std::unique_ptr tempTensor; if (isInputCopy) { const auto iter = mInputIdxMap.find(dstTensor); MNN_ASSERT(iter != mInputIdxMap.end()); - // memcpy((void*)&mInputTensors[iter->second], &srcTensor, sizeof(void*)); - auto code = CPUTensorConverter::convert(srcTensor, mInputContentTensors[iter->second].get()); - if (NO_ERROR != code) { - MNN_ERROR("Error in NNAPIBackend::onCopyBuffer:convert\n"); + auto realTensor = mInputContentTensors[iter->second].get(); + if (bytes() == 2) { + tempTensor.reset(Tensor::create(realTensor->shape(), nullptr, TensorUtils::getDimType(realTensor))); + auto code = CPUTensorConverter::convert(srcTensor, tempTensor.get()); + if (NO_ERROR != code) { + MNN_ERROR("Error in NNAPIBackend::onCopyBuffer:convert\n"); + } + FLOAT_TO_HALF(tempTensor->host(), realTensor->host(), realTensor->elementSize()); + } else { + auto code = CPUTensorConverter::convert(srcTensor, realTensor); + if (NO_ERROR != code) { + MNN_ERROR("Error in NNAPIBackend::onCopyBuffer:convert\n"); + } } } else if (isOutputCopy) { const auto iter = mOutputIdxMap.find(srcTensor); MNN_ASSERT(iter != mOutputIdxMap.end()); - // memcpy(dstTensor->host(), srcTensor->host(), std::min(srcTensor->size(), dstTensor->size())); - auto code = CPUTensorConverter::convert(mOutputContentTensors[iter->second].get(), dstTensor); - if (NO_ERROR != code) { - MNN_ERROR("Error in NNAPIBackend::onCopyBuffer:convert\n"); + auto realTensor = mOutputContentTensors[iter->second].get(); + if (bytes() == 2) { + tempTensor.reset(Tensor::create(realTensor->shape(), nullptr, TensorUtils::getDimType(realTensor))); + HALF_TO_FLOAT(realTensor->host(), tempTensor->host(), realTensor->elementSize()); + auto code = CPUTensorConverter::convert(tempTensor.get(), dstTensor); + if (NO_ERROR != code) { + MNN_ERROR("Error in NNAPIBackend::onCopyBuffer:convert\n"); + } + } else { + auto code = CPUTensorConverter::convert(realTensor, dstTensor); + if (NO_ERROR != code) { + MNN_ERROR("Error in NNAPIBackend::onCopyBuffer:convert\n"); + } } } } void NNAPIBackend::onResizeBegin() { + mHalfBuffer.clear(); } void NNAPIBackend::onResizeEnd() { buildModel(); + mHalfBuffer.clear(); } - uint32_t NNAPIBackend::getTensorIdx(const Tensor* t) { const auto& iter = mTensorIdxMap.find(t); if (iter != mTensorIdxMap.end()) { return iter->second; } - std::vector dims; + std::vector udims; for (auto d : t->shape()) { - dims.push_back(d); + udims.push_back(d); + } + dimsFormat(udims, TensorUtils::getDescribe(t)->dimensionFormat); + // scalar shape is {1} in NNAPI + if (udims.empty()) { + udims.push_back(1); + } + auto dtype = t->getType(); + auto code = ANEURALNETWORKS_TENSOR_FLOAT32; + if (dtype == halide_type_of()) { + code = ANEURALNETWORKS_TENSOR_INT32; } - std::vector udims(dims.begin(), dims.end()); - if (TensorUtils::getDescribe(t)->dimensionFormat != MNN_DATA_FORMAT_NHWC && !mNCHW) { - // NCHW -> NHWC - udims[0] = dims[0]; - udims[1] = dims[2]; - udims[2] = dims[3]; - udims[3] = dims[1]; + uint32_t idx = -1; + if (TensorUtils::getDescribe(t)->usage == Tensor::InsideDescribe::Usage::CONSTANT) { + idx = buildOperand(t->host(), t->size(), code, udims); + } else { + idx = buildOperand(nullptr, 0, code, udims); } - uint32_t idx = buildOperand(nullptr, 0, ANEURALNETWORKS_TENSOR_FLOAT32, udims); mTensorIdxMap.insert(std::make_pair(t, idx)); return idx; } + ErrorCode NNAPIBackend::replaceTensorWith(const Tensor* src, const Tensor* replace) { + const auto& iter = mTensorIdxMap.find(replace); + if (iter != mTensorIdxMap.end()) { + mTensorIdxMap.insert(std::make_pair(src, iter->second)); + return NO_ERROR; + } + MNN_ERROR("[NNAPI] The replace Tensor must register."); + return INVALID_VALUE; + } uint32_t NNAPIBackend::buildScalar(int scalar) { auto iter = mScalarIntMap.find(scalar); if (iter != mScalarIntMap.end()) { @@ -228,12 +306,22 @@ namespace MNN { if (iter != mScalarFloatMap.end()) { return iter->second; } - auto scalarIdx = buildOperand(&scalar, 4, ANEURALNETWORKS_FLOAT32); + uint32_t scalarIdx = -1; + if (bytes() == 2) { + uint16_t value = fp32to16(scalar); + scalarIdx = buildOperand(&value, 2, ANEURALNETWORKS_FLOAT16); + } else { + scalarIdx = buildOperand(&scalar, 4, ANEURALNETWORKS_FLOAT32); + } mScalarFloatMap.insert(std::make_pair(scalar, scalarIdx)); return scalarIdx; } - uint32_t NNAPIBackend::buildOperand(const void* data, size_t size, OperandCode code, std::vector dims) { + bool needQuant = (bytes() == 2 && code == ANEURALNETWORKS_TENSOR_FLOAT32); + if (needQuant) { + code = ANEURALNETWORKS_TENSOR_FLOAT16; + size /= 2; + } ANeuralNetworksOperandType operandType { .type = code, .dimensionCount = static_cast(dims.size()), @@ -243,32 +331,38 @@ namespace MNN { }; CHECK(ANeuralNetworksModel_addOperand_27, mNNAPIModel, &operandType); uint32_t operandIdx = mTensorIdx++; -#ifdef NNAPI_DEBUG - MNN_PRINT("build operand : {\n"); - MNN_PRINT("\tidx : %d\n", operandIdx); - MNN_PRINT("\tdata : %p\n", data); - MNN_PRINT("\tsize : %d\n", size); - MNN_PRINT("\ttype : %d\n", operandType.type); - MNN_PRINT("\tdimensions : [ "); - for (auto i : dims) MNN_PRINT("%d, ", i); - MNN_PRINT("]\n}\n"); -#endif + { + NNAPI_OP_LOG("build operand : {\n"); + NNAPI_OP_LOG("\tidx : %d\n", operandIdx); + NNAPI_OP_LOG("\tdata : %p\n", data); + NNAPI_OP_LOG("\tsize : %d\n", size); + NNAPI_OP_LOG("\ttype : %d\n", operandType.type); + NNAPI_OP_LOG("\tdimensions : [ "); + for (auto i : dims) NNAPI_OP_LOG("%d, ", i); + NNAPI_OP_LOG("]\n}\n"); + } if (data && size) { + if (needQuant) { + mHalfBuffer.emplace_back(new int16_t[size/2]); + FLOAT_TO_HALF(reinterpret_cast(data), mHalfBuffer.back().get(), size/2); + data = mHalfBuffer.back().get(); + } CHECK(ANeuralNetworksModel_setOperandValue_27, mNNAPIModel, operandIdx, data, size); } return operandIdx; } ErrorCode NNAPIBackend::buildOperation(int op, const std::vector &inputs, const std::vector &outputs, const char* name) { -#ifdef NNAPI_DEBUG - MNN_PRINT("build operation : {\n"); - MNN_PRINT("\ttype : %d\n", op); - MNN_PRINT("\tinputs : [ "); - for (auto i : inputs) MNN_PRINT("%d, ", i); - MNN_PRINT("]\n\toutputs : [ "); - for (auto i : outputs) MNN_PRINT("%d, ", i); - MNN_PRINT("]\n}\n"); -#endif + { + NNAPI_OP_LOG("build operation : {\n"); + NNAPI_OP_LOG("\tname : %s\n", name ? name : "none"); + NNAPI_OP_LOG("\ttype : %d\n", op); + NNAPI_OP_LOG("\tinputs : [ "); + for (auto i : inputs) NNAPI_OP_LOG("%d, ", i); + NNAPI_OP_LOG("]\n\toutputs : [ "); + for (auto i : outputs) NNAPI_OP_LOG("%d, ", i); + NNAPI_OP_LOG("]\n}\n"); + } if (name) mOpNames.push_back(name); CHECK(ANeuralNetworksModel_addOperation_27, mNNAPIModel, op, @@ -286,21 +380,20 @@ namespace MNN { for (int i = 0; i < mOutputTensors.size(); i++) { outputOperands[i] = getTensorIdx(mOutputTensors[i]); } -#ifdef NNAPI_DEBUG - MNN_PRINT("set model's inputs & outputs : {\n"); - MNN_PRINT("\tinputs : [ "); - for (auto i : inputOperands) MNN_PRINT("%d, ", i); - MNN_PRINT("]\n\toutputs : [ "); - for (auto i : outputOperands) MNN_PRINT("%d, ", i); - MNN_PRINT("]\n}\n"); -#endif + { + NNAPI_OP_LOG("set model's inputs & outputs : {\n"); + NNAPI_OP_LOG("\tinputs : [ "); + for (auto i : inputOperands) NNAPI_OP_LOG("%d, ", i); + NNAPI_OP_LOG("]\n\toutputs : [ "); + for (auto i : outputOperands) NNAPI_OP_LOG("%d, ", i); + NNAPI_OP_LOG("]\n}\n"); + } CHECK(ANeuralNetworksModel_identifyInputsAndOutputs_27, mNNAPIModel, inputOperands.size(), inputOperands.data(), outputOperands.size(), outputOperands.data()); - // segment fault CHECK(ANeuralNetworksModel_finish_27, mNNAPIModel); std::unique_ptr supports(new bool[mOpNames.size()]); int selectDeviceIdx = -1; @@ -309,16 +402,16 @@ namespace MNN { auto name = mNNAPIDevices[i].name; auto type = mNNAPIDevices[i].type; CHECK(ANeuralNetworksModel_getSupportedOperationsForDevices_29, mNNAPIModel, &device, 1, supports.get()); - MNN_PRINT("[NNAPI] device [%d : %s] supportOps = {\n", i, name); + NNAPI_DEVICE_LOG("[NNAPI] device [%d : %s] supportOps = {\n", i, name); bool allsupport = true; for (int i = 0; i < mOpNames.size(); i++) { allsupport &= supports[i]; - MNN_PRINT("\t%s : %d\n", mOpNames[i], supports[i]); + NNAPI_DEVICE_LOG("\t%s : %d\n", mOpNames[i], supports[i]); } - MNN_PRINT("}\n"); + NNAPI_DEVICE_LOG("}\n"); if (allsupport) { selectDeviceIdx = i; - MNN_PRINT("[NNAPI] using device [%d : %s : %d].\n", i, name, type); + NNAPI_DEVICE_LOG("[NNAPI] using device [%d : %s : %d].\n", i, name, type); break; } } @@ -330,11 +423,10 @@ namespace MNN { } void NNAPIBackend::invokeModel() const { -// #define NNAPI_PROFILE ANeuralNetworksExecution *execution; CHECK(ANeuralNetworksExecution_create_27, mNNAPICompilation, &execution); #ifdef NNAPI_PROFILE - CHECK(ANeuralNetworksExecution_setMeasureTiming, execution, true); + ANeuralNetworksExecution_setMeasureTiming_29(execution, true); #endif for (int i = 0; i < mInputTensors.size(); i++) { const void* data = mInputContentTensors[i]->host(); @@ -346,20 +438,13 @@ namespace MNN { size_t size = mOutputContentTensors[i]->size(); CHECK(ANeuralNetworksExecution_setOutput_27, execution, i, nullptr, data, size); } -#if 0 - ANeuralNetworksEvent *event = nullptr; - CHECK(ANeuralNetworksExecution_startCompute, execution, &event); - CHECK(ANeuralNetworksEvent_wait, event); - ANeuralNetworksEvent_free(event); -#else + CHECK(ANeuralNetworksExecution_compute_29, execution); - // CHECK(ANeuralNetworksExecution_burstCompute_29, execution, mNNAPIBurst); -#endif #ifdef NNAPI_PROFILE uint64_t duration; - CHECK(ANeuralNetworksExecution_getDuration, execution, ANEURALNETWORKS_DURATION_IN_DRIVER, &duration); + ANeuralNetworksExecution_getDuration_29(execution, ANEURALNETWORKS_DURATION_IN_DRIVER, &duration); if (duration != UINT64_MAX) MNN_PRINT("[NNAPI] driver time : %f ms\n", duration / 1000000.0); - CHECK(ANeuralNetworksExecution_getDuration, execution, ANEURALNETWORKS_DURATION_ON_HARDWARE, &duration); + ANeuralNetworksExecution_getDuration_29(execution, ANEURALNETWORKS_DURATION_ON_HARDWARE, &duration); if (duration != UINT64_MAX) MNN_PRINT("[NNAPI] hardware time : %f ms\n", duration / 1000000.0); #endif ANeuralNetworksExecution_free_27(execution); diff --git a/source/backend/nnapi/backend/NNAPIBackend.hpp b/source/backend/nnapi/backend/NNAPIBackend.hpp index 053cab74e..258ed9b76 100644 --- a/source/backend/nnapi/backend/NNAPIBackend.hpp +++ b/source/backend/nnapi/backend/NNAPIBackend.hpp @@ -66,13 +66,32 @@ namespace MNN { }; static bool addCreator(OpType t, Creator* c); // NNAPI functions - bool NCHW() { return mNCHW; } + bool NCHW() const { return mNCHW; } + int bytes() const { +#ifdef MNN_USE_ARMV82 + return mPrecision >= BackendConfig::PrecisionMode::Precision_Low ? 2 : 4; +#else + return 4; +#endif + } + template void dimsFormat(std::vector& dims, MNN_DATA_FORMAT format) { + if (dims.size() == 4) { + if (format != MNN_DATA_FORMAT_NHWC && !mNCHW) { + T n = dims[0], c = dims[1], h = dims[2], w = dims[3]; + dims[0] = n; + dims[1] = h; + dims[2] = w; + dims[3] = c; + } + } + } uint32_t getTensorIdx(const Tensor* t); uint32_t buildScalar(int scalar); uint32_t buildScalar(bool scalar); uint32_t buildScalar(float scalar); uint32_t buildOperand(const void* data, size_t size, OperandCode code, std::vector dims = {}); ErrorCode buildOperation(int op, const std::vector &inputs, const std::vector &outputs, const char* name = nullptr); + ErrorCode replaceTensorWith(const Tensor* src, const Tensor* replace); void buildModel(); void invokeModel() const; private: @@ -90,6 +109,8 @@ namespace MNN { std::map mScalarIntMap; std::map mScalarBoolMap; std::map mScalarFloatMap; + // fp16 buffer + std::vector> mHalfBuffer; // NNAPI resource struct NNAPIDevice { ANeuralNetworksDevice* device; diff --git a/source/backend/nnapi/backend/NNAPINeuralNetworks.h b/source/backend/nnapi/backend/NNAPINeuralNetworks.h index 2342f5f1c..082a1748f 100644 --- a/source/backend/nnapi/backend/NNAPINeuralNetworks.h +++ b/source/backend/nnapi/backend/NNAPINeuralNetworks.h @@ -15,7 +15,7 @@ */ /** - * @addtogroup MNNNeuralNetworks + * @addtogroup NeuralNetworks * @{ */ @@ -45,6 +45,7 @@ */ #include +#include #include #include #include @@ -90,7 +91,6 @@ typedef enum { * real_value = (integer_value - zeroPoint) * scale. */ ANEURALNETWORKS_TENSOR_QUANT8_ASYMM = 5, -// #if __ANDROID_API__ >= __ANDROID_API_Q__ /** * An 8 bit boolean scalar value. * @@ -182,7 +182,30 @@ typedef enum { * Available since API level 29. */ ANEURALNETWORKS_TENSOR_QUANT8_SYMM = 13, -// #endif // __ANDROID_API__ >= __ANDROID_API_Q__ + /** + * A tensor of 8 bit signed integers that represent real numbers. + * + * Attached to this tensor are two numbers that can be used to convert the + * 8 bit integer to the real value and vice versa. These two numbers are: + * - scale: a 32 bit floating point value greater than zero. + * - zeroPoint: a 32 bit integer, in range [-128, 127]. + * + * The formula is: + * real_value = (integer_value - zeroPoint) * scale. + * + * Available since API level 30. + */ + ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED = 14, + + /** + * A reference to a model. + * + * {@link ANeuralNetworksModel_setOperandValueFromModel} must be used to set + * the value for an Operand of this type. + * + * Available since API level 30. + */ + ANEURALNETWORKS_MODEL = 15, } OperandCode; /** @@ -224,6 +247,8 @@ typedef enum { * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29) * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30) + * * {@link ANEURALNETWORKS_TENSOR_INT32} (since API level 30) * * Supported tensor rank: up to 4 * @@ -231,15 +256,19 @@ typedef enum { * * 0: A tensor. * * 1: A tensor of the same {@link OperandCode}, and compatible dimensions * as input0. - * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} tensor, + * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and + * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scales and zeroPoint can be different from input0 scale and zeroPoint. * * 2: An {@link ANEURALNETWORKS_INT32} scalar, and has to be one of the * {@link FuseCode} values. Specifies the activation to * invoke on the result. + * For a {@link ANEURALNETWORKS_TENSOR_INT32} tensor, + * the {@link FuseCode} must be "NONE". * * Outputs: * * 0: The sum, a tensor of the same {@link OperandCode} as input0. - * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} tensor, + * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and + * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint can be different from inputs' scale and zeroPoint. * * Available since API level 27. @@ -263,6 +292,7 @@ typedef enum { * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29) * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: @@ -324,7 +354,8 @@ typedef enum { * Outputs: * * 0: The output 4-D tensor, of shape * [batches, out_height, out_width, depth]. - * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} tensor, + * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and + * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. * * Available since API level 27. @@ -342,6 +373,7 @@ typedef enum { * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} * (full support since API level 29, see the input section) + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30) * * Supported tensor rank: up to 4 * @@ -351,6 +383,9 @@ typedef enum { * Before API level 29, all input tensors of * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} * must have the same scale and zeroPoint as the output tensor. + * Input tensors of + * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} + * are allowed to have different scale and zeroPoint. * Since API level 29, zero-sized tensors are supported. * * n: An {@link ANEURALNETWORKS_INT32} scalar, specifying the * concatenation axis. @@ -403,6 +438,18 @@ typedef enum { * * * {@link ANEURALNETWORKS_TENSOR_INT32} for bias (scale set to 0.0, * * * each value scaling is separate and equal to input.scale * filter.scales[channel]). * + * Available since API level 30: + * * Quantized signed (since API level 30): + * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} for input, filter, and output. + * * * {@link ANEURALNETWORKS_TENSOR_INT32} for bias (with scale set to + * * * input.scale * filter.scale). + * + * * Quantized signed with filter symmetric per channel quantization (since API level 30): + * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} for input, and output. + * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter. + * * * {@link ANEURALNETWORKS_TENSOR_INT32} for bias (scale set to 0.0, + * * * each value scaling is separate and equal to input.scale * filter.scales[channel]). + * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: * [batch, height, width, channels]. Alternatively, the data layout could @@ -423,8 +470,9 @@ typedef enum { * must be set to 0. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link ANEURALNETWORKS_TENSOR_FLOAT32} - * or {@link ANEURALNETWORKS_TENSOR_FLOAT16} the bias must be of the same - * type. For filter tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}, + * or {@link ANEURALNETWORKS_TENSOR_FLOAT16} the bias must be of the same type. + * For filter tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} + * and {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED}, * the bias should be of {@link ANEURALNETWORKS_TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. * For filter tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL}, @@ -473,7 +521,9 @@ typedef enum { * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link ANEURALNETWORKS_TENSOR_FLOAT32} * or {@link ANEURALNETWORKS_TENSOR_FLOAT16} the bias must be of the same - * type. For filter tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}, + * type. + * For filter tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} + * and {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED}, * the bias should be of {@link ANEURALNETWORKS_TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. * For filter tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL}, @@ -555,6 +605,18 @@ typedef enum { * * * {@link ANEURALNETWORKS_TENSOR_INT32} for bias (scale set to 0.0, * * * each value scaling is separate and equal to input.scale * filter.scales[channel]). * + * Available since API level 30: + * * Quantized signed (since API level 30): + * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} for input, filter, and output. + * * * {@link ANEURALNETWORKS_TENSOR_INT32} for bias (with scale set to + * * * input.scale * filter.scale). + * + * * Quantized signed with filter symmetric per channel quantization (since API level 30): + * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} for input, and output. + * * * {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL} for filter. + * * * {@link ANEURALNETWORKS_TENSOR_INT32} for bias (scale set to 0.0, + * * * each value scaling is separate and equal to input.scale * filter.scales[channel]). + * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: * [batch, height, width, channels]. Alternatively, the data layout could @@ -573,8 +635,9 @@ typedef enum { * must be set to 3. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link ANEURALNETWORKS_TENSOR_FLOAT32} - * or {@link ANEURALNETWORKS_TENSOR_FLOAT16} the bias must be of the same - * type. For filter tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}, + * or {@link ANEURALNETWORKS_TENSOR_FLOAT16} the bias must be of the same type. + * For filter tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} + * and {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED}, * the bias should be of {@link ANEURALNETWORKS_TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. * For filter tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL}, @@ -619,8 +682,9 @@ typedef enum { * specifying the filter. * * 2: A 1-D tensor, of shape [depth_out], specifying the bias. For input * tensor of type {@link ANEURALNETWORKS_TENSOR_FLOAT32} - * or {@link ANEURALNETWORKS_TENSOR_FLOAT16} the bias must be of the same - * type. For filter tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}, + * or {@link ANEURALNETWORKS_TENSOR_FLOAT16} the bias must be of the same type. + * For filter tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} + * and {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED}, * the bias should be of {@link ANEURALNETWORKS_TENSOR_INT32}, with zeroPoint * of 0 and bias_scale == input_scale * filter_scale. * For filter tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL}, @@ -683,6 +747,7 @@ typedef enum { * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29) * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: @@ -703,7 +768,8 @@ typedef enum { * Outputs: * * 0: The output 4-D tensor, of shape [batch, height*block_size, * width*block_size, depth/(block_size*block_size)]. - * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} tensor, + * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and + * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. * * Available since API level 27. @@ -721,6 +787,7 @@ typedef enum { * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} * * {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM} (since API level 29) * * {@link ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL} (since API level 29) + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30) * * Supported output tensor {@link OperandCode}: * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29) @@ -760,9 +827,11 @@ typedef enum { * and an error must be reported. * * Supported value tensor {@link OperandCode}: + * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 30) * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} - * * {@link ANEURALNETWORKS_TENSOR_INT32} - * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} + * * {@link ANEURALNETWORKS_TENSOR_INT32} (since API level 29) + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} (since API level 29) + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30) * * Supported value tensor rank: from 2 * @@ -776,7 +845,8 @@ typedef enum { * * 0: A n-D tensor with the same rank and shape as the Values * tensor, except for the first dimension which has the same size * as Lookups' only dimension. - * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} tensor, + * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and + * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input1. * * Available since API level 27. @@ -815,6 +885,7 @@ typedef enum { * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29) * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30) * * Supported tensor rank: up to 4. * @@ -832,10 +903,11 @@ typedef enum { * of output nodes. * * 2: A 1-D tensor, of shape [num_units], specifying the bias. For input * tensor of {@link ANEURALNETWORKS_TENSOR_FLOAT32}, the bias should - * also be of {@link ANEURALNETWORKS_TENSOR_FLOAT32}. For input tensor - * of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}, the bias should be - * of {@link ANEURALNETWORKS_TENSOR_INT32}, with zeroPoint of 0 and - * bias_scale == input_scale * filter_scale. + * also be of {@link ANEURALNETWORKS_TENSOR_FLOAT32}. + * For input tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} + * and {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED}, + * the bias should be of {@link ANEURALNETWORKS_TENSOR_INT32}, + * with zeroPoint of 0 and bias_scale == input_scale * filter_scale. * * 3: An {@link ANEURALNETWORKS_INT32} scalar, and has to be one of the * {@link FuseCode} values. Specifies the activation to * invoke on the result. @@ -909,7 +981,7 @@ typedef enum { ANEURALNETWORKS_HASHTABLE_LOOKUP = 10, /** - * Applies L2 normalization along the depth dimension. + * Applies L2 normalization along the axis dimension. * * The values in the output tensor are computed as: * @@ -917,13 +989,13 @@ typedef enum { * input[batch, row, col, channel] / * sqrt(sum_{c} pow(input[batch, row, col, c], 2)) * - * For input tensor with rank less than 4, independently normalizes each - * 1-D slice along dimension dim. + * By default the axis dimension is the last dimension of the input tensor. * * Supported tensor {@link OperandCode}: * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29) * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} (since API level 29) + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30) * * Supported tensor rank: up to 4 * Tensors with rank less than 4 are only supported since API level 29. @@ -940,6 +1012,12 @@ typedef enum { * * 0: A tensor of the same {@link OperandCode} and same shape as input0. * For {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}, * the scale must be 1.f / 128 and the zeroPoint must be 128. + * For {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED}, + * the scale must be 1.f / 128 and the zeroPoint must be 0. + * + * NOTE: Before API level 30, if the elements along an axis are all zeros, + * the result is undefined. Since API level 30, if the elements along an axis + * are all zeros, the result is logical zero. * * Available since API level 27. */ @@ -1094,6 +1172,7 @@ typedef enum { * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29) * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30) * * Supported tensor rank: up to 4. * @@ -1105,6 +1184,8 @@ typedef enum { * * 0: The output tensor of same shape as input0. * For {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}, * the scale must be 1.f / 256 and the zeroPoint must be 0. + * For {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED}, + * the scale must be 1.f / 256 and the zeroPoint must be -128. * * Available since API level 27. */ @@ -1405,6 +1486,7 @@ typedef enum { * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29) * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: @@ -1466,7 +1548,8 @@ typedef enum { * Outputs: * * 0: The output 4-D tensor, of shape * [batches, out_height, out_width, depth]. - * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} tensor, + * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and + * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. * * Available since API level 27. @@ -1496,6 +1579,8 @@ typedef enum { * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29) * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30) + * * {@link ANEURALNETWORKS_TENSOR_INT32} (since API level 30) * * Supported tensor rank: up to 4 * @@ -1506,10 +1591,13 @@ typedef enum { * * 2: An {@link ANEURALNETWORKS_INT32} scalar, and has to be one of the * {@link FuseCode} values. Specifies the activation to * invoke on the result. + * For a {@link ANEURALNETWORKS_TENSOR_INT32} tensor, + * the {@link FuseCode} must be "NONE". * * Outputs: * * 0: The product, a tensor of the same {@link OperandCode} as input0. - * For output tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}, + * For output tensor of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} + * and {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED}, * the following condition must be satisfied: * output_scale > input1_scale * input2_scale. * @@ -1528,6 +1616,7 @@ typedef enum { * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29) * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30) * * Supported tensor rank: up to 4. * @@ -1537,7 +1626,8 @@ typedef enum { * * Outputs: * * 0: The output tensor of same shape as input0. - * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} tensor, + * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and + * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. * * Available since API level 27. @@ -1555,6 +1645,7 @@ typedef enum { * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29) * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30) * * Supported tensor rank: up to 4. * @@ -1564,7 +1655,8 @@ typedef enum { * * Outputs: * * 0: The output tensor of the same shape as input0. - * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} tensor, + * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and + * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. * * Available since API level 27. @@ -1582,6 +1674,7 @@ typedef enum { * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29) * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30) * * Supported tensor rank: up to 4. * @@ -1591,7 +1684,8 @@ typedef enum { * * Outputs: * * 0: The output tensor of same shape as input0. - * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} tensor, + * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and + * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. * * Available since API level 27. @@ -1608,6 +1702,7 @@ typedef enum { * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29) * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30) * * Supported tensor rank: up to 4. * @@ -1624,7 +1719,8 @@ typedef enum { * * Outputs: * * 0: The output tensor, of shape specified by the input shape. - * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} tensor, + * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and + * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. * * Available since API level 27. @@ -1642,6 +1738,7 @@ typedef enum { * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29) * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} (since API level 29) + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: @@ -1662,6 +1759,17 @@ typedef enum { * * 3: An optional {@link ANEURALNETWORKS_BOOL} scalar, default to false. * Set to true to specify NCHW data layout for input0 and output0. * Available since API level 29. + * * 4: Align corners. An optional {@link ANEURALNETWORKS_BOOL} + * scalar, default to false. If True, the centers of the 4 corner + * pixels of the input and output tensors are aligned, preserving the + * values at the corner pixels. + * Available since API level 30. + * * 5: Half pixel centers. An optional {@link ANEURALNETWORKS_BOOL} + * scalar, default to false. If True, the pixel centers are assumed to + * be at (0.5, 0.5). This is the default behavior of image.resize in + * TF 2.0. If this parameter is True, then align_corners parameter + * must be False. + * Available since API level 30. * * Inputs (resizing by scale, since API level 29): * * 0: A 4-D tensor, of shape [batches, height, width, depth], specifying @@ -1680,10 +1788,24 @@ typedef enum { * {@link ANEURALNETWORKS_FLOAT32} otherwise. * * 3: An optional {@link ANEURALNETWORKS_BOOL} scalar, default to false. * Set to true to specify NCHW data layout for input0 and output0. + * * 4: Align corners. An optional {@link ANEURALNETWORKS_BOOL} + * scalar, default to false. If True, the centers of the 4 corner + * pixels of the input and output tensors are aligned, preserving the + * values at the corner pixels. + * Available since API level 30. + * * 5: Half pixel centers. An optional {@link ANEURALNETWORKS_BOOL} + * scalar, default to false. If True, the pixel centers are assumed to + * be at (0.5, 0.5). This is the default behavior of image.resize in + * TF 2.0. If this parameter is True, then align_corners parameter + * must be False. + * Available since API level 30. * * Outputs: * * 0: The output 4-D tensor, of shape * [batches, new_height, new_width, depth]. + * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and + * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor, + * the scale and zeroPoint must be the same as input0. * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} tensor, * the scale and zeroPoint must be the same as input0. * @@ -1763,6 +1885,7 @@ typedef enum { * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29) * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30) * * Supported tensor rank: up to 4. * Tensors with rank other than 2 or 4 are only supported since API level 29. @@ -1771,9 +1894,10 @@ typedef enum { * * 0: A 2-D or 4-D tensor, specifying the tensor to be reshaped. * Since API level 29, this tensor may be zero-sized. * * 1: A scalar, specifying the positive scaling factor for the exponent, - * beta. If input0 is of {@link ANEURALNETWORKS_TENSOR_FLOAT32} or - * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}, the scalar must be of - * {@link ANEURALNETWORKS_FLOAT32}. + * beta. If input0 is of {@link ANEURALNETWORKS_TENSOR_FLOAT32}, + * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} or + * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED}, the scalar + * must be of {@link ANEURALNETWORKS_FLOAT32}. * If input0 is of {@link ANEURALNETWORKS_TENSOR_FLOAT16}, then the * scalar must be of {@link ANEURALNETWORKS_FLOAT16}. * * 2: An optional {@link ANEURALNETWORKS_INT32} scalar, default to -1, @@ -1786,6 +1910,8 @@ typedef enum { * * 0: The output tensor of same shape as input0. * For {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}, * the scale must be 1.f / 256 and the zeroPoint must be 0. + * For {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED}, + * the scale must be 1.f / 256 and the zeroPoint must be -128. * * Available since API level 27. */ @@ -1809,6 +1935,7 @@ typedef enum { * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29) * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: @@ -1829,7 +1956,8 @@ typedef enum { * Outputs: * * 0: The output 4-D tensor, of shape [batches, height/block_size, * width/block_size, depth_in*block_size*block_size]. - * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} tensor, + * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and + * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. * * Available since API level 27. @@ -1926,6 +2054,7 @@ typedef enum { * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29) * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} (since API level 29) + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30) * * Supported tensor rank: up to 4. * @@ -1937,6 +2066,8 @@ typedef enum { * * 0: The output tensor of same shape as input0. * For {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}, * the scale must be 1.f / 128 and the zeroPoint must be 128. + * For {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED}, + * the scale must be 1.f / 128 and the zeroPoint must be 0. * * Available since API level 27. */ @@ -1958,6 +2089,7 @@ typedef enum { * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29) * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. * With the default data layout NHWC, the data is stored in the order of: @@ -1976,7 +2108,8 @@ typedef enum { * * Outputs: * * 0: A tensor of the same {@link OperandCode} as input0. - * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} tensor, + * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and + * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. * * Available since API level 28. @@ -1990,6 +2123,11 @@ typedef enum { * dimensions. The output is the result of dividing the first input tensor * by the second, optionally modified by an activation function. * + * For inputs of {@link ANEURALNETWORKS_TENSOR_INT32}, performs + * "floor division" ("//" in Python). For example, + * 5 // 2 = 2 + * -5 // 2 = -3 + * * Two dimensions are compatible when: * 1. they are equal, or * 2. one of them is 1 @@ -2010,6 +2148,7 @@ typedef enum { * Supported tensor {@link OperandCode}: * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29) * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} + * * {@link ANEURALNETWORKS_TENSOR_INT32} (since API level 30) * * Supported tensor rank: up to 4 * @@ -2020,6 +2159,8 @@ typedef enum { * * 2: An {@link ANEURALNETWORKS_INT32} scalar, and has to be one of the * {@link FuseCode} values. Specifies the activation to * invoke on the result. + * For a {@link ANEURALNETWORKS_TENSOR_INT32} tensor, + * the {@link FuseCode} must be "NONE". * * Outputs: * * 0: A tensor of the same {@link OperandCode} as input0. @@ -2040,6 +2181,7 @@ typedef enum { * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29) * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30) * * Supported tensor rank: up to 4 * @@ -2059,8 +2201,11 @@ typedef enum { * * Outputs: * * 0: A tensor of the same {@link OperandCode} as input0. - * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} tensor, - * the scale and zeroPoint must be same as input0. + * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and + * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor, + * the scale and zeroPoint must be the same as input0. + * If all dimensions are reduced and keep_dims is false, the output + * shape is [1]. * * Available since API level 28. */ @@ -2075,6 +2220,7 @@ typedef enum { * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29) * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30) * (full support since API level 29, see the output section) * * Supported tensor rank: up to 4 @@ -2097,7 +2243,8 @@ typedef enum { * of the padding: * output0.dimension[i] = * padding[i, 0] + input0.dimension[i] + padding[i, 1] - * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} tensor, + * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and + * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. * * NOTE: Before API level 29, the pad value for @@ -2123,6 +2270,7 @@ typedef enum { * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29) * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30) * (full support since API level 29, see the output section) * * Supported tensor rank: 4, with "NHWC" or "NCHW" data layout. @@ -2150,7 +2298,8 @@ typedef enum { * * Outputs: * * 0: A tensor of the same {@link OperandCode} as input0. - * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} tensor, + * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and + * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. * * NOTE: Before API level 29, the pad value for @@ -2173,6 +2322,7 @@ typedef enum { * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29) * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30) * * Supported tensor rank: up to 4 * @@ -2188,8 +2338,11 @@ typedef enum { * * 0: A tensor of the same {@link OperandCode} as input0. Contains the * same data as input, but has one or more dimensions of size 1 * removed. - * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} tensor, + * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and + * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. + * If all input dimensions are equal to 1 and are to be squeezed, the + * output shape is [1]. * * Available since API level 28. */ @@ -2208,6 +2361,7 @@ typedef enum { * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29) * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30) * * Supported tensor rank: up to 4 * @@ -2237,8 +2391,11 @@ typedef enum { * Outputs: * * 0: A tensor of the same {@link OperandCode} as input0 and rank (n - k), * where k is the number of bits set in shrink_axis_mask. - * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} tensor, + * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and + * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. + * If shrink_axis_mask is true for all input dimensions, the output + * shape is [1]. * * Available since API level 28. */ @@ -2272,6 +2429,8 @@ typedef enum { * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29) * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} (since API level 29) + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30) + * * {@link ANEURALNETWORKS_TENSOR_INT32} (since API level 30) * * Supported tensor rank: up to 4 * @@ -2282,10 +2441,13 @@ typedef enum { * * 2: An {@link ANEURALNETWORKS_INT32} scalar, and has to be one of the * {@link FuseCode} values. Specifies the activation to * invoke on the result. + * For a {@link ANEURALNETWORKS_TENSOR_INT32} tensor, + * the {@link FuseCode} must be "NONE". * * Outputs: * * 0: A tensor of the same {@link OperandCode} as input0. - * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} tensor, + * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and + * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint can be different from inputs' scale and zeroPoint. * * Available since API level 28. @@ -2305,6 +2467,7 @@ typedef enum { * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} (since API level 29) * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30) * * Supported tensor rank: up to 4 * @@ -2316,7 +2479,8 @@ typedef enum { * * Outputs: * * 0: A tensor of the same {@link OperandCode} as input0. - * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} tensor, + * For a {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} and + * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} tensor, * the scale and zeroPoint must be the same as input0. * * Available since API level 28. @@ -2331,6 +2495,7 @@ typedef enum { * Supported tensor {@link OperandCode}: * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} + * * {@link ANEURALNETWORKS_TENSOR_INT32} (since API level 30) * * Supported tensor rank: from 1. * @@ -2352,6 +2517,7 @@ typedef enum { * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} * * {@link ANEURALNETWORKS_TENSOR_INT32} * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30) * * Supported tensor rank: from 1 * @@ -2363,6 +2529,7 @@ typedef enum { * * Outputs: * * 0: An (n - 1)-D {@link ANEURALNETWORKS_TENSOR_INT32} tensor. + * If input is 1-dimensional, the output shape is [1]. * * Available since API level 29. */ @@ -2378,6 +2545,7 @@ typedef enum { * * {@link ANEURALNETWORKS_TENSOR_FLOAT32} * * {@link ANEURALNETWORKS_TENSOR_INT32} * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} + * * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED} (since API level 30) * * Supported tensor rank: from 1 * @@ -2389,6 +2557,7 @@ typedef enum { * * Outputs: * * 0: An (n - 1)-D {@link ANEURALNETWORKS_TENSOR_INT32} tensor. + * If input is 1-dimensional, the output shape is [1]. * * Available since API level 29. */ @@ -2421,7 +2590,8 @@ typedef enum { * and height, dw and dh is the log-scale relative correction factor * for the width and height. For input0 of type * {@link ANEURALNETWORKS_TENSOR_QUANT16_ASYMM}, this tensor should be - * of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM}. Zero num_rois is + * of {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM} or + * {@link ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED}. Zero num_rois is * supported for this tensor. * * 2: An 1-D {@link ANEURALNETWORKS_TENSOR_INT32} tensor, of shape * [num_rois], specifying the batch index of each box. Boxes with @@ -2443,7 +2613,54 @@ typedef enum { ANEURALNETWORKS_AXIS_ALIGNED_BBOX_TRANSFORM = 41, /** - * Performs a forward LSTM on the input followed by a backward LSTM. + * A recurrent neural network layer that applies an LSTM cell to a + * sequence of inputs in forward and backward directions. + * + * The op supports cross-linking via an auxiliary input. Regular cell feeds + * one input into the two RNN cells in the following way: + * + * INPUT (INPUT_REVERSED) + * | | + * --------------------- + * | FW_LSTM BW_LSTM | + * --------------------- + * | | + * FW_OUT BW_OUT + * + * An op with cross-linking takes two inputs and feeds them into the RNN + * cells in the following way: + * + * AUX_INPUT (AUX_INPUT_REVERSED) + * | | + * INPUT | (INPUT_R'D.)| + * | | | | + * ----------------------- + * | \ / \ / | + * | FW_LSTM BW_LSTM | + * ----------------------- + * | | + * FW_OUT BW_OUT + * + * The cross-linking mode is enabled iff auxiliary input and auxiliary + * weights are present. While stacking this op on top of itself, this + * allows to connect both forward and backward outputs from previous cell + * to the next cell's input. + * + * Since API level 30 parallel linking mode is supported. The mode is + * enabled if auxiliary input is present but auxiliary weights are omitted. + * In this case, the cell feeds inputs into the RNN in the following way: + * + * INPUT (AUX_INPUT_REVERSED) + * | | + * --------------------- + * | FW_LSTM BW_LSTM | + * --------------------- + * | | + * FW_OUT BW_OUT + * + * While stacking this op on top of itself, this allows to connect both + * forward and backward outputs from previous cell to the next cell's + * corresponding inputs. * * Supported tensor {@link OperandCode}: * * {@link ANEURALNETWORKS_TENSOR_FLOAT16} @@ -2453,7 +2670,6 @@ typedef enum { * * All input and output tensors must be of the same type. * - * * Inputs: * * 0: The input. * A 3-D tensor of shape: @@ -2545,25 +2761,34 @@ typedef enum { * * 38: The backward input cell state. * A 2-D tensor of shape [batch_size, bw_num_units]. * * 39: The auxiliary input. Optional. - * A 3-D tensor of shape [max_time, batch_size, input_size], where “batch_size” - * corresponds to the batching dimension, and “input_size” is the size - * of the input. - * * 40: The forward auxiliary input-to-input weights. Optional. - * A 2-D tensor of shape [fw_num_units, input_size]. - * * 41: The forward auxiliary input-to-forget weights. Optional. - * A 2-D tensor of shape [fw_num_units, input_size]. - * * 42: The forward auxiliary input-to-cell weights. Optional. - * A 2-D tensor of shape [fw_num_units, input_size]. - * * 43: The forward auxiliary input-to-output weights. Optional. - * A 2-D tensor of shape [fw_num_units, input_size]. - * * 44: The backward auxiliary input-to-input weights. Optional. - * A 2-D tensor of shape [bw_num_units, input_size]. - * * 45: The backward auxiliary input-to-forget weights. Optional. - * A 2-D tensor of shape [bw_num_units, input_size]. - * * 46: The backward auxiliary input-to-cell weights. Optional. - * A 2-D tensor of shape [bw_num_units, input_size]. - * * 47: The backward auxiliary input-to-output weights. Optional. - * A 2-D tensor of shape [bw_num_units, input_size]. + * A 3-D tensor of shape [max_time, batch_size, aux_input_size], + * where “batch_size” corresponds to the batching dimension, and + * “aux_input_size” is the size of the auxiliary input. Optional. See + * the docs above for the usage modes explanation. + * * 40: The forward auxiliary input-to-input weights. + * Optional. See the docs above for the usage modes explanation. + * A 2-D tensor of shape [fw_num_units, aux_input_size]. + * * 41: The forward auxiliary input-to-forget weights. + * Optional. See the docs above for the usage modes explanation. + * A 2-D tensor of shape [fw_num_units, aux_input_size]. + * * 42: The forward auxiliary input-to-cell weights. + * Optional. See the docs above for the usage modes explanation. + * A 2-D tensor of shape [fw_num_units, aux_input_size]. + * * 43: The forward auxiliary input-to-output weights. + * Optional. See the docs above for the usage modes explanation. + * A 2-D tensor of shape [fw_num_units, aux_input_size]. + * * 44: The backward auxiliary input-to-input weights. + * Optional. See the docs above for the usage modes explanation. + * A 2-D tensor of shape [bw_num_units, aux_input_size]. + * * 45: The backward auxiliary input-to-forget weights. + * Optional. See the docs above for the usage modes explanation. + * A 2-D tensor of shape [bw_num_units, aux_input_size]. + * * 46: The backward auxiliary input-to-cell weights. + * Optional. See the docs above for the usage modes explanation. + * A 2-D tensor of shape [bw_num_units, aux_input_size]. + * * 47: The backward auxiliary input-to-output weights. + * Optional. See the docs above for the usage modes explanation. + * A 2-D tensor of shape [bw_num_units, aux_input_size]. * * 48: The activation function. * A value indicating the activation function: *