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
+96
View File
@@ -0,0 +1,96 @@
if(WIN32)
cc_test(
device_mesh_test
SRCS device_mesh_test.cc
DEPS type_info)
cc_test(
process_mesh_test
SRCS process_mesh_test.cc
DEPS type_info)
else()
cc_test(device_mesh_test SRCS device_mesh_test.cc)
cc_test(process_mesh_test SRCS process_mesh_test.cc)
endif()
cc_test(
dist_attr_test
SRCS dist_attr_test.cc
DEPS proto_desc)
if(WITH_DISTRIBUTE)
cc_library(
spmd_rule_test_util
SRCS spmd_rule_test_util.cc
DEPS gtest)
cc_test(
dist_tensor_test
SRCS dist_tensor_test.cc
DEPS phi common)
paddle_test(spmd_rule_test SRCS spmd_rule_test.cc DEPS spmd_rule_test_util
phi)
paddle_test(softmax_grad_spmd_rule_test SRCS softmax_grad_spmd_rule_test.cc
DEPS spmd_rule_test_util phi)
paddle_test(tile_spmd_rule_test SRCS tile_spmd_rule_test.cc DEPS
spmd_rule_test_util phi)
paddle_test(tile_co_shard_spmd_rule_test SRCS tile_co_shard_spmd_rule_test.cc
DEPS spmd_rule_test_util phi)
paddle_test(
fused_linear_param_grad_add_spmd_rule_test SRCS
fused_linear_param_grad_add_spmd_rule_test.cc DEPS spmd_rule_test_util phi)
paddle_test(
cross_entropy_softmax_spmd_rule_test SRCS
cross_entropy_softmax_spmd_rule_test.cc DEPS spmd_rule_test_util phi)
paddle_test(expand_spmd_rule_test SRCS expand_spmd_rule_test.cc DEPS
spmd_rule_test_util phi)
paddle_test(expand_as_spmd_rule_test SRCS expand_as_spmd_rule_test.cc DEPS
spmd_rule_test_util phi)
paddle_test(matmul_co_shard_spmd_rule_test SRCS
matmul_co_shard_spmd_rule_test.cc DEPS spmd_rule_test_util phi)
paddle_test(custom_op_spmd_rule_test SRCS custom_op_spmd_rule_test.cc DEPS
spmd_rule_test_util phi)
paddle_test(fused_rms_norm_spmd_rule_test SRCS
fused_rms_norm_spmd_rule_test.cc DEPS spmd_rule_test_util phi)
paddle_test(moe_gate_dispatch_spmd_rule_test SRCS
moe_gate_dispatch_spmd_rule_test.cc DEPS spmd_rule_test_util phi)
paddle_test(moe_combine_spmd_rule_test SRCS moe_combine_spmd_rule_test.cc
DEPS spmd_rule_test_util phi)
paddle_test(softmax_co_shard_spmd_rule_test SRCS
softmax_co_shard_spmd_rule_test.cc DEPS spmd_rule_test_util phi)
paddle_test(
index_select_co_shard_spmd_rule_test SRCS
index_select_co_shard_spmd_rule_test.cc DEPS spmd_rule_test_util phi)
paddle_test(reshape_co_shard_spmd_rule_test SRCS
reshape_co_shard_spmd_rule_test.cc DEPS spmd_rule_test_util phi)
paddle_test(argsort_co_shard_spmd_rule_test SRCS
argsort_co_shard_spmd_rule_test.cc DEPS spmd_rule_test_util phi)
paddle_test(transpose_co_shard_spmd_rule_test SRCS
transpose_co_shard_spmd_rule_test.cc DEPS spmd_rule_test_util phi)
endif()
if(WIN32)
cc_test(
dist_mapper_test
SRCS dist_mapper_test.cc
DEPS type_info)
else()
cc_test(
dist_mapper_test
SRCS dist_mapper_test.cc
DEPS phi)
endif()
@@ -0,0 +1,205 @@
/* Copyright (c) 2025 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 "test/cpp/auto_parallel/spmd_rule_test_util.h"
namespace paddle {
namespace distributed {
namespace auto_parallel {
struct ArgSortTestCase {
// input
std::vector<int64_t> x_shape;
std::vector<std::vector<int64_t>> x_dims_mapping;
// axis attribute
int axis;
// output
std::vector<std::vector<int64_t>> expected_x_dims_mapping;
std::vector<std::vector<int64_t>> expected_output_dims_mapping;
std::vector<std::vector<int64_t>> expected_indices_dims_mapping;
// unused attribute
bool descending = true;
bool stable = true;
};
struct ArgSortGradTestCase {
// input
std::vector<int64_t> input_shape;
std::vector<std::vector<int64_t>> indices_dims_mapping;
std::vector<std::vector<int64_t>> x_dims_mapping;
std::vector<std::vector<int64_t>> out_grad_dims_mapping;
// axis attribute
int axis;
// output
std::vector<std::vector<int64_t>> expected_indices_dims_mapping;
std::vector<std::vector<int64_t>> expected_x_dims_mapping;
std::vector<std::vector<int64_t>> expected_out_grad_dims_mapping;
std::vector<std::vector<int64_t>> expected_x_grad_dims_mapping;
// unused attribute
bool descending = true;
bool stable = true;
};
TEST(ArgSortInferSpmd, Ctor) {
std::vector<int64_t> mesh_shape = {2, 2, 2};
std::vector<int64_t> process_ids = {0, 1, 2, 3, 4, 5, 6, 7};
std::vector<std::string> dim_names = {"x", "y", "z"};
ProcessMesh process_mesh(mesh_shape, process_ids, dim_names);
std::vector<ArgSortTestCase> test_cases = {
// shape = [16, 32, 48], axis = -1
// [[0,1],[2],[]] -> [[],[2],[]], [[],[2],[]]
{{16, 32, 48},
{{0, 1}, {2}, {}},
-1,
{{0, 1}, {2}, {}},
{{0, 1}, {2}, {}},
{{0, 1}, {2}, {}}},
// shape = [16, 32, 48], axis = 2
// [[0],[],[1,2]] -> [[0],[],[]], [[0],[],[]]
{{16, 32, 48},
{{0}, {}, {1, 2}},
2,
{{0}, {}, {}},
{{0}, {}, {}},
{{0}, {}, {}}},
// shape = [10, 32, 48, 24], axis = 1
// [[0,1],[2],[],[]] -> [[0,1],[],[],[]], [[0,1],[],[],[]]
{{10, 32, 48, 24},
{{0, 1}, {2}, {}, {}},
1,
{{0, 1}, {}, {}, {}},
{{0, 1}, {}, {}, {}},
{{0, 1}, {}, {}, {}}}};
for (const auto& tc : test_cases) {
TensorDistAttr t_dist_attr = TensorDistAttr();
t_dist_attr.set_process_mesh(process_mesh);
t_dist_attr.set_dims_mapping(tc.x_dims_mapping);
t_dist_attr.set_dynamic_dims(std::vector<bool>(tc.x_shape.size(), false));
phi::distributed::DistMetaTensor x = phi::distributed::DistMetaTensor(
common::make_ddim(tc.x_shape), t_dist_attr);
// test forward
phi::distributed::SpmdInfo forward_spmd_info =
phi::distributed::ArgSortInferSpmd(
x, tc.axis, tc.descending, tc.stable);
EXPECT_EQ(forward_spmd_info.first.size(), static_cast<size_t>(1));
EXPECT_EQ(forward_spmd_info.second.size(), static_cast<size_t>(2));
check_multi_dims_mapping(forward_spmd_info.first[0],
tc.expected_x_dims_mapping);
check_multi_dims_mapping(forward_spmd_info.second[0],
tc.expected_output_dims_mapping);
check_multi_dims_mapping(forward_spmd_info.second[1],
tc.expected_indices_dims_mapping);
}
}
TEST(ArgSortGradInferSpmd, Ctor) {
std::vector<int64_t> mesh_shape = {2, 2, 2};
std::vector<int64_t> process_ids = {0, 1, 2, 3, 4, 5, 6, 7};
std::vector<std::string> dim_names = {"x", "y", "z"};
ProcessMesh process_mesh(mesh_shape, process_ids, dim_names);
std::vector<ArgSortGradTestCase> test_cases = {
// shape = [16, 32, 48], axis = -1
// [[0,1],[2],[]], [[0,1],[2],[]], [[0,1],[2],[]] -> [[0,1],[2],[]],
// [[0,1],[2],[]], [[0,1],[2],[]], [[0,1],[2],[]]
{{16, 32, 48},
{{0, 1}, {2}, {}},
{{0, 1}, {2}, {}},
{{0, 1}, {2}, {}},
-1,
{{0, 1}, {2}, {}},
{{0, 1}, {2}, {}},
{{0, 1}, {2}, {}},
{{0, 1}, {2}, {}}},
// axis = 2
// [[0,1],[],[2]], [[0,1],[],[2]], [[0,1],[],[2]] -> [[0,1],[],[]],
// [[0,1],[],[]], [[0,1],[],[]], [[0,1],[],[]]
{{16, 32, 48},
{{0, 1}, {}, {2}},
{{0, 1}, {}, {2}},
{{0, 1}, {}, {2}},
2,
{{0, 1}, {}, {}},
{{0, 1}, {}, {}},
{{0, 1}, {}, {}},
{{0, 1}, {}, {}}},
// [10, 32, 48, 24], axis = 1
// [[0],[1,2],[]], [[0],[1,2],[]], [[0],[1,2],[]] -> [[0],[],[]],
// [[0],[],[]], [[0],[],[]], [[0],[],[]]
{{10, 32, 48, 24},
{{0}, {1, 2}, {}, {}},
{{0}, {1, 2}, {}, {}},
{{0}, {1, 2}, {}, {}},
1,
{{0}, {}, {}, {}},
{{0}, {}, {}, {}},
{{0}, {}, {}, {}},
{{0}, {}, {}, {}}}};
for (const auto& tc : test_cases) {
TensorDistAttr indices_dist_attr = TensorDistAttr();
indices_dist_attr.set_process_mesh(process_mesh);
indices_dist_attr.set_dims_mapping(tc.indices_dims_mapping);
indices_dist_attr.set_dynamic_dims(
std::vector<bool>(tc.input_shape.size(), false));
phi::distributed::DistMetaTensor indices = phi::distributed::DistMetaTensor(
common::make_ddim(tc.input_shape), indices_dist_attr);
TensorDistAttr x_dist_attr = TensorDistAttr();
x_dist_attr.set_process_mesh(process_mesh);
x_dist_attr.set_dims_mapping(tc.x_dims_mapping);
x_dist_attr.set_dynamic_dims(
std::vector<bool>(tc.input_shape.size(), false));
phi::distributed::DistMetaTensor x = phi::distributed::DistMetaTensor(
common::make_ddim(tc.input_shape), x_dist_attr);
TensorDistAttr out_grad_dist_attr = TensorDistAttr();
out_grad_dist_attr.set_process_mesh(process_mesh);
out_grad_dist_attr.set_dims_mapping(tc.out_grad_dims_mapping);
out_grad_dist_attr.set_dynamic_dims(
std::vector<bool>(tc.input_shape.size(), false));
phi::distributed::DistMetaTensor out_grad =
phi::distributed::DistMetaTensor(common::make_ddim(tc.input_shape),
out_grad_dist_attr);
// test backward
phi::distributed::SpmdInfo backward_spmd_info =
phi::distributed::ArgSortGradInferSpmd(
indices, x, out_grad, tc.axis, tc.descending, tc.stable);
EXPECT_EQ(backward_spmd_info.first.size(), static_cast<size_t>(3));
EXPECT_EQ(backward_spmd_info.second.size(), static_cast<size_t>(1));
check_multi_dims_mapping(backward_spmd_info.first[0],
tc.expected_indices_dims_mapping);
check_multi_dims_mapping(backward_spmd_info.first[1],
tc.expected_x_dims_mapping);
check_multi_dims_mapping(backward_spmd_info.first[2],
tc.expected_out_grad_dims_mapping);
check_multi_dims_mapping(backward_spmd_info.second[0],
tc.expected_x_grad_dims_mapping);
}
}
} // namespace auto_parallel
} // namespace distributed
} // namespace paddle
@@ -0,0 +1,127 @@
/* 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 "test/cpp/auto_parallel/spmd_rule_test_util.h"
namespace paddle {
namespace distributed {
namespace auto_parallel {
TEST(CrossEntropyInferSpmd, Ctor) {
std::vector<int64_t> x_shape = {32, 48};
std::vector<int64_t> mesh_shape = {2, 3};
std::vector<int64_t> process_ids = {0, 1, 2, 3, 4, 5};
std::vector<std::string> dim_names = {"x", "y"};
ProcessMesh process_mesh(mesh_shape, process_ids, dim_names);
TensorDistAttr x_dist_attr = TensorDistAttr();
x_dist_attr.set_process_mesh(process_mesh);
x_dist_attr.set_dims_mapping(std::vector<int64_t>({0, -1}));
x_dist_attr.set_dynamic_dims(std::vector<bool>({false, false}));
TensorDistAttr label_dist_attr = TensorDistAttr();
label_dist_attr.set_process_mesh(process_mesh);
label_dist_attr.set_dims_mapping(std::vector<int64_t>({0, -1}));
label_dist_attr.set_dynamic_dims(std::vector<bool>({false, false}));
// forward
{
phi::distributed::DistMetaTensor x(phi::make_ddim(x_shape), x_dist_attr);
phi::distributed::DistMetaTensor label(phi::make_ddim(x_shape),
label_dist_attr);
int axis = 1;
auto spmdinfo =
CrossEntropyWithSoftmaxInferSpmd(x, label, false, true, true, 1, axis);
EXPECT_EQ(spmdinfo.first.size(), 2UL);
EXPECT_EQ(spmdinfo.second.size(), 2UL);
check_dim_mapping(spmdinfo.first[0], {0, -1});
check_dim_mapping(spmdinfo.first[1], {0, -1});
check_dim_mapping(spmdinfo.second[0], {0, -1});
check_dim_mapping(spmdinfo.second[1], {0, -1});
check_partial_dims(spmdinfo.second[0], {});
VLOG(4) << "Test CrossEntropyWithSoftmaxInferSpmd sharding on other axes."
<< std::endl
<< std::endl
<< std::endl;
}
// test sharding along softmax axis.
{
x_dist_attr.set_dims_mapping(std::vector<int64_t>({0, 1}));
label_dist_attr.set_dims_mapping(std::vector<int64_t>({0, -1}));
phi::distributed::DistMetaTensor x(phi::make_ddim(x_shape), x_dist_attr);
phi::distributed::DistMetaTensor label(phi::make_ddim(x_shape),
label_dist_attr);
int axis = 1;
auto spmdinfo =
CrossEntropyWithSoftmaxInferSpmd(x, label, false, true, true, 1, axis);
EXPECT_EQ(spmdinfo.first.size(), 2UL);
EXPECT_EQ(spmdinfo.second.size(), 2UL);
check_dim_mapping(spmdinfo.first[0], {0, -1});
check_dim_mapping(spmdinfo.first[1], {0, -1});
check_dim_mapping(spmdinfo.second[0], {0, -1});
check_dim_mapping(spmdinfo.second[1], {0, -1});
check_partial_dims(spmdinfo.second[0], {});
VLOG(4) << "Test CrossEntropyWithSoftmaxInferSpmd sharding on other axes."
<< std::endl
<< std::endl
<< std::endl;
}
// backward
{
std::vector<int64_t> loss_shape = {32, 1};
// Sharding along softmax axis.
x_dist_attr.set_dims_mapping(std::vector<int64_t>{0, 1});
label_dist_attr.set_dims_mapping(std::vector<int64_t>({0, 1}));
auto label = phi::distributed::DistMetaTensor(phi::make_ddim(x_shape),
label_dist_attr);
auto softmax =
phi::distributed::DistMetaTensor(phi::make_ddim(x_shape), x_dist_attr);
auto loss_dist_attr = x_dist_attr;
loss_dist_attr.set_dims_mapping(std::vector<int64_t>({0, -1}));
auto loss_grad = phi::distributed::DistMetaTensor(
phi::make_ddim(loss_shape), x_dist_attr);
int axis = 1;
auto spmdinfo = CrossEntropyWithSoftmaxGradInferSpmd(
label, softmax, loss_grad, true, true, true, 1, axis);
EXPECT_EQ(spmdinfo.first.size(), 3UL);
EXPECT_EQ(spmdinfo.second.size(), 1UL);
check_dim_mapping(spmdinfo.first[0], {0, -1});
check_dim_mapping(spmdinfo.first[1], {0, -1});
check_dim_mapping(spmdinfo.first[2], {0, -1});
check_dim_mapping(spmdinfo.second[0], {0, -1});
check_partial_dims(spmdinfo.second[0], {});
VLOG(4)
<< "Test CrossEntropyWithSoftmaxGradInferSpmd sharding on softmax axis."
<< std::endl
<< std::endl
<< std::endl;
}
}
} // namespace auto_parallel
} // namespace distributed
} // namespace paddle
@@ -0,0 +1,89 @@
/* 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 "paddle/phi/api/ext/op_meta_info.h"
#include "paddle/phi/api/ext/spmd_infer.h"
#include "test/cpp/auto_parallel/spmd_rule_test_util.h"
namespace paddle {
namespace distributed {
namespace auto_parallel {
TEST(CustomOp, Ctor) {
// test with concat rule
std::vector<int64_t> mesh_shape = {2, 2};
std::vector<int64_t> process_ids = {0, 1, 2, 3};
std::vector<std::string> dim_names = {"x", "y"};
ProcessMesh process_mesh(mesh_shape, process_ids, dim_names);
std::vector<std::vector<int64_t>> shapes = {
{16, 16, 16}, {4, 16, 16}, {2, 16, 16}};
std::vector<std::vector<int64_t>> dim_mappings = {
{-1, 0, 1}, {-1, 1, 0}, {-1, -1, 0}};
std::vector<std::vector<int64_t>> partial_status = {{}, {}, {1}};
auto build_inputs = [&] {
std::vector<phi::distributed::DistMetaTensor> inputs;
for (int i = 0; i < 3; i++) {
auto t_dist_attr = TensorDistAttr();
t_dist_attr.set_process_mesh(process_mesh);
t_dist_attr.set_dims_mapping(dim_mappings[i]);
t_dist_attr.set_dynamic_dims({false, false, false});
auto input = phi::distributed::DistMetaTensor(
common::make_ddim(shapes[i]), t_dist_attr);
inputs.push_back(input);
}
return inputs;
};
// test 1, inputs are aligned according to cost, and partial status is cleared
auto inputs = build_inputs();
auto forward_spmd_func =
PD_INFER_SPMD_RULE(phi::distributed::ConcatInferSpmd);
int axis = 0;
std::vector<CustomSpmdInferTensorArg> infer_inputs = {inputs};
std::vector<CustomSpmdInferAttrArg> attrs = {axis};
auto inferred_dist_attrs = forward_spmd_func(infer_inputs, attrs);
// list of tensor => single tensor
EXPECT_EQ(inferred_dist_attrs.first.size(), static_cast<size_t>(1));
EXPECT_EQ(inferred_dist_attrs.second.size(), static_cast<size_t>(1));
EXPECT_TRUE(
paddle::holds_alternative<std::vector<phi::distributed::TensorDistAttr>>(
inferred_dist_attrs.first[0]));
EXPECT_TRUE(paddle::holds_alternative<phi::distributed::TensorDistAttr>(
inferred_dist_attrs.second[0]));
auto& inputs_infer1 =
PADDLE_GET_CONST(std::vector<phi::distributed::TensorDistAttr>,
inferred_dist_attrs.first[0]);
for (auto e : inputs_infer1) {
check_dim_mapping(e, {-1, 1, 0});
check_partial_dims(e, {});
}
check_dim_mapping(inferred_dist_attrs.second[0], {-1, 1, 0});
check_partial_dims(inferred_dist_attrs.second[0], {});
}
TEST(CustomOp, Register) {
OpMetaInfoBuilder builder("test_custom_op_spmd", 0);
auto iter = OpMetaInfoMap::Instance().GetMap().find("test_custom_op_spmd");
EXPECT_TRUE(iter != OpMetaInfoMap::Instance().GetMap().end());
EXPECT_TRUE(OpMetaInfoHelper::GetInferSpmdFn(iter->second[0]) == nullptr);
builder.SetInferSpmdFn(PD_INFER_SPMD_RULE(phi::distributed::ConcatInferSpmd));
EXPECT_TRUE(OpMetaInfoHelper::GetInferSpmdFn(iter->second[0]) != nullptr);
}
} // namespace auto_parallel
} // namespace distributed
} // namespace paddle
@@ -0,0 +1,96 @@
/* 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 <sstream>
#include "paddle/phi/core/distributed/auto_parallel/device_mesh.h"
#include "paddle/phi/core/distributed/auto_parallel/proto_helper.h"
#include "gtest/gtest.h"
namespace phi {
namespace distributed {
namespace auto_parallel {
TEST(DeviceMesh, Ctor) {
std::vector<int64_t> shape = {2, 3};
std::vector<int64_t> device_ids = {0, 1, 2, 3, 4, 5};
std::vector<std::string> dim_names = {"x", "y"};
std::string device_type = "GPU";
int64_t size = shape[0] * shape[1];
DeviceMesh device_mesh("mesh", shape, device_ids, dim_names);
for (int64_t i = 0; i < shape[0]; ++i) {
for (int64_t j = 0; j < shape[1]; ++j) {
int64_t global_id = i * shape[1] + j;
int64_t local_id = j;
int64_t machine_id = i;
device_mesh.add_device(
Device(global_id, local_id, machine_id, device_type));
}
}
for (int64_t i = 0; i < size; ++i) {
for (int64_t j = 0; j < size; ++j) {
device_mesh.add_link(Link(i, j, "NVL"));
}
}
EXPECT_EQ(device_mesh.name(), "mesh");
EXPECT_EQ(device_mesh.shape(), shape);
EXPECT_EQ(device_mesh.device_ids(), device_ids);
EXPECT_EQ(device_mesh.dim_names()[0], "x");
EXPECT_EQ(device_mesh.dim_names()[1], "y");
EXPECT_EQ(device_mesh.device_type(), device_type);
EXPECT_EQ(device_mesh.size(), size);
EXPECT_EQ(device_mesh.ndim(), static_cast<int64_t>(shape.size()));
EXPECT_EQ(device_mesh.dim_size(0), shape[0]);
EXPECT_EQ(device_mesh.dim_size(-1), shape[1]);
EXPECT_EQ(device_mesh.dim_size("x"), shape[0]);
EXPECT_EQ(device_mesh.dim_size("y"), shape[1]);
EXPECT_EQ(device_mesh.empty(), false);
EXPECT_EQ(device_mesh.contains(0), true);
EXPECT_EQ(device_mesh.contains(6), false);
EXPECT_EQ(device_mesh.device(3).global_id(), 3);
EXPECT_EQ(device_mesh.device(3).local_id(), 0);
EXPECT_EQ(device_mesh.device(3).machine_id(), 1);
EXPECT_EQ(device_mesh.device(3).type(), "GPU");
EXPECT_EQ(device_mesh.link(3, 4).source_id(), 3);
EXPECT_EQ(device_mesh.link(3, 4).target_id(), 4);
EXPECT_EQ(device_mesh.link(3, 4).type(), "NVL");
for (int64_t i = 0; i < shape[0]; ++i) {
for (int64_t j = 0; j < shape[1]; ++j) {
int64_t global_id = i * shape[1] + j;
int64_t local_id = j;
int64_t machine_id = i;
auto device = device_mesh.devices().at(global_id);
EXPECT_EQ(device, Device(global_id, local_id, machine_id, device_type));
}
}
for (int64_t i = 0; i < size; ++i) {
for (int64_t j = 0; j < size; ++j) {
EXPECT_EQ(device_mesh.links().at(i).at(j), Link(i, j, "NVL"));
}
}
std::stringstream sstream;
sstream << device_mesh;
EXPECT_EQ(sstream.str(), device_mesh.to_string());
auto proto = phi::distributed::to_proto(device_mesh);
DeviceMesh new_device_mesh = DeviceMesh::from_proto(proto);
EXPECT_EQ(device_mesh, new_device_mesh);
}
} // namespace auto_parallel
} // namespace distributed
} // namespace phi
+182
View File
@@ -0,0 +1,182 @@
/* 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 <sstream>
#include "glog/logging.h"
#include "gtest/gtest.h"
#include "paddle/fluid/distributed/auto_parallel/dist_attr.h"
#include "paddle/fluid/framework/block_desc.h"
#include "paddle/fluid/framework/op_desc.h"
#include "paddle/fluid/framework/program_desc.h"
#include "paddle/fluid/framework/var_desc.h"
#include "paddle/phi/core/distributed/auto_parallel/proto_helper.h"
namespace phi {
namespace distributed {
namespace auto_parallel {
using paddle::framework::ProgramDesc;
using paddle::framework::VarDesc;
using paddle::distributed::auto_parallel::get_tensor_shape;
using paddle::distributed::auto_parallel::OperatorDistAttr;
TEST(DistAttr, ctor) {
ProgramDesc program;
auto* global_block = program.MutableBlock(0);
auto* x = global_block->Var("X");
x->SetType(paddle::framework::proto::VarType::DENSE_TENSOR);
x->SetLoDLevel(0);
x->SetDataType(paddle::framework::proto::VarType::FP32);
x->SetShape({1000, 784});
auto* y = global_block->Var("Y");
y->SetType(paddle::framework::proto::VarType::DENSE_TENSOR);
y->SetLoDLevel(0);
y->SetDataType(paddle::framework::proto::VarType::FP32);
y->SetShape({784, 100});
auto* op = global_block->AppendOp();
op->SetType("mul");
op->SetInput("X", {x->Name()});
op->SetInput("Y", {y->Name()});
auto* out = global_block->Var("Out");
out->SetType(paddle::framework::proto::VarType::DENSE_TENSOR);
out->SetShape({1000, 100});
op->SetOutput("Out", {out->Name()});
auto get_dist_attr = [](const VarDesc* var_desc) {
auto shape = get_tensor_shape(var_desc);
return TensorDistAttr(shape);
};
std::vector<int64_t> shape = {2, 4};
std::vector<int64_t> process_ids = {0, 1, 2, 3, 4, 5, 6, 7};
std::vector<std::string> dim_names = {"x", "y"};
ProcessMesh process_mesh(shape, process_ids, dim_names);
std::vector<int64_t> shape2 = {2, 2};
std::vector<int64_t> process_ids2 = {0, 1, 2, 3};
std::vector<std::string> dim_names2 = {"a", "b"};
ProcessMesh process_mesh2(shape2, process_ids2, dim_names2);
auto x_dist_attr = get_dist_attr(x);
auto y_dist_attr = get_dist_attr(y);
auto out_dist_attr = get_dist_attr(out);
x_dist_attr.set_process_mesh(process_mesh);
x_dist_attr.set_dims_mapping(std::vector<int64_t>({0, -1}));
x_dist_attr.set_batch_dim(0);
x_dist_attr.set_chunk_id(0);
x_dist_attr.set_dynamic_dims(std::vector<bool>({true, false}));
x_dist_attr.mark_annotated("process_mesh");
x_dist_attr.mark_annotated("dims_mapping");
EXPECT_EQ(x_dist_attr.process_mesh(), process_mesh);
EXPECT_EQ(x_dist_attr.dims_mapping(), std::vector<int64_t>({0, -1}));
EXPECT_EQ(x_dist_attr.batch_dim(), 0);
EXPECT_EQ(x_dist_attr.chunk_id(), 0);
EXPECT_EQ(x_dist_attr.dynamic_dims(), std::vector<bool>({true, false}));
EXPECT_EQ(x_dist_attr.is_annotated("process_mesh"), true);
EXPECT_EQ(x_dist_attr.is_annotated("dims_mapping"), true);
EXPECT_EQ(x_dist_attr.verify(get_tensor_shape(x)), true);
x_dist_attr.clear_annotated();
EXPECT_EQ(x_dist_attr.annotated().empty(), true);
std::stringstream x_sstream;
x_sstream << x_dist_attr;
EXPECT_EQ(x_sstream.str(), x_dist_attr.to_string());
auto x_proto = phi::distributed::to_proto(x_dist_attr);
TensorDistAttr new_x_dist_attr = get_dist_attr(x);
new_x_dist_attr.from_proto(x_proto);
EXPECT_EQ(x_dist_attr, new_x_dist_attr);
y_dist_attr.set_process_mesh(process_mesh);
y_dist_attr.set_dims_mapping(std::vector<int64_t>({-1, 0}));
y_dist_attr.set_batch_dim(-1);
y_dist_attr.set_chunk_id(0);
y_dist_attr.set_dynamic_dims(std::vector<bool>({false, true}));
x_dist_attr.mark_annotated("batch_dim");
x_dist_attr.mark_annotated("dynamic_dims");
EXPECT_EQ(y_dist_attr.process_mesh(), process_mesh);
EXPECT_EQ(y_dist_attr.dims_mapping(), std::vector<int64_t>({-1, 0}));
EXPECT_EQ(y_dist_attr.batch_dim(), -1);
EXPECT_EQ(y_dist_attr.chunk_id(), 0);
EXPECT_EQ(y_dist_attr.dynamic_dims(), std::vector<bool>({false, true}));
EXPECT_EQ(x_dist_attr.is_annotated("batch_dim"), true);
EXPECT_EQ(x_dist_attr.is_annotated("dynamic_dims"), true);
EXPECT_EQ(x_dist_attr.verify(get_tensor_shape(y)), true);
out_dist_attr.set_process_mesh(process_mesh);
out_dist_attr.set_dims_mapping(std::vector<int64_t>({0, 1}));
out_dist_attr.set_batch_dim(1);
out_dist_attr.set_dynamic_dims(std::vector<bool>({false, false}));
EXPECT_EQ(out_dist_attr.process_mesh(), process_mesh);
EXPECT_EQ(out_dist_attr.dims_mapping(), std::vector<int64_t>({0, 1}));
EXPECT_EQ(out_dist_attr.batch_dim(), 1);
EXPECT_EQ(out_dist_attr.dynamic_dims(), std::vector<bool>({false, false}));
EXPECT_EQ(out_dist_attr.verify(get_tensor_shape(out)), true);
OperatorDistAttr mul_dist_attr(*op);
EXPECT_EQ(mul_dist_attr.impl_type(),
paddle::distributed::auto_parallel::kDefault);
EXPECT_EQ(mul_dist_attr.impl_idx(), 0);
EXPECT_EQ(mul_dist_attr.chunk_id(), 0);
EXPECT_EQ(mul_dist_attr.is_recompute(), false);
EXPECT_EQ(mul_dist_attr.is_annotated("process_mesh"), false);
EXPECT_EQ(mul_dist_attr.is_annotated("impl_type"), false);
EXPECT_EQ(mul_dist_attr.is_annotated("impl_idx"), false);
mul_dist_attr.set_input_dist_attr(x->Name(), x_dist_attr);
mul_dist_attr.set_input_dist_attr(y->Name(), y_dist_attr);
mul_dist_attr.set_output_dist_attr(out->Name(), out_dist_attr);
mul_dist_attr.set_process_mesh(process_mesh2);
mul_dist_attr.set_impl_type("dist_mul");
mul_dist_attr.set_impl_idx(0);
mul_dist_attr.set_chunk_id(1);
mul_dist_attr.set_is_recompute(true);
mul_dist_attr.mark_annotated("process_mesh");
mul_dist_attr.mark_annotated("impl_type");
mul_dist_attr.mark_annotated("impl_idx");
EXPECT_NE(mul_dist_attr.input_dist_attr(x->Name()), x_dist_attr);
EXPECT_NE(mul_dist_attr.input_dist_attr(y->Name()), y_dist_attr);
EXPECT_NE(mul_dist_attr.output_dist_attr(out->Name()), out_dist_attr);
EXPECT_EQ(mul_dist_attr.process_mesh(), process_mesh2);
EXPECT_EQ(mul_dist_attr.input_dist_attr(x->Name()).process_mesh(),
process_mesh2);
EXPECT_EQ(mul_dist_attr.input_dist_attr(y->Name()).process_mesh(),
process_mesh2);
EXPECT_EQ(mul_dist_attr.impl_type(), "dist_mul");
EXPECT_EQ(mul_dist_attr.impl_idx(), 0);
EXPECT_EQ(mul_dist_attr.chunk_id(), 1);
EXPECT_EQ(mul_dist_attr.is_recompute(), true);
EXPECT_EQ(mul_dist_attr.is_annotated("process_mesh"), true);
EXPECT_EQ(mul_dist_attr.is_annotated("impl_type"), true);
EXPECT_EQ(mul_dist_attr.is_annotated("impl_idx"), true);
EXPECT_EQ(mul_dist_attr.verify(op), true);
mul_dist_attr.clear_annotated();
EXPECT_EQ(mul_dist_attr.annotated().empty(), true);
std::stringstream mul_sstream;
mul_sstream << mul_dist_attr;
EXPECT_EQ(mul_sstream.str(), mul_dist_attr.to_string());
auto mul_proto = mul_dist_attr.to_proto();
OperatorDistAttr new_mul_dist_attr(*op);
new_mul_dist_attr.from_proto(mul_proto);
EXPECT_EQ(mul_dist_attr, new_mul_dist_attr);
}
} // namespace auto_parallel
} // namespace distributed
} // namespace phi
@@ -0,0 +1,73 @@
/* 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/phi/core/distributed/auto_parallel/dist_mapper.h"
#include <map>
#include <sstream>
#include "gtest/gtest.h"
#include "paddle/phi/core/distributed/auto_parallel/proto_helper.h"
namespace phi {
namespace distributed {
namespace auto_parallel {
TEST(DistributedMapper, Ctor) {
std::vector<int64_t> shape = {2, 3};
std::vector<int64_t> device_ids = {0, 1, 2, 3, 4, 5};
std::vector<std::string> dim_names = {"x", "y"};
std::string device_type = "GPU";
int64_t size = shape[0] * shape[1];
DeviceMesh device_mesh("device_mesh", shape, device_ids, dim_names);
for (int64_t i = 0; i < shape[0]; ++i) {
for (int64_t j = 0; j < shape[1]; ++j) {
int64_t global_id = i * shape[1] + j;
int64_t local_id = j;
int64_t machine_id = i;
device_mesh.add_device(
Device(global_id, local_id, machine_id, device_type));
}
}
for (int64_t i = 0; i < size; ++i) {
for (int64_t j = 0; j < size; ++j) {
device_mesh.add_link(Link(i, j, "NVL"));
}
}
DistributedMapper dist_mapper;
dist_mapper.add_device_mesh(device_mesh);
std::map<int64_t, std::pair<std::string, std::vector<int64_t>>>
process_id_to_device_ids;
process_id_to_device_ids[0] = {"device_mesh", {5}};
process_id_to_device_ids[1] = {"device_mesh", {4}};
process_id_to_device_ids[2] = {"device_mesh", {3}};
process_id_to_device_ids[3] = {"device_mesh", {2}};
process_id_to_device_ids[4] = {"device_mesh", {1}};
process_id_to_device_ids[5] = {"device_mesh", {0}};
dist_mapper.set_process_id_to_device_ids(process_id_to_device_ids);
EXPECT_EQ(dist_mapper.device_meshes().at("device_mesh"), device_mesh);
EXPECT_EQ(dist_mapper.device_mesh("device_mesh"), device_mesh);
EXPECT_EQ(dist_mapper.process_id_to_device_ids(), process_id_to_device_ids);
std::stringstream sstream;
sstream << dist_mapper;
EXPECT_EQ(sstream.str(), dist_mapper.to_string());
auto proto = phi::distributed::to_proto(dist_mapper);
DistributedMapper new_dist_mapper = DistributedMapper::from_proto(proto);
EXPECT_EQ(dist_mapper, new_dist_mapper);
}
} // namespace auto_parallel
} // namespace distributed
} // namespace phi
@@ -0,0 +1,72 @@
/* 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 "paddle/phi/core/distributed/auto_parallel/dist_tensor.h"
#include <iostream>
#include "gtest/gtest.h"
#include "paddle/phi/core/distributed/auto_parallel/dist_attr.h"
#include "test/cpp/phi/core/allocator.h"
namespace phi {
namespace distributed {
namespace tests {
TEST(dist_tensor, constructor) {
auto fancy_allocator =
std::unique_ptr<Allocator>(new phi::tests::FancyAllocator);
auto* alloc = fancy_allocator.get();
DataType dtype{DataType::FLOAT16};
DDim dims({3, 4});
DenseTensorMeta meta(dtype, dims);
auto dist_attr = TensorDistAttr(common::vectorize(dims));
std::vector<int64_t> mesh_shape = {1};
std::vector<int64_t> process_ids = {0};
std::vector<std::string> dim_names = {"x"};
ProcessMesh mesh(mesh_shape, process_ids, dim_names);
dist_attr.set_process_mesh(mesh);
// copy construct
std::shared_ptr<DenseTensor> x1 = std::make_shared<DenseTensor>(alloc, meta);
DistTensor dist_x1(x1, dist_attr);
EXPECT_TRUE(dist_x1.defined());
EXPECT_TRUE(dist_x1.initialized());
EXPECT_TRUE(dist_x1.valid());
EXPECT_EQ(dist_x1.numel(), 12L);
EXPECT_EQ(dist_x1.local_dims()[0], 3L);
EXPECT_EQ(dist_x1.local_dims()[1], 4L);
// empty construct
DistTensor dist_x2(dims, dist_attr);
EXPECT_TRUE(!dist_x2.defined());
EXPECT_TRUE(!dist_x2.initialized());
// allocate error test
bool caught_exception = false;
try {
dist_x2.AllocateFrom(alloc, phi::DataType::FLOAT32, 12L, false);
} catch (common::enforce::EnforceNotMet& error) {
caught_exception = true;
EXPECT_NE(std::string(error.what()).find("Unavailable"), 0UL);
}
EXPECT_TRUE(caught_exception);
}
} // namespace tests
} // namespace distributed
} // namespace phi
@@ -0,0 +1,116 @@
/* 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 "test/cpp/auto_parallel/spmd_rule_test_util.h"
namespace paddle {
namespace distributed {
namespace auto_parallel {
TEST(ExpandAsInferSpmd, Ctor) {
// Sharding along axes besides softmax axis.
std::vector<int64_t> x_shape = {1, 48};
std::vector<int64_t> y_shape = {2, 32, 48};
std::vector<int64_t> mesh_shape = {2, 3};
std::vector<int64_t> process_ids = {0, 1, 2, 3, 4, 5};
std::vector<std::string> dim_names = {"x", "y"};
ProcessMesh process_mesh(mesh_shape, process_ids, dim_names);
TensorDistAttr x_dist_attr = TensorDistAttr();
x_dist_attr.set_process_mesh(process_mesh);
x_dist_attr.set_dims_mapping(std::vector<int64_t>({-1, -1}));
x_dist_attr.set_dynamic_dims(std::vector<bool>({false, false}));
TensorDistAttr y_dist_attr = TensorDistAttr();
y_dist_attr.set_process_mesh(process_mesh);
y_dist_attr.set_dims_mapping(std::vector<int64_t>({0, 1, -1}));
y_dist_attr.set_dynamic_dims(std::vector<bool>({false, false, false}));
phi::distributed::DistMetaTensor x(phi::make_ddim(x_shape), x_dist_attr);
phi::distributed::DistMetaTensor y(phi::make_ddim(y_shape), y_dist_attr);
// test info forward
auto spmdinfo = ExpandAsInferSpmd(x, y, y_shape);
EXPECT_EQ(spmdinfo.first.size(), 2UL);
EXPECT_EQ(spmdinfo.second.size(), 1UL);
EXPECT_EQ(get_dims_mapping(spmdinfo.first[0]),
std::vector<int64_t>({-1, -1}));
EXPECT_EQ(get_dims_mapping(spmdinfo.first[1]),
std::vector<int64_t>({0, 1, -1}));
EXPECT_EQ(get_dims_mapping(spmdinfo.second[0]),
std::vector<int64_t>({0, 1, -1}));
EXPECT_DOUBLE_EQ(
PADDLE_GET_CONST(TensorDistAttr, spmdinfo.second[0]).is_partial(), false);
VLOG(4) << "Test ExpandAsInferSpmd" << std::endl << std::endl << std::endl;
// test info forward without y
// x [1, 48], target [2, 32, 48]: [-1, -1] -> [-1, -1, -1]
spmdinfo = ExpandAsInferSpmd(x, phi::distributed::DistMetaTensor(), y_shape);
EXPECT_EQ(spmdinfo.first.size(), 2UL);
EXPECT_EQ(spmdinfo.second.size(), 1UL);
EXPECT_EQ(get_dims_mapping(spmdinfo.first[0]),
std::vector<int64_t>({-1, -1}));
const phi::distributed::ArgDistAttr& attr = spmdinfo.first[1];
if (paddle::holds_alternative<phi::distributed::TensorDistAttr>(attr)) {
EXPECT_EQ(paddle::get<phi::distributed::TensorDistAttr>(attr),
phi::distributed::TensorDistAttr());
} else {
FAIL() << "forward_info.first[1] is not TensorDistAttr";
}
EXPECT_EQ(get_dims_mapping(spmdinfo.second[0]),
std::vector<int64_t>({-1, -1, -1}));
EXPECT_DOUBLE_EQ(
PADDLE_GET_CONST(TensorDistAttr, spmdinfo.second[0]).is_partial(), false);
VLOG(4) << "Test ExpandAsInferSpmd" << std::endl << std::endl << std::endl;
// test info reverse
spmdinfo = ExpandAsInferSpmdReverse(x, y, y, y_shape);
EXPECT_EQ(spmdinfo.first.size(), 2UL);
EXPECT_EQ(spmdinfo.second.size(), 1UL);
EXPECT_EQ(get_dims_mapping(spmdinfo.first[0]),
std::vector<int64_t>({-1, -1}));
EXPECT_EQ(get_dims_mapping(spmdinfo.first[1]),
std::vector<int64_t>({0, 1, -1}));
EXPECT_EQ(get_dims_mapping(spmdinfo.second[0]),
std::vector<int64_t>({0, 1, -1}));
EXPECT_DOUBLE_EQ(
PADDLE_GET_CONST(TensorDistAttr, spmdinfo.second[0]).is_partial(), false);
VLOG(4) << "Test ExpandAsInferSpmdReverse" << std::endl
<< std::endl
<< std::endl;
// test info grad
spmdinfo = ExpandAsGradInferSpmd(x, y, y_shape);
EXPECT_EQ(spmdinfo.first.size(), 2UL);
EXPECT_EQ(spmdinfo.second.size(), 1UL);
EXPECT_EQ(get_dims_mapping(spmdinfo.first[0]),
std::vector<int64_t>({-1, -1}));
EXPECT_EQ(get_dims_mapping(spmdinfo.first[1]),
std::vector<int64_t>({0, 1, -1}));
EXPECT_EQ(get_dims_mapping(spmdinfo.second[0]),
std::vector<int64_t>({-1, -1}));
check_partial_dims(spmdinfo.second[0], {0, 1});
VLOG(4) << "Test ExpandAsGradInferSpmd" << std::endl
<< std::endl
<< std::endl;
}
} // namespace auto_parallel
} // namespace distributed
} // namespace paddle
@@ -0,0 +1,105 @@
/* Copyright (c) 2025 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 "test/cpp/auto_parallel/spmd_rule_test_util.h"
namespace paddle {
namespace distributed {
namespace auto_parallel {
ProcessMesh CreateProcessMesh() {
std::vector<int64_t> mesh_shape = {2, 3};
std::vector<int64_t> process_ids = {0, 1, 2, 3, 4, 5};
std::vector<std::string> dim_names = {"x", "y"};
return ProcessMesh(mesh_shape, process_ids, dim_names);
}
phi::distributed::DistMetaTensor CreateDistMetaTensor(
const std::vector<int64_t>& shape,
const std::vector<int64_t>& dims_mapping,
const ProcessMesh& process_mesh) {
TensorDistAttr dist_attr;
dist_attr.set_process_mesh(process_mesh);
dist_attr.set_dims_mapping(dims_mapping);
return phi::distributed::DistMetaTensor(phi::make_ddim(shape), dist_attr);
}
TEST(ExpandInferSpmd, Ctor) {
ProcessMesh process_mesh = CreateProcessMesh();
// Test case forward 1: Expand with shape {8, 2, 6, 1024, -1}
auto x = CreateDistMetaTensor(
{8, 2, 1, 1024, 128}, {0, -1, -1, 1, -1}, process_mesh);
phi::IntArray shape = {8, 2, 6, 1024, -1};
auto spmdinfo = ExpandInferSpmd(x, shape);
EXPECT_EQ(get_dims_mapping(spmdinfo.first[0]),
std::vector<int64_t>({0, -1, -1, 1, -1}));
EXPECT_EQ(get_dims_mapping(spmdinfo.second[0]),
std::vector<int64_t>({0, -1, -1, 1, -1}));
// Test case forward 2: Expand with shape {2, -1}
auto x1 = CreateDistMetaTensor({8}, {1}, process_mesh);
phi::IntArray shape1 = {2, -1};
auto spmdinfo1 = ExpandInferSpmd(x1, shape1);
EXPECT_EQ(get_dims_mapping(spmdinfo1.first[0]), std::vector<int64_t>({1}));
EXPECT_EQ(get_dims_mapping(spmdinfo1.second[0]),
std::vector<int64_t>({-1, 1}));
// Test case forward 3: Expand with shape {0, -1}
auto x2 = CreateDistMetaTensor({8}, {1}, process_mesh);
phi::IntArray shape2 = {0, -1};
auto spmdinfo2 = ExpandInferSpmd(x2, shape2);
EXPECT_EQ(get_dims_mapping(spmdinfo2.first[0]), std::vector<int64_t>({1}));
EXPECT_EQ(get_dims_mapping(spmdinfo2.second[0]),
std::vector<int64_t>({-1, 1}));
// Test case backward 1: ExpandGrad with shape {0, -1}
auto x3 = CreateDistMetaTensor({8}, {1}, process_mesh);
auto out3 = CreateDistMetaTensor({2, 8}, {-1, 1}, process_mesh);
phi::IntArray shape3 = {0, -1};
auto spmdinfo3 = ExpandGradInferSpmd(x3, out3, shape3);
EXPECT_EQ(get_dims_mapping(spmdinfo3.first[0]), std::vector<int64_t>({1}));
EXPECT_EQ(get_dims_mapping(spmdinfo3.first[1]),
std::vector<int64_t>({-1, 1}));
EXPECT_EQ(get_dims_mapping(spmdinfo3.second[0]), std::vector<int64_t>({1}));
// Test case backward 2: ExpandGrad with shape {2, 2, -1}
auto x4 = CreateDistMetaTensor({1, 8}, {-1, 1}, process_mesh);
auto out4 = CreateDistMetaTensor({2, 2, 8}, {-1, -1, 1}, process_mesh);
phi::IntArray shape4 = {2, 2, -1};
auto spmdinfo4 = ExpandGradInferSpmd(x4, out4, shape4);
EXPECT_EQ(get_dims_mapping(spmdinfo4.first[0]),
std::vector<int64_t>({-1, 1}));
EXPECT_EQ(get_dims_mapping(spmdinfo4.first[1]),
std::vector<int64_t>({-1, -1, 1}));
EXPECT_EQ(get_dims_mapping(spmdinfo4.second[0]),
std::vector<int64_t>({-1, 1}));
// Test case backward 3: ExpandGrad with shape {2, 2, -1}
auto x5 = CreateDistMetaTensor({1, 8}, {-1, 1}, process_mesh);
auto out5 = CreateDistMetaTensor({2, 2, 8}, {-1, 0, 1}, process_mesh);
phi::IntArray shape5 = {2, 2, -1};
auto spmdinfo5 = ExpandGradInferSpmd(x5, out5, shape5);
EXPECT_EQ(get_dims_mapping(spmdinfo5.first[0]),
std::vector<int64_t>({-1, 1}));
EXPECT_EQ(get_dims_mapping(spmdinfo5.first[1]),
std::vector<int64_t>({-1, 0, 1}));
EXPECT_EQ(get_dims_mapping(spmdinfo5.second[0]),
std::vector<int64_t>({-1, 1}));
EXPECT_EQ(get_partial_dims(spmdinfo5.second[0]), std::set<int64_t>({0}));
}
} // namespace auto_parallel
} // namespace distributed
} // namespace paddle
@@ -0,0 +1,103 @@
/* 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 "test/cpp/auto_parallel/spmd_rule_test_util.h"
namespace paddle {
namespace distributed {
namespace auto_parallel {
TEST(FusedLinearParamGradAddSPMDRule, Ctor) {
// build input data class
std::vector<int64_t> mesh_shape = {2, 4};
std::vector<int64_t> process_ids = {0, 1, 2, 3, 4, 5, 6, 7};
std::vector<std::string> dim_names = {"x", "y"};
ProcessMesh process_mesh(mesh_shape, process_ids, dim_names);
// b s h
std::vector<int64_t> x_shape = {2, 512, 1024};
std::vector<int64_t> out_shape = {2, 512, 2048};
std::vector<int64_t> weight_shape = {1024, 2048};
std::vector<int64_t> bias_shape = {2048};
// test mp col split
{
TensorDistAttr x_dist_attr = TensorDistAttr();
x_dist_attr.set_process_mesh(process_mesh);
x_dist_attr.set_dims_mapping(std::vector<int64_t>({0, -1, -1}));
x_dist_attr.set_dynamic_dims(std::vector<bool>({false, false, false}));
TensorDistAttr out_dist_attr = TensorDistAttr();
out_dist_attr.set_process_mesh(process_mesh);
out_dist_attr.set_dims_mapping(std::vector<int64_t>({0, -1, 1}));
out_dist_attr.set_dynamic_dims(std::vector<bool>({false, false, false}));
phi::distributed::DistMetaTensor x(phi::make_ddim(x_shape), x_dist_attr);
phi::distributed::DistMetaTensor out(phi::make_ddim(out_shape),
out_dist_attr);
phi::distributed::DistMetaTensor dweight;
phi::distributed::DistMetaTensor dbias;
for (int i = 0; i < 3; i++) {
auto spmd_info =
FusedLinearParamGradAddInferSpmd(x, out, dweight, dbias, 0, true);
check_dim_mapping(spmd_info.second[0], {-1, 1});
check_partial_dims(spmd_info.second[0], {0});
check_dim_mapping(spmd_info.second[1], {1});
check_partial_dims(spmd_info.second[1], {0});
dweight = phi::distributed::DistMetaTensor(
phi::make_ddim(weight_shape),
PADDLE_GET_CONST(TensorDistAttr, spmd_info.second[0]));
dbias = phi::distributed::DistMetaTensor(
phi::make_ddim(bias_shape),
PADDLE_GET_CONST(TensorDistAttr, spmd_info.second[1]));
}
}
// test mp row split
{
TensorDistAttr x_dist_attr = TensorDistAttr();
x_dist_attr.set_process_mesh(process_mesh);
x_dist_attr.set_dims_mapping(std::vector<int64_t>({0, -1, 1}));
x_dist_attr.set_dynamic_dims(std::vector<bool>({false, false, false}));
TensorDistAttr out_dist_attr = TensorDistAttr();
out_dist_attr.set_process_mesh(process_mesh);
out_dist_attr.set_dims_mapping(std::vector<int64_t>({0, -1, -1}));
out_dist_attr.set_dynamic_dims(std::vector<bool>({false, false, false}));
phi::distributed::DistMetaTensor x(phi::make_ddim(x_shape), x_dist_attr);
phi::distributed::DistMetaTensor out(phi::make_ddim(out_shape),
out_dist_attr);
phi::distributed::DistMetaTensor dweight;
phi::distributed::DistMetaTensor dbias;
for (int i = 0; i < 3; i++) {
auto spmd_info =
FusedLinearParamGradAddInferSpmd(x, out, dweight, dbias, 0, true);
check_dim_mapping(spmd_info.second[0], {1, -1});
check_partial_dims(spmd_info.second[0], {0});
check_dim_mapping(spmd_info.second[1], {-1});
check_partial_dims(spmd_info.second[1], {0});
dweight = phi::distributed::DistMetaTensor(
phi::make_ddim(weight_shape),
PADDLE_GET_CONST(TensorDistAttr, spmd_info.second[0]));
dbias = phi::distributed::DistMetaTensor(
phi::make_ddim(bias_shape),
PADDLE_GET_CONST(TensorDistAttr, spmd_info.second[1]));
}
}
}
} // namespace auto_parallel
} // namespace distributed
} // namespace paddle
@@ -0,0 +1,110 @@
/* Copyright (c) 2024 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 "test/cpp/auto_parallel/spmd_rule_test_util.h"
namespace paddle {
namespace distributed {
namespace auto_parallel {
TEST(FusedRmsNormSPMDRule, test_fused_rms_norm) {
// build input data class
std::vector<int64_t> x_shape = {64, 32, 1024};
std::vector<int64_t> scale_shape = {1024};
std::vector<int64_t> variance_shape = {64, 32};
std::vector<int64_t> mesh_shape = {2, 3};
std::vector<int64_t> process_ids = {0, 1, 2, 3, 4, 5};
std::vector<std::string> dim_names = {"x", "y"};
ProcessMesh process_mesh(mesh_shape, process_ids, dim_names);
TensorDistAttr x_dist_attr = TensorDistAttr();
x_dist_attr.set_process_mesh(process_mesh);
x_dist_attr.set_dims_mapping(std::vector<int64_t>({1, -1, -1}));
x_dist_attr.set_dynamic_dims(std::vector<bool>({false, false, false}));
TensorDistAttr scale_dist_attr = TensorDistAttr();
scale_dist_attr.set_process_mesh(process_mesh);
scale_dist_attr.set_dims_mapping(std::vector<int64_t>({-1}));
scale_dist_attr.set_dynamic_dims(std::vector<bool>({false}));
x_dist_attr.set_dims_mapping({1, -1, -1});
scale_dist_attr.set_dims_mapping(std::vector<int64_t>{-1});
phi::distributed::DistMetaTensor x(common::make_ddim(x_shape), x_dist_attr);
phi::distributed::DistMetaTensor scale(common::make_ddim(scale_shape),
scale_dist_attr);
auto inferred_dist_attrs = phi::distributed::RmsNormInferSpmd(x, scale, 0.5);
size_t input_size = 2;
size_t output_size = 2;
EXPECT_EQ(inferred_dist_attrs.first.size(), input_size);
EXPECT_EQ(inferred_dist_attrs.second.size(), output_size);
check_dim_mapping(inferred_dist_attrs.first[0], {1, -1, -1});
check_dim_mapping(inferred_dist_attrs.first[1], {-1});
check_dim_mapping(inferred_dist_attrs.second[0], {1, -1, -1});
check_dim_mapping(inferred_dist_attrs.second[1], {1, -1});
VLOG(4) << "test1 done.";
x_dist_attr.set_dims_mapping({1, 0, -1});
scale_dist_attr.set_dims_mapping(std::vector<int64_t>{0});
x = phi::distributed::DistMetaTensor(common::make_ddim(x_shape), x_dist_attr);
scale = phi::distributed::DistMetaTensor(common::make_ddim(scale_shape),
scale_dist_attr);
inferred_dist_attrs = phi::distributed::RmsNormInferSpmd(x, scale, 0.5);
check_dim_mapping(inferred_dist_attrs.first[0], {1, 0, -1});
check_dim_mapping(inferred_dist_attrs.first[1], {-1});
check_dim_mapping(inferred_dist_attrs.second[0], {1, 0, -1});
check_dim_mapping(inferred_dist_attrs.second[1], {1, 0});
VLOG(4) << "test2 done.";
TensorDistAttr out_dist_attr = TensorDistAttr();
out_dist_attr.set_process_mesh(process_mesh);
out_dist_attr.set_dims_mapping(std::vector<int64_t>({0, 1, -1}));
out_dist_attr.set_dynamic_dims(std::vector<bool>({false, false, false}));
phi::distributed::DistMetaTensor out(common::make_ddim(x_shape),
out_dist_attr);
TensorDistAttr invvar_dist_attr = TensorDistAttr();
invvar_dist_attr.set_process_mesh(process_mesh);
invvar_dist_attr.set_dims_mapping(std::vector<int64_t>({0, -1}));
invvar_dist_attr.set_dynamic_dims(std::vector<bool>({false, false}));
phi::distributed::DistMetaTensor invvar(common::make_ddim(variance_shape),
invvar_dist_attr);
inferred_dist_attrs =
phi::distributed::RmsNormInferSpmdReverse(x, scale, out, invvar, 0.5);
check_dim_mapping(inferred_dist_attrs.first[0], {0, 1, -1});
check_dim_mapping(inferred_dist_attrs.first[1], {-1});
check_dim_mapping(inferred_dist_attrs.second[0], {0, 1, -1});
check_dim_mapping(inferred_dist_attrs.second[1], {0, 1});
VLOG(4) << "test3 done.";
x_dist_attr.set_dims_mapping({0, 1, -1});
x = phi::distributed::DistMetaTensor(common::make_ddim(x_shape), x_dist_attr);
inferred_dist_attrs =
phi::distributed::RmsNormGradInferSpmd(x, scale, invvar, out, 0.5);
check_dim_mapping(inferred_dist_attrs.first[0], {0, 1, -1});
check_dim_mapping(inferred_dist_attrs.first[1], {-1});
check_dim_mapping(inferred_dist_attrs.first[2], {0, 1});
check_dim_mapping(inferred_dist_attrs.first[3], {0, 1, -1});
check_dim_mapping(inferred_dist_attrs.second[0], {0, 1, -1});
check_dim_mapping(inferred_dist_attrs.second[1], {-1});
check_partial_dims(inferred_dist_attrs.second[1], {0, 1});
}
} // namespace auto_parallel
} // namespace distributed
} // namespace paddle
@@ -0,0 +1,286 @@
/* Copyright (c) 2025 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 <set>
#include "test/cpp/auto_parallel/spmd_rule_test_util.h"
namespace paddle {
namespace distributed {
namespace auto_parallel {
struct IndexSelectTestCase {
// input
std::vector<int64_t> x_shape;
std::vector<std::vector<int64_t>> x_dims_mapping;
std::vector<int64_t> index_shape;
std::vector<std::vector<int64_t>> index_dims_mapping;
// axis attribute
int axis;
// output
std::vector<std::vector<int64_t>> expected_x_dims_mapping;
std::vector<std::vector<int64_t>> expected_index_dims_mapping;
std::vector<std::vector<int64_t>> expected_out_dims_mapping;
};
struct IndexSelectGradTestCase {
// input
std::vector<int64_t> x_shape;
std::vector<std::vector<int64_t>> x_dims_mapping;
std::vector<int64_t> index_shape;
std::vector<std::vector<int64_t>> index_dims_mapping;
std::vector<int64_t> out_grad_shape;
std::vector<std::vector<int64_t>> out_grad_dims_mapping;
// axis attribute
int axis;
// output
std::vector<std::vector<int64_t>> expected_x_dims_mapping;
std::vector<std::vector<int64_t>> expected_index_dims_mapping;
std::vector<std::vector<int64_t>> expected_out_grad_dims_mapping;
std::vector<std::vector<int64_t>> expected_x_grad_dims_mapping;
std::set<int64_t> partial_dims;
};
TEST(IndexSelectInferSpmd, Ctor) {
std::vector<int64_t> mesh_shape = {2, 2, 2};
std::vector<int64_t> process_ids = {0, 1, 2, 3, 4, 5, 6, 7};
std::vector<std::string> dim_names = {"x", "y", "z"};
ProcessMesh process_mesh(mesh_shape, process_ids, dim_names);
std::vector<IndexSelectTestCase> test_cases = {
// [8, 16, 32], [8], axis = 1
// [[0,1],[2],[]], [[]] -> [[0,1],[],[]], [[]], [[0,1],[],[]]
{{8, 16, 32},
{{0, 1}, {2}, {}},
{8},
{{}},
1,
{{0, 1}, {}, {}},
{{}},
{{0, 1}, {}, {}}},
// [8, 16, 32], [8], axis = 1
// [[0,1],[2],[]], [[2]] -> [[0,1],[],[]], [[2]], [[0,1],[2],[]]
{{8, 16, 32},
{{0, 1}, {2}, {}},
{8},
{{2}},
1,
{{0, 1}, {}, {}},
{{2}},
{{0, 1}, {2}, {}}},
// [8, 16, 32], [8], axis = 1
// [[0,1],[2],[]], [[0]] -> [[0,1],[],[]], [[]], [[0,1],[],[]]
{{8, 16, 32},
{{0, 1}, {2}, {}},
{8},
{{0}},
1,
{{0, 1}, {}, {}},
{{}},
{{0, 1}, {}, {}}},
// [8, 16, 32], [8], axis = 1
// [[2],[],[]], [[0,1]] -> [[2],[],[]], [[0,1]], [[2],[0,1],[]]
{{8, 16, 32},
{{2}, {}, {}},
{8},
{{0, 1}},
1,
{{2}, {}, {}},
{{0, 1}},
{{2}, {0, 1}, {}}},
// [8, 16, 32], [8], axis = 1
// [[0],[],[]], [[0,1]] -> [[0],[],[]], [[1]], [[0],[1],[]]
{{8, 16, 32},
{{0}, {}, {}},
{8},
{{0, 1}},
1,
{{0}, {}, {}},
{{1}},
{{0}, {1}, {}}},
};
for (const auto& tc : test_cases) {
TensorDistAttr x_dist_attr = TensorDistAttr();
x_dist_attr.set_process_mesh(process_mesh);
x_dist_attr.set_dims_mapping(tc.x_dims_mapping);
x_dist_attr.set_dynamic_dims(std::vector<bool>(tc.x_shape.size(), false));
phi::distributed::DistMetaTensor x = phi::distributed::DistMetaTensor(
common::make_ddim(tc.x_shape), x_dist_attr);
TensorDistAttr index_dist_attr = TensorDistAttr();
index_dist_attr.set_process_mesh(process_mesh);
index_dist_attr.set_dims_mapping(tc.index_dims_mapping);
index_dist_attr.set_dynamic_dims(
std::vector<bool>(tc.index_shape.size(), false));
phi::distributed::DistMetaTensor index = phi::distributed::DistMetaTensor(
common::make_ddim(tc.index_shape), index_dist_attr);
// test forward
phi::distributed::SpmdInfo forward_spmd_info =
phi::distributed::IndexSelectInferSpmd(x, index, tc.axis);
EXPECT_EQ(forward_spmd_info.first.size(), static_cast<size_t>(2));
EXPECT_EQ(forward_spmd_info.second.size(), static_cast<size_t>(1));
check_multi_dims_mapping(forward_spmd_info.first[0],
tc.expected_x_dims_mapping);
check_multi_dims_mapping(forward_spmd_info.first[1],
tc.expected_index_dims_mapping);
check_multi_dims_mapping(forward_spmd_info.second[0],
tc.expected_out_dims_mapping);
}
}
TEST(IndexSelectGradInferSpmd, Ctor) {
std::vector<int64_t> mesh_shape = {2, 2, 2};
std::vector<int64_t> process_ids = {0, 1, 2, 3, 4, 5, 6, 7};
std::vector<std::string> dim_names = {"x", "y", "z"};
ProcessMesh process_mesh(mesh_shape, process_ids, dim_names);
std::vector<IndexSelectGradTestCase> test_cases = {
// [8, 16, 32], [8], [8, 8, 32], axis = 1
// [[0,1],[2],[]], [[]], [[0,1], [], []] -> [[0,1],[],[]], [[]],
// [[0,1],[],[]], [[0,1],[],[]]
{{8, 16, 32},
{{0, 1}, {2}, {}},
{8},
{{}},
{8, 8, 32},
{{0, 1}, {2}, {}},
1,
{{0, 1}, {}, {}},
{{}},
{{0, 1}, {}, {}},
{{0, 1}, {}, {}},
{}},
// [8, 16, 32], [8], [8, 8, 32], axis = 1
// [[0,1],[2],[]], [[2]], [[0,1],[2],[]] -> [[0,1],[],[]], [[2]],
// [[0,1],[2],[]], [[0,1],[],[]]
{{8, 16, 32},
{{0, 1}, {2}, {}},
{8},
{{2}},
{8, 8, 32},
{{0, 1}, {2}, {}},
1,
{{0, 1}, {}, {}},
{{2}},
{{0, 1}, {2}, {}},
{{0, 1}, {}, {}},
{2}},
// [8, 16, 32], [8], [8, 8, 32], axis = 1
// [[0,1],[2],[]], [[0]], [[0,1],[],[]] -> [[0,1],[],[]], [[]],
// [[0,1],[],[]], [[0,1],[],[]]
{{8, 16, 32},
{{0, 1}, {2}, {}},
{8},
{{0}},
{8, 8, 32},
{{0, 1}, {}, {}},
1,
{{0, 1}, {}, {}},
{{}},
{{0, 1}, {}, {}},
{{0, 1}, {}, {}},
{}},
// [8, 16, 32], [8], [8, 8, 32], axis = 1
// [[2],[],[]], [[0,1]], [[2],[0,1],[]] -> [[2],[],[]], [[0,1]],
// [[2],[0,1],[]], [[2],[],[]]
{{8, 16, 32},
{{2}, {}, {}},
{8},
{{0, 1}},
{8, 8, 32},
{{2}, {0, 1}, {}},
1,
{{2}, {}, {}},
{{0, 1}},
{{2}, {0, 1}, {}},
{{2}, {}, {}},
{0, 1}},
// [8, 16, 32], [8], [8, 8, 32], axis = 1
// [[0],[],[]], [[0,1]], [[0],[1],[]] -> [[0],[],[]], [[1]], [[0],[1],[]],
// [[0],[],[]]
{{8, 16, 32},
{{0}, {}, {}},
{8},
{{0, 1}},
{8, 8, 32},
{{0}, {1}, {}},
1,
{{0}, {}, {}},
{{1}},
{{0}, {1}, {}},
{{0}, {}, {}},
{1}},
};
for (const auto& tc : test_cases) {
TensorDistAttr x_dist_attr = TensorDistAttr();
x_dist_attr.set_process_mesh(process_mesh);
x_dist_attr.set_dims_mapping(tc.x_dims_mapping);
x_dist_attr.set_dynamic_dims(std::vector<bool>(tc.x_shape.size(), false));
phi::distributed::DistMetaTensor x = phi::distributed::DistMetaTensor(
common::make_ddim(tc.x_shape), x_dist_attr);
TensorDistAttr index_dist_attr = TensorDistAttr();
index_dist_attr.set_process_mesh(process_mesh);
index_dist_attr.set_dims_mapping(tc.index_dims_mapping);
index_dist_attr.set_dynamic_dims(
std::vector<bool>(tc.index_shape.size(), false));
phi::distributed::DistMetaTensor index = phi::distributed::DistMetaTensor(
common::make_ddim(tc.index_shape), index_dist_attr);
TensorDistAttr out_grad_dist_attr = TensorDistAttr();
out_grad_dist_attr.set_process_mesh(process_mesh);
out_grad_dist_attr.set_dims_mapping(tc.out_grad_dims_mapping);
out_grad_dist_attr.set_dynamic_dims(
std::vector<bool>(tc.out_grad_shape.size(), false));
phi::distributed::DistMetaTensor out_grad =
phi::distributed::DistMetaTensor(common::make_ddim(tc.out_grad_shape),
out_grad_dist_attr);
// test backward
phi::distributed::SpmdInfo backward_spmd_info =
phi::distributed::IndexSelectGradInferSpmd(x, index, out_grad, tc.axis);
EXPECT_EQ(backward_spmd_info.first.size(), static_cast<size_t>(3));
EXPECT_EQ(backward_spmd_info.second.size(), static_cast<size_t>(1));
check_multi_dims_mapping(backward_spmd_info.first[0],
tc.expected_x_dims_mapping);
check_multi_dims_mapping(backward_spmd_info.first[1],
tc.expected_index_dims_mapping);
check_multi_dims_mapping(backward_spmd_info.first[2],
tc.expected_out_grad_dims_mapping);
check_multi_dims_mapping(backward_spmd_info.second[0],
tc.expected_x_grad_dims_mapping);
if (!tc.partial_dims.empty()) {
EXPECT_EQ(is_partial(backward_spmd_info.second[0]), true);
check_partial_dims(backward_spmd_info.second[0], tc.partial_dims);
}
}
}
} // namespace auto_parallel
} // namespace distributed
} // namespace paddle
@@ -0,0 +1,505 @@
/* Copyright (c) 2025 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 <set>
#include "paddle/phi/infermeta/spmd_rules/bmm.h"
#include "test/cpp/auto_parallel/spmd_rule_test_util.h"
namespace paddle {
namespace distributed {
namespace auto_parallel {
struct MatmulTestCase {
// input
std::vector<int64_t> x_shape;
std::vector<std::vector<int64_t>> x_dims_mapping;
std::vector<int64_t> y_shape;
std::vector<std::vector<int64_t>> y_dims_mapping;
// attribute
bool trans_x;
bool trans_y;
// output
std::vector<std::vector<int64_t>> expected_x_dims_mapping;
std::vector<std::vector<int64_t>> expected_y_dims_mapping;
std::vector<std::vector<int64_t>> expected_out_dims_mapping;
std::set<int64_t> partial_dims;
};
struct MatmulGradTestCase {
// input
std::vector<int64_t> x_shape;
std::vector<std::vector<int64_t>> x_dims_mapping;
std::vector<int64_t> y_shape;
std::vector<std::vector<int64_t>> y_dims_mapping;
std::vector<int64_t> out_grad_shape;
std::vector<std::vector<int64_t>> out_grad_dims_mapping;
// attribute
bool trans_x;
bool trans_y;
// output
std::vector<std::vector<int64_t>> expected_x_dims_mapping;
std::vector<std::vector<int64_t>> expected_y_dims_mapping;
std::vector<std::vector<int64_t>> expected_out_grad_dims_mapping;
std::vector<std::vector<int64_t>> expected_x_grad_dims_mapping;
std::vector<std::vector<int64_t>> expected_y_grad_dims_mapping;
std::set<int64_t> x_grad_partial_dims;
std::set<int64_t> y_grad_partial_dims;
};
TEST(MatmulInferSpmd, Ctor) {
std::vector<int64_t> mesh_shape = {2, 2, 2};
std::vector<int64_t> process_ids = {0, 1, 2, 3, 4, 5, 6, 7};
std::vector<std::string> dim_names = {"x", "y", "z"};
ProcessMesh process_mesh(mesh_shape, process_ids, dim_names);
std::vector<MatmulTestCase> test_cases = {
// [64, 32], [32, 48], trans_x=false, trans_y=false
// [[0,1], []] ,[[],[2]] -> [[0,1], []] ,[[],[2]],[[0,1],[2]]
{{64, 32},
{{0, 1}, {}},
{32, 48},
{{}, {2}},
false,
false,
{{0, 1}, {}},
{{}, {2}},
{{0, 1}, {2}},
{}},
// [64, 32], [32, 48], trans_x=false, trans_y=false
// [[0,1], [2]] ,[[],[]] -> [[0,1], [2]] ,[[2],[]],[[0,1],[]], partial: 2
{{64, 32},
{{0, 1}, {2}},
{32, 48},
{{}, {}},
false,
false,
{{0, 1}, {2}},
{{2}, {}},
{{0, 1}, {}},
{2}},
// [64, 32], [32, 48], trans_x=false, trans_y=false
// [[], []] ,[[0,1],[2]] -> [[],[0,1]] ,[[0,1],[2],[[],[2]], partial:
// {0,1}
{{64, 32},
{{}, {}},
{32, 48},
{{0, 1}, {2}},
false,
false,
{{}, {0, 1}},
{{0, 1}, {2}},
{{}, {2}},
{0, 1}},
// [64, 32], [32, 48], trans_x=false, trans_y=false
// [[0], [1]] ,[[2],[0]] -> [[0], [1,2]] ,[[1,2],[]],[[0],[]], partial:
// {1,2}
{{64, 32},
{{0}, {1}},
{32, 48},
{{2}, {0}},
false,
false,
{{0}, {1, 2}},
{{1, 2}, {}},
{{0}, {}},
{1, 2}},
// [64, 32], [32, 48], trans_x=false, trans_y=false
// [[0,1], [2]] ,[[0],[]] -> [[0,1], [2]] ,[[2],[]],[[0,1],[]], partial: 2
{{64, 32},
{{0, 1}, {2}},
{32, 48},
{{0}, {}},
false,
false,
{{0, 1}, {2}},
{{2}, {}},
{{0, 1}, {}},
{2}},
// [512, 48, 64, 32], [1, 32, 48], trans_x=false, trans_y=false
// [[0,1],[2],[],[]] ,[[],[],[]] -> [[0,1],[2],[],[]]
// ,[[],[],[]],[[0,1],[2],[],[]],
// partial: {}
{{512, 48, 64, 32},
{{0, 1}, {2}, {}, {}},
{1, 32, 48},
{{}, {}, {}},
false,
false,
{{0, 1}, {2}, {}, {}},
{{}, {}, {}},
{{0, 1}, {2}, {}, {}},
{}},
// [512, 48, 32, 64], [1, 32, 48], trans_x=true, trans_y=false
// [[0],[],[1,2],[]] ,[[],[],[2]] -> [[0],[],[1],[]]
// ,[[],[1],[2]],[[0],[],[],[2]],
// partial: {1}
{{512, 48, 32, 64},
{{0}, {}, {1, 2}, {}},
{1, 32, 48},
{{}, {}, {2}},
true,
false,
{{0}, {}, {1}, {}},
{{}, {1}, {2}},
{{0}, {}, {}, {2}},
{1}},
// [512, 48, 64, 32], [1, 48, 32], trans_x=false, trans_y=true
// [[0],[],[1,2],[]] ,[[],[0],[]] -> [[0],[],[1,2],[]]
// ,[[],[],[]],[[0],[],[1,2],[]],
// partial: {}
{{512, 48, 64, 32},
{{0}, {}, {1, 2}, {}},
{1, 48, 32},
{{}, {0}, {}},
false,
true,
{{0}, {}, {1, 2}, {}},
{{}, {}, {}},
{{0}, {}, {1, 2}, {}},
{}},
// [512, 48, 32, 64], [1, 48, 32], trans_x=true, trans_y=true
// [[],[],[0,1],[2]] ,[[],[0,1],[2]] -> [[],[],[],[2]]
// ,[[],[0,1],[]],[[],[],[2],[0,1]],
// partial: {}
{{512, 48, 32, 64},
{{}, {}, {0, 1}, {2}},
{1, 48, 32},
{{}, {0, 1}, {2}},
true,
true,
{{}, {}, {}, {2}},
{{}, {0, 1}, {}},
{{}, {}, {2}, {0, 1}},
{}},
};
for (const auto& tc : test_cases) {
TensorDistAttr x_dist_attr = TensorDistAttr();
x_dist_attr.set_process_mesh(process_mesh);
x_dist_attr.set_dims_mapping(tc.x_dims_mapping);
x_dist_attr.set_dynamic_dims(std::vector<bool>(tc.x_shape.size(), false));
phi::distributed::DistMetaTensor x = phi::distributed::DistMetaTensor(
common::make_ddim(tc.x_shape), x_dist_attr);
TensorDistAttr y_dist_attr = TensorDistAttr();
y_dist_attr.set_process_mesh(process_mesh);
y_dist_attr.set_dims_mapping(tc.y_dims_mapping);
y_dist_attr.set_dynamic_dims(std::vector<bool>(tc.y_shape.size(), false));
phi::distributed::DistMetaTensor y = phi::distributed::DistMetaTensor(
common::make_ddim(tc.y_shape), y_dist_attr);
// test forward
phi::distributed::SpmdInfo forward_spmd_info =
phi::distributed::MatmulInferSpmd(x, y, tc.trans_x, tc.trans_y);
EXPECT_EQ(forward_spmd_info.first.size(), static_cast<size_t>(2));
EXPECT_EQ(forward_spmd_info.second.size(), static_cast<size_t>(1));
check_multi_dims_mapping(forward_spmd_info.first[0],
tc.expected_x_dims_mapping);
check_multi_dims_mapping(forward_spmd_info.first[1],
tc.expected_y_dims_mapping);
check_multi_dims_mapping(forward_spmd_info.second[0],
tc.expected_out_dims_mapping);
if (!tc.partial_dims.empty()) {
EXPECT_EQ(is_partial(forward_spmd_info.second[0]), true);
check_partial_dims(forward_spmd_info.second[0], tc.partial_dims);
}
}
}
TEST(MatmulGradInferSpmd, Ctor) {
std::vector<int64_t> mesh_shape = {2, 2, 2};
std::vector<int64_t> process_ids = {0, 1, 2, 3, 4, 5, 6, 7};
std::vector<std::string> dim_names = {"x", "y", "z"};
ProcessMesh process_mesh(mesh_shape, process_ids, dim_names);
std::vector<MatmulGradTestCase> test_cases = {
// [64, 32], [32, 48], [64,48], trans_x=false, trans_y=false
// [[0,1], []] ,[[],[2]], [[0,1],[2]] -> [[0,1], []]
// ,[[],[2]],[[0,1],[2]], [[0,1],[]], [[],[2]], x_partial: {2}, y_partial:
// {0,1}
{{64, 32},
{{0, 1}, {}},
{32, 48},
{{}, {2}},
{64, 48},
{{0, 1}, {2}},
false,
false,
{{0, 1}, {}},
{{}, {2}},
{{0, 1}, {2}},
{{0, 1}, {}},
{{}, {2}},
{2},
{0, 1}},
// [1024,512,64,32], [1,32,48], [1024,512,64,48], trans_x=false,
// trans_y=false
// [[0],[],[1,2],[]] ,[[],[],[2]], [[0],[],[1,2],[]] -> [[0],[],[1,2],[]]
// ,[[],[],[]], [[0],[],[1,2],[]], [[0],[],[1,2],[]], [[],[],[]],
// x_grad_partial: {}, y_grad_partial: {0,1,2}
{{1024, 512, 64, 32},
{{0}, {}, {1, 2}, {}},
{1, 32, 48},
{{}, {}, {2}},
{1024, 512, 64, 48},
{{0}, {}, {1, 2}, {}},
false,
false,
{{0}, {}, {1, 2}, {}},
{{}, {}, {}},
{{0}, {}, {1, 2}, {}},
{{0}, {}, {1, 2}, {}},
{{}, {}, {}},
{},
{0, 1, 2}},
// [1024,512,64,32], [1,32,48], [1024,512,64,48], trans_x=false,
// trans_y=false
// [[],[0],[1,2],[]] ,[[],[],[2]], [[],[0],[1,2],[]] -> [[],[0],[1,2],[]]
// ,[[],[],[]], [[],[0],[1,2],[]], [[],[0],[1,2],[]], [[],[],[]],
// x_grad_partial: {}, y_grad_partial: {0,1,2}
{{1024, 512, 64, 32},
{{}, {0}, {1, 2}, {}},
{1, 32, 48},
{{}, {}, {2}},
{1024, 512, 64, 48},
{{}, {0}, {1, 2}, {}},
false,
false,
{{}, {0}, {1, 2}, {}},
{{}, {}, {}},
{{}, {0}, {1, 2}, {}},
{{}, {0}, {1, 2}, {}},
{{}, {}, {}},
{},
{0, 1, 2}},
// [1024,512,32,64], [1,32,48], [1024,512,64,48], trans_x=true,
// trans_y=false
// [[],[0],[1,2],[]] ,[[],[],[2]], [[],[0],[],[2]] -> [[],[0],[1],[]]
// ,[[],[1],[2]], [[],[0],[],[2]], [[],[0],[1],[]], [[],[1],[2]],
// x_grad_partial: {2}, y_grad_partial: {0}
{{1024, 512, 32, 64},
{{}, {0}, {1, 2}, {}},
{1, 32, 48},
{{}, {}, {2}},
{1024, 512, 64, 48},
{{}, {0}, {}, {2}},
true,
false,
{{}, {0}, {1}, {}},
{{}, {1}, {2}},
{{}, {0}, {}, {2}},
{{}, {0}, {1}, {}},
{{}, {1}, {2}},
{2},
{0}},
// [1024,512,32,64], [1,48,32], [1024,512,64,48], trans_x=true,
// trans_y=true
// [[],[],[1,2],[]] ,[[],[],[0]], [[],[],[],[]] -> [[],[],[0,1,2],[]]
// ,[[],[],[0,1,2]], [[],[],[],[]], [[],[],[0,1,2],[]], [[],[],[0,1,2]],
// x_grad_partial: {}, y_grad_partial: {}
{{1024, 512, 32, 64},
{{}, {}, {1, 2}, {}},
{1, 48, 32},
{{}, {}, {0}},
{1024, 512, 64, 48},
{{}, {}, {}, {}},
true,
true,
{{}, {}, {1, 2, 0}, {}},
{{}, {}, {1, 2, 0}},
{{}, {}, {}, {}},
{{}, {}, {1, 2, 0}, {}},
{{}, {}, {1, 2, 0}},
{},
{}},
// [1024,512,64,32], [1,48,32], [1024,512,64,48], trans_x=false,
// trans_y=true
// [[],[],[0],[1,2]] ,[[],[],[0]], [[],[],[0],[]] -> [[],[],[0],[1,2]]
// ,[[],[],[1,2]], [[],[],[0],[]], [[],[],[0],[1,2]],
// [[],[],[1,2]],
// x_grad_partial: {}, y_grad_partial: {0}
{{1024, 512, 64, 32},
{{}, {}, {0}, {1, 2}},
{1, 48, 32},
{{}, {}, {0}},
{1024, 512, 64, 48},
{{}, {}, {0}, {}},
false,
true,
{{}, {}, {0}, {1, 2}},
{{}, {}, {1, 2}},
{{}, {}, {0}, {}},
{{}, {}, {0}, {1, 2}},
{{}, {}, {1, 2}},
{},
{0}}};
for (const auto& tc : test_cases) {
TensorDistAttr x_dist_attr = TensorDistAttr();
x_dist_attr.set_process_mesh(process_mesh);
x_dist_attr.set_dims_mapping(tc.x_dims_mapping);
x_dist_attr.set_dynamic_dims(std::vector<bool>(tc.x_shape.size(), false));
phi::distributed::DistMetaTensor x = phi::distributed::DistMetaTensor(
common::make_ddim(tc.x_shape), x_dist_attr);
TensorDistAttr y_dist_attr = TensorDistAttr();
y_dist_attr.set_process_mesh(process_mesh);
y_dist_attr.set_dims_mapping(tc.y_dims_mapping);
y_dist_attr.set_dynamic_dims(std::vector<bool>(tc.y_shape.size(), false));
phi::distributed::DistMetaTensor y = phi::distributed::DistMetaTensor(
common::make_ddim(tc.y_shape), y_dist_attr);
TensorDistAttr out_grad_dist_attr = TensorDistAttr();
out_grad_dist_attr.set_process_mesh(process_mesh);
out_grad_dist_attr.set_dims_mapping(tc.out_grad_dims_mapping);
out_grad_dist_attr.set_dynamic_dims(
std::vector<bool>(tc.out_grad_shape.size(), false));
phi::distributed::DistMetaTensor out_grad =
phi::distributed::DistMetaTensor(common::make_ddim(tc.out_grad_shape),
out_grad_dist_attr);
// test backward
phi::distributed::SpmdInfo backward_spmd_info =
phi::distributed::MatmulGradInferSpmd(
x, y, out_grad, tc.trans_x, tc.trans_y);
EXPECT_EQ(backward_spmd_info.first.size(), static_cast<size_t>(3));
EXPECT_EQ(backward_spmd_info.second.size(), static_cast<size_t>(2));
check_multi_dims_mapping(backward_spmd_info.first[0],
tc.expected_x_dims_mapping);
check_multi_dims_mapping(backward_spmd_info.first[1],
tc.expected_y_dims_mapping);
check_multi_dims_mapping(backward_spmd_info.first[2],
tc.expected_out_grad_dims_mapping);
check_multi_dims_mapping(backward_spmd_info.second[0],
tc.expected_x_grad_dims_mapping);
if (!tc.x_grad_partial_dims.empty()) {
EXPECT_EQ(is_partial(backward_spmd_info.second[0]), true);
check_partial_dims(backward_spmd_info.second[0], tc.x_grad_partial_dims);
}
check_multi_dims_mapping(backward_spmd_info.second[1],
tc.expected_y_grad_dims_mapping);
if (!tc.y_grad_partial_dims.empty()) {
EXPECT_EQ(is_partial(backward_spmd_info.second[1]), true);
check_partial_dims(backward_spmd_info.second[1], tc.y_grad_partial_dims);
}
}
}
TEST(BmmInferSpmd, CoShard) {
std::vector<int64_t> mesh_shape = {2, 2, 2};
std::vector<int64_t> process_ids = {0, 1, 2, 3, 4, 5, 6, 7};
std::vector<std::string> dim_names = {"x", "y", "z"};
ProcessMesh process_mesh(mesh_shape, process_ids, dim_names);
std::vector<int64_t> x_shape = {4, 16, 8};
std::vector<std::vector<int64_t>> x_dims_mapping = {{0, 1}, {2}, {}};
TensorDistAttr x_dist_attr;
x_dist_attr.set_process_mesh(process_mesh);
x_dist_attr.set_dims_mapping(x_dims_mapping);
x_dist_attr.set_dynamic_dims(std::vector<bool>(x_shape.size(), false));
phi::distributed::DistMetaTensor x(common::make_ddim(x_shape), x_dist_attr);
std::vector<int64_t> y_shape = {4, 8, 32};
std::vector<std::vector<int64_t>> y_dims_mapping = {{0, 1}, {}, {}};
TensorDistAttr y_dist_attr;
y_dist_attr.set_process_mesh(process_mesh);
y_dist_attr.set_dims_mapping(y_dims_mapping);
y_dist_attr.set_dynamic_dims(std::vector<bool>(y_shape.size(), false));
phi::distributed::DistMetaTensor y(common::make_ddim(y_shape), y_dist_attr);
auto bmm_spmd_info = phi::distributed::BmmInferSpmd(x, y);
ASSERT_EQ(bmm_spmd_info.first.size(), static_cast<size_t>(2));
ASSERT_EQ(bmm_spmd_info.second.size(), static_cast<size_t>(1));
check_multi_dims_mapping(bmm_spmd_info.first[0], x_dims_mapping);
EXPECT_FALSE(is_partial(bmm_spmd_info.first[0]));
check_multi_dims_mapping(bmm_spmd_info.first[1], y_dims_mapping);
EXPECT_FALSE(is_partial(bmm_spmd_info.first[1]));
const std::vector<std::vector<int64_t>> expected_out_dims_mapping = {
{0, 1}, {2}, {}};
check_multi_dims_mapping(bmm_spmd_info.second[0], expected_out_dims_mapping);
EXPECT_FALSE(is_partial(bmm_spmd_info.second[0]));
}
TEST(BmmGradInferSpmd, CoShard) {
std::vector<int64_t> mesh_shape = {2, 2, 2};
std::vector<int64_t> process_ids = {0, 1, 2, 3, 4, 5, 6, 7};
std::vector<std::string> dim_names = {"x", "y", "z"};
ProcessMesh process_mesh(mesh_shape, process_ids, dim_names);
std::vector<int64_t> x_shape = {4, 16, 8};
std::vector<std::vector<int64_t>> x_dims_mapping = {{0, 1}, {2}, {}};
TensorDistAttr x_dist_attr;
x_dist_attr.set_process_mesh(process_mesh);
x_dist_attr.set_dims_mapping(x_dims_mapping);
x_dist_attr.set_dynamic_dims(std::vector<bool>(x_shape.size(), false));
phi::distributed::DistMetaTensor x(common::make_ddim(x_shape), x_dist_attr);
std::vector<int64_t> y_shape = {4, 8, 32};
std::vector<std::vector<int64_t>> y_dims_mapping = {{0, 1}, {}, {}};
TensorDistAttr y_dist_attr;
y_dist_attr.set_process_mesh(process_mesh);
y_dist_attr.set_dims_mapping(y_dims_mapping);
y_dist_attr.set_dynamic_dims(std::vector<bool>(y_shape.size(), false));
phi::distributed::DistMetaTensor y(common::make_ddim(y_shape), y_dist_attr);
std::vector<int64_t> out_grad_shape = {4, 16, 32};
std::vector<std::vector<int64_t>> out_grad_dims_mapping = {{0, 1}, {2}, {}};
TensorDistAttr out_grad_dist_attr;
out_grad_dist_attr.set_process_mesh(process_mesh);
out_grad_dist_attr.set_dims_mapping(out_grad_dims_mapping);
out_grad_dist_attr.set_dynamic_dims(
std::vector<bool>(out_grad_shape.size(), false));
phi::distributed::DistMetaTensor out_grad(common::make_ddim(out_grad_shape),
out_grad_dist_attr);
auto bmm_grad_spmd_info = phi::distributed::BmmGradInferSpmd(x, y, out_grad);
ASSERT_EQ(bmm_grad_spmd_info.first.size(), static_cast<size_t>(3));
ASSERT_EQ(bmm_grad_spmd_info.second.size(), static_cast<size_t>(2));
check_multi_dims_mapping(bmm_grad_spmd_info.first[0], x_dims_mapping);
EXPECT_FALSE(is_partial(bmm_grad_spmd_info.first[0]));
check_multi_dims_mapping(bmm_grad_spmd_info.first[1], y_dims_mapping);
EXPECT_FALSE(is_partial(bmm_grad_spmd_info.first[1]));
check_multi_dims_mapping(bmm_grad_spmd_info.first[2], out_grad_dims_mapping);
EXPECT_FALSE(is_partial(bmm_grad_spmd_info.first[2]));
check_multi_dims_mapping(bmm_grad_spmd_info.second[0], x_dims_mapping);
EXPECT_FALSE(is_partial(bmm_grad_spmd_info.second[0]));
check_multi_dims_mapping(bmm_grad_spmd_info.second[1], y_dims_mapping);
EXPECT_TRUE(is_partial(bmm_grad_spmd_info.second[1]));
check_partial_dims(bmm_grad_spmd_info.second[1], {2});
}
} // namespace auto_parallel
} // namespace distributed
} // namespace paddle
@@ -0,0 +1,144 @@
/* Copyright (c) 2024 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 "test/cpp/auto_parallel/spmd_rule_test_util.h"
namespace paddle {
namespace distributed {
namespace auto_parallel {
using phi::distributed::ArgDistAttr;
using phi::distributed::DistMetaTensor;
void test_moe_combine_spmd(
const std::vector<std::vector<int64_t>>& input_shapes,
const std::vector<std::vector<int64_t>>& input_dims_mappings,
const std::pair<std::vector<std::vector<int64_t>>,
std::vector<std::vector<int64_t>>>& expected_dims_mappings,
bool test_bwd_spmd = false) {
size_t num_inputs = 0;
if (test_bwd_spmd) {
num_inputs = 4;
} else {
num_inputs = 3;
}
EXPECT_EQ(input_shapes.size(), num_inputs)
<< "The number of input_shapes must be" << num_inputs << ", but got "
<< input_shapes.size();
EXPECT_EQ(input_dims_mappings.size(), num_inputs)
<< "The number of input_dims_mapping must be" << num_inputs
<< ", but got " << input_dims_mappings.size();
std::vector<int64_t> mesh_shape = {2, 2, 2};
std::vector<int64_t> process_ids = {0, 1, 2, 3, 4, 5, 6, 7};
std::vector<std::string> dim_names = {"dp", "mp", "pp"};
ProcessMesh process_mesh(mesh_shape, process_ids, dim_names);
std::vector<DistMetaTensor> dist_meta_tensors;
for (size_t i = 0; i < num_inputs; ++i) {
TensorDistAttr dist_attr = TensorDistAttr();
dist_attr.set_process_mesh(process_mesh);
const std::vector<int64_t>& shape = input_shapes[i];
const std::vector<int64_t>& dim_mapping = input_dims_mappings[i];
EXPECT_EQ(shape.size(), dim_mapping.size())
<< "The size of shape and dim_mapping for input " << i
<< " must be the same, but got " << shape.size()
<< " != " << dim_mapping.size();
dist_attr.set_dims_mapping(dim_mapping);
dist_attr.set_dynamic_dims(std::vector<bool>(shape.size(), false));
dist_meta_tensors.push_back(
DistMetaTensor(common::make_ddim(shape), dist_attr));
}
phi::distributed::SpmdInfo spmd_info;
if (test_bwd_spmd) {
spmd_info = phi::distributed::MoECombineGradInferSpmd(dist_meta_tensors[0],
dist_meta_tensors[1],
dist_meta_tensors[2],
dist_meta_tensors[3]);
} else {
spmd_info = phi::distributed::MoECombineInferSpmd(
dist_meta_tensors[0], dist_meta_tensors[1], dist_meta_tensors[2]);
}
for (size_t i = 0; i < 2; ++i) {
std::vector<ArgDistAttr> dist_attrs;
std::vector<std::vector<int64_t>> dims_mappings;
if (i == 0) {
dist_attrs = spmd_info.first;
dims_mappings = expected_dims_mappings.first;
} else {
dist_attrs = spmd_info.second;
dims_mappings = expected_dims_mappings.second;
}
EXPECT_EQ(dist_attrs.size(), dims_mappings.size())
<< "The size of dist_attr and expected_dims must be the same, but got "
<< dist_attrs.size() << " != " << dims_mappings.size();
for (size_t j = 0; j < dist_attrs.size(); ++j) {
const ArgDistAttr& inferred_attr = dist_attrs[j];
const std::vector<int64_t>& expected_dims_mapping = dims_mappings[j];
check_dim_mapping(inferred_attr, expected_dims_mapping);
}
}
}
TEST(MoECombineSPMDRule, test_moe_combine_spmd) {
// forward: x, combine_weights, scatter_index -> y
// backward: x, combine_weights, scatter_index, grad_y -> grad_x,
// grad_combine_weights
int s = 1024, h = 512, k = 2;
const std::vector<std::vector<int64_t>>& forward_input_shapes = {
{s * k, h}, {s, k}, {s, k}};
const std::vector<std::vector<int64_t>>& backward_input_shapes = {
{s * k, h}, {s, k}, {s, k}, {s, h}};
// replicated case, forward
std::vector<std::vector<int64_t>> input_dims_mappings = {
{-1, -1}, {-1, -1}, {-1, -1}};
std::pair<std::vector<std::vector<int64_t>>,
std::vector<std::vector<int64_t>>>
expected_dims_mappings = {{{-1, -1}, {-1, -1}, {-1, -1}}, {{-1, -1}}};
test_moe_combine_spmd(
forward_input_shapes, input_dims_mappings, expected_dims_mappings);
// replicated case, backward
input_dims_mappings = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}};
expected_dims_mappings = {{{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}},
{{-1, -1}, {-1, -1}, {-1, -1}}};
test_moe_combine_spmd(
backward_input_shapes, input_dims_mappings, expected_dims_mappings, true);
// mp case, forward
input_dims_mappings = {{1, -1}, {1, -1}, {-1, -1}};
expected_dims_mappings = {{{1, -1}, {1, -1}, {1, -1}}, {{1, -1}}};
test_moe_combine_spmd(
forward_input_shapes, input_dims_mappings, expected_dims_mappings);
// mp case, backward
input_dims_mappings = {{1, -1}, {1, -1}, {-1, -1}, {1, -1}};
expected_dims_mappings = {{{1, -1}, {1, -1}, {1, -1}, {1, -1}},
{{1, -1}, {1, -1}, {1, -1}}};
test_moe_combine_spmd(
backward_input_shapes, input_dims_mappings, expected_dims_mappings, true);
}
} // namespace auto_parallel
} // namespace distributed
} // namespace paddle
@@ -0,0 +1,188 @@
/* Copyright (c) 2024 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 "test/cpp/auto_parallel/spmd_rule_test_util.h"
namespace paddle {
namespace distributed {
namespace auto_parallel {
using phi::distributed::ArgDistAttr;
using phi::distributed::DistMetaTensor;
void test_moe_gate_dispatch_spmd(
const std::vector<std::vector<int64_t>>& input_shapes,
const std::vector<std::vector<int64_t>>& input_dims_mappings,
const std::pair<std::vector<std::vector<int64_t>>,
std::vector<std::vector<int64_t>>>& expected_dims_mappings,
int64_t k,
int64_t capacity,
bool use_pad,
bool test_bwd_spmd = false,
bool optional = true) {
size_t num_inputs = 0;
if (test_bwd_spmd) {
num_inputs = 5;
} else {
num_inputs = 3;
}
EXPECT_EQ(input_shapes.size(), num_inputs)
<< "The number of input_shapes must be" << num_inputs << ", but got "
<< input_shapes.size();
EXPECT_EQ(input_dims_mappings.size(), num_inputs)
<< "The number of input_dims_mapping must be" << num_inputs
<< ", but got " << input_dims_mappings.size();
std::vector<int64_t> mesh_shape = {4};
std::vector<int64_t> process_ids = {0, 1, 2, 3};
std::vector<std::string> dim_names = {"dpmp"};
ProcessMesh process_mesh(mesh_shape, process_ids, dim_names);
std::vector<DistMetaTensor> dist_meta_tensors;
for (size_t i = 0; i < num_inputs; ++i) {
TensorDistAttr dist_attr = TensorDistAttr();
dist_attr.set_process_mesh(process_mesh);
const std::vector<int64_t>& shape = input_shapes[i];
const std::vector<int64_t>& dim_mapping = input_dims_mappings[i];
EXPECT_EQ(shape.size(), dim_mapping.size())
<< "The size of shape and dim_mapping for input " << i
<< " must be the same, but got " << shape.size()
<< " != " << dim_mapping.size();
dist_attr.set_dims_mapping(dim_mapping);
dist_attr.set_dynamic_dims(std::vector<bool>(shape.size(), false));
dist_meta_tensors.push_back(
DistMetaTensor(common::make_ddim(shape), dist_attr));
}
phi::distributed::SpmdInfo spmd_info;
if (test_bwd_spmd) {
spmd_info =
phi::distributed::MoEGateDispatchGradInferSpmd(dist_meta_tensors[0],
dist_meta_tensors[1],
dist_meta_tensors[2],
dist_meta_tensors[3],
dist_meta_tensors[4],
k,
capacity,
use_pad);
} else {
phi::distributed::DistMetaTensor uninitialized_tensor;
spmd_info = phi::distributed::MoEGateDispatchInferSpmd(
dist_meta_tensors[0],
dist_meta_tensors[1],
optional ? dist_meta_tensors[2] : uninitialized_tensor,
k,
capacity,
use_pad);
}
for (size_t i = 0; i < 2; ++i) {
std::vector<ArgDistAttr> dist_attrs;
std::vector<std::vector<int64_t>> dims_mappings;
if (i == 0) {
dist_attrs = spmd_info.first;
dims_mappings = expected_dims_mappings.first;
} else {
dist_attrs = spmd_info.second;
dims_mappings = expected_dims_mappings.second;
}
EXPECT_EQ(dist_attrs.size(), dims_mappings.size())
<< "The size of dist_attr and expected_dims must be the same, but got "
<< dist_attrs.size() << " != " << dims_mappings.size();
for (size_t j = 0; j < dist_attrs.size(); ++j) {
const ArgDistAttr& inferred_attr = dist_attrs[j];
const std::vector<int64_t>& expected_dims_mapping = dims_mappings[j];
check_dim_mapping(inferred_attr, expected_dims_mapping);
}
}
}
TEST(MoECombineSPMDRule, test_moe_gate_dispatch_spmd) {
int64_t s = 1024, h = 512, k = 2, e = 8, capacity = 1024;
bool use_pad = true;
const std::vector<std::vector<int64_t>>& forward_input_shapes = {
{s, h}, {s, e}, {e}};
const std::vector<std::vector<int64_t>>& backward_input_shapes = {
{s, k}, {k, s}, {s, k}, {e, capacity, h}, {s, k}};
// replicated case, forward
std::vector<std::vector<int64_t>> input_dims_mappings = {
{-1, -1}, {-1, -1}, {-1}};
std::pair<std::vector<std::vector<int64_t>>,
std::vector<std::vector<int64_t>>>
expected_dims_mappings = {
{{-1, -1}, {-1, -1}, {-1}},
{{-1, -1, -1}, {-1, -1}, {-1, -1}, {-1}, {-1, -1}}};
test_moe_gate_dispatch_spmd(forward_input_shapes,
input_dims_mappings,
expected_dims_mappings,
k,
capacity,
use_pad);
// replicated case, backward
input_dims_mappings = {{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1, -1}, {-1, -1}};
expected_dims_mappings = {
{{-1, -1}, {-1, -1}, {-1, -1}, {-1, -1, -1}, {-1, -1}},
{{-1, -1}, {-1, -1}}};
test_moe_gate_dispatch_spmd(backward_input_shapes,
input_dims_mappings,
expected_dims_mappings,
k,
capacity,
use_pad,
true);
// ep case, forward
input_dims_mappings = {{0, -1}, {-1, -1}, {-1}};
expected_dims_mappings = {{{0, -1}, {0, -1}, {-1}},
{{-1, 0, -1}, {0, -1}, {-1, 0}, {-1}, {0, -1}}};
test_moe_gate_dispatch_spmd(forward_input_shapes,
input_dims_mappings,
expected_dims_mappings,
k,
capacity,
use_pad);
// ep case, backward
input_dims_mappings = {{0, -1}, {-1, 0}, {0, -1}, {-1, 0, -1}, {0, -1}};
expected_dims_mappings = {{{0, -1}, {-1, 0}, {0, -1}, {-1, 0, -1}, {0, -1}},
{{0, -1}, {0, -1}}};
test_moe_gate_dispatch_spmd(backward_input_shapes,
input_dims_mappings,
expected_dims_mappings,
k,
capacity,
use_pad,
true);
// ep, corr_bias is none case, forward
input_dims_mappings = {{0, -1}, {-1, -1}, {-1}};
expected_dims_mappings = {{{0, -1}, {0, -1}, {}},
{{-1, 0, -1}, {0, -1}, {-1, 0}, {-1}, {0, -1}}};
test_moe_gate_dispatch_spmd(forward_input_shapes,
input_dims_mappings,
expected_dims_mappings,
k,
capacity,
use_pad,
false,
false);
}
} // namespace auto_parallel
} // namespace distributed
} // namespace paddle
@@ -0,0 +1,54 @@
/* 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/phi/core/distributed/auto_parallel/process_mesh.h"
#include <iostream>
#include <sstream>
#include "gtest/gtest.h"
#include "paddle/phi/core/distributed/auto_parallel/proto_helper.h"
namespace phi {
namespace distributed {
namespace auto_parallel {
TEST(ProcessMesh, Ctor) {
std::vector<int64_t> shape = {2, 3};
std::vector<int64_t> process_ids = {0, 1, 2, 3, 4, 5};
std::vector<std::string> dim_names = {"x", "y"};
int64_t size = shape[0] * shape[1];
ProcessMesh process_mesh(shape, process_ids, dim_names);
EXPECT_EQ(process_mesh.shape(), shape);
EXPECT_EQ(process_mesh.process_ids(), process_ids);
EXPECT_EQ(process_mesh.dim_names()[0], "x");
EXPECT_EQ(process_mesh.dim_names()[1], "y");
EXPECT_EQ(process_mesh.size(), size);
EXPECT_EQ(process_mesh.ndim(), static_cast<int64_t>(shape.size()));
EXPECT_EQ(process_mesh.dim_size(0), shape[0]);
EXPECT_EQ(process_mesh.dim_size(-1), shape[1]);
EXPECT_EQ(process_mesh.dim_size("x"), shape[0]);
EXPECT_EQ(process_mesh.dim_size("y"), shape[1]);
EXPECT_EQ(process_mesh.empty(), false);
EXPECT_EQ(process_mesh.contains(0), true);
EXPECT_EQ(process_mesh.contains(6), false);
std::stringstream sstream;
sstream << process_mesh;
EXPECT_EQ(sstream.str(), process_mesh.to_string());
auto proto = phi::distributed::to_proto(process_mesh);
ProcessMesh new_process_mesh = ProcessMesh::from_proto(proto);
EXPECT_EQ(process_mesh, new_process_mesh);
}
} // namespace auto_parallel
} // namespace distributed
} // namespace phi
@@ -0,0 +1,153 @@
/* Copyright (c) 2025 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 "test/cpp/auto_parallel/spmd_rule_test_util.h"
namespace paddle {
namespace distributed {
namespace auto_parallel {
struct ReshapeTestCase {
// input
std::vector<int64_t> input_shape;
std::vector<std::vector<int64_t>> input_dims_mapping;
// shape attribute
std::vector<int64_t> target_shape;
// output
std::vector<std::vector<int64_t>> expected_input_dims_mapping;
std::vector<std::vector<int64_t>> expected_output_dims_mapping;
};
TEST(Reshape, Ctor) {
std::vector<int64_t> mesh_shape = {2, 2};
std::vector<int64_t> process_ids = {0, 1, 2, 3};
std::vector<std::string> dim_names = {"x", "y"};
ProcessMesh process_mesh(mesh_shape, process_ids, dim_names);
// test flatten
// [4, 6, 8] -> [192]:
// [[0], [1], [ ]] -> [[0, 1], [ ], [ ]], [[0, 1]]
// [4, 6, 8] -> [192]: [[ ], [0], [1]] -> [[ ], [ ], [ ]], [[ ]]
// [4, 6, 8] -> [192]:
// [[0, 1], [ ], [ ]] -> [[0, 1], [ ], [ ]], [[0, 1]]
// [2, 12, 8] -> [192]:
// [[0], [1], [ ]] -> [[0], [ ], [ ]], [[0]]
// test split
// [128] -> [4, 6, 8]:
// [[0, 1]] -> [[0, 1]], [[0, 1], [ ], [ ]]
// [128] -> [6, 4, 8]:
// [[0, 1]] -> [[ ], [ ], [ ]]
// [4, 6, 8] -> [2, 12, 8]
// [[0], [1], [ ]] -> [[0], [ ], [ ]], [[0], [ ], [ ]]
// [4, 6, 8] -> [2, 12, 8]
// [[0, 1], [ ], [ ]] -> [[ ], [ ], [ ]], [[ ], [ ], [ ]]
// [4, 6, 8] -> [12, 2, 8]:
// [[0], [1], [ ]] -> [[0, 1], [ ], [ ]], [[0, 1], [ ], [ ]]
// [4, 6, 8] -> [12, 2, 8]:
// [[0, 1], [ ], [ ]] -> [[0, 1], [ ], [ ]], [[0, 1], [ ], [ ]]
// [4, 6, 8] -> [8, 6, 4]:
// [[0], [1], [ ]] -> [[0, 1], [ ], [ ]], [[0, 1], [ ], [ ]]
// [4, 6, 8] -> [8, 6, 4]:
// [[ ], [0], [1]] -> [[ ], [ ], [ ]], [[ ], [ ], [ ]]
// [4, 6, 8] -> [8, 6, 4]:
// [[0], [ ], [1]] -> [[0], [ ], [ ]], [[0], [ ], [ ]]
// [4, 6, 8] -> [8, 6, 4]:
// [[0, 1], [ ], [ ]] -> [[0, 1], [ ], [ ]], [[0, 1], [ ], [ ]]
std::vector<ReshapeTestCase> test_cases = {
// input_shape, input_dims_mapping, target_shape,
// expected_input_dims_mapping, expected_output_dims_mapping
// test flatten
{{4, 6, 8}, {{0}, {1}, {}}, {192}, {{0, 1}, {}, {}}, {{0, 1}}},
{{4, 6, 8}, {{}, {0}, {1}}, {192}, {{}, {}, {}}, {{}}},
{{4, 6, 8}, {{0, 1}, {}, {}}, {192}, {{0, 1}, {}, {}}, {{0, 1}}},
{{2, 12, 8}, {{0}, {1}, {}}, {192}, {{0}, {}, {}}, {{0}}},
// test split
{{192}, {{0, 1}}, {4, 6, 8}, {{0, 1}}, {{0, 1}, {}, {}}},
{{192}, {{0, 1}}, {6, 4, 8}, {{}}, {{}, {}, {}}},
// test combination
{{4, 6, 8}, {{0}, {1}, {}}, {2, 12, 8}, {{0}, {}, {}}, {{0}, {}, {}}},
{{4, 6, 8}, {{0, 1}, {}, {}}, {2, 12, 8}, {{}, {}, {}}, {{}, {}, {}}},
{{4, 6, 8},
{{0}, {1}, {}},
{12, 2, 8},
{{0, 1}, {}, {}},
{{0, 1}, {}, {}}},
{{4, 6, 8},
{{0, 1}, {}, {}},
{12, 2, 8},
{{0, 1}, {}, {}},
{{0, 1}, {}, {}}},
{{4, 6, 8},
{{0}, {1}, {}},
{8, 6, 4},
{{0, 1}, {}, {}},
{{0, 1}, {}, {}}},
{{4, 6, 8}, {{}, {0}, {1}}, {8, 6, 4}, {{}, {}, {}}, {{}, {}, {}}},
{{4, 6, 8}, {{0}, {}, {1}}, {8, 6, 4}, {{0}, {}, {}}, {{0}, {}, {}}},
{{4, 6, 8},
{{0, 1}, {}, {}},
{8, 6, 4},
{{0, 1}, {}, {}},
{{0, 1}, {}, {}}},
{{4, 6, 8}, {{}, {}, {0, 1}}, {24, 2, 4}, {{}, {}, {}}, {{}, {}, {}}},
{{4, 6, 8},
{{}, {}, {0, 1}},
{24, 4, 2},
{{}, {}, {0, 1}},
{{}, {0, 1}, {}}},
};
for (const auto& tc : test_cases) {
TensorDistAttr t_dist_attr = TensorDistAttr();
t_dist_attr.set_process_mesh(process_mesh);
t_dist_attr.set_dims_mapping(tc.input_dims_mapping);
t_dist_attr.set_dynamic_dims(
std::vector<bool>(tc.input_shape.size(), false));
phi::distributed::DistMetaTensor x = phi::distributed::DistMetaTensor(
common::make_ddim(tc.input_shape), t_dist_attr);
// test forward
phi::distributed::SpmdInfo forward_spmd_info =
phi::distributed::ReshapeInferSpmd(x, tc.target_shape);
EXPECT_EQ(forward_spmd_info.first.size(), static_cast<size_t>(1));
EXPECT_EQ(forward_spmd_info.second.size(), static_cast<size_t>(1));
check_multi_dims_mapping(forward_spmd_info.first[0],
tc.expected_input_dims_mapping);
check_multi_dims_mapping(forward_spmd_info.second[0],
tc.expected_output_dims_mapping);
}
}
} // namespace auto_parallel
} // namespace distributed
} // namespace paddle
@@ -0,0 +1,243 @@
/* Copyright (c) 2025 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 "test/cpp/auto_parallel/spmd_rule_test_util.h"
namespace paddle {
namespace distributed {
namespace auto_parallel {
struct SoftmaxTestCase {
// input
std::vector<int64_t> input_shape;
std::vector<std::vector<int64_t>> input_dims_mapping;
// axis attribute
int axis;
// output
std::vector<std::vector<int64_t>> expected_input_dims_mapping;
std::vector<std::vector<int64_t>> expected_output_dims_mapping;
};
struct SoftmaxGradTestCase {
// input
std::vector<int64_t> out_shape;
std::vector<std::vector<int64_t>> out_dims_mapping;
std::vector<int64_t> out_grad_shape;
std::vector<std::vector<int64_t>> out_grad_dims_mapping;
// axis attribute
int axis;
// output
std::vector<std::vector<int64_t>> expected_out_dims_mapping;
std::vector<std::vector<int64_t>> expected_out_grad_dims_mapping;
std::vector<std::vector<int64_t>> expected_x_grad_dims_mapping;
};
TEST(SoftmaxInferSpmd, Ctor) {
std::vector<int64_t> mesh_shape = {2, 2, 2};
std::vector<int64_t> process_ids = {0, 1, 2, 3, 4, 5, 6, 7};
std::vector<std::string> dim_names = {"x", "y", "z"};
ProcessMesh process_mesh(mesh_shape, process_ids, dim_names);
std::vector<SoftmaxTestCase> test_cases = {
// shape = [32, 48, 128], axis = 0
// [[0,1],[2],[]] -> [[],[2],[]], [[],[2],[]]
{{32, 48, 128}, {{0, 1}, {2}, {}}, 0, {{}, {2}, {}}, {{}, {2}, {}}},
{{32, 48, 128}, {{0, 1}, {2}, {}}, -3, {{}, {2}, {}}, {{}, {2}, {}}},
// shape = [32, 48, 128], axis = 1
// [[0,1],[2],[]] -> [[0, 1],[],[]], [[0, 1],[],[]]
{{32, 48, 128},
{{0, 1}, {2}, {}},
1,
{{0, 1}, {}, {}},
{{0, 1}, {}, {}}}};
for (const auto& tc : test_cases) {
TensorDistAttr t_dist_attr = TensorDistAttr();
t_dist_attr.set_process_mesh(process_mesh);
t_dist_attr.set_dims_mapping(tc.input_dims_mapping);
t_dist_attr.set_dynamic_dims(
std::vector<bool>(tc.input_shape.size(), false));
phi::distributed::DistMetaTensor x = phi::distributed::DistMetaTensor(
common::make_ddim(tc.input_shape), t_dist_attr);
// test forward
phi::distributed::SpmdInfo forward_spmd_info =
phi::distributed::SoftmaxInferSpmd(x, tc.axis);
EXPECT_EQ(forward_spmd_info.first.size(), static_cast<size_t>(1));
EXPECT_EQ(forward_spmd_info.second.size(), static_cast<size_t>(1));
check_multi_dims_mapping(forward_spmd_info.first[0],
tc.expected_input_dims_mapping);
check_multi_dims_mapping(forward_spmd_info.second[0],
tc.expected_output_dims_mapping);
}
}
TEST(SoftmaxGradInferSpmd, Ctor) {
std::vector<int64_t> mesh_shape = {2, 2, 2};
std::vector<int64_t> process_ids = {0, 1, 2, 3, 4, 5, 6, 7};
std::vector<std::string> dim_names = {"x", "y", "z"};
ProcessMesh process_mesh(mesh_shape, process_ids, dim_names);
std::vector<SoftmaxGradTestCase> test_cases = {
// out_shape = [32, 48, 128], out_grad_shape = [32, 48, 128], axis = 0
// [[0,1],[2],[]], [[0,1],[2],[]] -> [[],[2],[]], [[],[2],[]], [[],[2],[]]
{{32, 48, 128},
{{0, 1}, {2}, {}},
{32, 48, 128},
{{0, 1}, {2}, {}},
0,
{{}, {2}, {}},
{{}, {2}, {}},
{{}, {2}, {}}},
// axis = 0
// [[0,1],[2],[]], [[0],[1,2],[]] -> [[],[1,2],[]], [[],[1, 2],[]],
// [[],[1,2],[]]
{{32, 48, 128},
{{0, 1}, {2}, {}},
{32, 48, 128},
{{0}, {1, 2}, {}},
0,
{{}, {1, 2}, {}},
{{}, {1, 2}, {}},
{{}, {1, 2}, {}}},
// axis = 1
// [[0,1],[2],[]], [[2],[0,1],[]] -> [[0,1,2],[],[]], [[0, 1, 2],[],[]],
// [[0, 1, 2],[],[]]
{{32, 48, 128},
{{0, 1}, {2}, {}},
{32, 48, 128},
{{2}, {0, 1}, {}},
1,
{{0, 1, 2}, {}, {}},
{{0, 1, 2}, {}, {}},
{{0, 1, 2}, {}, {}}},
// axis = 2
// [[0],[1],[]], [[],[0,1],[]] -> [[],[0,1],[]], [[],[0,1],[]],
// [[],[0,1],[]]
{{32, 48, 128},
{{0}, {1}, {}},
{32, 48, 128},
{{}, {0, 1}, {}},
2,
{{}, {0, 1}, {}},
{{}, {0, 1}, {}},
{{}, {0, 1}, {}}},
// axis = 2
// [[0],[1],[]], [[0,1],[],[]] -> [[0,1],[],[]], [[0, 1],[],[]],
// [[0,1],[],[]]
{{32, 48, 128},
{{0}, {1}, {}},
{32, 48, 128},
{{0, 1}, {}, {}},
2,
{{0, 1}, {}, {}},
{{0, 1}, {}, {}},
{{0, 1}, {}, {}}},
// axis = 2
// [[0],[1,2],[]], [[],[0,1],[]] -> [[0],[1,2],[]], [[0],[1,2],[]],
// [[0],[1,2],[]]
{{32, 48, 128},
{{0}, {1, 2}, {}},
{32, 48, 128},
{{}, {0, 1}, {}},
2,
{{0}, {1, 2}, {}},
{{0}, {1, 2}, {}},
{{0}, {1, 2}, {}}},
// axis = 2
// [[0],[1,2],[]], [[],[0,1],[]] -> [[0],[1,2],[]], [[0],[1,2],[]],
// [[0],[1,2],[]]
{{2, 4, 128},
{{0}, {1, 2}, {}},
{2, 4, 128},
{{}, {0, 1}, {}},
2,
{{0}, {1, 2}, {}},
{{0}, {1, 2}, {}},
{{0}, {1, 2}, {}}},
// axis = 2
// [[],[1,2],[]], [[],[0,1],[]] -> [[],[1,2],[]], [[],[1,2],[]],
// [[],[1,2],[]]
{{2, 4, 128},
{{}, {1, 2}, {}},
{2, 4, 128},
{{}, {0, 1}, {}},
2,
{{}, {1, 2}, {}},
{{}, {1, 2}, {}},
{{}, {1, 2}, {}}},
// axis = 1
// [[0,1],[],[]], [[],[],[2]] -> [[0,1],[],[2]], [[0,1],[],[2]],
// [[0,1],[],[2]]
{{32, 48, 128},
{{0, 1}, {}, {}},
{32, 48, 128},
{{}, {}, {2}},
1,
{{0, 1}, {}, {2}},
{{0, 1}, {}, {2}},
{{0, 1}, {}, {2}}},
// Note: just for pass coverage ci: axis = 2
// [[0],[0,1],[]], [[],[],[]] -> [[],[0,1],[]], [[],[0,1],[]],
// [[],[0,1],[]]
{{2, 4, 128},
{{0}, {0, 1}, {}},
{2, 4, 128},
{{}, {}, {}},
2,
{{}, {0, 1}, {}},
{{}, {0, 1}, {}},
{{}, {0, 1}, {}}}};
for (const auto& tc : test_cases) {
TensorDistAttr out_dist_attr = TensorDistAttr();
out_dist_attr.set_process_mesh(process_mesh);
out_dist_attr.set_dims_mapping(tc.out_dims_mapping);
out_dist_attr.set_dynamic_dims(
std::vector<bool>(tc.out_shape.size(), false));
phi::distributed::DistMetaTensor out = phi::distributed::DistMetaTensor(
common::make_ddim(tc.out_shape), out_dist_attr);
TensorDistAttr out_grad_attr = TensorDistAttr();
out_grad_attr.set_process_mesh(process_mesh);
out_grad_attr.set_dims_mapping(tc.out_grad_dims_mapping);
out_grad_attr.set_dynamic_dims(
std::vector<bool>(tc.out_grad_shape.size(), false));
phi::distributed::DistMetaTensor out_grad =
phi::distributed::DistMetaTensor(common::make_ddim(tc.out_grad_shape),
out_grad_attr);
// test backward
phi::distributed::SpmdInfo backward_spmd_info =
phi::distributed::SoftmaxGradInferSpmd(out, out_grad, tc.axis);
EXPECT_EQ(backward_spmd_info.first.size(), static_cast<size_t>(2));
EXPECT_EQ(backward_spmd_info.second.size(), static_cast<size_t>(1));
check_multi_dims_mapping(backward_spmd_info.first[0],
tc.expected_out_dims_mapping);
check_multi_dims_mapping(backward_spmd_info.first[1],
tc.expected_out_grad_dims_mapping);
check_multi_dims_mapping(backward_spmd_info.second[0],
tc.expected_x_grad_dims_mapping);
}
}
} // namespace auto_parallel
} // namespace distributed
} // namespace paddle
// [[0,1],[2]] [[2],[]]
@@ -0,0 +1,143 @@
/* 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 "test/cpp/auto_parallel/spmd_rule_test_util.h"
namespace paddle {
namespace distributed {
namespace auto_parallel {
TEST(SoftmaxGradInferSpmd, Ctor) {
// Sharding along axes besides softmax axis.
std::vector<int64_t> x_shape = {36, 48};
std::vector<int64_t> out_grad_shape = {36, 48};
std::vector<int64_t> mesh_shape = {2, 3};
std::vector<int64_t> process_ids = {0, 1, 2, 3, 4, 5};
std::vector<std::string> dim_names = {"x", "y"};
ProcessMesh process_mesh(mesh_shape, process_ids, dim_names);
TensorDistAttr x_dist_attr = TensorDistAttr();
x_dist_attr.set_process_mesh(process_mesh);
x_dist_attr.set_dims_mapping(std::vector<int64_t>({1, -1}));
x_dist_attr.set_dynamic_dims(std::vector<bool>({false, false}));
TensorDistAttr out_grad_dist_attr = TensorDistAttr();
out_grad_dist_attr.set_process_mesh(process_mesh);
out_grad_dist_attr.set_dims_mapping(std::vector<int64_t>({1, -1}));
out_grad_dist_attr.set_dynamic_dims(std::vector<bool>({false, false}));
phi::distributed::DistMetaTensor x(phi::make_ddim(x_shape), x_dist_attr);
phi::distributed::DistMetaTensor out_grad(phi::make_ddim(x_shape),
out_grad_dist_attr);
int axis = 1;
auto spmdinfo = SoftmaxGradInferSpmd(x, out_grad, axis);
EXPECT_EQ(spmdinfo.first.size(), 2UL);
EXPECT_EQ(spmdinfo.second.size(), 1UL);
EXPECT_EQ(get_dims_mapping(spmdinfo.first[0]), std::vector<int64_t>({1, -1}));
EXPECT_EQ(get_dims_mapping(spmdinfo.first[1]), std::vector<int64_t>({1, -1}));
EXPECT_EQ(get_dims_mapping(spmdinfo.second[0]),
std::vector<int64_t>({1, -1}));
EXPECT_DOUBLE_EQ(
PADDLE_GET_CONST(TensorDistAttr, spmdinfo.second[0]).is_partial(), false);
VLOG(4) << "Test SoftmaxGradInferSpmd sharding on other axes." << std::endl
<< std::endl
<< std::endl;
// Sharding along softmax axis.
x_dist_attr.set_dims_mapping(std::vector<int64_t>({-1, 1}));
out_grad_dist_attr.set_dims_mapping(std::vector<int64_t>({-1, 1}));
x = phi::distributed::DistMetaTensor(phi::make_ddim(x_shape), x_dist_attr);
out_grad = phi::distributed::DistMetaTensor(phi::make_ddim(x_shape),
out_grad_dist_attr);
axis = 1;
spmdinfo = SoftmaxGradInferSpmd(x, out_grad, axis);
EXPECT_EQ(spmdinfo.first.size(), 2UL);
EXPECT_EQ(spmdinfo.second.size(), 1UL);
EXPECT_EQ(get_dims_mapping(spmdinfo.first[0]),
std::vector<int64_t>({-1, -1}));
EXPECT_EQ(get_dims_mapping(spmdinfo.first[1]),
std::vector<int64_t>({-1, -1}));
EXPECT_EQ(get_dims_mapping(spmdinfo.second[0]),
std::vector<int64_t>({-1, -1}));
EXPECT_DOUBLE_EQ(
PADDLE_GET_CONST(TensorDistAttr, spmdinfo.second[0]).is_partial(), false);
VLOG(4) << "Test SoftmaxGradInferSpmd sharding on softmax axis." << std::endl
<< std::endl
<< std::endl;
// Sharding on multi axes.
x_shape = {10, 36, 48, 24};
out_grad_shape = {10, 36, 48, 24};
x_dist_attr.set_dims_mapping(std::vector<int64_t>({0, 1, -1, -1}));
out_grad_dist_attr.set_dims_mapping(std::vector<int64_t>({0, 1, -1, -1}));
x = phi::distributed::DistMetaTensor(phi::make_ddim(x_shape), x_dist_attr);
out_grad = phi::distributed::DistMetaTensor(phi::make_ddim(x_shape),
out_grad_dist_attr);
axis = 1;
spmdinfo = SoftmaxGradInferSpmd(x, out_grad, axis);
EXPECT_EQ(spmdinfo.first.size(), 2UL);
EXPECT_EQ(spmdinfo.second.size(), 1UL);
EXPECT_EQ(get_dims_mapping(spmdinfo.first[0]),
std::vector<int64_t>({0, -1, -1, -1}));
EXPECT_EQ(get_dims_mapping(spmdinfo.first[1]),
std::vector<int64_t>({0, -1, -1, -1}));
EXPECT_EQ(get_dims_mapping(spmdinfo.second[0]),
std::vector<int64_t>({0, -1, -1, -1}));
EXPECT_DOUBLE_EQ(
PADDLE_GET_CONST(TensorDistAttr, spmdinfo.second[0]).is_partial(), false);
VLOG(4) << "Test SoftmaxGradInferSpmd sharding on multi axes." << std::endl
<< std::endl
<< std::endl;
// Sharding on multi axes.
x_shape = {10, 36, 48, 24};
out_grad_shape = {10, 36, 48, 24};
x_dist_attr.set_dims_mapping(std::vector<int64_t>({0, -1, -1, -1}));
out_grad_dist_attr.set_dims_mapping(std::vector<int64_t>({-1, -1, 1, -1}));
x = phi::distributed::DistMetaTensor(phi::make_ddim(x_shape), x_dist_attr);
out_grad = phi::distributed::DistMetaTensor(phi::make_ddim(x_shape),
out_grad_dist_attr);
axis = 1;
spmdinfo = SoftmaxGradInferSpmd(x, out_grad, axis);
EXPECT_EQ(spmdinfo.first.size(), 2UL);
EXPECT_EQ(spmdinfo.second.size(), 1UL);
EXPECT_EQ(get_dims_mapping(spmdinfo.first[0]),
std::vector<int64_t>({0, -1, 1, -1}));
EXPECT_EQ(get_dims_mapping(spmdinfo.first[1]),
std::vector<int64_t>({0, -1, 1, -1}));
EXPECT_EQ(get_dims_mapping(spmdinfo.second[0]),
std::vector<int64_t>({0, -1, 1, -1}));
EXPECT_DOUBLE_EQ(
PADDLE_GET_CONST(TensorDistAttr, spmdinfo.second[0]).is_partial(), false);
VLOG(4) << "Test SoftmaxGradInferSpmd sharding on multi axes." << std::endl
<< std::endl
<< std::endl;
}
} // namespace auto_parallel
} // namespace distributed
} // namespace paddle
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,118 @@
/* 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 "test/cpp/auto_parallel/spmd_rule_test_util.h"
namespace paddle {
namespace distributed {
namespace auto_parallel {
const std::vector<int64_t>& get_dims_mapping(
const phi::distributed::ArgDistAttr& dist_attr) {
EXPECT_TRUE(
paddle::holds_alternative<phi::distributed::TensorDistAttr>(dist_attr));
const auto& tensor_attr =
PADDLE_GET_CONST(phi::distributed::TensorDistAttr, dist_attr);
return tensor_attr.dims_mapping();
}
bool is_partial(const phi::distributed::ArgDistAttr& dist_attr) {
EXPECT_TRUE(
paddle::holds_alternative<phi::distributed::TensorDistAttr>(dist_attr));
const auto& tensor_attr =
PADDLE_GET_CONST(phi::distributed::TensorDistAttr, dist_attr);
return tensor_attr.is_partial();
}
const std::set<int64_t> get_partial_dims(
const phi::distributed::ArgDistAttr& dist_attr) {
EXPECT_TRUE(
paddle::holds_alternative<phi::distributed::TensorDistAttr>(dist_attr));
const auto& tensor_attr =
PADDLE_GET_CONST(phi::distributed::TensorDistAttr, dist_attr);
return tensor_attr.partial_dims();
}
const std::vector<std::vector<int64_t>>& get_multi_dims_mapping(
const phi::distributed::ArgDistAttr& dist_attr) {
EXPECT_TRUE(
paddle::holds_alternative<phi::distributed::TensorDistAttr>(dist_attr));
const auto& tensor_attr =
PADDLE_GET_CONST(phi::distributed::TensorDistAttr, dist_attr);
return tensor_attr.multi_dims_mapping();
}
void check_dim_mapping(const phi::distributed::ArgDistAttr& dist_attr,
const std::vector<int64_t>& dim_mapping,
const std::string& line) {
EXPECT_TRUE(
paddle::holds_alternative<phi::distributed::TensorDistAttr>(dist_attr))
<< line;
EXPECT_EQ(get_dims_mapping(dist_attr), dim_mapping) << line;
}
void check_multi_dims_mapping(
const phi::distributed::ArgDistAttr& dist_attr,
const std::vector<std::vector<int64_t>>& dim_mapping,
const std::string& line) {
EXPECT_TRUE(
paddle::holds_alternative<phi::distributed::TensorDistAttr>(dist_attr))
<< line;
EXPECT_EQ(get_multi_dims_mapping(dist_attr), dim_mapping) << line;
}
void check_empty_dist_attr(const phi::distributed::ArgDistAttr& dist_attr,
const std::string& line) {
EXPECT_TRUE(
paddle::holds_alternative<phi::distributed::TensorDistAttr>(dist_attr))
<< line;
EXPECT_EQ(PADDLE_GET_CONST(phi::distributed::TensorDistAttr, dist_attr),
phi::distributed::TensorDistAttr());
}
void check_partial_dims(const phi::distributed::ArgDistAttr& dist_attr,
const std::set<int64_t>& dims,
const std::string& line) {
EXPECT_TRUE(
paddle::holds_alternative<phi::distributed::TensorDistAttr>(dist_attr))
<< line;
EXPECT_EQ(get_partial_dims(dist_attr), dims) << line;
}
void clean_partial_status(phi::distributed::ArgDistAttr* dist_attr) {
EXPECT_TRUE(
paddle::holds_alternative<phi::distributed::TensorDistAttr>(*dist_attr));
auto& tensor_attr = PADDLE_GET(phi::distributed::TensorDistAttr, *dist_attr);
tensor_attr.clean_partial_status();
}
void clean_partial_dims(phi::distributed::ArgDistAttr* dist_attr,
std::vector<int64_t> dims) {
EXPECT_TRUE(
paddle::holds_alternative<phi::distributed::TensorDistAttr>(*dist_attr));
auto& tensor_attr = PADDLE_GET(phi::distributed::TensorDistAttr, *dist_attr);
tensor_attr.clean_partial_dims(dims);
}
void set_partial_status(phi::distributed::ArgDistAttr* dist_attr,
std::vector<int64_t> dims) {
EXPECT_TRUE(
paddle::holds_alternative<phi::distributed::TensorDistAttr>(*dist_attr));
auto& tensor_attr = PADDLE_GET(phi::distributed::TensorDistAttr, *dist_attr);
tensor_attr.set_partial_status(dims);
}
} // namespace auto_parallel
} // namespace distributed
} // namespace paddle
@@ -0,0 +1,74 @@
/* 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. */
#pragma once
#include <iostream>
#include <sstream>
#include <string>
#include "glog/logging.h"
#include "gtest/gtest.h"
#include "paddle/phi/core/distributed/auto_parallel/dist_attr.h"
#include "paddle/phi/core/distributed/auto_parallel/inferspmd_utils.h"
#include "paddle/phi/core/distributed/auto_parallel/process_mesh.h"
#include "paddle/phi/core/distributed/type_defs.h"
#include "paddle/phi/infermeta/spmd_rules/replicated.h"
#include "paddle/phi/infermeta/spmd_rules/rules.h"
namespace paddle {
namespace distributed {
namespace auto_parallel {
using phi::distributed::ProcessMesh;
using phi::distributed::TensorDistAttr;
const std::vector<int64_t>& get_dims_mapping(
const phi::distributed::ArgDistAttr& dist_attr);
bool is_partial(const phi::distributed::ArgDistAttr& dist_attr);
const std::set<int64_t> get_partial_dims(
const phi::distributed::ArgDistAttr& dist_attr);
const std::vector<std::vector<int64_t>>& get_multi_dims_mapping(
const phi::distributed::ArgDistAttr& dist_attr);
void check_dim_mapping(const phi::distributed::ArgDistAttr& dist_attr,
const std::vector<int64_t>& dim_mapping,
const std::string& line = "");
void check_multi_dims_mapping(
const phi::distributed::ArgDistAttr& dist_attr,
const std::vector<std::vector<int64_t>>& dim_mapping,
const std::string& line = "");
void check_empty_dist_attr(const phi::distributed::ArgDistAttr& dist_attr,
const std::string& line = "");
void check_partial_dims(const phi::distributed::ArgDistAttr& dist_attr,
const std::set<int64_t>& dims,
const std::string& line = "");
void clean_partial_status(phi::distributed::ArgDistAttr* dist_attr);
void clean_partial_dims(phi::distributed::ArgDistAttr* dist_attr,
std::vector<int64_t> dims);
void set_partial_status(phi::distributed::ArgDistAttr* dist_attr,
std::vector<int64_t> dims);
} // namespace auto_parallel
} // namespace distributed
} // namespace paddle
@@ -0,0 +1,215 @@
/* Copyright (c) 2025 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/phi/infermeta/spmd_rules/tile.h"
#include "test/cpp/auto_parallel/spmd_rule_test_util.h"
namespace paddle {
namespace distributed {
namespace auto_parallel {
struct TileTestCase {
// input
std::vector<int64_t> x_shape;
std::vector<std::vector<int64_t>> x_dims_mapping;
// repeat_times attribute
phi::IntArray repeat_times;
// output
std::vector<std::vector<int64_t>> expected_x_dims_mapping;
std::vector<std::vector<int64_t>> expected_out_dims_mapping;
};
struct TileGradTestCase {
// input
std::vector<int64_t> x_shape;
std::vector<std::vector<int64_t>> x_dims_mapping;
std::vector<int64_t> out_grad_shape;
std::vector<std::vector<int64_t>> out_grad_dims_mapping;
// repeat_times attribute
phi::IntArray repeat_times;
// output
std::vector<std::vector<int64_t>> expected_x_dims_mapping;
std::vector<std::vector<int64_t>> expected_out_grad_dims_mapping;
std::vector<std::vector<int64_t>> expected_x_grad_dims_mapping;
std::set<int64_t> partial_dims;
};
TEST(TileInferSpmd, Ctor) {
std::vector<int64_t> mesh_shape = {2, 2, 2};
std::vector<int64_t> process_ids = {0, 1, 2, 3, 4, 5, 6, 7};
std::vector<std::string> dim_names = {"x", "y", "z"};
ProcessMesh process_mesh(mesh_shape, process_ids, dim_names);
std::vector<TileTestCase> test_cases = {
// shape = [8, 16, 24], repeat_times = {2, 2, 1, 1}
// [[0],[],[1,2]] -> [[],[],[1,2]], [[],[],[],[1,2]]
{
{8, 16, 24},
{{0}, {}, {1, 2}},
phi::IntArray({2, 2, 1, 1}),
{{}, {}, {1, 2}},
{{}, {}, {}, {1, 2}},
},
// shape = [8, 16, 24], repeat_times = {1, 2}
// [[0,1],[],[2]] -> [[0,1],[],[]], [[0,1],[],[]]
{
{8, 16, 24},
{{0, 1}, {}, {2}},
phi::IntArray({1, 2}),
{{0, 1}, {}, {}},
{{0, 1}, {}, {}},
},
// shape = [8, 16, 24], repeat_times = {}
// [[0,1],[],[2]] -> [[0,1],[],[2]], [[0,1],[],[2]]
{
{8, 16, 24},
{{0, 1}, {}, {2}},
phi::IntArray({}),
{{0, 1}, {}, {2}},
{{0, 1}, {}, {2}},
},
};
for (const auto& tc : test_cases) {
TensorDistAttr x_dist_attr = TensorDistAttr();
x_dist_attr.set_process_mesh(process_mesh);
x_dist_attr.set_dims_mapping(tc.x_dims_mapping);
x_dist_attr.set_dynamic_dims(std::vector<bool>(tc.x_shape.size(), false));
phi::distributed::DistMetaTensor x = phi::distributed::DistMetaTensor(
common::make_ddim(tc.x_shape), x_dist_attr);
// test forward
phi::distributed::SpmdInfo forward_spmd_info =
phi::distributed::TileInferSpmdDynamic(x, tc.repeat_times);
EXPECT_EQ(forward_spmd_info.first.size(), static_cast<size_t>(1));
EXPECT_EQ(forward_spmd_info.second.size(), static_cast<size_t>(1));
check_multi_dims_mapping(forward_spmd_info.first[0],
tc.expected_x_dims_mapping);
check_multi_dims_mapping(forward_spmd_info.second[0],
tc.expected_out_dims_mapping);
}
}
TEST(TileGradInferSpmd, Ctor) {
std::vector<int64_t> mesh_shape = {2, 2, 2};
std::vector<int64_t> process_ids = {0, 1, 2, 3, 4, 5, 6, 7};
std::vector<std::string> dim_names = {"x", "y", "z"};
ProcessMesh process_mesh(mesh_shape, process_ids, dim_names);
std::vector<TileGradTestCase> test_cases = {
// x_shape = [8, 16, 24], out_grad_shape = [2, 16, 16, 24], repeat_times =
// {2, 2, 1, 1}
// [[0],[],[1,2]], [[],[],[],[1,2]] -> [[],[],[1,2]], [[],[],[],[1,2]],
// [[],[],[1,2]], partial on {}
{
{8, 16, 24},
{{0}, {}, {1, 2}},
{2, 16, 16, 24},
{{}, {}, {}, {1, 2}},
phi::IntArray({2, 2, 1, 1}),
{{}, {}, {1, 2}},
{{}, {}, {}, {1, 2}},
{{}, {}, {1, 2}},
{},
},
// x_shape = [8, 16, 24], out_grad_shape = [8, 16, 48], repeat_times = {1,
// 2}
// [[0,1],[],[2]], [[0,1],[],[2]] -> [[0,1],[],[]], [[0,1],[],[]]],
// [[0,1],[],[]], partial on {}
{
{8, 16, 24},
{{0, 1}, {}, {2}},
{8, 16, 48},
{{0, 1}, {}, {2}},
phi::IntArray({1, 2}),
{{0, 1}, {}, {}},
{{0, 1}, {}, {}},
{{0, 1}, {}, {}},
{},
},
// x_shape = [8, 16, 24], out_grad_shape = [8, 16, 24], repeat_times = {}
// [[0,1],[],[2]], [[0],[1],[2]] -> [[0],[1],[2]], [[0],[1],[2]],
// [[0],[1],[2]], partial on {}
{
{8, 16, 24},
{{0, 1}, {}, {2}},
{8, 16, 24},
{{0}, {1}, {2}},
phi::IntArray({}),
{{0}, {1}, {2}},
{{0}, {1}, {2}},
{{0}, {1}, {2}},
{},
},
// x_shape = [8, 16, 24], out_grad_shape = [8, 16, 16, 24], repeat_times =
// {8, 2, 1, 1}
// [[0],[],[]], [[1,2],[],[],[]] -> [[],[],[]], [[1,2],[],[],[]],
// [[],[],[]], partial on {1,2}
{
{8, 16, 24},
{{0}, {}, {}},
{8, 16, 16, 24},
{{1, 2}, {}, {}, {}},
phi::IntArray({8, 2, 1, 1}),
{{}, {}, {}},
{{1, 2}, {}, {}, {}},
{{}, {}, {}},
{1, 2},
},
};
for (const auto& tc : test_cases) {
TensorDistAttr x_dist_attr = TensorDistAttr();
x_dist_attr.set_process_mesh(process_mesh);
x_dist_attr.set_dims_mapping(tc.x_dims_mapping);
x_dist_attr.set_dynamic_dims(std::vector<bool>(tc.x_shape.size(), false));
phi::distributed::DistMetaTensor x = phi::distributed::DistMetaTensor(
common::make_ddim(tc.x_shape), x_dist_attr);
TensorDistAttr out_grad_attr = TensorDistAttr();
out_grad_attr.set_process_mesh(process_mesh);
out_grad_attr.set_dims_mapping(tc.out_grad_dims_mapping);
out_grad_attr.set_dynamic_dims(
std::vector<bool>(tc.out_grad_shape.size(), false));
phi::distributed::DistMetaTensor out_grad =
phi::distributed::DistMetaTensor(common::make_ddim(tc.out_grad_shape),
out_grad_attr);
// test backward
phi::distributed::SpmdInfo backward_spmd_info =
phi::distributed::TileGradInferSpmdDynamic(
x, out_grad, tc.repeat_times);
EXPECT_EQ(backward_spmd_info.first.size(), static_cast<size_t>(2));
EXPECT_EQ(backward_spmd_info.second.size(), static_cast<size_t>(1));
check_multi_dims_mapping(backward_spmd_info.first[0],
tc.expected_x_dims_mapping);
check_multi_dims_mapping(backward_spmd_info.first[1],
tc.expected_out_grad_dims_mapping);
check_multi_dims_mapping(backward_spmd_info.second[0],
tc.expected_x_grad_dims_mapping);
}
}
} // namespace auto_parallel
} // namespace distributed
} // namespace paddle
@@ -0,0 +1,63 @@
/* 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 "test/cpp/auto_parallel/spmd_rule_test_util.h"
namespace paddle {
namespace distributed {
namespace auto_parallel {
TEST(Tile, Ctor) {
std::vector<int64_t> mesh_shape = {2, 2};
std::vector<int64_t> process_ids = {0, 1, 2, 3};
std::vector<std::string> dim_names = {"x", "y"};
ProcessMesh process_mesh(mesh_shape, process_ids, dim_names);
std::vector<int64_t> shape = {6, 8, 10};
std::vector<int64_t> dims_mapping = {0, -1, 1};
TensorDistAttr t_dist_attr = TensorDistAttr();
t_dist_attr.set_process_mesh(process_mesh);
t_dist_attr.set_dims_mapping(dims_mapping);
t_dist_attr.set_dynamic_dims({false, false, false});
phi::distributed::DistMetaTensor x =
phi::distributed::DistMetaTensor(common::make_ddim(shape), t_dist_attr);
std::vector<int64_t> repeat_times = {2, 2, 1, 1};
// test forward
phi::distributed::SpmdInfo forward_spmd_info =
phi::distributed::TileInferSpmd(x, repeat_times);
EXPECT_EQ(forward_spmd_info.first.size(), static_cast<size_t>(1));
EXPECT_EQ(forward_spmd_info.second.size(), static_cast<size_t>(1));
check_dim_mapping(forward_spmd_info.first[0], {-1, -1, 1});
check_dim_mapping(forward_spmd_info.second[0], {-1, -1, -1, 1});
check_partial_dims(forward_spmd_info.second[0], {});
// test backward
auto out_grad_dist_attr =
PADDLE_GET_CONST(TensorDistAttr, forward_spmd_info.second[0]);
out_grad_dist_attr.set_dims_mapping({0, -1, -1, 1});
phi::distributed::DistMetaTensor out_grad = phi::distributed::DistMetaTensor(
common::make_ddim({2, 12, 8, 10}), out_grad_dist_attr);
phi::distributed::SpmdInfo backward_spmd_info =
TileGradInferSpmd(x, out_grad, repeat_times);
EXPECT_EQ(backward_spmd_info.first.size(), static_cast<size_t>(2));
EXPECT_EQ(backward_spmd_info.second.size(), static_cast<size_t>(1));
check_dim_mapping(backward_spmd_info.first[0], {-1, -1, 1});
check_dim_mapping(backward_spmd_info.first[1], {0, -1, -1, 1});
check_dim_mapping(backward_spmd_info.second[0], {-1, -1, 1});
check_partial_dims(backward_spmd_info.second[0], {0});
}
} // namespace auto_parallel
} // namespace distributed
} // namespace paddle
@@ -0,0 +1,89 @@
/* Copyright (c) 2025 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 "test/cpp/auto_parallel/spmd_rule_test_util.h"
namespace paddle {
namespace distributed {
namespace auto_parallel {
struct TransposeTestCase {
// input
std::vector<int64_t> input_shape;
std::vector<std::vector<int64_t>> input_dims_mapping;
// shape attribute
std::vector<int> perm;
// output
std::vector<std::vector<int64_t>> expected_input_dims_mapping;
std::vector<std::vector<int64_t>> expected_output_dims_mapping;
};
TEST(Transpose, Ctor) {
std::vector<int64_t> mesh_shape = {2, 2};
std::vector<int64_t> process_ids = {0, 1, 2, 3};
std::vector<std::string> dim_names = {"x", "y"};
ProcessMesh process_mesh(mesh_shape, process_ids, dim_names);
//
std::vector<TransposeTestCase> test_cases = {
// input_shape, input_dims_mapping, perm,
// expected_input_dims_mapping, expected_output_dims_mapping
{{64, 48, 36, 24},
{{0, 1}, {}, {}, {}},
{1, 0, 2, 3},
{{0, 1}, {}, {}, {}},
{{}, {0, 1}, {}, {}}},
{{64, 48, 36, 24},
{{0, 1}, {}, {}, {}},
{0, 1, 2, 3},
{{0, 1}, {}, {}, {}},
{{0, 1}, {}, {}, {}}},
{{64, 48, 36, 24},
{{}, {}, {0, 1}, {}},
{0, 2, 3, 1},
{{}, {}, {0, 1}, {}},
{{}, {0, 1}, {}, {}}},
{{64, 48, 36, 24},
{{}, {}, {0, 1}, {}},
{-1, 0, -2, 1},
{{}, {}, {0, 1}, {}},
{{}, {}, {0, 1}, {}}},
};
for (const auto& tc : test_cases) {
TensorDistAttr t_dist_attr = TensorDistAttr();
t_dist_attr.set_process_mesh(process_mesh);
t_dist_attr.set_dims_mapping(tc.input_dims_mapping);
t_dist_attr.set_dynamic_dims(
std::vector<bool>(tc.input_shape.size(), false));
phi::distributed::DistMetaTensor x = phi::distributed::DistMetaTensor(
common::make_ddim(tc.input_shape), t_dist_attr);
// test forward
phi::distributed::SpmdInfo forward_spmd_info =
phi::distributed::TransposeInferSpmd(x, tc.perm);
EXPECT_EQ(forward_spmd_info.first.size(), static_cast<size_t>(1));
EXPECT_EQ(forward_spmd_info.second.size(), static_cast<size_t>(1));
check_multi_dims_mapping(forward_spmd_info.first[0],
tc.expected_input_dims_mapping);
check_multi_dims_mapping(forward_spmd_info.second[0],
tc.expected_output_dims_mapping);
}
}
} // namespace auto_parallel
} // namespace distributed
} // namespace paddle