From 943a25a47b98a60811f85d3e46a3308a64b1888a Mon Sep 17 00:00:00 2001 From: yoni baehr Date: Mon, 3 Aug 2020 17:24:16 +0300 Subject: [PATCH] train on device --- mindspore/lite/schema/model.fbs | 13 + mindspore/lite/schema/ops.fbs | 115 +++- mindspore/lite/src/common/file_utils_ext.cc | 53 ++ mindspore/lite/src/common/file_utils_ext.h | 28 + mindspore/lite/src/lite_kernel.h | 8 +- .../kernel/arm/fp32/activation_grad.cc | 110 ++++ .../runtime/kernel/arm/fp32/activation_grad.h | 50 ++ .../kernel/arm/fp32/arithmetic_grad.cc | 285 ++++++++++ .../runtime/kernel/arm/fp32/arithmetic_grad.h | 90 +++ .../src/runtime/kernel/arm/fp32/bias_grad.cc | 115 ++++ .../src/runtime/kernel/arm/fp32/bias_grad.h | 46 ++ .../runtime/kernel/arm/fp32/bngrad_input.cc | 115 ++++ .../runtime/kernel/arm/fp32/bngrad_input.h | 41 ++ .../arm/fp32/convolution_grad_filter.cc | 156 ++++++ .../kernel/arm/fp32/convolution_grad_filter.h | 41 ++ .../kernel/arm/fp32/convolution_grad_input.cc | 136 +++++ .../kernel/arm/fp32/convolution_grad_input.h | 41 ++ .../runtime/kernel/arm/fp32/opt_momentum.cc | 78 +++ .../runtime/kernel/arm/fp32/opt_momentum.h | 40 ++ .../runtime/kernel/arm/fp32/pooling_grad.cc | 195 +++++++ .../runtime/kernel/arm/fp32/pooling_grad.h | 50 ++ .../src/runtime/kernel/arm/fp32/power_grad.cc | 67 +++ .../src/runtime/kernel/arm/fp32/power_grad.h | 49 ++ ...parse_softmax_cross_entropy_with_logits.cc | 145 +++++ ...sparse_softmax_cross_entropy_with_logits.h | 50 ++ .../kernel/arm/opclib/activation_grad.h | 88 +++ .../runtime/kernel/arm/opclib/batch_norm.cc | 120 ++++ .../runtime/kernel/arm/opclib/batch_norm.h | 39 ++ .../kernel/arm/opclib/fp32/arithmetic_grad.cc | 29 + .../kernel/arm/opclib/fp32/arithmetic_grad.h | 22 + .../runtime/kernel/arm/opclib/fp32/gemm.cc | 108 ++++ .../src/runtime/kernel/arm/opclib/fp32/gemm.h | 23 + .../kernel/arm/opclib/fp32/pooling_grad.cc | 149 +++++ .../kernel/arm/opclib/fp32/pooling_grad.h | 25 + .../kernel/arm/opclib/fp32/reduce_grad.cc | 130 +++++ .../kernel/arm/opclib/fp32/reduce_grad.h | 24 + .../kernel/arm/opclib/fp32/softmax_grad.h | 29 + .../src/runtime/kernel/arm/opclib/pack_ext.cc | 176 ++++++ .../src/runtime/kernel/arm/opclib/pack_ext.h | 26 + mindspore/lite/test/CMakeLists.txt | 1 + .../arm/fp32/activation_grad_fp32_tests.cc | 312 +++++++++++ .../arm/fp32/arithmetic_grad_fp32_tests.cc | 497 +++++++++++++++++ .../kernel/arm/fp32/bias_grad_fp32_tests.cc | 71 +++ .../arm/fp32/convolution_grad_fp32_tests.cc | 521 ++++++++++++++++++ .../arm/fp32/pooling_grad_fp32_tests.cc | 332 +++++++++++ .../activationGrad/hsigmoid_out_50.bin | 1 + .../activationGrad/hsigmoid_x_50.bin | 1 + .../activationGrad/hsigmoid_yt_50.bin | 1 + .../activationGrad/hswish_out_50.bin | 1 + .../test_data/activationGrad/hswish_x_50.bin | 1 + .../test_data/activationGrad/hswish_yt_50.bin | Bin 0 -> 40 bytes .../test_data/activationGrad/lrelu_out_50.bin | Bin 0 -> 200 bytes .../test_data/activationGrad/lrelu_y_50.bin | 1 + .../test_data/activationGrad/lrelu_yt_50.bin | Bin 0 -> 200 bytes .../test_data/activationGrad/relu6_out_50.bin | Bin 0 -> 200 bytes .../test_data/activationGrad/relu6_y_50.bin | Bin 0 -> 200 bytes .../test_data/activationGrad/relu6_yt_50.bin | Bin 0 -> 200 bytes .../test_data/activationGrad/relu_out_50.bin | Bin 0 -> 200 bytes .../test_data/activationGrad/relu_y_50.bin | Bin 0 -> 200 bytes .../test_data/activationGrad/relu_yt_50.bin | Bin 0 -> 200 bytes .../activationGrad/sigmoid_out_50.bin | 1 + .../test_data/activationGrad/sigmoid_y_50.bin | 1 + .../activationGrad/sigmoid_yt_50.bin | 1 + .../test_data/activationGrad/tanh_out_50.bin | 2 + .../test_data/activationGrad/tanh_y_50.bin | Bin 0 -> 200 bytes .../test_data/activationGrad/tanh_yt_50.bin | Bin 0 -> 200 bytes .../test_data/conv/convfp32_dw_32_3_3_3.bin | 0 .../conv/convfp32_dw_g3_18_3_3_3.bin | 0 .../conv/convfp32_dw_g3_d2_18_3_3_3.bin | 0 .../test_data/conv/convfp32_dx_1_28_28_3.bin | 0 .../conv/convfp32_dx_g3_1_28_28_3.bin | 0 .../conv/convfp32_dx_g3_d2_1_28_28_3.bin | 0 .../test_data/conv/convfp32_dy_1_28_28_32.bin | 0 .../conv/convfp32_dy_g3_1_28_28_18.bin | 0 .../conv/convfp32_dy_g3_d2_1_26_26_18.bin | 0 .../test_data/conv/convfp32_w_32_3_3_3.bin | 0 .../test_data/conv/convfp32_w_g3_18_3_3_3.bin | 4 + .../conv/convfp32_w_g3_d2_18_3_3_3.bin | 0 .../test_data/conv/convfp32_x_1_28_28_3.bin | 0 .../conv/convfp32_x_g3_1_28_28_3.bin | 0 .../conv/convfp32_x_g3_d2_1_28_28_3.bin | 0 .../conv/convfp32_y_g3_d2_1_26_26_18.bin | 0 .../test_data/matmul/matmulfp32_a_10x4.bin | Bin 0 -> 160 bytes .../test_data/matmul/matmulfp32_a_4x10.bin | Bin 0 -> 160 bytes .../test_data/matmul/matmulfp32_b_10x5.bin | Bin 0 -> 200 bytes .../test_data/matmul/matmulfp32_b_5x10.bin | Bin 0 -> 200 bytes .../arm/test_data/matmul/matmulfp32_c_4x5.bin | 1 + .../arithmetic_fp32_10_dx1_5_4_6.bin | Bin 0 -> 480 bytes .../arithmetic_fp32_10_dx2_5_1_6.bin | Bin 0 -> 120 bytes .../operators/arithmetic_fp32_10_dy_5_4_6.bin | 1 + .../operators/arithmetic_fp32_1_dx1_4_6.bin | 1 + .../operators/arithmetic_fp32_1_dx2_1_6.bin | 1 + .../operators/arithmetic_fp32_1_dy_4_6.bin | 1 + .../operators/arithmetic_fp32_1_x1_4_6.bin | 1 + .../operators/arithmetic_fp32_1_x2_1_6.bin | 1 + .../operators/arithmetic_fp32_2_dx1_4_6.bin | Bin 0 -> 96 bytes .../operators/arithmetic_fp32_2_dx2_1_6.bin | 1 + .../operators/arithmetic_fp32_2_dy_4_6.bin | Bin 0 -> 96 bytes .../operators/arithmetic_fp32_3_dx1_4_6.bin | Bin 0 -> 96 bytes .../operators/arithmetic_fp32_3_dx2_1_6.bin | 1 + .../operators/arithmetic_fp32_3_dy_4_6.bin | Bin 0 -> 96 bytes .../operators/arithmetic_fp32_4_dx1_4_6.bin | 2 + .../operators/arithmetic_fp32_4_dx2_1_6.bin | 1 + .../operators/arithmetic_fp32_4_dy_4_6.bin | 1 + .../operators/arithmetic_fp32_5_dx1_4_6.bin | 1 + .../operators/arithmetic_fp32_5_dx2_1_6.bin | 1 + .../operators/arithmetic_fp32_5_dy_4_6.bin | 2 + .../operators/arithmetic_fp32_6_dx1_1_6.bin | 1 + .../operators/arithmetic_fp32_6_dx2_4_6.bin | 1 + .../operators/arithmetic_fp32_6_dy_4_6.bin | Bin 0 -> 96 bytes .../operators/arithmetic_fp32_7_dx1_4_5_6.bin | Bin 0 -> 480 bytes .../operators/arithmetic_fp32_7_dx2_1_1_6.bin | 1 + .../operators/arithmetic_fp32_7_dy_4_5_6.bin | Bin 0 -> 480 bytes .../operators/arithmetic_fp32_7_x1_4_5_6.bin | 2 + .../operators/arithmetic_fp32_7_x2_1_1_6.bin | 1 + .../operators/arithmetic_fp32_8_dx1_5_4_6.bin | Bin 0 -> 480 bytes .../operators/arithmetic_fp32_8_dx2_5_1_6.bin | Bin 0 -> 120 bytes .../operators/arithmetic_fp32_8_dy_5_4_6.bin | Bin 0 -> 480 bytes .../operators/arithmetic_fp32_8_x1_5_4_6.bin | Bin 0 -> 480 bytes .../operators/arithmetic_fp32_8_x2_5_1_6.bin | Bin 0 -> 120 bytes .../operators/arithmetic_fp32_9_dx1_5_4_6.bin | Bin 0 -> 480 bytes .../operators/arithmetic_fp32_9_dx2_5_1_6.bin | 2 + .../operators/arithmetic_fp32_9_dy_5_4_6.bin | Bin 0 -> 480 bytes .../operators/arithmetic_fp32_9_x1_5_4_6.bin | Bin 0 -> 480 bytes .../operators/arithmetic_fp32_9_x2_5_1_6.bin | Bin 0 -> 120 bytes .../operators/biasgradfp32_1_db_7.bin | Bin 0 -> 28 bytes .../biasgradfp32_1_dy_10_28_28_7.bin | Bin 0 -> 219520 bytes .../test_data/operators/sce_fp32_1_dy_6_4.bin | 2 + .../test_data/operators/sce_fp32_1_l_6.bin | Bin 0 -> 48 bytes .../test_data/operators/sce_fp32_1_loss_1.bin | 1 + .../test_data/operators/sce_fp32_1_y_6_4.bin | 1 + .../avgpoolgradfp32_1_dx_1_28_28_3.bin | Bin 0 -> 9408 bytes .../avgpoolgradfp32_1_dy_1_28_28_3.bin | Bin 0 -> 9408 bytes .../pooling/avgpoolgradfp32_1_x_1_28_28_3.bin | Bin 0 -> 9408 bytes .../maxpoolgradfp32_1_dx_1_28_28_3.bin | Bin 0 -> 9408 bytes .../maxpoolgradfp32_1_dy_1_28_28_3.bin | Bin 0 -> 9408 bytes .../pooling/maxpoolgradfp32_1_i_1_28_28_3.bin | Bin 0 -> 18816 bytes .../maxpoolgradfp32_2_dx_1_30_30_3.bin | Bin 0 -> 10800 bytes .../maxpoolgradfp32_2_dy_1_10_10_3.bin | Bin 0 -> 1200 bytes .../maxpoolgradfp32_2_dy_1_3_10_10.bin | Bin 0 -> 1200 bytes .../pooling/maxpoolgradfp32_2_i_1_10_10_3.bin | Bin 0 -> 2400 bytes .../pooling/maxpoolgradfp32_2_i_1_3_10_10.bin | Bin 0 -> 2400 bytes .../pooling/maxpoolgradfp32_2_x_1_30_30_3.bin | Bin 0 -> 10800 bytes .../powerfp32_dx_scale5_shift2_power3.bin | 2 + .../powerfp32_dy_scale5_shift2_power3.bin | 1 + .../powerfp32_x_scale5_shift2_power3.bin | 1 + .../arm/test_data/train/train_bias_10.bin | 1 + .../test_data/train/train_input_32_1000.bin | 0 .../test_data/train/train_weight_10_1000.bin | 0 149 files changed, 4882 insertions(+), 6 deletions(-) create mode 100644 mindspore/lite/src/common/file_utils_ext.cc create mode 100644 mindspore/lite/src/common/file_utils_ext.h create mode 100644 mindspore/lite/src/runtime/kernel/arm/fp32/activation_grad.cc create mode 100644 mindspore/lite/src/runtime/kernel/arm/fp32/activation_grad.h create mode 100644 mindspore/lite/src/runtime/kernel/arm/fp32/arithmetic_grad.cc create mode 100644 mindspore/lite/src/runtime/kernel/arm/fp32/arithmetic_grad.h create mode 100644 mindspore/lite/src/runtime/kernel/arm/fp32/bias_grad.cc create mode 100644 mindspore/lite/src/runtime/kernel/arm/fp32/bias_grad.h create mode 100644 mindspore/lite/src/runtime/kernel/arm/fp32/bngrad_input.cc create mode 100644 mindspore/lite/src/runtime/kernel/arm/fp32/bngrad_input.h create mode 100644 mindspore/lite/src/runtime/kernel/arm/fp32/convolution_grad_filter.cc create mode 100644 mindspore/lite/src/runtime/kernel/arm/fp32/convolution_grad_filter.h create mode 100644 mindspore/lite/src/runtime/kernel/arm/fp32/convolution_grad_input.cc create mode 100644 mindspore/lite/src/runtime/kernel/arm/fp32/convolution_grad_input.h create mode 100644 mindspore/lite/src/runtime/kernel/arm/fp32/opt_momentum.cc create mode 100644 mindspore/lite/src/runtime/kernel/arm/fp32/opt_momentum.h create mode 100644 mindspore/lite/src/runtime/kernel/arm/fp32/pooling_grad.cc create mode 100644 mindspore/lite/src/runtime/kernel/arm/fp32/pooling_grad.h create mode 100644 mindspore/lite/src/runtime/kernel/arm/fp32/power_grad.cc create mode 100644 mindspore/lite/src/runtime/kernel/arm/fp32/power_grad.h create mode 100644 mindspore/lite/src/runtime/kernel/arm/fp32/sparse_softmax_cross_entropy_with_logits.cc create mode 100644 mindspore/lite/src/runtime/kernel/arm/fp32/sparse_softmax_cross_entropy_with_logits.h create mode 100644 mindspore/lite/src/runtime/kernel/arm/opclib/activation_grad.h create mode 100644 mindspore/lite/src/runtime/kernel/arm/opclib/batch_norm.cc create mode 100644 mindspore/lite/src/runtime/kernel/arm/opclib/batch_norm.h create mode 100644 mindspore/lite/src/runtime/kernel/arm/opclib/fp32/arithmetic_grad.cc create mode 100644 mindspore/lite/src/runtime/kernel/arm/opclib/fp32/arithmetic_grad.h create mode 100644 mindspore/lite/src/runtime/kernel/arm/opclib/fp32/gemm.cc create mode 100644 mindspore/lite/src/runtime/kernel/arm/opclib/fp32/gemm.h create mode 100644 mindspore/lite/src/runtime/kernel/arm/opclib/fp32/pooling_grad.cc create mode 100644 mindspore/lite/src/runtime/kernel/arm/opclib/fp32/pooling_grad.h create mode 100644 mindspore/lite/src/runtime/kernel/arm/opclib/fp32/reduce_grad.cc create mode 100644 mindspore/lite/src/runtime/kernel/arm/opclib/fp32/reduce_grad.h create mode 100644 mindspore/lite/src/runtime/kernel/arm/opclib/fp32/softmax_grad.h create mode 100644 mindspore/lite/src/runtime/kernel/arm/opclib/pack_ext.cc create mode 100644 mindspore/lite/src/runtime/kernel/arm/opclib/pack_ext.h create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/fp32/activation_grad_fp32_tests.cc create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/fp32/arithmetic_grad_fp32_tests.cc create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/fp32/bias_grad_fp32_tests.cc create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/fp32/convolution_grad_fp32_tests.cc create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/fp32/pooling_grad_fp32_tests.cc create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/hsigmoid_out_50.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/hsigmoid_x_50.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/hsigmoid_yt_50.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/hswish_out_50.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/hswish_x_50.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/hswish_yt_50.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/lrelu_out_50.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/lrelu_y_50.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/lrelu_yt_50.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/relu6_out_50.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/relu6_y_50.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/relu6_yt_50.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/relu_out_50.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/relu_y_50.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/relu_yt_50.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/sigmoid_out_50.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/sigmoid_y_50.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/sigmoid_yt_50.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/tanh_out_50.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/tanh_y_50.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/tanh_yt_50.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_dw_32_3_3_3.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_dw_g3_18_3_3_3.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_dw_g3_d2_18_3_3_3.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_dx_1_28_28_3.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_dx_g3_1_28_28_3.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_dx_g3_d2_1_28_28_3.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_dy_1_28_28_32.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_dy_g3_1_28_28_18.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_dy_g3_d2_1_26_26_18.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_w_32_3_3_3.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_w_g3_18_3_3_3.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_w_g3_d2_18_3_3_3.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_x_1_28_28_3.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_x_g3_1_28_28_3.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_x_g3_d2_1_28_28_3.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_y_g3_d2_1_26_26_18.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/matmul/matmulfp32_a_10x4.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/matmul/matmulfp32_a_4x10.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/matmul/matmulfp32_b_10x5.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/matmul/matmulfp32_b_5x10.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/matmul/matmulfp32_c_4x5.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_10_dx1_5_4_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_10_dx2_5_1_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_10_dy_5_4_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_1_dx1_4_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_1_dx2_1_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_1_dy_4_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_1_x1_4_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_1_x2_1_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_2_dx1_4_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_2_dx2_1_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_2_dy_4_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_3_dx1_4_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_3_dx2_1_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_3_dy_4_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_4_dx1_4_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_4_dx2_1_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_4_dy_4_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_5_dx1_4_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_5_dx2_1_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_5_dy_4_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_6_dx1_1_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_6_dx2_4_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_6_dy_4_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_7_dx1_4_5_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_7_dx2_1_1_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_7_dy_4_5_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_7_x1_4_5_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_7_x2_1_1_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_8_dx1_5_4_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_8_dx2_5_1_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_8_dy_5_4_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_8_x1_5_4_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_8_x2_5_1_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_9_dx1_5_4_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_9_dx2_5_1_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_9_dy_5_4_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_9_x1_5_4_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_9_x2_5_1_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/biasgradfp32_1_db_7.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/biasgradfp32_1_dy_10_28_28_7.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/sce_fp32_1_dy_6_4.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/sce_fp32_1_l_6.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/sce_fp32_1_loss_1.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/sce_fp32_1_y_6_4.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/pooling/avgpoolgradfp32_1_dx_1_28_28_3.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/pooling/avgpoolgradfp32_1_dy_1_28_28_3.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/pooling/avgpoolgradfp32_1_x_1_28_28_3.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/pooling/maxpoolgradfp32_1_dx_1_28_28_3.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/pooling/maxpoolgradfp32_1_dy_1_28_28_3.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/pooling/maxpoolgradfp32_1_i_1_28_28_3.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/pooling/maxpoolgradfp32_2_dx_1_30_30_3.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/pooling/maxpoolgradfp32_2_dy_1_10_10_3.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/pooling/maxpoolgradfp32_2_dy_1_3_10_10.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/pooling/maxpoolgradfp32_2_i_1_10_10_3.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/pooling/maxpoolgradfp32_2_i_1_3_10_10.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/pooling/maxpoolgradfp32_2_x_1_30_30_3.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/power/powerfp32_dx_scale5_shift2_power3.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/power/powerfp32_dy_scale5_shift2_power3.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/power/powerfp32_x_scale5_shift2_power3.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/train/train_bias_10.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/train/train_input_32_1000.bin create mode 100644 mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/train/train_weight_10_1000.bin diff --git a/mindspore/lite/schema/model.fbs b/mindspore/lite/schema/model.fbs index b71fa966c1..7cc9e082b4 100644 --- a/mindspore/lite/schema/model.fbs +++ b/mindspore/lite/schema/model.fbs @@ -174,6 +174,19 @@ union PrimitiveType { Where, OneHot, Lstm, + Conv2DGradFilter, + Conv2DGradInput, + PoolingGrad, + BNGradInput, + OptMomentum, + BiasGrad, + SoftmaxCrossEntropy, + AddGrad, + SubGrad, + MulGrad, + DivGrad, + PowerGrad, + ActivationGrad, PriorBox } diff --git a/mindspore/lite/schema/ops.fbs b/mindspore/lite/schema/ops.fbs index 52fb99aabe..a78b43b349 100644 --- a/mindspore/lite/schema/ops.fbs +++ b/mindspore/lite/schema/ops.fbs @@ -55,7 +55,25 @@ enum ActivationType : byte { LINEAR = 15, UNKNOW = 16 } - +enum ActivationGradType : byte { + NO_ACTIVATION = 0, + RELU = 1, + SIGMOID = 2, + RELU6 = 3, + ELU = 4, + LEAKY_RELU = 5, + ABS = 6, + RELU1 = 7, + SOFTSIGN = 8, + SOFTPLUS = 9, + TANH = 10, + SELU = 11, + HSWISH = 12, + HSIGMOID = 13, + THRESHOLDRELU = 14, + LINEAR = 15, + UNKNOW = 16 +} enum ReduceType : byte { REDUCE_MAX = 0, REDUCE_MEAN = 1, @@ -125,6 +143,10 @@ table SoftMax { table Activation { type: ActivationType = 0; } +table ActivationGrad { + type: ActivationGradType = 0; +} + table Conv2D { format: Format = 0; @@ -146,7 +168,45 @@ table Conv2D { activationType: ActivationType = 0; } -table FusedBatchNorm { +table Conv2DGradFilter { + format: Format = 0; + group: int; + channelIn: int; + channelOut: int; + kernelW: int; + kernelH: int; + strideW: int; + strideH: int; + padMode: PadMode; + padUp: int; + padDown: int; + padLeft: int; + padRight: int; + dilateW: int; + dilateH: int; + hasBias: bool = false; + activationType: ActivationType = 0; +} + +table Conv2DGradInput { + format: Format = 0; + group: int; + channelIn: int; + channelOut: int; + kernelW: int; + kernelH: int; + strideW: int; + strideH: int; + padMode: PadMode; + padUp: int; + padDown: int; + padLeft: int; + padRight: int; + dilateW: int; + dilateH: int; + hasBias: bool = false; + activationType: ActivationType = 0; +}table FusedBatchNorm { epsilon: float = 0.00001; // eg. epsilon=0.001 momentum: float = 0.9; spatial: int = 1; @@ -156,6 +216,31 @@ table CaffeBatchNorm { epsilon: float; // eg. epsilon=0.001 } +table BiasGrad { + axis: [int]; +} + + +table SoftmaxCrossEntropy { + axis: [int]; +} + + +table PoolingGrad { + format: Format = 0; + poolingMode: PoolMode; + global: bool = false; + windowW: int; + windowH: int; + strideW: int; + strideH: int; + padMode: PadMode; + padUp: int; + padDown: int; + padLeft: int; + padRight: int; + roundMode: RoundMode; +} table Shape { } @@ -286,7 +371,10 @@ table DeConv2D { hasBias: bool = false; activationType: ActivationType = 0; } - +table BNGradInput { + eps : float; + channels: int; +} table Scale { format: Format = 0; } @@ -307,6 +395,17 @@ table Mul { table Div { } +table AddGrad { +} + +table SubGrad { +} + +table MulGrad { +} + +table DivGrad { +} table RealDiv { } @@ -389,7 +488,11 @@ table Power { scale: float; shift: float; } - +table PowerGrad { + power: float; + scale: float; + shift: float; +} table ArgMax { axis: int; outMaxValue: bool; @@ -712,6 +815,10 @@ table SquaredDifference { table TupleGetItem { } +table OptMomentum { +} + + table Where{ } diff --git a/mindspore/lite/src/common/file_utils_ext.cc b/mindspore/lite/src/common/file_utils_ext.cc new file mode 100644 index 0000000000..cdaa337e23 --- /dev/null +++ b/mindspore/lite/src/common/file_utils_ext.cc @@ -0,0 +1,53 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include "src/common/file_utils.h" +#include "src/common/file_utils_ext.h" + +namespace mindspore { +namespace lite { +static int CompareOutputRelativeData(float *output_data, float *correct_data, int data_size) { + float error = 0; + + // relative error + float diffSum = 0.0f; + float sum = 0.0f; + for (int i = 0; i < data_size; i++) { + sum += std::abs(correct_data[i]); + } + for (int i = 0; i < data_size; i++) { + float diff = std::abs(output_data[i] - correct_data[i]); + diffSum += diff; + } + error = diffSum / sum; + if (error > 1e-4) { + std::cout << "has accuracy error!\n" << error << "\n"; + return 1; + } + return 0; +} + +int CompareRelativeOutput(float *output_data, std::string file_path) { + size_t output_size; + auto ground_truth = reinterpret_cast(mindspore::lite::ReadFile(file_path.c_str(), &output_size)); + size_t output_num = output_size / sizeof(float); + std::cout << "output num : " << output_num << "\n"; + return CompareOutputRelativeData(output_data, ground_truth, output_num); +} +} // namespace lite +} // namespace mindspore diff --git a/mindspore/lite/src/common/file_utils_ext.h b/mindspore/lite/src/common/file_utils_ext.h new file mode 100644 index 0000000000..28eea02e41 --- /dev/null +++ b/mindspore/lite/src/common/file_utils_ext.h @@ -0,0 +1,28 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_LITE_COMMON_FILE_UTILS_EXT_H_ +#define MINDSPORE_LITE_COMMON_FILE_UTILS_EXT_H_ +#include + + +namespace mindspore { +namespace lite { +int CompareRelativeOutput(float *output_data, std::string file_path); + +} +} // namespace mindspore +#endif // MINDSPORE_LITE_COMMON_FILE_UTILS_EXT_H_ diff --git a/mindspore/lite/src/lite_kernel.h b/mindspore/lite/src/lite_kernel.h index 7cd2cfa9f2..b9086ee675 100644 --- a/mindspore/lite/src/lite_kernel.h +++ b/mindspore/lite/src/lite_kernel.h @@ -64,7 +64,7 @@ class LiteKernel { LiteKernel() = default; explicit LiteKernel(OpParameter *parameter, const std::vector &inputs, const std::vector &outputs) - : opParameter(parameter), inputs_(inputs), outputs_(outputs) { + : opParameter(parameter), inputs_(inputs), outputs_(outputs), train_mode(false) { this->in_kernel_.clear(); this->out_kernel_.clear(); } @@ -77,7 +77,10 @@ class LiteKernel { virtual int Run() { return -1; } std::string Name() { return this->name; } - + virtual void train() { train_mode = true; } + virtual bool is_train() { return train_mode == true; } + virtual void eval() { train_mode = false; } + virtual bool is_eval() { return train_mode == false; } void set_name(const std::string &name) { this->name = name; } schema::PrimitiveType type() { return (schema::PrimitiveType)this->opParameter->type_; } @@ -117,6 +120,7 @@ class LiteKernel { std::vector outputs_; std::vector in_kernel_; std::vector out_kernel_; + bool train_mode; }; class SubGraphKernel : public LiteKernel { diff --git a/mindspore/lite/src/runtime/kernel/arm/fp32/activation_grad.cc b/mindspore/lite/src/runtime/kernel/arm/fp32/activation_grad.cc new file mode 100644 index 0000000000..279832aca2 --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/fp32/activation_grad.cc @@ -0,0 +1,110 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "src/runtime/kernel/arm/fp32/activation_grad.h" +#include "schema/model_generated.h" +#include "src/kernel_registry.h" +#include "src/runtime/runtime_api.h" +#include "include/errorcode.h" + +using mindspore::lite::KernelRegistrar; +using mindspore::kernel::KERNEL_ARCH::kCPU; +using mindspore::lite::RET_ERROR; +using mindspore::lite::RET_OK; +using mindspore::schema::ActivationGradType_HSWISH; +using mindspore::schema::ActivationGradType_LEAKY_RELU; +using mindspore::schema::ActivationGradType_RELU; +using mindspore::schema::ActivationGradType_RELU6; +using mindspore::schema::PrimitiveType_ActivationGrad; + +namespace mindspore::kernel { +int ActivationGradCPUKernel::Init() { + outputs_[0]->set_shape(inputs_[0]->shape()); + return RET_OK; +} + +int ActivationGradCPUKernel::ReSize() { return RET_OK; } + +int ActivationGradCPUKernel::DoActivation(int task_id) { + auto yt_addr = reinterpret_cast(inputs_.at(0)->Data()); + auto input_addr = reinterpret_cast(inputs_.at(1)->Data()); + auto output_addr = reinterpret_cast(outputs_.at(0)->Data()); + auto length = inputs_.at(0)->ElementsNum(); + + auto error_code = RET_OK; + + if (type_ == schema::ActivationGradType_RELU) { + error_code = ReluGrad(yt_addr, input_addr, length, output_addr); + } else if (type_ == schema::ActivationGradType_RELU6) { + error_code = Relu6Grad(yt_addr, input_addr, length, output_addr); + } else if (type_ == schema::ActivationGradType_LEAKY_RELU) { + error_code = LReluGrad(yt_addr, input_addr, length, output_addr, alpha_); + } else if (type_ == schema::ActivationGradType_SIGMOID) { + error_code = SigmoidGrad(yt_addr, input_addr, length, output_addr); + } else if (type_ == schema::ActivationGradType_TANH) { + error_code = TanhGrad(yt_addr, input_addr, length, output_addr); + } else if (type_ == schema::ActivationGradType_HSWISH) { + error_code = HSwishGrad(yt_addr, input_addr, length, output_addr); + } else if (type_ == schema::ActivationGradType_HSIGMOID) { + error_code = HSigmoidGrad(yt_addr, input_addr, length, output_addr); + } else { + MS_LOG(ERROR) << "Activation type error"; + return RET_ERROR; + } + if (error_code != RET_OK) { + return RET_ERROR; + } + return RET_OK; +} + +int ActivationGradRun(int task_id, LiteParallelGroupEnv *penv, void *cdata) { + auto activationGrad_kernel = reinterpret_cast(cdata); + auto error_code = activationGrad_kernel->DoActivation(task_id); + if (error_code != RET_OK) { + MS_LOG(ERROR) << "ActivationGradRun error task_id[" << task_id << "] error_code[" << error_code << "]"; + return RET_ERROR; + } + return RET_OK; +} + +int ActivationGradCPUKernel::Run() { + int error_code = LiteBackendParallelLaunch(ActivationGradRun, this, thread_count_); + if (error_code != RET_OK) { + MS_LOG(ERROR) << "Activation function error error_code[" << error_code << "]"; + return RET_ERROR; + } + return RET_OK; +} + +kernel::LiteKernel *CpuActivationGradFp32KernelCreator(const std::vector &inputs, + const std::vector &outputs, + OpParameter *opParameter, const lite::Context *ctx, + const kernel::KernelKey &desc) { + MS_ASSERT(opParameter != nullptr); + MS_ASSERT(desc.type == schema::PrimitiveType_ActivationGrad); + auto *kernel = new (std::nothrow) ActivationGradCPUKernel(opParameter, inputs, outputs); + MS_ASSERT(kernel != nullptr); + auto ret = kernel->Init(); + if (ret != RET_OK) { + MS_LOG(ERROR) << "InferShape kernel failed, name: " << opParameter->name_ + << ", type: " + << schema::EnumNamePrimitiveType(static_cast(opParameter->type_)); + } + return kernel; +} + +REG_KERNEL(kCPU, kNumberTypeFloat32, PrimitiveType_ActivationGrad, CpuActivationGradFp32KernelCreator) +} // namespace mindspore::kernel diff --git a/mindspore/lite/src/runtime/kernel/arm/fp32/activation_grad.h b/mindspore/lite/src/runtime/kernel/arm/fp32/activation_grad.h new file mode 100644 index 0000000000..4fc4265d49 --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/fp32/activation_grad.h @@ -0,0 +1,50 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_FP32_ACTIVATION_GRAD_H_ +#define MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_FP32_ACTIVATION_GRAD_H_ + +#include +#include "src/lite_kernel.h" +#include "ir/anf.h" + +#include "src/runtime/kernel/arm/opclib/activation_grad.h" + +namespace mindspore::kernel { +class ActivationGradCPUKernel : public LiteKernel { + public: + explicit ActivationGradCPUKernel(OpParameter *param, const std::vector &inputs, + const std::vector &outputs) + : LiteKernel(param, inputs, outputs) { + ActivationGradParameter *param_act_grad = reinterpret_cast(param); + type_ = param_act_grad->type_; + alpha_ = param_act_grad->alpha_; + } + ~ActivationGradCPUKernel() override = default; + + int Init() override; + int ReSize() override; + int Run() override; + int DoActivation(int task_id); + + private: + int thread_count_; + int type_; + float alpha_; +}; +} // namespace mindspore::kernel + +#endif // MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_FP32_ACTIVATION_GRAD_H_ diff --git a/mindspore/lite/src/runtime/kernel/arm/fp32/arithmetic_grad.cc b/mindspore/lite/src/runtime/kernel/arm/fp32/arithmetic_grad.cc new file mode 100644 index 0000000000..a9d62c8ee9 --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/fp32/arithmetic_grad.cc @@ -0,0 +1,285 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "schema/model_generated.h" +#include "src/kernel_registry.h" +#include "src/runtime/kernel/arm/opclib/fp32/reduce_grad.h" +#include "src/runtime/kernel/arm/fp32/arithmetic_grad.h" +#include "src/runtime/kernel/arm/opclib/fp32/arithmetic_grad.h" +#include "include/errorcode.h" + +using mindspore::kernel::KERNEL_ARCH::kCPU; +using mindspore::lite::KernelRegistrar; +using mindspore::lite::RET_ERROR; +using mindspore::lite::RET_OK; + +namespace mindspore::kernel { +namespace { +constexpr int kArithGradOpInputNum = 3; +constexpr int kArithGradOpOutputNum = 2; +} // namespace + +int ArithmeticGradCPUKernel::Init() { + auto ret = InferShape(); + return ret; +} + +int ArithmeticGradCPUKernel::InferShape() { + if (inputs_.size() != kArithGradOpInputNum) { + MS_LOG(ERROR) << "The number of input must be " << kArithGradOpInputNum; + return RET_ERROR; + } + if (outputs_.size() != kArithGradOpOutputNum) { + MS_LOG(ERROR) << "The number of output must be " << kArithGradOpOutputNum; + return RET_ERROR; + } + auto dy = inputs_[0]; + auto x1 = inputs_[1]; + auto x2 = inputs_[2]; + auto dx1 = outputs_[0]; + auto dx2 = outputs_[1]; + + MS_ASSERT(dy != nullptr); + MS_ASSERT(x1 != nullptr); + MS_ASSERT(x2 != nullptr); + MS_ASSERT(dx1 != nullptr); + MS_ASSERT(dx2 != nullptr); + + auto inShape0 = x1->shape(); + auto inShape1 = x2->shape(); + auto outShape = dy->shape(); + + if ((type() == PrimitiveType_AddGrad) || (type() == PrimitiveType_SubGrad)) { + arithmeticParameter_->ndim_ = outShape.size(); + auto fillDimNum0 = outShape.size() - inShape0.size(); + auto fillDimNum1 = outShape.size() - inShape1.size(); + int j0 = 0; + int j1 = 0; + for (unsigned int i = 0; i < outShape.size(); i++) { + arithmeticParameter_->in_shape0_[i] = (i < fillDimNum0) ? 1 : inShape0[j0++]; + arithmeticParameter_->in_shape1_[i] = (i < fillDimNum1) ? 1 : inShape1[j1++]; + arithmeticParameter_->out_shape_[i] = outShape[i]; + } + } else { + // if (inShape0.size() < inShape1.size()) + if (dx1->ElementsNum() < dx2->ElementsNum()) { + arithmeticParameter_->ndim_ = inShape1.size(); + if (type() == PrimitiveType_MulGrad) + arithmetic_grad_ = &ArithmeticGradCPUKernel::ArithmeticGradMul2L; + else if (type() == PrimitiveType_DivGrad) + arithmetic_grad_ = &ArithmeticGradCPUKernel::ArithmeticGradDiv2L; + + auto fillDimNum = inShape1.size() - inShape0.size(); // This will not work for batch! + int j = 0; + for (unsigned int i = 0; i < inShape1.size(); i++) { + if (i < fillDimNum) { + arithmeticParameter_->in_shape1_[i] = 1; + } else { + arithmeticParameter_->in_shape1_[i] = inShape0[j++]; + } + arithmeticParameter_->in_shape0_[i] = inShape1[i]; + arithmeticParameter_->out_shape_[i] = outShape[i]; + } + } else if (dx2->ElementsNum() < dx1->ElementsNum()) { // if (inShape0.size() > inShape1.size()) + arithmeticParameter_->ndim_ = inShape0.size(); + if (type() == PrimitiveType_MulGrad) + arithmetic_grad_ = &ArithmeticGradCPUKernel::ArithmeticGradMul1L; + else if (type() == PrimitiveType_DivGrad) + arithmetic_grad_ = &ArithmeticGradCPUKernel::ArithmeticGradDiv1L; + arithmeticParameter_->broadcasting_ = true; + arithmeticParameter_->ndim_ = inShape0.size(); + int j = 0; + auto fillDimNum = inShape0.size() - inShape1.size(); + for (unsigned int i = 0; i < inShape0.size(); i++) { + if (i < fillDimNum) { + arithmeticParameter_->in_shape1_[i] = 1; + } else { + arithmeticParameter_->in_shape1_[i] = inShape1[j++]; + } + arithmeticParameter_->in_shape0_[i] = inShape0[i]; + arithmeticParameter_->out_shape_[i] = outShape[i]; + } + } else { + arithmeticParameter_->broadcasting_ = false; + for (unsigned int i = 0; i < inShape0.size(); i++) { + arithmeticParameter_->in_shape1_[i] = inShape1[i]; + arithmeticParameter_->in_shape0_[i] = inShape0[i]; + arithmeticParameter_->out_shape_[i] = outShape[i]; + } + } + tile_data0 = new (std::nothrow) float[inputs_.at(0)->ElementsNum()]; + MS_ASSERT(tile_data0 != nullptr); + tile_data1 = new (std::nothrow) float[inputs_.at(0)->ElementsNum()]; + MS_ASSERT(tile_data1 != nullptr); + if (type() == PrimitiveType_DivGrad) { + tile_data2 = new (std::nothrow) float[inputs_.at(0)->ElementsNum()]; + MS_ASSERT(tile_data2 != nullptr); + } + } + + dx1->set_shape(x1->shape()); + dx2->set_shape(x2->shape()); + // outTensor->set_shape(out_shape); + dx1->set_data_type(dy->data_type()); + dx2->set_data_type(dy->data_type()); + return RET_OK; +} + +void ArithmeticGradCPUKernel::ArithmeticGradAdd(float *dy, int dy_size, float *dx1, int dx1_size, float *dx2, + int dx2_size) { + if (dx1_size == dy_size) + memcpy(dx1, dy, dy_size * sizeof(float)); + else + ReduceSumByAxes(dy, arithmeticParameter_->out_shape_, dx1, arithmeticParameter_->in_shape0_, + arithmeticParameter_->ndim_); + if (dx2_size == dy_size) + memcpy(dx2, dy, dy_size * sizeof(float)); + else + ReduceSumByAxes(dy, arithmeticParameter_->out_shape_, dx2, arithmeticParameter_->in_shape1_, + arithmeticParameter_->ndim_); +} + +void ArithmeticGradCPUKernel::ArithmeticGradSub(float *dy, int dy_size, float *dx1, int dx1_size, float *dx2, + int dx2_size) { + if (dx1_size == dy_size) + memcpy(dx1, dy, dy_size * sizeof(float)); + else + ReduceSumByAxes(dy, arithmeticParameter_->out_shape_, dx1, arithmeticParameter_->in_shape0_, + arithmeticParameter_->ndim_); + if (dx2_size == dy_size) { + for (int i = 0; i < dx2_size; i++) { + dx2[i] = -dy[i]; + } + } else { + ReduceSumByAxes(dy, arithmeticParameter_->out_shape_, dx2, arithmeticParameter_->in_shape1_, + arithmeticParameter_->ndim_); + for (int i = 0; i < dx2_size; i++) { + dx2[i] = -dx2[i]; + } + } +} + +void ArithmeticGradCPUKernel::ArithmeticGradMul(float *dy, int dy_size, float *dx1, int dx1_size, float *dx2, + int dx2_size) { + auto x1_data = reinterpret_cast(inputs_[1]->Data()); + auto x2_data = reinterpret_cast(inputs_[2]->Data()); + ElementMul(dy, x1_data, dx2, dy_size); + ElementMul(dy, x2_data, dx1, dy_size); +} + +void ArithmeticGradCPUKernel::ArithmeticGradMul1L(float *dy, int dy_size, float *dx1, int dx1_size, float *dx2, + int dx2_size) { + auto x1_data = reinterpret_cast(inputs_[1]->Data()); + auto x2_data = reinterpret_cast(inputs_[2]->Data()); + ElementMul(dy, x1_data, tile_data0, dy_size); + ReduceSumByAxes(tile_data0, arithmeticParameter_->in_shape0_, dx2, arithmeticParameter_->in_shape1_, + arithmeticParameter_->ndim_); + + BroadcastMul(dy, x2_data, tile_data0, tile_data1, dx1, dy_size, arithmeticParameter_); // broadcast directly to dx1 +} + +void ArithmeticGradCPUKernel::ArithmeticGradMul2L(float *dy, int dy_size, float *dx1, int dx1_size, float *dx2, + int dx2_size) { + auto x1_data = reinterpret_cast(inputs_[1]->Data()); + auto x2_data = reinterpret_cast(inputs_[2]->Data()); + ElementMul(dy, x2_data, tile_data0, dy_size); + ReduceSumByAxes(tile_data0, arithmeticParameter_->in_shape0_, dx1, arithmeticParameter_->in_shape1_, + arithmeticParameter_->ndim_); + + BroadcastMul(dy, x1_data, tile_data0, tile_data1, dx2, dy_size, arithmeticParameter_); // broadcast directly to dx2 +} + +void ArithmeticGradCPUKernel::ArithmeticGradDiv(float *dy, int dy_size, float *dx1, int dx1_size, float *dx2, + int dx2_size) { + auto x1 = reinterpret_cast(inputs_[1]->Data()); + auto x2 = reinterpret_cast(inputs_[2]->Data()); + ElementDiv(dy, x2, dx1, dy_size); + ElementMulAndDivNegSquare(dy, x1, x2, dx2, dy_size); +} + +void ArithmeticGradCPUKernel::ArithmeticGradDiv1L(float *dy, int dy_size, float *dx1, int dx1_size, float *dx2, + int dx2_size) { + auto x1_data = reinterpret_cast(inputs_[1]->Data()); + auto x2_data = reinterpret_cast(inputs_[2]->Data()); + + ElementMul(x2_data, x2_data, dx2, dx2_size); + ElementMul(x1_data, dy, dx1, dy_size); // use dx1 buffer + BroadcastDiv(dx1, dx2, tile_data0, tile_data1, tile_data2, dy_size, + arithmeticParameter_); // broadcast directly to dx1 + ReduceSumByAxes(tile_data2, arithmeticParameter_->in_shape0_, dx2, arithmeticParameter_->in_shape1_, + arithmeticParameter_->ndim_); + for (int i = 0; i < dx2_size; i++) dx2[i] = -dx2[i]; + // ReduceNegSumPrefix(tile_data2, dy_size, dx2, dx2_size); //then reduce into dx2 + + // broadcasting x2 + BroadcastDiv(dy, x2_data, tile_data0, tile_data1, dx1, dy_size, arithmeticParameter_); // broadcast directly to dx1 +} + +void ArithmeticGradCPUKernel::ArithmeticGradDiv2L(float *dy, int dy_size, float *dx1, int dx1_size, float *dx2, + int dx2_size) { + auto x1_data = reinterpret_cast(inputs_[1]->Data()); + auto x2_data = reinterpret_cast(inputs_[2]->Data()); + + // dx1 = dy/x2 + ElementDiv(dy, x2_data, tile_data0, dy_size); // first multiply into temp + ReduceSumByAxes(tile_data0, arithmeticParameter_->in_shape0_, dx1, arithmeticParameter_->in_shape1_, + arithmeticParameter_->ndim_); + + // dx2 = -dy*x1/(x2*x2) + BroadcastMul(dy, x1_data, tile_data0, tile_data1, tile_data2, dy_size, arithmeticParameter_); // broadcast numerator + ElementDivNegSquare(tile_data2, x2_data, dx2, dy_size); +} + +int ArithmeticGradCPUKernel::ReSize() { return RET_OK; } + +int ArithmeticGradCPUKernel::Run() { + auto dy = reinterpret_cast(inputs_[0]->Data()); + // auto input1_data1 = reinterpret_cast(inputs_[1]->Data()); + auto dx1 = reinterpret_cast(outputs_[0]->Data()); + auto dx2 = reinterpret_cast(outputs_[1]->Data()); + + size_t dy_size = inputs_.at(0)->ElementsNum(); + size_t dx1_size = outputs_.at(0)->ElementsNum(); + size_t dx2_size = outputs_[1]->ElementsNum(); + (this->*arithmetic_grad_)(dy, dy_size, dx1, dx1_size, dx2, dx2_size); + return RET_OK; +} + +kernel::LiteKernel *CpuArithmeticGradFp32KernelCreator(const std::vector &inputs, + const std::vector &outputs, + OpParameter *opParameter, const lite::Context *ctx, + const kernel::KernelKey &desc) { + MS_EXCEPTION_IF_NULL(opParameter); + if (opParameter == nullptr) { + return nullptr; + } + auto *kernel = new (std::nothrow) ArithmeticGradCPUKernel(opParameter, inputs, outputs); + MS_ASSERT(kernel != nullptr); + auto ret = kernel->Init(); + if (ret != RET_OK) { + MS_LOG(ERROR) << "Init kernel failed, name: " << opParameter->name_ << ", type: " + << schema::EnumNamePrimitiveType(static_cast(opParameter->type_)); + delete kernel; + return nullptr; + } + return kernel; +} + +REG_KERNEL(kCPU, kNumberTypeFloat32, PrimitiveType_MulGrad, CpuArithmeticGradFp32KernelCreator) +REG_KERNEL(kCPU, kNumberTypeFloat32, PrimitiveType_AddGrad, CpuArithmeticGradFp32KernelCreator) +REG_KERNEL(kCPU, kNumberTypeFloat32, PrimitiveType_SubGrad, CpuArithmeticGradFp32KernelCreator) +REG_KERNEL(kCPU, kNumberTypeFloat32, PrimitiveType_DivGrad, CpuArithmeticGradFp32KernelCreator) +} // namespace mindspore::kernel diff --git a/mindspore/lite/src/runtime/kernel/arm/fp32/arithmetic_grad.h b/mindspore/lite/src/runtime/kernel/arm/fp32/arithmetic_grad.h new file mode 100644 index 0000000000..a11ef24a44 --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/fp32/arithmetic_grad.h @@ -0,0 +1,90 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_FP32_ARITHMETIC_GRAD_H_ +#define MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_FP32_ARITHMETIC_GRAD_H_ + +#include +#include "src/lite_kernel.h" +#include "src/runtime/kernel/arm/opclib/fp32/arithmetic.h" +#include "schema/model_generated.h" +#include "ir/anf.h" + +using mindspore::schema::PrimitiveType_AddGrad; +using mindspore::schema::PrimitiveType_DivGrad; +using mindspore::schema::PrimitiveType_MulGrad; +using mindspore::schema::PrimitiveType_SubGrad; + +namespace mindspore::kernel { + +class ArithmeticGradCPUKernel; + +class ArithmeticGradCPUKernel : public LiteKernel { + typedef void (ArithmeticGradCPUKernel::*ArithmeticGradOperation)(float *, int, float *, int, float *, int); + + public: + explicit ArithmeticGradCPUKernel(OpParameter *parameter, const std::vector &inputs, + const std::vector &outputs) + : LiteKernel(parameter, inputs, outputs), tile_data0(NULL), tile_data1(NULL), tile_data2(NULL) { + switch (type()) { + case PrimitiveType_MulGrad: + arithmetic_grad_ = &ArithmeticGradCPUKernel::ArithmeticGradMul; // this will be adjusted in InferShape + break; + case PrimitiveType_AddGrad: + arithmetic_grad_ = &ArithmeticGradCPUKernel::ArithmeticGradAdd; + break; + case PrimitiveType_SubGrad: + arithmetic_grad_ = &ArithmeticGradCPUKernel::ArithmeticGradSub; + break; + case PrimitiveType_DivGrad: + arithmetic_grad_ = &ArithmeticGradCPUKernel::ArithmeticGradDiv; // this will be adjusted in InferShape + break; + default: + MS_LOG(ERROR) << "Error Operator type " << parameter->type_; + break; + } + arithmeticParameter_ = reinterpret_cast(parameter); + } + ~ArithmeticGradCPUKernel() override { + if (tile_data0) delete[] tile_data0; + if (tile_data1) delete[] tile_data1; + if (tile_data2) delete[] tile_data2; + } + void InitKernel(const CNodePtr &kernel_node); + + int Init() override; + int InferShape(); + int ReSize() override; + int Run() override; + + private: + void ArithmeticGradAdd(float *dy, int dy_size, float *dx1, int dx1_size, float *dx2, int dx2_size); + void ArithmeticGradSub(float *dy, int dy_size, float *dx1, int dx1_size, float *dx2, int dx2_size); + void ArithmeticGradMul(float *dy, int dy_size, float *dx1, int dx1_size, float *dx2, int dx2_size); + void ArithmeticGradMul1L(float *dy, int dy_size, float *dx1, int dx1_size, float *dx2, int dx2_size); + void ArithmeticGradMul2L(float *dy, int dy_size, float *dx1, int dx1_size, float *dx2, int dx2_size); + void ArithmeticGradDiv(float *dy, int dy_size, float *dx1, int dx1_size, float *dx2, int dx2_size); + void ArithmeticGradDiv1L(float *dy, int dy_size, float *dx1, int dx1_size, float *dx2, int dx2_size); + void ArithmeticGradDiv2L(float *dy, int dy_size, float *dx1, int dx1_size, float *dx2, int dx2_size); + ArithmeticParameter *arithmeticParameter_; + ArithmeticGradOperation arithmetic_grad_; + float *tile_data0; + float *tile_data1; + float *tile_data2; +}; +} // namespace mindspore::kernel + +#endif // MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_FP32_ARITHMETIC_GRAD_H_ diff --git a/mindspore/lite/src/runtime/kernel/arm/fp32/bias_grad.cc b/mindspore/lite/src/runtime/kernel/arm/fp32/bias_grad.cc new file mode 100644 index 0000000000..e57fe298ab --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/fp32/bias_grad.cc @@ -0,0 +1,115 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "src/runtime/kernel/arm/fp32/bias_grad.h" +#include "schema/model_generated.h" +#include "src/kernel_registry.h" +#include "include/errorcode.h" + + +using mindspore::kernel::KERNEL_ARCH::kCPU; +using mindspore::lite::KernelRegistrar; +using mindspore::schema::PrimitiveType_BiasGrad; +using mindspore::lite::RET_ERROR; +using mindspore::lite::RET_OK; + +namespace mindspore::kernel { +int BiasGradCPUKernel::InferShape() { + if (1 != this->inputs_.size()) { + MS_LOG(ERROR) << "BiasGrad should have one input"; + return RET_ERROR; + } + if (1 != this->outputs_.size()) { + MS_LOG(ERROR) << "BiasGrad should have one output"; + return RET_ERROR; + } + auto *in0 = inputs_.front(); + auto *out = outputs_.front(); + MS_ASSERT(in0 != nullptr); + MS_ASSERT(out != nullptr); + auto inshape = in0->shape(); + int ndim = inshape.size(); + for (int i = 0; i < ndim - 1; i++) { + inshape[i] = 1; + } + out->set_shape(inshape); + out->set_data_type(in0->data_type()); + return RET_OK; +} + +int BiasGradCPUKernel::Init() { + MS_ASSERT(InferShape() == RET_OK); + + auto dims = inputs_[0]->shape(); + bias_param->ndim_ = dims.size(); + for (unsigned int i = 0; i < bias_param->ndim_; i++) { + bias_param->in_shape0_[i] = dims[i]; + bias_param->out_shape_[i] = 1; // 1 dimension for N,H,W, + } + bias_param->out_shape_[bias_param->ndim_ - 1] = dims[bias_param->ndim_ - 1]; + for (int i = bias_param->ndim_; i < 4; i++) { + bias_param->in_shape0_[i] = 0; + bias_param->out_shape_[i] = 0; + } + return RET_OK; +} + + +int BiasGradCPUKernel::ReSize() { return 0; } + +int BiasGradCPUKernel::Run() { + auto in = reinterpret_cast(inputs_.at(0)->Data()); + auto out = reinterpret_cast(outputs_.at(0)->Data()); + // size_t data_size = inputs_.at(0)->ElementsNum(); + + size_t nhw_size = 1; + size_t channels = bias_param->in_shape0_[bias_param->ndim_ - 1]; // C in NHWC + for (unsigned int i = 0; i < bias_param->ndim_ - 1; i++) nhw_size *= bias_param->in_shape0_[i]; + + size_t total_size = channels * nhw_size; + for (size_t c = 0; c < channels; ++c) { + out[c] = 0; + for (size_t offset = 0; offset < total_size; offset += channels) { + out[c] += in[offset + c]; + } + } + + return RET_OK; +} + + +kernel::LiteKernel *CpuBiasGradFp32KernelCreator(const std::vector &inputs, + const std::vector &outputs, + OpParameter *opParameter, const lite::Context *ctx, + const kernel::KernelKey &desc) { + MS_ASSERT(opParameter != nullptr); + MS_ASSERT(desc.type == schema::PrimitiveType_BiasGrad); + auto *kernel = new (std::nothrow) BiasGradCPUKernel(reinterpret_cast(opParameter), inputs, outputs); + MS_ASSERT(kernel != nullptr); + + auto ret = kernel->Init(); + if (RET_OK != ret) { + MS_LOG(ERROR) << "Init kernel failed, name: " << opParameter->name_ << ", type: " + << schema::EnumNamePrimitiveType(static_cast(opParameter->type_)); + delete kernel; + return nullptr; + } + return kernel; +} + +REG_KERNEL(kCPU, kNumberTypeFloat32, PrimitiveType_BiasGrad, CpuBiasGradFp32KernelCreator) +} // namespace mindspore::kernel diff --git a/mindspore/lite/src/runtime/kernel/arm/fp32/bias_grad.h b/mindspore/lite/src/runtime/kernel/arm/fp32/bias_grad.h new file mode 100644 index 0000000000..0e7ac18692 --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/fp32/bias_grad.h @@ -0,0 +1,46 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_FP32_BIAS_GRAD_H_ +#define MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_FP32_BIAS_GRAD_H_ + +#include +#include "src/lite_kernel.h" +#include "ir/anf.h" + +#include "src/runtime/kernel/arm/opclib/fp32/arithmetic.h" + +namespace mindspore::kernel { +class BiasGradCPUKernel : public LiteKernel { + public: + explicit BiasGradCPUKernel(OpParameter *parameter, const std::vector &inputs, + const std::vector &outputs) + : LiteKernel(parameter, inputs, outputs) { + bias_param = reinterpret_cast(parameter); + } + ~BiasGradCPUKernel() override = default; + + int Init() override; + int InferShape(); + int ReSize() override; + int Run() override; + + private: + ArithmeticParameter *bias_param; +}; +} // namespace mindspore::kernel + +#endif // MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_FP32_BIAS_GRAD_H_ diff --git a/mindspore/lite/src/runtime/kernel/arm/fp32/bngrad_input.cc b/mindspore/lite/src/runtime/kernel/arm/fp32/bngrad_input.cc new file mode 100644 index 0000000000..a9492b2644 --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/fp32/bngrad_input.cc @@ -0,0 +1,115 @@ +/** + * Copyright 2019 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "schema/model_generated.h" +#include "src/kernel_factory.h" +#include "src/runtime/kernel/arm/fp32/bngrad_input.h" +#include "src/runtime//kernel/arm/opclib/batch_norm.h" +#include "include/errorcode.h" + +using mindspore::kernel::KERNEL_ARCH::kCPU; +using mindspore::lite::KernelRegistrar; +using mindspore::lite::RET_ERROR; +using mindspore::lite::RET_OK; +// using mindspore::lite::REG_OP; +using mindspore::schema::PrimitiveType_BNGradInput; + +namespace mindspore::kernel { +int BNGradInputCPUKernel::Init() { + auto bn_param = reinterpret_cast(opParameter); + workspace_size = 5 * bn_param->channels; + workspace = new float[workspace_size]; + + if (2 != this->inputs_.size()) { + MS_LOG(ERROR) << "Conv2d Grad should has 2 inputs"; + return RET_ERROR; + } + if (1 != this->outputs_.size()) { + MS_LOG(ERROR) << "Conv2d Grad should has one output"; + return RET_ERROR; + } + auto *input_tensor = inputs_.at(0); + // auto *weight_tensor = inputs_.at(1); + auto *out_tensor = outputs_.at(0); + auto in_shape = input_tensor->shape(); + out_tensor->set_shape(in_shape); + out_tensor->set_data_type(input_tensor->data_type()); + return RET_OK; +} + +int BNGradInputCPUKernel::ReSize() { return RET_OK; } + +/* +according to https://wiseodd.github.io/techblog/2016/07/04/batchnorm +*/ + +int BNGradInputCPUKernel::Run() { + // std::cout << "run succ" << std::endl; + auto *input_x = inputs_.at(0); + auto *input_yt = inputs_.at(1); + auto *input_scale = inputs_.at(2); + auto *output_grad = outputs_.at(0); + // Tensor *bias = input[5]; + auto bn_param = reinterpret_cast(opParameter); + int batch = bn_param->batch; + int channels = bn_param->channels; + int spatial = bn_param->spatial; + float eps = bn_param->eps; + std::fill(workspace, workspace + workspace_size, 0.f); + + float *mean = workspace; + float *variance = mean + channels; + float *mean_delta = variance + channels; + float *variance_delta = mean_delta + channels; + float *mean_add_delta = variance_delta + channels; + + float *x = reinterpret_cast(input_x->Data()); + float *yt = reinterpret_cast(input_yt->Data()); + float *scale = reinterpret_cast(input_scale->Data()); + float *out = reinterpret_cast(output_grad->Data()); + + std::copy(yt, yt + batch * channels * spatial, out); + meanVar(x, batch, spatial, channels, mean, variance); + scaleBias(scale, batch, channels, spatial, out); + meanDelta(out, spatial, channels, eps, variance, mean_delta); + varianceDelta(x, out, mean, variance, batch, channels, spatial, eps, variance_delta); + meanAdd(x, mean, variance_delta, batch, channels, spatial, mean_add_delta, mean_delta); + NormalizeDelta(x, mean, variance, mean_delta, variance_delta, batch, channels, eps, spatial, out); + return RET_OK; +} + +kernel::LiteKernel *CpuBNGradInputFp32KernelCreator(const std::vector &inputs, + const std::vector &outputs, + OpParameter *opParameter, const lite::Context *ctx, + const kernel::KernelKey &desc) { + MS_ASSERT(opParameter != nullptr); + MS_ASSERT(desc.type == schema::PrimitiveType_BNGradInput); + // parameter->name = opDef.name()->str().data(); + // parameter->type = opDef.attr_type(); + auto *kernel = new (std::nothrow) BNGradInputCPUKernel(opParameter, inputs, outputs); + MS_ASSERT(kernel != nullptr); + auto ret = kernel->Init(); + if (RET_OK != ret) { + MS_LOG(ERROR) << "Init kernel failed, name: " << opParameter->name_ << ", type: " + << schema::EnumNamePrimitiveType(static_cast(opParameter->type_)); + } + return kernel; +} + +REG_KERNEL(kCPU, kNumberTypeFloat32, PrimitiveType_BNGradInput, CpuBNGradInputFp32KernelCreator) +} // namespace mindspore::kernel diff --git a/mindspore/lite/src/runtime/kernel/arm/fp32/bngrad_input.h b/mindspore/lite/src/runtime/kernel/arm/fp32/bngrad_input.h new file mode 100644 index 0000000000..e4e6d6e746 --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/fp32/bngrad_input.h @@ -0,0 +1,41 @@ +/** + * Copyright 2019 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_FP32_BNGRAD_INPUT_H_ +#define MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_FP32_BNGRAD_INPUT_H_ + +#include +#include "src/lite_kernel.h" +#include "ir/anf.h" + +namespace mindspore::kernel { +class BNGradInputCPUKernel : public LiteKernel { + public: + explicit BNGradInputCPUKernel(OpParameter *parameter, const std::vector &inputs, + const std::vector &outputs) + : LiteKernel(parameter, inputs, outputs) {} + ~BNGradInputCPUKernel() override { delete workspace; } + + int Init() override; + int ReSize() override; + int Run() override; + + private: + float *workspace; + int workspace_size; +}; +} // namespace mindspore::kernel +#endif // MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_FP32_BNGRAD_INPUT_H_ diff --git a/mindspore/lite/src/runtime/kernel/arm/fp32/convolution_grad_filter.cc b/mindspore/lite/src/runtime/kernel/arm/fp32/convolution_grad_filter.cc new file mode 100644 index 0000000000..89cba44768 --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/fp32/convolution_grad_filter.cc @@ -0,0 +1,156 @@ +/** + * Copyright 2019 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "src/runtime/kernel/arm/fp32/convolution_grad_filter.h" +#include "src/kernel_registry.h" +#include "src/runtime/kernel/arm/opclib/pack.h" +#include "src/runtime/kernel/arm/opclib/pack_ext.h" +#include "src/runtime/kernel/arm/opclib/fp32/gemm.h" +#include "include/errorcode.h" + +using mindspore::kernel::KERNEL_ARCH::kCPU; +using mindspore::lite::KernelRegistrar; +using mindspore::lite::RET_ERROR; +using mindspore::lite::RET_OK; +using mindspore::schema::PrimitiveType_Conv2DGradFilter; + +namespace mindspore::kernel { +int ConvolutionGradFilterCPUKernel::Init() { + // dy is in input 0 + // x is in input 1 + // dw is output 0 + + if (2 != this->inputs_.size()) { + MS_LOG(ERROR) << "Conv2d Grad should has 2 inputs"; + return RET_ERROR; + } + if (1 != this->outputs_.size()) { + MS_LOG(ERROR) << "Conv2d Grad should has one output"; + return RET_ERROR; + } + + auto *input_tensor = inputs_.at(1); + MS_ASSERT(input_tensor != nullptr); + auto *dy = inputs_.at(0); + MS_ASSERT(dy != nullptr); + auto *weight_tensor = outputs_.at(0); + MS_ASSERT(weight_tensor != nullptr); + + auto conv_param = reinterpret_cast(opParameter); + conv_param->output_batch_ = this->inputs_.at(0)->shape().at(kNHWC_N); + conv_param->input_batch_ = this->inputs_.at(1)->shape().at(kNHWC_N); + conv_param->input_h_ = this->inputs_.at(1)->shape().at(kNHWC_H); + conv_param->input_w_ = this->inputs_.at(1)->shape().at(kNHWC_W); + // assume OutCh|kh|kw|In + conv_param->input_channel_ = this->inputs_.at(1)->shape().at(kNHWC_C); + conv_param->output_channel_ = this->outputs_.at(0)->shape().at(kNHWC_N); + + int ws_size = conv_param->output_h_ * conv_param->output_w_ * conv_param->kernel_h_ * conv_param->kernel_w_ * + conv_param->input_channel_ / conv_param->group_; + + workspace = new float[ws_size]; + + int output_w = 0; + int output_h = 0; + output_h = dy->shape()[kNHWC_H]; + output_w = dy->shape()[kNHWC_W]; + + std::vector out_shape(4); + out_shape.at(0) = conv_param->output_channel_; + out_shape.at(1) = conv_param->kernel_h_; + out_shape.at(2) = conv_param->kernel_w_; + out_shape.at(3) = conv_param->input_channel_ / conv_param->group_; + + // weight is output + weight_tensor->set_shape(out_shape); + weight_tensor->set_data_type(input_tensor->data_type()); + + conv_param->output_h_ = output_h; + conv_param->output_w_ = output_w; + + return RET_OK; +} + +int ConvolutionGradFilterCPUKernel::ReSize() { return 0; } + +int ConvolutionGradFilterCPUKernel::Run() { + auto conv_param = reinterpret_cast(opParameter); + auto *input_dy = inputs_.at(0); + auto *input_x = inputs_.at(1); + auto *out_dw = outputs_.at(0); + + auto x_addr = reinterpret_cast(input_x->Data()); + auto dy_addr = reinterpret_cast(input_dy->Data()); + auto dw_addr = reinterpret_cast(out_dw->Data()); + + int i, j; + int nweights = out_dw->ElementsNum(); + int in_ch = conv_param->input_channel_; + int in_h = conv_param->input_h_; + int in_w = conv_param->input_w_; + int k_h = conv_param->kernel_h_; // out_dw->shape()[1]; + int k_w = conv_param->kernel_w_; // out_dw->shape()[2]; + int batch = conv_param->output_batch_; + int out_ch = conv_param->output_channel_; + int groups = conv_param->group_; + int out_h = conv_param->output_h_; + int out_w = conv_param->output_w_; + + int m = out_h * out_w; + int n = k_h * k_w * in_ch / groups; + int k = out_ch / groups; + + // zero out pointer + memset(dw_addr, 0, out_dw->Size()); + + for (i = 0; i < batch; ++i) { + for (j = 0; j < groups; ++j) { + float *mat_a = dy_addr + (i * groups) * m * k + j * (out_ch / groups); + float *mat_b = workspace; + float *mat_c = dw_addr + j * nweights / groups; + float *im = x_addr + (i * groups) * (in_ch / groups) * in_h * in_w + j * (in_ch / groups); + + im2row_hwc(im, mat_b, conv_param); + gemm(1, 1, k, n, m, 1, mat_a, out_ch, mat_b, m, 1, mat_c, n); + } + } + + // std::cout << "run succ" << std::endl; + return RET_OK; +} + +kernel::LiteKernel *CpuConvGradFilterFp32KernelCreator(const std::vector &inputs, + const std::vector &outputs, + OpParameter *opParameter, const lite::Context *ctx, + const kernel::KernelKey &desc) { + MS_ASSERT(opParameter != nullptr); + MS_ASSERT(desc.type == schema::PrimitiveType_Conv2DGradFilter); + + auto *kernel = new (std::nothrow) ConvolutionGradFilterCPUKernel(opParameter, inputs, outputs); + MS_ASSERT(kernel != nullptr); + + auto ret = kernel->Init(); + if (RET_OK != ret) { + MS_LOG(ERROR) << "Init kernel failed, name: " << opParameter->name_ << ", type: " + << schema::EnumNamePrimitiveType(static_cast(opParameter->type_)); + delete kernel; + return nullptr; + } + return kernel; +} + +REG_KERNEL(kCPU, kNumberTypeFloat32, PrimitiveType_Conv2DGradFilter, CpuConvGradFilterFp32KernelCreator) +} // namespace mindspore::kernel diff --git a/mindspore/lite/src/runtime/kernel/arm/fp32/convolution_grad_filter.h b/mindspore/lite/src/runtime/kernel/arm/fp32/convolution_grad_filter.h new file mode 100644 index 0000000000..c32a798eaf --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/fp32/convolution_grad_filter.h @@ -0,0 +1,41 @@ +/** + * Copyright 2019 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_FP32_CONVOLUTION_GRAD_FILTER_H_ +#define MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_FP32_CONVOLUTION_GRAD_FILTER_H_ + +#include +#include "src/lite_kernel.h" +#include "ir/anf.h" + +namespace mindspore::kernel { +class ConvolutionGradFilterCPUKernel : public LiteKernel { + public: + explicit ConvolutionGradFilterCPUKernel(OpParameter *parameter, const std::vector &inputs, + const std::vector &outputs) + : LiteKernel(parameter, inputs, outputs) {} + ~ConvolutionGradFilterCPUKernel() override { delete workspace; } + + int Init() override; + int ReSize() override; + int Run() override; + + private: + float *workspace; +}; +} // namespace mindspore::kernel + +#endif // MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_FP32_CONVOLUTION_GRAD_FILTER_H_ diff --git a/mindspore/lite/src/runtime/kernel/arm/fp32/convolution_grad_input.cc b/mindspore/lite/src/runtime/kernel/arm/fp32/convolution_grad_input.cc new file mode 100644 index 0000000000..29bb49a8c8 --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/fp32/convolution_grad_input.cc @@ -0,0 +1,136 @@ +/** + * Copyright 2019 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "src/runtime/kernel/arm/fp32/convolution_grad_input.h" +#include "src/kernel_registry.h" +#include "src/runtime/kernel/arm/opclib/pack.h" +#include "src/runtime/kernel/arm/opclib/pack_ext.h" +#include "src/runtime/kernel/arm/opclib/fp32/gemm.h" +#include "include/errorcode.h" + +using mindspore::kernel::KERNEL_ARCH::kCPU; +using mindspore::lite::KernelRegistrar; +using mindspore::schema::PrimitiveType_Conv2DGradInput; +using mindspore::lite::RET_ERROR; +using mindspore::lite::RET_OK; + +namespace mindspore::kernel { +int ConvolutionGradInputCPUKernel::Init() { + if (2 != this->inputs_.size()) { + MS_LOG(ERROR) << "Conv2d Grad should has 2 inputs"; + return RET_ERROR; + } + if (1 != this->outputs_.size()) { + MS_LOG(ERROR) << "Conv2d Grad should has one output"; + return RET_ERROR; + } + + auto *dy_tensor = inputs_.at(kInputIndex); + MS_ASSERT(dy_tensor != nullptr); + auto *weight_tensor = inputs_.at(kWeightIndex); + MS_ASSERT(weight_tensor != nullptr); + auto *dx_tensor = outputs_.at(kOutputIndex); + MS_ASSERT(dx_tensor != nullptr); + + auto conv_param = reinterpret_cast(opParameter); + conv_param->output_batch_ = dx_tensor->shape()[(kNHWC_N)]; + conv_param->input_batch_ = dy_tensor->shape()[(kNHWC_N)]; + + conv_param->input_h_ = dx_tensor->shape()[(kNHWC_H)]; + conv_param->input_w_ = dx_tensor->shape()[(kNHWC_W)]; + + // assume OutCh|kh|kw|In + conv_param->input_channel_ = dx_tensor->shape()[(kNHWC_C)]; + conv_param->output_channel_ = weight_tensor->shape()[(kNHWC_N)]; + + // TBD + conv_param->output_h_ = dy_tensor->shape()[kNHWC_H]; + conv_param->output_w_ = dy_tensor->shape()[kNHWC_W]; + + int ws_size = conv_param->output_h_ * conv_param->output_w_ * conv_param->kernel_h_ * conv_param->kernel_w_ * + conv_param->input_channel_ / conv_param->group_; + + workspace = new float[ws_size]; + return 0; +} + +int ConvolutionGradInputCPUKernel::ReSize() { return 0; } + +int ConvolutionGradInputCPUKernel::Run() { + auto conv_param = reinterpret_cast(opParameter); + auto *input_dy = inputs_.at(0); + auto *input_w = inputs_.at(1); + auto *out_dx = outputs_.at(0); + + auto dy_addr = reinterpret_cast(input_dy->Data()); + auto w_addr = reinterpret_cast(input_w->Data()); + auto dx_addr = reinterpret_cast(out_dx->Data()); + + int i, j; + int nweights = input_w->ElementsNum(); + int in_ch = conv_param->input_channel_; + int in_h = conv_param->input_h_; + int in_w = conv_param->input_w_; + int k_h = conv_param->kernel_h_; // out_dw->shape()[1]; + int k_w = conv_param->kernel_w_; // out_dw->shape()[2]; + int batch = conv_param->output_batch_; + int out_ch = conv_param->output_channel_; + int groups = conv_param->group_; + int out_h = conv_param->output_h_; + int out_w = conv_param->output_w_; + + int m = out_h * out_w; + int n = k_w * k_h * in_ch / groups; + int k = out_ch / groups; + + memset(dx_addr, 0, sizeof(float) * batch * in_ch * in_h * in_w); + + for (i = 0; i < batch; ++i) { + for (j = 0; j < groups; ++j) { + float *mat_a = dy_addr + (i * groups) * m * k + j * (out_ch / groups); + float *mat_b = w_addr + j * nweights / groups; + float *mat_c = workspace; + gemm(0, 0, m, n, k, 1, mat_a, out_ch, mat_b, n, 0, mat_c, n); + col2im_hwc(mat_c, dx_addr + (i * groups) * (in_ch / groups) * in_h * in_w + j * (in_ch / groups), conv_param); + } + } + + // std::cout << "run succ" << std::endl; + return 0; +} + +kernel::LiteKernel *CpuConvGradInputFp32KernelCreator(const std::vector &inputs, + const std::vector &outputs, + OpParameter *opParameter, const lite::Context *ctx, + const kernel::KernelKey &desc) { + MS_ASSERT(opParameter != nullptr); + MS_ASSERT(desc.type == schema::PrimitiveType_Conv2DGradInput); + + auto *kernel = new (std::nothrow) ConvolutionGradInputCPUKernel(opParameter, inputs, outputs); + MS_ASSERT(kernel != nullptr); + + auto ret = kernel->Init(); + if (0 != ret) { + MS_LOG(ERROR) << "Init kernel failed, name: " << opParameter->name_ << ", type: " + << schema::EnumNamePrimitiveType(static_cast(opParameter->type_)); + delete kernel; + return nullptr; + } + return kernel; +} + +REG_KERNEL(kCPU, kNumberTypeFloat32, PrimitiveType_Conv2DGradInput, CpuConvGradInputFp32KernelCreator) +} // namespace mindspore::kernel diff --git a/mindspore/lite/src/runtime/kernel/arm/fp32/convolution_grad_input.h b/mindspore/lite/src/runtime/kernel/arm/fp32/convolution_grad_input.h new file mode 100644 index 0000000000..86901b37ba --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/fp32/convolution_grad_input.h @@ -0,0 +1,41 @@ +/** + * Copyright 2019 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_FP32_CONVOLUTION_GRAD_INPUT_H_ +#define MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_FP32_CONVOLUTION_GRAD_INPUT_H_ + +#include +#include "src/lite_kernel.h" +#include "ir/anf.h" + +namespace mindspore::kernel { +class ConvolutionGradInputCPUKernel : public LiteKernel { + public: + explicit ConvolutionGradInputCPUKernel(OpParameter *parameter, const std::vector &inputs, + const std::vector &outputs) + : LiteKernel(parameter, inputs, outputs) {} + ~ConvolutionGradInputCPUKernel() override { delete workspace; } + + int Init() override; + int ReSize() override; + int Run() override; + + private: + float *workspace; +}; +} // namespace mindspore::kernel + +#endif // MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_FP32_CONVOLUTION_GRAD_INPUT_H_ diff --git a/mindspore/lite/src/runtime/kernel/arm/fp32/opt_momentum.cc b/mindspore/lite/src/runtime/kernel/arm/fp32/opt_momentum.cc new file mode 100644 index 0000000000..84c51509ba --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/fp32/opt_momentum.cc @@ -0,0 +1,78 @@ + +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "schema/model_generated.h" +#include "src/kernel_registry.h" +#include "src/runtime/kernel/arm/fp32/opt_momentum.h" +#include "include/errorcode.h" + +using mindspore::kernel::KERNEL_ARCH::kCPU; +using mindspore::lite::KernelRegistrar; +using mindspore::schema::PrimitiveType_OptMomentum; +using mindspore::lite::RET_ERROR; +using mindspore::lite::RET_OK; + +namespace mindspore::kernel { + +int OptMomentumCPUKernel::ReSize() { return 0; } + +int OptMomentumCPUKernel::Run() { + if (inputs_.size() != 5 || !outputs_.empty()) { + MS_LOG(ERROR) << "OptMomentumCPUKernel error input output size!"; + return RET_ERROR; + } + + if (inputs_[0]->ElementsNum() != inputs_[1]->ElementsNum() || + inputs_[0]->ElementsNum() != inputs_[3]->ElementsNum()) { + MS_LOG(ERROR) << "error input data size!"; + return RET_ERROR; + } + auto weight = reinterpret_cast(inputs_[0]->Data()); + auto accumulate = reinterpret_cast(inputs_[1]->Data()); + float learning_rate = reinterpret_cast(inputs_[2]->Data())[0]; + auto gradient = reinterpret_cast(inputs_[3]->Data()); + float moment = reinterpret_cast(inputs_[4]->Data())[0]; + size_t elem_num = inputs_[0]->ElementsNum(); + for (size_t i = 0; i < elem_num; ++i) { + accumulate[i] = accumulate[i] * moment + gradient[i]; + weight[i] -= accumulate[i] * learning_rate; + } + return RET_OK; +} + +int OptMomentumCPUKernel::Init() { return 0; } + +kernel::LiteKernel *CpuOptMomentumFp32KernelCreator(const std::vector &inputs, + const std::vector &outputs, + OpParameter *opParameter, const lite::Context *ctx, + const kernel::KernelKey &desc) { + MS_ASSERT(desc.type == schema::PrimitiveType_OptMomentum); + auto *kernel = new (std::nothrow) OptMomentumCPUKernel(opParameter, inputs, outputs); + MS_ASSERT(kernel != nullptr); + + auto ret = kernel->Init(); + if (0 != ret) { + MS_LOG(ERROR) << "Init kernel failed, name: " << opParameter->name_ << ", type: " + << schema::EnumNamePrimitiveType(static_cast(opParameter->type_)); + delete kernel; + return nullptr; + } + return kernel; +} + +REG_KERNEL(kCPU, kNumberTypeFloat32, PrimitiveType_OptMomentum, CpuOptMomentumFp32KernelCreator) +} // namespace mindspore::kernel diff --git a/mindspore/lite/src/runtime/kernel/arm/fp32/opt_momentum.h b/mindspore/lite/src/runtime/kernel/arm/fp32/opt_momentum.h new file mode 100644 index 0000000000..6746b5bf0b --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/fp32/opt_momentum.h @@ -0,0 +1,40 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_LITE_SRC_BACKEND_ARM_FP32_OPT_MOMENTUM_H_ +#define MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_OPT_MOMENTUM_H_ + +#include +#include "src/lite_kernel.h" +#include "ir/anf.h" + +namespace mindspore::kernel { +class OptMomentumCPUKernel : public LiteKernel { + public: + explicit OptMomentumCPUKernel(OpParameter *parameter, const std::vector &inputs, + const std::vector &outputs) + : LiteKernel(parameter, inputs, outputs) {} + ~OptMomentumCPUKernel() override {} + + int Init() override; + int ReSize() override; + int Run() override; + + private: +}; +} // namespace mindspore::kernel + +#endif // MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_OPT_MOMENTUM_H_ diff --git a/mindspore/lite/src/runtime/kernel/arm/fp32/pooling_grad.cc b/mindspore/lite/src/runtime/kernel/arm/fp32/pooling_grad.cc new file mode 100644 index 0000000000..9b10cbf369 --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/fp32/pooling_grad.cc @@ -0,0 +1,195 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "src/runtime/kernel/arm/fp32/pooling_grad.h" +#include "schema/model_generated.h" +#include "src/kernel_registry.h" +#include "src/runtime/kernel/arm/opclib/fp32/pooling.h" +#include "src/runtime/kernel/arm/opclib/fp32/pooling_grad.h" +#include "include/errorcode.h" + +using mindspore::kernel::KERNEL_ARCH::kCPU; +using mindspore::lite::KernelRegistrar; +using mindspore::lite::RET_ERROR; +using mindspore::lite::RET_OK; +using mindspore::schema::PrimitiveType_PoolingGrad; + +namespace mindspore::kernel { +#if 0 +int PoolingGradCPUKernel::TfPadding(int input_w, int input_h, int &output_w, int &output_h) { + PoolingParameter *pool_param = reinterpret_cast (opParameter); + + auto stride_w = pool_param->stride_w_; + auto stride_h = pool_param->stride_h_; + auto window_w = pool_param->window_w_; + auto window_h = pool_param->window_h_; + auto pad_up = pool_param->pad_u_; + auto pad_down = pool_param->pad_d_; + auto pad_left = pool_param->pad_l_; + auto pad_right = pool_param->pad_r_; + if (pool_param->pad_mode_ == PADMODE_SAME) { + output_w = ceil(input_w / stride_w); + output_h = ceil(input_h / stride_h); + } else { + output_w = ceil((input_w + pad_left + pad_right - window_w + 1) / stride_w); + output_h = ceil((input_h + pad_up + pad_down - window_h + 1) / stride_h); + } + return RET_OK; +} + +int PoolingGradCPUKernel::CaffePadding(int input_w, int input_h, int &output_w, int &output_h) { + PoolingParameter *pool_param = reinterpret_cast (opParameter); + + auto round_mode = pool_param->round_mode_; + auto stride_w = pool_param->stride_w_; + auto stride_h = pool_param->stride_h_; + auto window_w = pool_param->window_w_; + auto window_h = pool_param->window_h_; + auto pad_up = pool_param->pad_u_; + auto pad_down = pool_param->pad_d_; + auto pad_left = pool_param->pad_l_; + auto pad_right = pool_param->pad_r_; + if (round_mode == ROUNDMODE_FLOOR && false) { + output_w = floor((input_w + pad_left + pad_right - window_w) / stride_w + 1); + output_h = floor((input_h + pad_up + pad_down - window_h) / stride_h + 1); + } else if (round_mode == ROUNDMODE_CEIL || true) { + output_w = ceil((input_w + pad_left + pad_right - window_w) / stride_w + 1); + output_h = ceil((input_h + pad_up + pad_down - window_h) / stride_h + 1); + } else { + MS_LOG(ERROR) << "round mode not support."; + } + + if (pad_left > 0 || pad_up > 0) { + if ((output_w - 1) * stride_w >= input_w + pad_left) { + --output_w; + } + if ((output_h - 1) * stride_h >= input_h + pad_up) { + --output_h; + } + } + return RET_OK; +} + +int PoolingGradCPUKernel::OnnxPadding(int input_w, int input_h, int &output_w, int &output_h) { + PoolingParameter *pool_param = reinterpret_cast (opParameter); + + auto round_mode = pool_param->round_mode_; + auto stride_w = pool_param->stride_w_; + auto stride_h = pool_param->stride_h_; + auto window_w = pool_param->window_w_; + auto window_h = pool_param->window_h_; + auto pad_up = pool_param->pad_u_; + auto pad_down = pool_param->pad_d_; + auto pad_left = pool_param->pad_l_; + auto pad_right = pool_param->pad_r_; + if (round_mode == ROUNDMODE_FLOOR) { + output_w = floor((input_w + pad_left + pad_right - window_w) / stride_w + 1); + output_h = floor((input_h + pad_up + pad_down - window_h) / stride_h + 1); + } else if (round_mode == ROUNDMODE_CEIL) { + MS_LOG(ERROR) << "RoundMode_CEIL mode not support."; + } else { + MS_LOG(ERROR) << "OnnxPadding round mode not support."; + } + return RET_OK; +} +#endif + +int PoolingGradCPUKernel::Init() { + // InferShape(): + // auto *in_tensor = reinterpret_cast(inputs_.at(0)->Data()); + // auto *x_tensor = reinterpret_cast(inputs_.at(1)->Data()); + + PoolingParameter *pool_param = reinterpret_cast(opParameter); + + auto in_shape = inputs_.at(0)->shape(); + int input_h = in_shape.at(1); + int input_w = in_shape.at(2); + + if (pool_param->global_) { + pool_param->window_w_ = input_w; + pool_param->window_h_ = input_h; + } + + // Emir -- here I assume we get the outputshape in the output tensor + auto *out_tensor = outputs_.front(); + auto out_shape = out_tensor->shape(); + +#if 0 + int output_w = 0, output_h = 0; + auto fmk_type = pool_param->fmk_type_; + switch (fmk_type) { + case lite::FmkType_TF: + break; + case lite::FmkType_CAFFE: + CaffePadding(input_w, input_h, output_w, output_h); + break; + case lite::FmkType_ONNX: + OnnxPadding(input_w, input_h, output_w, output_h); + break; + case lite::FmkType_MS: + break; + case lite::FmkType_TFLITE: + TfPadding(input_w, input_h, output_w, output_h); + break; + default: + MS_LOG(ERROR) << "Not support this framework."; + } + std::vector out_shape{in_tensor->shape()}; + out_shape.at(1) = output_h; + out_shape.at(2) = output_w; +#endif + out_tensor->set_shape(out_shape); + out_tensor->set_data_type(inputs_.at(0)->data_type()); + return RET_OK; +} + +int PoolingGradCPUKernel::ReSize() { return RET_OK; } + +int PoolingGradCPUKernel::Run() { + PoolingParameter *pool_param = reinterpret_cast(opParameter); + auto input_ptr = reinterpret_cast(inputs_.at(0)->Data()); + auto output_ptr = reinterpret_cast(outputs_.at(0)->Data()); + + if (pool_param->max_pooling_) { + auto ind = reinterpret_cast(inputs_.at(1)->Data()); + MaxPoolingGrad(input_ptr, ind, output_ptr, pool_param); + } else { + AvgPoolingGrad(input_ptr, output_ptr, pool_param); + } + return RET_OK; +} + +kernel::LiteKernel *CpuPoolingGradFp32KernelCreator(const std::vector &inputs, + const std::vector &outputs, + OpParameter *opParameter, const lite::Context *ctx, + const kernel::KernelKey &desc) { + MS_ASSERT(opParameter != nullptr); + MS_ASSERT(desc.type == schema::PrimitiveType_PoolingGrad); + + auto *kernel = new (std::nothrow) PoolingGradCPUKernel(opParameter, inputs, outputs); + MS_ASSERT(kernel != nullptr); + auto ret = kernel->Init(); + if (RET_OK != ret) { + MS_LOG(ERROR) << "Init kernel failed, name: " << opParameter->name_ << ", type: " + << schema::EnumNamePrimitiveType(static_cast(opParameter->type_)); + delete kernel; + return nullptr; + } + return kernel; +} + +REG_KERNEL(kCPU, kNumberTypeFloat32, PrimitiveType_PoolingGrad, CpuPoolingGradFp32KernelCreator) +} // namespace mindspore::kernel diff --git a/mindspore/lite/src/runtime/kernel/arm/fp32/pooling_grad.h b/mindspore/lite/src/runtime/kernel/arm/fp32/pooling_grad.h new file mode 100644 index 0000000000..eec333d860 --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/fp32/pooling_grad.h @@ -0,0 +1,50 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_FP32_POOLING_GRAD_H_ +#define MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_FP32_POOLING_GRAD_H_ + +#include +#include "src/lite_kernel.h" +#include "ir/anf.h" + +namespace mindspore::kernel { +using mindspore::schema::PadMode; +using mindspore::schema::PoolMode; +using mindspore::schema::QuantType; +using mindspore::schema::RoundMode; + +class PoolingGradCPUKernel : public LiteKernel { + public: + explicit PoolingGradCPUKernel(OpParameter *parameter, const std::vector &inputs, + const std::vector &outputs) + : LiteKernel(parameter, inputs, outputs) {} + ~PoolingGradCPUKernel() override = default; + + // int TfPadding(int input_w, int input_h, int &output_w, int &output_h); + // int CaffePadding(int input_w, int input_h, int &output_w, int &output_h); + // int OnnxPadding(int input_w, int input_h, int &output_w, int &output_h); + + int Init() override; + int ReSize() override; + int Run() override; + + private: + uint8_t data_shape_{0}; +}; +} // namespace mindspore::kernel + +#endif // MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_FP32_POOLING_GRAD_H_ diff --git a/mindspore/lite/src/runtime/kernel/arm/fp32/power_grad.cc b/mindspore/lite/src/runtime/kernel/arm/fp32/power_grad.cc new file mode 100644 index 0000000000..759cf8b437 --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/fp32/power_grad.cc @@ -0,0 +1,67 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "src/runtime/kernel/arm/fp32/power_grad.h" +#include "schema/model_generated.h" +#include "src/kernel_registry.h" +#include "include/errorcode.h" +#include "src/runtime/kernel/arm/opclib/fp32/arithmetic.h" + +using mindspore::lite::KernelRegistrar; +using mindspore::lite::RET_ERROR; +using mindspore::lite::RET_OK; +using mindspore::schema::PrimitiveType_PowerGrad; + +namespace mindspore::kernel { +int PowerGradCPUKernel::Init() { return RET_OK; } + +int PowerGradCPUKernel::ReSize() { return RET_OK; } + +int PowerGradCPUKernel::Run() { + auto dy_addr = reinterpret_cast(inputs_.at(0)->Data()); + auto x_addr = reinterpret_cast(inputs_.at(1)->Data()); + auto dx_addr = reinterpret_cast(outputs_.at(0)->Data()); + auto size = inputs_.at(0)->ElementsNum(); + + Power(x_addr, dx_addr, size, power_ - 1, scale_, shift_); + ElementMul(dx_addr, dy_addr, dx_addr, size); + float scale = scale_ * power_; + for (int i = 0; i < size; i++) { + dx_addr[i] *= scale; + } + + return RET_OK; +} + +kernel::LiteKernel *CpuPowerGradFp32KernelCreator(const std::vector &inputs, + const std::vector &outputs, + OpParameter *opParameter, const lite::Context *ctx, + const kernel::KernelKey &desc) { + MS_ASSERT(opParameter != nullptr); + MS_ASSERT(desc.type == schema::PrimitiveType_PowerGrad); + auto *kernel = new (std::nothrow) PowerGradCPUKernel(opParameter, inputs, outputs); + auto ret = kernel->Init(); + if (ret != RET_OK) { + MS_LOG(ERROR) << "Init kernel failed, name: " << opParameter->name_ << ", type: " + << schema::EnumNamePrimitiveType(static_cast(opParameter->type_)); + delete kernel; + return nullptr; + } + return kernel; +} + +REG_KERNEL(kCPU, kNumberTypeFloat32, PrimitiveType_PowerGrad, CpuPowerGradFp32KernelCreator) +} // namespace mindspore::kernel diff --git a/mindspore/lite/src/runtime/kernel/arm/fp32/power_grad.h b/mindspore/lite/src/runtime/kernel/arm/fp32/power_grad.h new file mode 100644 index 0000000000..316b55e1eb --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/fp32/power_grad.h @@ -0,0 +1,49 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_FP32_POWER_GRAD_H_ +#define MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_FP32_POWER_GRAD_H_ + +#include +#include "src/lite_kernel.h" +#include "ir/anf.h" +#include "src/runtime/kernel/arm/opclib/power.h" + +namespace mindspore::kernel { +class PowerGradCPUKernel : public LiteKernel { + public: + PowerGradCPUKernel(OpParameter *param, const std::vector &inputs, + const std::vector &outputs) + : LiteKernel(param, inputs, outputs) { + PowerParameter *power_param = reinterpret_cast(param); + power_ = power_param->power_; + scale_ = power_param->scale_; + shift_ = power_param->shift_; + } + ~PowerGradCPUKernel() override = default; + + int Init() override; + int ReSize() override; + int Run() override; + + private: + float power_; + float scale_; + float shift_; +}; +} // namespace mindspore::kernel + +#endif // MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_FP32_POWER_GRAD_H_ diff --git a/mindspore/lite/src/runtime/kernel/arm/fp32/sparse_softmax_cross_entropy_with_logits.cc b/mindspore/lite/src/runtime/kernel/arm/fp32/sparse_softmax_cross_entropy_with_logits.cc new file mode 100644 index 0000000000..005b091fb6 --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/fp32/sparse_softmax_cross_entropy_with_logits.cc @@ -0,0 +1,145 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "src/runtime/kernel/arm/fp32/sparse_softmax_cross_entropy_with_logits.h" +#include "src/runtime/kernel/arm/opclib/fp32/softmax.h" +#include "schema/model_generated.h" +#include "src/kernel_registry.h" +#include "include/errorcode.h" + +using mindspore::kernel::KERNEL_ARCH::kCPU; +using mindspore::lite::KernelRegistrar; +using mindspore::lite::RET_ERROR; +using mindspore::lite::RET_OK; +using mindspore::schema::PrimitiveType_SoftmaxCrossEntropy; + +namespace mindspore::kernel { + +int SparseSoftmaxCrossEntropyWithLogitsCPUKernel::ReSize() { return RET_OK; } + +void SparseSoftmaxCrossEntropyWithLogitsCPUKernel::ForwardPostExecute(const int *labels, const float *losses, + float *output) const { + float total_loss = 0; + for (int i = 0; i < param->batch_size_; ++i) { + if (labels[i] < 0) { + MS_LOG(EXCEPTION) << "label value must >= 0"; + } + size_t label = labels[i]; + if (label > param->number_of_classes_) { + MS_LOG(EXCEPTION) << "error label input!"; + } else { + total_loss -= logf(losses[i * param->number_of_classes_ + label]); + } + } + output[0] = total_loss / param->batch_size_; +} + +void SparseSoftmaxCrossEntropyWithLogitsCPUKernel::GradPostExecute(const int *labels, const float *losses, + float *output) const { + size_t row_start = 0; + for (int i = 0; i < param->batch_size_; ++i) { + if (labels[i] < 0) { + MS_LOG(EXCEPTION) << "label value must >= 0"; + } + size_t label = labels[i]; + if (label > param->number_of_classes_) { + MS_LOG(EXCEPTION) << "error label input!"; + } + for (size_t j = 0; j < param->number_of_classes_; ++j) { + size_t index = row_start + j; + if (j == label) { + output[index] = (losses[index] - 1) / param->batch_size_; + } else { + output[index] = losses[index] / param->batch_size_; + } + } + row_start += param->number_of_classes_; + } +} + +int SparseSoftmaxCrossEntropyWithLogitsCPUKernel::Run() { + auto ins = reinterpret_cast(inputs_.at(0)->Data()); + auto labels = reinterpret_cast(inputs_.at(1)->Data()); + auto out = reinterpret_cast(outputs_.at(0)->Data()); + float *grads = NULL; + if (is_train()) { // outputs_.size() > 1) + grads = reinterpret_cast(outputs_.at(0)->Data()); + } + size_t data_size = inputs_.at(0)->ElementsNum(); + float *losses = new (std::nothrow) float[data_size]; + MS_ASSERT(losses != nullptr); + std::fill(losses, losses + data_size, 0); + + MS_ASSERT(out != nullptr); + MS_ASSERT(labels != nullptr); + MS_ASSERT(ins != nullptr); + + SoftmaxParameter sm_params; + sm_params.n_dim_ = param->n_dim_; + sm_params.element_size_ = data_size; + sm_params.axis_ = 1; + for (int i = 0; i < 4; i++) // softmax has only 4 params in shape + sm_params.input_shape_[i] = param->input_shape_[i]; + float sum_data[sm_params.input_shape_[sm_params.axis_]]; + Softmax(ins, losses, sum_data, &sm_params); + + if (is_train()) { + GradPostExecute(labels, losses, grads); + } else { + ForwardPostExecute(labels, losses, out); + } + return RET_OK; +} + +int SparseSoftmaxCrossEntropyWithLogitsCPUKernel::Init() { + auto dims = inputs_[0]->shape(); + param->n_dim_ = 2; + param->number_of_classes_ = dims[1]; + param->batch_size_ = dims[0]; + for (unsigned int i = 0; i < dims.size(); i++) param->input_shape_[i] = dims[i]; + if (2 != this->inputs_.size()) { + MS_LOG(ERROR) << "softmax entropy loss should have two inputs"; + return RET_ERROR; + } + auto *in0 = inputs_.front(); + if (in0 == nullptr) { + MS_LOG(ERROR) << "softmax etropy loss in0 have no data"; + return RET_ERROR; + } + + return RET_OK; +} + +kernel::LiteKernel *CpuSoftmaxCrossEntropyFp32KernelCreator(const std::vector &inputs, + const std::vector &outputs, + OpParameter *opParameter, const lite::Context *ctx, + const kernel::KernelKey &desc) { + MS_ASSERT(opParameter != nullptr); + MS_ASSERT(desc.type == schema::PrimitiveType_SoftmaxCrossEntropy); + auto *kernel = new (std::nothrow) SparseSoftmaxCrossEntropyWithLogitsCPUKernel(opParameter, inputs, outputs); + MS_ASSERT(kernel != nullptr); + auto ret = kernel->Init(); + if (RET_OK != ret) { + MS_LOG(ERROR) << "Init kernel failed, name: " << opParameter->name_ << ", type: " + << schema::EnumNamePrimitiveType(static_cast(opParameter->type_)); + delete kernel; + return nullptr; + } + return kernel; +} + +REG_KERNEL(kCPU, kNumberTypeFloat32, PrimitiveType_SoftmaxCrossEntropy, CpuSoftmaxCrossEntropyFp32KernelCreator) +} // namespace mindspore::kernel diff --git a/mindspore/lite/src/runtime/kernel/arm/fp32/sparse_softmax_cross_entropy_with_logits.h b/mindspore/lite/src/runtime/kernel/arm/fp32/sparse_softmax_cross_entropy_with_logits.h new file mode 100644 index 0000000000..ae9a4dd0a9 --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/fp32/sparse_softmax_cross_entropy_with_logits.h @@ -0,0 +1,50 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_FP32_SPARSE_SOFTMAX_CROSS_ENTROPY_WITH_LOGITS_H_ +#define MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_FP32_SPARSE_SOFTMAX_CROSS_ENTROPY_WITH_LOGITS_H_ + +#include +#include "src/lite_kernel.h" +#include "ir/anf.h" +#include "src/runtime/kernel/arm/opclib/fp32/softmax_grad.h" +#include "src/runtime/kernel/arm/opclib/fp32/arithmetic.h" + +namespace mindspore::kernel { + +class SparseSoftmaxCrossEntropyWithLogitsCPUKernel : public LiteKernel { + public: + explicit SparseSoftmaxCrossEntropyWithLogitsCPUKernel(OpParameter *parameter, + const std::vector &inputs, + const std::vector &outputs) + : LiteKernel(parameter, inputs, outputs) { + param = reinterpret_cast(parameter); + } + ~SparseSoftmaxCrossEntropyWithLogitsCPUKernel() override = default; + + void ForwardPostExecute(const int *labels, const float *losses, float *output) const; + void GradPostExecute(const int *labels, const float *losses, float *output) const; + + int Init() override; + int ReSize() override; + int Run() override; + + private: + SoftmaxCrossEntropyParameter *param; +}; +} // namespace mindspore::kernel + +#endif // MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_FP32_SPARSE_SOFTMAX_CROSS_ENTROPY_WITH_LOGITS_H_ diff --git a/mindspore/lite/src/runtime/kernel/arm/opclib/activation_grad.h b/mindspore/lite/src/runtime/kernel/arm/opclib/activation_grad.h new file mode 100644 index 0000000000..ac49b8567a --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/opclib/activation_grad.h @@ -0,0 +1,88 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_OPCLIB_ACTIVATION_GRAD_H_ +#define MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_OPCLIB_ACTIVATION_GRAD_H_ + +#include +#include "src/runtime/kernel/arm/opclib/op_base.h" +#include "src/runtime/kernel/arm/opclib/fp32/arithmetic.h" +#include "src/runtime/kernel/arm/opclib/errorcode.h" + +struct ActivationGradParameter { + OpParameter op_parameter{}; + int type_; + float alpha_{0.01}; +}; + +inline int ReluGrad(float *src0, float *src1, int length, float *dst) { + for (int i = 0; i < length; ++i) { + dst[i] = src1[i] > 0 ? 1.0f : 0.0f; + } + ElementMul(src0, dst, dst, length); + return OPCLIB_OK; +} + +inline int Relu6Grad(float *src0, float *src1, int length, float *dst) { + for (int i = 0; i < length; ++i) { + if (src1[i] < 0) { + dst[i] = 0; + } else { + dst[i] = src1[i] > 6.0f ? 0.0f : 1.0f; + } + } + ElementMul(src0, dst, dst, length); + return OPCLIB_OK; +} + +inline int LReluGrad(float *src0, float *src1, int length, float *dst, float alpha) { + for (int i = 0; i < length; ++i) { + dst[i] = src1[i] > 0.0f ? 1.0f : alpha; + } + ElementMul(src0, dst, dst, length); + return OPCLIB_OK; +} + +inline int SigmoidGrad(float *src0, float *src1, int length, float *dst) { + for (int i = 0; i < length; ++i) { + dst[i] = src0[i] * (src1[i] * (1.0f - src1[i])); + } + return OPCLIB_OK; +} + +inline int TanhGrad(float *src0, float *src1, int length, float *dst) { + for (int i = 0; i < length; ++i) { + dst[i] = (1.0f - (src1[i] * src1[i])) * src0[i]; + } + return OPCLIB_OK; +} + +inline int HSwishGrad(float *src0, float *src1, int length, float *dst) { + for (int i = 0; i < length; ++i) { + float tmp = (src1[i] > 3.0f ? 1.0f : (src1[i] < -3.0f ? 0.0f : (2.0f * src1[i] + 3.0f) / 6.0f)); + dst[i] = tmp * src0[i]; + } + return OPCLIB_OK; +} + +inline int HSigmoidGrad(float *src0, float *src1, int length, float *dst) { + for (int i = 0; i < length; ++i) { + float tmp = (src1[i] > 3.0f ? 1.0f : (src1[i] < -3.0f ? 0.0f : 1.0f / 6.0f)); + dst[i] = tmp * src0[i]; + } + return OPCLIB_OK; +} + +#endif // MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_OPCLIB_ACTIVATION_GRAD_H_ diff --git a/mindspore/lite/src/runtime/kernel/arm/opclib/batch_norm.cc b/mindspore/lite/src/runtime/kernel/arm/opclib/batch_norm.cc new file mode 100644 index 0000000000..c11819a1d9 --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/opclib/batch_norm.cc @@ -0,0 +1,120 @@ +/** + * Copyright 2019 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include "src/runtime/kernel/arm/opclib/batch_norm.h" + +static void sumSpatialBatch(const float *in, int size, int ch, float *out) { + std::fill(out, out + ch, 0.f); + for (int i = 0; i < size; i++) { + const float *ptr = in + i * ch; + for (int c = 0; c < ch; c++) { + out[c] += ptr[c]; + } + } +} + +void scaleBias(const float *scales, int batch, int n, int size, float *output) { + for (int i = 0; i < batch * size; i++) + for (int c = 0; c < n; c++) output[i * n + c] *= scales[c]; +} + +void normalize(const float *x, const float *mean, const float *variance, float eps, int batch, int filters, int spatial, + float *out) { + int b, f, i; + for (b = 0; b < batch; ++b) { + for (i = 0; i < spatial; ++i) { + for (f = 0; f < filters; ++f) { + int index = b * filters * spatial + i * filters + f; + out[index] = (x[index] - mean[f]) / (std::sqrt(variance[f]) + eps); + } + } + } +} + +void backwardScale(const float *x_norm, const float *delta, int batch, int n, int size, float *scale_updates) { + int i, b, f; + std::fill(scale_updates, scale_updates + n, 0.f); + for (b = 0; b < batch; ++b) { + for (i = 0; i < size; ++i) { + for (f = 0; f < n; ++f) { + int index = (b * size + i) * n + f; + scale_updates[f] += delta[index] * x_norm[index]; + } + } + } +} + +void meanVar(const float *in, int batch, int spatial, int ch, float *mean, float *var) { + float N = batch * spatial; + sumSpatialBatch(in, N, ch, mean); + for (int f = 0; f < ch; ++f) mean[f] /= N; + std::fill(var, var + ch, 0.f); + for (int i = 0; i < N; i++) { + for (int f = 0; f < ch; f++) { + float x = in[i * ch + f]; + var[f] += (x - mean[f]) * (x - mean[f]); + } + } + for (int f = 0; f < ch; f++) var[f] /= N; +} + +void meanDelta(float *yt, int size, int ch, float eps, float *variance, float *mean_delta) { + sumSpatialBatch(yt, size, ch, mean_delta); + for (int i = 0; i < ch; i++) mean_delta[i] *= -1.f / std::sqrt((variance[i] + eps)); +} + +void meanAdd(const float *x, const float *mean, const float *variance_delta, int batch, int filters, int spatial, + float *mean_add, float *mean_delta) { + int i, k; + std::fill(mean_add, mean_add + filters, 0.f); + for (k = 0; k < spatial * batch; ++k) { + for (i = 0; i < filters; ++i) { + int index = k * filters + i; + mean_add[i] += x[index] - mean[i]; + } + } + for (i = 0; i < filters; ++i) { + mean_add[i] *= variance_delta[i] * (-2.f / (spatial * batch)); + mean_delta[i] += mean_add[i]; + } +} + +void varianceDelta(const float *x, const float *delta, const float *mean, const float *variance, int batch, int filters, + int spatial, float eps, float *variance_delta) { + int i, k; + std::fill(variance_delta, variance_delta + filters, 0.f); + for (k = 0; k < batch * spatial; k++) { + for (i = 0; i < filters; i++) { + int index = k * filters + i; + variance_delta[i] += delta[index] * (x[index] - mean[i]); + } + } + for (i = 0; i < filters; i++) variance_delta[i] *= -.5 * pow(variance[i] + eps, (-3.f / 2.f)); +} + +void NormalizeDelta(const float *x, const float *mean, const float *variance, const float *mean_delta, + const float *variance_delta, int batch, int filters, int spatial, float eps, float *delta) { + int f, k; + for (k = 0; k < batch * spatial; k++) { + for (f = 0; f < filters; f++) { + int index = k * filters + f; + delta[index] = delta[index] * 1. / (std::sqrt(variance[f] + eps)) + + variance_delta[f] * 2. * (x[index] - mean[f]) / (spatial * batch) + + mean_delta[f] / (spatial * batch); + } + } +} diff --git a/mindspore/lite/src/runtime/kernel/arm/opclib/batch_norm.h b/mindspore/lite/src/runtime/kernel/arm/opclib/batch_norm.h new file mode 100644 index 0000000000..0d9e8b74bf --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/opclib/batch_norm.h @@ -0,0 +1,39 @@ +/** + * Copyright 2019 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_LITE_SRC_BACKEND_ARM_BATCH_NORM_H_ +#define MINDSPORE_LITE_SRC_BACKEND_ARM_BATCH_NORM_H_ + +struct bnParameter { + int batch; + int channels; + int spatial; + float eps; +}; +void scaleBias(const float *scales, int batch, int n, int size, float *output); +void normalize(const float *x, const float *mean, const float *variance, float eps, int batch, int filters, int spatial, + float *out); +void backwardScale(const float *x_norm, const float *delta, int batch, int n, int size, float *scale_updates); +void meanVar(const float *in, int batch, int size, int ch, float *mean, float *var); +void meanDelta(float *yt, int size, int ch, float eps, float *variance, float *mean_delta); +void varianceDelta(const float *x, const float *delta, const float *mean, const float *variance, int batch, int ch, + int spatial, float eps, float *variance_delta); +void meanAdd(const float *x, const float *mean, const float *variance_delta, int batch, int filters, int spatial, + float *mean_add, float *mean_delta); +void NormalizeDelta(const float *x, const float *mean, const float *variance, const float *mean_delta, + const float *variance_delta, int batch, int filters, int spatial, float eps, float *delta); + +#endif diff --git a/mindspore/lite/src/runtime/kernel/arm/opclib/fp32/arithmetic_grad.cc b/mindspore/lite/src/runtime/kernel/arm/opclib/fp32/arithmetic_grad.cc new file mode 100644 index 0000000000..4baec49d02 --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/opclib/fp32/arithmetic_grad.cc @@ -0,0 +1,29 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "src/runtime/kernel/arm/opclib/fp32/arithmetic_grad.h" + +void ElementDivNegSquare(const float *nom, const float *denom, float *output, int element_size) { + for (int i = 0; i < element_size; i++) { + output[i] = -nom[i] / (denom[i] * denom[i]); + } +} + +void ElementMulAndDivNegSquare(const float *a, const float *b, const float *denom, float *output, int element_size) { + for (int i = 0; i < element_size; i++) { + output[i] = -a[i] * b[i] / (denom[i] * denom[i]); + } +} diff --git a/mindspore/lite/src/runtime/kernel/arm/opclib/fp32/arithmetic_grad.h b/mindspore/lite/src/runtime/kernel/arm/opclib/fp32/arithmetic_grad.h new file mode 100644 index 0000000000..5ce96e669b --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/opclib/fp32/arithmetic_grad.h @@ -0,0 +1,22 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_OPCLIB_FP32_ARITHMETIC_GRAD_H_ +#define MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_OPCLIB_FP32_ARITHMETIC_GRAD_H_ + +void ElementDivNegSquare(const float *nom, const float *denom, float *output, int element_size); +void ElementMulAndDivNegSquare(const float *a, const float *b, const float *denom, float *output, int element_size); + +#endif // MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_OPCLIB_FP32_ARITHMETIC_GRAD_H_ diff --git a/mindspore/lite/src/runtime/kernel/arm/opclib/fp32/gemm.cc b/mindspore/lite/src/runtime/kernel/arm/opclib/fp32/gemm.cc new file mode 100644 index 0000000000..a8f3b2afd4 --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/opclib/fp32/gemm.cc @@ -0,0 +1,108 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "src/runtime/kernel/arm/opclib/fp32/gemm.h" + +static void gemm_nn(int M, int N, int K, float alpha, float *mat_a, int lda, float *mat_B, int ldb, float *mat_c, + int ldc) { + int i, j, k; + for (i = 0; i < M; ++i) { + for (k = 0; k < K; ++k) { + float a = alpha * mat_a[i * lda + k]; + for (j = 0; j < N; ++j) { + mat_c[i * ldc + j] += a * mat_B[k * ldb + j]; + } + } + } +} + +static void gemm_nt(int M, int N, int K, float alpha, float *mat_a, int lda, float *mat_b, int ldb, float *mat_c, + int ldc) { + int i, j, k; + for (i = 0; i < M; ++i) { + for (j = 0; j < N; ++j) { + float sum = 0; + for (k = 0; k < K; ++k) { + sum += alpha * mat_a[i * lda + k] * mat_b[j * ldb + k]; + } + mat_c[i * ldc + j] += sum; + } + } +} + +static void gemm_tn(int M, int N, int K, float alpha, float *mat_a, int lda, float *mat_b, int ldb, float *mat_c, + int ldc) { + int i, j, k; + for (i = 0; i < M; ++i) { + for (k = 0; k < K; ++k) { + float a = alpha * mat_a[k * lda + i]; + for (j = 0; j < N; ++j) { + mat_c[i * ldc + j] += a * mat_b[k * ldb + j]; + } + } + } +} + +static void gemm_tt(int M, int N, int K, float alpha, float *mat_a, int lda, float *mat_b, int ldb, float *mat_c, + int ldc) { + int i, j, k; + for (i = 0; i < M; ++i) { + for (j = 0; j < N; ++j) { + float sum = 0; + for (k = 0; k < K; ++k) { + sum += alpha * mat_a[i + k * lda] * mat_b[k + j * ldb]; + } + mat_c[i * ldc + j] += sum; + } + } +} + +// mat_c = alpha*op( mat_a )*op( mat_b ) + beta*C +// M - number of rows of matrix a +// N - number of cols of matrix b +// K - number of cols of matrix a + +void gemm(int transpose_a, int transpose_b, int M, int N, int K, float alpha, float *mat_a, int lda, float *mat_b, + int ldb, float beta, float *mat_c, int ldc) { + // printf("cpu: %d %d %d %d %d %f %d %d %f %d\n",TA, TB, M, N, K, ALPHA, lda, ldb, BETA, ldc); + if (beta >= 0.f && beta <= 0.f) { + for (int i = 0; i < M; ++i) { + for (int j = 0; j < N; ++j) { + mat_c[i * ldc + j] = 0; + } + } + } else if (beta < 1.f || beta > 1.f) { + for (int i = 0; i < M; ++i) { + for (int j = 0; j < N; ++j) { + mat_c[i * ldc + j] *= beta; + } + } + } + + int t; + + for (t = 0; t < M; ++t) { + if (!transpose_a && !transpose_b) { + gemm_nn(1, N, K, alpha, mat_a + t * lda, lda, mat_b, ldb, mat_c + t * ldc, ldc); + } else if (transpose_a && !transpose_b) { + gemm_tn(1, N, K, alpha, mat_a + t, lda, mat_b, ldb, mat_c + t * ldc, ldc); + } else if (!transpose_a && transpose_b) { + gemm_nt(1, N, K, alpha, mat_a + t * lda, lda, mat_b, ldb, mat_c + t * ldc, ldc); + } else { + gemm_tt(1, N, K, alpha, mat_a + t, lda, mat_b, ldb, mat_c + t * ldc, ldc); + } + } +} diff --git a/mindspore/lite/src/runtime/kernel/arm/opclib/fp32/gemm.h b/mindspore/lite/src/runtime/kernel/arm/opclib/fp32/gemm.h new file mode 100644 index 0000000000..8caf05755f --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/opclib/fp32/gemm.h @@ -0,0 +1,23 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_OPCLIB_FP32_GEMM_H_ +#define MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_OPCLIB_FP32_GEMM_H_ + +void gemm(int transpose_a, int transpose_b, int M, int N, int K, float alpha, float *mat_a, int lda, float *mat_b, + int ldb, float beta, float *mat_c, int ldc); + +#endif // MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_OPCLIB_FP32_GEMM_H_ diff --git a/mindspore/lite/src/runtime/kernel/arm/opclib/fp32/pooling_grad.cc b/mindspore/lite/src/runtime/kernel/arm/opclib/fp32/pooling_grad.cc new file mode 100644 index 0000000000..2730cbe95d --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/opclib/fp32/pooling_grad.cc @@ -0,0 +1,149 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include "src/runtime/kernel/arm/opclib/fp32/pooling_grad.h" + +void AvgPoolingGrad(const float *input_ptr, float *output_ptr, PoolingParameter *pooling_param) { + int stride_w = pooling_param->stride_w_; + int stride_h = pooling_param->stride_h_; + int pad_w = pooling_param->pad_l_; + int pad_h = pooling_param->pad_u_; + int win_w = pooling_param->window_w_; + int win_h = pooling_param->window_h_; + int channel = pooling_param->input_channel_; + int in_w = pooling_param->input_w_; + int in_h = pooling_param->input_h_; + int output_w = pooling_param->output_w_; + int output_h = pooling_param->output_h_; + int output_batch = pooling_param->output_batch_; + + const float *inPtr; + for (int i = 0; i < output_h * output_w * channel * output_batch; i++) output_ptr[i] = 0.0; + + // int pad_top = padding[2]; + + float kk = static_cast(win_h * win_w); + + for (uint16_t ib = 0; ib < output_batch; ib++) { + // int in_batch_offset = batch * in_h * in_w * channel; + // int out_batch_offset = batch * output_h * output_w * channel; + // out = grads->getData(ib*grads->imgSize()); + // inPtr = in->getData(ib*in->imgSize()); + float *out; + out = &output_ptr[(ib * output_h * output_w)]; + inPtr = reinterpret_cast(&input_ptr[(ib * in_h * in_w)]); + if (1) { // in->layout() == Tensor::nhwc) + // iterate over yt + for (uint16_t yh = 0; yh < in_h; yh++) { + for (uint16_t yw = 0; yw < in_w; yw++) { + for (uint16_t ic = 0; ic < channel; ic++) { + int idx = (yw + yh * in_w) * channel + ic; // (ic*in_h*in_w) + (in_w*yh) + yw; + float delta = inPtr[idx] / kk; + for (int32_t kh = 0; kh < win_h; kh++) { + int xh = yh * stride_h + kh - pad_h; + if ((xh < 0) || (xh >= output_h)) { + continue; + } + for (int32_t kw = 0; kw < win_w; kw++) { + int xw = yw * stride_w + kw - pad_w; + if ((xw < 0) || (xw >= output_w)) { + continue; + } + // out[(ic*output_h*output_w) + (xh*output_w) + xw] += delta; + out[(xw + output_w * xh) * channel + ic] += delta; + } + } + } + } + } + } else { // nchw + for (uint16_t ic = 0; ic < channel; ic++) { + // iterate over yt + for (uint16_t yh = 0; yh < in_h; yh++) { + for (uint16_t yw = 0; yw < in_w; yw++) { + int idx = (ic * in_h * in_w) + (in_w * yh) + yw; + float delta = inPtr[idx] / kk; + for (int32_t kh = 0; kh < win_h; kh++) { + int xh = yh * stride_h + kh - pad_h; + if ((xh < 0) || (xh >= output_h)) { + continue; + } + for (int32_t kw = 0; kw < win_w; kw++) { + int xw = yw * stride_w + kw - pad_w; + if ((xw < 0) || (xw >= output_w)) { + continue; + } + out[(ic * output_h * output_w) + (xh * output_w) + xw] += delta; + } + } + } + } + } + } + } +} + +void MaxPoolingGrad(const float *dy, const int *indices, float *output_ptr, PoolingParameter *pooling_param) { + // int stride_w = pooling_param->stride_w_; + // int stride_h = pooling_param->stride_h_; + // int pad_w = pooling_param->pad_l_; + // int pad_h = pooling_param->pad_u_; + // int win_w = pooling_param->window_w_; + // int win_h = pooling_param->window_h_; + int channel = pooling_param->input_channel_; + int in_w = pooling_param->input_w_; + int in_h = pooling_param->input_h_; + int output_w = pooling_param->output_w_; + int output_h = pooling_param->output_h_; + int output_batch = pooling_param->output_batch_; + + int out_img_size = + output_h * output_w; // Emir -- in original code this varible is calculated according to input size ?? + int ind_img_size = in_h * in_w; + // const int w_pad = (output_w + pad_w + pad_w); + + for (int i = 0; i < output_h * output_w * channel * output_batch; i++) output_ptr[i] = 0.0; + + const float *yt = reinterpret_cast(dy); + const int *pos = reinterpret_cast(indices); + float *out; + + if (1) { // grads->layout() == Tensor::nhwc) + for (int ib = 0; ib < output_batch; ib++) { + out = &(output_ptr[ib * output_w * output_w * channel]); + for (int ix = 0; ix < ind_img_size; ix++) { + for (int cix = 0; cix < channel; cix++) { + int idx = (*pos) * channel + cix; + out[idx] += *yt; + pos++; + yt++; + } + } + } + } else { + for (int ib = 0; ib < output_batch; ib++) { + out = &output_ptr[(ib * out_img_size)]; + for (int cix = 0; cix < channel; cix++) { + for (int ix = 0; ix < ind_img_size; ix++) { + int idx = cix * output_h * output_w + *pos; // cord_y*output_w + cord_x; + out[idx] += *yt; + pos++; + yt++; + } + } + } + } +} diff --git a/mindspore/lite/src/runtime/kernel/arm/opclib/fp32/pooling_grad.h b/mindspore/lite/src/runtime/kernel/arm/opclib/fp32/pooling_grad.h new file mode 100644 index 0000000000..750530d767 --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/opclib/fp32/pooling_grad.h @@ -0,0 +1,25 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_OPCLIB_FP32_POOLING_GRAD_H_ +#define MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_OPCLIB_FP32_POOLING_GRAD_H_ + +#include "src/runtime/kernel/arm/opclib/fp32/pooling.h" + +void AvgPoolingGrad(const float *input_ptr, float *output_ptr, PoolingParameter *pooling_param); +void MaxPoolingGrad(const float *dy, const int *indices_ptr, float *output_ptr, PoolingParameter *pooling_param); + +#endif // MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_OPCLIB_FP32_POOLING_GRAD_H_ diff --git a/mindspore/lite/src/runtime/kernel/arm/opclib/fp32/reduce_grad.cc b/mindspore/lite/src/runtime/kernel/arm/opclib/fp32/reduce_grad.cc new file mode 100644 index 0000000000..24e7189b3e --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/opclib/fp32/reduce_grad.cc @@ -0,0 +1,130 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include "mindspore/lite/src/runtime/kernel/arm/opclib/fp32/reduce_grad.h" + +static inline bool NextIndex(const int num_dims, const int *dims, int *current) { + int carry = 1; + for (int idx = num_dims - 1; idx >= 0; --idx) { + int current_val = current[idx] + carry; + if (dims[idx] == current_val) { + current[idx] = 0; + } else { + current[idx] = current_val; + carry = 0; + break; + } + } + return (carry == 0); +} + +static inline size_t GetInputOffset(const int num_dims, const int *dims, const int *iter) { + size_t offset = 0; + for (int idx = 0; idx < num_dims; ++idx) { + offset = offset * (size_t)(dims[idx]) + (size_t)(iter[idx]); + } + + return offset; +} + +static inline size_t GetOutputOffset(const int num_dims, const int *dims, const int *iter, const int num_axis, + const int *axes) { + size_t offset = 0; + for (int idx = 0; idx < num_dims; ++idx) { + // if we need to skip this axis + bool is_axis = false; + for (int axis_idx = 0; axis_idx < num_axis; ++axis_idx) { + if (idx == axes[axis_idx]) { + is_axis = true; + break; + } + } + + if (!is_axis) { + offset = offset * (size_t)(dims[idx]) + (size_t)(iter[idx]); + } + } + return offset; +} + +void ReduceMeanByAxes(const float *input_data, int *input_iter, const int *input_dims, int input_num_dims, + const int *axes, int num_axes, float *output_data, const int *output_dims, int output_num_dims) { + size_t num_outputs = 1; + for (int idx = 0; idx < output_num_dims; ++idx) { + size_t current = (size_t)(output_dims[idx]); + num_outputs *= current; + } + + // Reset input iterator. + for (int idx = 0; idx < input_num_dims; ++idx) { + input_iter[idx] = 0; + } + // Iterate through input_data. + do { + size_t input_offset = GetInputOffset(input_num_dims, input_dims, input_iter); + size_t output_offset = GetOutputOffset(input_num_dims, input_dims, input_iter, num_axes, axes); + output_data[output_offset] += input_data[input_offset]; + } while (NextIndex(input_num_dims, input_dims, input_iter)); + + // Calculate mean by dividing output_data by num of aggregated element. + size_t num_elements_in_axis = 1; + for (int idx = 0; idx < num_axes; ++idx) { + size_t current = (size_t)(input_dims[axes[idx]]); + num_elements_in_axis *= current; + } + + for (size_t idx = 0; idx < num_outputs; ++idx) { + output_data[idx] = output_data[idx] / static_cast(num_elements_in_axis); + } +} + +float ReduceMeanAll(const float *src, int size) { + float sum = 0; + for (int i = 0; i < size; ++i) { + sum += src[i]; + } + return sum / size; +} + +void ReduceSumByAxes(const float *input, const int *input_dims, float *output, const int *output_dims, int num_dims) { + int num_outputs = 1; + int same_shape = true; + for (int idx = 0; idx < num_dims; ++idx) { + num_outputs *= output_dims[idx]; + if (output_dims[idx] != input_dims[idx]) same_shape = false; + } + if (same_shape) { + std::copy(input, input + num_outputs * sizeof(float), output); + // memcpy(output, input, num_outputs*sizeof(float)); + return; + } + + for (int idx = 0; idx < num_outputs; ++idx) output[idx] = 0; // zero output + + int input_iter[8] = {0}; + int axes[5] = {0}; + int num_axes = 0; + for (int i = 0; i < num_dims; i++) + if (output_dims[i] == 1) axes[num_axes++] = i; + + // Iterate through input_data. + do { + size_t input_offset = GetInputOffset(num_dims, input_dims, input_iter); + size_t output_offset = GetOutputOffset(num_dims, input_dims, input_iter, num_axes, axes); + output[output_offset] += input[input_offset]; + } while (NextIndex(num_dims, input_dims, input_iter)); +} diff --git a/mindspore/lite/src/runtime/kernel/arm/opclib/fp32/reduce_grad.h b/mindspore/lite/src/runtime/kernel/arm/opclib/fp32/reduce_grad.h new file mode 100644 index 0000000000..7645817135 --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/opclib/fp32/reduce_grad.h @@ -0,0 +1,24 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_OPCLIB_FP32_REDUCE_GRAD_H_ +#define MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_OPCLIB_FP32_REDUCE_GRAD_H_ + +float ReduceMeanAll(const float *src, int size); +void ReduceSumByAxes(const float *input, const int *input_dims, float *output, const int *output_dims, int num_dims); + +#endif // MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_OPCLIB_FP32_REDUCE_GRAD_H_ + diff --git a/mindspore/lite/src/runtime/kernel/arm/opclib/fp32/softmax_grad.h b/mindspore/lite/src/runtime/kernel/arm/opclib/fp32/softmax_grad.h new file mode 100644 index 0000000000..6fb7fc1580 --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/opclib/fp32/softmax_grad.h @@ -0,0 +1,29 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_OPCLIB_FP32_SOFTMAX_GRAD_H_ +#define MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_OPCLIB_FP32_SOFTMAX_GRAD_H_ + +#include "src/runtime/kernel/arm/opclib/op_base.h" + +struct SoftmaxCrossEntropyParameter { + OpParameter op_parameter; + int32_t batch_size_; + unsigned int number_of_classes_; + int n_dim_; + int input_shape_[5]; +}; +#endif // MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_OPCLIB_FP32_SOFTMAX_GRAD_H_ diff --git a/mindspore/lite/src/runtime/kernel/arm/opclib/pack_ext.cc b/mindspore/lite/src/runtime/kernel/arm/opclib/pack_ext.cc new file mode 100644 index 0000000000..bb6cd1ce6b --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/opclib/pack_ext.cc @@ -0,0 +1,176 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "src/runtime/kernel/arm/opclib/pack_ext.h" + +static int is_a_ge_zero_and_a_lt_b(int a, int b) { return (unsigned)(a) < (unsigned)(b); } + +void im2col_hwc(const float *in_data, float *data_col, ConvParameter *conv_param) { + const int pad_left = /*conv_param->pad_l_*/ conv_param->pad_w_; + // const int pad_right = /*conv_param->pad_r_*/conv_param->pad_w_; + const int pad_up = /*conv_param->pad_u_*/ conv_param->pad_h_; + // const int pad_down = /*conv_param->pad_d/*/conv_param->pad_h_; + + const int stride_h = conv_param->stride_h_; + const int stride_w = conv_param->stride_w_; + + const int dilation_h = conv_param->dilation_h_; + const int dilation_w = conv_param->dilation_w_; + + const int kernel_h = conv_param->kernel_h_; + const int kernel_w = conv_param->kernel_w_; + + const int in_height = conv_param->input_h_; + const int in_width = conv_param->input_w_; + + const int output_h = conv_param->output_h_; + const int output_w = conv_param->output_w_; + const int channels = conv_param->input_channel_ / conv_param->group_; + const int tot_channels = conv_param->input_channel_; + + int /*channel,*/ kernel_row, kernel_col, output_rows, output_col; + + int row_stride_offset = 0; + + for (output_rows = output_h; output_rows; output_rows--) { + int col_stride_offset = 0; + for (output_col = output_w; output_col; output_col--) { + for (kernel_row = 0; kernel_row < kernel_h; kernel_row++) { + int input_row = -pad_up + kernel_row * dilation_h + row_stride_offset; + for (kernel_col = 0; kernel_col < kernel_w; kernel_col++) { + int input_col = -pad_left + kernel_col * dilation_w + col_stride_offset; + + if (is_a_ge_zero_and_a_lt_b(input_row, in_height) && is_a_ge_zero_and_a_lt_b(input_col, in_width)) { + const int offset = (input_row * in_width + input_col) * tot_channels; + memcpy(data_col, in_data + offset, sizeof(float) * channels); + data_col += channels; + } else { + memset(data_col, 0, sizeof(float) * channels); + data_col += channels; + } + } + } + col_stride_offset += stride_w; + } + row_stride_offset += stride_h; + } +} + +// output matrix is (kernel_h*kernel_w*channels)X(output_h*output_w) +void im2row_hwc(const float *in_data, float *data_row, ConvParameter *conv_param) { + const int pad_left = /*conv_param->pad_l_*/ conv_param->pad_w_; + // const int pad_right = /*conv_param->pad_r_*/conv_param->pad_w_; + const int pad_up = /*conv_param->pad_u_*/ conv_param->pad_h_; + // const int pad_down = /*conv_param->pad_d/*/conv_param->pad_h_; + + const int stride_h = conv_param->stride_h_; + const int stride_w = conv_param->stride_w_; + + const int dilation_h = conv_param->dilation_h_; + const int dilation_w = conv_param->dilation_w_; + + const int kernel_h = conv_param->kernel_h_; + const int kernel_w = conv_param->kernel_w_; + + const int in_height = conv_param->input_h_; + const int in_width = conv_param->input_w_; + + const int output_h = conv_param->output_h_; + const int output_w = conv_param->output_w_; + const int channels = conv_param->input_channel_ / conv_param->group_; + const int tot_channels = conv_param->input_channel_; + + int channel, kernel_row, kernel_col, output_rows, output_col; + + for (kernel_row = 0; kernel_row < kernel_h; kernel_row++) { + for (kernel_col = 0; kernel_col < kernel_w; kernel_col++) { + for (channel = 0; channel < channels; channel++) { + int input_row = -pad_up + kernel_row * dilation_h; + for (output_rows = output_h; output_rows; output_rows--) { + if (!is_a_ge_zero_and_a_lt_b(input_row, in_height)) { + for (output_col = output_w; output_col; output_col--) { + *(data_row++) = 0; + } + } else { + int input_col = -pad_left + kernel_col * dilation_w; + for (output_col = output_w; output_col; output_col--) { + if (is_a_ge_zero_and_a_lt_b(input_col, in_width)) { + const int offset = (input_row * in_width + input_col) * tot_channels + channel; + *(data_row++) = in_data[offset]; + } else { + *(data_row++) = 0; + } + input_col += stride_w; + } + } + input_row += stride_h; + } + } + } + } +} + +void col2im_hwc(const float *data_col, float *data_im, ConvParameter *conv_param) { + const int pad_left = /*conv_param->pad_l_*/ conv_param->pad_w_; + // const int pad_right = /*conv_param->pad_r_*/conv_param->pad_w_; + const int pad_up = /*conv_param->pad_u_*/ conv_param->pad_h_; + // const int pad_down = /*conv_param->pad_d/*/conv_param->pad_h_; + + const int stride_h = conv_param->stride_h_; + const int stride_w = conv_param->stride_w_; + + const int dilation_h = conv_param->dilation_h_; + const int dilation_w = conv_param->dilation_w_; + + const int kernel_h = conv_param->kernel_h_; + const int kernel_w = conv_param->kernel_w_; + + const int in_height = conv_param->input_h_; + const int in_width = conv_param->input_w_; + + const int output_h = conv_param->output_h_; + const int output_w = conv_param->output_w_; + const int channels = conv_param->input_channel_ / conv_param->group_; + const int tot_channels = conv_param->input_channel_; + + int kernel_row, kernel_col, output_rows, output_col; + + int row_stride_offset = 0; + + for (output_rows = output_h; output_rows; output_rows--) { + int col_stride_offset = 0; + for (output_col = output_w; output_col; output_col--) { + for (kernel_row = 0; kernel_row < kernel_h; kernel_row++) { + int input_row = -pad_up + kernel_row * dilation_h + row_stride_offset; + for (kernel_col = 0; kernel_col < kernel_w; kernel_col++) { + int input_col = -pad_left + kernel_col * dilation_w + col_stride_offset; + + if (is_a_ge_zero_and_a_lt_b(input_row, in_height) && is_a_ge_zero_and_a_lt_b(input_col, in_width)) { + int offset = (input_row * in_width + input_col) * tot_channels; + float *data_im_ptr = &data_im[offset]; + for (int i = 0; i < channels; i++) { + data_im_ptr[i] += data_col[i]; + } + } + data_col += channels; + } + } + col_stride_offset += stride_w; + } + row_stride_offset += stride_h; + } +} diff --git a/mindspore/lite/src/runtime/kernel/arm/opclib/pack_ext.h b/mindspore/lite/src/runtime/kernel/arm/opclib/pack_ext.h new file mode 100644 index 0000000000..3f51aae13d --- /dev/null +++ b/mindspore/lite/src/runtime/kernel/arm/opclib/pack_ext.h @@ -0,0 +1,26 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_OPCLIB_PACK_EXT_H_ +#define MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_OPCLIB_PACK_EXT_H_ + +#include "src/runtime/kernel/arm/opclib/conv_parameter.h" + +void im2col_hwc(const float *in_data, float *data_col, ConvParameter *conv_param); +void im2row_hwc(const float *in_data, float *data_row, ConvParameter *conv_param); +void col2im_hwc(const float *data_col, float *data_im, ConvParameter *conv_param); + +#endif // MINDSPORE_LITE_SRC_RUNTIME_KERNEL_ARM_OPCLIB_PACK_EXT_H diff --git a/mindspore/lite/test/CMakeLists.txt b/mindspore/lite/test/CMakeLists.txt index ad0ef96195..0bfa4b1dbd 100644 --- a/mindspore/lite/test/CMakeLists.txt +++ b/mindspore/lite/test/CMakeLists.txt @@ -152,6 +152,7 @@ set(TEST_LITE_SRC ${LITE_DIR}/src/scheduler.cc ${LITE_DIR}/src/common/graph_util.cc ${LITE_DIR}/src/common/file_utils.cc + ${LITE_DIR}/src/common/file_utils_ext.cc ${LITE_DIR}/src/common/utils.cc ${LITE_DIR}/tools/common/graph_util.cc ${LITE_DIR}/tools/common/tensor_util.cc diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/fp32/activation_grad_fp32_tests.cc b/mindspore/lite/test/ut/src/runtime/kernel/arm/fp32/activation_grad_fp32_tests.cc new file mode 100644 index 0000000000..1badd29a26 --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/fp32/activation_grad_fp32_tests.cc @@ -0,0 +1,312 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include "utils/log_adapter.h" +#include "common/common_test.h" +#include "src/common/file_utils.h" +#include "src/common/file_utils_ext.h" +#include "mindspore/lite/src/kernel_registry.h" +#include "mindspore/lite/src/ir/tensor.h" +#include "mindspore/lite/src/lite_kernel.h" +#include "mindspore/lite/src/runtime/kernel/arm/fp32/activation_grad.h" + +namespace mindspore { +class TestActGradFp32 : public mindspore::Common { + public: + TestActGradFp32() {} +}; + +TEST_F(TestActGradFp32, ReluGradFp32) { + // runtime part + printf("Calculating runtime cost...\n"); + uint64_t time_avg = 0; + size_t output_data_size = 50; + + size_t input_size; + std::string input_path = "./test_data/activationGrad/relu_y_50.bin"; + auto input_data = reinterpret_cast(mindspore::lite::ReadFile(input_path.c_str(), &input_size)); + std::string yt_path = "./test_data/activationGrad/relu_yt_50.bin"; + auto yt_data = reinterpret_cast(mindspore::lite::ReadFile(yt_path.c_str(), &input_size)); + + auto output_data = new float[output_data_size]; + // warm up loop + for (int i = 0; i < 3; i++) { + ReluGrad(yt_data, input_data, 50, output_data); + } + + int loop_count = 100; + auto time_start = mindspore::lite::GetTimeUs(); + for (int i = 0; i < loop_count; i++) { + ReluGrad(yt_data, input_data, 50, output_data); + } + auto time_end = mindspore::lite::GetTimeUs(); + auto cost = time_end - time_start; + time_avg = cost / loop_count; + printf("single thread running time : %f ms\n", time_avg / 1000.0f); + + printf("==================output data=================\n"); + for (int i = 0; i < 20; i++) { + std::cout << output_data[i] << " ,"; + } + std::cout << std::endl; + + std::string output_path = "./test_data/activationGrad/relu_out_50.bin"; + + int res = lite::CompareRelativeOutput(output_data, output_path); + + EXPECT_EQ(res, 0); + + delete input_data; + delete[] output_data; + delete yt_data; + + MS_LOG(INFO) << "ReluGradFp32 passed"; +} + +TEST_F(TestActGradFp32, Relu6GradFp32) { + // runtime part + printf("Calculating runtime cost...\n"); + uint64_t time_avg = 0; + size_t output_data_size = 50; + + size_t input_size; + std::string input_path = "./test_data/activationGrad/relu6_y_50.bin"; + auto input_data = reinterpret_cast(mindspore::lite::ReadFile(input_path.c_str(), &input_size)); + std::string yt_path = "./test_data/activationGrad/relu6_yt_50.bin"; + auto yt_data = reinterpret_cast(mindspore::lite::ReadFile(yt_path.c_str(), &input_size)); + + auto output_data = new float[output_data_size]; + // warm up loop + for (int i = 0; i < 3; i++) { + Relu6Grad(yt_data, input_data, 50, output_data); + } + + int loop_count = 100; + auto time_start = mindspore::lite::GetTimeUs(); + for (int i = 0; i < loop_count; i++) { + Relu6Grad(yt_data, input_data, 50, output_data); + } + auto time_end = mindspore::lite::GetTimeUs(); + auto cost = time_end - time_start; + time_avg = cost / loop_count; + printf("single thread running time : %f ms\n", time_avg / 1000.0f); + + printf("==================output data=================\n"); + for (int i = 0; i < 20; i++) { + std::cout << output_data[i] << " ,"; + } + std::cout << std::endl; + + std::string output_path = "./test_data/activationGrad/relu6_out_50.bin"; + int res = lite::CompareRelativeOutput(output_data, output_path); + + EXPECT_EQ(res, 0); + + delete input_data; + delete[] output_data; + delete yt_data; + + MS_LOG(INFO) << "Relu6GradFp32 passed"; +} + +TEST_F(TestActGradFp32, LReluGradFp32) { + // runtime part + printf("Calculating runtime cost...\n"); + uint64_t time_avg = 0; + size_t output_data_size = 50; + + size_t input_size; + std::string input_path = "./test_data/activationGrad/lrelu_y_50.bin"; + auto input_data = reinterpret_cast(mindspore::lite::ReadFile(input_path.c_str(), &input_size)); + std::string yt_path = "./test_data/activationGrad/lrelu_yt_50.bin"; + auto yt_data = reinterpret_cast(mindspore::lite::ReadFile(yt_path.c_str(), &input_size)); + + auto output_data = new float[output_data_size]; + // warm up loop + for (int i = 0; i < 3; i++) { + LReluGrad(yt_data, input_data, 50, output_data, 0.1); + } + + int loop_count = 100; + auto time_start = mindspore::lite::GetTimeUs(); + for (int i = 0; i < loop_count; i++) { + LReluGrad(yt_data, input_data, 50, output_data, 0.1); + } + auto time_end = mindspore::lite::GetTimeUs(); + auto cost = time_end - time_start; + time_avg = cost / loop_count; + printf("single thread running time : %f ms\n", time_avg / 1000.0f); + + printf("==================output data=================\n"); + for (int i = 0; i < 20; i++) { + std::cout << output_data[i] << " ,"; + } + std::cout << std::endl; + + std::string output_path = "./test_data/activationGrad/lrelu_out_50.bin"; + int res = lite::CompareRelativeOutput(output_data, output_path); + + EXPECT_EQ(res, 0); + + delete input_data; + delete[] output_data; + delete yt_data; + + MS_LOG(INFO) << "LReluGradFp32 passed"; +} + +TEST_F(TestActGradFp32, SigmoidGradFp32) { + // runtime part + printf("Calculating runtime cost...\n"); + uint64_t time_avg = 0; + size_t output_data_size = 50; + + size_t input_size; + std::string input_path = "./test_data/activationGrad/sigmoid_y_50.bin"; + auto input_data = reinterpret_cast(mindspore::lite::ReadFile(input_path.c_str(), &input_size)); + std::string yt_path = "./test_data/activationGrad/sigmoid_yt_50.bin"; + auto yt_data = reinterpret_cast(mindspore::lite::ReadFile(yt_path.c_str(), &input_size)); + + auto output_data = new float[output_data_size]; + // warm up loop + for (int i = 0; i < 3; i++) { + SigmoidGrad(yt_data, input_data, 50, output_data); + } + + int loop_count = 100; + auto time_start = mindspore::lite::GetTimeUs(); + for (int i = 0; i < loop_count; i++) { + SigmoidGrad(yt_data, input_data, 50, output_data); + } + auto time_end = mindspore::lite::GetTimeUs(); + auto cost = time_end - time_start; + time_avg = cost / loop_count; + printf("single thread running time : %f ms\n", time_avg / 1000.0f); + + printf("==================output data=================\n"); + for (int i = 0; i < 20; i++) { + std::cout << output_data[i] << " ,"; + } + std::cout << std::endl; + + std::string output_path = "./test_data/activationGrad/sigmoid_out_50.bin"; + int res = lite::CompareRelativeOutput(output_data, output_path); + + EXPECT_EQ(res, 0); + // lite::CompareOutput(output_data, output_path); + + delete input_data; + delete[] output_data; + delete yt_data; + + MS_LOG(INFO) << "SigmoidGradFp32 passed"; +} + +TEST_F(TestActGradFp32, tanhGradFp32) { + // runtime part + printf("Calculating runtime cost...\n"); + uint64_t time_avg = 0; + size_t output_data_size = 50; + + size_t input_size; + std::string input_path = "./test_data/activationGrad/tanh_y_50.bin"; + auto input_data = reinterpret_cast(mindspore::lite::ReadFile(input_path.c_str(), &input_size)); + std::string yt_path = "./test_data/activationGrad/tanh_yt_50.bin"; + auto yt_data = reinterpret_cast(mindspore::lite::ReadFile(yt_path.c_str(), &input_size)); + + auto output_data = new float[output_data_size]; + // warm up loop + for (int i = 0; i < 3; i++) { + TanhGrad(yt_data, input_data, 50, output_data); + } + + int loop_count = 100; + auto time_start = mindspore::lite::GetTimeUs(); + for (int i = 0; i < loop_count; i++) { + TanhGrad(yt_data, input_data, 50, output_data); + } + auto time_end = mindspore::lite::GetTimeUs(); + auto cost = time_end - time_start; + time_avg = cost / loop_count; + printf("single thread running time : %f ms\n", time_avg / 1000.0f); + + printf("==================output data=================\n"); + for (int i = 0; i < 20; i++) { + std::cout << output_data[i] << " ,"; + } + std::cout << std::endl; + + std::string output_path = "./test_data/activationGrad/tanh_out_50.bin"; + int res = lite::CompareRelativeOutput(output_data, output_path); + + EXPECT_EQ(res, 0); + + delete input_data; + delete[] output_data; + delete yt_data; + MS_LOG(INFO) << "TanhGradFp32 passed"; +} + +TEST_F(TestActGradFp32, hswishGradFp32) { + // runtime part + printf("Calculating runtime cost...\n"); + uint64_t time_avg = 0; + size_t output_data_size = 50; + + size_t input_size; + std::string input_path = "./test_data/activationGrad/hswish_x_50.bin"; + auto input_data = reinterpret_cast(mindspore::lite::ReadFile(input_path.c_str(), &input_size)); + std::string yt_path = "./test_data/activationGrad/hswish_yt_50.bin"; + auto yt_data = reinterpret_cast(mindspore::lite::ReadFile(yt_path.c_str(), &input_size)); + + auto output_data = new float[output_data_size]; + // warm up loop + for (int i = 0; i < 3; i++) { + HSwishGrad(yt_data, input_data, 50, output_data); + } + + int loop_count = 100; + auto time_start = mindspore::lite::GetTimeUs(); + for (int i = 0; i < loop_count; i++) { + HSwishGrad(yt_data, input_data, 50, output_data); + } + auto time_end = mindspore::lite::GetTimeUs(); + auto cost = time_end - time_start; + time_avg = cost / loop_count; + printf("single thread running time : %f ms\n", time_avg / 1000.0f); + + printf("==================output data=================\n"); + for (int i = 0; i < 20; i++) { + std::cout << output_data[i] << " ,"; + } + std::cout << std::endl; + + std::string output_path = "./test_data/activationGrad/hswish_out_50.bin"; + int res = lite::CompareRelativeOutput(output_data, output_path); + + EXPECT_EQ(res, 0); + + delete input_data; + delete[] output_data; + delete yt_data; + MS_LOG(INFO) << "hswishGradFp32 passed"; +} + +} // namespace mindspore diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/fp32/arithmetic_grad_fp32_tests.cc b/mindspore/lite/test/ut/src/runtime/kernel/arm/fp32/arithmetic_grad_fp32_tests.cc new file mode 100644 index 0000000000..48d5c93e56 --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/fp32/arithmetic_grad_fp32_tests.cc @@ -0,0 +1,497 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include +#include "utils/log_adapter.h" +#include "common/common_test.h" +#include "src/common/file_utils.h" +#include "src/common/file_utils_ext.h" +#include "mindspore/lite/src/runtime/kernel/arm/opclib/fp32/reduce.h" +#include "mindspore/lite/src/runtime/kernel/arm/fp32/arithmetic_grad.h" +#include "mindspore/lite/src/kernel_registry.h" + +namespace mindspore { + +class TestArithmeticGradFp32 : public mindspore::Common { + public: + TestArithmeticGradFp32() {} +}; + +std::vector GenerateTensorsForTest(const char *test, int test_id) { + size_t input_size; + std::vector large_dim({4, 6}); + std::vector small_dim({6}); + int large_size = (4 * 6); + int small_size = (1 * 6); + char *dx1_file = const_cast("./test_data/operators/arithmetic_fp32_1_x1_4_6.bin"); + char *dx2_file = const_cast("./test_data/operators/arithmetic_fp32_1_x2_1_6.bin"); + + if (test_id == 7) { + large_dim = std::vector({4, 5, 6}); + small_dim = std::vector({6}); + large_size = (4 * 5 * 6); + small_size = (6); + dx1_file = const_cast("./test_data/operators/arithmetic_fp32_7_x1_4_5_6.bin"); + dx2_file = const_cast("./test_data/operators/arithmetic_fp32_7_x2_1_1_6.bin"); + } + if (test_id >= 8) { + large_dim = std::vector({5, 4, 6}); + small_dim = std::vector({5, 1, 6}); + large_size = (4 * 5 * 6); + small_size = (5 * 6); + dx1_file = const_cast("./test_data/operators/arithmetic_fp32_8_x1_5_4_6.bin"); + dx2_file = const_cast("./test_data/operators/arithmetic_fp32_8_x2_5_1_6.bin"); + } + + auto dy_data = reinterpret_cast(mindspore::lite::ReadFile(test, &input_size)); + lite::tensor::Tensor *dy_tensor = new lite::tensor::Tensor(TypeId::kNumberTypeFloat32, large_dim); + dy_tensor->SetData(dy_data); + + auto x1_data = reinterpret_cast(mindspore::lite::ReadFile(dx1_file, &input_size)); + lite::tensor::Tensor *x1_tensor = new lite::tensor::Tensor(TypeId::kNumberTypeFloat32, large_dim); + x1_tensor->SetData(x1_data); + + auto x2_data = reinterpret_cast(mindspore::lite::ReadFile(dx2_file, &input_size)); + lite::tensor::Tensor *x2_tensor = new lite::tensor::Tensor(TypeId::kNumberTypeFloat32, small_dim); + x2_tensor->SetData(x2_data); + + auto dx1_data = new float[large_size]; + lite::tensor::Tensor *dx1_tensor = new lite::tensor::Tensor(TypeId::kNumberTypeFloat32, large_dim); + dx1_tensor->SetData(dx1_data); + + auto dx2_data = new float[small_size]; + lite::tensor::Tensor *dx2_tensor = new lite::tensor::Tensor(TypeId::kNumberTypeFloat32, small_dim); + dx2_tensor->SetData(dx2_data); + + std::vector ret_vector = {dy_tensor, x1_tensor, x2_tensor, dx1_tensor, dx2_tensor}; + return ret_vector; +} + +TEST_F(TestArithmeticGradFp32, TestAddGradFp32) { + auto param = new ArithmeticParameter(); + param->op_parameter_.type_ = PrimitiveType_AddGrad; + std::vector all_tensors = + GenerateTensorsForTest("./test_data/operators/arithmetic_fp32_1_dy_4_6.bin", 1); + + std::vector inputs = {all_tensors[0], all_tensors[1], all_tensors[2]}; + std::vector outputs = {all_tensors[3], all_tensors[4]}; + kernel::KernelKey desc = {kernel::kCPU, TypeId::kNumberTypeFloat32, schema::PrimitiveType_AddGrad}; + auto creator = lite::KernelRegistry::GetInstance()->GetCreator(desc); + auto kernel_obj = creator(inputs, outputs, reinterpret_cast(param), NULL, desc); + kernel_obj->Run(); + + float *output_ptr = reinterpret_cast(outputs[1]->Data()); + printf("==================output data=================\n"); + for (int i = 0; i < 6; i++) { + std::cout << output_ptr[i] << " ,"; + } + std::cout << std::endl; + + std::string output_path = "./test_data/operators/arithmetic_fp32_1_dx1_4_6.bin"; + EXPECT_EQ(0, lite::CompareRelativeOutput(reinterpret_cast(outputs[0]->Data()), output_path)); + + std::string dx2_path = "./test_data/operators/arithmetic_fp32_1_dx2_1_6.bin"; + EXPECT_EQ(0, lite::CompareRelativeOutput(output_ptr, dx2_path)); + + for (int i = 0; i < 5; i++) delete all_tensors[i]; + delete param; + MS_LOG(INFO) << "TestAddGradFp32 passed"; +} + +TEST_F(TestArithmeticGradFp32, TestAddGrad2Fp32) { + auto param = new ArithmeticParameter(); + param->op_parameter_.type_ = PrimitiveType_AddGrad; + std::vector all_tensors = + GenerateTensorsForTest("./test_data/operators/arithmetic_fp32_1_dy_4_6.bin", 1); + + std::vector inputs = {all_tensors[0], all_tensors[2], all_tensors[1]}; + std::vector outputs = {all_tensors[4], all_tensors[3]}; + kernel::KernelKey desc = {kernel::kCPU, TypeId::kNumberTypeFloat32, schema::PrimitiveType_AddGrad}; + auto creator = lite::KernelRegistry::GetInstance()->GetCreator(desc); + auto kernel_obj = creator(inputs, outputs, reinterpret_cast(param), NULL, desc); + kernel_obj->Run(); + + float *output_ptr = reinterpret_cast(outputs[0]->Data()); + printf("==================output data=================\n"); + for (int i = 0; i < 6; i++) { + std::cout << output_ptr[i] << " ,"; + } + std::cout << std::endl; + + std::string output_path = "./test_data/operators/arithmetic_fp32_1_dx1_4_6.bin"; + EXPECT_EQ(0, lite::CompareRelativeOutput(reinterpret_cast(outputs[1]->Data()), output_path)); + + std::string dx2_path = "./test_data/operators/arithmetic_fp32_1_dx2_1_6.bin"; + EXPECT_EQ(0, lite::CompareRelativeOutput(output_ptr, dx2_path)); + + for (int i = 0; i < 5; i++) delete all_tensors[i]; + delete param; + MS_LOG(INFO) << "TestAddGrad2Fp32 passed"; +} + +TEST_F(TestArithmeticGradFp32, TestAddGrad3Fp32) { + auto param = new ArithmeticParameter(); + param->op_parameter_.type_ = PrimitiveType_AddGrad; + std::vector all_tensors = + GenerateTensorsForTest("./test_data/operators/arithmetic_fp32_8_dy_5_4_6.bin", 8); + + std::vector inputs = {all_tensors[0], all_tensors[1], all_tensors[2]}; + std::vector outputs = {all_tensors[3], all_tensors[4]}; + kernel::KernelKey desc = {kernel::kCPU, TypeId::kNumberTypeFloat32, schema::PrimitiveType_AddGrad}; + auto creator = lite::KernelRegistry::GetInstance()->GetCreator(desc); + auto kernel_obj = creator(inputs, outputs, reinterpret_cast(param), NULL, desc); + kernel_obj->Run(); + + float *output_ptr = reinterpret_cast(outputs[0]->Data()); + printf("==================output data=================\n"); + for (int i = 0; i < 6; i++) { + std::cout << output_ptr[i] << " ,"; + } + std::cout << std::endl; + + std::string output_path = "./test_data/operators/arithmetic_fp32_8_dx2_5_1_6.bin"; + EXPECT_EQ(0, lite::CompareRelativeOutput(reinterpret_cast(outputs[1]->Data()), output_path)); + + std::string dx2_path = "./test_data/operators/arithmetic_fp32_8_dx1_5_4_6.bin"; + EXPECT_EQ(0, lite::CompareRelativeOutput(output_ptr, dx2_path)); + + for (int i = 0; i < 5; i++) delete all_tensors[i]; + delete param; + MS_LOG(INFO) << "TestAddGrad3Fp32 passed"; +} + +TEST_F(TestArithmeticGradFp32, TestSubGradFp32) { + auto param = new ArithmeticParameter(); + param->op_parameter_.type_ = PrimitiveType_SubGrad; + std::vector all_tensors = + GenerateTensorsForTest("./test_data/operators/arithmetic_fp32_2_dy_4_6.bin", 2); + + std::vector inputs = {all_tensors[0], all_tensors[1], all_tensors[2]}; + std::vector outputs = {all_tensors[3], all_tensors[4]}; + kernel::KernelKey desc = {kernel::kCPU, TypeId::kNumberTypeFloat32, schema::PrimitiveType_SubGrad}; + auto creator = lite::KernelRegistry::GetInstance()->GetCreator(desc); + auto kernel_obj = creator(inputs, outputs, reinterpret_cast(param), NULL, desc); + kernel_obj->Run(); + + float *output_ptr = reinterpret_cast(outputs[1]->Data()); + printf("==================output data=================\n"); + for (int i = 0; i < 6; i++) { + std::cout << output_ptr[i] << " ,"; + } + std::cout << std::endl; + + std::string output_path = "./test_data/operators/arithmetic_fp32_2_dx1_4_6.bin"; + EXPECT_EQ(0, lite::CompareRelativeOutput(reinterpret_cast(outputs[0]->Data()), output_path)); + + std::string dx2_path = "./test_data/operators/arithmetic_fp32_2_dx2_1_6.bin"; + EXPECT_EQ(0, lite::CompareRelativeOutput(output_ptr, dx2_path)); + + for (int i = 0; i < 5; i++) delete all_tensors[i]; + delete param; + MS_LOG(INFO) << "TestSubGradFp32 passed"; +} + +TEST_F(TestArithmeticGradFp32, TestSubGrad2Fp32) { + auto param = new ArithmeticParameter(); + param->op_parameter_.type_ = PrimitiveType_SubGrad; + std::vector all_tensors = + GenerateTensorsForTest("./test_data/operators/arithmetic_fp32_3_dy_4_6.bin", 3); + + std::vector inputs = {all_tensors[0], all_tensors[2], all_tensors[1]}; + std::vector outputs = {all_tensors[4], all_tensors[3]}; + kernel::KernelKey desc = {kernel::kCPU, TypeId::kNumberTypeFloat32, schema::PrimitiveType_SubGrad}; + auto creator = lite::KernelRegistry::GetInstance()->GetCreator(desc); + auto kernel_obj = creator(inputs, outputs, reinterpret_cast(param), NULL, desc); + kernel_obj->Run(); + + float *output_ptr = reinterpret_cast(outputs[0]->Data()); + printf("==================output data=================\n"); + for (int i = 0; i < 6; i++) { + std::cout << output_ptr[i] << " ,"; + } + std::cout << std::endl; + + std::string output_path = "./test_data/operators/arithmetic_fp32_3_dx1_4_6.bin"; + EXPECT_EQ(0, lite::CompareRelativeOutput(reinterpret_cast(outputs[1]->Data()), output_path)); + + std::string dx2_path = "./test_data/operators/arithmetic_fp32_3_dx2_1_6.bin"; + EXPECT_EQ(0, lite::CompareRelativeOutput(output_ptr, dx2_path)); + + for (int i = 0; i < 5; i++) delete all_tensors[i]; + delete param; + MS_LOG(INFO) << "TestSubGrad2Fp32 passed"; +} + +TEST_F(TestArithmeticGradFp32, TestMulGradFp32) { + auto param = new ArithmeticParameter(); + param->op_parameter_.type_ = PrimitiveType_MulGrad; + std::vector all_tensors = + GenerateTensorsForTest("./test_data/operators/arithmetic_fp32_4_dy_4_6.bin", 4); + + std::vector inputs = {all_tensors[0], all_tensors[1], all_tensors[2]}; + std::vector outputs = {all_tensors[3], all_tensors[4]}; + kernel::KernelKey desc = {kernel::kCPU, TypeId::kNumberTypeFloat32, schema::PrimitiveType_MulGrad}; + auto creator = lite::KernelRegistry::GetInstance()->GetCreator(desc); + auto kernel_obj = creator(inputs, outputs, reinterpret_cast(param), NULL, desc); + + int loop_count = 1000; + auto time_start = mindspore::lite::GetTimeUs(); + for (int i = 0; i < loop_count; i++) { + kernel_obj->Run(); + } + auto time_end = mindspore::lite::GetTimeUs(); + auto cost = time_end - time_start; + printf("total cost (for %d loops): %lu us\n", loop_count, cost); + // auto time_avg = cost / loop_count; + // printf("single thread running time : %f ms\n", time_avg / 1000.0f); + + float *output_ptr = reinterpret_cast(outputs[1]->Data()); + printf("==================output data=================\n"); + for (int i = 0; i < 6; i++) { + std::cout << output_ptr[i] << " ,"; + } + std::cout << std::endl; + + std::string output_path = "./test_data/operators/arithmetic_fp32_4_dx1_4_6.bin"; + EXPECT_EQ(0, lite::CompareRelativeOutput(reinterpret_cast(outputs[0]->Data()), output_path)); + + std::string dx2_path = "./test_data/operators/arithmetic_fp32_4_dx2_1_6.bin"; + EXPECT_EQ(0, lite::CompareRelativeOutput(output_ptr, dx2_path)); + + for (int i = 0; i < 5; i++) delete all_tensors[i]; + delete param; + MS_LOG(INFO) << "TestMulGradFp32 passed"; +} + +TEST_F(TestArithmeticGradFp32, TestMulGrad2Fp32) { + auto param = new ArithmeticParameter(); + param->op_parameter_.type_ = PrimitiveType_MulGrad; + std::vector all_tensors = + GenerateTensorsForTest("./test_data/operators/arithmetic_fp32_4_dy_4_6.bin", 4); + + std::vector inputs = {all_tensors[0], all_tensors[2], all_tensors[1]}; + std::vector outputs = {all_tensors[4], all_tensors[3]}; + kernel::KernelKey desc = {kernel::kCPU, TypeId::kNumberTypeFloat32, schema::PrimitiveType_MulGrad}; + auto creator = lite::KernelRegistry::GetInstance()->GetCreator(desc); + auto kernel_obj = creator(inputs, outputs, reinterpret_cast(param), NULL, desc); + kernel_obj->Run(); + + float *output_ptr = reinterpret_cast(outputs[0]->Data()); + printf("==================output data=================\n"); + for (int i = 0; i < 6; i++) { + std::cout << output_ptr[i] << " ,"; + } + std::cout << std::endl; + + std::string output_path = "./test_data/operators/arithmetic_fp32_4_dx1_4_6.bin"; + EXPECT_EQ(0, lite::CompareRelativeOutput(reinterpret_cast(outputs[1]->Data()), output_path)); + + std::string dx2_path = "./test_data/operators/arithmetic_fp32_4_dx2_1_6.bin"; + EXPECT_EQ(0, lite::CompareRelativeOutput(output_ptr, dx2_path)); + + for (int i = 0; i < 5; i++) delete all_tensors[i]; + delete param; + MS_LOG(INFO) << "TestMulGrad2Fp32 passed"; +} + +TEST_F(TestArithmeticGradFp32, TestMulGrad3Fp32) { + auto param = new ArithmeticParameter(); + param->op_parameter_.type_ = PrimitiveType_MulGrad; + std::vector all_tensors = + GenerateTensorsForTest("./test_data/operators/arithmetic_fp32_9_dy_5_4_6.bin", 9); + + std::vector inputs = {all_tensors[0], all_tensors[1], all_tensors[2]}; + std::vector outputs = {all_tensors[3], all_tensors[4]}; + kernel::KernelKey desc = {kernel::kCPU, TypeId::kNumberTypeFloat32, schema::PrimitiveType_MulGrad}; + auto creator = lite::KernelRegistry::GetInstance()->GetCreator(desc); + auto kernel_obj = creator(inputs, outputs, reinterpret_cast(param), NULL, desc); + kernel_obj->Run(); + + float *output_ptr = reinterpret_cast(outputs[1]->Data()); + printf("==================output data=================\n"); + for (int i = 0; i < 6; i++) { + std::cout << output_ptr[i] << " ,"; + } + std::cout << std::endl; + + std::string output_path = "./test_data/operators/arithmetic_fp32_9_dx1_5_4_6.bin"; + EXPECT_EQ(0, lite::CompareRelativeOutput(reinterpret_cast(outputs[0]->Data()), output_path)); + + std::string dx2_path = "./test_data/operators/arithmetic_fp32_9_dx2_5_1_6.bin"; + EXPECT_EQ(0, lite::CompareRelativeOutput(output_ptr, dx2_path)); + + for (int i = 0; i < 5; i++) delete all_tensors[i]; + delete param; + MS_LOG(INFO) << "TestMulGrad3Fp32 passed"; +} + +TEST_F(TestArithmeticGradFp32, TestMulGrad4Fp32) { + auto param = new ArithmeticParameter(); + param->op_parameter_.type_ = PrimitiveType_MulGrad; + std::vector all_tensors = + GenerateTensorsForTest("./test_data/operators/arithmetic_fp32_9_dy_5_4_6.bin", 9); + + std::vector inputs = {all_tensors[0], all_tensors[2], all_tensors[1]}; + std::vector outputs = {all_tensors[4], all_tensors[3]}; + kernel::KernelKey desc = {kernel::kCPU, TypeId::kNumberTypeFloat32, schema::PrimitiveType_MulGrad}; + auto creator = lite::KernelRegistry::GetInstance()->GetCreator(desc); + auto kernel_obj = creator(inputs, outputs, reinterpret_cast(param), NULL, desc); + kernel_obj->Run(); + + float *output_ptr = reinterpret_cast(outputs[0]->Data()); + printf("==================output data=================\n"); + for (int i = 0; i < 6; i++) { + std::cout << output_ptr[i] << " ,"; + } + std::cout << std::endl; + + std::string output_path = "./test_data/operators/arithmetic_fp32_9_dx1_5_4_6.bin"; + EXPECT_EQ(0, lite::CompareRelativeOutput(reinterpret_cast(outputs[1]->Data()), output_path)); + + std::string dx2_path = "./test_data/operators/arithmetic_fp32_9_dx2_5_1_6.bin"; + EXPECT_EQ(0, lite::CompareRelativeOutput(output_ptr, dx2_path)); + + for (int i = 0; i < 5; i++) delete all_tensors[i]; + delete param; + MS_LOG(INFO) << "TestMulGrad4Fp32 passed"; +} + +TEST_F(TestArithmeticGradFp32, TestDivGradFp32) { + auto param = new ArithmeticParameter(); + param->op_parameter_.type_ = PrimitiveType_DivGrad; + std::vector all_tensors = + GenerateTensorsForTest("./test_data/operators/arithmetic_fp32_5_dy_4_6.bin", 5); + + std::vector inputs = {all_tensors[0], all_tensors[1], all_tensors[2]}; + std::vector outputs = {all_tensors[3], all_tensors[4]}; + kernel::KernelKey desc = {kernel::kCPU, TypeId::kNumberTypeFloat32, schema::PrimitiveType_DivGrad}; + auto creator = lite::KernelRegistry::GetInstance()->GetCreator(desc); + auto kernel_obj = creator(inputs, outputs, reinterpret_cast(param), NULL, desc); + kernel_obj->Run(); + + float *output_ptr = reinterpret_cast(outputs[1]->Data()); + printf("==================output data=================\n"); + for (int i = 0; i < 6; i++) { + std::cout << output_ptr[i] << " ,"; + } + std::cout << std::endl; + + std::string output_path = "./test_data/operators/arithmetic_fp32_5_dx1_4_6.bin"; + EXPECT_EQ(0, lite::CompareRelativeOutput(reinterpret_cast(outputs[0]->Data()), output_path)); + + std::string dx2_path = "./test_data/operators/arithmetic_fp32_5_dx2_1_6.bin"; + EXPECT_EQ(0, lite::CompareRelativeOutput(output_ptr, dx2_path)); + + for (int i = 0; i < 5; i++) delete all_tensors[i]; + delete param; + MS_LOG(INFO) << "TestDivGradFp32 passed"; +} + +TEST_F(TestArithmeticGradFp32, TestDivGrad2Fp32) { + auto param = new ArithmeticParameter(); + param->op_parameter_.type_ = PrimitiveType_DivGrad; + std::vector all_tensors = + GenerateTensorsForTest("./test_data/operators/arithmetic_fp32_6_dy_4_6.bin", 6); + + std::vector inputs = {all_tensors[0], all_tensors[2], all_tensors[1]}; + std::vector outputs = {all_tensors[4], all_tensors[3]}; + kernel::KernelKey desc = {kernel::kCPU, TypeId::kNumberTypeFloat32, schema::PrimitiveType_DivGrad}; + auto creator = lite::KernelRegistry::GetInstance()->GetCreator(desc); + auto kernel_obj = creator(inputs, outputs, reinterpret_cast(param), NULL, desc); + kernel_obj->Run(); + + float *output_ptr = reinterpret_cast(outputs[0]->Data()); + printf("==================output data=================\n"); + for (int i = 0; i < 6; i++) { + std::cout << output_ptr[i] << " ,"; + } + std::cout << std::endl; + + std::string dx2_path = "./test_data/operators/arithmetic_fp32_6_dx2_4_6.bin"; + EXPECT_EQ(0, lite::CompareRelativeOutput(reinterpret_cast(outputs[1]->Data()), dx2_path)); + + std::string output_path = "./test_data/operators/arithmetic_fp32_6_dx1_1_6.bin"; + EXPECT_EQ(0, lite::CompareRelativeOutput(output_ptr, output_path)); + + for (int i = 0; i < 5; i++) delete all_tensors[i]; + delete param; + MS_LOG(INFO) << "TestDivGrad2Fp32 passed"; +} + +TEST_F(TestArithmeticGradFp32, TestDivGrad3Fp32) { + auto param = new ArithmeticParameter(); + param->op_parameter_.type_ = PrimitiveType_DivGrad; + std::vector all_tensors = + GenerateTensorsForTest("./test_data/operators/arithmetic_fp32_10_dy_5_4_6.bin", 10); + + std::vector inputs = {all_tensors[0], all_tensors[1], all_tensors[2]}; + std::vector outputs = {all_tensors[3], all_tensors[4]}; + kernel::KernelKey desc = {kernel::kCPU, TypeId::kNumberTypeFloat32, schema::PrimitiveType_DivGrad}; + auto creator = lite::KernelRegistry::GetInstance()->GetCreator(desc); + auto kernel_obj = creator(inputs, outputs, reinterpret_cast(param), NULL, desc); + kernel_obj->Run(); + + float *output_ptr = reinterpret_cast(outputs[1]->Data()); + printf("==================output data=================\n"); + for (int i = 0; i < 6; i++) { + std::cout << output_ptr[i] << " ,"; + } + std::cout << std::endl; + + std::string dx1_path = "./test_data/operators/arithmetic_fp32_10_dx1_5_4_6.bin"; + EXPECT_EQ(0, lite::CompareRelativeOutput(reinterpret_cast(outputs[0]->Data()), dx1_path)); + + std::string output_path = "./test_data/operators/arithmetic_fp32_10_dx2_5_1_6.bin"; + EXPECT_EQ(0, lite::CompareRelativeOutput(output_ptr, output_path)); + + for (int i = 0; i < 5; i++) delete all_tensors[i]; + delete param; + MS_LOG(INFO) << "TestDivGrad3Fp32 passed"; +} + +TEST_F(TestArithmeticGradFp32, Test3DDivGrad2Fp32) { + auto param = new ArithmeticParameter(); + param->op_parameter_.type_ = PrimitiveType_DivGrad; + std::vector all_tensors = + GenerateTensorsForTest("./test_data/operators/arithmetic_fp32_7_dy_4_5_6.bin", 7); + + std::vector inputs = {all_tensors[0], all_tensors[1], all_tensors[2]}; + std::vector outputs = {all_tensors[3], all_tensors[4]}; + kernel::KernelKey desc = {kernel::kCPU, TypeId::kNumberTypeFloat32, schema::PrimitiveType_DivGrad}; + auto creator = lite::KernelRegistry::GetInstance()->GetCreator(desc); + auto kernel_obj = creator(inputs, outputs, reinterpret_cast(param), NULL, desc); + kernel_obj->Run(); + + float *output_ptr = reinterpret_cast(outputs[1]->Data()); + printf("==================output data=================\n"); + for (int i = 0; i < 6; i++) { + std::cout << output_ptr[i] << " ,"; + } + std::cout << std::endl; + + std::string dx1_path = "./test_data/operators/arithmetic_fp32_7_dx1_4_5_6.bin"; + EXPECT_EQ(0, lite::CompareRelativeOutput(reinterpret_cast(outputs[0]->Data()), dx1_path)); + + std::string output_path = "./test_data/operators/arithmetic_fp32_7_dx2_1_1_6.bin"; + EXPECT_EQ(0, lite::CompareRelativeOutput(output_ptr, output_path)); + + for (int i = 0; i < 5; i++) delete all_tensors[i]; + delete param; + MS_LOG(INFO) << "TestDivGrad2Fp32 passed"; +} + +} // namespace mindspore diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/fp32/bias_grad_fp32_tests.cc b/mindspore/lite/test/ut/src/runtime/kernel/arm/fp32/bias_grad_fp32_tests.cc new file mode 100644 index 0000000000..7c26e95022 --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/fp32/bias_grad_fp32_tests.cc @@ -0,0 +1,71 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include "utils/log_adapter.h" +#include "common/common_test.h" +#include "src/common/file_utils.h" +#include "mindspore/lite/src/runtime/kernel/arm/fp32/bias_grad.h" +#include "mindspore/lite/src/kernel_registry.h" + +namespace mindspore { + +class TestBiasGradFp32 : public mindspore::Common { + public: + TestBiasGradFp32() {} +}; + +TEST_F(TestBiasGradFp32, BiasGradFp32) { + // prepare stage + auto bias_param = new ArithmeticParameter(); + + size_t input_size; + std::string input_path = "./test_data/operators/biasgradfp32_1_dy_10_28_28_7.bin"; + auto input_data = reinterpret_cast(mindspore::lite::ReadFile(input_path.c_str(), &input_size)); + std::vector dim_dy({10, 28, 28, 7}); + lite::tensor::Tensor dy_tensor(TypeId::kNumberTypeFloat32, dim_dy); + dy_tensor.SetData(input_data); + + std::vector inputs = {&dy_tensor}; + + auto output_data = new float[7]; + std::vector dim_dw({7}); + lite::tensor::Tensor dw_tensor(TypeId::kNumberTypeFloat32, dim_dw); + dw_tensor.SetData(output_data); + std::vector outputs = {&dw_tensor}; + + kernel::KernelKey desc = {kernel::kCPU, TypeId::kNumberTypeFloat32, schema::PrimitiveType_BiasGrad}; + + auto creator = lite::KernelRegistry::GetInstance()->GetCreator(desc); + auto kernel_obj = creator(inputs, outputs, reinterpret_cast(bias_param), NULL, desc); + + kernel_obj->Run(); + + printf("==================output data=================\n"); + for (int i = 0; i < 7; i++) { + std::cout << output_data[i] << " ,"; + } + std::cout << std::endl; + std::string output_path = "./test_data/operators/biasgradfp32_1_db_7.bin"; + lite::CompareOutput(output_data, output_path); + + // delete input_data; + // delete[] output_data; + delete bias_param; + MS_LOG(INFO) << "BiasGradFp32 passed"; +} + +} // namespace mindspore diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/fp32/convolution_grad_fp32_tests.cc b/mindspore/lite/test/ut/src/runtime/kernel/arm/fp32/convolution_grad_fp32_tests.cc new file mode 100644 index 0000000000..ef501fa655 --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/fp32/convolution_grad_fp32_tests.cc @@ -0,0 +1,521 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include "utils/log_adapter.h" +#include "common/common_test.h" +#include "src/common/file_utils.h" +#include "src/common/file_utils_ext.h" +#include "mindspore/lite/src/runtime/kernel/arm/fp32/convolution_grad_filter.h" +#include "mindspore/lite/src/runtime/kernel/arm/fp32/convolution_grad_input.h" +#include "mindspore/lite/src/runtime/kernel/arm/opclib/conv_parameter.h" +#include "mindspore/lite/src/kernel_registry.h" + +namespace mindspore { +class TestConvolutionGradFp32 : public mindspore::Common { + public: + TestConvolutionGradFp32() {} +}; + +void InitConvParamGroup1FP32(ConvParameter *conv_param) { + conv_param->input_batch_ = 1; + conv_param->input_h_ = 28; + conv_param->input_w_ = 28; + conv_param->input_channel_ = 3; + + conv_param->output_batch_ = 1; + conv_param->output_h_ = 28; + conv_param->output_w_ = 28; + conv_param->output_channel_ = 32; + + conv_param->kernel_h_ = 3; + conv_param->kernel_w_ = 3; + + conv_param->stride_h_ = 1; + conv_param->stride_w_ = 1; + + conv_param->dilation_h_ = 1; + conv_param->dilation_w_ = 1; + + conv_param->pad_h_ = 1; + conv_param->pad_w_ = 1; + + conv_param->group_ = 1; + conv_param->is_relu_ = false; + conv_param->is_relu6_ = false; + conv_param->thread_num_ = 1; +} + +void InitConvParamGroup3FP32(ConvParameter *conv_param) { + InitConvParamGroup1FP32(conv_param); + conv_param->group_ = 3; + conv_param->output_channel_ = 18; +} + +void InitConvParamGroup3Dilation2FP32(ConvParameter *conv_param) { + InitConvParamGroup3FP32(conv_param); + conv_param->dilation_h_ = 2; + conv_param->dilation_w_ = 2; + conv_param->output_h_ = 26; + conv_param->output_w_ = 26; +} + +TEST_F(TestConvolutionGradFp32, ConvFp32FilterGrad) { + // prepare stage + auto conv_param = new ConvParameter(); + InitConvParamGroup1FP32(conv_param); + + size_t dy_size; + std::string dy_path = "./test_data/conv/convfp32_dy_1_28_28_32.bin"; + auto dy_data = reinterpret_cast(mindspore::lite::ReadFile(dy_path.c_str(), &dy_size)); + std::vector dim_dy({1, 28, 28, 32}); + lite::tensor::Tensor dy_tensor(TypeId::kNumberTypeFloat32, dim_dy); + dy_tensor.SetData(dy_data); + + // runtime part + printf("Calculating runtime cost...\n"); + uint64_t time_avg = 0; + size_t output_data_size = + conv_param->output_channel_ * conv_param->kernel_h_ * conv_param->kernel_w_ * conv_param->input_channel_; + + size_t input_size; + std::string input_path = "./test_data/conv/convfp32_x_1_28_28_3.bin"; + auto input_data = reinterpret_cast(mindspore::lite::ReadFile(input_path.c_str(), &input_size)); + std::vector dim_x({1, 28, 28, 3}); + lite::tensor::Tensor x_tensor(TypeId::kNumberTypeFloat32, dim_x); + x_tensor.SetData(input_data); + + auto dw_data = new float[output_data_size]; + std::vector dim_dw({32, 3, 3, 3}); + lite::tensor::Tensor dw_tensor(TypeId::kNumberTypeFloat32, dim_dw); + dw_tensor.SetData(dw_data); + std::vector inputs = {&dy_tensor, &x_tensor}; + std::vector outputs = {&dw_tensor}; + + kernel::KernelKey desc = {kernel::kCPU, TypeId::kNumberTypeFloat32, schema::PrimitiveType_Conv2DGradFilter}; + auto creator = lite::KernelRegistry::GetInstance()->GetCreator(desc); + auto kernel = creator(inputs, outputs, reinterpret_cast(conv_param), NULL, desc); + + // warm up loop + for (int i = 0; i < 3; i++) { + kernel->Run(); + } + + int loop_count = 100; + auto time_start = mindspore::lite::GetTimeUs(); + for (int i = 0; i < loop_count; i++) { + kernel->Run(); + } + auto time_end = mindspore::lite::GetTimeUs(); + auto cost = time_end - time_start; + time_avg = cost / loop_count; + printf("single thread running time : %f ms\n", time_avg / 1000.0f); + + std::string output_path = "./test_data/conv/convfp32_dw_32_3_3_3.bin"; + auto res = lite::CompareRelativeOutput(dw_data, output_path); + + EXPECT_EQ(res, 0); + + // delete input_data; + // delete dy_data; + // delete [] dw_data; + delete kernel; + delete conv_param; + MS_LOG(INFO) << "TestConvolutionGradFp32 Filter Grad passed"; +} + +TEST_F(TestConvolutionGradFp32, ConvFp32InputGrad) { + // prepare stage + auto conv_param = new ConvParameter(); + InitConvParamGroup1FP32(conv_param); + + size_t dy_size; + std::string dy_path = "./test_data/conv/convfp32_dy_1_28_28_32.bin"; + auto dy_data = reinterpret_cast(mindspore::lite::ReadFile(dy_path.c_str(), &dy_size)); + std::vector dim_dy({1, 28, 28, 32}); + lite::tensor::Tensor dy_tensor(TypeId::kNumberTypeFloat32, dim_dy); + dy_tensor.SetData(dy_data); + + size_t w_size; + std::string w_path = "./test_data/conv/convfp32_w_32_3_3_3.bin"; + auto w_data = reinterpret_cast(mindspore::lite::ReadFile(w_path.c_str(), &w_size)); + std::vector dim_dw({32, 3, 3, 3}); + lite::tensor::Tensor w_tensor(TypeId::kNumberTypeFloat32, dim_dw); + w_tensor.SetData(w_data); + + size_t output_data_size = + conv_param->input_batch_ * conv_param->input_h_ * conv_param->input_w_ * conv_param->input_channel_; + auto dx_data = new float[output_data_size]; + std::vector dim_dx({1, 28, 28, 3}); + lite::tensor::Tensor dx_tensor(TypeId::kNumberTypeFloat32, dim_dx); + dx_tensor.SetData(dx_data); + + std::vector inputs = {&dy_tensor, &w_tensor}; + std::vector outputs = {&dx_tensor}; + // runtime part + + printf("Calculating runtime cost...\n"); + uint64_t time_avg = 0; + + kernel::KernelKey desc = {kernel::kCPU, TypeId::kNumberTypeFloat32, schema::PrimitiveType_Conv2DGradInput}; + auto creator = lite::KernelRegistry::GetInstance()->GetCreator(desc); + auto kernel = creator(inputs, outputs, reinterpret_cast(conv_param), NULL, desc); + + // warm up loop + for (int i = 0; i < 3; i++) { + kernel->Run(); + } + + int loop_count = 100; + auto time_start = mindspore::lite::GetTimeUs(); + for (int i = 0; i < loop_count; i++) { + kernel->Run(); + } + auto time_end = mindspore::lite::GetTimeUs(); + auto cost = time_end - time_start; + time_avg = cost / loop_count; + printf("single thread running time : %f ms\n", time_avg / 1000.0f); + + std::string output_path = "./test_data/conv/convfp32_dx_1_28_28_3.bin"; + auto res = lite::CompareRelativeOutput(dx_data, output_path); + EXPECT_EQ(res, 0); + + delete kernel; + delete conv_param; + MS_LOG(INFO) << "TestConvolutionGradFp32 Filter Grad passed"; +} + +TEST_F(TestConvolutionGradFp32, ConvFp32GroupFilterGrad) { + // prepare stage + auto conv_param = new ConvParameter(); + InitConvParamGroup3FP32(conv_param); + + size_t dy_size; + std::string dy_path = "./test_data/conv/convfp32_dy_g3_1_28_28_18.bin"; + auto dy_data = reinterpret_cast(mindspore::lite::ReadFile(dy_path.c_str(), &dy_size)); + std::vector dim_dy({1, 28, 28, 18}); + lite::tensor::Tensor dy_tensor(TypeId::kNumberTypeFloat32, dim_dy); + dy_tensor.SetData(dy_data); + + // runtime part + printf("Calculating runtime cost...\n"); + uint64_t time_avg = 0; + size_t output_data_size = conv_param->output_channel_ * conv_param->kernel_h_ * conv_param->kernel_w_ * + conv_param->input_channel_ / conv_param->group_; + + size_t input_size; + std::string input_path = "./test_data/conv/convfp32_x_g3_1_28_28_3.bin"; + auto input_data = reinterpret_cast(mindspore::lite::ReadFile(input_path.c_str(), &input_size)); + std::vector dim_x({1, 28, 28, 3}); + lite::tensor::Tensor x_tensor(TypeId::kNumberTypeFloat32, dim_x); + x_tensor.SetData(input_data); + + auto dw_data = new float[output_data_size]; + std::vector dim_dw({18, 3, 3, 1}); + lite::tensor::Tensor dw_tensor(TypeId::kNumberTypeFloat32, dim_dw); + dw_tensor.SetData(dw_data); + std::vector inputs = {&dy_tensor, &x_tensor}; + std::vector outputs = {&dw_tensor}; + + kernel::KernelKey desc = {kernel::kCPU, TypeId::kNumberTypeFloat32, schema::PrimitiveType_Conv2DGradFilter}; + auto creator = lite::KernelRegistry::GetInstance()->GetCreator(desc); + auto kernel = creator(inputs, outputs, reinterpret_cast(conv_param), NULL, desc); + + // warm up loop + for (int i = 0; i < 3; i++) { + kernel->Run(); + } + + int loop_count = 100; + auto time_start = mindspore::lite::GetTimeUs(); + for (int i = 0; i < loop_count; i++) { + kernel->Run(); + } + auto time_end = mindspore::lite::GetTimeUs(); + auto cost = time_end - time_start; + time_avg = cost / loop_count; + printf("single thread running time : %f ms\n", time_avg / 1000.0f); + + std::string output_path = "./test_data/conv/convfp32_dw_g3_18_3_3_3.bin"; + auto res = lite::CompareRelativeOutput(dw_data, output_path); + EXPECT_EQ(res, 0); + + // delete input_data; + // delete dy_data; + // delete [] dw_data; + delete kernel; + delete conv_param; + MS_LOG(INFO) << "TestConvolutionGradFp32 Filter Grad passed"; +} + +TEST_F(TestConvolutionGradFp32, ConvFp32GroupInputGrad) { + // prepare stage + auto conv_param = new ConvParameter(); + InitConvParamGroup3FP32(conv_param); + + size_t dy_size; + std::string dy_path = "./test_data/conv/convfp32_dy_g3_1_28_28_18.bin"; + auto dy_data = reinterpret_cast(mindspore::lite::ReadFile(dy_path.c_str(), &dy_size)); + std::vector dim_dy({1, 28, 28, 18}); + lite::tensor::Tensor dy_tensor(TypeId::kNumberTypeFloat32, dim_dy); + dy_tensor.SetData(dy_data); + + size_t w_size; + std::string w_path = "./test_data/conv/convfp32_w_g3_18_3_3_3.bin"; + auto w_data = reinterpret_cast(mindspore::lite::ReadFile(w_path.c_str(), &w_size)); + std::vector dim_dw({18, 3, 3, 1}); + lite::tensor::Tensor w_tensor(TypeId::kNumberTypeFloat32, dim_dw); + w_tensor.SetData(w_data); + + size_t output_data_size = + conv_param->input_batch_ * conv_param->input_h_ * conv_param->input_w_ * conv_param->input_channel_; + auto dx_data = new float[output_data_size]; + std::vector dim_dx({1, 28, 28, 3}); + lite::tensor::Tensor dx_tensor(TypeId::kNumberTypeFloat32, dim_dx); + dx_tensor.SetData(dx_data); + + std::vector inputs = {&dy_tensor, &w_tensor}; + std::vector outputs = {&dx_tensor}; + // runtime part + + printf("Calculating runtime cost...\n"); + uint64_t time_avg = 0; + + kernel::KernelKey desc = {kernel::kCPU, TypeId::kNumberTypeFloat32, schema::PrimitiveType_Conv2DGradInput}; + auto creator = lite::KernelRegistry::GetInstance()->GetCreator(desc); + auto kernel = creator(inputs, outputs, reinterpret_cast(conv_param), NULL, desc); + + // warm up loop + for (int i = 0; i < 3; i++) { + kernel->Run(); + } + + int loop_count = 100; + auto time_start = mindspore::lite::GetTimeUs(); + for (int i = 0; i < loop_count; i++) { + kernel->Run(); + } + auto time_end = mindspore::lite::GetTimeUs(); + auto cost = time_end - time_start; + time_avg = cost / loop_count; + printf("single thread running time : %f ms\n", time_avg / 1000.0f); + + std::string output_path = "./test_data/conv/convfp32_dx_g3_1_28_28_3.bin"; + auto res = lite::CompareRelativeOutput(dx_data, output_path); + EXPECT_EQ(res, 0); + + delete kernel; + delete conv_param; + MS_LOG(INFO) << "TestConvolutionGradFp32 Filter Grad passed"; +} + +TEST_F(TestConvolutionGradFp32, ConvFp32GroupDilationFilterGrad) { + // prepare stage + auto conv_param = new ConvParameter(); + + InitConvParamGroup3Dilation2FP32(conv_param); + + size_t dy_size; + std::string dy_path = "./test_data/conv/convfp32_dy_g3_d2_1_26_26_18.bin"; + auto dy_data = reinterpret_cast(mindspore::lite::ReadFile(dy_path.c_str(), &dy_size)); + std::vector dim_dy({1, 26, 26, 18}); + lite::tensor::Tensor dy_tensor(TypeId::kNumberTypeFloat32, dim_dy); + dy_tensor.SetData(dy_data); + + // runtime part + printf("Calculating runtime cost...\n"); + uint64_t time_avg = 0; + size_t output_data_size = conv_param->output_channel_ * conv_param->kernel_h_ * conv_param->kernel_w_ * + conv_param->input_channel_ / conv_param->group_; + + size_t input_size; + std::string input_path = "./test_data/conv/convfp32_x_g3_d2_1_28_28_3.bin"; + auto input_data = reinterpret_cast(mindspore::lite::ReadFile(input_path.c_str(), &input_size)); + std::vector dim_x({1, 28, 28, 3}); + lite::tensor::Tensor x_tensor(TypeId::kNumberTypeFloat32, dim_x); + x_tensor.SetData(input_data); + + auto dw_data = new float[output_data_size]; + std::vector dim_dw({18, 3, 3, 1}); + lite::tensor::Tensor dw_tensor(TypeId::kNumberTypeFloat32, dim_dw); + dw_tensor.SetData(dw_data); + std::vector inputs = {&dy_tensor, &x_tensor}; + std::vector outputs = {&dw_tensor}; + + kernel::KernelKey desc = {kernel::kCPU, TypeId::kNumberTypeFloat32, schema::PrimitiveType_Conv2DGradFilter}; + auto creator = lite::KernelRegistry::GetInstance()->GetCreator(desc); + auto kernel = creator(inputs, outputs, reinterpret_cast(conv_param), NULL, desc); + + // warm up loop + for (int i = 0; i < 3; i++) { + kernel->Run(); + } + + int loop_count = 100; + auto time_start = mindspore::lite::GetTimeUs(); + for (int i = 0; i < loop_count; i++) { + kernel->Run(); + } + auto time_end = mindspore::lite::GetTimeUs(); + auto cost = time_end - time_start; + time_avg = cost / loop_count; + printf("single thread running time : %f ms\n", time_avg / 1000.0f); + + std::string output_path = "./test_data/conv/convfp32_dw_g3_d2_18_3_3_3.bin"; + auto res = lite::CompareRelativeOutput(dw_data, output_path); + EXPECT_EQ(res, 0); + // delete input_data; + // delete dy_data; + // delete [] dw_data; + delete kernel; + delete conv_param; + MS_LOG(INFO) << "TestConvolutionGradFp32 Filter Grad passed"; +} + +TEST_F(TestConvolutionGradFp32, ConvFp32GroupDilationInputGrad) { + // prepare stage + auto conv_param = new ConvParameter(); + InitConvParamGroup3Dilation2FP32(conv_param); + + size_t dy_size; + std::string dy_path = "./test_data/conv/convfp32_dy_g3_d2_1_26_26_18.bin"; + auto dy_data = reinterpret_cast(mindspore::lite::ReadFile(dy_path.c_str(), &dy_size)); + std::vector dim_dy({1, 26, 26, 18}); + lite::tensor::Tensor dy_tensor(TypeId::kNumberTypeFloat32, dim_dy); + dy_tensor.SetData(dy_data); + + size_t w_size; + std::string w_path = "./test_data/conv/convfp32_w_g3_d2_18_3_3_3.bin"; + auto w_data = reinterpret_cast(mindspore::lite::ReadFile(w_path.c_str(), &w_size)); + std::vector dim_w({18, 3, 3, 1}); + lite::tensor::Tensor w_tensor(TypeId::kNumberTypeFloat32, dim_w); + w_tensor.SetData(w_data); + + size_t output_data_size = + conv_param->input_batch_ * conv_param->input_h_ * conv_param->input_w_ * conv_param->input_channel_; + auto dx_data = new float[output_data_size]; + std::vector dim_dx({1, 28, 28, 3}); + lite::tensor::Tensor dx_tensor(TypeId::kNumberTypeFloat32, dim_dx); + dx_tensor.SetData(dx_data); + + std::vector inputs = {&dy_tensor, &w_tensor}; + std::vector outputs = {&dx_tensor}; + // runtime part + + printf("Calculating runtime cost...\n"); + uint64_t time_avg = 0; + + kernel::KernelKey desc = {kernel::kCPU, TypeId::kNumberTypeFloat32, schema::PrimitiveType_Conv2DGradInput}; + auto creator = lite::KernelRegistry::GetInstance()->GetCreator(desc); + auto kernel = creator(inputs, outputs, reinterpret_cast(conv_param), NULL, desc); + + // warm up loop + for (int i = 0; i < 3; i++) { + kernel->Run(); + } + + int loop_count = 100; + auto time_start = mindspore::lite::GetTimeUs(); + for (int i = 0; i < loop_count; i++) { + kernel->Run(); + } + auto time_end = mindspore::lite::GetTimeUs(); + auto cost = time_end - time_start; + time_avg = cost / loop_count; + printf("single thread running time : %f ms\n", time_avg / 1000.0f); + + std::string output_path = "./test_data/conv/convfp32_dx_g3_d2_1_28_28_3.bin"; + auto res = lite::CompareRelativeOutput(dx_data, output_path); + EXPECT_EQ(res, 0); + + delete kernel; + delete conv_param; + MS_LOG(INFO) << "TestConvolutionGradFp32 Filter Grad passed"; +} + +// TEST_F(TestConvolutionGradFp32, ConvGroupDilation) { +// // prepare stage +// auto conv_param = new ConvParameter(); +// InitConvParamGroup3Dilation2FP32(conv_param); + +// size_t x_size; +// std::string x_path = "./test_data/conv/convfp32_x_g3_d2_1_28_28_3.bin"; +// auto x_data = reinterpret_cast(mindspore::lite::ReadFile(x_path.c_str(), &x_size)); +// std::vector dim_x({1, 28, 28, 3}); +// tensor::Tensor x_tensor(TypeId::kNumberTypeFloat32, dim_x); +// x_tensor.SetData(x_data); + +// size_t w_size; +// std::string w_path = "./test_data/conv/convfp32_w_g3_d2_18_3_3_3.bin"; +// auto w_data = reinterpret_cast(mindspore::lite::ReadFile(w_path.c_str(), &w_size)); +// std::vector dim_w({18, 3, 3, 1}); +// tensor::Tensor w_tensor(TypeId::kNumberTypeFloat32, dim_w); +// w_tensor.SetData(w_data); + +// size_t output_data_size = +// conv_param->output_batch_ * conv_param->output_h_ * conv_param->output_w_ * conv_param->output_channel_; +// auto y_data = new float[output_data_size]; +// std::vector dim_y({1, 26, 26, 18}); +// tensor::Tensor y_tensor(TypeId::kNumberTypeFloat32, dim_y); +// y_tensor.SetData(y_data); + +// std::vector inputs = {&x_tensor, &w_tensor}; +// std::vector outputs = {&y_tensor}; +// // runtime part + +// printf("Calculating runtime cost...\n"); +// uint64_t time_avg = 0; + +// lite::Context context; +// ; +// context.deviceCtx.type = lite::DT_CPU; +// context.threadNum = 1; + +// kernel::KernelKey desc = {kernel::kCPU, kNumberTypeFloat32, schema::PrimitiveType_Conv2D}; +// auto creator = lite::KernelRegistry::GetInstance()->GetKernelCreator(desc); +// auto kernel = creator(inputs, outputs, (OpParameter *)conv_param, &context, desc); + +// kernel->train(); +// EXPECT_EQ(kernel->is_train(), 1); + +// // warm up loop +// for (int i = 0; i < 3; i++) { +// kernel->Run(); +// } + +// int loop_count = 100; +// auto time_start = mindspore::lite::GetTimeUs(); +// for (int i = 0; i < loop_count; i++) { +// kernel->Run(); +// } +// auto time_end = mindspore::lite::GetTimeUs(); +// auto cost = time_end - time_start; +// time_avg = cost / loop_count; +// printf("single thread running time : %f ms\n", time_avg / 1000.0f); + +// std::string output_path = "./test_data/conv/convfp32_y_g3_d2_1_26_26_18.bin"; +// auto res = lite::CompareRelativeOutput(y_data, output_path); +// EXPECT_EQ(res, 0); + +// delete kernel; +// delete conv_param; + +// MS_LOG(INFO) << "TestConvolutionFp32 Filter Grad passed"; +// } + +} // namespace mindspore diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/fp32/pooling_grad_fp32_tests.cc b/mindspore/lite/test/ut/src/runtime/kernel/arm/fp32/pooling_grad_fp32_tests.cc new file mode 100644 index 0000000000..0dace8d7cd --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/fp32/pooling_grad_fp32_tests.cc @@ -0,0 +1,332 @@ +/** + * Copyright 2020 Huawei Technologies Co., Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "mindspore/lite/include/context.h" +#include "utils/log_adapter.h" +#include "common/common_test.h" +#include "mindspore/lite/src/kernel_registry.h" +#include "src/common/utils.h" +#include "src/common/file_utils.h" +#include "src/runtime/kernel/arm/fp32/pooling_grad.h" +#include "src/runtime/kernel/arm/opclib/fp32/pooling_grad.h" + +namespace mindspore { +class TestPoolingGradFp32 : public mindspore::Common { + public: + TestPoolingGradFp32() {} +}; + +void InitPoolingParamFP32(PoolingParameter *pooling_param) { + pooling_param->input_batch_ = 1; + pooling_param->input_h_ = 28; + pooling_param->input_w_ = 28; + pooling_param->input_channel_ = 3; + + pooling_param->output_batch_ = 1; + pooling_param->output_h_ = 28; + pooling_param->output_w_ = 28; + pooling_param->output_channel_ = 32; + + pooling_param->window_h_ = 3; + pooling_param->window_w_ = 3; + + pooling_param->stride_h_ = 1; + pooling_param->stride_w_ = 1; + + pooling_param->pad_u_ = 1; + pooling_param->pad_d_ = 1; + pooling_param->pad_l_ = 1; + pooling_param->pad_r_ = 1; + pooling_param->thread_num_ = 1; +} + +TEST_F(TestPoolingGradFp32, AvgPoolingGradFp32) { + // prepare stage + auto pooling_param = new PoolingParameter(); + InitPoolingParamFP32(pooling_param); + pooling_param->output_channel_ = 3; + + // runtime part + printf("Calculating runtime cost...\n"); + uint64_t time_avg = 0; + size_t output_data_size = + pooling_param->output_batch_ * pooling_param->output_channel_ * pooling_param->output_h_ * pooling_param->output_w_; + + size_t input_size; + std::string input_path = "./test_data/pooling/avgpoolgradfp32_1_dy_1_28_28_3.bin"; + auto input_data = reinterpret_cast(mindspore::lite::ReadFile(input_path.c_str(), &input_size)); + + auto output_data = new float[output_data_size]; + // warm up loop + for (int i = 0; i < 3; i++) { + AvgPoolingGrad(input_data, output_data, pooling_param); + } + + int loop_count = 100; + auto time_start = mindspore::lite::GetTimeUs(); + for (int i = 0; i < loop_count; i++) { + AvgPoolingGrad(input_data, output_data, pooling_param); + } + auto time_end = mindspore::lite::GetTimeUs(); + auto cost = time_end - time_start; + time_avg = cost / loop_count; + printf("single thread running time : %f ms\n", time_avg / 1000.0f); + + printf("==================output data=================\n"); + for (int i = 0; i < 20; i++) { + std::cout << output_data[i] << " ,"; + } + std::cout << std::endl; + std::string output_path = "./test_data/pooling/avgpoolgradfp32_1_dx_1_28_28_3.bin"; + lite::CompareOutput(output_data, output_path); + + delete input_data; + delete[] output_data; + delete pooling_param; + MS_LOG(INFO) << "TestAvgPoolingGradFp32 passed"; +} + +TEST_F(TestPoolingGradFp32, AvgPoolingKernelGradFp32) { + // prepare stage + auto pooling_param = new PoolingParameter(); + InitPoolingParamFP32(pooling_param); + + pooling_param->output_channel_ = 3; + + // runtime part + printf("Calculating runtime cost...\n"); + // uint64_t time_avg = 0; + size_t output_data_size = + pooling_param->output_batch_ * pooling_param->output_channel_ * pooling_param->output_h_ * pooling_param->output_w_; + + size_t input_size; + std::string input_path = "./test_data/pooling/avgpoolgradfp32_1_dy_1_28_28_3.bin"; + auto input_data = reinterpret_cast(mindspore::lite::ReadFile(input_path.c_str(), &input_size)); + std::vector dim_dy({1, 28, 28, 3}); + lite::tensor::Tensor dy_tensor(TypeId::kNumberTypeFloat32, dim_dy); + dy_tensor.SetData(input_data); + + std::string input1_path = "./test_data/pooling/avgpoolgradfp32_1_x_1_28_28_3.bin"; + input_data = reinterpret_cast(mindspore::lite::ReadFile(input1_path.c_str(), &input_size)); + std::vector dim_x({1, 28, 28, 3}); + lite::tensor::Tensor x_tensor(TypeId::kNumberTypeFloat32, dim_x); + x_tensor.SetData(input_data); + + std::vector inputs = {&dy_tensor, &x_tensor}; + + auto output_data = new float[output_data_size]; + std::vector dim_dx({1, 28, 28, 3}); + lite::tensor::Tensor dx_tensor(TypeId::kNumberTypeFloat32, dim_dx); + dx_tensor.SetData(output_data); + std::vector outputs = {&dx_tensor}; + + kernel::KernelKey desc = {kernel::kCPU, TypeId::kNumberTypeFloat32, schema::PrimitiveType_PoolingGrad}; + + auto creator = lite::KernelRegistry::GetInstance()->GetCreator(desc); + auto kernel_obj = creator(inputs, outputs, reinterpret_cast(pooling_param), NULL, desc); + + kernel_obj->Run(); + + printf("==================output data=================\n"); + for (int i = 0; i < 20; i++) { + std::cout << output_data[i] << " ,"; + } + std::cout << std::endl; + std::string output_path = "./test_data/pooling/avgpoolgradfp32_1_dx_1_28_28_3.bin"; + lite::CompareOutput(output_data, output_path); + + // delete input_data; + // delete[] output_data; + delete pooling_param; + MS_LOG(INFO) << "TestAvgPoolingGradFp32 passed"; +} + +TEST_F(TestPoolingGradFp32, MaxPoolingGradFp32) { + // prepare stage + auto pooling_param = new PoolingParameter(); + InitPoolingParamFP32(pooling_param); + pooling_param->output_channel_ = 3; + pooling_param->avg_pooling_ = false; + pooling_param->max_pooling_ = true; + // runtime part + printf("Calculating runtime cost...\n"); + uint64_t time_avg = 0; + size_t output_data_size = + pooling_param->output_batch_ * pooling_param->output_channel_ * pooling_param->output_h_ * pooling_param->output_w_; + + size_t input_size; + std::string i_path = "./test_data/pooling/maxpoolgradfp32_1_i_1_28_28_3.bin"; + auto ill_data = reinterpret_cast(mindspore::lite::ReadFile(i_path.c_str(), &input_size)); + auto i_data = new int[output_data_size]; + for (uint32_t i = 0; i < output_data_size; i++) { + i_data[i] = static_cast(ill_data[i]); + } + + std::string dy_path = "./test_data/pooling/maxpoolgradfp32_1_dy_1_28_28_3.bin"; + auto dy_data = reinterpret_cast(mindspore::lite::ReadFile(dy_path.c_str(), &input_size)); + + auto output_data = new float[output_data_size]; + // warm up loop + for (int i = 0; i < 3; i++) { + MaxPoolingGrad(dy_data, i_data, output_data, pooling_param); + } + + int loop_count = 100; + auto time_start = mindspore::lite::GetTimeUs(); + for (int i = 0; i < loop_count; i++) { + MaxPoolingGrad(dy_data, i_data, output_data, pooling_param); + } + auto time_end = mindspore::lite::GetTimeUs(); + auto cost = time_end - time_start; + time_avg = cost / loop_count; + printf("single thread running time : %f ms\n", time_avg / 1000.0f); + + printf("==================output data=================\n"); + for (int i = 0; i < 20; i++) { + std::cout << output_data[i] << " ,"; + } + std::cout << std::endl; + std::string output_path = "./test_data/pooling/maxpoolgradfp32_1_dx_1_28_28_3.bin"; + lite::CompareOutput(output_data, output_path); + + // delete input_data; + delete pooling_param; + delete[] output_data; + MS_LOG(INFO) << "TestMaxPoolingGradFp32 passed"; +} + +#if 0 +TEST_F(TestPoolingGradFp32, MaxPoolingKernelGradFp32) { + // prepare stage + auto maxpool = new PoolingParameter(); + InitPoolingParamFP32(maxpool); + maxpool->avg_pooling_ = false; + maxpool->max_pooling_ = true; + maxpool->input_h_ = 30; + maxpool->input_w_ = 30; + maxpool->input_channel_ = 3; + + maxpool->output_batch_ = 1; + maxpool->output_h_ = 10; + maxpool->output_w_ = 10; + maxpool->output_channel_ = 3; + maxpool->stride_h_ = 3; + maxpool->stride_w_ = 3; + + maxpool->pad_u_ = 0; + maxpool->pad_d_ = 0; + maxpool->pad_l_ = 0; + maxpool->pad_r_ = 0; + + size_t input_size; + size_t y_data_size = maxpool->output_batch_ * maxpool->output_channel_ * maxpool->output_h_ * maxpool->output_w_; + + auto x_data = reinterpret_cast( + mindspore::lite::ReadFile("./test_data/pooling/maxpoolgradfp32_2_x_1_30_30_3.bin", &input_size)); + std::vector dim_x({1, 30, 30, 3}); + lite::tensor::Tensor x_tensor(TypeId::kNumberTypeFloat32, dim_x); + x_tensor.SetData(x_data); + std::vector maxpool_inputs = {&x_tensor}; + + auto y_data = new float[y_data_size]; + std::vector dim_y({1, 10, 10, 3}); + lite::tensor::Tensor y_tensor(TypeId::kNumberTypeFloat32, dim_y); + y_tensor.SetData(y_data); + + auto ind_data = new int[y_data_size]; + lite::tensor::Tensor ind_tensor(TypeId::kNumberTypeInt32, dim_y); + ind_tensor.SetData(ind_data); + + std::vector maxpool_outputs = {&y_tensor, &ind_tensor}; + + kernel::KernelKey maxpool_desc = {kernel::kCPU, TypeId::kNumberTypeFloat32, schema::PrimitiveType_Pooling}; + auto maxpool_creator = lite::KernelRegistry::GetInstance()->GetCreator(maxpool_desc); + auto maxpoolobj = maxpool_creator(maxpool_inputs, maxpool_outputs, reinterpret_cast(maxpool), + NULL, maxpool_desc); + maxpoolobj->Run(); + + printf("==================indices data=================\n"); + for (int i = 0; i < 10; i++) { + std::cout << ind_data[i] << " ,"; + } + std::cout << std::endl; + + auto pooling_param = new PoolingParameter(); + InitPoolingParamFP32(pooling_param); + pooling_param->avg_pooling_ = false; + pooling_param->max_pooling_ = true; + pooling_param->input_h_ = 10; + pooling_param->input_w_ = 10; + pooling_param->input_channel_ = 3; + + pooling_param->output_batch_ = 1; + pooling_param->output_h_ = 30; + pooling_param->output_w_ = 30; + pooling_param->output_channel_ = 3; + + // runtime part + printf("Calculating runtime cost...\n"); + // uint64_t time_avg = 0; + size_t output_data_size = + pooling_param->output_batch_ * pooling_param->output_channel_ * pooling_param->output_h_ * pooling_param->output_w_; + + auto dy_data = reinterpret_cast( + mindspore::lite::ReadFile("./test_data/pooling/maxpoolgradfp32_2_dy_1_10_10_3.bin", &input_size)); + std::vector dim_dy({1, 3, 10, 10}); + lite::tensor::Tensor dy_tensor(TypeId::kNumberTypeFloat32, dim_dy); + dy_tensor.SetData(dy_data); + +#if 0 + std::string i_path = "./test_data/pooling/maxpoolgradfp32_2_i_1_3_10_10.bin"; + auto ill_data = reinterpret_cast(mindspore::lite::ReadFile(i_path.c_str(), &input_size)); + auto i_data = new int[output_data_size]; + for (int i=0; i < output_data_size; i++) + i_data[i] = static_cast(ill_data[i]); + std::vector dim_ind({1, 3, 10, 10}); + lite::tensor::Tensor ind_tensor(TypeId::kNumberTypeInt32, dim_ind); + ind_tensor.SetData(i_data); +#endif + + std::vector inputs = {&dy_tensor, &ind_tensor}; + + auto output_data = new float[output_data_size]; + std::vector dim_dx({1, 3, 30, 30}); + lite::tensor::Tensor dx_tensor(TypeId::kNumberTypeFloat32, dim_dx); + dx_tensor.SetData(output_data); + std::vector outputs = {&dx_tensor}; + + kernel::KernelKey desc = {kernel::kCPU, TypeId::kNumberTypeFloat32, schema::PrimitiveType_PoolingGrad}; + auto creator = lite::KernelRegistry::GetInstance()->GetCreator(desc); + auto kernel_obj = creator(inputs, outputs, reinterpret_cast(pooling_param), NULL, desc); + kernel_obj->Run(); + + printf("==================output data=================\n"); + for (int i = 0; i < 20; i++) { + std::cout << output_data[i] << " ,"; + } + std::cout << std::endl; + std::string output_path = "./test_data/pooling/maxpoolgradfp32_2_dx_1_30_30_3.bin"; + lite::CompareOutput(output_data, output_path); + + // delete input_data; + // delete[] output_data; + delete pooling_param; + MS_LOG(INFO) << "TestMaxPoolingKernelGradFp32 passed"; +} +#endif // if 0 before MaxPoolingKernelGradFp32 +} // namespace mindspore diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/hsigmoid_out_50.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/hsigmoid_out_50.bin new file mode 100644 index 0000000000..9418b5866b --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/hsigmoid_out_50.bin @@ -0,0 +1 @@ +"x>#>K9>pR >)J >4>K>Z>>>L>=Q>*^>M>&>6>S>*>N>-=+L>vK>+A}>w^>$Q>s>/W>=M'>9[*>#%<#>C>>>$=Gj>>7*>2>6> >1p>s#>Y)>k>9==lQ0>w> \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/hsigmoid_x_50.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/hsigmoid_x_50.bin new file mode 100644 index 0000000000..d216d74d9d --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/hsigmoid_x_50.bin @@ -0,0 +1 @@ +M?Ƿ? H2|7>0?dyX?C.\fT@?ͳg?Lw񾫘žE9&7A?T?XF4??ҹ?(k?0??VH?-Tz@&"-1w?F?羢D>Y> _p?] ?%R5 Ks=? \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/hsigmoid_yt_50.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/hsigmoid_yt_50.bin new file mode 100644 index 0000000000..23f04a2015 --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/hsigmoid_yt_50.bin @@ -0,0 +1 @@ +?6V?U?S?=M?;?3P?;?E?Ln?u?!?V??sW?9_?e?}H?h??X=? ?%??Y1?[s??c??t{?Ո?7=DK?eW???>?kcY?S???_fQ?u%?-u?}??k9??=?? \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/hswish_out_50.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/hswish_out_50.bin new file mode 100644 index 0000000000..6ff3dd84c9 --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/hswish_out_50.bin @@ -0,0 +1 @@ +v=qٽBs>Q=@"\=`ο;?廿? \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/hswish_yt_50.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/hswish_yt_50.bin new file mode 100644 index 0000000000000000000000000000000000000000..b25a5c778789a510adef8e4bfaeab774aed1d472 GIT binary patch literal 40 ycmV+@0N4NF)HlCH`YgY7r^P-AL;$}xK^?zzhQ&QB`aZwGo!vi@=|8_UnDjrLrW9uY literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/lrelu_out_50.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/lrelu_out_50.bin new file mode 100644 index 0000000000000000000000000000000000000000..b13b02ddbc42052e6cec58ba089a97ea76390f24 GIT binary patch literal 200 zcmV;(05|`IG}gN;Uj@98LNvUyuP{J#5J^C&+nCK)#pEyidjF#a*jX-STH}} Cj9#_? literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/lrelu_y_50.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/lrelu_y_50.bin new file mode 100644 index 0000000000..6031302671 --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/lrelu_y_50.bin @@ -0,0 +1 @@ +&5Sa?t?@W,2ս&8?;V?橡?$?5pNF7:?5V:΄?m ,!@`|>Vؚ ?_B?0Խ"?q!>%=,? >Ѓ?;?qGh?7<U>=?-ap?g?>r@X> \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/lrelu_yt_50.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/lrelu_yt_50.bin new file mode 100644 index 0000000000000000000000000000000000000000..7cd15ef7f91202ece4cd01401a6de73b64d1c769 GIT binary patch literal 200 zcmV;(05|{B;Dx>Swx+!`Q{la{uP{J#5J^Cn7BVXRy@4| zo-#n@sUbilM4ETKT;`IWw4d{RGF z{x!bXnsB`b6^%b%(ZW9yFjT(M!=gXq%x}JtA&))=C4WAvj;ueMj*`3#^N2pV&;vk} zJDor3aXG$6XdXZ}|4BX37MQ)jpVdA+)MY>g;H|x3>+nCK)#pEyidjF#a*jX-STH{% C;$l7k literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/relu6_out_50.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/relu6_out_50.bin new file mode 100644 index 0000000000000000000000000000000000000000..0e9de34e838a98b8f169c1d10b4673b62786470d GIT binary patch literal 200 zcmZQzK!B7zFYLYCC)>kBB1GKmB{Hvr`Roz=4!ZV+4j{R!hm!2iU)X4G6m4yv`TLH2 zQ0p_h?qF`P97z7I*(tCdyU+x<7)bnqeYh=%27$yIq7IK+zr=v*USsdwhMg#7Xz93!2Y@o%kBB1GKmB{Hvr`Roz=4!ZV+4j{R!hm!2iU)X4G6m4yv`TLH2 zQ0p_h?qF`P97z7I*(tCdyU+x<7)bnqeYh=%27$yIq7IKxY`R0+;BEb zJLimK`rGRQcEgW literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/relu_yt_50.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/relu_yt_50.bin new file mode 100644 index 0000000000000000000000000000000000000000..dc7098eca0e8ef210e6b3f762d83b8a78c06fd7e GIT binary patch literal 200 zcmcbAW4Ha8j{^3wxY`R0+;BEb zJLimK`E >Jn>bK>8=

&>g>];>Q>I>=\>S> ŀ=C*>K=n>Iy>>l>/=>rp>>>( >[>->{j=4>C>e>D>B==x>/m>vj>P>v=Pʕ>=3>vN= >ӂ> \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/sigmoid_y_50.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/sigmoid_y_50.bin new file mode 100644 index 0000000000..9e3724e2c0 --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/sigmoid_y_50.bin @@ -0,0 +1 @@ +w>>XO>?>h>=%?o:?9>"q=7> >?? >9?{>t?D2\?J>n>1>>OF?/?7y?J0?eT?A?F$>'>Ab>#?"m@>$i>8?*C?)>r3?ᆒ>X?9y>>^2>S??w!'? \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/sigmoid_yt_50.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/sigmoid_yt_50.bin new file mode 100644 index 0000000000..ca66395f8f --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/sigmoid_yt_50.bin @@ -0,0 +1 @@ +wa?"?XOo??Q?>E>?o?9i?"qv>> u??? W?9?>t?D2?>n8?>o?O?/Ǚ?7y?J?e?A?F$&?'?Ab_??"m>˼?? ??>$>?*?)l?r??X?9>??^>SԿ?w!? \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/tanh_out_50.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/tanh_out_50.bin new file mode 100644 index 0000000000..9e3e18c43c --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/tanh_out_50.bin @@ -0,0 +1,2 @@ +@?^*Su>?(1?Y?O]>8>yͽh>Y:ן<e +?@?C?C?6GUp>_=I 0`>0>ݎ9?;?Gs*>e3>?ʑ>;?(,?&3*?C?Cw<2?=K>%HC%8?M>~>'u>JI>^4YuZ? \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/tanh_y_50.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/tanh_y_50.bin new file mode 100644 index 0000000000000000000000000000000000000000..0a9a479053216ca28ee149d7a28170c1f82b3ecb GIT binary patch literal 200 zcmV;(05|_u3<5uu#67>EVkti###Fyvw>Up*h($jt<6u7|U1vY8Yfims)ayNmXzsr9 zy?#G-e^EaGLLWb$b8EjB>0wX>H3@g9MS5Uv6;$T0iibXzm6fi#@G4ej2 zm~=n-Ep|T*RYpHt@f1GlV(~sjmd-wd+rhrZwFH(AP_({t C`&L2# literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/tanh_yt_50.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/activationGrad/tanh_yt_50.bin new file mode 100644 index 0000000000000000000000000000000000000000..7323533d2f7db7e605f0718712a06a961f732344 GIT binary patch literal 200 zcmV;(05|_u41zzE#J#_vVyQnL#?-%Fx41uRh{ZoD*hj znDjsTE%rYRRmMMD@svL5VsSr3mQFu|+d;p^wTix{sLelMSBXC$Yl^=queU#Dbn!h+ zPY6FiCZE6gF!sOWZ)ZPm#@s)bjp@Ili-A4_B?mt_3NgR^UGhJ?DDl52rzk%rP&B_2 CfMZSo literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_dw_32_3_3_3.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_dw_32_3_3_3.bin new file mode 100644 index 0000000000..e69de29bb2 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_dw_g3_18_3_3_3.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_dw_g3_18_3_3_3.bin new file mode 100644 index 0000000000..e69de29bb2 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_dw_g3_d2_18_3_3_3.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_dw_g3_d2_18_3_3_3.bin new file mode 100644 index 0000000000..e69de29bb2 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_dx_1_28_28_3.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_dx_1_28_28_3.bin new file mode 100644 index 0000000000..e69de29bb2 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_dx_g3_1_28_28_3.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_dx_g3_1_28_28_3.bin new file mode 100644 index 0000000000..e69de29bb2 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_dx_g3_d2_1_28_28_3.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_dx_g3_d2_1_28_28_3.bin new file mode 100644 index 0000000000..e69de29bb2 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_dy_1_28_28_32.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_dy_1_28_28_32.bin new file mode 100644 index 0000000000..e69de29bb2 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_dy_g3_1_28_28_18.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_dy_g3_1_28_28_18.bin new file mode 100644 index 0000000000..e69de29bb2 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_dy_g3_d2_1_26_26_18.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_dy_g3_d2_1_26_26_18.bin new file mode 100644 index 0000000000..e69de29bb2 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_w_32_3_3_3.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_w_32_3_3_3.bin new file mode 100644 index 0000000000..e69de29bb2 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_w_g3_18_3_3_3.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_w_g3_18_3_3_3.bin new file mode 100644 index 0000000000..1dc4bf74d8 --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_w_g3_18_3_3_3.bin @@ -0,0 +1,4 @@ +F .N2?󻾩`?ͽؿSį2xR=}%T?9>R?Eÿ?>?@<*Fs?h>۾i) W>+ ;=y@\?V=~?)оϬ?HF}?տի?F꓿E +?Gÿ#μ>PD>>J?gNY, <ֈu?Y_"4?fx Y7;¡̾?)???]@-/zb?Ye?M /6?"?t?T?; -1?,6?.>n>8D?Ǿ +F+j?~B? +P??t ek?I?WJ>&? ?;;隿j =sg?[k?r?ݖc>.ljy?D>S¿?l?rSq?#m(@_?>l %6?h%k>=4?ŋoJs>fW?8c;??k:?bQ1Y>yp>nW= z|S:?P?r?K?kw>->V?~> \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_w_g3_d2_18_3_3_3.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_w_g3_d2_18_3_3_3.bin new file mode 100644 index 0000000000..e69de29bb2 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_x_1_28_28_3.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_x_1_28_28_3.bin new file mode 100644 index 0000000000..e69de29bb2 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_x_g3_1_28_28_3.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_x_g3_1_28_28_3.bin new file mode 100644 index 0000000000..e69de29bb2 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_x_g3_d2_1_28_28_3.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_x_g3_d2_1_28_28_3.bin new file mode 100644 index 0000000000..e69de29bb2 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_y_g3_d2_1_26_26_18.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/conv/convfp32_y_g3_d2_1_26_26_18.bin new file mode 100644 index 0000000000..e69de29bb2 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/matmul/matmulfp32_a_10x4.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/matmul/matmulfp32_a_10x4.bin new file mode 100644 index 0000000000000000000000000000000000000000..9d152d6f6cdf16f555e2edf864c494d7ed06ed47 GIT binary patch literal 160 zcmV;R0AK$SJ_A2+lW4x#x+c9nWdXe)Ugth&pEN)2ORzs7n2o-JPWZl#V2D1mO`g9( z!ehTkwDUd$S|PrZP@_J4jBLNP@o2t+uS-7wEtbEaje0(gjJ!SB2PQs8hMYeyg_}R& zX(Yciikm;&b_qayUgti8PWZk^wDUf-@o2t|jJ!SJX(Yd!%Z5LDIF~=)JH5YflW4wZ zpEN&?V2C~hS|PrIuS-AK2PQr=ikm-*K2ScvxY5YEIhE4|n literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/matmul/matmulfp32_b_10x5.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/matmul/matmulfp32_b_10x5.bin new file mode 100644 index 0000000000000000000000000000000000000000..a6df1ed831a045b7950ad2a3d0a285e242924003 GIT binary patch literal 200 zcmV;(05|_)vB5u)`LaH2i!(nyf+9b&X+Xayzg@pIkOM$*L=C{SkJY|#g`L0qKIFe_ zQj$NH@r6IqfY!gS($BuSVQs%=qzFCohAqF}O;Ep9o1;IUL7u;zmQuf1n@zucsHQ&L zr4Bx)IC?%Q={!DiVYNP!A?H4Gr362cUMoN6V1qx@@NU1O_7Xo&?OwhK>T11PA$dOl zJ+{Bwq1L_LBTv4&b&bDYLI*#G8VT12ab&bChIj}#G`LaGW zkOM$$Qj$MrqzFBomQued={!E?V1qwfA$dPvLI*!jNuIuJi!(oQL=C`~@r6I~hAqEX zn@zuRVYNQg@NT~VJ+{Ax8V literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/matmul/matmulfp32_c_4x5.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/matmul/matmulfp32_c_4x5.bin new file mode 100644 index 0000000000..183a9f0ba5 --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/matmul/matmulfp32_c_4x5.bin @@ -0,0 +1 @@ +.@8|A-=,fAQ>2@dui}?t4@@2zN@ԣx@&(ӂe@g \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_10_dx1_5_4_6.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_10_dx1_5_4_6.bin new file mode 100644 index 0000000000000000000000000000000000000000..fcb5df39266ce621bdb133949f02f82f5fb4d302 GIT binary patch literal 480 zcmV<60U!Q9oOi!ghLk}7&*DLO>oGsli$B5dhP6W;3j4pkbs55%>6X6g{}jF-xz54J z4va%uhQYwh#*{%o<99%2^t-*GyqUnosJOz)F~z>k{=UI$WSv2w)1*D?B!|Jsf)K=2 zdz?P@PE|f)l@3AM{OLjDUeQ7cOy$84ON+n#_U1lLCk4XAbdtXs^YTL3)#<_8J*7U5 zgpxme+nK=)$TC0%UADrSB1gbg@asKpLRP=;-m$?jOvXU4hB3n@hBiPO`jEbFbSXdo zpHx8l-i$&1BPhVnTLQr1;|M=-(ab;RhWWogGoe5fN}oXW%wj-Vz?VIo2wT2Rhn_#0 znTA0+J()ni!T`Z*n7BO^!_Ys_s-ZyV<5@xC^#s3&YIQ(;1>Hed#jL+2X>&gvjMu+% zMvgzZO%=f6w4gvAPZ>a|8f!pjwyeG(BN@ML?}EW-EDOPoM0CKk`5r%t^(jD(y9K|A zX7j+3=}Ez>ZbU%C8p*#7a-P4p<66I^PLM$}!;m}&>SjO5b34K(Sr@>R#DhP#<@vzS zv8p~(+O}sxm>>=gPh%2FO2Vaj*zc7neFr^rA2t&hVCn<>L0P^`sy z*pS2jH;}$s;B!C#U-`fS5d_0PM5)1=LD<3YODw~dvvXB)%A a)<(X!%27a%ijYKnFhD}D(V;)5sIEcz0X~KR literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_10_dy_5_4_6.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_10_dy_5_4_6.bin new file mode 100644 index 0000000000..c68b9c80b0 --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_10_dy_5_4_6.bin @@ -0,0 +1 @@ +&JvBAoL?̓I?̿A6ԽS?d>5?iӿ`@u@G@`M>Av>B)>c@$/AwA˿^ 0kܾȁAfr>0x˿cR?vu=`,>pŔ?aK@y?׾db3?@ڤeK?Ч9)?uu@?"=P>b>v@Nl@ÐU>ot ?*@y ; @Av_ 俶\q?w@0ݻj?Aq;bo,3@I`?3sfl@@I?? AC_>=L@? .@xy`?῿A3 3ˑ?n?.=\B@/A>B_KGF?-^.;?V]?K@z:} QPqH ſ?,@~?LP>7>Pq@P>@ \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_1_dx2_1_6.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_1_dx2_1_6.bin new file mode 100644 index 0000000000..1676dc671f --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_1_dx2_1_6.bin @@ -0,0 +1 @@ +L&h>)A[7?.O2@ \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_1_dy_4_6.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_1_dy_4_6.bin new file mode 100644 index 0000000000..37947edcb8 --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_1_dy_4_6.bin @@ -0,0 +1 @@ +wӿ?8>GF?-^.;?V]?K@z:} QPqH ſ?,@~?LP>7>Pq@P>@ \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_1_x1_4_6.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_1_x1_4_6.bin new file mode 100644 index 0000000000..a093c882f6 --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_1_x1_4_6.bin @@ -0,0 +1 @@ +.%?.s?d-f=<Vnߔ?`Dz?t"?e|>~ ޾I? ??ƽY?3B?Xf \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_2_dx1_4_6.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_2_dx1_4_6.bin new file mode 100644 index 0000000000000000000000000000000000000000..6737f96700fa3514ac6f83dbc461eec7409b3881 GIT binary patch literal 96 zcmV-m0H6Ol$FM)~RZTzu1)RY83Kc*$O_9IW_MW~Rn~Xm(5L7@=M=`&o00h9SlWe~l zslva{?hioth~7R&A7Q|Sy<Hq{bEQ7~P$@t~SC&90 CY%2Bu literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_2_dx2_1_6.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_2_dx2_1_6.bin new file mode 100644 index 0000000000..94bd26e133 --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_2_dx2_1_6.bin @@ -0,0 +1 @@ +2)A%dȑ \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_2_dy_4_6.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_2_dy_4_6.bin new file mode 100644 index 0000000000000000000000000000000000000000..6737f96700fa3514ac6f83dbc461eec7409b3881 GIT binary patch literal 96 zcmV-m0H6Ol$FM)~RZTzu1)RY83Kc*$O_9IW_MW~Rn~Xm(5L7@=M=`&o00h9SlWe~l zslva{?hioth~7R&A7Q|Sy<Hq{bEQ7~P$@t~SC&90 CY%2Bu literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_3_dx1_4_6.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_3_dx1_4_6.bin new file mode 100644 index 0000000000000000000000000000000000000000..6737f96700fa3514ac6f83dbc461eec7409b3881 GIT binary patch literal 96 zcmV-m0H6Ol$FM)~RZTzu1)RY83Kc*$O_9IW_MW~Rn~Xm(5L7@=M=`&o00h9SlWe~l zslva{?hioth~7R&A7Q|Sy<Hq{bEQ7~P$@t~SC&90 CY%2Bu literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_3_dx2_1_6.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_3_dx2_1_6.bin new file mode 100644 index 0000000000..94bd26e133 --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_3_dx2_1_6.bin @@ -0,0 +1 @@ +2)A%dȑ \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_3_dy_4_6.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_3_dy_4_6.bin new file mode 100644 index 0000000000000000000000000000000000000000..a4130257de45f33ca3b375ff3d8d178872776118 GIT binary patch literal 96 zcmV-m0H6Ol$FRTgRZYME1)MD7cbEUrgP$|GgSC+s@ CY%KNw literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_4_dx1_4_6.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_4_dx1_4_6.bin new file mode 100644 index 0000000000..b8cc5229db --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_4_dx1_4_6.bin @@ -0,0 +1,2 @@ +;p +?y=xJɷi<%.ve!?N[@I(*8Iኽ}> $!ÿi>u?JWy?R8]?z{?5> \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_4_dx2_1_6.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_4_dx2_1_6.bin new file mode 100644 index 0000000000..40d97286c8 --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_4_dx2_1_6.bin @@ -0,0 +1 @@ +b殿Q.* (@0˸ok@ \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_4_dy_4_6.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_4_dy_4_6.bin new file mode 100644 index 0000000000..3cac9bfc20 --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_4_dy_4_6.bin @@ -0,0 +1 @@ +ao=XD<ԟо?$_`=US>]%@?,?SG+b>&e+ѿ#Nv1>b?\i׿׺ H|@N?& ?ǖb ?9A{d@uh?wN?3(cvi5Ϙ>t +6?ngZ?> /TA \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_6_dx1_1_6.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_6_dx1_1_6.bin new file mode 100644 index 0000000000..4fe396e1bc --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_6_dx1_1_6.bin @@ -0,0 +1 @@ +YA:ۢA93*B%B \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_6_dx2_4_6.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_6_dx2_4_6.bin new file mode 100644 index 0000000000..35a86f48b5 --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_6_dx2_4_6.bin @@ -0,0 +1 @@ +gE|: J"@۽>'BtpB=?C?[^9Ano*Bļ-hVCDBYD\ۿ \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_6_dy_4_6.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_6_dy_4_6.bin new file mode 100644 index 0000000000000000000000000000000000000000..4bfe040d8ca8e26da89e09f67b3a5ac7b861036e GIT binary patch literal 96 zcmV-m0H6OW6SG0#n`6Il9vHw-Gv~f{2ZBGlcAh{7Cg?!KQdz&dRV_eNOt3ypACEs} zR)xRxhlIfCr({6$&%(e=Ta3QsZ&ttm$E(2S|Kz{w0JK1>2$nz^ya7Qlhs(c2VN5=? CJ1?yO literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_7_dx1_4_5_6.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_7_dx1_4_5_6.bin new file mode 100644 index 0000000000000000000000000000000000000000..32e73ebd1a59a71d7b9cafad77c73a29792021d2 GIT binary patch literal 480 zcmV<60U!RULtDSv!)QT(W0gQ#Aw9pM>E*tclrzH~{HMPyG+jcqr|-Z#t&u-v2SdJR zXfZ`TQRP2iH&{ZCc0oWVLKQxJO+&v^_ya|x!Q{WNjKjd2g?vAUWZS0_-HS#{8mIgjSfdEEdbdx_D6xqOhBSygReEq)Z<5<7;!8t}2)6Kt^sFgvT zJlMdD7L~q1nMywn8SKOxUoOAOGNVG&U3);8XRg133MIc0Hn_!<;#$DOo2EixXyL!% zZ128l%5c8HKn+GD&3eCJ>!?BGet5vZZ!W*dZWTXrv@}G-kTJi!>;J($F<8Lt?=C+Y z;E+BW!N5g|b&bD|D2%|HajU@aXHvfu!i2vRk}JhWAm+XtV2(jWszg9jq>8_shnzkP zR~SYHhZaB*6zM?-%AP>f5!ydYt3dsjR^2&)YxH5YWC7 zH$y_zmhHclR3AZ|VGBTYH(@@PThPC3HxWV&0_{KC8IZp*?lnKS7}mY*gmJ$%JiI~z zGPSm5)A9XAMIG#+bi7_n*JXR`88tw8lmo!S60pCHv&zEN$6`QejCDaDMe%?!WZzNtcz4X(ai W8a_Y<&)+}j1qi?NWւpټR4=p?v֥?RݾQ>(v?pj?H?G)>I޿ʟ>u{`Խ>Ԁ!O?9;>c>?\7K?cb_?.kuS=j?1=y? p)P?=V ?.>ј?H?*wMH ?\q>(z࿣?-=? y?ƿ׻+ _?dGp X?Qt>F?N=N +Yn`%G?)$?Jdi?7"8){oϾ w>(L?Pԝ'2?u?2?">!פ???<߾f?9F&QEE}<:G>.}.S?\̿K?*V%?Q꿹uyC7:?T4>`>o>!?>;y_ \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_7_x2_1_1_6.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_7_x2_1_1_6.bin new file mode 100644 index 0000000000..b0921a2d80 --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_7_x2_1_1_6.bin @@ -0,0 +1 @@ +<>o8?#?d@ٌ< \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_8_dx1_5_4_6.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_8_dx1_5_4_6.bin new file mode 100644 index 0000000000000000000000000000000000000000..199d5821733aa9fa063141ad08b318b442d5a522 GIT binary patch literal 480 zcmV<60U!RN_Iy7mCLTYYGKWCYY7{})o;ttP9TPzKw5C3re=)#O3oAd&WP(6_xEH|k zGTuL6dKth7p&mb>!_6aY;ZXC9gnE;HST2$b!IC z%Va<(3mCvTHK9Mz9-Kg4GgCl>-zvbkQyD*ZC-lE&P6NOx02e=go^e1aA1}buA!k4U z<`KUZ<8r?`pprkZsSm)C-lIMs#!5iYhK#@nmzTe+8PGqA43@x=N`gP)0v14W$-cjy z7MedDup>Y~Kcc)C74|-LoPY@I-evw*W_UpL)H1-D!y~`jc8oya W3YoovG^f4*nzlSGSQfx*psK%Jq1^TW literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_8_dx2_5_1_6.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_8_dx2_5_1_6.bin new file mode 100644 index 0000000000000000000000000000000000000000..ea5dbc6a93c0f4d62a7f5edfbbe453ce12661a1b GIT binary patch literal 120 zcmV-;0EhqNV3j^dI6J_o)&oIc@en@A zE`q>@icCQs;Df-bEP+6wy9Gh&sUbm57imCzoqj-AIRZglS&P65Jo!K~kbS`rnfE^> a<*Y#fbb`PDdAz`|{02X|oEpJVFAKry4mGR* literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_8_dy_5_4_6.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_8_dy_5_4_6.bin new file mode 100644 index 0000000000000000000000000000000000000000..199d5821733aa9fa063141ad08b318b442d5a522 GIT binary patch literal 480 zcmV<60U!RN_Iy7mCLTYYGKWCYY7{})o;ttP9TPzKw5C3re=)#O3oAd&WP(6_xEH|k zGTuL6dKth7p&mb>!_6aY;ZXC9gnE;HST2$b!IC z%Va<(3mCvTHK9Mz9-Kg4GgCl>-zvbkQyD*ZC-lE&P6NOx02e=go^e1aA1}buA!k4U z<`KUZ<8r?`pprkZsSm)C-lIMs#!5iYhK#@nmzTe+8PGqA43@x=N`gP)0v14W$-cjy z7MedDup>Y~Kcc)C74|-LoPY@I-evw*W_UpL)H1-D!y~`jc8oya W3YoovG^f4*nzlSGSQfx*psK%Jq1^TW literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_8_x1_5_4_6.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_8_x1_5_4_6.bin new file mode 100644 index 0000000000000000000000000000000000000000..d14440793e805aa258e892763ba286414278fb17 GIT binary patch literal 480 zcmV<60U!S638lUUjtxJ`O5s0qpb0<|V>Q1CshvLtQzyS7LXy8t=asx2gXX?a!o$B= zNpn9z{Q$sr%MCyGI(9ypW0Af;m65)4VW7ThZv(zV2sXb5SDZg$|9(F7^MAjT1^d6N z45vPeu1!9+|FS+66a+vQs=YtqsMfzcvy{K~wB9}yDW|{WR;9f+72H3D=-R)dX0Sea zM~y$}CPBX@)k!}0GNr#*Y&yPN-}^mInNGiEOkcls-QPYh(ICKE-zq*mjGw;5I~PCt zXlp*JMRPwe>_@*A$E3dVr4~O>%eFrqA_~5MFpEC;WxYRuR}VkQ0H-}FdqciJgs(kQ zacDnVG`2ql!lJ+CCCfcyP`W?e{jxreBRoI87aqQC8yi2fb;v))Y$m^yV-G)9NpZi* z7|1`M)`h-_!I3_Vt&>0JehNS?RzbdyUsu1-zUsfmbNs%uOY6UyOuIfNLB2mC6+FK~ zFj~LiAUD69H@!bD?`*%aT`|9f?3up`Tme7}T6#Ui+A%*hfF8diWe&d@Dl0#wQq;d| znUg;X5sW{P$F{!#opnC(Dki@`InBOxr2M{VN{GEA!F;}b7$`s>$%DSm@~J+R>E6D0 W6`DULEkL@-Z!$mmuMWN6O>w+EO5{)g literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_8_x2_5_1_6.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_8_x2_5_1_6.bin new file mode 100644 index 0000000000000000000000000000000000000000..9b6169666c7e2ea3861264db2b9ae128d87e02de GIT binary patch literal 120 zcmV-;0EhoX08u~5>v_J$X|z5tH6K7tC$K&|v#7l)2)jS|z_Gu)YL7nRRlq(wN-REg zC9gj5<-I?f0;|8ic)mU#HK;x_V?{sF=np^1WUM|XL3=-V?~1=pZHGUutk%B_Ve&o> aR472t-JZWybSA!Gl`p@o;*q~J+a|vV>Nw#5 literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_9_dx1_5_4_6.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_9_dx1_5_4_6.bin new file mode 100644 index 0000000000000000000000000000000000000000..5824f414cfa339ade5c4b7008f205129063a623f GIT binary patch literal 480 zcmV<60U!QM0o=ZE>4rTn$=^QX>eN9*#4EmZ?ua}~4PUQ^Gt< zv`9V~rPx0}yG_5jkl#L`N2Wk6EXF-6b0R*w`8&Rb55zv2&$T|_PoTe)@2Eet3t{cTdRRZK{0Kl(1qQvf_yxZUSKdG6WwgKc zL4QG!!&gAPjGDc06=yzg+1J0rU9P^Kb=ts)@=?B>w^h8_CLTZnFe|?zWsp9Cz`(## WTWvtfej>Pw;U_;wS-HKD1x>u?=+?M@,@ @eAOF@ۉ@%AN* ++| \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_9_dy_5_4_6.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_9_dy_5_4_6.bin new file mode 100644 index 0000000000000000000000000000000000000000..dde1dd8cbc6da1c723ef49e774c4e3a368f33ea4 GIT binary patch literal 480 zcmV<60U!QBy#~L8F^ayd#hyQZE-OLnpZUI^%1^%Znuxy%$qqjxNmIO2TMxjbvxdKT zQXsy`ol?MmZHm4!hb=xL*0jIsSxCNmU{gIYoL0WFwXr^vTU*amM_IuBqME-+OFO?tad^EF9uzLb<-Ff8Re$HTmV!N+ zx)?v@d<;O#{Iv+J{EQLP5Joi2j%X7ZNVlF=b{)RsRSEIk4qnp2FN&mmH z%csCVZ+*VhPDDPx@DM=kQ0XPLEgVC0jj3KO4#dN<2prSn;N1Z&%mFXk^ literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_9_x1_5_4_6.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_9_x1_5_4_6.bin new file mode 100644 index 0000000000000000000000000000000000000000..d14440793e805aa258e892763ba286414278fb17 GIT binary patch literal 480 zcmV<60U!S638lUUjtxJ`O5s0qpb0<|V>Q1CshvLtQzyS7LXy8t=asx2gXX?a!o$B= zNpn9z{Q$sr%MCyGI(9ypW0Af;m65)4VW7ThZv(zV2sXb5SDZg$|9(F7^MAjT1^d6N z45vPeu1!9+|FS+66a+vQs=YtqsMfzcvy{K~wB9}yDW|{WR;9f+72H3D=-R)dX0Sea zM~y$}CPBX@)k!}0GNr#*Y&yPN-}^mInNGiEOkcls-QPYh(ICKE-zq*mjGw;5I~PCt zXlp*JMRPwe>_@*A$E3dVr4~O>%eFrqA_~5MFpEC;WxYRuR}VkQ0H-}FdqciJgs(kQ zacDnVG`2ql!lJ+CCCfcyP`W?e{jxreBRoI87aqQC8yi2fb;v))Y$m^yV-G)9NpZi* z7|1`M)`h-_!I3_Vt&>0JehNS?RzbdyUsu1-zUsfmbNs%uOY6UyOuIfNLB2mC6+FK~ zFj~LiAUD69H@!bD?`*%aT`|9f?3up`Tme7}T6#Ui+A%*hfF8diWe&d@Dl0#wQq;d| znUg;X5sW{P$F{!#opnC(Dki@`InBOxr2M{VN{GEA!F;}b7$`s>$%DSm@~J+R>E6D0 W6`DULEkL@-Z!$mmuMWN6O>w+EO5{)g literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_9_x2_5_1_6.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/arithmetic_fp32_9_x2_5_1_6.bin new file mode 100644 index 0000000000000000000000000000000000000000..9b6169666c7e2ea3861264db2b9ae128d87e02de GIT binary patch literal 120 zcmV-;0EhoX08u~5>v_J$X|z5tH6K7tC$K&|v#7l)2)jS|z_Gu)YL7nRRlq(wN-REg zC9gj5<-I?f0;|8ic)mU#HK;x_V?{sF=np^1WUM|XL3=-V?~1=pZHGUutk%B_Ve&o> aR472t-JZWybSA!Gl`p@o;*q~J+a|vV>Nw#5 literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/biasgradfp32_1_db_7.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/biasgradfp32_1_db_7.bin new file mode 100644 index 0000000000000000000000000000000000000000..46853507f8e63a02e44b66514730cffc2c388d75 GIT binary patch literal 28 icmcb>)_jNo2pZoj9A3-R;B?Vn{4ldt!QuSC#zO#^91A@F literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/biasgradfp32_1_dy_10_28_28_7.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/operators/biasgradfp32_1_dy_10_28_28_7.bin new file mode 100644 index 0000000000000000000000000000000000000000..c079b77a367c198c8b6da19257eb43ca89f5d605 GIT binary patch literal 219520 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Μ2z}%?1PQx7|T{?ES$Jq;8}Zy@)GxK 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%0DcxRqs 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 [?Q=?56>ȭ? \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/pooling/avgpoolgradfp32_1_dx_1_28_28_3.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/pooling/avgpoolgradfp32_1_dx_1_28_28_3.bin new file mode 100644 index 0000000000000000000000000000000000000000..e5d086ef061316adad5650c336a9ff7ce158c8e3 GIT binary patch literal 9408 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 literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/pooling/avgpoolgradfp32_1_x_1_28_28_3.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/pooling/avgpoolgradfp32_1_x_1_28_28_3.bin new file mode 100644 index 0000000000000000000000000000000000000000..d32ffbe755462f66fdb69c3585ca43e787be2296 GIT binary patch literal 9408 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 literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/pooling/maxpoolgradfp32_1_dx_1_28_28_3.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/pooling/maxpoolgradfp32_1_dx_1_28_28_3.bin new file mode 100644 index 0000000000000000000000000000000000000000..cca67a85df1163f95027823b6502328f323f4555 GIT binary patch literal 9408 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 EzndwMv;Y7A literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/pooling/maxpoolgradfp32_2_dx_1_30_30_3.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/pooling/maxpoolgradfp32_2_dx_1_30_30_3.bin new file mode 100644 index 0000000000000000000000000000000000000000..e2ee3307f9f464025eea0a473e7921a1c0ce282c GIT binary patch literal 10800 zcmd5>X;2hL7+nDoF$D%FM1_b% zXha+wrMQ8eXTQOE3^0)=0$u z^{NyZOZb>6u+;{PN&lM{A8;TYi*eT92bjEy)^D60Dwyk>O9B!b+G>Tg-|d-+w2KCi z`n+yp$AzLTID7+YHzha~s#7>BpXQdx@}JIjVA*bK=0UbCg=?Yus8g#!PM!p^i7+Ym zcO6cg>Y>p{f1&qgpi_68a}1^wKIHUcB>iXRYUzGt-v%n6scfP`yphk<<%)az!+1`- zL6htq5btF_r?OV|yVkW}8xWgWAUQ|O{s3tg@g$qp>*PCNq16t(3sni)ynN?ZP3Oh% zG(TW>P)7-*n;`5w=?jDsH$~18jD42BLJ&4%oCWY3J(Uyt{e13sgV3L-+9$4?X2I$o z;iISEW8Q#X=PO@ZVhMCjC&?8oBUSD@(7$?3aRTngN(ZwL`Zh`fgGR51o^%T+*whwDuOoD+)u)wn2dQvtTEWP|31rx;)_p0pG#5Lf!Gdy zBRjvKIQFmg11P(qHp4bUPQKttQcgc#yY+PwIOCmSgs)w$sjtK_Pw{&XE-h{8If9-s zox|xv{Cq^m4Yce~sR6h+j9cTt(fhyg>NguJd~SA+apY{1OOGPHI!|+O=OlbTUjN?YsDel18-V5RQRKL2wPjO!BTv+?p9=sST{?H-*y_;GGo3Aa(0NF-R-V)MoBvt*_->D&d zEE?5ZzydA!PFy4))#jE%&uek{7i9bTr}sd1CY97mo5V5ge0A`&zkeufoT2bOQ}N9v zNgz0651{JG$bFBlQ!1alnmV7F3`+Y|5_gDq`;i!^E@Gs)m-cbK2NXOuq!Wu<9mW0M zt0^`B>yN>E?y8NRkgm%Xb|AJEzT>>Dkqj~p!*^M+683&_)(hcx0AXqP`=?XO&d;Fw zi_3?*t3bMOxRH@dcyTL@#Jm_Lzsiq^*yq5+4o1D{%t~NV0-uq$-O3l-kEqNH66^2n zBshlX$CL0RWWS?ygXH2NxcJg|r-guyd92MnR}$ES3fbBpwE)hOr;~AEfN>d#)DofOidH_93vUMXvE=#xv{7 zYU}{hCU3oTx@;fopfM54m7Tl^ME8ur`sr=ncbBcvbGG-0ecxDOV=ns?V|{c!s{BTz zoIA6th44Ou;1B76_ajuBxcpoJ`|b~iRm8qB5x(o%p!*e2goldJaWsV9yCi38&^3hn zd3LC??`pO5`tMF`uFJluq}_|aYAa4{!ukkp4b|-L>}4J`kX8amPts|!Gj_{Mc&%<~ I$FFJs0DJH5<^TWy literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/pooling/maxpoolgradfp32_2_dy_1_10_10_3.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/pooling/maxpoolgradfp32_2_dy_1_10_10_3.bin new file mode 100644 index 0000000000000000000000000000000000000000..0985d76b035273333eb1f6f69b1276a3f4aecda6 GIT binary patch literal 1200 zcmV~$2{adW0KoA=5n zvBQOJ_620?<`BCtokq(wbY~dzrm>RNih1NciW8@&mE!ejOq6=X5cVXA#*lLUd*2}J zuf>SaL0j|-Ka012dgJ@o4WYT%zf2LE|f`_dwwhBl~S^5Qt4}4$el|wsQ5>d z%dVLy9@it`jWW@L*3|fYk7m~y@o>V2#WhdGr(aDFht3GyJ}HfZGNyd*im|nO5ayOt zpSVL_L_TWEXS38@hV5XdXp~{o0(asLy+DQf`i6Iv5_Sj{UIb6+p#q$8k?u4Z0a6kU4{_~QVC79<`ib+qH(`R z47~Q>gF^~^4PFF(Uxu~ILt(amF^Amjk-k$$7PuRu_~kt7eCxQk&*J8+6^s}EAzBaSQYKYkIM5Z zswU-X2Gb;F94aZ}-@$CoriHQct5}Lx)e7wgc^p3SSiIPl$F4L#Vn(aU$k8LWq(fvY zwFsvf&&A#4acd zAp_J0REbz5r)5}%q(z1Ci~@`Y(>e9{Z*eu+j_$4nn9s|@IawXgWGANNaU{Q*jZ^fH zaLa!$7VZn6>C2-G6_yLf4_>4m^J3a`LtG_}#3?k0!|iMl9_cws14B)oD1 zlT~XNRmnoj@~qG`o5fo7RC>k>M6Z%7Q`f(yqoPTi(##?tDFU4fMPhx^H^{9ucxhpS zxAuJ6c7&ppqXw@OndPZKxt1p7IYSW--{_$*$=<%p9uoAG;*NupLbinljX;p@Zt<`5>8t=SYZ7Zc}5nte*e zZ4|Q!@Sk0{(33d5>G>cKj3p~*GY#R%n00(Y!Ocg)a$P=^t&NmsWeA7#e8McOxf78~uhl8>?;#WP z6pd^+zm+T7<>;)tg~l#`MG7y*sPnj6*~sV+Gp21U7gmFgEFQWk8qWu^H$uwvSXa^) z*-+H916iRzGTBPZO*5&kZlhsVr07u8arL@{b^2ekv)UWyU3pCKHy|uy4{1|!P=$Gr zl4OVSsG6mHuZ67TnE1!U8skWfc;GvQ{uS~-v8uRf;TJ%!VXrF2c&BK~|@%jF-l zNgQ6xjwMz+Ip{->!jXZ*D$;t!(ezh6hB;;Uj4Yz?;R6w8-z&!Z?Iy(1k=&~l;{6wk zY5F#Vn5brQCkrsuF&OX4)T$vd%RtGc^%g`Ff5CyQP`slP`1JNgVcPti`0YhH;})y& z%wZIW6qAq67`GbBTXwsUGhTQx}{HMZ7Rxl zm1Gsnpt(AjqhpLX5FALC&KZ@#hrGODi7sp*b9{<~boExUz2ulbUxwa==~&CQksw#m z9g56|vK|R)iTFFkzpP4IXkNS~GS# z8Dds;U)b1cIeftjhZTWDpNq!KvPO*eHK5Nvp8fN3#N)P;)a$#@6uE-s?>UjunZy~1 zGgVO@L=Q~kZp$!+ry8Nm2&He6J&&X^5`UPE`6Lg{h^c5+J5o1L#{w@4mKm1fy4H^l zO)2fkrD7;F9Q9xj@_}w~u6+)*&gOXA8IrM9O}6kQLC=ZtZc+l|^O<(1xG z_iuBa^{Bbgx|i0x8s2)85uRzvJBK3)OfMFOop!8!Q_k~@3JzUp5EWJq?5LCCch-lH zpQ4aeT^Finfp{k9M1Hv*MOR&zef**5&CEioiK3x9fZ1Aa{L04Sw$2Hox#z{^M1A7h z(lL#XBgaX`8m*dLX{W`g(H6w@9N}KMHw6)uV$}jU>*t%1?fC&+lYQ{mvl>-PJgDNE+eJP|Pa+14z-=KL7v# literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/pooling/maxpoolgradfp32_2_i_1_10_10_3.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/pooling/maxpoolgradfp32_2_i_1_10_10_3.bin new file mode 100644 index 0000000000000000000000000000000000000000..d5647f32dc7d45efa3283cbf26ec277dd030e70b GIT binary patch literal 2400 zcmZ|NTWF7A0LO77=ggWzTbs$5MJPjB4lQP7qNaw?oEpVU+gN59S|rI0a#)UIhP5)s zaKsOUs!j?VtQRwd)47a!9L5zK!I2!zl}u$O$M7t7 z2fbeJWwiI{i`>Y19^hp*a5GDIh>g6;a$e_A9^-M|;z?F=C#(Krr_PZN-Q@f)-!aDd z9o6)bH!+QqxrkF($}246K_2Ec9$^JZE4YbQxt%xJ#&-VVZ~kF3KQJ!3^UWiIeoWf~L;w+BfSkB`F9%2Qz zu#UwnWi@y6Ecf#rV`4hL_yaj!ek}Kq`|^c(qWoH3E|27Bj^kRUa3YJil-pUtTinCF zyvrsY=22GiAzS&K17bUW_e=Q=|FM~|p6kvQ^96D$Co_l3n9B^7aW2clx%(qVMfPL9 z^GWQ_(2wczOqMc_t69#2JjBhc}r23alVx4T)|b$=RO`_A&XeaI_}_iM(&T$k9W?a+>fw7BKz^pb76n<_k7qN zgXN)2W*$R7vg8Fk$QoW@=tq@Y!dtB89fp21$@ln)J=~8L`5D9h=#U3`?ya0FuVg0k z8TwHuZ)6T5`*FfN?2l^s49~NXH9W#PUS}JB@CC#EcqJ#fukYoL9An;-UG-y%^KC3< L=*Jv6lk4~&-sOz= literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/pooling/maxpoolgradfp32_2_x_1_30_30_3.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/pooling/maxpoolgradfp32_2_x_1_30_30_3.bin new file mode 100644 index 0000000000000000000000000000000000000000..61cfb07fdb62835ef471cc0b277cb50fae2ee0e7 GIT binary patch literal 10800 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 literal 0 HcmV?d00001 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/power/powerfp32_dx_scale5_shift2_power3.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/power/powerfp32_dx_scale5_shift2_power3.bin new file mode 100644 index 0000000000..0bb3ced765 --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/power/powerfp32_dx_scale5_shift2_power3.bin @@ -0,0 +1,2 @@ +NG^aFN.cJ5G +WExeء?wDRGTEAC_>YHÜ*IIM.IEB:g$IHpñ BFCBtHjC{@FIW>tFӦJE1F x3E~#)JIE4'nIB \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/power/powerfp32_dy_scale5_shift2_power3.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/power/powerfp32_dy_scale5_shift2_power3.bin new file mode 100644 index 0000000000..b1e404b742 --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/power/powerfp32_dy_scale5_shift2_power3.bin @@ -0,0 +1 @@ +N#LSRDi] Bo;Eg9WNA{CB@I4~D>PD DSpBH  VNLDCm B*l A֓\@iC AB^tB+3ECOAs`D3DeB~D`v@: \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/power/powerfp32_x_scale5_shift2_power3.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/power/powerfp32_x_scale5_shift2_power3.bin new file mode 100644 index 0000000000..d902be1588 --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/power/powerfp32_x_scale5_shift2_power3.bin @@ -0,0 +1 @@ +h)jr_O%?"=|;9$>=Dw9u??PҴ?~q<= BͿ9Ċ?,?6>8$du5?gb>")H`>q?I>.=,%?$!Y>H?| \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/train/train_bias_10.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/train/train_bias_10.bin new file mode 100644 index 0000000000..527f9f7399 --- /dev/null +++ b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/train/train_bias_10.bin @@ -0,0 +1 @@ +>SY@+[Kc߾&O?-?Qjt? \ No newline at end of file diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/train/train_input_32_1000.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/train/train_input_32_1000.bin new file mode 100644 index 0000000000..e69de29bb2 diff --git a/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/train/train_weight_10_1000.bin b/mindspore/lite/test/ut/src/runtime/kernel/arm/test_data/train/train_weight_10_1000.bin new file mode 100644 index 0000000000..e69de29bb2