// Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved. // // 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 #include "lite/core/op_registry.h" #include "lite/kernels/arm/elementwise_compute.h" namespace paddle { namespace lite { namespace kernels { namespace arm { TEST(elementwise_add_arm, retrive_op) { auto elementwise_add = KernelRegistry::Global().Create("elementwise_add"); ASSERT_FALSE(elementwise_add.empty()); ASSERT_TRUE(elementwise_add.front()); } TEST(elementwise_add_arm, init) { ElementwiseAddCompute elementwise_add; ASSERT_EQ(elementwise_add.precision(), PRECISION(kFloat)); ASSERT_EQ(elementwise_add.target(), TARGET(kARM)); } template void elementwise_compute_ref(const operators::ElementwiseParam& param, const std::string elt_type, const std::string act_type) { const dtype* x_data = param.X->data(); const dtype* y_data = param.Y->data(); dtype* out_data = param.Out->mutable_data(); auto x_dims = param.X->dims(); auto y_dims = param.Y->dims(); int axis = param.axis; if (axis < 0) { axis = x_dims.size() - y_dims.size(); } int batch = 1; int channels = 1; int num = 1; for (int i = 0; i < axis; ++i) { batch *= x_dims[i]; } for (int i = 0; i < y_dims.size(); ++i) { channels *= y_dims[i]; } for (int i = y_dims.size() + axis; i < x_dims.size(); ++i) { num *= x_dims[i]; } // do elementwise add/sub/max... if (elt_type == "add") { for (int i = 0; i < batch; ++i) { for (int j = 0; j < channels; ++j) { int offset = (i * channels + j) * num; const dtype* din_ptr = x_data + offset; const dtype diny_data = y_data[j]; dtype* dout_ptr = out_data + offset; for (int k = 0; k < num; ++k) { *dout_ptr = *din_ptr + diny_data; dout_ptr++; din_ptr++; } } } } else if (elt_type == "sub") { for (int i = 0; i < batch; ++i) { for (int j = 0; j < channels; ++j) { int offset = (i * channels + j) * num; const dtype* din_ptr = x_data + offset; const dtype diny_data = y_data[j]; dtype* dout_ptr = out_data + offset; for (int k = 0; k < num; ++k) { *dout_ptr = *din_ptr - diny_data; dout_ptr++; din_ptr++; } } } } else if (elt_type == "mul") { for (int i = 0; i < batch; ++i) { for (int j = 0; j < channels; ++j) { int offset = (i * channels + j) * num; const dtype* din_ptr = x_data + offset; const dtype diny_data = y_data[j]; dtype* dout_ptr = out_data + offset; for (int k = 0; k < num; ++k) { *dout_ptr = *din_ptr * diny_data; dout_ptr++; din_ptr++; } } } } else if (elt_type == "div") { for (int i = 0; i < batch; ++i) { for (int j = 0; j < channels; ++j) { int offset = (i * channels + j) * num; const dtype* din_ptr = x_data + offset; const dtype diny_data = y_data[j]; dtype* dout_ptr = out_data + offset; for (int k = 0; k < num; ++k) { *dout_ptr = *din_ptr / diny_data; dout_ptr++; din_ptr++; } } } } else if (elt_type == "max") { for (int i = 0; i < batch; ++i) { for (int j = 0; j < channels; ++j) { int offset = (i * channels + j) * num; const dtype* din_ptr = x_data + offset; const dtype diny_data = y_data[j]; dtype* dout_ptr = out_data + offset; for (int k = 0; k < num; ++k) { *dout_ptr = std::max(*din_ptr, diny_data); dout_ptr++; din_ptr++; } } } } else { LOG(FATAL) << "unsupported Elementwise type: " << elt_type; } // do activation relu/sigmod... if (act_type.size() > 0) { if (act_type == "relu") { for (int i = 0; i < batch; ++i) { for (int j = 0; j < channels; ++j) { dtype* dout_ptr = out_data + (i * channels + j) * num; for (int k = 0; k < num; ++k) { *dout_ptr = *dout_ptr > 0.0f ? *dout_ptr : 0.0f; dout_ptr++; } } } } else { LOG(FATAL) << "unsupported Activation type: " << elt_type; } } } template void elementwise_fmod_compute_ref(const operators::ElementwiseParam& param, const std::string act_type) { const dtype* x_data = param.X->data(); const dtype* y_data = param.Y->data(); dtype* out_data = param.Out->mutable_data(); auto x_dims = param.X->dims(); auto y_dims = param.Y->dims(); int axis = param.axis; if (axis < 0) { axis = x_dims.size() - y_dims.size(); } int batch = 1; int channels = 1; int num = 1; for (int i = 0; i < axis; ++i) { batch *= x_dims[i]; } for (int i = 0; i < y_dims.size(); ++i) { channels *= y_dims[i]; } for (int i = y_dims.size() + axis; i < x_dims.size(); ++i) { num *= x_dims[i]; } for (int i = 0; i < batch; ++i) { for (int j = 0; j < channels; ++j) { int offset = (i * channels + j) * num; const dtype* din_ptr = x_data + offset; const dtype diny_data = y_data[j]; dtype* dout_ptr = out_data + offset; for (int k = 0; k < num; ++k) { *dout_ptr = fmod(diny_data + fmod(*din_ptr, diny_data), diny_data); dout_ptr++; din_ptr++; } } } // do activation relu if (act_type.size() > 0) { if (act_type == "relu") { for (int i = 0; i < batch; ++i) { for (int j = 0; j < channels; ++j) { dtype* dout_ptr = out_data + (i * channels + j) * num; for (int k = 0; k < num; ++k) { *dout_ptr = *dout_ptr > 0.0f ? *dout_ptr : 0.0f; dout_ptr++; } } } } } } template void elementwise_imod_compute_ref(const operators::ElementwiseParam& param, const std::string act_type) { const dtype* x_data = param.X->data(); const dtype* y_data = param.Y->data(); dtype* out_data = param.Out->mutable_data(); auto x_dims = param.X->dims(); auto y_dims = param.Y->dims(); int axis = param.axis; if (axis < 0) { axis = x_dims.size() - y_dims.size(); } int batch = 1; int channels = 1; int num = 1; for (int i = 0; i < axis; ++i) { batch *= x_dims[i]; } for (int i = 0; i < y_dims.size(); ++i) { channels *= y_dims[i]; } for (int i = y_dims.size() + axis; i < x_dims.size(); ++i) { num *= x_dims[i]; } for (int i = 0; i < batch; ++i) { for (int j = 0; j < channels; ++j) { int offset = (i * channels + j) * num; const dtype* din_ptr = x_data + offset; const dtype diny_data = y_data[j]; dtype* dout_ptr = out_data + offset; for (int k = 0; k < num; ++k) { *dout_ptr = (*din_ptr) % diny_data; dout_ptr++; din_ptr++; } } } // do activation relu if (act_type.size() > 0) { if (act_type == "relu") { for (int i = 0; i < batch; ++i) { for (int j = 0; j < channels; ++j) { dtype* dout_ptr = out_data + (i * channels + j) * num; for (int k = 0; k < num; ++k) { *dout_ptr = *dout_ptr > 0.0f ? *dout_ptr : 0.0f; dout_ptr++; } } } } } } template void elementwise_fmod_compute_ref( const operators::ElementwiseParam& param, const std::string act_type); template void elementwise_imod_compute_ref( const operators::ElementwiseParam& param, const std::string act_type); template void elementwise_imod_compute_ref( const operators::ElementwiseParam& param, const std::string act_type); template bool is_fp_close(T v1, T v2, T rel_tol = 1e-4, T abs_tol = 1e-5) { bool abs_chk = std::abs(v1 - v2) < abs_tol; bool rel_chk = (std::abs(v1 - v2) / std::min(std::abs(v1), std::abs(v2))) < rel_tol; return abs_chk || rel_chk; } template