chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:40:42 +08:00
commit e25996e7db
15472 changed files with 3536181 additions and 0 deletions
+40
View File
@@ -0,0 +1,40 @@
if(WITH_CUSTOM_DEVICE AND NOT WITH_GPU)
set(PLUGIN_URL https://github.com/PaddlePaddle/PaddleCustomDevice.git)
set(PLUGIN_TAG develop)
file(
GLOB TEST_OPS
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
"test_*.py")
string(REPLACE ".py" "" TEST_OPS "${TEST_OPS}")
list(REMOVE_ITEM TEST_OPS test_custom_cpu_profiler_plugin)
list(REMOVE_ITEM TEST_OPS test_custom_cpu_to_static)
list(REMOVE_ITEM TEST_OPS test_collective_process_group_xccl)
foreach(TEST_OP ${TEST_OPS})
py_test(
${TEST_OP}
SRCS ${TEST_OP}.py ENVS FLAGS_allocator_strategy=naive_best_fit
PLUGIN_URL=${PLUGIN_URL} PLUGIN_TAG=${PLUGIN_TAG}
FLAGS_enable_pir_with_pt_in_dy2st=False)
endforeach()
bash_test_modules(
test_fleet_launch_custom_device
START_BASH
test_fleet_launch_custom_device.sh
ENVS
PYTHONPATH=""
FLAGS_allocator_strategy=naive_best_fit
PADDLE_BINARY_DIR=${PADDLE_BINARY_DIR}
PLUGIN_URL=${PLUGIN_URL}
PLUGIN_TAG=${PLUGIN_TAG}
PYTHON_EXECUTABLE=${PYTHON_EXECUTABLE})
set_tests_properties(test_fleet_launch_custom_device PROPERTIES TIMEOUT 120)
set_tests_properties(test_custom_cpu_plugin PROPERTIES TIMEOUT 120)
set_tests_properties(test_custom_op_setup PROPERTIES TIMEOUT 120)
# cpp testing
paddle_test(extension_header_test SRCS extension_header_test.cc DEPS phi
common)
endif()
@@ -0,0 +1,39 @@
# 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.
import os
import sys
def train(prefix):
selected_accelerators = os.getenv("FLAGS_selected_accelerators")
selected_custom_devices = os.getenv("FLAGS_selected_custom_cpus")
trainer_id = int(os.getenv("PADDLE_TRAINER_ID"))
worker_endpoints_env = os.getenv("PADDLE_TRAINER_ENDPOINTS")
current_endpoint = os.getenv("PADDLE_CURRENT_ENDPOINT")
worker_endpoints = worker_endpoints_env
trainers_num = len(worker_endpoints.split(','))
device_ids = os.getenv("PADDLE_WORLD_DEVICE_IDS")
current_device_id = os.getenv("PADDLE_LOCAL_DEVICE_IDS")
details = f"selected_accelerators:{selected_accelerators} selected_custom_devices:{selected_custom_devices} worker_endpoints:{worker_endpoints} trainers_num:{trainers_num} current_endpoint:{current_endpoint} trainer_id:{trainer_id} device_ids:{device_ids} device_id:{current_device_id}"
print(details)
with open(f"multi_process_{prefix}.check_{trainer_id}.log", "w") as f:
f.write(details)
if __name__ == '__main__':
prefix = sys.argv[1]
train(prefix)
+215
View File
@@ -0,0 +1,215 @@
// 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 <iostream>
#include <vector>
#include "paddle/extension.h"
#include "paddle/phi/backends/context_pool.h"
#define CHECK_CPU_INPUT(x) PD_CHECK(x.is_cpu(), #x " must be a CPU Tensor.")
#define CHECK_CUSTOM_INPUT(x) \
PD_CHECK(x.is_custom_device(), #x " must be a custom 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]);
}
}
template <typename data_t>
void relu_cpu_backward_kernel(const data_t* grad_out_data,
const data_t* out_data,
data_t* grad_x_data,
int64_t out_numel) {
for (int64_t i = 0; i < out_numel; ++i) {
grad_x_data[i] =
grad_out_data[i] * (out_data[i] > static_cast<data_t>(0) ? 1. : 0.);
}
}
template <typename data_t>
void relu_cpu_double_backward_kernel(const data_t* out_data,
const data_t* ddx_data,
data_t* ddout_data,
int64_t ddout_numel) {
for (int64_t i = 0; i < ddout_numel; ++i) {
ddout_data[i] =
ddx_data[i] * (out_data[i] > static_cast<data_t>(0) ? 1. : 0.);
}
}
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_cpu_backward(const paddle::Tensor& x,
const paddle::Tensor& out,
const paddle::Tensor& grad_out) {
auto grad_x = paddle::empty_like(x);
PD_DISPATCH_FLOATING_TYPES(out.type(), "relu_cpu_backward", ([&] {
relu_cpu_backward_kernel<data_t>(
grad_out.data<data_t>(),
out.data<data_t>(),
grad_x.data<data_t>(),
out.size());
}));
return {grad_x};
}
std::vector<paddle::Tensor> relu_cpu_double_backward(
const paddle::Tensor& out, const paddle::Tensor& ddx) {
CHECK_CPU_INPUT(out);
CHECK_CPU_INPUT(ddx);
auto ddout = paddle::empty(out.shape(), out.dtype(), out.place());
PD_DISPATCH_FLOATING_TYPES(out.type(), "relu_cpu_double_backward", ([&] {
relu_cpu_double_backward_kernel<data_t>(
out.data<data_t>(),
ddx.data<data_t>(),
ddout.mutable_data<data_t>(out.place()),
ddout.size());
}));
return {ddout};
}
std::vector<paddle::Tensor> relu_custom_forward(const paddle::Tensor& x) {
CHECK_CUSTOM_INPUT(x);
auto out = paddle::relu(x);
return {out};
}
std::vector<paddle::Tensor> relu_custom_backward(
const paddle::Tensor& x,
const paddle::Tensor& out,
const paddle::Tensor& grad_out) {
CHECK_CUSTOM_INPUT(x);
CHECK_CUSTOM_INPUT(out);
auto grad_x = paddle::empty_like(x, x.dtype(), x.place());
auto ones = paddle::experimental::full_like(x, 1.0, x.dtype(), x.place());
auto zeros = paddle::experimental::full_like(x, 0.0, x.dtype(), x.place());
auto condition = paddle::experimental::greater_than(x, zeros);
grad_x = paddle::multiply(grad_out, paddle::where(condition, ones, zeros));
return {grad_x};
}
std::vector<paddle::Tensor> relu_custom_double_backward(
const paddle::Tensor& out, const paddle::Tensor& ddx) {
CHECK_CUSTOM_INPUT(out);
auto ddout = paddle::empty(out.shape(), out.dtype(), out.place());
auto ones =
paddle::experimental::full_like(out, 1.0, out.dtype(), out.place());
auto zeros =
paddle::experimental::full_like(out, 0.0, out.dtype(), out.place());
auto condition = paddle::experimental::greater_than(out, zeros);
ddout = paddle::multiply(ddx, paddle::where(condition, ones, zeros));
return {ddout};
}
std::vector<paddle::Tensor> ReluForward(const paddle::Tensor& x) {
if (x.is_cpu()) {
return relu_cpu_forward(x);
} else if (x.is_custom_device()) {
return relu_custom_forward(x);
} else {
PD_THROW("Not implemented.");
}
}
std::vector<paddle::Tensor> ReluBackward(const paddle::Tensor& x,
const paddle::Tensor& out,
const paddle::Tensor& grad_out) {
if (x.is_cpu()) {
return relu_cpu_backward(x, out, grad_out);
} else if (x.is_custom_device()) {
return relu_custom_backward(x, out, grad_out);
} else {
PD_THROW("Not implemented.");
}
}
std::vector<paddle::Tensor> ReluDoubleBackward(const paddle::Tensor& out,
const paddle::Tensor& ddx) {
if (out.is_cpu()) {
return relu_cpu_double_backward(out, ddx);
} else if (out.is_custom_device()) {
return relu_custom_double_backward(out, ddx);
} else {
PD_THROW("Not implemented.");
}
}
std::vector<std::vector<int64_t>> ReluDoubleBackwardInferShape(
const std::vector<int64_t>& out_shape,
const std::vector<int64_t>& ddx_shape) {
return {out_shape};
}
PD_BUILD_OP(custom_relu)
.Inputs({"X"})
.Outputs({"Out"})
.SetKernelFn(PD_KERNEL(ReluForward));
PD_BUILD_GRAD_OP(custom_relu)
.Inputs({"X", "Out", paddle::Grad("Out")})
.Outputs({paddle::Grad("X")})
.SetKernelFn(PD_KERNEL(ReluBackward));
PD_BUILD_DOUBLE_GRAD_OP(custom_relu)
.Inputs({"Out", paddle::Grad(paddle::Grad("X"))})
.Outputs({paddle::Grad(paddle::Grad("Out"))})
.SetKernelFn(PD_KERNEL(ReluDoubleBackward))
.SetInferShapeFn(PD_INFER_SHAPE(ReluDoubleBackwardInferShape));
std::vector<paddle::Tensor> StreamForward(const paddle::Tensor& x) {
CHECK_CUSTOM_INPUT(x);
auto dev_ctx =
paddle::experimental::DeviceContextPool::Instance().Get(x.place());
auto custom_ctx = static_cast<const phi::CustomContext*>(dev_ctx);
std::shared_ptr<phi::stream::Stream> stream = custom_ctx->GetStream();
PD_CHECK(stream != nullptr);
std::cout << "Check stream != nullptr successfully" << std::endl;
custom_ctx->Wait();
std::cout << "Check Wait successfully" << std::endl;
return {x};
}
PD_BUILD_OP(custom_stream)
.Inputs({"X"})
.Outputs({"Out"})
.SetKernelFn(PD_KERNEL(StreamForward));
@@ -0,0 +1,24 @@
// Copyright (c) 2023 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 "glog/logging.h"
#include "gtest/gtest.h"
// Note(qili93): ensure compile with one header file 'extension.h' only,
// !!! do not fix this ut by adding other header files (PR#60842) !!!
#include "paddle/phi/extension.h"
TEST(CustomDevice, extension_header) {
VLOG(1) << "check extension header support compile only";
}
+235
View File
@@ -0,0 +1,235 @@
# 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.
import random
import unittest
import numpy as np
import paddle
from paddle.base import core
def init_process_group(strategy=None):
nranks = paddle.distributed.ParallelEnv().nranks
rank = paddle.distributed.ParallelEnv().local_rank
is_master = True if rank == 0 else False
store = paddle.base.core.TCPStore("127.0.0.1", 6173, is_master, nranks)
pg_group = core.ProcessGroupCustom.create(
store,
paddle.distributed.ParallelEnv().device_type,
rank,
nranks,
)
return pg_group
class TestProcessGroupFp32(unittest.TestCase):
def setUp(self):
paddle.seed(2022)
random.seed(2022)
np.random.seed(2022)
self.config()
def config(self):
self.dtype = "float32"
self.shape = (2, 10, 5)
def test_create_process_group_xccl(self):
device_id = paddle.distributed.ParallelEnv().dev_id
paddle.set_device(f'custom_cpu:{device_id}')
pg = init_process_group()
x = np.random.random(self.shape).astype(self.dtype)
tensor_x = paddle.to_tensor(x)
y = np.random.random(self.shape).astype(self.dtype)
tensor_y = paddle.to_tensor(y)
sum_result = tensor_x + tensor_y
if pg.rank() == 0:
task = pg.all_reduce(tensor_x, core.ReduceOp.SUM, sync_op=True)
task.wait()
# assert np.array_equal(tensor_x, sum_result)
else:
task = pg.all_reduce(tensor_y, core.ReduceOp.SUM, sync_op=True)
task.wait()
# assert np.array_equal(tensor_y, sum_result)
print("test allreduce sum api ok", flush=True)
x = np.random.random(self.shape).astype(self.dtype)
tensor_x = paddle.to_tensor(x)
y = np.random.random(self.shape).astype(self.dtype)
tensor_y = paddle.to_tensor(y)
max_result = paddle.maximum(tensor_x, tensor_y)
if pg.rank() == 0:
task = pg.all_reduce(tensor_x, core.ReduceOp.MAX, sync_op=True)
task.wait()
# assert np.array_equal(tensor_x, max_result)
else:
task = pg.all_reduce(tensor_y, core.ReduceOp.MAX, sync_op=True)
task.wait()
# assert np.array_equal(tensor_y, max_result)
print("test allreduce max api ok", flush=True)
# test broadcast
# rank 0
x = np.random.random(self.shape).astype(self.dtype)
tensor_x = paddle.to_tensor(x)
# rank 1
y = np.random.random(self.shape).astype(self.dtype)
tensor_y = paddle.to_tensor(y)
broadcast_result = paddle.assign(tensor_x)
if pg.rank() == 0:
task = pg.broadcast(tensor_x, 0, sync_op=True)
task.wait()
# paddle.base.core._custom_device_synchronize("custom_cpu", -1)
assert task.is_completed()
# assert np.array_equal(broadcast_result, tensor_x)
else:
task = pg.broadcast(tensor_y, 0, sync_op=True)
task.wait()
# paddle.base.core._custom_device_synchronize("custom_cpu", -1)
assert task.is_completed()
# assert np.array_equal(broadcast_result, tensor_y)
print("test broadcast api ok", flush=True)
# test barrier
# rank 0
if pg.rank() == 0:
task = pg.barrier(device_id)
task.wait()
# rank 1
else:
task = pg.barrier(device_id)
task.wait()
print("test barrier api ok\n", flush=True)
return
# test allgather
# rank 0
x = np.random.random(self.shape).astype(self.dtype)
y = np.random.random(self.shape).astype(self.dtype)
tensor_x = paddle.to_tensor(x)
tensor_y = paddle.to_tensor(y)
out_shape = list(self.shape)
out_shape[0] *= 2
out = np.random.random(out_shape).astype(self.dtype)
tensor_out = paddle.to_tensor(out)
if pg.rank() == 0:
task = pg.all_gather(tensor_out, tensor_x, sync_op=True)
task.wait()
# paddle.base.core._custom_device_synchronize("custom_cpu", -1)
# rank 1
else:
task = pg.all_gather(tensor_out, tensor_y, sync_op=True)
task.wait()
# paddle.base.core._custom_device_synchronize("custom_cpu", -1)
out_1 = paddle.slice(tensor_out, [0], [0], [out_shape[0] // 2])
out_2 = paddle.slice(
tensor_out, [0], [out_shape[0] // 2], [out_shape[0]]
)
# assert np.array_equal(tensor_x, out_1)
# assert np.array_equal(tensor_y, out_2)
print("test allgather api ok\n", flush=True)
# test alltoall
# rank 0
x = np.random.random(self.shape).astype(self.dtype)
y = np.random.random(self.shape).astype(self.dtype)
out1 = np.random.random(self.shape).astype(self.dtype)
out2 = np.random.random(self.shape).astype(self.dtype)
tensor_x = paddle.to_tensor(x)
tensor_y = paddle.to_tensor(y)
tensor_out1 = paddle.to_tensor(out1)
tensor_out2 = paddle.to_tensor(out2)
raw_tensor_x_2 = paddle.slice(
tensor_x, [0], [self.shape[0] // 2], [self.shape[0]]
)
raw_tensor_y_1 = paddle.slice(tensor_y, [0], [0], [self.shape[0] // 2])
if pg.rank() == 0:
task = pg.alltoall(tensor_out1, tensor_x)
task.wait()
# paddle.base.core._custom_device_synchronize("custom_cpu", -1)
# rank 1
else:
task = pg.alltoall(tensor_out2, tensor_y)
task.wait()
# paddle.base.core._custom_device_synchronize("custom_cpu", -1)
out1_2 = paddle.slice(
tensor_out1, [0], [self.shape[0] // 2], [self.shape[0]]
)
out2_1 = paddle.slice(tensor_out2, [0], [0], [self.shape[0] // 2])
# if pg.rank() == 0:
# assert np.array_equal(out1_2.numpy(), raw_tensor_y_1.numpy())
# else:
# assert np.array_equal(out2_1, raw_tensor_x_2)
print("test alltoall api ok\n", flush=True)
# test Reduce
# rank 0
x = np.random.random(self.shape).astype(self.dtype)
y = np.random.random(self.shape).astype(self.dtype)
tensor_x = paddle.to_tensor(x)
tensor_y = paddle.to_tensor(y)
sum_result = tensor_x + tensor_y
if pg.rank() == 0:
task = pg.reduce(tensor_x, 0)
task.wait()
# paddle.base.core._custom_device_synchronize("custom_cpu", -1)
# rank 1
else:
task = pg.reduce(tensor_y, 0)
task.wait()
# paddle.base.core._custom_device_synchronize("custom_cpu", -1)
# if pg.rank() == 0:
# assert np.array_equal(tensor_x, sum_result)
print("test reduce sum api ok\n", flush=True)
# test Scatter
# rank 0
in_shape = list(self.shape)
in_shape[0] *= 2
x = np.random.random(in_shape).astype(self.dtype)
y = np.random.random(self.shape).astype(self.dtype)
tensor_x = paddle.to_tensor(x)
tensor_y = paddle.to_tensor(y)
if pg.rank() == 0:
task = pg.scatter(tensor_x, tensor_y, 0)
task.wait()
# paddle.base.core._custom_device_synchronize("custom_cpu", -1)
# rank 1
else:
task = pg.scatter(tensor_x, tensor_y, 0)
task.wait()
# paddle.base.core._custom_device_synchronize("custom_cpu", -1)
out1 = paddle.slice(tensor_x, [0], [0], [self.shape[0]])
out2 = paddle.slice(tensor_x, [0], [self.shape[0]], [self.shape[0] * 2])
# if pg.rank() == 0:
# assert np.array_equal(tensor_y, out1)
# else:
# assert np.array_equal(tensor_y, out2)
print("test scatter api ok\n", flush=True)
if __name__ == "__main__":
unittest.main()
@@ -0,0 +1,192 @@
# 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.
import copy
import os
import subprocess
import sys
import tempfile
import time
import unittest
def start_local_trainers(
cluster,
pod,
training_script,
training_script_args,
eager_mode=True,
log_dir=None,
):
from paddle.distributed.utils.launch_utils import ( # noqa: F401
TrainerProc,
find_free_ports,
get_cluster,
watch_local_trainers,
)
current_env = copy.copy(os.environ.copy())
# paddle broadcast ncclUniqueId use socket, and
# proxy maybe make trainers unreachable, so delete them.
# if we set them to "", grpc will log error message "bad uri"
# so just delete them.
current_env.pop("http_proxy", None)
current_env.pop("https_proxy", None)
procs = []
os.system("rm -rf log && mkdir -p log")
for idx, t in enumerate(pod.trainers):
proc_env = {
"FLAGS_selected_custom_cpus": "{}".format(
",".join([str(g) for g in t.gpus])
),
"PADDLE_TRAINER_ID": str(t.rank),
"PADDLE_CURRENT_ENDPOINT": str(t.endpoint),
"PADDLE_TRAINERS_NUM": str(cluster.trainers_nranks()),
"PADDLE_TRAINER_ENDPOINTS": ",".join(cluster.trainers_endpoints()),
"PADDLE_DISTRI_CUSTOM_DEVICE_TYPE": "custom_cpu",
}
current_env.update(proc_env)
print(f"trainer proc env:{current_env}")
if os.getenv('WITH_COVERAGE', 'OFF') == 'ON':
cmd = "python -m coverage run --branch -p " + training_script
else:
cmd = "python -u " + training_script
print(f"start trainer proc:{cmd} env:{proc_env}")
fn = open(f"workerlog.{idx}", "a")
proc = subprocess.Popen(
cmd.split(" "), env=current_env, stdout=fn, stderr=fn
)
tp = TrainerProc()
tp.proc = proc
tp.rank = t.rank
tp.log_fn = fn
tp.cmd = cmd
procs.append(tp)
return procs
def get_cluster_from_args(selected_gpus):
from paddle.distributed.utils.launch_utils import ( # noqa: F401
TrainerProc,
find_free_ports,
get_cluster,
watch_local_trainers,
)
cluster_node_ips = '127.0.0.1'
node_ip = '127.0.0.1'
node_ips = [x.strip() for x in cluster_node_ips.split(',')]
node_ips.index(node_ip)
free_ports = None
free_ports = find_free_ports(len(selected_gpus))
if free_ports is not None:
free_ports = list(free_ports)
trainer_endpoints = []
for ip in node_ips:
trainer_endpoints.append([f"{ip}:{port}" for port in free_ports])
return get_cluster(node_ips, node_ip, trainer_endpoints, selected_gpus)
class TestMultipleCustomCPU(unittest.TestCase):
def run_mnist_2custom_cpu(self, target_file_name, eager_mode=True):
from paddle.distributed.utils.launch_utils import ( # noqa: F401
TrainerProc,
find_free_ports,
get_cluster,
watch_local_trainers,
)
selected_devices = [0, 1]
cluster = None
pod = None
cluster, pod = get_cluster_from_args(selected_devices)
procs = start_local_trainers(
cluster,
pod,
eager_mode=eager_mode,
training_script=target_file_name,
training_script_args=[],
)
while True:
alive = watch_local_trainers(procs, cluster.trainers_endpoints())
if not alive:
print(f"Local procs complete, POD info:{pod}")
break
time.sleep(3)
class TestProcessGroup(TestMultipleCustomCPU):
def setUp(self):
# compile so and set to current path
cur_dir = os.path.dirname(os.path.abspath(__file__))
self.temp_dir = tempfile.TemporaryDirectory()
cmd = 'cd {} \
&& git clone --depth 1 {} \
&& cd PaddleCustomDevice \
&& git fetch origin \
&& git checkout {} -b dev \
&& cd backends/custom_cpu \
&& mkdir build && cd build && cmake .. -DPython_EXECUTABLE={} -DWITH_TESTING=OFF && make -j8'.format(
self.temp_dir.name,
os.getenv('PLUGIN_URL'),
os.getenv('PLUGIN_TAG'),
sys.executable,
)
os.system(cmd)
# set environment for loading and registering compiled custom kernels
# only valid in current process
os.environ['CUSTOM_DEVICE_ROOT'] = os.path.join(
cur_dir,
f'{self.temp_dir.name}/PaddleCustomDevice/backends/custom_cpu/build',
)
os.environ['FLAGS_selected_custom_cpus'] = '0,1'
os.environ['CUSTOM_CPU_VISIBLE_DEVICES'] = '0,1'
os.environ['PADDLE_XCCL_BACKEND'] = 'custom_cpu'
def tearDown(self):
self.temp_dir.cleanup()
def test_process_group_xccl(self):
from paddle.distributed.utils.launch_utils import ( # noqa: F401
TrainerProc,
find_free_ports,
get_cluster,
watch_local_trainers,
)
self.run_mnist_2custom_cpu('process_group_xccl.py')
if __name__ == "__main__":
unittest.main()
+336
View File
@@ -0,0 +1,336 @@
# 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.
import os
import sys
import tempfile
import unittest
import numpy as np
class TestCustomCPUPlugin(unittest.TestCase):
def setUp(self):
# compile so and set to current path
cur_dir = os.path.dirname(os.path.abspath(__file__))
self.temp_dir = tempfile.TemporaryDirectory()
cmd = 'cd {} \
&& git clone --depth 1 {} \
&& cd PaddleCustomDevice \
&& git fetch origin \
&& git checkout {} -b dev \
&& cd backends/custom_cpu \
&& mkdir build && cd build && cmake .. -DPython_EXECUTABLE={} -DWITH_TESTING=OFF && make -j8'.format(
self.temp_dir.name,
os.getenv('PLUGIN_URL'),
os.getenv('PLUGIN_TAG'),
sys.executable,
)
os.system(cmd)
# set environment for loading and registering compiled custom kernels
# only valid in current process
os.environ['CUSTOM_DEVICE_ROOT'] = os.path.join(
cur_dir,
f'{self.temp_dir.name}/PaddleCustomDevice/backends/custom_cpu/build',
)
def tearDown(self):
self.temp_dir.cleanup()
del os.environ['CUSTOM_DEVICE_ROOT']
def test_custom_device(self):
self._test_custom_device_dataloader()
self._test_custom_device_mnist()
self._test_eager_backward_api()
self._test_eager_copy_to()
self._test_fallback_kernel()
self._test_scalar()
self._test_custom_device_py_api()
self._test_custom_device_mix_precision()
def _test_custom_device_dataloader(self):
import paddle
paddle.set_device('custom_cpu')
dataset = paddle.vision.datasets.MNIST(
mode='test',
transform=paddle.vision.transforms.Compose(
[
paddle.vision.transforms.CenterCrop(20),
paddle.vision.transforms.RandomResizedCrop(14),
paddle.vision.transforms.Normalize(),
paddle.vision.transforms.ToTensor(),
]
),
)
loader = paddle.io.DataLoader(
dataset, batch_size=32, num_workers=1, shuffle=True
)
for image, label in loader:
self.assertTrue(image.place.is_custom_place())
self.assertTrue(label.place.is_custom_place())
break
def _test_custom_device_mnist(self):
import paddle
class MNIST(paddle.nn.Layer):
def __init__(self):
super().__init__()
self.shape = 1 * 28 * 28
self.size = 10
self.output_weight = self.create_parameter(
[self.shape, self.size]
)
self.accuracy = paddle.metric.Accuracy()
def forward(self, inputs, label=None):
x = paddle.reshape(inputs, shape=[-1, self.shape])
x = paddle.matmul(x, self.output_weight)
x = paddle.nn.functional.softmax(x)
if label is not None:
self.accuracy.reset()
correct = self.accuracy.compute(x, label)
self.accuracy.update(correct)
acc = self.accuracy.accumulate()
return x, acc
else:
return x
paddle.set_device('custom_cpu')
dataset = paddle.vision.datasets.MNIST(
mode='train',
transform=paddle.vision.transforms.Compose(
[paddle.vision.transforms.ToTensor()]
),
)
loader = paddle.io.DataLoader(
dataset, batch_size=64, num_workers=1, shuffle=True
)
mnist = MNIST()
sgd = paddle.optimizer.SGD(
learning_rate=0.01, parameters=mnist.parameters()
)
data = next(loader())
img = data[0]
label = data[1]
label_int32 = paddle.cast(label, 'int32')
pred, acc = mnist(img, label_int32)
avg_loss = paddle.nn.functional.cross_entropy(pred, label_int32)
avg_loss.backward()
sgd.step()
sgd.clear_grad()
self.assertTrue(pred.place.is_custom_place())
def _test_eager_backward_api(self):
x = np.random.random([2, 2]).astype("float32")
y = np.random.random([2, 2]).astype("float32")
grad = np.ones([2, 2]).astype("float32")
import paddle
paddle.set_device('custom_cpu')
paddle.device.get_available_device()
x_tensor = paddle.to_tensor(x, stop_gradient=False)
y_tensor = paddle.to_tensor(y)
z1_tensor = paddle.matmul(x_tensor, y_tensor)
z2_tensor = paddle.matmul(x_tensor, y_tensor)
grad_tensor = paddle.to_tensor(grad)
paddle.autograd.backward([z1_tensor, z2_tensor], [grad_tensor, None])
self.assertTrue(x_tensor.grad.place.is_custom_place())
def _test_eager_copy_to(self):
import paddle
x = np.random.random([2, 2]).astype("float32")
# cpu -> custom
cpu_tensor = paddle.to_tensor(
x, dtype='float32', place=paddle.CPUPlace()
)
custom_cpu_tensor = cpu_tensor._copy_to(
paddle.CustomPlace('custom_cpu', 0), True
)
np.testing.assert_array_equal(custom_cpu_tensor, x)
self.assertTrue(custom_cpu_tensor.place.is_custom_place())
# custom -> custom
another_custom_cpu_tensor = custom_cpu_tensor._copy_to(
paddle.CustomPlace('custom_cpu', 0), True
)
np.testing.assert_array_equal(another_custom_cpu_tensor, x)
self.assertTrue(another_custom_cpu_tensor.place.is_custom_place())
# custom -> cpu
another_cpu_tensor = custom_cpu_tensor._copy_to(paddle.CPUPlace(), True)
np.testing.assert_array_equal(another_cpu_tensor, x)
self.assertTrue(another_cpu_tensor.place.is_cpu_place())
# custom -> custom self
another_custom_cpu_tensor = another_custom_cpu_tensor._copy_to(
paddle.CustomPlace('custom_cpu', 0), True
)
np.testing.assert_array_equal(another_custom_cpu_tensor, x)
self.assertTrue(another_custom_cpu_tensor.place.is_custom_place())
def _test_fallback_kernel(self):
# using (custom_cpu, add, int16) which is not registered
import paddle
r = np.array([6, 6, 6], 'int16')
x = paddle.to_tensor([5, 4, 3], 'int16')
y = paddle.to_tensor([1, 2, 3], 'int16')
z = paddle.add(x, y)
np.testing.assert_array_equal(z, r)
def _test_scalar(self):
import paddle
data_1 = paddle.to_tensor(
[[[[1.0, 4.0, 5.0, 7.0], [3.0, 4.0, 5.0, 6.0]]]]
)
k_t = paddle.to_tensor([3], dtype="int32")
value_1, indices_1 = paddle.topk(data_1, k=k_t)
def _test_custom_device_gradient_accumulation(self):
import paddle
class MNIST(paddle.nn.Layer):
def __init__(self):
super().__init__()
self.shape = 1 * 28 * 28
self.size = 10
self.output_weight = self.create_parameter(
[self.shape, self.size]
)
self.accuracy = paddle.metric.Accuracy()
def forward(self, inputs, label=None):
x = paddle.reshape(inputs, shape=[-1, self.shape])
x = paddle.matmul(x, self.output_weight)
x = paddle.nn.functional.softmax(x)
if label is not None:
self.accuracy.reset()
correct = self.accuracy.compute(x, label)
self.accuracy.update(correct)
acc = self.accuracy.accumulate()
return x, acc
else:
return x
paddle.set_device('custom_cpu')
dataset = paddle.vision.datasets.MNIST(
mode='train',
transform=paddle.vision.transforms.Compose(
[paddle.vision.transforms.ToTensor()]
),
)
loader = paddle.io.DataLoader(
dataset, batch_size=64, num_workers=1, shuffle=True
)
mnist = MNIST()
sgd = paddle.optimizer.SGD(
learning_rate=0.01, parameters=mnist.parameters()
)
data = next(loader())
img = data[0]
label = data[1]
label_int32 = paddle.cast(label, 'int32')
pred, acc = mnist(img, label_int32)
avg_loss = paddle.nn.functional.cross_entropy(pred, label_int32)
avg_loss.backward(retain_graph=True)
avg_loss = paddle.nn.functional.cross_entropy(pred, label_int32)
avg_loss.backward()
sgd.step()
def _test_custom_device_mix_precision(self):
import tempfile
import paddle
from paddle.inference import (
PlaceType,
PrecisionType,
convert_to_mixed_precision,
)
from paddle.jit import to_static
from paddle.static import InputSpec
from paddle.vision.models import resnet50
self.temp_dir = tempfile.TemporaryDirectory()
model = resnet50(True)
net = to_static(
model,
input_spec=[InputSpec(shape=[None, 3, 224, 224], name='x')],
full_graph=True,
)
paddle.jit.save(
net, os.path.join(self.temp_dir.name, 'resnet50/inference')
)
if paddle.framework.use_pir_api():
return
convert_to_mixed_precision(
os.path.join(self.temp_dir.name, 'resnet50/inference.pdmodel'),
os.path.join(self.temp_dir.name, 'resnet50/inference.pdiparams'),
os.path.join(
self.temp_dir.name, 'mixed_precision/inference.pdmodel'
),
os.path.join(
self.temp_dir.name, 'mixed_precision/inference.pdiparams'
),
backend=PlaceType.CUSTOM,
mixed_precision=PrecisionType.Half,
)
self.temp_dir.cleanup()
def _test_custom_device_py_api(self):
import paddle
p = paddle.set_device('custom_cpu')
paddle.device.synchronize('custom_cpu')
s1 = paddle.device.Stream()
s2 = paddle.device.Stream(p)
s1 = paddle.device.current_stream()
s2 = paddle.device.current_stream(p)
e1 = paddle.device.Event()
e2 = paddle.device.Event(p)
s = paddle.device.Stream()
e = paddle.device.Event()
s.query()
s.synchronize()
s.wait_event(e)
s.record_event(e)
s.wait_stream(s)
paddle.device.set_stream(s)
e.query()
e.synchronize()
e.record(s)
if __name__ == '__main__':
if os.name == 'nt' or sys.platform.startswith('darwin'):
# only support Linux now
sys.exit()
unittest.main()
@@ -0,0 +1,76 @@
# 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.
import os
import sys
import tempfile
import unittest
class TestCustomCPUProfilerPlugin(unittest.TestCase):
def setUp(self):
# compile so and set to current path
cur_dir = os.path.dirname(os.path.abspath(__file__))
self.temp_dir = tempfile.TemporaryDirectory()
cmd = 'cd {} \
&& git clone --depth 1 {} \
&& cd PaddleCustomDevice \
&& git fetch origin \
&& git checkout {} -b dev \
&& cd backends/custom_cpu \
&& mkdir build && cd build && cmake .. -DPython_EXECUTABLE={} -DWITH_TESTING=OFF && make -j8'.format(
self.temp_dir.name,
os.getenv('PLUGIN_URL'),
os.getenv('PLUGIN_TAG'),
sys.executable,
)
os.system(cmd)
# set environment for loading and registering compiled custom kernels
# only valid in current process
os.environ['CUSTOM_DEVICE_ROOT'] = os.path.join(
cur_dir,
f'{self.temp_dir.name}/PaddleCustomDevice/backends/custom_cpu/build',
)
def tearDown(self):
self.temp_dir.cleanup()
del os.environ['CUSTOM_DEVICE_ROOT']
def test_custom_profiler(self):
import paddle
from paddle import profiler
paddle.set_device('custom_cpu')
x = paddle.to_tensor([1, 2, 3])
p = profiler.Profiler(
targets=[
profiler.ProfilerTarget.CPU,
profiler.ProfilerTarget.CUSTOM_DEVICE,
]
)
p.start()
for iter in range(10):
x = x + 1
p.step()
p.stop()
p.summary()
if __name__ == '__main__':
if os.name == 'nt' or sys.platform.startswith('darwin'):
# only support Linux now
sys.exit()
unittest.main()
@@ -0,0 +1,281 @@
# 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.
import os
import sys
import tempfile
import time
import unittest
import numpy as np
EPOCH_NUM = 1
BATCH_SIZE = 1024
def train_func_base(epoch_id, train_loader, model, cost, optimizer):
total_step = len(train_loader)
epoch_start = time.time()
for batch_id, (images, labels) in enumerate(train_loader()):
# forward
outputs = model(images)
loss = cost(outputs, labels)
# backward and optimize
loss.backward()
optimizer.step()
optimizer.clear_grad()
print(
f"Epoch [{epoch_id + 1}/{EPOCH_NUM}], Step [{batch_id + 1}/{total_step}], Loss: {loss.numpy()}"
)
epoch_end = time.time()
print(
f"Epoch ID: {epoch_id + 1}, FP32 train epoch time: {(epoch_end - epoch_start) * 1000} ms"
)
def train_func_ampo1(epoch_id, train_loader, model, cost, optimizer, scaler):
import paddle
total_step = len(train_loader)
epoch_start = time.time()
for batch_id, (images, labels) in enumerate(train_loader()):
# forward
with paddle.amp.auto_cast(
custom_black_list={
"flatten_contiguous_range",
"greater_than",
"matmul_v2",
},
level='O1',
):
outputs = model(images)
loss = cost(outputs, labels)
# backward and optimize
scaled = scaler.scale(loss)
scaled.backward()
scaler.minimize(optimizer, scaled)
optimizer.clear_grad()
print(
f"Epoch [{epoch_id + 1}/{EPOCH_NUM}], Step [{batch_id + 1}/{total_step}], Loss: {loss.numpy()}"
)
epoch_end = time.time()
print(
f"Epoch ID: {epoch_id + 1}, AMPO1 train epoch time: {(epoch_end - epoch_start) * 1000} ms"
)
def test_func(epoch_id, test_loader, model, cost):
import paddle
# evaluation every epoch finish
model.eval()
avg_acc = [[], []]
for batch_id, (images, labels) in enumerate(test_loader()):
# forward
outputs = model(images)
loss = cost(outputs, labels)
# accuracy
acc_top1 = paddle.metric.accuracy(input=outputs, label=labels, k=1)
acc_top5 = paddle.metric.accuracy(input=outputs, label=labels, k=5)
avg_acc[0].append(acc_top1.numpy())
avg_acc[1].append(acc_top5.numpy())
model.train()
print(
f"Epoch ID: {epoch_id + 1}, Top1 accuracy: {np.array(avg_acc[0]).mean()}, Top5 accuracy: {np.array(avg_acc[1]).mean()}"
)
class TestCustomCPUPlugin(unittest.TestCase):
def setUp(self):
# compile so and set to current path
cur_dir = os.path.dirname(os.path.abspath(__file__))
self.temp_dir = tempfile.TemporaryDirectory()
cmd = 'cd {} \
&& git clone --depth 1 {} \
&& cd PaddleCustomDevice \
&& git fetch origin \
&& git checkout {} -b dev \
&& cd backends/custom_cpu \
&& mkdir build && cd build && cmake .. -DPython_EXECUTABLE={} -DWITH_TESTING=OFF && make -j8'.format(
self.temp_dir.name,
os.getenv('PLUGIN_URL'),
os.getenv('PLUGIN_TAG'),
sys.executable,
)
os.system(cmd)
# set environment for loading and registering compiled custom kernels
# only valid in current process
os.environ['CUSTOM_DEVICE_ROOT'] = os.path.join(
cur_dir,
f'{self.temp_dir.name}/PaddleCustomDevice/backends/custom_cpu/build',
)
def tearDown(self):
self.temp_dir.cleanup()
def test_custom_cpu_plugin(self):
self._test_to_static()
self._test_amp_o1()
def _test_to_static(self):
import paddle
class LeNet5(paddle.nn.Layer):
def __init__(self):
super().__init__()
self.fc = paddle.nn.Linear(in_features=1024, out_features=10)
self.relu = paddle.nn.ReLU()
self.fc1 = paddle.nn.Linear(in_features=10, out_features=10)
def forward(self, x):
out = paddle.flatten(x, 1)
out = self.fc(out)
out = self.relu(out)
out = self.fc1(out)
return out
# set device
paddle.set_device('custom_cpu')
# model
model = LeNet5()
# cost and optimizer
cost = paddle.nn.CrossEntropyLoss()
optimizer = paddle.optimizer.Adam(
learning_rate=0.001, parameters=model.parameters()
)
# convert to static model
build_strategy = paddle.static.BuildStrategy()
mnist = paddle.jit.to_static(
model, build_strategy=build_strategy, full_graph=True
)
# data loader
transform = paddle.vision.transforms.Compose(
[
paddle.vision.transforms.Resize((32, 32)),
paddle.vision.transforms.ToTensor(),
paddle.vision.transforms.Normalize(
mean=(0.1307,), std=(0.3081,)
),
]
)
train_dataset = paddle.vision.datasets.MNIST(
mode='train', transform=transform, download=True
)
test_dataset = paddle.vision.datasets.MNIST(
mode='test', transform=transform, download=True
)
train_loader = paddle.io.DataLoader(
train_dataset,
batch_size=BATCH_SIZE,
shuffle=True,
drop_last=True,
num_workers=2,
)
test_loader = paddle.io.DataLoader(
test_dataset,
batch_size=BATCH_SIZE,
shuffle=True,
drop_last=True,
num_workers=2,
)
# train and eval
for epoch_id in range(EPOCH_NUM):
train_func_base(epoch_id, train_loader, model, cost, optimizer)
test_func(epoch_id, test_loader, model, cost)
def _test_amp_o1(self):
import paddle
class LeNet5(paddle.nn.Layer):
def __init__(self):
super().__init__()
self.fc = paddle.nn.Linear(in_features=1024, out_features=10)
self.relu = paddle.nn.ReLU()
self.fc1 = paddle.nn.Linear(in_features=10, out_features=10)
def forward(self, x):
out = paddle.flatten(x, 1)
out = self.fc(out)
out = self.relu(out)
out = self.fc1(out)
return out
# set device
paddle.set_device('custom_cpu')
# model
model = LeNet5()
# cost and optimizer
cost = paddle.nn.CrossEntropyLoss()
optimizer = paddle.optimizer.Adam(
learning_rate=0.001, parameters=model.parameters()
)
# convert to static model
scaler = paddle.amp.GradScaler(init_loss_scaling=1024)
model, optimizer = paddle.amp.decorate(
models=model, optimizers=optimizer, level='O1'
)
# data loader
transform = paddle.vision.transforms.Compose(
[
paddle.vision.transforms.Resize((32, 32)),
paddle.vision.transforms.ToTensor(),
paddle.vision.transforms.Normalize(
mean=(0.1307,), std=(0.3081,)
),
]
)
train_dataset = paddle.vision.datasets.MNIST(
mode='train', transform=transform, download=True
)
test_dataset = paddle.vision.datasets.MNIST(
mode='test', transform=transform, download=True
)
train_loader = paddle.io.DataLoader(
train_dataset,
batch_size=BATCH_SIZE,
shuffle=True,
drop_last=True,
num_workers=2,
)
test_loader = paddle.io.DataLoader(
test_dataset,
batch_size=BATCH_SIZE,
shuffle=True,
drop_last=True,
num_workers=2,
)
# train and eval
for epoch_id in range(EPOCH_NUM):
train_func_ampo1(
epoch_id, train_loader, model, cost, optimizer, scaler
)
test_func(epoch_id, test_loader, model, cost)
if __name__ == '__main__':
if os.name == 'nt' or sys.platform.startswith('darwin'):
# only support Linux now
sys.exit()
unittest.main()
+280
View File
@@ -0,0 +1,280 @@
# 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.
import os
import sys
import tempfile
import unittest
from pathlib import Path
from site import getsitepackages
import numpy as np
from paddle.utils.cpp_extension.extension_utils import (
_get_all_paddle_includes_from_include_root,
)
def custom_relu_dynamic(func, device, dtype, np_x, use_func=True):
import paddle
paddle.set_device(device)
t = paddle.to_tensor(np_x, dtype=dtype)
t.stop_gradient = False
t.retain_grads()
sys.stdout.flush()
out = func(t) if use_func else paddle.nn.functional.relu(t)
out.stop_gradient = False
out.backward()
if t.grad is None:
return out.numpy(), t.grad
else:
return out.numpy(), t.grad.numpy()
def custom_relu_static(func, device, dtype, np_x, use_func=True):
import paddle
from paddle import static
paddle.enable_static()
paddle.set_device(device)
with (
static.scope_guard(static.Scope()),
static.program_guard(static.Program()),
):
x = static.data(name="X", shape=[None, 8], dtype=dtype)
x.stop_gradient = False
out = func(x) if use_func else paddle.nn.functional.relu(x)
static.append_backward(out)
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],
)
paddle.disable_static()
return out_v
def custom_relu_double_grad_dynamic(func, device, dtype, np_x, use_func=True):
import paddle
paddle.set_device(device)
t = paddle.to_tensor(np_x, dtype=dtype, stop_gradient=False)
t.retain_grads()
out = func(t) if use_func else paddle.nn.functional.relu(t)
out.retain_grads()
dx = paddle.grad(
outputs=out,
inputs=t,
grad_outputs=paddle.ones_like(t),
create_graph=True,
retain_graph=True,
)
ddout = paddle.grad(
outputs=dx[0],
inputs=out.grad,
grad_outputs=paddle.ones_like(t),
create_graph=False,
)
assert ddout[0].numpy() is not None
return dx[0].numpy(), ddout[0].numpy()
class TestNewCustomOpSetUpInstall(unittest.TestCase):
def setUp(self):
# compile so and set to current path
self.cur_dir = os.path.dirname(os.path.abspath(__file__))
self.temp_dir = tempfile.TemporaryDirectory()
cmd = 'cd {} \
&& git clone --depth 1 {} \
&& cd PaddleCustomDevice \
&& git fetch origin \
&& git checkout {} -b dev \
&& cd backends/custom_cpu \
&& mkdir build && cd build && cmake .. -DPython_EXECUTABLE={} -DWITH_TESTING=OFF && make -j8 \
&& cd {}'.format(
self.temp_dir.name,
os.getenv('PLUGIN_URL'),
os.getenv('PLUGIN_TAG'),
sys.executable,
self.cur_dir,
)
os.system(cmd)
# set environment for loading and registering compiled custom kernels
# only valid in current process
os.environ['CUSTOM_DEVICE_ROOT'] = os.path.join(
self.cur_dir,
f'{self.temp_dir.name}/PaddleCustomDevice/backends/custom_cpu/build',
)
# `import paddle` loads custom_cpu.so, hence we must import paddle after finishing build PaddleCustomDevice
import paddle
# [Why specific paddle_includes directory?]
# Add paddle_includes to pass CI, for more details,
# please refer to the comments in `paddle/tests/custom_op/utils.py``
paddle_includes = []
for site_packages_path in getsitepackages():
paddle_include_dir = Path(site_packages_path) / "paddle/include"
paddle_includes.extend(
_get_all_paddle_includes_from_include_root(
str(paddle_include_dir)
)
)
custom_module = paddle.utils.cpp_extension.load(
name='custom_device',
sources=['custom_op.cc'],
extra_include_paths=paddle_includes, # add for Coverage CI
extra_cxx_cflags=["-w", "-g"], # test for cc flags
# build_directory=self.cur_dir,
verbose=True,
)
self.custom_op = custom_module.custom_relu
self.custom_stream_op = custom_module.custom_stream
self.dtypes = ["float32", "float64"]
self.device = "custom_cpu"
# config seed
SEED = 2021
paddle.seed(SEED)
paddle.framework.random._manual_program_seed(SEED)
def tearDown(self):
self.temp_dir.cleanup()
del os.environ['CUSTOM_DEVICE_ROOT']
def test_custom_device(self):
self._test_static()
self._test_dynamic()
self._test_double_grad_dynamic()
self._test_with_dataloader()
self._test_stream()
def _test_static(self):
for dtype in self.dtypes:
x = np.random.uniform(-1, 1, [4, 8]).astype(dtype)
out = custom_relu_static(self.custom_op, self.device, dtype, x)
pd_out = custom_relu_static(
self.custom_op, self.device, dtype, x, False
)
np.testing.assert_array_equal(
out,
pd_out,
err_msg=f"custom op out: {out},\n paddle api out: {pd_out}",
)
def _test_dynamic(self):
for dtype in self.dtypes:
x = np.random.uniform(-1, 1, [4, 8]).astype(dtype)
out, x_grad = custom_relu_dynamic(
self.custom_op, self.device, dtype, x
)
pd_out, pd_x_grad = custom_relu_dynamic(
self.custom_op, self.device, dtype, x, False
)
np.testing.assert_array_equal(
out,
pd_out,
err_msg=f"custom op out: {out},\n paddle api out: {pd_out}",
)
np.testing.assert_array_equal(
x_grad,
pd_x_grad,
err_msg=f"custom op x grad: {x_grad},\n paddle api x grad: {pd_x_grad}",
)
def _test_double_grad_dynamic(self):
for dtype in self.dtypes:
x = np.random.uniform(-1, 1, [4, 8]).astype(dtype)
out, dx_grad = custom_relu_double_grad_dynamic(
self.custom_op, self.device, dtype, x
)
pd_out, pd_dx_grad = custom_relu_double_grad_dynamic(
self.custom_op, self.device, dtype, x, False
)
np.testing.assert_array_equal(
out,
pd_out,
err_msg=f"custom op out: {out},\n paddle api out: {pd_out}",
)
np.testing.assert_array_equal(
dx_grad,
pd_dx_grad,
err_msg=f"custom op dx grad: {dx_grad},\n paddle api dx grad: {pd_dx_grad}",
)
def _test_with_dataloader(self):
import paddle
from paddle.vision.transforms import Compose, Normalize
paddle.set_device(self.device)
# data loader
transform = Compose(
[Normalize(mean=[127.5], std=[127.5], data_format="CHW")]
)
train_dataset = paddle.vision.datasets.MNIST(
mode="train", transform=transform
)
train_loader = paddle.io.DataLoader(
train_dataset,
batch_size=64,
shuffle=True,
drop_last=True,
num_workers=0,
)
for batch_id, (image, _) in enumerate(train_loader()):
out = self.custom_op(image)
pd_out = paddle.nn.functional.relu(image)
np.testing.assert_array_equal(
out,
pd_out,
err_msg=f"custom op out: {out},\n paddle api out: {pd_out}",
)
if batch_id == 5:
break
def _test_stream(self):
import paddle
paddle.set_device(self.device)
x = paddle.ones([2, 2], dtype='float32')
out = self.custom_stream_op(x)
np.testing.assert_array_equal(x.numpy(), out.numpy())
if __name__ == "__main__":
if os.name == 'nt' or sys.platform.startswith('darwin'):
# only support Linux now
sys.exit()
unittest.main()
@@ -0,0 +1,35 @@
#!/bin/bash
# Copyright (c) 2020 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.
set -e
temp_dir=$(mktemp --directory)
pushd ${temp_dir} \
&& git clone --depth 1 ${PLUGIN_URL} \
&& pushd PaddleCustomDevice/ \
&& git fetch origin \
&& git checkout ${PLUGIN_TAG} -b dev \
&& pushd backends/custom_cpu \
&& mkdir build && pushd build && cmake .. -DPython_EXECUTABLE=${PYTHON_EXECUTABLE} -DWITH_TESTING=OFF && make -j8 && popd && popd && popd && popd
echo "begin test use custom_cpu"
export FLAGS_selected_custom_cpus=0,1
export CUSTOM_CPU_VISIBLE_DEVICES=0,1
export CUSTOM_DEVICE_ROOT=${temp_dir}/PaddleCustomDevice/backends/custom_cpu/build
distributed_args="--devices=0,1"
python -m paddle.distributed.fleet.launch ${distributed_args} custom_device_multi_process_collective.py fleetlaunch_custom_cpu