From 9b031026d69988eaa792115a960872ba9e0ccf9b Mon Sep 17 00:00:00 2001 From: cifar10 <41565156+cifar10@users.noreply.github.com> Date: Tue, 21 Jun 2022 14:58:21 +0800 Subject: [PATCH] add mlu expand_as_v2 kernel (#43393) --- paddle/fluid/operators/expand_as_v2_op_mlu.cc | 99 ++++++++++ .../unittests/mlu/test_expand_as_v2_op_mlu.py | 181 ++++++++++++++++++ 2 files changed, 280 insertions(+) create mode 100644 paddle/fluid/operators/expand_as_v2_op_mlu.cc create mode 100644 python/paddle/fluid/tests/unittests/mlu/test_expand_as_v2_op_mlu.py diff --git a/paddle/fluid/operators/expand_as_v2_op_mlu.cc b/paddle/fluid/operators/expand_as_v2_op_mlu.cc new file mode 100644 index 00000000000..dfdc134ffab --- /dev/null +++ b/paddle/fluid/operators/expand_as_v2_op_mlu.cc @@ -0,0 +1,99 @@ +/* Copyright (c) 2022 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 "paddle/fluid/framework/op_registry.h" +#include "paddle/fluid/framework/operator.h" +#include "paddle/fluid/framework/tensor.h" +#include "paddle/fluid/operators/expand_as_v2_op.h" +#include "paddle/fluid/operators/mlu/mlu_baseop.h" + +namespace paddle { +namespace operators { + +using Tensor = framework::Tensor; + +template +class ExpandAsV2MLUKernel : public framework::OpKernel { + public: + void Compute(const framework::ExecutionContext& context) const override { + auto rank = context.Input("X")->dims().size(); + auto target_shape = context.Attr>("target_shape"); + auto target_rank = target_shape.size(); + PADDLE_ENFORCE_GE(target_rank, rank, + platform::errors::InvalidArgument( + "The rank (%d) of the input 'target_tensor' for " + "expand_as_v2 op must be greater than or equal to " + "the rank (%d) of the input 'x'.", + target_rank, rank)); + PADDLE_ENFORCE_GE( + rank, 1, + platform::errors::InvalidArgument("The rank (%d) of the input 'x' for " + "expand_as_v2 op must be positive.", + rank)); + PADDLE_ENFORCE_LE(target_rank, MAX_RANK_SUPPORTED, + platform::errors::InvalidArgument( + "The rank (%d) of the input 'target_tensor' for " + "expand_as_v2 op must be less than or equal to %d.", + target_rank, MAX_RANK_SUPPORTED)); + ExpandAs(context); + } + + protected: + void ExpandAs(const framework::ExecutionContext& context) const { + auto* in0 = context.Input("X"); + auto in_dims = in0->dims(); + auto target_shape = context.Attr>("target_shape"); + auto vec_in_dims = phi::vectorize(in_dims); + auto diff = target_shape.size() - vec_in_dims.size(); + vec_in_dims.insert(vec_in_dims.begin(), diff, 1); + + for (size_t i = 0; i < vec_in_dims.size(); ++i) { + PADDLE_ENFORCE_NE(target_shape[i], 0, + platform::errors::InvalidArgument( + "The value of target shape cannot be zero.")); + if (vec_in_dims[i] != 1) { + PADDLE_ENFORCE_EQ( + vec_in_dims[i], target_shape[i], + platform::errors::InvalidArgument( + "The value (%d) of the non-singleton dimension does not match" + " the corresponding value (%d) in " + "target tensor for expand_as_v2 op.", + vec_in_dims[i], target_shape[i])); + } + } + auto* out0 = context.Output("Out"); + + framework::DDim out_dims = phi::make_ddim(target_shape); + + out0->Resize(out_dims); + out0->mutable_data(context.GetPlace()); + + MLUCnnlTensorDesc x_desc(*in0); + MLUCnnlTensorDesc out_desc(*out0); + + MLUCnnl::BroadcastTo(context, x_desc.get(), GetBasePtr(in0), out_desc.get(), + GetBasePtr(out0)); + } +}; + +} // namespace operators +} // namespace paddle + +namespace ops = paddle::operators; +REGISTER_OP_MLU_KERNEL(expand_as_v2, ops::ExpandAsV2MLUKernel, + ops::ExpandAsV2MLUKernel, + ops::ExpandAsV2MLUKernel, + ops::ExpandAsV2MLUKernel, + ops::ExpandAsV2MLUKernel, + ops::ExpandAsV2MLUKernel, + ops::ExpandAsV2MLUKernel); diff --git a/python/paddle/fluid/tests/unittests/mlu/test_expand_as_v2_op_mlu.py b/python/paddle/fluid/tests/unittests/mlu/test_expand_as_v2_op_mlu.py new file mode 100644 index 00000000000..4ef67b9f80e --- /dev/null +++ b/python/paddle/fluid/tests/unittests/mlu/test_expand_as_v2_op_mlu.py @@ -0,0 +1,181 @@ +# Copyright (c) 2022 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. + +from __future__ import print_function +import unittest +import sys + +sys.path.append('..') +import numpy as np +from op_test import OpTest +import paddle.fluid as fluid +import paddle + +paddle.enable_static() + + +def test_class1(op_type, typename): + + class TestExpandAsBasic(OpTest): + + def setUp(self): + self.set_mlu() + self.op_type = "expand_as_v2" + self.python_api = paddle.expand_as + x = np.random.rand(100).astype(typename) + target_tensor = np.random.rand(2, 100).astype(typename) + self.inputs = {'X': x} + self.attrs = {'target_shape': target_tensor.shape} + bcast_dims = [2, 1] + output = np.tile(self.inputs['X'], bcast_dims) + self.outputs = {'Out': output} + + def set_mlu(self): + self.__class__.use_mlu = True + self.place = paddle.device.MLUPlace(0) + self.__class__.no_need_check_grad = True + + def test_check_output(self): + self.check_output_with_place(self.place) + + cls_name = str(op_type) + "_" + str(typename) + "_1" + TestExpandAsBasic.__name__ = cls_name + globals()[cls_name] = TestExpandAsBasic + + +def test_class2(op_type, typename): + + class TestExpandAsOpRank2(OpTest): + + def setUp(self): + self.set_mlu() + self.op_type = "expand_as_v2" + self.python_api = paddle.expand_as + x = np.random.rand(10, 12).astype(typename) + target_tensor = np.random.rand(10, 12).astype(typename) + self.inputs = {'X': x} + self.attrs = {'target_shape': target_tensor.shape} + bcast_dims = [1, 1] + output = np.tile(self.inputs['X'], bcast_dims) + self.outputs = {'Out': output} + + def set_mlu(self): + self.__class__.use_mlu = True + self.place = paddle.device.MLUPlace(0) + self.__class__.no_need_check_grad = True + + def test_check_output(self): + self.check_output_with_place(self.place) + + cls_name = str(op_type) + "_" + str(typename) + "_2" + TestExpandAsOpRank2.__name__ = cls_name + globals()[cls_name] = TestExpandAsOpRank2 + + +def test_class3(op_type, typename): + + class TestExpandAsOpRank3(OpTest): + + def setUp(self): + self.set_mlu() + self.op_type = "expand_as_v2" + self.python_api = paddle.expand_as + x = np.random.rand(2, 3, 20).astype(typename) + target_tensor = np.random.rand(2, 3, 20).astype(typename) + self.inputs = {'X': x} + self.attrs = {'target_shape': target_tensor.shape} + bcast_dims = [1, 1, 1] + output = np.tile(self.inputs['X'], bcast_dims) + self.outputs = {'Out': output} + + def set_mlu(self): + self.__class__.use_mlu = True + self.place = paddle.device.MLUPlace(0) + self.__class__.no_need_check_grad = True + + def test_check_output(self): + self.check_output_with_place(self.place) + + cls_name = str(op_type) + "_" + str(typename) + "_3" + TestExpandAsOpRank3.__name__ = cls_name + globals()[cls_name] = TestExpandAsOpRank3 + + +def test_class4(op_type, typename): + + class TestExpandAsOpRank4(OpTest): + + def setUp(self): + self.set_mlu() + self.op_type = "expand_as_v2" + self.python_api = paddle.expand_as + x = np.random.rand(1, 1, 7, 16).astype(typename) + target_tensor = np.random.rand(4, 6, 7, 16).astype(typename) + self.inputs = {'X': x} + self.attrs = {'target_shape': target_tensor.shape} + bcast_dims = [4, 6, 1, 1] + output = np.tile(self.inputs['X'], bcast_dims) + self.outputs = {'Out': output} + + def set_mlu(self): + self.__class__.use_mlu = True + self.place = paddle.device.MLUPlace(0) + self.__class__.no_need_check_grad = True + + def test_check_output(self): + self.check_output_with_place(self.place) + + cls_name = str(op_type) + "_" + str(typename) + "_4" + TestExpandAsOpRank4.__name__ = cls_name + globals()[cls_name] = TestExpandAsOpRank4 + + +# Test python API +class TestExpandAsV2API(unittest.TestCase): + + def test_api(self): + input1 = np.random.random([12, 14]).astype("float32") + input2 = np.random.random([2, 12, 14]).astype("float32") + x = fluid.layers.data(name='x', + shape=[12, 14], + append_batch_size=False, + dtype="float32") + + y = fluid.layers.data(name='target_tensor', + shape=[2, 12, 14], + append_batch_size=False, + dtype="float32") + + out_1 = paddle.expand_as(x, y=y) + + exe = fluid.Executor(place=fluid.MLUPlace(0)) + res_1 = exe.run(fluid.default_main_program(), + feed={ + "x": input1, + "target_tensor": input2 + }, + fetch_list=[out_1]) + assert np.array_equal(res_1[0], np.tile(input1, (2, 1, 1))) + + +for _typename in { + 'float16', 'float32', 'int64', 'int32', 'int8', 'uint8', 'bool' +}: + test_class1('expand_as_v2', _typename) + test_class2('expand_as_v2', _typename) + test_class3('expand_as_v2', _typename) + test_class4('expand_as_v2', _typename) + +if __name__ == "__main__": + unittest.main() -- GitLab