Files
paddlepaddle--paddle/paddle/phi/infermeta/spmd_rules/moe_gate_dispatch.cc
T
2026-07-13 12:40:42 +08:00

480 lines
20 KiB
C++

/* 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 "paddle/phi/infermeta/spmd_rules/moe_gate_dispatch.h"
#include "glog/logging.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/utils.h"
#include "paddle/phi/infermeta/spmd_rules/spmd_rule_macro_define.h"
#include "paddle/phi/infermeta/spmd_rules/utils.h"
namespace phi {
namespace distributed {
SpmdInfo MoEGateDispatchFwdInferSpmd(const DistMetaTensor& x,
const DistMetaTensor& gate_logits,
int64_t k,
int64_t capacity,
bool use_pad) {
/*
inputs:
x: [S, H], S = b*s
gate_logits: [S, E]
outputs:
y: [E, C, H] is use_pad is true, else [S, K, H], currently only support
use_pad=true combine_weights: [S, K] scatter_index: [K, S] expert_offset: [E]
expert_id: [S, K]
*/
EXTRACT_SHAPE_AND_DIST_ATTR_WITH_DIM_CK(x);
EXTRACT_SHAPE_AND_DIST_ATTR_WITH_DIM_CK(gate_logits);
// do some check
PADDLE_ENFORCE_EQ(
x_shape.size(),
2,
errors::InvalidArgument(
"x should be a 2-D tensor, but got x_shape.size() == %d",
x_shape.size()));
PADDLE_ENFORCE_EQ(
gate_logits_shape.size(),
2,
errors::InvalidArgument("gate_logits should be a 2-D tensor, but "
"got gate_logits_shape.size() == %d",
gate_logits_shape.size()));
// infer axes dims_mapping
std::string x_axes = "sh";
std::string gate_logits_axes = "se";
std::unordered_map<std::string, int64_t> axis_to_dim_map =
ShardingMergeForTensors(
{{x_axes, x_dims_mapping_src},
{gate_logits_axes, gate_logits_dims_mapping_src}});
axis_to_dim_map["k"] = -1; // not allowed dim k to be sharded
// input axes
std::vector<int64_t> x_dims_mapping_dst =
GetDimsMappingForAxes(x_axes, axis_to_dim_map);
std::vector<int64_t> gate_logits_dims_mapping_dst =
GetDimsMappingForAxes(gate_logits_axes, axis_to_dim_map);
// infer input dist attr
TensorDistAttr x_dist_attr_dst = CopyTensorDistAttrForOutput(x_dist_attr_src);
x_dist_attr_dst.set_dims_mapping(x_dims_mapping_dst);
TensorDistAttr gate_logits_dist_attr_dst =
CopyTensorDistAttrForOutput(gate_logits_dist_attr_src);
gate_logits_dist_attr_dst.set_dims_mapping(gate_logits_dims_mapping_dst);
// output axes
std::string y_axes = "esh";
std::vector<int64_t> y_dims_mapping =
GetDimsMappingForAxes(y_axes, axis_to_dim_map);
std::string combine_weights_axes = "sk";
std::vector<int64_t> combine_weights_dims_mapping =
GetDimsMappingForAxes(combine_weights_axes, axis_to_dim_map);
std::string scatter_index_axes = "ks";
std::vector<int64_t> scatter_index_dims_mapping =
GetDimsMappingForAxes(scatter_index_axes, axis_to_dim_map);
std::string expert_offset_axes = "e";
std::vector<int64_t> expert_offset_dims_mapping =
GetDimsMappingForAxes(expert_offset_axes, axis_to_dim_map);
std::string expert_id_axes = "sk";
std::vector<int64_t> expert_id_dims_mapping =
GetDimsMappingForAxes(expert_id_axes, axis_to_dim_map);
// infer output dist attr
TensorDistAttr y_dist_attr_dst = CopyTensorDistAttrForOutput(x_dist_attr_src);
y_dist_attr_dst.set_dims_mapping(y_dims_mapping);
TensorDistAttr combine_weights_dist_attr =
CopyTensorDistAttrForOutput(x_dist_attr_src);
combine_weights_dist_attr.set_dims_mapping(combine_weights_dims_mapping);
TensorDistAttr scatter_index_dist_attr =
CopyTensorDistAttrForOutput(x_dist_attr_src);
scatter_index_dist_attr.set_dims_mapping(scatter_index_dims_mapping);
TensorDistAttr expert_offset_dist_attr =
CopyTensorDistAttrForOutput(x_dist_attr_src);
expert_offset_dist_attr.set_dims_mapping(expert_offset_dims_mapping);
TensorDistAttr expert_id_dist_attr =
CopyTensorDistAttrForOutput(x_dist_attr_src);
expert_id_dist_attr.set_dims_mapping(expert_id_dims_mapping);
return {{x_dist_attr_dst, gate_logits_dist_attr_dst},
{y_dist_attr_dst,
combine_weights_dist_attr,
scatter_index_dist_attr,
expert_offset_dist_attr,
expert_id_dist_attr}};
}
SpmdInfo MoEGateDispatchBwdInferSpmd(const DistMetaTensor& combine_weights,
const DistMetaTensor& scatter_index,
const DistMetaTensor& expert_id,
const DistMetaTensor& grad_y,
const DistMetaTensor& grad_combine_weights,
int64_t k,
int64_t capacity,
bool use_pad) {
/*
inputs:
combine_weights: [S, K]
scatter_index: [K, S]
expert_id: [S, K]
grad_y: [E, C, H] is use_pad is true, else [S, K, H], currently only
support use_pad=true grad_combine_weights: [S, K] outputs: grad_x: [S, H]
grad_gate_logits: [S, E]
*/
EXTRACT_SHAPE_AND_DIST_ATTR_WITH_DIM_CK(combine_weights);
EXTRACT_SHAPE_AND_DIST_ATTR_WITH_DIM_CK(scatter_index);
EXTRACT_SHAPE_AND_DIST_ATTR_WITH_DIM_CK(expert_id);
EXTRACT_SHAPE_AND_DIST_ATTR_WITH_DIM_CK(grad_y);
EXTRACT_SHAPE_AND_DIST_ATTR_WITH_DIM_CK(grad_combine_weights);
// do some check
PADDLE_ENFORCE_EQ(
combine_weights_shape.size(),
2,
errors::InvalidArgument("combine_weights should be a 2-D tensor, but "
"got combine_weights_shape.size() == %d",
combine_weights_shape.size()));
PADDLE_ENFORCE_EQ(
scatter_index_shape.size(),
2,
errors::InvalidArgument("scatter_index should be a 2-D tensor, but "
"got scatter_index_shape.size() == %d",
scatter_index_shape.size()));
PADDLE_ENFORCE_EQ(
expert_id_shape.size(),
2,
errors::InvalidArgument("expert_id should be a 2-D tensor, but "
"got expert_id_shape.size() == %d",
expert_id_shape.size()));
PADDLE_ENFORCE_EQ(
grad_y_shape.size(),
3,
errors::InvalidArgument("grad_y should be a 3-D tensor, but "
"got grad_y_shape.size() == %d",
grad_y_shape.size()));
PADDLE_ENFORCE_EQ(grad_combine_weights_shape.size(),
2,
errors::InvalidArgument(
"grad_combine_weights should be a 2-D tensor, but "
"got grad_combine_weights_shape.size() == %d",
grad_combine_weights_shape.size()));
// infer axes dims_mapping
std::string combine_weights_axes = "sk";
std::string scatter_index_axes = "ks";
std::string expert_id_axes = "sk";
std::string grad_y_axes = "esh";
std::string grad_combine_weights_axes = "sk";
std::unordered_map<std::string, int64_t> axis_to_dim_map =
ShardingMergeForTensors(
{{combine_weights_axes, combine_weights_dims_mapping_src},
{scatter_index_axes, scatter_index_dims_mapping_src},
{expert_id_axes, expert_id_dims_mapping_src},
{grad_y_axes, grad_y_dims_mapping_src},
{grad_combine_weights_axes, grad_combine_weights_dims_mapping_src}});
// axis_to_dim_map["e"] = -1; // not allowed dim e to be sharded
// input axes
std::vector<int64_t> combine_weights_dims_mapping_dst =
GetDimsMappingForAxes(combine_weights_axes, axis_to_dim_map);
std::vector<int64_t> scatter_index_dims_mapping_dst =
GetDimsMappingForAxes(scatter_index_axes, axis_to_dim_map);
std::vector<int64_t> expert_id_dims_mapping_dst =
GetDimsMappingForAxes(expert_id_axes, axis_to_dim_map);
std::vector<int64_t> grad_y_dims_mapping_dst =
GetDimsMappingForAxes(grad_y_axes, axis_to_dim_map);
std::vector<int64_t> grad_combine_weights_dims_mapping_dst =
GetDimsMappingForAxes(grad_combine_weights_axes, axis_to_dim_map);
// infer input dist attr
TensorDistAttr combine_weights_dist_attr_dst =
CopyTensorDistAttrForOutput(combine_weights_dist_attr_src);
combine_weights_dist_attr_dst.set_dims_mapping(
combine_weights_dims_mapping_dst);
TensorDistAttr scatter_index_dist_attr_dst =
CopyTensorDistAttrForOutput(scatter_index_dist_attr_src);
scatter_index_dist_attr_dst.set_dims_mapping(scatter_index_dims_mapping_dst);
TensorDistAttr expert_id_dist_attr_dst =
CopyTensorDistAttrForOutput(expert_id_dist_attr_src);
expert_id_dist_attr_dst.set_dims_mapping(expert_id_dims_mapping_dst);
TensorDistAttr grad_y_dist_attr_dst =
CopyTensorDistAttrForOutput(grad_y_dist_attr_src);
grad_y_dist_attr_dst.set_dims_mapping(grad_y_dims_mapping_dst);
TensorDistAttr grad_combine_weights_dist_attr_dst =
CopyTensorDistAttrForOutput(grad_combine_weights_dist_attr_src);
grad_combine_weights_dist_attr_dst.set_dims_mapping(
grad_combine_weights_dims_mapping_dst);
// output axes
std::string grad_x_axes = "sh";
std::string grad_gate_logits = "se";
std::vector<int64_t> grad_x_dims_mapping =
GetDimsMappingForAxes(grad_x_axes, axis_to_dim_map);
std::vector<int64_t> grad_gate_logits_dims_mapping =
GetDimsMappingForAxes(grad_gate_logits, axis_to_dim_map);
// output dist attr
TensorDistAttr grad_x_dist_attr_dst =
CopyTensorDistAttrForOutput(grad_y_dist_attr_src);
grad_x_dist_attr_dst.set_dims_mapping(grad_x_dims_mapping);
TensorDistAttr grad_gate_logits_dist_attr_dst =
CopyTensorDistAttrForOutput(grad_y_dist_attr_src);
grad_gate_logits_dist_attr_dst.set_dims_mapping(
grad_gate_logits_dims_mapping);
return {{combine_weights_dist_attr_dst,
scatter_index_dist_attr_dst,
expert_id_dist_attr_dst,
grad_y_dist_attr_dst,
grad_combine_weights_dist_attr_dst},
{grad_x_dist_attr_dst, grad_gate_logits_dist_attr_dst}};
}
SpmdInfo MoEGateDispatchInferSpmd(const DistMetaTensor& x,
const DistMetaTensor& gate_logits,
const DistMetaTensor& corr_bias,
int64_t k,
int64_t capacity,
bool use_pad) {
/*
inputs:
x: [S, H], S = b*s
gate_logits: [S, E]
corr_bias: [E] (optional)
outputs:
y: [E, C, H] is use_pad is true, else [S, K, H], currently only support
use_pad=true combine_weights: [S, K] scatter_index: [K, S] expert_offset: [E]
expert_id: [S, K]
*/
EXTRACT_SHAPE_AND_DIST_ATTR_WITH_DIM_CK(x);
EXTRACT_SHAPE_AND_DIST_ATTR_WITH_DIM_CK(gate_logits);
// do some check
PADDLE_ENFORCE_EQ(
x_shape.size(),
2,
errors::InvalidArgument(
"x should be a 2-D tensor, but got x_shape.size() == %d",
x_shape.size()));
PADDLE_ENFORCE_EQ(
gate_logits_shape.size(),
2,
errors::InvalidArgument("gate_logits should be a 2-D tensor, but "
"got gate_logits_shape.size() == %d",
gate_logits_shape.size()));
if (corr_bias.initialized()) {
EXTRACT_SHAPE_AND_DIST_ATTR_WITH_DIM_CK(corr_bias);
PADDLE_ENFORCE_EQ(
corr_bias_shape.size(),
1,
errors::InvalidArgument("corr_bias should be a 1-D tensor, but "
"got corr_bias_shape.size() == %d",
corr_bias_shape.size()));
}
// infer axes dims_mapping
std::string x_axes = "sh";
std::string gate_logits_axes = "se";
std::unordered_map<std::string, int64_t> axis_to_dim_map =
ShardingMergeForTensors(
{{x_axes, x_dims_mapping_src},
{gate_logits_axes, gate_logits_dims_mapping_src}});
axis_to_dim_map["k"] = -1; // not allowed dim k to be sharded
// input axes
std::vector<int64_t> x_dims_mapping_dst =
GetDimsMappingForAxes(x_axes, axis_to_dim_map);
std::vector<int64_t> gate_logits_dims_mapping_dst =
GetDimsMappingForAxes(gate_logits_axes, axis_to_dim_map);
// infer input dist attr
TensorDistAttr x_dist_attr_dst = CopyTensorDistAttrForOutput(x_dist_attr_src);
x_dist_attr_dst.set_dims_mapping(x_dims_mapping_dst);
TensorDistAttr gate_logits_dist_attr_dst =
CopyTensorDistAttrForOutput(gate_logits_dist_attr_src);
gate_logits_dist_attr_dst.set_dims_mapping(gate_logits_dims_mapping_dst);
TensorDistAttr corr_bias_dist_attr_dst;
// output axes
std::string y_axes = "esh";
std::vector<int64_t> y_dims_mapping =
GetDimsMappingForAxes(y_axes, axis_to_dim_map);
std::string combine_weights_axes = "sk";
std::vector<int64_t> combine_weights_dims_mapping =
GetDimsMappingForAxes(combine_weights_axes, axis_to_dim_map);
std::string scatter_index_axes = "ks";
std::vector<int64_t> scatter_index_dims_mapping =
GetDimsMappingForAxes(scatter_index_axes, axis_to_dim_map);
std::string expert_offset_axes = "e";
std::vector<int64_t> expert_offset_dims_mapping =
GetDimsMappingForAxes(expert_offset_axes, axis_to_dim_map);
std::string expert_id_axes = "sk";
std::vector<int64_t> expert_id_dims_mapping =
GetDimsMappingForAxes(expert_id_axes, axis_to_dim_map);
// infer output dist attr
TensorDistAttr y_dist_attr_dst = CopyTensorDistAttrForOutput(x_dist_attr_src);
y_dist_attr_dst.set_dims_mapping(y_dims_mapping);
TensorDistAttr combine_weights_dist_attr =
CopyTensorDistAttrForOutput(x_dist_attr_src);
combine_weights_dist_attr.set_dims_mapping(combine_weights_dims_mapping);
TensorDistAttr scatter_index_dist_attr =
CopyTensorDistAttrForOutput(x_dist_attr_src);
scatter_index_dist_attr.set_dims_mapping(scatter_index_dims_mapping);
TensorDistAttr expert_offset_dist_attr =
CopyTensorDistAttrForOutput(x_dist_attr_src);
expert_offset_dist_attr.set_dims_mapping(expert_offset_dims_mapping);
TensorDistAttr expert_id_dist_attr =
CopyTensorDistAttrForOutput(x_dist_attr_src);
expert_id_dist_attr.set_dims_mapping(expert_id_dims_mapping);
if (corr_bias.initialized()) {
EXTRACT_SHAPE_AND_DIST_ATTR(corr_bias);
corr_bias_dist_attr_dst =
CopyTensorDistAttrForOutput(corr_bias_dist_attr_src);
corr_bias_dist_attr_dst.set_dims_mapping(
std::vector<int64_t>{gate_logits_dist_attr_dst.dims_mapping().back()});
} else {
corr_bias_dist_attr_dst = TensorDistAttr();
}
return {{x_dist_attr_dst, gate_logits_dist_attr_dst, corr_bias_dist_attr_dst},
{y_dist_attr_dst,
combine_weights_dist_attr,
scatter_index_dist_attr,
expert_offset_dist_attr,
expert_id_dist_attr}};
}
SpmdInfo MoEGateDispatchGradInferSpmd(
const DistMetaTensor& combine_weights,
const DistMetaTensor& scatter_index,
const DistMetaTensor& expert_id,
const DistMetaTensor& grad_y,
const DistMetaTensor& grad_combine_weights,
int64_t k,
int64_t capacity,
bool use_pad) {
/*
inputs:
combine_weights: [S, K]
scatter_index: [K, S]
expert_id: [S, K]
grad_y: [E, C, H] is use_pad is true, else [S, K, H], currently only
support use_pad=true grad_combine_weights: [S, K] outputs: grad_x: [S, H]
grad_gate_logits: [S, E]
*/
EXTRACT_SHAPE_AND_DIST_ATTR_WITH_DIM_CK(combine_weights);
EXTRACT_SHAPE_AND_DIST_ATTR_WITH_DIM_CK(scatter_index);
EXTRACT_SHAPE_AND_DIST_ATTR_WITH_DIM_CK(expert_id);
EXTRACT_SHAPE_AND_DIST_ATTR_WITH_DIM_CK(grad_y);
EXTRACT_SHAPE_AND_DIST_ATTR_WITH_DIM_CK(grad_combine_weights);
// do some check
PADDLE_ENFORCE_EQ(
combine_weights_shape.size(),
2,
errors::InvalidArgument("combine_weights should be a 2-D tensor, but "
"got combine_weights_shape.size() == %d",
combine_weights_shape.size()));
PADDLE_ENFORCE_EQ(
scatter_index_shape.size(),
2,
errors::InvalidArgument("scatter_index should be a 2-D tensor, but "
"got scatter_index_shape.size() == %d",
scatter_index_shape.size()));
PADDLE_ENFORCE_EQ(
expert_id_shape.size(),
2,
errors::InvalidArgument("expert_id should be a 2-D tensor, but "
"got expert_id_shape.size() == %d",
expert_id_shape.size()));
PADDLE_ENFORCE_EQ(
grad_y_shape.size(),
3,
errors::InvalidArgument("grad_y should be a 3-D tensor, but "
"got grad_y_shape.size() == %d",
grad_y_shape.size()));
PADDLE_ENFORCE_EQ(grad_combine_weights_shape.size(),
2,
errors::InvalidArgument(
"grad_combine_weights should be a 2-D tensor, but "
"got grad_combine_weights_shape.size() == %d",
grad_combine_weights_shape.size()));
// infer axes dims_mapping
std::string combine_weights_axes = "sk";
std::string scatter_index_axes = "ks";
std::string expert_id_axes = "sk";
std::string grad_y_axes = "esh";
std::string grad_combine_weights_axes = "sk";
std::unordered_map<std::string, int64_t> axis_to_dim_map =
ShardingMergeForTensors(
{{combine_weights_axes, combine_weights_dims_mapping_src},
{scatter_index_axes, scatter_index_dims_mapping_src},
{expert_id_axes, expert_id_dims_mapping_src},
{grad_y_axes, grad_y_dims_mapping_src},
{grad_combine_weights_axes, grad_combine_weights_dims_mapping_src}});
// axis_to_dim_map["e"] = -1; // not allowed dim e to be sharded
// input axes
std::vector<int64_t> combine_weights_dims_mapping_dst =
GetDimsMappingForAxes(combine_weights_axes, axis_to_dim_map);
std::vector<int64_t> scatter_index_dims_mapping_dst =
GetDimsMappingForAxes(scatter_index_axes, axis_to_dim_map);
std::vector<int64_t> expert_id_dims_mapping_dst =
GetDimsMappingForAxes(expert_id_axes, axis_to_dim_map);
std::vector<int64_t> grad_y_dims_mapping_dst =
GetDimsMappingForAxes(grad_y_axes, axis_to_dim_map);
std::vector<int64_t> grad_combine_weights_dims_mapping_dst =
GetDimsMappingForAxes(grad_combine_weights_axes, axis_to_dim_map);
// infer input dist attr
TensorDistAttr combine_weights_dist_attr_dst =
CopyTensorDistAttrForOutput(combine_weights_dist_attr_src);
combine_weights_dist_attr_dst.set_dims_mapping(
combine_weights_dims_mapping_dst);
TensorDistAttr scatter_index_dist_attr_dst =
CopyTensorDistAttrForOutput(scatter_index_dist_attr_src);
scatter_index_dist_attr_dst.set_dims_mapping(scatter_index_dims_mapping_dst);
TensorDistAttr expert_id_dist_attr_dst =
CopyTensorDistAttrForOutput(expert_id_dist_attr_src);
expert_id_dist_attr_dst.set_dims_mapping(expert_id_dims_mapping_dst);
TensorDistAttr grad_y_dist_attr_dst =
CopyTensorDistAttrForOutput(grad_y_dist_attr_src);
grad_y_dist_attr_dst.set_dims_mapping(grad_y_dims_mapping_dst);
TensorDistAttr grad_combine_weights_dist_attr_dst =
CopyTensorDistAttrForOutput(grad_combine_weights_dist_attr_src);
grad_combine_weights_dist_attr_dst.set_dims_mapping(
grad_combine_weights_dims_mapping_dst);
// output axes
std::string grad_x_axes = "sh";
std::string grad_gate_logits = "se";
std::vector<int64_t> grad_x_dims_mapping =
GetDimsMappingForAxes(grad_x_axes, axis_to_dim_map);
std::vector<int64_t> grad_gate_logits_dims_mapping =
GetDimsMappingForAxes(grad_gate_logits, axis_to_dim_map);
// output dist attr
TensorDistAttr grad_x_dist_attr_dst =
CopyTensorDistAttrForOutput(grad_y_dist_attr_src);
grad_x_dist_attr_dst.set_dims_mapping(grad_x_dims_mapping);
TensorDistAttr grad_gate_logits_dist_attr_dst =
CopyTensorDistAttrForOutput(grad_y_dist_attr_src);
grad_gate_logits_dist_attr_dst.set_dims_mapping(
grad_gate_logits_dims_mapping);
return {{combine_weights_dist_attr_dst,
scatter_index_dist_attr_dst,
expert_id_dist_attr_dst,
grad_y_dist_attr_dst,
grad_combine_weights_dist_attr_dst},
{grad_x_dist_attr_dst, grad_gate_logits_dist_attr_dst}};
}
} // namespace distributed
} // namespace phi