-
Notifications
You must be signed in to change notification settings - Fork 5.9k
[Custom XPU Support] Custom extension support xpu backend #48733
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
3c49713
9067686
2715bc2
e472ee3
896fe73
fb45154
26aa059
1fa6dec
1dc1e3d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| // Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 2021->2022
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thx, next PR fix this. |
||
| // | ||
| // 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 <iostream> | ||
| #include <vector> | ||
|
|
||
| #include "paddle/extension.h" | ||
|
|
||
| #define CHECK_CPU_INPUT(x) PD_CHECK(x.is_cpu(), #x " must be a CPU Tensor.") | ||
| #define CHECK_XPU_INPUT(x) PD_CHECK(x.is_xpu(), #x " must be a XPU Tensor.") | ||
|
|
||
| template <typename data_t> | ||
| void relu_cpu_forward_kernel(const data_t* x_data, | ||
| data_t* out_data, | ||
| int64_t x_numel) { | ||
| PD_CHECK(x_data != nullptr, "x_data is nullptr."); | ||
| PD_CHECK(out_data != nullptr, "out_data is nullptr."); | ||
| for (int64_t i = 0; i < x_numel; ++i) { | ||
| out_data[i] = std::max(static_cast<data_t>(0.), x_data[i]); | ||
| } | ||
| } | ||
|
|
||
| std::vector<paddle::Tensor> relu_cpu_forward(const paddle::Tensor& x) { | ||
| CHECK_CPU_INPUT(x); | ||
| auto out = paddle::empty_like(x); | ||
|
|
||
| PD_DISPATCH_FLOATING_TYPES( | ||
| x.type(), "relu_cpu_forward", ([&] { | ||
| relu_cpu_forward_kernel<data_t>( | ||
| x.data<data_t>(), out.data<data_t>(), x.numel()); | ||
| })); | ||
|
|
||
| return {out}; | ||
| } | ||
|
|
||
| std::vector<paddle::Tensor> relu_xpu_forward(const paddle::Tensor& x) { | ||
| CHECK_XPU_INPUT(x); | ||
| auto out = paddle::relu(x); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这块能直接调用XPU的api吗?在paddle中有xpu api的头文件和so
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 理论上是可以的,load 函数提供了
|
||
| return {out}; | ||
| } | ||
|
|
||
| std::vector<paddle::Tensor> ReluForward(const paddle::Tensor& x) { | ||
| if (x.is_cpu()) { | ||
| return relu_cpu_forward(x); | ||
| } else if (x.is_xpu()) { | ||
| return relu_xpu_forward(x); | ||
| } else { | ||
| PD_THROW("Not implemented."); | ||
| } | ||
| } | ||
|
|
||
| PD_BUILD_OP(custom_relu) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 反向要怎么加?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 反向可以通过前向 api 构造出来,下个 PR 会完善此处的测试用例 grad_op can be implemented by the forward api, next PR will add more test cases here. |
||
| .Inputs({"X"}) | ||
| .Outputs({"Out"}) | ||
| .SetKernelFn(PD_KERNEL(ReluForward)); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| # Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 2021 -> 2022
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thx, next PR fix this. |
||
| # | ||
| # 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 utils import extra_compile_args, paddle_includes | ||
|
|
||
| from paddle.utils.cpp_extension import CppExtension, setup | ||
|
|
||
| setup( | ||
| name='custom_relu_xpu_module_setup', | ||
| ext_modules=CppExtension( # XPU don't support GPU | ||
| sources=['custom_relu_op_xpu.cc'], | ||
| include_dirs=paddle_includes, | ||
| extra_compile_args=extra_compile_args, | ||
| verbose=True, | ||
| ), | ||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,136 @@ | ||
| # Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 2021->2022
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thx, next PR fix this. |
||
| # | ||
| # 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. | ||
|
|
||
| import os | ||
| import site | ||
| import sys | ||
| import unittest | ||
|
|
||
| import numpy as np | ||
|
|
||
| import paddle | ||
| import paddle.static as static | ||
| from paddle.fluid.framework import _test_eager_guard | ||
| from paddle.utils.cpp_extension.extension_utils import run_cmd | ||
|
|
||
|
|
||
| def custom_relu_dynamic(func, device, dtype, np_x, use_func=True): | ||
| paddle.set_device(device) | ||
|
|
||
| t = paddle.to_tensor(np_x, dtype=dtype) | ||
| out = func(t) if use_func else paddle.nn.functional.relu(t) | ||
|
|
||
| return out.numpy() | ||
|
|
||
|
|
||
| def custom_relu_static( | ||
| func, device, dtype, np_x, use_func=True, test_infer=False | ||
| ): | ||
| paddle.enable_static() | ||
| paddle.set_device(device) | ||
|
|
||
| with static.scope_guard(static.Scope()): | ||
| with static.program_guard(static.Program()): | ||
| x = static.data(name='X', shape=[None, 8], dtype=dtype) | ||
| out = func(x) if use_func else paddle.nn.functional.relu(x) | ||
|
|
||
| exe = static.Executor() | ||
| exe.run(static.default_startup_program()) | ||
| # in static mode, x data has been covered by out | ||
| out_v = exe.run( | ||
| static.default_main_program(), | ||
| feed={'X': np_x}, | ||
| fetch_list=[out.name], | ||
| ) | ||
|
|
||
| paddle.disable_static() | ||
| return out_v | ||
|
|
||
|
|
||
| class TestNewCustomOpSetUpInstall(unittest.TestCase): | ||
| def setUp(self): | ||
| cur_dir = os.path.dirname(os.path.abspath(__file__)) | ||
| # compile, install the custom op egg into site-packages under background | ||
| # Currently custom XPU op does not support Windows | ||
| if os.name == 'nt': | ||
| return | ||
| cmd = 'cd {} && {} custom_relu_xpu_setup.py install'.format( | ||
| cur_dir, sys.executable | ||
| ) | ||
| run_cmd(cmd) | ||
|
|
||
| site_dir = site.getsitepackages()[0] | ||
| custom_egg_path = [ | ||
| x | ||
| for x in os.listdir(site_dir) | ||
| if 'custom_relu_xpu_module_setup' in x | ||
| ] | ||
| assert len(custom_egg_path) == 1, "Matched egg number is %d." % len( | ||
| custom_egg_path | ||
| ) | ||
| sys.path.append(os.path.join(site_dir, custom_egg_path[0])) | ||
|
|
||
| # usage: import the package directly | ||
| import custom_relu_xpu_module_setup | ||
|
|
||
| self.custom_op = custom_relu_xpu_module_setup.custom_relu | ||
|
|
||
| self.dtypes = ['float32', 'float64'] | ||
| self.devices = ['xpu'] | ||
|
|
||
| # config seed | ||
| SEED = 2021 | ||
| paddle.seed(SEED) | ||
| paddle.framework.random._manual_program_seed(SEED) | ||
|
|
||
| def test_static(self): | ||
| for device in self.devices: | ||
| for dtype in self.dtypes: | ||
| x = np.random.uniform(-1, 1, [4, 8]).astype(dtype) | ||
| out = custom_relu_static(self.custom_op, device, dtype, x) | ||
| pd_out = custom_relu_static( | ||
| self.custom_op, device, dtype, x, False | ||
| ) | ||
| np.testing.assert_array_equal( | ||
| out, | ||
| pd_out, | ||
| err_msg='custom op out: {},\n paddle api out: {}'.format( | ||
| out, pd_out | ||
| ), | ||
| ) | ||
|
|
||
| def func_dynamic(self): | ||
| for device in self.devices: | ||
| for dtype in self.dtypes: | ||
| x = np.random.uniform(-1, 1, [4, 8]).astype(dtype) | ||
| out = custom_relu_dynamic(self.custom_op, device, dtype, x) | ||
| pd_out = custom_relu_dynamic( | ||
| self.custom_op, device, dtype, x, False | ||
| ) | ||
| np.testing.assert_array_equal( | ||
| out, | ||
| pd_out, | ||
| err_msg='custom op out: {},\n paddle api out: {}'.format( | ||
| out, pd_out | ||
| ), | ||
| ) | ||
|
|
||
| def test_dynamic(self): | ||
| with _test_eager_guard(): | ||
| self.func_dynamic() | ||
| self.func_dynamic() | ||
|
|
||
|
|
||
| if __name__ == '__main__': | ||
| unittest.main() | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
init这个问题有找到具体原因吗?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
py_test是 paddle 自己封装的函数(ref.cmake/generic.cmake)而非 cmake 内部函数,使用py_test添加单测时,默认开启FLAGS_init_allocated_mem=true,所以此处需要手动设置成FLAGS_init_allocated_mem=0避免报错py_testis a function implemented in paddle (ref.cmake/generic.cmake) instead of cmake internal function.py_testusesFLAGS_init_allocated_mem=trueby default, so we need to manually setFLAGS_init_allocated_mem=0in XPU unit test to avoid error.