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

6654 lines
252 KiB
C++

/* 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/infermeta/fusion.h"
#include <unordered_set>
#include <vector>
#include "paddle/common/layout.h"
#include "paddle/phi/common/scalar.h"
#include "paddle/phi/core/infermeta_utils.h"
#include "paddle/phi/core/meta_tensor.h"
#include "paddle/phi/kernels/cpu/conv_util.h"
#include "paddle/phi/kernels/funcs/blas/blas.h"
#include "paddle/phi/kernels/funcs/common_shape.h"
#include "paddle/phi/kernels/funcs/concat_funcs.h"
#include "paddle/phi/kernels/funcs/fused_elemwise_activation_functor.h"
#include "paddle/phi/kernels/funcs/strided_slice.h"
namespace phi {
static DDim BroadCastInferShape(const DDim x_dims,
const DDim y_dims,
int axis) {
std::vector<int> out_dims_array(x_dims.size(), -1);
if (x_dims != y_dims) {
int max_dim = std::max(x_dims.size(), y_dims.size());
if (x_dims.size() == y_dims.size()) {
PADDLE_ENFORCE_EQ((axis == -1) || (axis == 0),
true,
common::errors::InvalidArgument(
"axis should be -1 or 0 while the dimension of "
"tensor X (%s) is equal to the dimension of "
"tensor Y (%s), but received axis: %s",
x_dims.size(),
y_dims.size(),
axis));
}
PADDLE_ENFORCE_EQ((axis >= (-1 * max_dim)) && (axis < max_dim),
true,
common::errors::InvalidArgument(
"The axis range must be [%s, %s), but axis is %s. "
"Please set the axis again.",
-1 * max_dim,
max_dim,
axis));
axis = (axis < 0 ? (std::abs(x_dims.size() - y_dims.size()) + axis + 1)
: axis);
std::vector<int> x_dims_array(max_dim);
std::vector<int> y_dims_array(max_dim);
out_dims_array.resize(max_dim);
funcs::GetBroadcastDimsArrays(x_dims,
y_dims,
x_dims_array.data(),
y_dims_array.data(),
out_dims_array.data(),
max_dim,
axis);
return make_ddim(out_dims_array);
}
return x_dims;
}
void AddActXPUInferMeta(const MetaTensor& x,
const MetaTensor& x_max,
const MetaTensor& y,
const MetaTensor& y_max,
int act_type,
MetaTensor* out,
MetaTensor* out_max) {
int axis = -1;
auto x_dims = x.dims();
auto y_dims = y.dims();
if (x_dims != y_dims) {
auto out_dims = BroadCastInferShape(x_dims, y_dims, axis);
out->set_dims(out_dims);
} else {
out->set_dims(x_dims);
}
out->set_dtype(x.dtype());
out->set_layout(x.layout());
out->share_lod(x);
out_max->set_dims(make_ddim({6}));
out_max->set_dtype(x.dtype());
out_max->set_layout(x.layout());
}
void AddLayernormXPUInferMeta(const MetaTensor& x,
const MetaTensor& y,
const MetaTensor& scale,
const MetaTensor& bias,
int begin_norm_axis,
float epsilon,
MetaTensor* out) {
int axis = -1;
auto x_dims = x.dims();
auto y_dims = y.dims();
auto out_dims = x_dims;
if (x_dims != y_dims) {
out_dims = BroadCastInferShape(x_dims, y_dims, axis);
out->set_dims(out_dims);
} else {
out->set_dims(out_dims);
}
out->set_dtype(x.dtype());
out->set_layout(x.layout());
out->share_lod(x);
}
void GroupNormalizeSiluXPUInferMeta(const MetaTensor& x,
const MetaTensor& scale,
const MetaTensor& bias,
int groups,
double epsilon,
MetaTensor* out) {
auto x_dims = x.dims();
auto out_dims = x_dims;
out->set_dims(out_dims);
out->set_dtype(x.dtype());
out->set_layout(x.layout());
out->share_lod(x);
}
void LayerNormalizeReluXPUInferMeta(const MetaTensor& x,
const MetaTensor& scale,
const MetaTensor& bias,
int begin_norm_axis,
float epsilon,
MetaTensor* out) {
out->set_dims(x.dims());
// y->share_lod(x);
out->set_dtype(x.dtype());
out->set_layout(x.layout());
}
void FusedMultiTransformerInferMeta(
const MetaTensor& x,
const std::vector<const MetaTensor*>& ln_scales,
const paddle::optional<std::vector<const MetaTensor*>>& ln_biases,
const std::vector<const MetaTensor*>& qkv_weights,
const paddle::optional<std::vector<const MetaTensor*>>& qkv_biases,
const paddle::optional<std::vector<const MetaTensor*>>& cache_kvs,
const paddle::optional<std::vector<const MetaTensor*>>& pre_caches,
const MetaTensor& rotary_tensor,
const MetaTensor& beam_offset,
const MetaTensor& time_step,
const MetaTensor& seq_lengths,
const MetaTensor& src_mask,
const std::vector<const MetaTensor*>& out_linear_weights,
const paddle::optional<std::vector<const MetaTensor*>>& out_linear_biases,
const std::vector<const MetaTensor*>& ffn_ln_scales,
const paddle::optional<std::vector<const MetaTensor*>>& ffn_ln_biases,
const std::vector<const MetaTensor*>& ffn1_weights,
const paddle::optional<std::vector<const MetaTensor*>>& ffn1_biases,
const std::vector<const MetaTensor*>& ffn2_weights,
const paddle::optional<std::vector<const MetaTensor*>>& ffn2_biases,
bool pre_layer_norm,
float epsilon,
float residual_alpha,
float dropout_rate,
int rotary_emb_dims,
bool is_test,
const std::string& dropout_implementation,
const std::string& act_method,
bool trans_qkvw,
int ring_id,
const std::string& norm_type,
bool use_neox_rotary_style,
int gqa_group_size,
std::vector<MetaTensor*> cache_kv_outs,
MetaTensor* out) {
// x: qkv's input [batch_size, seq_len, dim_embed]
// y: qkv's weight: [3, num_head, dim_head, dim_embed]
auto x_dim = x.dims();
auto y_dim = qkv_weights[0]->dims();
PADDLE_ENFORCE_EQ(
x_dim.size(),
3,
common::errors::InvalidArgument("The dimensions of x must be 3"
"(batch_size, seq_len, dim_embed), "
"but received dimensions of "
"Input is [%d]",
x_dim.size()));
if (gqa_group_size > 0) {
PADDLE_ENFORCE_EQ(y_dim.size(),
3,
common::errors::InvalidArgument(
"The dimensions of qkv_weight when use gqa must be 3"
"(num_head + 2 * kv_num_heads, dim_head, dim_embed), "
"but received dimensions of "
"Input is [%d]",
y_dim.size()));
} else {
PADDLE_ENFORCE_EQ(
y_dim.size(),
4,
common::errors::InvalidArgument("The dimensions of qkv_weight must be 4"
"(3, num_head, dim_head, dim_embed), "
"but received dimensions of "
"Input is [%d]",
y_dim.size()));
}
if (gqa_group_size > 0) {
PADDLE_ENFORCE_EQ(x_dim[2],
trans_qkvw ? y_dim[2] : y_dim[0],
common::errors::InvalidArgument(
"ShapeError: when use gqa, the dimension of x_dim[2] "
"and y_dim[2](trans_qkvw is "
"true) or y_dim[0](trans_qkvw is false)"
"must be equal. But received: the shape "
"of input x = [%s], and the shape of "
"input qkv_weight = [%s]",
x_dim,
y_dim));
} else {
PADDLE_ENFORCE_EQ(
x_dim[2],
trans_qkvw ? y_dim[3] : y_dim[0],
common::errors::InvalidArgument(
"ShapeError: the dimension of x_dim[2] and y_dim[3](trans_qkvw is "
"true) or y_dim[0](trans_qkvw is false)"
"must be equal. But received: the shape "
"of input x = [%s], and the shape of "
"input qkv_weight = [%s]",
x_dim,
y_dim));
}
if (cache_kvs && cache_kvs->size() > 0) {
// [2, batch_size, num_head, max_seq_len, head_size]
const auto& c_dim = cache_kvs.get()[0]->dims();
PADDLE_ENFORCE_EQ(
c_dim.size(),
5,
common::errors::InvalidArgument(
"The CacheKV must be 5 dims, but got %d", c_dim.size()));
PADDLE_ENFORCE_EQ(c_dim[0],
2,
common::errors::InvalidArgument(
"The first dim of CacheKV must be 2, but got %d",
c_dim[0])); // 2
PADDLE_ENFORCE_EQ(c_dim[1],
x_dim[0],
common::errors::InvalidArgument(
"The second dim of CacheKV must be equal with "
"batch size %d, but got %d",
x_dim[0],
c_dim[1])); // batch_size
if (gqa_group_size > 0) {
PADDLE_ENFORCE_EQ(c_dim[2],
gqa_group_size,
common::errors::InvalidArgument(
"The third dim of CacheKV must be equal with num "
"head %d, but got %d",
gqa_group_size,
c_dim[2])); // num_head
PADDLE_ENFORCE_EQ(c_dim[4],
trans_qkvw ? y_dim[1] : y_dim[2],
common::errors::InvalidArgument(
"The fifth dim of CacheKV must be equal with head "
"size %d, but got %d",
trans_qkvw ? y_dim[1] : y_dim[2],
c_dim[4])); // head_size
} else {
PADDLE_ENFORCE_EQ(c_dim[2],
trans_qkvw ? y_dim[1] : y_dim[2],
common::errors::InvalidArgument(
"The third dim of CacheKV must be equal with num "
"head %d, but got %d",
trans_qkvw ? y_dim[1] : y_dim[2],
c_dim[2])); // num_head
PADDLE_ENFORCE_EQ(c_dim[4],
trans_qkvw ? y_dim[2] : y_dim[3],
common::errors::InvalidArgument(
"The fifth dim of CacheKV must be equal with head "
"size %d, but got %d",
trans_qkvw ? y_dim[2] : y_dim[3],
c_dim[4])); // head_size
}
}
out->set_dims(x.dims());
}
void BlhaGetMaxLenInferMeta(const MetaTensor& seq_lens_encoder,
const MetaTensor& seq_lens_decoder,
const MetaTensor& batch_size,
MetaTensor* max_enc_len_this_time,
MetaTensor* max_dec_len_this_time) {
max_enc_len_this_time->set_dims({1});
max_enc_len_this_time->set_dtype(DataType::INT32);
max_dec_len_this_time->set_dims({1});
max_dec_len_this_time->set_dtype(DataType::INT32);
}
void BlockMultiheadAttentionInferMeta(const MetaTensor& qkv,
const MetaTensor& key_cache,
const MetaTensor& value_cache,
const MetaTensor& seq_lens_encoder,
const MetaTensor& seq_lens_decoder,
const MetaTensor& seq_lens_this_time,
const MetaTensor& padding_offsets,
const MetaTensor& cum_offsets,
const MetaTensor& cu_seqlens_q,
const MetaTensor& cu_seqlens_k,
const MetaTensor& block_tables,
const MetaTensor& pre_key_cache,
const MetaTensor& pre_value_cache,
const MetaTensor& rope_emb,
const MetaTensor& mask,
const MetaTensor& tgt_mask,
const MetaTensor& cache_k_quant_scales,
const MetaTensor& cache_v_quant_scales,
const MetaTensor& cache_k_dequant_scales,
const MetaTensor& cache_v_dequant_scales,
const MetaTensor& qkv_out_scale,
const MetaTensor& qkv_bias,
const MetaTensor& out_shift,
const MetaTensor& out_smooth,
const MetaTensor& max_enc_len_this_time,
const MetaTensor& max_dec_len_this_time,
int max_seq_len,
int block_size,
bool use_neox_style,
bool dynamic_cachekv_quant,
const int quant_round_type,
const float quant_max_bound,
const float quant_min_bound,
const float out_scale,
const std::string& compute_dtype,
const float rope_theta,
MetaTensor* fmha_out,
MetaTensor* qkv_out,
MetaTensor* key_cache_out,
MetaTensor* value_cache_out) {
auto input_dims = qkv.dims();
auto key_cache_dims = key_cache.dims();
const int64_t kv_num_head = key_cache_dims[1];
const int64_t dim_head = key_cache_dims[3];
const int64_t total_num_head = qkv.dims()[qkv.dims().size() - 1] / dim_head;
const int64_t q_num_head = total_num_head - 2 * kv_num_head;
PADDLE_ENFORCE_EQ(
q_num_head % kv_num_head,
0,
errors::InvalidArgument(
"The q num_head (%d) must be divisible by kv num_head (%d)",
q_num_head,
kv_num_head));
PADDLE_ENFORCE_EQ(
input_dims.size(),
2UL,
errors::InvalidArgument("The input(qkv) must be a 2D Tensor."));
PADDLE_ENFORCE_EQ(
key_cache_dims.size(),
4UL,
errors::InvalidArgument("The input(key_cache) must be a 4D Tensor."));
PADDLE_ENFORCE_EQ(
(2 * kv_num_head + q_num_head) * dim_head,
input_dims[1],
errors::InvalidArgument("The input_dims[1] must be equal to (2 * "
"kv_num_head + q_num_head) * dim_head"));
fmha_out->set_dims({input_dims[0], q_num_head * dim_head});
qkv_out->set_dims(qkv.dims());
key_cache_out->set_dims(key_cache_dims);
key_cache_out->set_dtype(key_cache.dtype());
value_cache_out->set_dims(key_cache_dims);
value_cache_out->set_dtype(value_cache.dtype());
auto FBADtypeCheck = [](const MetaTensor& check_tensor,
const std::string& tensor_name,
const std::string& compute_dtype) {
if (compute_dtype == "bf16") {
PADDLE_ENFORCE_EQ(
check_tensor.dtype(),
DataType::BFLOAT16,
common::errors::InvalidArgument(
"Input(%s) dtype must be the same with Attr(compute_dtype)",
tensor_name));
} else if (compute_dtype == "fp16") {
PADDLE_ENFORCE_EQ(
check_tensor.dtype(),
DataType::FLOAT16,
common::errors::InvalidArgument(
"Input(%s) dtype must be the same with Attr(compute_dtype)",
tensor_name));
} else if (compute_dtype == "fp32") {
PADDLE_ENFORCE_EQ(
check_tensor.dtype(),
DataType::FLOAT32,
common::errors::InvalidArgument(
"Input(%s) dtype must be the same with Attr(compute_dtype)",
tensor_name));
}
};
// In the case of quantization enabled, the dtype for computation is
// determined based on compute_dtype.
if (qkv.dtype() == DataType::INT32) {
PADDLE_ENFORCE_NE(
compute_dtype,
"default",
common::errors::InvalidArgument(
"If Input(x) dtype is INT32, Attr(compute_dtype) must be set."));
if (out_scale > 0) {
fmha_out->set_dtype(DataType::INT8);
} else {
if (compute_dtype == "bf16") {
fmha_out->set_dtype(DataType::BFLOAT16);
} else if (compute_dtype == "fp16") {
fmha_out->set_dtype(DataType::FLOAT16);
} else if (compute_dtype == "fp32") {
fmha_out->set_dtype(DataType::FLOAT32);
} else {
PADDLE_THROW(common::errors::InvalidArgument(
"In the case of quantization enabled with Input(x) INT32, "
"Attr(compute_dtype) must be set in (bf16, fp16, fp32), "
"but get compute_dtype (%s)",
compute_dtype));
}
}
} else {
if (compute_dtype != "default") {
FBADtypeCheck(qkv, "qkv", compute_dtype);
}
if (out_scale > 0) {
if (fabs(quant_max_bound - 127.0f) < 0.000001) {
fmha_out->set_dtype(DataType::INT8);
} else if (fabs(quant_max_bound - 448.0f) < 0.000001) {
fmha_out->set_dtype(DataType::FLOAT8_E4M3FN);
}
} else {
fmha_out->set_dtype(qkv.dtype());
}
}
}
void BlockMultiheadAttentionInferXPUMeta(
const MetaTensor& qkv,
const MetaTensor& key_cache,
const MetaTensor& value_cache,
const MetaTensor& seq_lens_encoder,
const MetaTensor& seq_lens_decoder,
const MetaTensor& seq_lens_this_time,
const MetaTensor& padding_offsets,
const MetaTensor& cum_offsets,
const MetaTensor& cu_seqlens_q,
const MetaTensor& cu_seqlens_k,
const MetaTensor& cache_k_per_batch_maxs,
const MetaTensor& cache_v_per_batch_maxs,
const MetaTensor& block_tables,
const MetaTensor& pre_key_cache,
const MetaTensor& pre_value_cache,
const MetaTensor& rope_emb,
const MetaTensor& mask,
const MetaTensor& tgt_mask,
const MetaTensor& cache_k_quant_scales,
const MetaTensor& cache_v_quant_scales,
const MetaTensor& cache_k_dequant_scales,
const MetaTensor& cache_v_dequant_scales,
const MetaTensor& qkv_out_scale,
const MetaTensor& qkv_bias,
const MetaTensor& out_shift,
const MetaTensor& out_smooth,
const MetaTensor& max_enc_len_this_time,
const MetaTensor& max_dec_len_this_time,
int max_seq_len,
int block_size,
bool use_neox_style,
bool dynamic_cachekv_quant,
const int quant_round_type,
const float quant_max_bound,
const float quant_min_bound,
const float out_scale,
const std::string& compute_dtype,
const float rope_theta,
MetaTensor* fmha_out,
MetaTensor* qkv_out,
MetaTensor* key_cache_out,
MetaTensor* value_cache_out) {
BlockMultiheadAttentionInferMeta(qkv,
key_cache,
value_cache,
seq_lens_encoder,
seq_lens_decoder,
seq_lens_this_time,
padding_offsets,
cum_offsets,
cu_seqlens_q,
cu_seqlens_k,
block_tables,
pre_key_cache,
pre_value_cache,
rope_emb,
mask,
tgt_mask,
cache_k_quant_scales,
cache_v_quant_scales,
cache_k_dequant_scales,
cache_v_dequant_scales,
qkv_out_scale,
qkv_bias,
out_shift,
out_smooth,
max_enc_len_this_time,
max_dec_len_this_time,
max_seq_len,
block_size,
use_neox_style,
dynamic_cachekv_quant,
quant_round_type,
quant_max_bound,
quant_min_bound,
out_scale,
compute_dtype,
rope_theta,
fmha_out,
qkv_out,
key_cache_out,
value_cache_out);
}
void Conv1dXPUInferMeta(const MetaTensor& x,
const MetaTensor& x_max,
const MetaTensor& filter,
const MetaTensor& filter_max,
const MetaTensor& bias,
const MetaTensor& branch,
const MetaTensor& branch_max,
const std::vector<int>& paddings,
const std::string& padding_algorithm,
int dilations,
int strides,
int groups,
int act_type,
float act_param,
MetaTensor* out,
MetaTensor* out_max) {
auto in_dims = x.dims();
auto filter_dims = filter.dims();
// do some checks
PADDLE_ENFORCE_EQ(
in_dims.size(),
3,
common::errors::InvalidArgument(
"The input of Op(Conv_xpu) should be a 3-D Tensor. But "
"received: input's dimension is %u, input's shape is [%s].",
in_dims.size(),
in_dims));
PADDLE_ENFORCE_EQ(
in_dims.size(),
filter_dims.size(),
common::errors::InvalidArgument(
"The input's dimension and filter's dimension of "
"Op(Conv_xpu) should be equal. But received: the input's shape is "
"[%s], "
"the input's dimension is %d; the filter's shape is [%s], "
"the filter's dimension is %d.",
in_dims,
in_dims.size(),
filter_dims,
filter_dims.size()));
const auto input_channels = in_dims[1];
PADDLE_ENFORCE_GT(
dilations,
0,
common::errors::InvalidArgument(
"The dilation of Op(Conv) should be larger than 0, but received "
"dilation is %d.",
dilations));
PADDLE_ENFORCE_EQ(
input_channels,
filter_dims[1] * groups,
common::errors::InvalidArgument(
"The number of input's channels should be equal to filter's channels "
"* groups for Op(Conv_xpu). But received: the input's channels is "
"%d, "
"the input's shape is [%s]; the filter's channels is %d, the "
"filter's shape is [%s]; the groups is %d. ",
input_channels,
in_dims,
filter_dims[1],
filter_dims,
groups));
PADDLE_ENFORCE_EQ(
filter_dims[0] % groups,
0,
common::errors::InvalidArgument(
"The number of output's channels (filter's first dimension) of "
"Op(Conv) should be divided by groups. But received: "
"the output channels is %d, the filter's shape is [%s], "
"the groups is %d.",
filter_dims[0],
filter_dims,
groups));
std::vector<int64_t> out_shape({in_dims[0], filter_dims[0]});
out_shape.push_back(ConvOutSize(in_dims[2],
filter_dims[2],
dilations,
paddings[0],
paddings[1],
strides));
// set output and output max dims
out->set_dims(DDim(out_shape.data(), static_cast<int>(out_shape.size())));
out->set_dtype(x.dtype());
out->set_layout(x.layout());
out_max->set_dims(make_ddim({6}));
}
void Conv2dXPUInferMeta(const MetaTensor& x,
const MetaTensor& x_max,
const MetaTensor& filter,
const MetaTensor& filter_max,
const MetaTensor& bias,
const MetaTensor& branch,
const MetaTensor& branch_max,
const MetaTensor& scale_max,
const MetaTensor& out_max_in,
const std::vector<int>& paddings,
const std::vector<int>& dilations,
const std::vector<int>& strides,
const std::string& padding_algorithm,
int groups,
int act_type,
float act_param,
DataType out_dtype,
MetaTensor* out,
MetaTensor* out_max) {
auto in_dims = x.dims();
auto filter_dims = filter.dims();
// do some checks
PADDLE_ENFORCE_EQ(
in_dims.size(),
4,
common::errors::InvalidArgument(
"The input of Op(Conv_xpu) should be a 4-D Tensor. But "
"received: input's dimension is %u, input's shape is [%s].",
in_dims.size(),
in_dims));
PADDLE_ENFORCE_EQ(
in_dims.size(),
filter_dims.size(),
common::errors::InvalidArgument(
"The input's dimension and filter's dimension of "
"Op(Conv_xpu) should be equal. But received: the input's shape is "
"[%s], "
"the input's dimension is %d; the filter's shape is [%s], "
"the filter's dimension is %d.",
in_dims,
in_dims.size(),
filter_dims,
filter_dims.size()));
const auto input_channels = in_dims[1];
int stride_size = static_cast<int>(strides.size());
int in_sub_stride_size = in_dims.size() - stride_size;
int dilation_size = static_cast<int>(dilations.size());
PADDLE_ENFORCE_EQ(
in_dims.size(),
strides.size() + 2U,
common::errors::InvalidArgument(
"The difference of input's dimension and Attr(strides)'s "
"length must be equal to 2 for Op(Conv_xpu). "
"But received: input's dimension is %d, input's shape is [%s]; "
"Attr(stride)'s length is %d, Attr(stride) is [%s]; "
"difference of input's dimension and Attr(strides)'s length = %u.",
in_dims.size(),
in_dims,
strides.size(),
make_ddim(strides),
in_sub_stride_size));
for (int i = 0; i < dilation_size; ++i) {
PADDLE_ENFORCE_GT(
dilations[i],
0,
common::errors::InvalidArgument(
"The dilation of Op(Conv) should be larger than 0, but received "
"dilation is %d.",
dilations[i]));
}
PADDLE_ENFORCE_EQ(
input_channels,
filter_dims[1] * groups,
common::errors::InvalidArgument(
"The number of input's channels should be equal to filter's channels "
"* groups for Op(Conv_xpu). But received: the input's channels is "
"%d, "
"the input's shape is [%s]; the filter's channels is %d, the "
"filter's shape is [%s]; the groups is %d. ",
input_channels,
in_dims,
filter_dims[1],
filter_dims,
groups));
PADDLE_ENFORCE_EQ(
filter_dims[0] % groups,
0,
common::errors::InvalidArgument(
"The number of output's channels (filter's first dimension) of "
"Op(Conv) should be divided by groups. But received: "
"the output channels is %d, the filter's shape is [%s], "
"the groups is %d.",
filter_dims[0],
filter_dims,
groups));
// update paddings and dilations according to padding_algorithm
std::vector<int> paddings_vec = paddings;
std::vector<int> dilations_vec = dilations;
DDim in_data_dims = slice_ddim(in_dims, 2, in_dims.size());
DDim filter_data_dims = slice_ddim(filter_dims, 2, filter_dims.size());
std::vector<int> ksize = vectorize<int>(filter_data_dims);
phi::UpdatePaddingAndDilation(&paddings_vec,
&dilations_vec,
padding_algorithm,
in_data_dims,
strides,
ksize);
std::vector<int64_t> out_shape({in_dims[0], filter_dims[0]});
for (int i = 0; i < static_cast<int>(strides.size()); ++i) {
// VLOG(3) << "conv_xpu: strides " << i;
if ((in_dims[i + 2] <= 0 || filter_dims[i + 2] <= 0)) {
out_shape.push_back(-1);
} else {
out_shape.push_back(ConvOutSize(in_dims[i + 2],
filter_dims[i + 2],
dilations[i],
paddings_vec[i * 2],
paddings_vec[i * 2 + 1],
strides[i]));
}
}
// set output and output max dims
out->set_dims(DDim(out_shape.data(), static_cast<int>(out_shape.size())));
out_max->set_dims(make_ddim({6}));
out->set_dtype(out_dtype);
}
void SpatialTransformerResblockXPUInferMeta(
const MetaTensor& x,
const std::vector<const MetaTensor*>& x_max,
const std::vector<const MetaTensor*>& conv_bias,
const std::vector<const MetaTensor*>& conv_filter,
const std::vector<const MetaTensor*>& conv_filter_max,
const std::vector<const MetaTensor*>& gn_bias,
const std::vector<const MetaTensor*>& gn_scale,
const std::vector<int>& dilations,
const std::vector<int>& paddings,
const std::vector<int>& strides,
const std::vector<float>& gn_eps,
const std::vector<int>& gn_groups,
const std::vector<int>& groups,
bool conv_fix,
bool has_silu_fc_input,
bool include_silu,
MetaTensor* out,
MetaTensor* out_max) {
auto input_shape = x.dims();
auto batch_size = input_shape[0];
auto channel_out = conv_filter[0]->dims()[0];
auto h = input_shape[2];
auto w = input_shape[3];
out->set_dims(make_ddim({batch_size, channel_out, h, w}));
out->set_dtype(x.dtype());
out->set_layout(x.layout());
out->share_lod(x);
}
void EmbeddingWithEltwiseAddXPUInferMeta(
const std::vector<const MetaTensor*>& ids,
const std::vector<const MetaTensor*>& tables,
const MetaTensor& mask,
MetaTensor* out,
MetaTensor* seq_lod,
MetaTensor* max_seq_len) {
PADDLE_ENFORCE_GT(ids.size(),
0UL,
common::errors::InvalidArgument(
"The input ids in EmbeddingWithEltwiseAddXPUInferMeta "
"can't be empty."));
PADDLE_ENFORCE_GT(tables.size(),
0UL,
common::errors::InvalidArgument(
"The input tables in "
"EmbeddingWithEltwiseAddXPUInferMeta can't be empty."));
auto id_dims = ids[0]->dims();
auto table_dims = tables[0]->dims();
out->set_dims(make_ddim({id_dims[0], id_dims[1], table_dims[1]}));
out->set_dtype(tables[0]->dtype());
out->set_layout(ids[0]->layout());
}
void FcXPUInferMeta(const MetaTensor& x,
const MetaTensor& x_max,
const MetaTensor& w,
const MetaTensor& w_max,
const MetaTensor& bias,
const MetaTensor& scale_max,
const MetaTensor& out_max_in,
int in_num_col_dims,
bool transpose_x,
float alpha,
float beta,
int act_type,
float act_alpha,
DataType out_dtype,
MetaTensor* out,
MetaTensor* out_max) {
std::vector<int> out_shape(in_num_col_dims + 1);
for (int i = 0; i < in_num_col_dims; i++) {
out_shape[i] = x.dims()[i];
}
out_shape[in_num_col_dims] = w.dims()[0];
if (act_type == 23 /*phi::backends::xpu::Activation_t::SWISH_GLU*/) {
out_shape[in_num_col_dims] = out_shape[in_num_col_dims] / 2;
}
out->set_dims(DDim(out_shape.data(), static_cast<int>(out_shape.size())));
out->set_dtype(out_dtype);
out->set_layout(x.layout());
out_max->set_dims(make_ddim({6}));
out_max->set_dtype(x.dtype());
out_max->set_layout(x.layout());
}
void FusedActDequantInferMeta(const MetaTensor& x,
const MetaTensor& x_scale,
MetaTensor* out) {
auto x_dims = x.dims();
PADDLE_ENFORCE_EQ(
x.dtype(),
DataType::FLOAT8_E4M3FN,
common::errors::InvalidArgument(
"The data type of X should be FLOAT8_E4M3FN, but received %s.",
x.dtype()));
PADDLE_ENFORCE_EQ(
x_scale.dtype() == DataType::FLOAT32 ||
x_scale.dtype() == DataType::INT32,
true,
common::errors::InvalidArgument("The data type of X_scale should be "
"FLOAT32 or INT32, but received %s.",
x_scale.dtype()));
PADDLE_ENFORCE_EQ(x_dims.size(),
2,
common::errors::InvalidArgument(
"The input X should be a 2D tensor, but received %dD.",
x_dims.size()));
int64_t rows = x_dims[0];
int64_t cols = x_dims[1];
PADDLE_ENFORCE_GT(
rows,
0,
common::errors::InvalidArgument(
"The rows of X should be positive, but received %d.", rows));
PADDLE_ENFORCE_GT(
cols,
0,
common::errors::InvalidArgument(
"The cols of X should be positive, but received %d.", cols));
auto scale_dims = x_scale.dims();
int64_t scale_cols_expected = (cols + 127) / 128;
if (x_scale.dtype() == DataType::INT32) {
scale_cols_expected = (scale_cols_expected + 3) / 4;
}
// Check scale shape assuming it is [rows, scale_cols] or flattened
if (scale_dims.size() == 2) {
PADDLE_ENFORCE_EQ(scale_dims[0],
rows,
common::errors::InvalidArgument(
"The rows of X_scale should be equal to rows of X"));
PADDLE_ENFORCE_EQ(
scale_dims[1],
scale_cols_expected,
common::errors::InvalidArgument("The cols of X_scale should be %d",
scale_cols_expected));
} else if (scale_dims.size() == 1) {
PADDLE_ENFORCE_EQ(
scale_dims[0],
rows * scale_cols_expected,
common::errors::InvalidArgument("The numel of X_scale should be %d",
rows * scale_cols_expected));
}
out->set_dims(x_dims);
out->set_dtype(DataType::BFLOAT16);
out->set_layout(x.layout());
}
void FusedAttentionInferMeta(const MetaTensor& x,
const MetaTensor& ln_scale,
const MetaTensor& ln_bias,
const MetaTensor& qkv_weight,
const MetaTensor& qkv_bias,
const MetaTensor& cache_kv,
const MetaTensor& src_mask,
const MetaTensor& out_linear_weight,
const MetaTensor& out_linear_bias,
const MetaTensor& ln_scale_2,
const MetaTensor& ln_bias_2,
int num_heads,
bool transpose_qkv_wb,
bool pre_layer_norm,
float epsilon,
float attn_dropout_rate,
bool is_test,
bool attn_dropout_fix_seed,
int attn_dropout_seed,
const std::string& attn_dropout_implementation,
float dropout_rate,
bool dropout_fix_seed,
int dropout_seed,
const std::string& dropout_implementation,
float ln_epsilon,
bool add_residual,
int ring_id,
MetaTensor* ln_mean,
MetaTensor* ln_var,
MetaTensor* ln_out,
MetaTensor* qkv_out,
MetaTensor* qkv_bias_out,
MetaTensor* transpose_out_2,
MetaTensor* qk_out,
MetaTensor* qktv_out,
MetaTensor* softmax_out,
MetaTensor* attn_dropout_mask_out,
MetaTensor* attn_dropout_out,
MetaTensor* src_mask_out,
MetaTensor* fmha_out,
MetaTensor* out_linear_out,
MetaTensor* dropout_mask_out,
MetaTensor* ln_mean_2,
MetaTensor* ln_var_2,
MetaTensor* bias_dropout_residual_out,
MetaTensor* cache_kv_out,
MetaTensor* out,
MetaConfig config) {
auto x_dim = x.dims();
auto y_dim = qkv_weight.dims();
int64_t dim_head = 0;
int64_t hidden_size = 0;
int64_t nranks = 1;
if (transpose_qkv_wb) {
PADDLE_ENFORCE_EQ(y_dim.size(),
2,
common::errors::InvalidArgument(
"The dimensions of qkv_weight must be 2 if enable "
"transpose_qkv_wb: (dim_embed, 3 * dim_embed), "
"but received dimensions of "
"Input is [%d]",
y_dim.size()));
PADDLE_ENFORCE_GT(num_heads,
0,
common::errors::InvalidArgument(
"The num_heads must be provided and greater than 0 "
"if enable transpose_qkv_wb, but we got %d.",
num_heads));
PADDLE_ENFORCE_EQ(y_dim[0] % num_heads,
0,
common::errors::InvalidArgument(
"First dim of qkv_w must be divisible by num heads "
"if enable transpose_qkv_wb, but receive first "
"dim of qkv_w is %d and num_heads is %d.",
y_dim[0],
num_heads));
if (ring_id == -1) {
PADDLE_ENFORCE_EQ(y_dim[0] * 3,
y_dim[1],
common::errors::InvalidArgument(
"The dimensions of qkv_weight must be 2"
"(dim_embed, 3 * dim_embed)."));
} else {
// compute the mp nranks
nranks = (y_dim[0] * 3) / y_dim[1];
}
dim_head = y_dim[0] / (num_heads * nranks);
hidden_size = y_dim[0];
} else {
PADDLE_ENFORCE_EQ(y_dim.size(),
4,
common::errors::InvalidArgument(
"The dimensions of qkv_weight must be 4 if not "
"enable transpose_qkv_wb: (3, num_head, dim_head, "
"dim_embed), but received [%d]",
y_dim.size()));
PADDLE_ENFORCE_EQ(y_dim[0],
3,
common::errors::InvalidArgument(
"First dim of qkv_w must be 3 if disable "
"transpose_qkv_wb, but we got %d.",
y_dim[0]));
if (ring_id == -1) {
PADDLE_ENFORCE_EQ(y_dim[1] * y_dim[2],
y_dim[3],
common::errors::InvalidArgument(
"The dimensions of qkv_weight must be 4"
"(3, num_head, dim_head, dim_embed),"
"and must satisfy the limitations: "
"(num_head * dim_head == dim_embed)"));
}
// TODO(large-tensor): num_heads, dim_head, hidden_size may exceed INT_MAX
int64_t num_heads_int64 = y_dim[1];
int64_t dim_head_int64 = y_dim[2];
int64_t hidden_size_int64 = y_dim[3];
PADDLE_ENFORCE_LE_INT_MAX(num_heads_int64, "num_heads");
PADDLE_ENFORCE_LE_INT_MAX(dim_head_int64, "dim_head");
PADDLE_ENFORCE_LE_INT_MAX(hidden_size_int64, "hidden_size");
num_heads = static_cast<int>(num_heads_int64);
dim_head = static_cast<int>(dim_head_int64);
hidden_size = static_cast<int>(hidden_size_int64);
}
PADDLE_ENFORCE_EQ(
x_dim.size(),
3,
common::errors::InvalidArgument("The dimensions of x must be 3"
"(batch_size, seq_len, dim_embed), "
"but received dimensions of "
"Input is [%d]",
x_dim.size()));
PADDLE_ENFORCE_EQ(x_dim[2],
hidden_size,
common::errors::InvalidArgument(
"ShapeError: the dimension of x_dim[2] and y_dim[3] "
"(y_dim[1] if enable transpose_qkv_w) "
"must be equal. But received: the shape "
"of input x = [%s], and the shape of "
"input qkv_weight = [%s]",
x_dim,
y_dim));
if (pre_layer_norm) {
ln_mean->set_dims({x_dim[0] * x_dim[1]});
ln_var->set_dims({x_dim[0] * x_dim[1]});
ln_out->set_dims(x.dims());
} else {
ln_mean_2->set_dims({x_dim[0] * x_dim[1]});
ln_var_2->set_dims({x_dim[0] * x_dim[1]});
bias_dropout_residual_out->set_dims(x.dims());
}
if (transpose_qkv_wb) {
// [batch_size, seq_len, 3 * num_heads * dim_head]
qkv_out->set_dims({x_dim[0], x_dim[1], 3 * num_heads * dim_head});
if (qkv_bias) {
qkv_bias_out->set_dims({x_dim[0], x_dim[1], 3 * num_heads * dim_head});
}
} else {
// [batch_size, seq_len, 3, num_head, head_size]
qkv_out->set_dims({x_dim[0], x_dim[1], 3, num_heads, dim_head});
if (qkv_bias) {
qkv_bias_out->set_dims({x_dim[0], x_dim[1], 3, num_heads, dim_head});
}
}
// [3, batch_size, num_head, seq_len, head_size]
transpose_out_2->set_dims({3, x_dim[0], num_heads, x_dim[1], dim_head});
// cache_seq_len + seq_len if cache else seq_len
auto out_seq_len = x_dim[1];
if (cache_kv) {
// [2, batch_size, num_head, cache_seq_len, head_size]
auto c_dim = cache_kv.dims();
PADDLE_ENFORCE_EQ(
c_dim.size(),
5,
common::errors::InvalidArgument(
"The CacheKV must be 5 dims, but got %d", c_dim.size()));
PADDLE_ENFORCE_EQ(c_dim[0],
2,
common::errors::InvalidArgument(
"The first dim of CacheKV must be 2, but got %d",
c_dim[0])); // 2
PADDLE_ENFORCE_EQ(c_dim[1],
x_dim[0],
common::errors::InvalidArgument(
"The second dim of CacheKV must be equal with "
"batch size %d, but got %d",
x_dim[0],
c_dim[1])); // batch_size
PADDLE_ENFORCE_EQ(c_dim[2],
num_heads,
common::errors::InvalidArgument(
"The third dim of CacheKV must be equal with num "
"head %d, but got %d",
num_heads,
c_dim[2])); // num_head
// In compile stage, input seq_len can be -1, in that case
// c_dim[3] may < 0 in while
if (config.is_runtime) {
PADDLE_ENFORCE_GE(
c_dim[3],
0,
common::errors::InvalidArgument(
"The forth dim of CacheKV must be greater than 0, but got %d",
c_dim[3])); // cache_seq_len
}
PADDLE_ENFORCE_EQ(c_dim[4],
dim_head,
common::errors::InvalidArgument(
"The fifth dim of CacheKV must be equal with head "
"size %d, but got %d",
dim_head,
c_dim[4])); // head_size
out_seq_len += c_dim[3];
// [3, batch_size, num_head, cache_seq_len + seq_len, head_size]
cache_kv_out->set_dims(
{c_dim[0], c_dim[1], c_dim[2], out_seq_len, c_dim[4]});
}
// [batch, num_head, seq_len, out_seq_len]
qk_out->set_dims({x_dim[0], num_heads, x_dim[1], out_seq_len});
if (src_mask) {
src_mask_out->set_dims({x_dim[0], num_heads, x_dim[1], out_seq_len});
}
// the same as QKOut's shape.
attn_dropout_out->set_dims({x_dim[0], num_heads, x_dim[1], out_seq_len});
if (!is_test) {
attn_dropout_mask_out->set_dims(
{x_dim[0], num_heads, x_dim[1], out_seq_len});
}
softmax_out->set_dims({x_dim[0], num_heads, x_dim[1], out_seq_len});
// [batch_size, num_heads, seq_len, head_dim]
qktv_out->set_dims({x_dim[0], num_heads, x_dim[1], dim_head});
// [batch_size, seq_len, number of heads*head size]
fmha_out->set_dims({x_dim[0], x_dim[1], num_heads, dim_head});
out_linear_out->set_dims(x.dims());
if (is_test == false) {
dropout_mask_out->set_dims(x.dims());
}
out->set_dims(x.dims());
out->set_dtype(x.dtype());
}
void FusedAttentionGradInferMeta(const MetaTensor& out_grad,
const MetaTensor& x,
const MetaTensor& qkv_weight,
const MetaTensor& qkv_bias,
const MetaTensor& qkv_bias_out,
const MetaTensor& src_mask,
const MetaTensor& src_mask_out,
const MetaTensor& out_linear_weight,
const MetaTensor& out_linear_bias,
const MetaTensor& ln_scale,
const MetaTensor& ln_bias,
const MetaTensor& ln_scale_2,
const MetaTensor& ln_bias_2,
const MetaTensor& ln_out,
const MetaTensor& ln_mean,
const MetaTensor& ln_var,
const MetaTensor& ln_mean_2,
const MetaTensor& ln_var_2,
const MetaTensor& bias_dropout_residual_out,
const MetaTensor& qkv_out,
const MetaTensor& transpose_out_2,
const MetaTensor& qk_out,
const MetaTensor& qktv_out,
const MetaTensor& softmax_out,
const MetaTensor& attn_dropout_mask_out,
const MetaTensor& attn_dropout_out,
const MetaTensor& fmha_out,
const MetaTensor& out_linear_out,
const MetaTensor& dropout_mask_out,
int num_heads,
bool transpose_qkv_wb,
bool pre_layer_norm,
float epsilon,
float attn_dropout_rate,
bool is_test,
bool attn_dropout_fix_seed,
int attn_dropout_seed,
const std::string& attn_dropout_implementation,
float dropout_rate,
bool dropout_fix_seed,
int dropout_seed,
const std::string& dropout_implementation,
float ln_epsilon,
bool add_residual,
int ring_id,
MetaTensor* qkv_bias_grad,
MetaTensor* qkv_bias_out_grad,
MetaTensor* src_mask_out_grad,
MetaTensor* out_linear_bias_grad,
MetaTensor* ln_scale_grad,
MetaTensor* ln_bias_grad,
MetaTensor* ln_scale_2_grad,
MetaTensor* ln_bias_2_grad,
MetaTensor* x_grad,
MetaTensor* qkv_weight_grad,
MetaTensor* out_linear_weight_grad,
MetaTensor* ln_out_grad,
MetaTensor* bias_dropout_residual_out_grad,
MetaTensor* qkv_out_grad,
MetaTensor* qktv_out_grad,
MetaTensor* transpose_out_2_grad,
MetaTensor* qk_out_grad,
MetaTensor* softmax_out_grad,
MetaTensor* attn_dropout_out_grad,
MetaTensor* fmha_out_grad,
MetaTensor* out_linear_out_grad) {
PADDLE_ENFORCE_EQ(is_test,
false,
common::errors::InvalidArgument(
"GradOp is only callable when is_test is false"));
if (!pre_layer_norm) {
if (ln_scale_2_grad && ln_scale_2) {
ln_scale_2_grad->set_dims(ln_scale_2.dims());
}
if (ln_bias_2_grad && ln_bias_2) {
ln_bias_2_grad->set_dims(ln_bias_2.dims());
}
}
if (pre_layer_norm && ln_scale) {
if (ln_scale_grad) {
ln_scale_grad->set_dims(ln_scale.dims());
}
if (ln_bias_grad && ln_bias) {
ln_bias_grad->set_dims(ln_bias.dims());
}
}
if (x_grad) {
x_grad->set_dims(x.dims());
}
if (out_linear_bias_grad && out_linear_bias) {
out_linear_bias_grad->set_dims(out_linear_bias.dims());
}
if (out_linear_weight_grad) {
out_linear_weight_grad->set_dims(out_linear_weight.dims());
}
if (qkv_weight_grad) {
qkv_weight_grad->set_dims(qkv_weight.dims());
}
if (qkv_bias_grad && qkv_bias) {
qkv_bias_grad->set_dims(qkv_bias.dims());
}
if (pre_layer_norm) {
if (ln_out_grad) {
ln_out_grad->set_dims(ln_out.dims());
}
} else {
if (bias_dropout_residual_out_grad && bias_dropout_residual_out) {
bias_dropout_residual_out_grad->set_dims(
bias_dropout_residual_out.dims());
}
}
if (fmha_out_grad) {
fmha_out_grad->set_dims(fmha_out.dims());
}
if (qktv_out_grad) {
qktv_out_grad->set_dims(qktv_out.dims());
}
if (transpose_out_2_grad) {
transpose_out_2_grad->set_dims(transpose_out_2.dims());
}
if (qk_out_grad) {
qk_out_grad->set_dims(qk_out.dims());
}
if (softmax_out_grad) {
softmax_out_grad->set_dims(softmax_out.dims());
}
if (attn_dropout_out_grad) {
attn_dropout_out_grad->set_dims(attn_dropout_out.dims());
}
if (src_mask_out_grad) {
src_mask_out_grad->set_dims(src_mask_out.dims());
}
if (qkv_out_grad) {
qkv_out_grad->set_dims(qkv_out.dims());
}
if (qkv_bias_out_grad) {
qkv_bias_out_grad->set_dims(qkv_bias_out.dims());
}
if (out_linear_out_grad) {
out_linear_out_grad->set_dims(out_linear_out.dims());
}
}
void FusedBiasDropoutResidualLnInferMeta(
const MetaTensor& x,
const MetaTensor& residual,
const MetaTensor& bias,
const MetaTensor& ln_scale,
const MetaTensor& ln_bias,
const float dropout_rate,
const bool is_test,
const bool dropout_fix_seed,
const int dropout_seed,
const std::string& dropout_implementation,
const float ln_epsilon,
MetaTensor* y,
MetaTensor* bias_dropout_residual_out,
MetaTensor* dropout_mask_out,
MetaTensor* ln_mean,
MetaTensor* ln_variance) {
PADDLE_ENFORCE_EQ(dropout_rate >= 0.0f && dropout_rate <= 1.0f,
true,
common::errors::InvalidArgument(
"'dropout_rate' must be between 0.0 and 1.0."));
PADDLE_ENFORCE_EQ(
dropout_implementation == "downgrade_in_infer" ||
dropout_implementation == "upscale_in_train",
true,
common::errors::InvalidArgument(
"dropout_implementation can only be downgrade_in_infer or "
"upscale_in_train"));
PADDLE_ENFORCE_EQ(ln_epsilon >= 0.0f && ln_epsilon <= 0.001f,
true,
common::errors::InvalidArgument(
"'epsilon' of the LayerNorm should be between "
"0.0 and 0.001, But received [%s].",
ln_epsilon));
auto x_dim = x.dims();
int64_t left = 1;
for (int i = 0; i < x_dim.size() - 1; i++) {
left *= x_dim[i];
}
bias_dropout_residual_out->set_dims(x.dims());
if (is_test == false) {
dropout_mask_out->set_dims(x.dims());
}
ln_mean->set_dims({left});
ln_variance->set_dims({left});
y->set_dims(x.dims());
if (common::product(x_dim) != 0 && common::product(residual.dims()) == 0) {
y->set_dims(residual.dims());
}
}
void FusedBiasDropoutResidualLnGradInferMeta(
const MetaTensor& x,
const MetaTensor& residual,
const MetaTensor& bias,
const MetaTensor& ln_scale,
const MetaTensor& ln_bias,
const MetaTensor& ln_mean,
const MetaTensor& ln_variance,
const MetaTensor& bias_dropout_residual_out,
const MetaTensor& dropout_mask_out,
const MetaTensor& y_grad,
const float dropout_rate,
const bool is_test,
const bool dropout_fix_seed,
const int dropout_seed,
const std::string& dropout_implementation,
const float ln_epsilon,
MetaTensor* x_grad,
MetaTensor* residual_grad,
MetaTensor* bias_grad,
MetaTensor* ln_scale_grad,
MetaTensor* ln_bias_grad) {
PADDLE_ENFORCE_EQ(is_test,
false,
common::errors::InvalidArgument(
"GradOp is only callable when is_test is false"));
if (ln_scale_grad) {
ln_scale_grad->set_dims(ln_scale.dims());
ln_scale_grad->set_dtype(y_grad.dtype());
}
if (ln_bias_grad) {
ln_bias_grad->set_dims(ln_bias.dims());
ln_bias_grad->set_dtype(y_grad.dtype());
}
if (residual_grad) {
residual_grad->set_dims(residual.dims());
residual_grad->set_dtype(y_grad.dtype());
}
if (bias_grad) {
bias_grad->set_dims(bias.dims());
bias_grad->set_dtype(y_grad.dtype());
}
if (x_grad) {
x_grad->set_dims(x.dims());
x_grad->set_dtype(y_grad.dtype());
}
}
void FusedDotProductAttentionInferMeta(const MetaTensor& q,
const MetaTensor& k,
const MetaTensor& v,
const MetaTensor& bias,
MetaTensor* out,
MetaTensor* softmax_out,
MetaTensor* rng_state) {
// q input shape: [batch_size, q_seq_len, num_heads, head_size]
// k, v input shape: [batch_size, kv_seq_len, num_heads, head_size]
// cu_seqlen_q and cu_seqlen_kv input shape: [batch_size+1]
// bias shape: [b,1,s,s] or [b,h,s,s] or [1,1,s,s] or [1, h, s, s]
auto q_dim = q.dims();
auto k_dim = k.dims();
auto v_dim = v.dims();
// check shape
PADDLE_ENFORCE(q_dim.size() == 4 && k_dim.size() == 4 && v_dim.size() == 4,
common::errors::InvalidArgument(
"The dimensions of q, k, v must be 4"
"(batch_size, seq_len, num_heads, head_size), "
"but received dimensions of "
"Input is [%d], [%d], [%d]",
q_dim.size(),
k_dim.size(),
v_dim.size()));
PADDLE_ENFORCE(q_dim[0] == k_dim[0] && k_dim[0] == v_dim[0],
common::errors::InvalidArgument(
"The first dimension of q, k, v must be equal, "
"but received dimensions of "
"Input is [%d], [%d], [%d]",
q_dim[0],
k_dim[0],
v_dim[0]));
// [batch_size, num_heads, q_seqlen, 1]
std::vector<int64_t> softmax_out_shape({q_dim[0], q_dim[2], q_dim[1], 1});
out->set_dims(q_dim);
softmax_out->set_dims(
DDim(softmax_out_shape.data(), softmax_out_shape.size()));
// rng_state: {seed, offset}
std::vector<int64_t> rng_state_shape({2});
rng_state->set_dims(DDim(rng_state_shape.data(), rng_state_shape.size()));
}
void FusedDotProductAttentionGradInferMeta(const MetaTensor& q,
const MetaTensor& k,
const MetaTensor& v,
const MetaTensor& bias,
MetaTensor* q_grad,
MetaTensor* k_grad,
MetaTensor* v_grad,
MetaTensor* bias_grad) {
q_grad->share_meta(q);
k_grad->share_meta(k);
v_grad->share_meta(v);
if (bias) {
if (bias_grad) {
bias_grad->share_meta(bias);
}
}
}
void FusedFeedForwardInferMeta(const MetaTensor& x,
const MetaTensor& dropout1_seed,
const MetaTensor& dropout2_seed,
const MetaTensor& linear1_weight,
const MetaTensor& linear1_bias,
const MetaTensor& linear2_weight,
const MetaTensor& linear2_bias,
const MetaTensor& ln1_scale,
const MetaTensor& ln1_bias,
const MetaTensor& ln2_scale,
const MetaTensor& ln2_bias,
bool pre_layer_norm,
float ln1_epsilon,
float ln2_epsilon,
const std::string& act_method,
float dropout1_prob,
float dropout2_prob,
const std::string& dropout1_implementation,
const std::string& dropout2_implementation,
bool is_test,
bool dropout1_fix_seed,
bool dropout2_fix_seed,
int dropout1_seed_val,
int dropout2_seed_val,
bool add_residual,
int ring_id,
MetaTensor* out,
MetaTensor* dropout1_mask,
MetaTensor* dropout2_mask,
MetaTensor* ln1_mean,
MetaTensor* ln1_variance,
MetaTensor* ln2_mean,
MetaTensor* ln2_variance,
MetaTensor* linear1_out,
MetaTensor* ln1_out,
MetaTensor* dropout1_out,
MetaTensor* dropout2_out) {
auto dim_x = x.dims();
auto RowMatrixFromVector = [](const DDim& x_dim) -> DDim {
if (x_dim.size() > 1) {
return x_dim;
}
return make_ddim({1, x_dim[0]});
};
auto mat_dim_x =
funcs::CreateMatrixDescriptor(RowMatrixFromVector(dim_x), 0, false);
// verify for the pre layer_norm, the feature size must be larger than 1
PADDLE_ENFORCE_GT(
mat_dim_x.width_,
static_cast<size_t>(1),
common::errors::InvalidArgument("Product from the X shape[1] to "
"shape[n-1] must be larger than 1!"));
auto dim_Linear1Weight = linear1_weight.dims();
auto tmp_dim_x = dim_x;
tmp_dim_x[dim_x.size() - 1] = dim_Linear1Weight[dim_Linear1Weight.size() - 1];
out->set_dims(dim_x);
if (!is_test) {
dropout1_mask->set_dims(tmp_dim_x);
}
dropout1_out->set_dims(tmp_dim_x);
linear1_out->set_dims(tmp_dim_x);
dropout2_out->set_dims(dim_x);
if (!is_test) {
dropout2_mask->set_dims(dim_x);
}
auto mean_dim = make_ddim({mat_dim_x.batch_size_ * mat_dim_x.height_});
if (pre_layer_norm) {
ln1_out->set_dims(dim_x);
ln1_mean->set_dims(mean_dim);
ln1_variance->set_dims(mean_dim);
} else {
ln2_mean->set_dims(mean_dim);
ln2_variance->set_dims(mean_dim);
}
out->share_lod(x);
out->set_dtype(x.dtype());
}
static bool IsUnaryCompound(const std::vector<std::string>& functor_list) {
PADDLE_ENFORCE_EQ(
functor_list.size(),
2,
common::errors::InvalidArgument(
"Invalid functor list size %d, which should be equal to %d.",
functor_list.size(),
2));
static std::unordered_set<std::string> binary_fun = {"elementwise_add",
"elementwise_mul",
"elementwise_add_grad",
"elementwise_mul_grad"};
return binary_fun.count(functor_list[1]) != 0;
}
static bool InputXCanBeAbsent(const std::vector<std::string>& functor_list) {
PADDLE_ENFORCE_EQ(
functor_list.size(),
2,
common::errors::InvalidArgument(
"Invalid functor list size %d, which should be equal to %d.",
functor_list.size(),
2));
static std::unordered_set<std::string> binary_fun = {"elementwise_add_grad"};
return binary_fun.count(functor_list[0]) != 0 ||
binary_fun.count(functor_list[1]) != 0;
}
static bool IsBcastY(const DDim& x_dim, const DDim& y_dim) {
bool bcast_y = x_dim.size() >= y_dim.size();
if (x_dim.size() == y_dim.size()) {
for (int i = 0; i < x_dim.size(); ++i) {
if (x_dim[i] < y_dim[i]) {
bcast_y = false;
break;
}
}
}
return bcast_y;
}
void FusedElemwiseAddActivationInferMeta(
const MetaTensor& x,
const MetaTensor& y,
const std::vector<std::string>& functor_list,
float scale,
int axis,
bool save_intermediate_out,
MetaTensor* out,
MetaTensor* intermediate_out) {
PADDLE_ENFORCE_NOT_NULL(
x,
errors::NotFound(
"Input(X) of FusedElemwiseAddActivationOp op should not be null."));
PADDLE_ENFORCE_NOT_NULL(
y,
errors::NotFound(
"Input(Y) of FusedElemwiseAddActivationOp op should not be null."));
PADDLE_ENFORCE_NOT_NULL(out,
common::errors::InvalidArgument(
"Output(Out) of FusedElemwiseAddActivationOp op "
"should not be null."));
auto x_dim = x.dims();
auto y_dim = y.dims();
// Whether the shape of Y is a continuous subsequence of X,
// For more information please refer to the op's introduction.
bool bcast_y = IsBcastY(x_dim, y_dim);
auto out_dim = bcast_y ? x_dim : y_dim;
auto out_lod = bcast_y ? x : y;
auto out_dtype = bcast_y ? x.dtype() : y.dtype();
PADDLE_ENFORCE_NOT_NULL(
intermediate_out,
errors::NotFound(
"Output(IntermediateOut) of FusedElemwiseAddActivationOp "
"should not be null."));
if (IsUnaryCompound(functor_list)) {
// for Unary(Binary(X, Y)), the shape and lod of out and
// intermediate_out are the same.
intermediate_out->set_dims(out_dim);
// set the lod of intermediate_out
intermediate_out->share_lod(out_lod);
} else {
// for Binary(X, Unary(Y)), the shape and lod of Y and
// intermediate_out are the same.
intermediate_out->set_dims(y_dim);
// set the lod of intermediate_out
intermediate_out->share_lod(y);
}
out->set_dims(out_dim);
out->share_lod(out_lod);
out->set_dtype(out_dtype);
bool elemntwise_add_detected = false;
for (auto names : functor_list) {
if (names == "elementwise_add") {
elemntwise_add_detected = true;
break;
}
}
PADDLE_ENFORCE_EQ(
elemntwise_add_detected,
true,
common::errors::InvalidArgument(
"When the FusedElemwiseAddActivationOp Is used in fused pass, the "
"elementwise_add Op must be "
"detected and used, Please check the fuse pass pattern"));
}
void FusedElemwiseAddActivationGradInferMeta(
const MetaTensor& x,
const MetaTensor& y,
const MetaTensor& out,
const MetaTensor& intermediate_out,
const MetaTensor& out_grad,
const std::vector<std::string>& functor_list,
float scale,
int axis,
bool save_intermediate_out,
MetaTensor* x_grad,
MetaTensor* y_grad) {
PADDLE_ENFORCE_NOT_NULL(
out_grad,
common::errors::InvalidArgument("Input(Out@GRAD) should not be null."));
if (save_intermediate_out) {
PADDLE_ENFORCE_NOT_NULL(intermediate_out,
common::errors::InvalidArgument(
"Input(IntermediateOut) should not be null."));
} else {
if (!InputXCanBeAbsent(functor_list)) {
PADDLE_ENFORCE_NOT_NULL(
x, common::errors::InvalidArgument("Input(X) should not be null."));
}
}
if (x_grad) {
if (x) {
x_grad->set_dtype(x.dtype());
x_grad->set_dims(x.dims());
x_grad->share_lod(x);
} else {
// Currently, only when Binary is elementwise_add or elementwise_sub,
// the "X" could be absent.
PADDLE_ENFORCE_EQ(
InputXCanBeAbsent(functor_list),
true,
common::errors::InvalidArgument(
"Only when BinaryFunctor is elementwise_add, the 'X' "
"could be absent."));
// Node: If "X" is absence, the shape of Y should be a continuous
// subsequence of X, otherwise, we could not infer the shape of dx.
x_grad->set_dtype(out.dtype());
x_grad->set_dims(out_grad.dims());
x_grad->share_lod(out_grad);
}
}
if (y_grad) {
PADDLE_ENFORCE_NOT_NULL(
y, common::errors::InvalidArgument("Input(Y) should not be null."));
y_grad->set_dims(y.dims());
y_grad->share_lod(y);
y_grad->set_dtype(y.dtype());
}
// if (intermediate_out_grad) {
// // For Unary(Binary(X, Y)), IntermediateOut should not be empty.
// if (IsUnaryCompound(functor_list)) {
// intermediate_out_grad->set_dims(out_grad.dims());
// intermediate_out_grad->share_lod(out_grad);
// } else {
// intermediate_out_grad->set_dims(y.dims());
// intermediate_out_grad->share_lod(y);
// }
// }
bool elemntwise_add_grad_detected = false;
for (auto names : functor_list) {
if (names == "elementwise_add_grad") {
elemntwise_add_grad_detected = true;
break;
}
}
PADDLE_ENFORCE_EQ(
elemntwise_add_grad_detected,
true,
common::errors::InvalidArgument(
"When the FusedElemwiseAddActivationOpGrad Is used in fused pass, "
"the elementwise_add_grad Op must be "
"detected and used, Please check the fuse pass pattern"));
}
void FusedFeedForwardGradInferMeta(const MetaTensor& out_grad,
const MetaTensor& x,
const MetaTensor& linear1_weight,
const MetaTensor& linear1_bias,
const MetaTensor& linear2_weight,
const MetaTensor& dropout1_mask,
const MetaTensor& dropout2_mask,
const MetaTensor& linear1_out,
const MetaTensor& dropout1_out,
const MetaTensor& dropout2_out,
const MetaTensor& ln1_scale,
const MetaTensor& ln1_bias,
const MetaTensor& ln1_out,
const MetaTensor& ln1_mean,
const MetaTensor& ln1_variance,
const MetaTensor& ln2_scale,
const MetaTensor& ln2_bias,
const MetaTensor& ln2_mean,
const MetaTensor& ln2_variance,
const MetaTensor& linear2_bias,
bool pre_layer_norm,
float ln1_epsilon,
float ln2_epsilon,
const std::string& act_method,
float dropout1_prob,
float dropout2_prob,
const std::string& dropout1_implementation,
const std::string& dropout2_implementation,
bool is_test,
bool dropout1_fix_seed,
bool dropout2_fix_seed,
int dropout1_seed_val,
int dropout2_seed_val,
bool add_residual,
int ring_id,
MetaTensor* x_grad,
MetaTensor* linear1_weight_grad,
MetaTensor* linear1_bias_grad,
MetaTensor* linear2_weight_grad,
MetaTensor* linear2_bias_grad,
MetaTensor* ln1_scale_grad,
MetaTensor* ln1_bias_grad,
MetaTensor* ln2_scale_grad,
MetaTensor* ln2_bias_grad) {
x_grad->set_dims(out_grad.dims());
if (ln1_scale_grad && ln1_scale) {
ln1_scale_grad->set_dims(ln1_scale.dims());
}
if (ln1_bias_grad && ln1_bias) {
ln1_bias_grad->set_dims(ln1_bias.dims());
}
if (ln2_scale_grad && ln2_scale) {
ln2_scale_grad->set_dims(ln2_scale.dims());
}
if (ln2_bias_grad && ln2_bias) {
ln2_bias_grad->set_dims(ln2_bias.dims());
}
linear1_weight_grad->set_dims(linear1_weight.dims());
if (linear1_bias_grad && linear1_bias) {
linear1_bias_grad->set_dims(linear1_bias.dims());
}
linear2_weight_grad->set_dims(linear2_weight.dims());
if (linear2_bias_grad && linear2_bias) {
linear2_bias_grad->set_dims(linear2_bias.dims());
}
}
void GenerateSequenceXPUInferMeta(const MetaTensor& x,
DataType dtype,
MetaTensor* out) {
out->set_dims(x.dims());
out->set_dtype(dtype);
out->set_layout(x.layout());
}
void MultiEncoderXPUInferMeta(
const MetaTensor& x,
const std::vector<const MetaTensor*>& fc_input_max,
const std::vector<const MetaTensor*>& fc_weight,
const std::vector<const MetaTensor*>& fc_weight_max,
const std::vector<const MetaTensor*>& fc_bias,
const std::vector<const MetaTensor*>& ln_scale,
const std::vector<const MetaTensor*>& ln_bias,
const std::vector<const MetaTensor*>& smooth_scale_weight,
const std::vector<const MetaTensor*>& roformer_embedding,
const MetaTensor& mask,
const MetaTensor& seq_lod,
const MetaTensor& max_seq_len,
int layer_num,
bool norm_before,
int hidden_dim,
int head_num,
int size_per_head,
int ffn_hidden_dim_scale,
int act_type,
int relative_type,
int slice_idx,
bool is_per_channel,
int max_pos_len,
const std::vector<float>& softmax_max_value,
const std::vector<std::string>& quant_types,
MetaTensor* out,
MetaTensor* x_fp16,
MetaTensor* out_fp16) {
auto x_dims = x.dims();
x_fp16->set_dims(x_dims);
x_fp16->set_dtype(DataType::FLOAT16);
x_fp16->set_layout(x.layout());
out->set_dtype(x.dtype());
out->set_layout(x.layout());
out_fp16->set_dtype(DataType::FLOAT16);
out_fp16->set_layout(x.layout());
if (slice_idx == -1) {
out->set_dims(x_dims);
out_fp16->set_dims(x_dims);
} else {
out->set_dims({x_dims[0], x_dims[2]});
out_fp16->set_dims({x_dims[0], x_dims[2]});
}
}
void FusedGemmEpilogueInferMeta(const MetaTensor& x,
const MetaTensor& y,
const MetaTensor& bias,
bool trans_x,
bool trans_y,
const std::string& activation,
MetaTensor* out,
MetaTensor* reserve_space,
MetaConfig config) {
const auto& x_dims = x.dims();
const auto& y_dims = y.dims();
const auto& bias_dims = bias.dims();
PADDLE_ENFORCE_EQ(y_dims.size(),
2,
common::errors::InvalidArgument(
"The Input tensor Y's dimension of FusedGemmEpilogueOp "
" should be 2, but got %d.",
y_dims.size()));
PADDLE_ENFORCE_GE(x_dims.size(),
2,
common::errors::InvalidArgument(
"The Input tensor X's dimension of FusedGemmEpilogueOp "
" should be >= 2, but got %d.",
x_dims.size()));
PADDLE_ENFORCE_EQ(
bias_dims.size(),
1,
common::errors::InvalidArgument(
"The Input tensor bias's dimension of FusedGemmEpilogueOp "
" should be == 1, but got %d.",
bias_dims.size()));
PADDLE_ENFORCE_EQ(bias_dims[0],
trans_y ? y_dims[0] : y_dims[1],
common::errors::InvalidArgument(
"The Input tensor bias's dimension 0"
" should be == Y[-1], but got bias's shape = [%s] "
"and Y's shape = [%s]",
bias_dims,
y_dims));
auto x_mat_dims = flatten_to_2d(x_dims, trans_x ? 1 : x_dims.size() - 1);
auto x_rank = x_dims.size();
int64_t K_from_x = trans_x ? x_dims[x_rank - 2] : x_mat_dims[1];
int64_t K_from_y = trans_y ? y_dims[1] : y_dims[0];
bool check_dim = (!config.is_runtime && K_from_x != -1) || config.is_runtime;
if (check_dim) {
PADDLE_ENFORCE_EQ(
K_from_x,
K_from_y,
common::errors::InvalidArgument(
"The last dimension of X should be equal with Y's first dimension."
"But received X[-1] = [%d], Y[0] = [%d].",
K_from_x,
K_from_y));
}
std::vector<int64_t> out_dims;
out_dims.reserve(x_rank);
for (int i = 0; i + 2 < x_rank; ++i) {
out_dims.push_back(x_dims[i]);
}
out_dims.push_back(trans_x ? x_dims[x_rank - 1] : x_dims[x_rank - 2]);
if (trans_y) {
out_dims.push_back(y_dims[0]);
} else {
out_dims.push_back(y_dims[1]);
}
out->set_dims(make_ddim(out_dims));
out->set_dtype(x.dtype());
if (reserve_space) {
reserve_space->set_dims(make_ddim(out_dims));
reserve_space->set_dtype(x.dtype());
if (activation == "none") {
PADDLE_THROW(common::errors::InvalidArgument(
"The ReserveSpace would not be used when activation = \"none\""));
} else {
int min_size_of_n = activation == "relu" ? 128 : 8;
int64_t N_size = trans_y ? y_dims[0] : y_dims[1];
PADDLE_ENFORCE_EQ(N_size % min_size_of_n,
0,
common::errors::InvalidArgument(
"The output dimension N (X(MxK) * Y(KxN) = C(MxN)) "
"should be multiple of %d when auxiliary_key given "
"and activation=%s, but got N = %d.",
min_size_of_n,
activation,
N_size));
}
}
}
void FusedGemmEpilogueGradInferMeta(const MetaTensor& x,
const MetaTensor& y,
const MetaTensor& reserve_space,
const MetaTensor& out_grad,
bool trans_x,
bool trans_y,
const std::string& activation_grad,
MetaTensor* x_grad,
MetaTensor* y_grad,
MetaTensor* bias_grad) {
auto x_dims = x.dims();
auto y_dims = y.dims();
auto dout_dims = out_grad.dims();
PADDLE_ENFORCE_GE(
dout_dims.size(),
2,
common::errors::InvalidArgument(
"The Input tensor DOut's dimension of FusedGemmEpilogueGradOp "
" should be >= 2, but got %d.",
dout_dims.size()));
PADDLE_ENFORCE_EQ(
y_dims.size(),
2,
common::errors::InvalidArgument(
"The Input tensor Y's dimension of FusedGemmEpilogueGradOp "
" should be 2, but got %d.",
y_dims.size()));
PADDLE_ENFORCE_GE(
x_dims.size(),
2,
common::errors::InvalidArgument(
"The Input tensor X's dimension of FusedGemmEpilogueGradOp "
" should be >= 2, but got %d.",
x_dims.size()));
PADDLE_ENFORCE_EQ(
dout_dims.size(),
x_dims.size(),
common::errors::InvalidArgument(
"The Input tensor DOut's and X's dimension of "
"FusedGemmEpilogueGradOp "
" should be the same, but got DOut's dim = %d and X's = %d.",
dout_dims.size(),
x_dims.size()));
auto dout_mat_dims = flatten_to_2d(dout_dims, dout_dims.size() - 1);
PADDLE_ENFORCE_EQ(
dout_mat_dims[1],
trans_y ? y_dims[0] : y_dims[1],
common::errors::InvalidArgument(
"The last dimension of DOut should be equal with Y's last "
"dimension. But received DOut[-1] = [%d], Y[1] = [%d].",
dout_mat_dims[1],
y_dims[1]));
for (int32_t i = 0; i + 2 < x_dims.size(); ++i) {
if (dout_dims[i] > 0 && x_dims[i] > 0) {
PADDLE_ENFORCE_EQ(
dout_dims[i],
x_dims[i],
common::errors::InvalidArgument(
"The i dimension of DOut should be equal with i dimension of X."
"But received DOut[%d] = [%d], Y[%d] = [%d].",
i,
dout_dims[i],
i,
x_dims[i]));
}
}
auto k_from_dout = dout_dims[x_dims.size() - 2];
auto k_from_x =
trans_x ? x_dims[x_dims.size() - 1] : x_dims[x_dims.size() - 2];
bool check_k = (k_from_dout < 0 || k_from_x < 0) || (k_from_dout == k_from_x);
PADDLE_ENFORCE_EQ(
check_k,
true,
common::errors::InvalidArgument(
"K from dout and x is not same, k_from_dout is [%d], k_from_x is[%d]",
k_from_dout,
k_from_x));
if (activation_grad != "none" && !reserve_space) {
PADDLE_THROW(common::errors::InvalidArgument(
"The ReserveSpace should not be empty. "
"when activation == {relu_grad, gelu_grad}."));
}
if (x_grad) {
x_grad->set_dims(x_dims);
x_grad->set_dtype(x.dtype());
}
if (y_grad) {
y_grad->set_dims(y_dims);
y_grad->set_dtype(y.dtype());
}
if (bias_grad) {
int64_t dbias_dim = trans_y ? y_dims[0] : y_dims[1];
bias_grad->set_dims(make_ddim({dbias_dim}));
bias_grad->set_dtype(y.dtype());
}
}
void FusedMultiTransformerXpuInferMeta(
const MetaTensor& x,
const std::vector<const MetaTensor*>& ln_scale,
const std::vector<const MetaTensor*>& ln_bias,
const std::vector<const MetaTensor*>& qkvw,
const std::vector<const MetaTensor*>& qkvw_max,
const std::vector<const MetaTensor*>& qkv_bias,
const std::vector<const MetaTensor*>& out_linear_w,
const std::vector<const MetaTensor*>& out_linear_wmax,
const std::vector<const MetaTensor*>& out_linear_bias,
const std::vector<const MetaTensor*>& ffn_ln_scale,
const std::vector<const MetaTensor*>& ffn_ln_bias,
const std::vector<const MetaTensor*>& ffn1_weight,
const std::vector<const MetaTensor*>& ffn1_weight_max,
const std::vector<const MetaTensor*>& ffn1_bias,
const std::vector<const MetaTensor*>& ffn2_weight,
const std::vector<const MetaTensor*>& ffn2_weight_max,
const std::vector<const MetaTensor*>& ffn2_bias,
const std::vector<const MetaTensor*>& cache_kv,
const std::vector<const MetaTensor*>& pre_caches,
const MetaTensor& rotary_pos_emb,
const MetaTensor& time_step,
const MetaTensor& seq_lengths,
const MetaTensor& src_mask,
const MetaTensor& gather_index,
const MetaTensor& max_buffer,
bool pre_layer_norm,
int rotary_emb_dims,
float epsilon,
float dropout_rate,
bool is_test,
const std::string& dropout_implementation,
const std::string& act_method,
bool trans_qkvw,
int ring_id,
int gather_axis,
MetaTensor* out,
std::vector<MetaTensor*> cache_kv_out) {
auto x_dim = x.dims();
auto y_dim = qkvw[0]->dims();
PADDLE_ENFORCE_EQ(x_dim.size(),
3,
common::errors::InvalidArgument(
"The dimensions of x must be 3(batch_size, seq_len, "
"dim_embed), but received dimensions of Input is [%d]",
x_dim.size()));
PADDLE_ENFORCE_EQ(
y_dim.size(),
4,
common::errors::InvalidArgument(
"The dimensions of qkv_weight must be 4(3, num_head, dim_head, "
"dim_embed), but received dimensions of qkv_weight is [%d]",
y_dim.size()));
PADDLE_ENFORCE_EQ(
x_dim[2],
trans_qkvw ? y_dim[3] : y_dim[0],
common::errors::InvalidArgument(
"The dimension of x_dim[2] and y_dim[3](trans_qkvw is true) or "
"y_dim[0](trans_qkvw is false) must be equal, but received: the "
"shape of input x = [%s], and the shape of input qkv_weight = [%s]",
x_dim,
y_dim));
if (!cache_kv.empty()) {
const auto& c_dim = cache_kv[0]->dims();
PADDLE_ENFORCE_EQ(
c_dim.size(),
5,
common::errors::InvalidArgument(
"The CacheKV must be 5 dims, but got %d", c_dim.size()));
PADDLE_ENFORCE_EQ(c_dim[0],
2,
common::errors::InvalidArgument(
"The first dim of CacheKV must be 2, but got %d",
c_dim[0])); // 2
PADDLE_ENFORCE_EQ(c_dim[3],
trans_qkvw ? y_dim[1] : y_dim[2],
common::errors::InvalidArgument(
"The fourth dim of CacheKV must be equal "
"with num head %d, but got %d",
trans_qkvw ? y_dim[1] : y_dim[2],
c_dim[3])); // num_head
PADDLE_ENFORCE_EQ(c_dim[4],
trans_qkvw ? y_dim[2] : y_dim[3],
common::errors::InvalidArgument(
"The fifth dim of CacheKV must be equal "
"with head size %d, but got %d",
trans_qkvw ? y_dim[2] : y_dim[3],
c_dim[4])); // head_size
}
out->set_dims(x_dim);
out->set_dtype(x.dtype());
out->set_layout(x.layout());
}
void FusedMultiTransformerInt8XpuInferMeta(
const MetaTensor& x,
const std::vector<const MetaTensor*>& ln_scale,
const std::vector<const MetaTensor*>& ln_bias,
const std::vector<const MetaTensor*>& qkv_in_max,
const std::vector<const MetaTensor*>& qkvw,
const std::vector<const MetaTensor*>& qkv_bias,
const std::vector<const MetaTensor*>& qkv_scales,
const std::vector<const MetaTensor*>& out_linear_in_max,
const std::vector<const MetaTensor*>& out_linear_w,
const std::vector<const MetaTensor*>& out_linear_bias,
const std::vector<const MetaTensor*>& out_linear_scales,
const std::vector<const MetaTensor*>& ffn_ln_scale,
const std::vector<const MetaTensor*>& ffn_ln_bias,
const std::vector<const MetaTensor*>& ffn1_in_max,
const std::vector<const MetaTensor*>& ffn1_weight,
const std::vector<const MetaTensor*>& ffn1_bias,
const std::vector<const MetaTensor*>& ffn1_scales,
const std::vector<const MetaTensor*>& ffn2_in_max,
const std::vector<const MetaTensor*>& ffn2_weight,
const std::vector<const MetaTensor*>& ffn2_bias,
const std::vector<const MetaTensor*>& ffn2_scales,
const std::vector<const MetaTensor*>& cache_kv,
const std::vector<const MetaTensor*>& pre_caches,
const MetaTensor& rotary_pos_emb,
const MetaTensor& time_step,
const MetaTensor& seq_lengths,
const MetaTensor& src_mask,
const MetaTensor& gather_index,
const MetaTensor& max_buffer,
bool pre_layer_norm,
int rotary_emb_dims,
float epsilon,
float dropout_rate,
bool is_test,
const std::string& dropout_implementation,
const std::string& act_method,
bool trans_qkvw,
int ring_id,
int gather_axis,
MetaTensor* out,
std::vector<MetaTensor*> cache_kv_out) {
auto x_dim = x.dims();
auto y_dim = qkvw[0]->dims();
PADDLE_ENFORCE_EQ(x_dim.size(),
3,
common::errors::InvalidArgument(
"The dimensions of x must be 3(batch_size, seq_len, "
"dim_embed), but received dimensions of Input is [%d]",
x_dim.size()));
PADDLE_ENFORCE_EQ(
y_dim.size(),
4,
common::errors::InvalidArgument(
"The dimensions of qkv_weight must be 4(3, num_head, dim_head, "
"dim_embed), but received dimensions of qkv_weight is [%d]",
y_dim.size()));
PADDLE_ENFORCE_EQ(
x_dim[2],
trans_qkvw ? y_dim[3] : y_dim[0],
common::errors::InvalidArgument(
"The dimension of x_dim[2] and y_dim[3](trans_qkvw is true) or "
"y_dim[0](trans_qkvw is false) must be equal, but received: the "
"shape of input x = [%s], and the shape of input qkv_weight = [%s]",
x_dim,
y_dim));
if (!cache_kv.empty()) {
const auto& c_dim = cache_kv[0]->dims();
PADDLE_ENFORCE_EQ(
c_dim.size(),
5,
common::errors::InvalidArgument(
"The CacheKV must be 5 dims, but got %d", c_dim.size()));
PADDLE_ENFORCE_EQ(c_dim[0],
2,
common::errors::InvalidArgument(
"The first dim of CacheKV must be 2, but got %d",
c_dim[0])); // 2
PADDLE_ENFORCE_EQ(c_dim[3],
trans_qkvw ? y_dim[1] : y_dim[2],
common::errors::InvalidArgument(
"The fourth dim of CacheKV must be equal "
"with num head %d, but got %d",
trans_qkvw ? y_dim[1] : y_dim[2],
c_dim[3])); // num_head
PADDLE_ENFORCE_EQ(c_dim[4],
trans_qkvw ? y_dim[2] : y_dim[3],
common::errors::InvalidArgument(
"The fifth dim of CacheKV must be equal "
"with head size %d, but got %d",
trans_qkvw ? y_dim[2] : y_dim[3],
c_dim[4])); // head_size
}
out->set_dims(x_dim);
out->set_dtype(x.dtype());
out->set_layout(x.layout());
}
void FusedMultiTransformerInt8InferMeta(
const MetaTensor& x,
const std::vector<const MetaTensor*>& ln_scale,
const std::vector<const MetaTensor*>& ln_bias,
const std::vector<const MetaTensor*>& qkv_w,
const paddle::optional<std::vector<const MetaTensor*>>& qkv_bias,
const paddle::optional<std::vector<const MetaTensor*>>& cache_kv,
const MetaTensor& time_step,
const MetaTensor& src_mask,
const std::vector<const MetaTensor*>& out_linear_w,
const paddle::optional<std::vector<const MetaTensor*>>& out_linear_bias,
const std::vector<const MetaTensor*>& ffn_ln_scale,
const std::vector<const MetaTensor*>& ffn_ln_bias,
const std::vector<const MetaTensor*>& ffn1_weight,
const paddle::optional<std::vector<const MetaTensor*>>& ffn1_bias,
const std::vector<const MetaTensor*>& ffn2_weight,
const paddle::optional<std::vector<const MetaTensor*>>& ffn2_bias,
const paddle::optional<std::vector<const MetaTensor*>>& qkv_out_scale,
const paddle::optional<std::vector<const MetaTensor*>>&
out_linear_out_scale,
const paddle::optional<std::vector<const MetaTensor*>>& ffn1_out_scale,
const paddle::optional<std::vector<const MetaTensor*>>& ffn2_out_scale,
bool pre_layer_norm,
float epsilon,
float dropout_rate,
bool is_test,
const std::string& dropout_implementation,
const std::string& act_method,
bool trans_qkvw,
int ring_id,
int num_head,
int dim_head,
int dim_ffn,
const std::vector<float>& qkv_in_scale,
const std::vector<float>& out_linear_in_scale,
const std::vector<float>& ffn1_in_scale,
const std::vector<float>& ffn2_in_scale,
int quant_round_type,
float quant_max_bound,
float quant_min_bound,
std::vector<MetaTensor*> cache_kv_out,
MetaTensor* out) {
// x: qkv's input [batch_size, seq_len, dim_embed]
// y: qkv's weight: [3, num_head, dim_head, dim_embed]
const auto& x_dim = x.dims();
const auto& y_dim = qkv_w[0]->dims();
PADDLE_ENFORCE_EQ(
x_dim.size(),
3,
common::errors::InvalidArgument("The dimensions of x must be 3"
"(batch_size, seq_len, dim_embed), "
"but received dimensions of "
"Input is [%d]",
x_dim.size()));
PADDLE_ENFORCE_EQ(
y_dim.size(),
4,
common::errors::InvalidArgument("The dimensions of qkv_weight must be 4"
"(3, num_head, dim_head, dim_embed), "
"but received dimensions of "
"Input is [%d]",
y_dim.size()));
PADDLE_ENFORCE_EQ(
x_dim[2],
trans_qkvw ? y_dim[3] : y_dim[0],
common::errors::InvalidArgument(
"ShapeError: the dimension of x_dim[2] and y_dim[3](trans_qkvw is "
"true) or y_dim[0](trans_qkvw is false)"
"must be equal. But received: the shape "
"of input x = [%s], and the shape of "
"input qkv_weight = [%s]",
x_dim,
y_dim));
if (ring_id == -1) {
if (trans_qkvw) {
PADDLE_ENFORCE_EQ(y_dim[1] * y_dim[2],
y_dim[3],
common::errors::InvalidArgument(
"The dimensions of qkv_weight must be 4"
"(3, num_head, dim_head, dim_embed),"
"and must satisfy the limitations: "
"(num_head * dim_head == dim_embed)"));
} else {
PADDLE_ENFORCE_EQ(y_dim[2] * y_dim[3],
y_dim[0],
common::errors::InvalidArgument(
"The dimensions of qkv_weight must be 4"
"(dim_embed, 3, num_head, dim_head),"
"and must satisfy the limitations: "
"(num_head * dim_head == dim_embed)"));
}
}
if (cache_kv && cache_kv.get().size() > 0) {
// [2, batch_size, num_head, max_seq_len, head_size]
const auto& c_dim = cache_kv.get()[0]->dims();
PADDLE_ENFORCE_EQ(
c_dim.size(),
5,
common::errors::InvalidArgument(
"The CacheKV must be 5 dims, but got %d", c_dim.size()));
PADDLE_ENFORCE_EQ(c_dim[0],
2,
common::errors::InvalidArgument(
"The first dim of CacheKV must be 2, but got %d",
c_dim[0])); // 2
PADDLE_ENFORCE_EQ(c_dim[1],
x_dim[0],
common::errors::InvalidArgument(
"The second dim of CacheKV must be equal with "
"batch size %d, but got %d",
x_dim[0],
c_dim[1])); // batch_size
PADDLE_ENFORCE_EQ(c_dim[2],
trans_qkvw ? y_dim[1] : y_dim[2],
common::errors::InvalidArgument(
"The third dim of CacheKV must be equal with num "
"head %d, but got %d",
trans_qkvw ? y_dim[1] : y_dim[2],
c_dim[2])); // num_head
PADDLE_ENFORCE_GT(
c_dim[3],
0,
common::errors::InvalidArgument(
"The forth dim of CacheKV must be greater than 0, but got %d",
c_dim[3])); // cache_seq_len
PADDLE_ENFORCE_EQ(c_dim[4],
trans_qkvw ? y_dim[2] : y_dim[3],
common::errors::InvalidArgument(
"The fifth dim of CacheKV must be equal with head "
"size %d, but got %d",
trans_qkvw ? y_dim[2] : y_dim[3],
c_dim[4])); // head_size
}
out->set_dims(x.dims());
out->set_dtype(x.dtype());
}
void FusedPartialRopeInferMeta(const MetaTensor& x,
const MetaTensor& cos,
const MetaTensor& sin,
MetaTensor* out) {
const auto x_dims = x.dims();
PADDLE_ENFORCE_EQ(
x_dims.size(),
4,
common::errors::InvalidArgument("The input x must be a 4D tensor"));
const int64_t batch_size = x_dims[0];
const int64_t seq_len = x_dims[1];
const int64_t num_heads = x_dims[2];
const int64_t head_dim = x_dims[3];
PADDLE_ENFORCE_LE(
batch_size * seq_len * num_heads,
std::numeric_limits<int>::max(),
common::errors::InvalidArgument("Currently only supports batch_size * "
"seq_len * num_heads <= INT_MAX"));
PADDLE_ENFORCE_LE(head_dim,
std::numeric_limits<int>::max(),
common::errors::InvalidArgument(
"Currently only supports head_dim <= INT_MAX"));
const auto cos_dims = cos.dims();
PADDLE_ENFORCE_EQ(
cos_dims.size(),
4,
common::errors::InvalidArgument("The input cos must be a 4D tensor"));
PADDLE_ENFORCE_EQ(
cos_dims[0],
1,
common::errors::InvalidArgument("The batch_size of cos must be 1"));
PADDLE_ENFORCE_EQ(
cos_dims[1],
seq_len,
common::errors::InvalidArgument("The seq_len of cos must match x"));
PADDLE_ENFORCE_EQ(
cos_dims[2],
1,
common::errors::InvalidArgument("The num_heads of cos must be 1"));
const int64_t pe_head_dim = cos_dims[3];
PADDLE_ENFORCE_LE(pe_head_dim,
head_dim,
common::errors::InvalidArgument(
"pe_head_dim must be no larger than head_dim"));
PADDLE_ENFORCE_EQ(
pe_head_dim % 2,
0,
common::errors::InvalidArgument("pe_head_dim must be multiple of 2"));
PADDLE_ENFORCE_LE(pe_head_dim,
1024,
common::errors::InvalidArgument(
"Currently only supports pe_head_dim <= 1024"));
const auto sin_dims = sin.dims();
PADDLE_ENFORCE_EQ(
sin_dims.size(),
4,
common::errors::InvalidArgument("The input sin must be a 4D tensor"));
PADDLE_ENFORCE_EQ(
sin_dims[0],
1,
common::errors::InvalidArgument("The batch_size of sin must be 1"));
PADDLE_ENFORCE_EQ(
sin_dims[1],
seq_len,
common::errors::InvalidArgument("The seq_len of sin must match x"));
PADDLE_ENFORCE_EQ(
sin_dims[2],
1,
common::errors::InvalidArgument("The num_heads of sin must be 1"));
PADDLE_ENFORCE_EQ(
sin_dims[3],
pe_head_dim,
common::errors::InvalidArgument("The pe_head_dim of sin must match cos"));
out->set_dims(x.dims());
out->set_dtype(x.dtype());
}
void FusedTransposeSplitQuantInferMeta(const MetaTensor& x,
const MetaTensor& input_scales,
const IntArray& tokens_per_expert,
bool pow_2_scales,
std::vector<MetaTensor*> outs,
std::vector<MetaTensor*> scales) {
PADDLE_ENFORCE_EQ(
x.dtype() == DataType::BFLOAT16 || x.dtype() == DataType::FLOAT8_E4M3FN,
true,
common::errors::InvalidArgument("The dtype of Input(x) must be BFLOAT16 "
"or FLOAT8_E4M3FN, but received %s",
x.dtype()));
auto x_dims = x.dims();
PADDLE_ENFORCE_EQ(x_dims.size(),
2,
common::errors::InvalidArgument(
"The dimensions of Input(x) must be 2, but "
"received dimensions of "
"Input(x) is [%d]",
x_dims.size()));
const int64_t M = x_dims[0];
const int64_t N = x_dims[1];
auto tokens_list = tokens_per_expert.GetData();
const size_t num_experts = tokens_list.size();
PADDLE_ENFORCE_GT(
num_experts,
0,
common::errors::InvalidArgument("tokens_per_expert cannot be empty"));
PADDLE_ENFORCE_EQ(
outs.size(),
num_experts,
common::errors::InvalidArgument(
"Size of outs (%d) must equal size of tokens_per_expert (%d)",
outs.size(),
num_experts));
PADDLE_ENFORCE_EQ(
scales.size(),
num_experts,
common::errors::InvalidArgument(
"Size of scales (%d) must equal size of tokens_per_expert (%d)",
scales.size(),
num_experts));
int64_t sum_tokens = 0;
for (size_t i = 0; i < num_experts; ++i) {
const int64_t tokens = tokens_list[i];
PADDLE_ENFORCE_EQ(
tokens % 128,
0,
common::errors::InvalidArgument(
"tokens_per_expert[%d] (%d) must be divisible by 128", i, tokens));
sum_tokens += tokens;
if (outs[i] != nullptr) {
outs[i]->set_dims(make_ddim({N, tokens}));
outs[i]->set_dtype(DataType::FLOAT8_E4M3FN);
outs[i]->set_layout(x.layout());
}
if (scales[i] != nullptr) {
scales[i]->set_dims(make_ddim({tokens / 128, N}));
scales[i]->set_dtype(DataType::FLOAT32);
scales[i]->set_layout(x.layout());
}
}
PADDLE_ENFORCE_EQ(
sum_tokens,
M,
common::errors::InvalidArgument(
"Sum of tokens_per_expert (%d) must equal x.shape[0] (%d)",
sum_tokens,
M));
PADDLE_ENFORCE_LE(N,
65535LL * 128,
common::errors::InvalidArgument(
"x.shape[1] (%d) must be <= 65535 * 128", N));
}
void FusedTransposeWLCHSplitQuantInferMeta(const MetaTensor& x,
const IntArray& tokens_per_expert,
bool pow_2_scales,
std::vector<MetaTensor*> outs,
std::vector<MetaTensor*> scales) {
PADDLE_ENFORCE_EQ(
x.dtype(),
DataType::BFLOAT16,
common::errors::InvalidArgument(
"The dtype of Input(x) must be BFLOAT16, but received %s",
x.dtype()));
auto x_dims = x.dims();
PADDLE_ENFORCE_EQ(
x_dims.size(),
4,
common::errors::InvalidArgument(
"Input(x) must have dimension of 4, but got %d.", x_dims.size()));
const int64_t M = x_dims[0] * x_dims[1] * x_dims[2];
const int64_t H = x_dims[3];
auto tokens_list = tokens_per_expert.GetData();
const size_t num_experts = tokens_list.size();
PADDLE_ENFORCE_EQ(
outs.size(),
num_experts,
common::errors::InvalidArgument(
"Size of outs (%d) must equal size of tokens_per_expert (%d)",
outs.size(),
num_experts));
PADDLE_ENFORCE_EQ(
scales.size(),
num_experts,
common::errors::InvalidArgument(
"Size of scales (%d) must equal size of tokens_per_expert (%d)",
scales.size(),
num_experts));
int64_t sum_tokens = 0;
for (size_t i = 0; i < num_experts; ++i) {
const int64_t tokens = tokens_list[i];
PADDLE_ENFORCE_EQ(
tokens % 128,
0,
common::errors::InvalidArgument(
"tokens_per_expert[%d] (%d) must be divisible by 128", i, tokens));
sum_tokens += tokens;
if (outs[i] != nullptr) {
outs[i]->set_dims(make_ddim({H, tokens}));
outs[i]->set_dtype(DataType::FLOAT8_E4M3FN);
outs[i]->set_layout(x.layout());
}
if (scales[i] != nullptr) {
scales[i]->set_dims(make_ddim({tokens / 128, H}));
scales[i]->set_dtype(DataType::FLOAT32);
scales[i]->set_layout(x.layout());
}
}
PADDLE_ENFORCE_EQ(
sum_tokens,
M,
common::errors::InvalidArgument("Sum of tokens_per_expert (%d) must "
"equal the upper dims of Input(x) (%d)",
sum_tokens,
M));
PADDLE_ENFORCE_LE(
H,
65535 * 128,
common::errors::InvalidArgument("Currently only supports the hidden size "
"of Input(x) <= 65535 * 128, but got %d.",
H));
}
void YoloBoxXPUInferMeta(const MetaTensor& x,
const MetaTensor& x_max,
const MetaTensor& grid,
const MetaTensor& stride,
const MetaTensor& anchor_grid,
float offset,
MetaTensor* out,
MetaTensor* out_max) {
auto x_dims = x.dims();
auto x_dims_size = x_dims.size();
PADDLE_ENFORCE_GT(
x_dims[x_dims_size - 1],
4,
common::errors::InvalidArgument(
"The last dim of x should be larger than 4, but received "
" is %d.",
x_dims[x_dims_size - 1]));
// compute left out_dims
// y[..., 0:2] = (x[..., 0:2] * 2 + self.grid[i]) * self.stride[i] # xy
std::vector<int> axes_ = {x_dims_size - 1};
std::vector<int> infer_flags_ = {1};
std::vector<int> decrease_axis_ = {-1};
std::vector<int64_t> strides_ = {1};
std::vector<int64_t> starts_l = {0};
std::vector<int64_t> ends_l = {2};
std::vector<int64_t> left_slice_out_dims_vector(x_dims_size, -1);
funcs::StridedSliceOutDims(starts_l,
ends_l,
strides_,
axes_,
infer_flags_,
x_dims,
decrease_axis_,
left_slice_out_dims_vector.data(),
1,
true);
auto left_slice_out_dims = make_ddim(left_slice_out_dims_vector);
auto grid_dims = grid.dims();
auto left_add_out_dims =
BroadCastInferShape(left_slice_out_dims, grid_dims, -1);
auto stride_dims = stride.dims();
auto left_mul_out_dims =
BroadCastInferShape(left_add_out_dims, stride_dims, -1);
// compute mid out_dims
// wh = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i] # wh
std::vector<int64_t> starts_m = {2};
std::vector<int64_t> ends_m = {4};
std::vector<int64_t> mid_slice_out_dims_vector(x_dims_size, -1);
funcs::StridedSliceOutDims(starts_m,
ends_m,
strides_,
axes_,
infer_flags_,
x_dims,
decrease_axis_,
mid_slice_out_dims_vector.data(),
1,
true);
auto mid_slice_out_dims = make_ddim(mid_slice_out_dims_vector);
auto anchor_grid_dims = anchor_grid.dims();
auto mid_mul_out_dims =
BroadCastInferShape(mid_slice_out_dims, anchor_grid_dims, -1);
// compute right out_dims
std::vector<int64_t> starts_r = {4};
std::vector<int64_t> ends_r = {2147483647};
std::vector<int64_t> right_slice_out_dims_vector(x_dims_size, -1);
funcs::StridedSliceOutDims(starts_r,
ends_r,
strides_,
axes_,
infer_flags_,
x_dims,
decrease_axis_,
right_slice_out_dims_vector.data(),
1,
true);
auto right_slice_out_dims = make_ddim(right_slice_out_dims_vector);
// compute concat out_dims
std::vector<DDim> in_dims;
in_dims.reserve(3);
in_dims.emplace_back(left_mul_out_dims);
in_dims.emplace_back(mid_mul_out_dims);
in_dims.emplace_back(right_slice_out_dims);
DDim out_dim = funcs::ComputeAndCheckShape(false, in_dims, x_dims_size - 1);
out->set_dims(out_dim);
out->set_dtype(x.dtype());
out->set_layout(x.layout());
out_max->set_dims(make_ddim({6}));
out_max->set_dtype(x.dtype());
out_max->set_layout(x.layout());
}
void ConvTransposeXPUInferMeta(const MetaTensor& x,
const MetaTensor& filter,
const std::vector<int>& strides,
const std::vector<int>& paddings,
const std::vector<int>& output_padding,
const std::vector<int>& output_size,
const std::string& padding_algorithm,
int groups,
const std::vector<int>& dilations,
const std::string& data_format,
MetaTensor* out,
MetaTensor* out_max) {
auto x_dims = x.dims();
auto filter_dims = filter.dims();
std::vector<int> paddings_ = paddings;
std::vector<int> dilations_ = dilations;
PADDLE_ENFORCE_EQ(
x_dims.size() == 4,
true,
errors::InvalidArgument("Input of Op(conv_transpose) should be 4-D "
"Tensor. But received: %u-D Tensor, "
"the shape of input is [%s]",
x_dims.size(),
x_dims));
PADDLE_ENFORCE_EQ(
x_dims.size(),
filter_dims.size(),
errors::InvalidArgument(
"The input's dimension size and filter's dimension size of "
"Op (conv_transpose) should be equal. But received: the shape of "
"input is [%s], the dimension size of input is [%d], the shape "
"of filter is [%s], the dimension size of filter is [%d]. ",
x_dims,
x_dims.size(),
filter_dims,
filter_dims.size()));
int stride_size = static_cast<int>(strides.size());
for (int i = 0; i < stride_size; ++i) {
PADDLE_ENFORCE_GT(
strides[i],
0,
errors::InvalidArgument(
"The stride of Op(Conv) should be larger than 0, but received "
"stride is %d.",
strides[i]));
}
int in_sub_stride_size = x_dims.size() - stride_size;
PADDLE_ENFORCE_EQ(
x_dims.size() - strides.size(),
2U,
errors::InvalidArgument(
"The input's dimension size minus Attr(stride)'s size must "
"be equal to 2 for Op(conv_transpose). But received: [%d], the "
"input's dimension size is [%d], the shape of input "
"is [%s], the Attr(stride)'s size is [%d].",
in_sub_stride_size,
x_dims.size(),
x_dims,
strides.size()));
if (!output_size.empty())
PADDLE_ENFORCE_EQ(
output_size.size(),
strides.size(),
errors::InvalidArgument(
"The Attr(output_size) and Attr(stride) of Op(conv_transpose) "
"should be the same."));
if (!output_padding.empty())
PADDLE_ENFORCE_EQ(
output_padding.size(),
strides.size(),
errors::InvalidArgument(
"The Attr(output_padding) and Attr(stride) of Op(conv_transpose) "
"should be the same."));
const int64_t C =
(data_format != "NHWC" ? x_dims[1] : x_dims[x_dims.size() - 1]);
PADDLE_ENFORCE_EQ(
C,
filter_dims[0],
errors::InvalidArgument(
"The number of input channels should be equal to filter channels "
"for Op(conv_transpose). But received: the input's channels is "
"[%d], the shape of input is [%s], the filter's channels is [%d], "
"the shape of filter is [%s]. The data_format is %s."
"The error may come from wrong data_format setting.",
C,
x_dims,
filter_dims[0],
filter_dims,
data_format));
DDim x_data_dims;
if (data_format != "NHWC") {
x_data_dims = slice_ddim(x_dims, 2, x_dims.size());
} else {
x_data_dims = slice_ddim(x_dims, 1, x_dims.size() - 1);
}
DDim filter_data_dims = slice_ddim(filter_dims, 2, filter_dims.size());
std::vector<int> ksize = vectorize<int>(filter_data_dims);
UpdatePaddingAndDilation(
&paddings_, &dilations_, padding_algorithm, x_data_dims, strides, ksize);
std::vector<int64_t> output_shape({x_dims[0]});
if (data_format != "NHWC") {
output_shape.push_back(filter_dims[1] * groups);
}
const int offset = (data_format != "NHWC" ? 2 : 1);
for (int i = 0; i < static_cast<int>(strides.size()); ++i) {
auto filter_extent = dilations_[i] * (filter_dims[i + 2] - 1) + 1;
auto infer_shape = (x_dims[i + offset] > 0)
? (x_dims[i + offset] - 1) * strides[i] -
paddings_[2 * i] - paddings_[2 * i + 1] +
filter_extent
: -1;
if (!output_size.empty()) {
output_shape.push_back(output_size[i]);
} else if (!output_padding.empty()) {
output_shape.push_back((infer_shape + output_padding[i]));
} else {
output_shape.push_back(infer_shape);
}
}
if (data_format == "NHWC") {
output_shape.push_back(filter_dims[1] * groups);
}
out->set_dims(make_ddim(output_shape));
out->set_dtype(x.dtype());
out_max->set_dims(make_ddim({6}));
}
void Conv2dTransposeXPUInferMeta(const MetaTensor& x,
const MetaTensor& x_max,
const MetaTensor& filter,
const MetaTensor& filter_max,
const MetaTensor& bias,
const std::vector<int>& strides,
const std::vector<int>& paddings,
const std::vector<int>& output_padding,
const IntArray& output_size,
const std::string& padding_algorithm,
int groups,
const std::vector<int>& dilations,
const std::string& data_format,
bool has_bias,
bool with_act,
const std::string& act_type,
MetaTensor* out,
MetaTensor* out_max) {
std::vector<int32_t> vec_output_size(output_size.GetData().begin(),
output_size.GetData().end());
ConvTransposeXPUInferMeta(x,
filter,
strides,
paddings,
output_padding,
vec_output_size,
padding_algorithm,
groups,
dilations,
data_format,
out,
out_max);
}
void FastWhereXPUInferMeta(const MetaTensor& condition,
const MetaTensor& x,
const MetaTensor& y,
MetaTensor* out) {
out->set_dims(x.dims());
out->set_dtype(x.dtype());
}
void FastLayernormXPUInferMeta(const MetaTensor& x,
const MetaTensor& scale,
const MetaTensor& bias,
int begin_norm_axis,
float epsilon,
MetaTensor* out) {
out->set_dims(x.dims());
out->set_dtype(x.dtype());
out->set_layout(x.layout());
}
void BNActXPUInferMeta(const MetaTensor& x,
const MetaTensor& mean,
const MetaTensor& variance,
const MetaTensor& scale,
const MetaTensor& bias,
float momentum,
float epsilon,
const std::string& data_layout,
int act_type,
MetaTensor* y,
MetaConfig config) {
const auto x_dims = x.dims();
for (int i = 0; i < x_dims.size(); i++) {
PADDLE_ENFORCE_EQ(
(x_dims[i] == -1) || (x_dims[i] > 0),
true,
common::errors::InvalidArgument(
"Each dimension of input tensor is expected to be -1 or a "
"positive number, but received %d. Input's shape is [%s].",
x_dims[i],
x_dims));
}
const DataLayout data_layout_str = StringToDataLayout(data_layout);
PADDLE_ENFORCE_GE(
x_dims.size(),
2,
common::errors::InvalidArgument(
"ShapeError: the dimension of input "
"X must greater than or equal to 2. But received: the shape of input "
"X = [%s], the dimension of input X =[%d]",
x_dims,
x_dims.size()));
PADDLE_ENFORCE_LE(
x_dims.size(),
5,
common::errors::InvalidArgument(
"ShapeError: the dimension of input X "
"must smaller than or equal to 5. But received: the shape of input X "
"= [%s], the dimension of input X = [%d]",
x_dims,
x_dims.size()));
const int64_t C = ((config.is_run_onednn_kernel == true) ||
(data_layout_str == DataLayout::NCHW)
? x_dims[1]
: x_dims[x_dims.size() - 1]);
auto scale_dim = scale.dims();
auto bias_dim = bias.dims();
PADDLE_ENFORCE_EQ(
scale_dim.size(),
1UL,
common::errors::InvalidArgument(
"ShapeError: the dimension of scale must equal to 1."
"But received: the shape of scale is [%s], the dimension "
"of scale is [%d]",
scale_dim,
scale_dim.size()));
PADDLE_ENFORCE_EQ(bias_dim.size(),
1UL,
common::errors::InvalidArgument(
"ShapeError: the dimension of bias must equal to 1."
"But received: the shape of bias is [%s],the dimension "
"of bias is [%d]",
bias_dim,
bias_dim.size()));
bool check = true;
if ((!config.is_runtime) &&
(contain_unknown_dim(scale_dim) || contain_unknown_dim(bias_dim))) {
check = false;
}
if (check) {
PADDLE_ENFORCE_EQ(scale_dim[0],
C,
common::errors::InvalidArgument(
"ShapeError: the shape of scale must equal to [%d]"
"But received: the shape of scale is [%d]",
C,
scale_dim[0]));
PADDLE_ENFORCE_EQ(bias_dim[0],
C,
common::errors::InvalidArgument(
"ShapeError: the shape of bias must equal to [%d]"
"But received: the shape of bias is [%d]",
C,
bias_dim[0]));
}
y->set_dims(x_dims);
y->share_lod(x);
y->set_dtype(x.dtype());
}
void AddCMulXPUInferMeta(const MetaTensor& x,
const MetaTensor& y,
const MetaTensor& w,
MetaTensor* out) {
out->set_dims(x.dims());
out->set_dtype(x.dtype());
out->set_layout(x.layout());
}
void LayerNormActXPUInferMeta(const MetaTensor& x,
const MetaTensor& scale,
const MetaTensor& bias,
int begin_norm_axis,
float epsilon,
int act_type,
float act_param,
MetaTensor* y) {
y->set_dims(x.dims());
// y->share_lod(x);
y->set_dtype(x.dtype());
y->set_layout(x.layout());
}
void FusedScaleBiasReluConvBnInferMeta(const MetaTensor& x,
const MetaTensor& w,
const MetaTensor& scale,
const MetaTensor& bias,
const MetaTensor& bn_scale,
const MetaTensor& bn_bias,
const MetaTensor& input_running_mean,
const MetaTensor& input_running_var,
const std::vector<int>& paddings,
const std::vector<int>& dilations,
const std::vector<int>& strides,
const std::string& padding_algorithm,
int groups,
const std::string& data_format,
float momentum,
float epsilon,
bool fuse_prologue,
bool exhaustive_search,
int64_t accumulation_count,
MetaTensor* out,
MetaTensor* out_running_mean,
MetaTensor* out_running_var,
MetaTensor* saved_mean,
MetaTensor* saved_var,
MetaTensor* eq_scale,
MetaTensor* eq_bias) {
auto in_dims = x.dims();
auto filter_dims = w.dims();
// do some checks
PADDLE_ENFORCE_EQ(
in_dims.size(),
4,
common::errors::InvalidArgument(
"The input of Op(FusedScaleBiasReluConvBn) should be a 4-D "
"Tensor. But "
"received: input's dimension is %u, input's shape is [%s].",
in_dims.size(),
in_dims));
PADDLE_ENFORCE_EQ(
in_dims.size(),
filter_dims.size(),
common::errors::InvalidArgument(
"The input's dimension and filter's dimension of "
"Op(FusedScaleBiasReluConvBn) should be equal. But received: "
"the input's"
" shape is [%s], "
"the input's dimension is %d; the filter's shape is [%s], "
"the filter's dimension is %d.",
in_dims,
in_dims.size(),
filter_dims,
filter_dims.size()));
// Check if data format is NHWC
PADDLE_ENFORCE_EQ(
data_format,
"NHWC",
common::errors::InvalidArgument(
"Operator(FusedScaleBiasReluConvBn) only supports data format "
"of "
"channel last (NHWC) now. But received: data_format = '%s'.",
data_format));
PADDLE_ENFORCE_EQ(
groups,
1,
common::errors::InvalidArgument("Expect group to be 1, got %d.", groups));
const auto input_channels = in_dims[in_dims.size() - 1];
int dilation_size = static_cast<int>(dilations.size());
for (int i = 0; i < dilation_size; ++i) {
PADDLE_ENFORCE_GT(
dilations[i],
0,
common::errors::InvalidArgument(
"The dilation of Op(Conv) should be larger than 0, but received "
"dilation is %d.",
dilations[i]));
}
PADDLE_ENFORCE_EQ(
input_channels,
filter_dims[1] * groups,
common::errors::InvalidArgument(
"The number of input's channels should be equal to filter's channels "
"* groups for Op(FusedScaleBiasReluConvBn). But received: the "
"input's"
" channels is %d, "
"the input's shape is [%s]; the filter's channels is %d, the "
"filter's shape is [%s]; the groups is %d. ",
input_channels,
in_dims,
filter_dims[1],
filter_dims,
groups));
// update paddings and dilations according to padding_algorithm
std::vector<int> paddings_vec = paddings;
std::vector<int> dilations_vec = dilations;
// get "HW" from "NHWC"
DDim in_data_dims = slice_ddim(in_dims, 1, in_dims.size() - 1);
DDim filter_data_dims = slice_ddim(filter_dims, 2, filter_dims.size());
std::vector<int> ksize = vectorize<int>(filter_data_dims);
phi::UpdatePaddingAndDilation(&paddings_vec,
&dilations_vec,
padding_algorithm,
in_data_dims,
strides,
ksize);
std::vector<int64_t> out_shape({in_dims[0]});
for (int i = 0; i < static_cast<int>(strides.size()); ++i) {
out_shape.push_back(ConvOutSize(in_dims[i + 1],
filter_dims[i + 2],
dilations[i],
paddings_vec[i * 2],
paddings_vec[i * 2 + 1],
strides[i]));
}
out_shape.push_back(filter_dims[0]);
// make shape for other outputs
auto c_dims = make_ddim({filter_dims[0]});
// set output and output max dims
out->set_dims(DDim(out_shape.data(), static_cast<int>(out_shape.size())));
out_running_mean->set_dims(c_dims);
out_running_var->set_dims(c_dims);
saved_mean->set_dims(c_dims);
saved_var->set_dims(c_dims);
eq_scale->set_dims(c_dims);
eq_bias->set_dims(c_dims);
}
void FusedScaleBiasAddReluInferMeta(const MetaTensor& x1,
const MetaTensor& scale1,
const MetaTensor& bias1,
const MetaTensor& x2,
const MetaTensor& scale2,
const MetaTensor& bias2,
bool fuse_dual,
bool exhaustive_search,
MetaTensor* out) {
// check optional inputs
if (fuse_dual) {
bool has_scale2 = !!scale2;
bool has_bias2 = !!bias2;
PADDLE_ENFORCE(has_scale2 && has_bias2,
common::errors::InvalidArgument(
"Argument scale2 and bias2 should be provided when "
"fuse_dual is set, but got has_scale2=%d, has_bias2=%d, "
"fuse_dual=%d.",
has_scale2,
has_bias2,
fuse_dual));
}
// set output dims
out->set_dims(x1.dims());
out->set_dtype(x1.dtype());
out->set_layout(x1.layout());
}
void FusedDconvDreluDbnInferMeta(const MetaTensor& grad_output,
const MetaTensor& weight,
const MetaTensor& grad_output_add,
const MetaTensor& residual_input,
const MetaTensor& bn1_eqscale,
const MetaTensor& bn1_eqbias,
const MetaTensor& conv_input,
const MetaTensor& bn1_mean,
const MetaTensor& bn1_inv_std,
const MetaTensor& bn1_gamma,
const MetaTensor& bn1_beta,
const MetaTensor& bn1_input,
const MetaTensor& bn2_mean,
const MetaTensor& bn2_inv_std,
const MetaTensor& bn2_gamma,
const MetaTensor& bn2_beta,
const MetaTensor& bn2_input,
const std::vector<int>& paddings,
const std::vector<int>& dilations,
const std::vector<int>& strides,
const std::string& padding_algorithm,
int groups,
const std::string& data_format,
bool fuse_shortcut,
bool fuse_dual,
bool fuse_add,
bool exhaustive_search,
MetaTensor* grad_weight,
MetaTensor* grad_bn1_input,
MetaTensor* grad_bn1_gamma,
MetaTensor* grad_bn1_beta,
MetaTensor* grad_bn2_input,
MetaTensor* grad_bn2_gamma,
MetaTensor* grad_bn2_beta) {
// Check if data format is NHWC
PADDLE_ENFORCE_EQ(
data_format,
"NHWC",
common::errors::InvalidArgument(
"Operator(FusedScaleBiasReluConvBnstats) only supports data format "
"of "
"channel last (NHWC) now. But received: data_format = '%s'.",
data_format));
PADDLE_ENFORCE_EQ(
groups,
1,
common::errors::InvalidArgument("Expect group to be 1, got %d.", groups));
PADDLE_ENFORCE_EQ(
fuse_shortcut && fuse_dual,
0,
common::errors::InvalidArgument(
"fuse_shortcut and fuse_dual should not be set at the same time."
"Got fuse_shortcut=%d, fuse_dual=%d.",
fuse_shortcut,
fuse_dual));
if (fuse_add) {
PADDLE_ENFORCE_EQ(
!!grad_output_add,
true,
common::errors::InvalidArgument(
"grad_output_add must be provided when fuse_add = true."
"Got fuse_add=%d, grad_output_add=%d.",
fuse_add,
!!grad_output_add));
}
if (fuse_shortcut) {
PADDLE_ENFORCE_EQ(
!!residual_input,
true,
common::errors::InvalidArgument(
"residual_input must be provided when fuse_shortcut = true."
"Got fuse_shortcut =%d, residual_input=%d.",
fuse_shortcut,
!!residual_input));
}
if (fuse_shortcut || fuse_dual) {
PADDLE_ENFORCE_EQ(
!!conv_input,
true,
common::errors::InvalidArgument(
"conv_input must be provided when either fuse_shortcut "
"or fuse_dual is set to true. Got conv_input=%d, fuse_shortcut=%d, "
"fuse_dual=%d.",
!!conv_input,
fuse_shortcut,
fuse_dual));
} else {
PADDLE_ENFORCE_EQ(
bn1_eqscale && bn1_eqbias,
true,
common::errors::InvalidArgument(
"bn1_eqscale and bn1_eqbias must be provided when neither "
"fuse_shortcut "
"or fuse_dual is set. Got bn1_eqscale=%d, bn1_eqbias=%d.",
!!bn1_eqscale,
!!bn1_eqbias));
}
if (fuse_dual) {
PADDLE_ENFORCE_EQ(
bn2_mean && bn2_inv_std && bn2_gamma && bn2_beta && bn2_input,
true,
common::errors::InvalidArgument(
"bn2_mean, bn2_inv_std, bn2_gamma, "
"bn2_beta, bn2_input must be provided "
"when fuse_dual is set. Got bn2_mean=%d, "
"bn2_inv_std=%d, bn2_gamma=%d, "
"bn2_beta=%d, bn2_input=%d.",
!!bn2_mean,
!!bn2_inv_std,
!!bn2_gamma,
!!bn2_beta,
!!bn2_input));
}
auto set_unchanged_meta = [](MetaTensor* out, const MetaTensor& input) {
out->set_dims(input.dims());
out->set_dtype(input.dtype());
out->set_layout(input.layout());
};
set_unchanged_meta(grad_weight, weight);
set_unchanged_meta(grad_bn1_input, bn1_input);
set_unchanged_meta(grad_bn1_gamma, bn1_gamma);
set_unchanged_meta(grad_bn1_beta, bn1_beta);
if (grad_bn2_input) {
set_unchanged_meta(grad_bn2_input, bn1_input);
}
if (grad_bn2_gamma) {
set_unchanged_meta(grad_bn2_gamma, bn1_gamma);
}
if (grad_bn2_beta) {
set_unchanged_meta(grad_bn2_beta, bn1_beta);
}
}
void SqueezeExcitationInferMeta(const MetaTensor& x,
const MetaTensor& filter,
const MetaTensor& filter_max,
const MetaTensor& bias,
const MetaTensor& branch,
const std::vector<int>& act_type,
const std::vector<float>& act_param,
const std::vector<int>& filter_dims,
MetaTensor* out) {
auto in_dims = x.dims();
// do some checks
PADDLE_ENFORCE_EQ(
in_dims.size(),
4,
common::errors::InvalidArgument(
"The input should be a 4-D Tensor. But "
"received: input's dimension is %u, input's shape is [%s].",
in_dims.size(),
in_dims));
std::vector<int64_t> out_shape(
{in_dims[0], filter_dims[1], in_dims[2], in_dims[3]});
// set output dims
out->set_dims(DDim(out_shape.data(), static_cast<int>(out_shape.size())));
}
void FusedEmbeddingEltWiseLayerNormInferMeta(
const std::vector<const MetaTensor*>& ids,
const std::vector<const MetaTensor*>& embs,
const MetaTensor& bias,
const MetaTensor& scale,
const float epsilon,
MetaTensor* out) {
PADDLE_ENFORCE_EQ(
ids.size(),
embs.size(),
common::errors::InvalidArgument(
"Two inputs of EmbeddingEltWiseLayerNormOp shoube be "
"the same size, but received the size of input Ids = %d,"
" the size of input Embs = %d",
ids.size(),
embs.size()));
PADDLE_ENFORCE_GE(embs.size(),
2UL,
common::errors::InvalidArgument(
"Input Embs of EmbeddingEltWiseLayerNormOp should "
"have at least 2 tensors"));
PADDLE_ENFORCE_GE(ids.size(),
2UL,
common::errors::InvalidArgument(
"Input Ids of EmbeddingEltWiseLayerNormOp should "
"have at least 2 tensors"));
// batch * seq_len * 1
std::vector<DDim> ids_dims, embs_dims;
ids_dims.reserve(ids.size());
std::transform(ids.begin(),
ids.end(),
std::back_inserter(ids_dims),
[](const MetaTensor* var) { return var->dims(); });
// word_num * hidden
embs_dims.reserve(embs.size());
std::transform(embs.begin(),
embs.end(),
std::back_inserter(embs_dims),
[](const MetaTensor* var) { return var->dims(); });
// hidden
DDim dims_bias = bias.dims();
int64_t batch = ids_dims[0][0];
int64_t seq_len = ids_dims[0][1];
int64_t hidden = embs_dims[0][1];
for (auto& embs_dim : embs_dims) {
PADDLE_ENFORCE_EQ(
embs_dim.size(),
2,
common::errors::InvalidArgument(
"The Emb dim's size should be 2, but found %d.", embs_dim.size()));
PADDLE_ENFORCE_EQ(
embs_dim[1],
dims_bias[0],
common::errors::InvalidArgument(
"The second dims (%d) of the Embedding should be equal "
"to the Bias's size(%d).",
embs_dim[1],
dims_bias[0]));
PADDLE_ENFORCE_EQ(
embs_dim[1],
hidden,
common::errors::InvalidArgument(
"The second dimension size(%d) of the Embedding should be "
"equal to the hidden's size(%d)",
embs_dim[1],
hidden));
}
auto dim_output = make_ddim({batch, seq_len, hidden});
out->set_dims(dim_output);
out->share_lod(*ids[0]);
out->set_dtype((*embs[0]).dtype());
}
void FusionTransposeFlattenConcatInferMeta(
const std::vector<const MetaTensor*>& x,
const std::vector<int>& trans_axis,
const int flatten_axis,
const int concat_axis,
MetaTensor* out) {
PADDLE_ENFORCE_GE(
x.size(),
1UL,
common::errors::InvalidArgument(
"Inputs(X) of TransposeFlattenConcat op should not be empty."));
std::vector<DDim> ins;
ins.reserve(x.size());
std::transform(
x.begin(), x.end(), std::back_inserter(ins), [](const MetaTensor* var) {
return var->dims();
});
const size_t n = ins.size();
PADDLE_ENFORCE_GT(n,
0,
common::errors::InvalidArgument(
"The size of Inputs(X)'s dimension should be greater "
" than 0, but received %d.",
n));
size_t x_rank = ins[0].size();
size_t trans_axis_size = trans_axis.size();
PADDLE_ENFORCE_EQ(x_rank,
trans_axis_size,
common::errors::InvalidArgument(
"The input tensor's rank(%d) "
"should be equal to the permutation axis's size(%d)",
x_rank,
trans_axis_size));
auto dims0 = funcs::GetFlattenShape(
flatten_axis, funcs::GetPermuteShape(trans_axis, ins[0]));
std::vector<int> out_dims(dims0);
for (size_t i = 1; i < n; i++) {
auto dimsi = funcs::GetFlattenShape(
flatten_axis, funcs::GetPermuteShape(trans_axis, ins[i]));
for (int j = 0; j < static_cast<int>(dims0.size()); j++) {
if (j == concat_axis) {
out_dims[concat_axis] += dimsi[j];
} else {
PADDLE_ENFORCE_EQ(out_dims[j],
dimsi[j],
common::errors::InvalidArgument(
"After flatting, the %d-th dim should be save "
"except the specify axis.",
j));
}
}
}
if (out_dims[concat_axis] < 0) {
out_dims[concat_axis] = -1;
}
out->set_dims(make_ddim(out_dims));
out->set_dtype((*x[0]).dtype());
}
void FusedFCElementwiseLayerNormInferMeta(const MetaTensor& x,
const MetaTensor& w,
const MetaTensor& y,
const MetaTensor& bias0,
const MetaTensor& scale,
const MetaTensor& bias1,
const int x_num_col_dims,
const std::string& activation_type,
const float epsilon,
const int begin_norm_axis,
MetaTensor* out,
MetaTensor* mean,
MetaTensor* variance,
MetaConfig config) {
DDim w_dims = w.dims();
PADDLE_ENFORCE_EQ(
w_dims.size(),
2,
common::errors::InvalidArgument(
"The input Weight of fc is expected to be a 2-D tensor. "
"But received the number of Weight's dimensions is %d, "
"Weight's shape is %s.",
w_dims.size(),
w_dims));
if (bias0) {
DDim bias0_dims = bias0.dims();
PADDLE_ENFORCE_LE(bias0_dims.size(),
2,
common::errors::InvalidArgument(
"The input Bias of fc is expected to be an 1-D or "
"2-D tensor. But received the number of Bias's "
"dimensions is %d, Bias's shape is %s.",
bias0_dims.size(),
bias0_dims));
PADDLE_ENFORCE_EQ(
bias0_dims[bias0_dims.size() - 1],
w_dims[1],
common::errors::InvalidArgument(
"The last dimension of input Bias is expected be equal "
"to the actual width of input Weight. But received the last "
"dimension of Bias is %d, Bias's shape is %s; "
"the actual width of Weight is %d, Weight's shape is %s.",
bias0_dims[bias0_dims.size() - 1],
bias0_dims,
w_dims[1],
w_dims));
if (bias0_dims.size() == 2) {
PADDLE_ENFORCE_EQ(
bias0_dims[0],
1,
common::errors::InvalidArgument(
"The first dimension of input Bias is expected to be 1, "
"but received %d, Bias's shape is %s.",
bias0_dims[0],
bias0_dims));
}
}
DDim x_dims = x.dims();
PADDLE_ENFORCE_LT(
x_num_col_dims,
x_dims.size(),
common::errors::InvalidArgument(
"The attribute x_num_col_dims used to flatten input X to "
"a 2-D tensor, is expected to be less than the number of "
"input X's dimensions. But received x_num_col_dims is %d, "
"the number of input X's dimensions is %d, input X's shape is %s.",
x_num_col_dims,
x_dims.size(),
x_dims));
auto x_mat_dims = flatten_to_2d(x_dims, x_num_col_dims);
PADDLE_ENFORCE_EQ(
x_mat_dims[1],
w_dims[0],
common::errors::InvalidArgument(
"The input's second dimension and weight's first dimension is "
"expected to be the same. But received input's second dimension is "
"%d, input's shape is %s; weight's first dimension is %d, weight's "
"shape is %s.",
x_mat_dims[1],
x_mat_dims,
w_dims[0],
w_dims));
std::vector<int64_t> fc_out_dims;
for (int i = 0; i < x_num_col_dims; ++i) {
fc_out_dims.push_back(x_dims[i]);
}
fc_out_dims.push_back(w_dims[1]);
DDim y_dims = y.dims();
PADDLE_ENFORCE_EQ(make_ddim(fc_out_dims),
y_dims,
common::errors::InvalidArgument(
"The output's shape of fc is expected to be equal to "
"that of input Y. But received output's shape of fc "
"is %s, input Y's shape is %s.",
make_ddim(fc_out_dims),
y_dims));
PADDLE_ENFORCE_LT(
begin_norm_axis,
y_dims.size(),
common::errors::InvalidArgument(
"The attribute begin_norm_axis used to flatten input Y to a 2-D "
"tensor, is expected to be less than the number of input Y's "
"dimensions. But received begin_norm_axis is %d, the number of "
"input Y's dimensions is %d, input Y's shape is %s.",
begin_norm_axis,
y_dims.size(),
y_dims));
auto y_mat_dim = flatten_to_2d(y_dims, begin_norm_axis);
int64_t dim_0 = y_mat_dim[0];
int64_t dim_1 = y_mat_dim[1];
if (scale) {
DDim scale_dims = scale.dims();
PADDLE_ENFORCE_EQ(scale_dims.size(),
1,
common::errors::InvalidArgument(
"The input Scale is expected to be an 1-D tensor. "
"But received the number of input Scale's "
"dimensions is %d, input Scale's shape is %s.",
scale_dims.size(),
scale_dims));
if (config.is_runtime) {
PADDLE_ENFORCE_EQ(
scale_dims[0],
dim_1,
common::errors::InvalidArgument(
"The first dimension of input Scale is expected to be equal to "
"the second dimension of input Y after flattened. "
"But received the first dimension of input Scale is %d, input "
"Scale's shape is %s; the second dimension of flattened input "
"Y is %d, input Y's shape is %s, flattened axis is %d.",
scale_dims[0],
scale_dims,
dim_1,
y_dims,
begin_norm_axis));
}
}
if (bias1) {
DDim bias1_dims = bias1.dims();
PADDLE_ENFORCE_EQ(
bias1_dims.size(),
1,
common::errors::InvalidArgument(
"The input Bias1 is expected to be an 1-D tensor. "
"But received the number of input Bias1's dimension is %d, "
"input Bias1's shape is %s.",
bias1_dims.size(),
bias1_dims));
if (config.is_runtime) {
PADDLE_ENFORCE_EQ(
bias1_dims[0],
dim_1,
common::errors::InvalidArgument(
"The first dimension of input Bias1 is expected to be equal to "
"the second dimension of input Y after flattened. "
"But received the first dimension of input Bias1 is %d, input "
"Bias1's shape is %s; the second dimension of flatten input "
"Y is %d, input Y's shape is %s, flattened axis is %d.",
bias1_dims[0],
bias1_dims,
dim_1,
y_dims,
begin_norm_axis));
}
}
out->set_dims(y_dims);
out->set_dtype(x.dtype());
if (mean) {
mean->set_dtype(x.dtype());
mean->set_dims({dim_0});
}
if (variance) {
variance->set_dims({dim_0});
variance->set_dtype(x.dtype());
}
out->share_lod(x);
}
void FusedConv2dAddActInferMeta(const MetaTensor& input,
const MetaTensor& filter,
const MetaTensor& bias,
const MetaTensor& residual_data,
const std::vector<int>& strides,
const std::vector<int>& paddings,
const std::string& padding_algorithm,
const std::vector<int>& dilations,
int groups,
const std::string& data_format,
const std::string& activation,
const std::vector<int>& split_channels,
MetaTensor* output,
std::vector<MetaTensor*> outputs,
MetaConfig config) {
// TODO(liuyuanle): onednn seems only support nchw.
const bool channel_last = (data_format == "NHWC" || data_format == "NDHWC");
std::vector<int64_t> out_shape = ComputeOutputShape(input,
filter,
bias,
strides,
paddings,
padding_algorithm,
dilations,
groups,
data_format,
channel_last,
config);
output->set_dims(make_ddim(out_shape));
output->set_dtype(input.dtype());
if (data_format == "NHWC") {
output->set_layout(DataLayout::NHWC);
} else if (data_format == "NDHWC") {
output->set_layout(DataLayout::NDHWC);
}
output->share_lod(input);
if (split_channels.size()) {
PADDLE_ENFORCE_EQ(
outputs.size(),
split_channels.size(),
common::errors::InvalidArgument(
"The number of Output(Outputs) of operator 'fused_conv2d_add_act' "
"is "
"expected to be equal to the length of Attr(split_channels). But "
"received: the number of Output(Outputs) = %u; the length of "
"Attr(split_channels) = %u, the content = [%s].",
outputs.size(),
split_channels.size(),
make_ddim(split_channels)));
int64_t split_channels_sum = 0;
std::vector<DDim> output_shapes(split_channels.size());
for (size_t i = 0; i < split_channels.size(); ++i) {
split_channels_sum += split_channels[i];
if (channel_last) {
output_shapes[i] = make_ddim(
{out_shape[0], out_shape[1], out_shape[2], split_channels[i]});
} else {
output_shapes[i] = make_ddim(
{out_shape[0], split_channels[i], out_shape[2], out_shape[3]});
}
}
int64_t output_channels = out_shape[1];
// for NHWC
if (channel_last) output_channels = out_shape[3];
PADDLE_ENFORCE_EQ(
split_channels_sum,
output_channels,
common::errors::InvalidArgument(
"The sum of Attr(split_channels) is expected to be equal to "
"the "
"total output split_channels. But received: the sum of "
"Attr(split_channels) = %d, the total output split_channels = %d.",
split_channels_sum,
output_channels));
for (size_t i = 0; i < outputs.size(); ++i) {
if (outputs[i]) {
outputs[i]->set_dims(output_shapes[i]);
outputs[i]->set_dtype(input.dtype());
if (data_format == "NHWC") {
outputs[i]->set_layout(DataLayout::NHWC);
} else if (data_format == "NDHWC") {
outputs[i]->set_layout(DataLayout::NDHWC);
}
outputs[i]->share_lod(input);
}
}
}
}
void FusionRepeatedFCReluInferMeta(const MetaTensor& x,
const std::vector<const MetaTensor*>& w,
const std::vector<const MetaTensor*>& bias,
std::vector<MetaTensor*> relu_out,
MetaTensor* out) {
auto sz = w.size();
PADDLE_ENFORCE_GT(sz,
1UL,
common::errors::InvalidArgument(
"Inputs(W) of FusionRepeatedFCReluOp should "
"be greater than 1, but received value is %d.",
sz));
PADDLE_ENFORCE_EQ(
bias.size(),
sz,
common::errors::InvalidArgument(
"Size of inputs(Bias) of FusionRepeatedFCReluOp should be "
"equal to inputs size %d, but received value is %d.",
sz,
bias.size()));
PADDLE_ENFORCE_EQ(
relu_out.size(),
sz - 1,
common::errors::InvalidArgument(
"Size of output(ReluOut) of FusionRepeatedFCReluOp should "
"be equal to inputs size minus one %d, but received value is %d",
sz - 1,
relu_out.size()));
auto i_dims = x.dims();
PADDLE_ENFORCE_EQ(
i_dims.size(),
2,
common::errors::InvalidArgument(
"Input shape size should be 2, but received value is %d.",
i_dims.size()));
std::vector<DDim> w_dims, b_dims;
w_dims.reserve(w.size());
std::transform(w.begin(),
w.end(),
std::back_inserter(w_dims),
[](const MetaTensor* var) { return var->dims(); });
b_dims.reserve(bias.size());
std::transform(bias.begin(),
bias.end(),
std::back_inserter(b_dims),
[](const MetaTensor* var) { return var->dims(); });
PADDLE_ENFORCE_EQ(w_dims.size(),
b_dims.size(),
common::errors::InvalidArgument(
"Shape size of weight and bias should be equal, but "
"weight size is %d, bias size is %d.",
w_dims.size(),
b_dims.size()));
PADDLE_ENFORCE_EQ(i_dims[1],
w_dims[0][0],
common::errors::InvalidArgument(
"input width should be equal to weight height, but "
"input width is %d, weight height is %d.",
i_dims[1],
w_dims[0][0]));
for (size_t i = 1; i < sz; ++i) {
PADDLE_ENFORCE_EQ(w_dims[i].size(),
2,
common::errors::InvalidArgument(
"Every weight shape size should be 2, but received "
"w_dims[%d].size() = %d.",
i,
w_dims[i].size()));
PADDLE_ENFORCE_EQ(
common::product(b_dims[i]),
w_dims[i][1],
common::errors::InvalidArgument(
"The length of Bias must be equal with w_dims[1], but received "
"product(b_dims[%d]) = %d, w_dims[%d][1] = %d.",
i,
common::product(b_dims[i]),
i,
w_dims[i][1]));
}
out->set_dims({i_dims[0], w_dims[sz - 1][1]});
out->share_lod(x);
out->set_dtype(x.dtype());
}
void FusionSquaredMatSubInferMeta(const MetaTensor& x,
const MetaTensor& y,
const float scalar,
MetaTensor* squared_x,
MetaTensor* squared_y,
MetaTensor* squared_xy,
MetaTensor* out) {
auto x_dims = x.dims();
auto y_dims = y.dims();
PADDLE_ENFORCE_EQ(
x_dims.size(),
y_dims.size(),
common::errors::InvalidArgument("The input tensor X's dims size should "
"be equal to Y's. But received X's "
"dims size = %d, Y's dims size = %d.",
x_dims.size(),
y_dims.size()));
PADDLE_ENFORCE_EQ(x_dims.size(),
2,
common::errors::InvalidArgument(
"The input tensor X's dims size should be 2. But "
"received X's dims size = %d.",
x_dims.size()));
PADDLE_ENFORCE_EQ(
x_dims[1],
y_dims[0],
common::errors::InvalidArgument("The input tensor X's dims[1] should "
"be equal to Y's dims[0]. But received "
"X's dims[1] = %d, Y's dims[0] = %d.",
x_dims[1],
y_dims[0]));
squared_x->set_dims(x_dims);
squared_x->set_dtype(x.dtype());
squared_y->set_dims(y_dims);
squared_y->set_dtype(x.dtype());
squared_xy->set_dims({x_dims[0], y_dims[1]});
squared_xy->set_dtype(x.dtype());
out->set_dims({x_dims[0], y_dims[1]});
out->set_dtype(x.dtype());
}
void FusionGRUInferMeta(const MetaTensor& x,
const MetaTensor& h0,
const MetaTensor& weight_x,
const MetaTensor& weight_h,
const MetaTensor& bias,
const std::string& activation,
const std::string& gate_activation,
const bool is_reverse,
const bool use_seq,
const bool origin_mode,
const bool force_fp32_output,
MetaTensor* reordered_h0,
MetaTensor* xx,
MetaTensor* batched_input,
MetaTensor* batched_out,
MetaTensor* hidden) {
DDim x_dims = x.dims();
auto x_mat_dims = (x_dims.size() == 3 && x_dims[1] == 1)
? flatten_to_2d(x_dims, 1)
: x_dims;
PADDLE_ENFORCE_EQ(
x_mat_dims.size(),
2,
common::errors::InvalidArgument("The size of input X dims should be 2, "
"or 3 with second dimension equal to "
"1, but now Input X dim is:[%s] ",
x_dims));
auto wx_dims = weight_x.dims();
PADDLE_ENFORCE_EQ(wx_dims.size(),
2,
common::errors::InvalidArgument(
"The rank of Input(WeightX) should be 2, but received "
"WeightX dim size is:%d, WeightX dim is:[%s] ",
wx_dims.size(),
wx_dims));
PADDLE_ENFORCE_EQ(
wx_dims[0],
x_mat_dims[1],
common::errors::InvalidArgument(
"The first dimension of flattened WeightX "
"should equal to last dimension of flattened input X, but "
"received fattened WeightX dimension is:%d, flattened X dimension "
"is:%d",
wx_dims[0],
x_mat_dims[1]));
int64_t frame_size = wx_dims[1] / 3;
auto wh_dims = weight_h.dims();
PADDLE_ENFORCE_EQ(wh_dims.size(),
2,
common::errors::InvalidArgument(
"The rank of Input(WeightH) should be 2, but received "
"WeightH dim size is:%d, WeightH dim is:[%s]",
wh_dims.size(),
wh_dims));
PADDLE_ENFORCE_EQ(wh_dims[0],
frame_size,
common::errors::InvalidArgument(
"The first dimension of WeightH "
"should equal to frame_size, but received WeightH's "
"first dimension is: "
"%d, frame size is:%d",
wh_dims[0],
frame_size));
PADDLE_ENFORCE_EQ(wh_dims[1],
3 * frame_size,
common::errors::InvalidArgument(
"The second dimension of Input(WeightH) "
"should equal to 3 * frame_size, but received WeightH "
"is:%d, frame size is:%d",
wh_dims[1],
frame_size));
if (h0) {
auto h0_dims = h0.dims();
PADDLE_ENFORCE_EQ(h0_dims[1],
frame_size,
common::errors::InvalidArgument(
"The width of H0 must be equal to frame_size, but "
"received the width of H0 is:%d, frame size is:%d",
h0_dims[1],
frame_size));
reordered_h0->set_dtype(x.dtype());
}
if (bias) {
auto b_dims = bias.dims();
PADDLE_ENFORCE_EQ(b_dims.size(),
2,
common::errors::InvalidArgument(
"The rank of Input(Bias) should be 2, but received "
"Bias rank is:%d, Bias dim is:[%s]",
b_dims.size(),
b_dims));
PADDLE_ENFORCE_EQ(b_dims[0],
1,
common::errors::InvalidArgument(
"The first dimension of Input(Bias) should be 1, but "
"received Bias first dim is:%d, Bias dim is:[%s]",
b_dims[0],
b_dims));
PADDLE_ENFORCE_EQ(b_dims[1],
frame_size * 3,
common::errors::InvalidArgument(
"The shape of Bias must be [1, frame_size * 3], but "
"received bias dim is:[%s], frame size is:%d",
b_dims,
frame_size));
}
DDim out_dims({x_mat_dims[0], frame_size});
hidden->set_dims(out_dims);
hidden->share_lod(x);
hidden->set_dtype(x.dtype());
int64_t xx_width = 0;
if (use_seq) {
xx_width = wx_dims[1];
} else {
xx_width = x_mat_dims[1] > wx_dims[1] ? wx_dims[1] : x_mat_dims[1];
batched_input->set_dims({x_mat_dims[0], wx_dims[1]});
batched_input->set_dtype(x.dtype());
batched_out->set_dims(out_dims);
batched_out->set_dtype(x.dtype());
}
xx->set_dims({x_mat_dims[0], xx_width});
xx->set_dtype(x.dtype());
xx->share_lod(x);
}
void FusionSeqConvEltAddReluInferMeta(const MetaTensor& x,
const MetaTensor& filter,
const MetaTensor& bias,
const int context_length,
const int context_start,
const int context_stride,
MetaTensor* out,
MetaTensor* col_mat) {
auto x_dims = x.dims();
auto w_dims = filter.dims();
PADDLE_ENFORCE_GT(context_length,
0,
common::errors::InvalidArgument(
"context_length should be greater than 0, "
"but received context_length is: %d",
context_length));
PADDLE_ENFORCE_EQ(context_stride,
1,
common::errors::InvalidArgument(
"Currently, FusionSeqConvEltAddReluOp only supports "
"contextStride=1, but received value is: %d.",
context_stride));
PADDLE_ENFORCE_EQ(
x_dims.size(),
2,
common::errors::InvalidArgument(
"Input(X) should be 2-D tensor, but received value is: %d.",
x_dims.size()));
PADDLE_ENFORCE_EQ(
w_dims.size(),
2,
common::errors::InvalidArgument(
"Filter should be 2-D tensor, but received value is: %d.",
w_dims.size()));
PADDLE_ENFORCE_EQ(w_dims[0],
context_length * x_dims[1],
common::errors::InvalidArgument(
"Filter's height should be equal to context_length * "
"input_hidden_size, but received Filter height is: %d,"
"context_length is: %d, input_hidden_size is: %d.",
w_dims[0],
context_length,
x_dims[1]));
PADDLE_ENFORCE_GT(
context_length + context_start,
0,
common::errors::InvalidArgument(
"contextStart size should be smaller than contextLength, "
"but received context_length is: %d, contextStart is: "
"%d.",
context_length,
context_start));
out->set_dims({x_dims[0], w_dims[1]});
col_mat->set_dims({x_dims[0], w_dims[0]});
out->share_lod(x);
col_mat->set_dtype(x.dtype());
out->set_dtype(x.dtype());
}
void FusionSeqExpandConcatFCInferMeta(const std::vector<const MetaTensor*>& x,
const MetaTensor& fc_weight,
const MetaTensor& fc_bias,
const std::string& fc_activation,
MetaTensor* out,
MetaTensor* fc_out) {
PADDLE_ENFORCE_GT(x.size(),
1UL,
common::errors::InvalidArgument(
"Inputs(X) of FusionSeqExpandConcatFCOp should larger "
"than 1, but received value is: %d.",
x.size()));
std::vector<DDim> ins_dims;
ins_dims.reserve(x.size());
std::transform(x.begin(),
x.end(),
std::back_inserter(ins_dims),
[](const MetaTensor* var) { return var->dims(); });
auto w_dims = fc_weight.dims(); // (M0+M1+M2+..) x D
PADDLE_ENFORCE_EQ(
w_dims.size(),
2,
common::errors::InvalidArgument(
"Input(FCWeight)'s rank must be 2, but received value is: %d.",
w_dims.size()));
const int64_t D = w_dims[1];
int64_t sum = ins_dims[0][1];
for (size_t i = 1; i < ins_dims.size(); ++i) {
sum += ins_dims[i][1];
}
PADDLE_ENFORCE_EQ(
sum,
w_dims[0],
common::errors::InvalidArgument("FC height should be sum of all inputs "
"width, but received FC height is: %d, "
"sum of all inputs width is: %d.",
w_dims[0],
sum));
if (fc_bias) {
auto b_dims = fc_bias.dims();
PADDLE_ENFORCE_EQ(
b_dims.size() == 1 || b_dims.size() == 2,
true,
common::errors::InvalidArgument(
"FCBias dim should be 1 or 2, but received value is: %d.",
b_dims.size()));
if (b_dims.size() == 1) {
PADDLE_ENFORCE_EQ(b_dims[0],
D,
common::errors::InvalidArgument(
"FCBias shapes must be %d when FCBias dim = 1, but "
"received value is: %d.",
D,
b_dims[0]));
} else {
PADDLE_ENFORCE_EQ(b_dims[0],
1,
common::errors::InvalidArgument(
"FCBias shapes must be 1x%d, when FCBias dim = 2, "
"but received dim[0] is: %d.",
D,
b_dims[0]));
PADDLE_ENFORCE_EQ(b_dims[1],
D,
common::errors::InvalidArgument(
"FCBias shapes must be 1x%d, when FCBias dim = 2, "
"but received dim[1] is: %d.",
D,
b_dims[1]));
}
}
fc_out->set_dtype((*x[0]).dtype());
out->set_dims({ins_dims[0][0], D});
out->set_dtype((*x[0]).dtype());
// fcout should be reshape when run since can not get lod in infershape
// explicit share the ref lod
out->share_lod(*x[0]);
}
std::tuple<int64_t, int64_t, int64_t> FusedStackQuantCommonCheck(
const std::vector<const MetaTensor*>& x) {
PADDLE_ENFORCE_GT(x.size(),
0UL,
common::errors::InvalidArgument(
"Number of Inputs(x) must be larger than 0, but"
" received value is:%d.",
x.size()));
int64_t N = x.size();
for (int i = 0; i < N; ++i) {
PADDLE_ENFORCE_EQ(
x[i]->dtype(),
DataType::BFLOAT16,
common::errors::InvalidArgument(
"input must be bfloat16, but received dtype: %s", x[i]->dtype()));
}
auto input_dims = x[0]->dims();
PADDLE_ENFORCE_EQ(
input_dims.size(),
2U,
common::errors::InvalidArgument(
"input must be 2-D, but received dims: %s", input_dims.to_str()));
int64_t M = input_dims[0];
int64_t K = input_dims[1];
for (int i = 1; i < N; ++i) {
input_dims = x[i]->dims();
PADDLE_ENFORCE_EQ(input_dims.size(),
2U,
common::errors::InvalidArgument(
"input must be 2-D, but received input[%d] dims: %s",
i,
input_dims.to_str()));
PADDLE_ENFORCE_EQ(
input_dims[0],
M,
common::errors::InvalidArgument(
"input [%d] must be shape %d, %d, but received dims: %s",
i,
M,
K,
input_dims.to_str()));
PADDLE_ENFORCE_EQ(
input_dims[1],
K,
common::errors::InvalidArgument(
"input [%d] must be shape %d, %d, but received dims: %s",
i,
M,
K,
input_dims.to_str()));
}
PADDLE_ENFORCE_LE(N,
65535,
common::errors::InvalidArgument(
"The batch size (N) must be no larger than 65535."));
PADDLE_ENFORCE_EQ(M % 128,
0,
common::errors::InvalidArgument(
"The upper dim (M) must be multiple of 128."));
PADDLE_ENFORCE_EQ(K % 128,
0,
common::errors::InvalidArgument(
"The lower dim (K) must be multiple of 128."));
return {N, M, K};
}
void FusedStackTransposeQuantInferMeta(const std::vector<const MetaTensor*>& x,
MetaTensor* out,
MetaTensor* scale) {
int64_t N, M, K;
std::tie(N, M, K) = FusedStackQuantCommonCheck(x);
std::vector<int64_t> out_shape = {N * K, M};
std::vector<int64_t> scale_shape = {N * K / 128, M / 128};
out->set_dims(make_ddim(out_shape));
scale->set_dims(make_ddim(scale_shape));
out->set_dtype(DataType::FLOAT8_E4M3FN);
scale->set_dtype(DataType::FLOAT32);
out->share_lod(*x.at(0));
scale->share_lod(*x.at(0));
out->set_layout(x.at(0)->layout());
scale->set_layout(x.at(0)->layout());
}
void FusedStackQuantInferMeta(const std::vector<const MetaTensor*>& x,
MetaTensor* out,
MetaTensor* scale) {
int64_t N, M, K;
std::tie(N, M, K) = FusedStackQuantCommonCheck(x);
std::vector<int64_t> out_shape = {N * M, K};
std::vector<int64_t> scale_shape = {N * M / 128, K / 128};
out->set_dims(make_ddim(out_shape));
scale->set_dims(make_ddim(scale_shape));
out->set_dtype(DataType::FLOAT8_E4M3FN);
scale->set_dtype(DataType::FLOAT32);
out->share_lod(*x.at(0));
scale->share_lod(*x.at(0));
out->set_layout(x.at(0)->layout());
scale->set_layout(x.at(0)->layout());
}
// Current constraint is appropriate for GemmEpilogueOp but relaxed for FcOp
void FCInferMeta(const MetaTensor& input,
const MetaTensor& w,
const MetaTensor& bias,
const int in_num_col_dims,
const std::string& activation_type,
const bool padding_weights,
MetaTensor* out) {
PADDLE_ENFORCE_GE(
in_num_col_dims,
1,
common::errors::InvalidArgument(
"The in_num_col_dims is expected to equal or greater than 1. "
"But received the in_num_col_dims is %d. ",
in_num_col_dims));
auto w_dims = w.dims();
PADDLE_ENFORCE_EQ(
w_dims.size(),
2,
common::errors::InvalidArgument(
"The input Weight of fc is expected to be a 2-D tensor. "
"But received the number of Weight's dimensions is %d, "
"Weight's shape is %s.",
w_dims.size(),
w_dims));
if (bias) {
auto bias_dims = bias.dims();
auto w_dims1 = padding_weights ? w_dims[1] - 4 : w_dims[1];
PADDLE_ENFORCE_EQ(
bias_dims[bias_dims.size() - 1],
w_dims1,
common::errors::InvalidArgument(
"The last dimension of input Bias is expected be equal "
"to the actual width of input Weight. But received the last "
"dimension of Bias is %d, Bias's shape is %s; "
"the actual width of Weight is %d, Weight's shape is %s.",
bias_dims[bias_dims.size() - 1],
bias_dims,
w_dims1,
w_dims));
}
auto in_dims = input.dims();
PADDLE_ENFORCE_LT(
in_num_col_dims,
in_dims.size(),
common::errors::InvalidArgument(
"The attribute in_num_col_dims used to flatten Input to "
"a 2-D tensor, is expected to be less than the number of "
"Input's dimensions. But received in_num_col_dims is %d, "
"the number of Input's dimensions is %d, Input's shape is %s.",
in_num_col_dims,
in_dims.size(),
in_dims));
std::unordered_set<std::string> support_acts = {"", "relu", "gelu"};
PADDLE_ENFORCE_EQ(
support_acts.count(activation_type),
1,
common::errors::InvalidArgument(
"The attribute activation_type of fc is expected "
"to be one of [\"\", \"relu\", \"gelu\"], but received %s.",
activation_type.c_str()));
std::vector<int64_t> output_dims;
funcs::FCOutputSize(
in_dims, w_dims, output_dims, in_num_col_dims, padding_weights);
out->set_dims(make_ddim(output_dims));
out->share_lod(input);
out->set_dtype(input.dtype());
}
void FCOneDNNInferMeta(const MetaTensor& input,
const MetaTensor& w,
const MetaTensor& bias,
const int in_num_col_dims,
const std::string& activation_type,
const bool padding_weights,
const std::vector<int>& fused_reshape2_shape,
MetaTensor* out) {
PADDLE_ENFORCE_GE(
in_num_col_dims,
1,
common::errors::InvalidArgument(
"The in_num_col_dims is expected to equal or greater than 1. "
"But received the in_num_col_dims is %d. ",
in_num_col_dims));
auto w_dims = w.dims();
PADDLE_ENFORCE_EQ(
w_dims.size(),
2,
common::errors::InvalidArgument(
"The input Weight of fc is expected to be a 2-D tensor. "
"But received the number of Weight's dimensions is %d, "
"Weight's shape is %s.",
w_dims.size(),
w_dims));
if (bias) {
auto bias_dims = bias.dims();
auto w_dims1 = padding_weights ? w_dims[1] - 4 : w_dims[1];
PADDLE_ENFORCE_EQ(
bias_dims[bias_dims.size() - 1],
w_dims1,
common::errors::InvalidArgument(
"The last dimension of input Bias is expected be equal "
"to the actual width of input Weight. But received the last "
"dimension of Bias is %d, Bias's shape is %s; "
"the actual width of Weight is %d, Weight's shape is %s.",
bias_dims[bias_dims.size() - 1],
bias_dims,
w_dims1,
w_dims));
}
auto in_dims = input.dims();
// VLOG(-2) << "fc in dims: " << in_dims.size();
PADDLE_ENFORCE_LT(
in_num_col_dims,
in_dims.size(),
common::errors::InvalidArgument(
"The attribute in_num_col_dims used to flatten Input to "
"a 2-D tensor, is expected to be less than the number of "
"Input's dimensions. But received in_num_col_dims is %d, "
"the number of Input's dimensions is %d, Input's shape is %s.",
in_num_col_dims,
in_dims.size(),
in_dims));
std::unordered_set<std::string> support_acts = {"", "relu", "gelu"};
PADDLE_ENFORCE_EQ(
support_acts.count(activation_type),
1,
common::errors::InvalidArgument(
"The attribute activation_type of fc is expected "
"to be one of [\"\", \"relu\", \"gelu\"], but received %s.",
activation_type.c_str()));
std::vector<int64_t> output_dims;
funcs::FCOutputSize(
in_dims, w_dims, output_dims, in_num_col_dims, padding_weights);
auto out_dims = make_ddim(output_dims);
auto reshape_size = fused_reshape2_shape;
if (!reshape_size.empty()) {
out_dims = out_dims.reshape(reshape_size);
}
out->set_dims(out_dims);
out->share_lod(input);
out->set_dtype(input.dtype());
}
void SelfDPAttenInferMeta(const MetaTensor& x,
const float alpha,
const int head_number,
MetaTensor* out) {
auto dim_input = x.dims();
PADDLE_ENFORCE_EQ(dim_input.size(),
5,
common::errors::InvalidArgument(
"The size of input X dims should be 5, "
"[batchsize, tokensize, 3, nhead, headsize] "
", but now Input X dim is:[%s] ",
dim_input));
DDim out_dims({dim_input[0], dim_input[1], dim_input[3], dim_input[4]});
out->set_dims(out_dims);
out->share_lod(x);
out->set_dtype(x.dtype());
}
void SkipLayerNormInferMeta(const MetaTensor& x,
const MetaTensor& y,
const MetaTensor& scale,
const MetaTensor& bias,
const float epsilon,
const int begin_norm_axis,
MetaTensor* out) {
auto dim_input = x.dims();
out->set_dims(dim_input);
out->share_lod(x);
out->set_dtype(x.dtype());
}
void VariableLengthMemoryEfficientAttentionInferMeta(
const MetaTensor& query,
const MetaTensor& key,
const MetaTensor& value,
const MetaTensor& seq_lens,
const MetaTensor& kv_seq_lens,
const MetaTensor& mask,
float scale,
bool causal,
int pre_cache_length,
MetaTensor* out) {
PADDLE_ENFORCE_EQ(
query.dims().size(),
4,
common::errors::InvalidArgument("Query should be a 4-D tensor. "
"But received Query dimension(%s)",
query.dims().size()));
PADDLE_ENFORCE_EQ(
key.dims().size(),
4,
common::errors::InvalidArgument("Key should be a 4-D tensor. "
"But received Key dimension(%s)",
key.dims().size()));
PADDLE_ENFORCE_EQ(
value.dims().size(),
4,
common::errors::InvalidArgument("Value should be a 4-D tensor. "
"But received Value dimension(%s)",
value.dims().size()));
const int64_t query_batch_size = query.dims()[0];
const int64_t query_num_head = query.dims()[1];
const int64_t query_seq_length = query.dims()[2];
const int64_t query_head_size = query.dims()[3];
const int64_t key_batch_size = key.dims()[0];
const int64_t key_num_head = key.dims()[1];
const int64_t key_seq_length = key.dims()[2];
const int64_t key_head_size = key.dims()[3];
const int64_t value_batch_size = value.dims()[0];
const int64_t value_num_head = value.dims()[1];
const int64_t value_seq_length = value.dims()[2];
const int64_t value_head_size = value.dims()[3];
PADDLE_ENFORCE_EQ(
((query_batch_size == key_batch_size) &&
(key_batch_size == value_batch_size)),
true,
common::errors::InvalidArgument(
"The batch size of Query, Key, Value should be equal."));
PADDLE_ENFORCE_EQ((key_num_head == value_num_head),
true,
common::errors::InvalidArgument(
"The head number of Key, Value should be equal."));
if (key_num_head != 0) {
PADDLE_ENFORCE_EQ(
query_num_head % key_num_head,
0,
errors::InvalidArgument(
"The num_head of query must be divisible by the num_head of key, "
"but "
"received num_head of query is %d, and the num_head of key is %d",
query_num_head,
key_num_head));
}
PADDLE_ENFORCE_EQ(query_head_size == key_head_size,
true,
common::errors::InvalidArgument(
"The head size of Query, Key should be equal."));
PADDLE_ENFORCE_EQ(key_seq_length == value_seq_length,
true,
common::errors::InvalidArgument(
"The seq length of Key, Value should be equal."));
if (mask) {
PADDLE_ENFORCE_EQ(
mask.dims().size(),
4,
common::errors::InvalidArgument("Mask should be a 4-D tensor. "
"But received Value dimension(%s)",
mask.dims().size()));
const int64_t mask_batch_size = mask.dims()[0];
PADDLE_ENFORCE_EQ(
query_batch_size == mask_batch_size,
true,
common::errors::InvalidArgument(
"The batch size of Query, Key, Value and Mask should be equal."));
PADDLE_ENFORCE_EQ(
mask.dims()[1],
1,
common::errors::InvalidArgument(
"The second dim of mask should be 1, but received mask dim is [%s]",
mask.dims()));
}
std::vector<int64_t> out_dims(
{query_batch_size, query_num_head, query_seq_length, value_head_size});
out->set_dims(make_ddim(out_dims));
out->set_dtype(query.dtype());
out->set_layout(query.layout());
}
void QKVAttentionXPUInferMeta(const MetaTensor& q,
const MetaTensor& k,
const MetaTensor& v,
const MetaTensor& q_max,
const MetaTensor& k_max,
const MetaTensor& v_max,
const MetaTensor& qk_max,
const MetaTensor& qkv_max,
float alpha,
int head_num,
int head_dim,
bool qkv_fc_fusion,
DataType out_dtype,
MetaTensor* qkv) {
auto q_dims = q.dims();
auto k_dims = k.dims();
auto v_dims = v.dims();
// input shape : {B, L, 3*H*D} or {B, L, H*D}
PADDLE_ENFORCE_EQ(q_dims.size(),
3,
common::errors::InvalidArgument("The dim of q should be 3! "
"But received ."));
PADDLE_ENFORCE_EQ(k_dims.size(),
3,
common::errors::InvalidArgument("The dim of k should be 3! "
"But received ."));
PADDLE_ENFORCE_EQ(v_dims.size(),
3,
common::errors::InvalidArgument("The dim of v should be 3! "
"But received ."));
for (int i = 0; i < q_dims.size(); ++i) {
PADDLE_ENFORCE_EQ(q_dims[i],
k_dims[i],
common::errors::InvalidArgument(
"The shape of q, k should be the same! "
"But received ."));
PADDLE_ENFORCE_EQ(k_dims[i],
v_dims[i],
common::errors::InvalidArgument(
"The shape of k , v should be the same! "
"But received ."));
}
int64_t hidden_dim = qkv_fc_fusion
? static_cast<int64_t>(3) * head_num * head_dim
: static_cast<int64_t>(head_num) * head_dim;
PADDLE_ENFORCE_EQ(
q_dims[2],
hidden_dim,
common::errors::InvalidArgument(
"The shape of q should be [B, L, H*D] or [B, L, 3*H*D]! "
"But received q_dims[2]: [%d] != expected hidden_dim : [%d].",
q_dims[2],
hidden_dim));
// output shape: {B, L, HD}
qkv->set_dims(make_ddim(
{q_dims[0], q_dims[1], static_cast<int64_t>(head_num) * head_dim}));
qkv->set_dtype(out_dtype);
qkv->set_layout(q.layout());
}
void SinePosXPUInferMeta(const MetaTensor& x,
const MetaTensor& y,
MetaTensor* out) {
auto x_dims = x.dims();
auto x_dims_size = x_dims.size();
PADDLE_ENFORCE_EQ(
x_dims_size,
3,
common::errors::InvalidArgument(
"x_dims_size should be 3, but received x_dims_size is %d",
x_dims_size));
PADDLE_ENFORCE_EQ(x_dims[x_dims_size - 1],
1,
common::errors::InvalidArgument(
"x last dim size should be 1, but received is %d",
x_dims[x_dims_size - 1]));
auto y_dims = y.dims();
auto y_dims_size = y_dims.size();
PADDLE_ENFORCE_EQ(
y_dims_size,
1,
common::errors::InvalidArgument(
"x_dims_size should be 3, but received x_dims_size is %d",
y_dims_size));
DDim out_dim = make_ddim({x_dims[0], x_dims[1], y_dims[0]});
out->set_dims(out_dim);
out->set_dtype(x.dtype());
}
void Pad2dXPUInferMeta(const MetaTensor& x,
const std::vector<int>& paddings,
const std::string& mode,
float pad_value,
const std::string& data_format,
MetaTensor* out) {
auto x_dims = x.dims();
DDim out_dim;
if (data_format == "NCHW") {
out_dim = make_ddim(
{x_dims[0],
x_dims[1],
x_dims[2] + paddings[2] + paddings[3], // top bottom height
x_dims[3] + paddings[0] + paddings[1]}); // left right weight
} else if (data_format == "NHWC") {
out_dim = make_ddim({x_dims[0],
x_dims[1] + paddings[2] + paddings[3], // height
x_dims[2] + paddings[0] + paddings[1], // width
x_dims[3]});
} else {
PADDLE_THROW(common::errors::External(
"XPU is not support data format in pad2d is %s", data_format));
}
if (data_format == "NHWC") {
out->set_layout(DataLayout::NHWC);
} else if (data_format == "NCHW") {
out->set_layout(DataLayout::NCHW);
}
out->set_dims(out_dim);
out->set_dtype(x.dtype());
}
void CrossAttentionXPUInferMeta(
const MetaTensor& input_q,
const MetaTensor& input_kv,
const std::vector<const MetaTensor*>& fc_weight,
const std::vector<const MetaTensor*>& fc_weight_max,
const std::vector<const MetaTensor*>& fc_bias,
const MetaTensor& mask,
int head_num,
int head_dim,
float alpha,
DataType out_dtype,
MetaTensor* qkv,
MetaTensor* qkv_max) {
auto input_q_dims = input_q.dims();
auto input_kv_dims = input_kv.dims();
auto mask_dims = mask.dims();
// input shape : {B, L, H*D}
PADDLE_ENFORCE_EQ(input_q_dims.size(),
3,
common::errors::InvalidArgument(
"The dim of input_q should be 3! But received %d.",
input_q_dims.size()));
PADDLE_ENFORCE_EQ(input_kv_dims.size(),
3,
common::errors::InvalidArgument(
"The dim of input_kv should be 3! But received %d.",
input_kv_dims.size()));
// sequence length of q and k/v not required to be equal
// but batch size and dim should be the same
PADDLE_ENFORCE_EQ(
input_q_dims[0],
input_kv_dims[0],
common::errors::InvalidArgument(
"The batch size of input_q and input_kv should be the same! "
"Received %d vs %d.",
input_q_dims[0],
input_kv_dims[0]));
PADDLE_ENFORCE_EQ(
input_q_dims[2],
input_kv_dims[2],
common::errors::InvalidArgument(
"The hidden_dim of input_q and input_kv should be the same! "
"Received %d vs %d.",
input_q_dims[2],
input_kv_dims[2]));
int64_t hidden_dim = static_cast<int64_t>(head_num) * head_dim;
PADDLE_ENFORCE_EQ(input_q_dims[2],
hidden_dim,
common::errors::InvalidArgument(
"The last dimension of input_q should be [H*D]! "
"Received %d != expected %d.",
input_q_dims[2],
hidden_dim));
PADDLE_ENFORCE_EQ(fc_weight.size(),
3,
common::errors::InvalidArgument(
"The size of fc_weight should be 3! But received %d.",
fc_weight.size()));
PADDLE_ENFORCE_EQ(
fc_weight_max.size(),
3,
common::errors::InvalidArgument(
"The size of fc_weight_max should be 3! But received %d.",
fc_weight_max.size()));
PADDLE_ENFORCE_EQ(
fc_bias.size(),
3,
common::errors::InvalidArgument(
"The size of fc_bias should be 3! But received %d.", fc_bias.size()));
PADDLE_ENFORCE_LE(
mask_dims.size(),
4,
common::errors::InvalidArgument(
"The dim of mask should be not greater than 4! But received %d.",
mask_dims.size()));
// output shape: {B, qL, H*D}
qkv->set_dims(make_ddim({input_q_dims[0],
input_q_dims[1],
static_cast<int64_t>(head_num) * head_dim}));
qkv->set_dtype(out_dtype);
qkv->set_layout(input_q.layout());
// TODO(Terry) optimize the max value num
// unable to pass few PR-CIs, so just use a constant value
// int xpu2_max_value_num = phi::backends::xpu::get_xpu_max_ptr_size(-1);
const int xpu2_max_value_num = 6;
qkv_max->set_dims(make_ddim({xpu2_max_value_num}));
qkv_max->set_dtype(out_dtype);
qkv_max->set_layout(input_q.layout());
}
void MaskAdaptiveXPUInferMeta(const MetaTensor& mask,
MetaTensor* length,
MetaTensor* seq_lod,
MetaTensor* pad_seq_len) {
auto mask_dims = mask.dims();
auto mask_dims_size = mask_dims.size();
PADDLE_ENFORCE_EQ(
mask_dims_size,
3,
common::errors::InvalidArgument(
"mask_dims_size should be 3, but received mask_dims_size is %d",
mask_dims_size));
length->set_dims({mask_dims[0]});
seq_lod->set_dims({mask_dims[0] + 1});
pad_seq_len->set_dims({1});
length->set_dtype(DataType::INT64);
seq_lod->set_dtype(DataType::INT32);
pad_seq_len->set_dtype(DataType::INT32);
}
void SequenceUnpadXPUInferMeta(const MetaTensor& x,
const MetaTensor& length,
MetaTensor* out) {
auto x_dims = x.dims();
auto len_dims = length.dims();
PADDLE_ENFORCE_GE(
x_dims.size(),
2,
common::errors::InvalidArgument(
"Rank of X can't be less than 2, but received x_dims.size() is %d",
x_dims.size()));
PADDLE_ENFORCE_EQ(
len_dims.size(),
1,
common::errors::InvalidArgument(
"Rank of Length should be 1, but received en_dims.size() is %d",
len_dims.size()));
PADDLE_ENFORCE_EQ(x_dims[0],
len_dims[0],
common::errors::InvalidArgument(
"X and Length should have the same 1st dim, but "
"received X.dims[0] is %d, Length.dims[0] is %d",
x_dims[0],
len_dims[0]));
out->set_dtype(x.dtype());
}
void MultiGruInferMeta(
const MetaTensor& x,
const std::vector<const MetaTensor*>& weight_x,
const std::vector<const MetaTensor*>& weight_h,
const paddle::optional<std::vector<const MetaTensor*>>& bias,
const paddle::optional<std::vector<const MetaTensor*>>& scale_weights,
const std::string& activation,
const std::string& gate_activation,
int layers,
bool origin_mode,
const std::string& onednn_data_type,
float scale_data,
float shift_data,
bool force_fp32_output,
MetaTensor* hidden) {
auto x_dims = x.dims();
auto x_mat_dims = (x_dims.size() == 3 && x_dims[1] == 1)
? flatten_to_2d(x_dims, 1)
: x_dims;
PADDLE_ENFORCE_EQ(
x_mat_dims.size(),
2,
common::errors::InvalidArgument("The size of input X dims should be 2, "
"or 3 with second dimension equal to "
"1, but now Input X dim is:[%s] ",
x_dims));
for (int i : {0, 1}) {
PADDLE_ENFORCE_EQ(
weight_x[i]->dims()[0],
x_mat_dims[1],
common::errors::InvalidArgument(
"The first dimension of flattened WeightX #%d "
"should equal to last dimension of flattened input X, but "
"received fattened WeightX dimension is:%d, flattened X "
"dimension "
"is:%d",
i,
weight_x[i]->dims()[0],
x_mat_dims[1]));
}
for (int i = 0; i < 2 * layers; ++i) {
PADDLE_ENFORCE_EQ(weight_x[i]->dims().size(),
2,
common::errors::InvalidArgument(
"The rank of WeightX #%d should be 2, but received "
"WeightX dim size is:%d, WeightX dim is:[%s] ",
i,
weight_x[i]->dims().size(),
weight_x[i]->dims()));
PADDLE_ENFORCE_EQ(weight_h[i]->dims().size(),
2,
common::errors::InvalidArgument(
"The rank of WeightH #%d should be 2, but received "
"WeightH dim size is:%d, WeightH dim is:[%s] ",
i,
weight_h[i]->dims().size(),
weight_h[i]->dims()));
int64_t frame_size = weight_h[i]->dims()[0];
PADDLE_ENFORCE_EQ(
weight_h[i]->dims()[1],
3 * frame_size,
common::errors::InvalidArgument(
"The second dimension of WeightH #%d "
"should equal to 3 * frame_size, but received WeightH's "
"second dimension is: %d, frame size is:%d",
i,
weight_h[i]->dims()[1],
frame_size));
PADDLE_ENFORCE_EQ(
weight_x[i]->dims()[1],
3 * frame_size,
common::errors::InvalidArgument(
"The second dimension of WeightX #%d "
"should equal to 3 * frame_size, but received WeightX's "
"second dimension is: %d, frame size is:%d",
i,
weight_x[i]->dims()[1],
frame_size));
}
if (bias) {
for (int i = 0; i < 2 * layers; ++i) {
int64_t frame_size = weight_h[i]->dims()[0];
PADDLE_ENFORCE_EQ(bias.get()[i]->dims().size(),
2,
common::errors::InvalidArgument(
"The rank of Bias #%d should be 2, but received "
"Bias rank is:%d, Bias dim is:[%s]",
i,
bias.get()[i]->dims().size(),
bias.get()[i]->dims()));
PADDLE_ENFORCE_EQ(bias.get()[i]->dims()[0],
1,
common::errors::InvalidArgument(
"The first dimension of Bias #%d should be 1, but "
"received Bias first dim is:%d, Bias dim is:[%s]",
i,
bias.get()[i]->dims()[0],
bias.get()[i]->dims()));
PADDLE_ENFORCE_EQ(
bias.get()[i]->dims()[1],
frame_size * 3,
common::errors::InvalidArgument(
"The shape of Bias #%d must be [1, frame_size * 3], but "
"received bias dim is:[%s], frame size is:%d",
i,
bias.get()[i]->dims(),
frame_size));
}
}
int64_t last_frame_size = weight_h.back()->dims()[0];
DDim out_dims({x_mat_dims[0], 2 * last_frame_size});
hidden->set_dims(out_dims);
hidden->share_lod(x);
}
void FusionLstmInferMeta(const MetaTensor& x,
const MetaTensor& weight_x,
const MetaTensor& weight_h,
const MetaTensor& bias,
const MetaTensor& h0,
const MetaTensor& c0,
const bool use_peepholes,
const bool is_reverse,
const bool use_seq,
const std::string& gate_activation,
const std::string& cell_activation,
const std::string& candidate_activation,
const float scale_data,
const float shift_data,
const std::vector<float>& scale_weights,
const bool force_fp32_output,
MetaTensor* hidden,
MetaTensor* cell,
MetaTensor* xx,
MetaTensor* batched_input,
MetaTensor* batched_hidden,
MetaTensor* batched_cell,
MetaTensor* reordered_h0,
MetaTensor* reordered_c0,
MetaTensor* checked_cell) {
auto x_dims = x.dims();
PADDLE_ENFORCE_EQ(x_dims.size(),
2,
common::errors::InvalidArgument(
"Input(X)'s rank must be 2, but received x's rank "
"is:%d, x dim is:[%s]",
x_dims.size(),
x_dims));
if (h0.initialized()) {
PADDLE_ENFORCE_EQ(
c0.initialized(),
true,
common::errors::InvalidArgument(
"fusion_lstm must has h0 and c0 input at the same time."));
auto h_dims = h0.dims();
auto c_dims = c0.dims();
PADDLE_ENFORCE_EQ(h_dims,
c_dims,
common::errors::InvalidArgument(
"The dimension of Input(H0) and Input(C0) should be "
"same, but received h0 dims is:[%s], c0 dims is:[%s]",
h_dims,
c_dims));
}
auto wx_dims = weight_x.dims();
PADDLE_ENFORCE_EQ(wx_dims.size(),
2,
common::errors::InvalidArgument(
"The rank of Input(WeightX) should be 2, but received "
"WeightX's rank is:%d, WeightX dim is:[%s]",
wx_dims.size(),
wx_dims));
PADDLE_ENFORCE_EQ(wx_dims[0],
x_dims[1],
common::errors::InvalidArgument(
"The first dimension of Input(WeightX) "
"should equal to second dimension of Input(X), but "
"received WeightX first dim is:%d, X second dim is:%d",
wx_dims[0],
x_dims[1]));
int64_t frame_size = wx_dims[1] / 4;
auto wh_dims = weight_h.dims();
PADDLE_ENFORCE_EQ(wh_dims.size(),
2,
common::errors::InvalidArgument(
"The rank of Input(WeightH) should be 2, but received "
"WeightH rank is:%d, WeightH dim is:[%s]",
wh_dims.size(),
wh_dims));
PADDLE_ENFORCE_EQ(wh_dims[0],
frame_size,
common::errors::InvalidArgument(
"The first dimension of Input(WeightH) "
"should equal to frame size, but received WeightH "
"first dim is:%d, frame size is:%d.",
wh_dims[0],
frame_size));
PADDLE_ENFORCE_EQ(wh_dims[1],
4 * frame_size,
common::errors::InvalidArgument(
"The second dimension of Input(WeightH) "
"should equal to 4 * frame_size, but received WeightH "
"second dimension is:%d, frame size is:%d.",
wh_dims[1],
frame_size));
auto b_dims = bias.dims();
PADDLE_ENFORCE_EQ(b_dims.size(),
2,
common::errors::InvalidArgument(
"The rank of Input(Bias) should be 2, but received "
"Bias rank is:%d, Bias dim is:[%s]",
b_dims.size(),
b_dims));
PADDLE_ENFORCE_EQ(b_dims[0],
1,
common::errors::InvalidArgument(
"The first dimension of Input(Bias) should be 1, but "
"received Bias's dimension is:[%s]",
b_dims));
if (use_peepholes) {
PADDLE_ENFORCE_EQ(b_dims[1],
7 * frame_size,
common::errors::InvalidArgument(
"The second dimension of Input(Bias) should be "
"7 * %d if enable peepholes connection, but received "
"Bias dim is:[%s]",
frame_size,
b_dims));
checked_cell->set_dims(make_ddim({2, frame_size}));
checked_cell->set_dtype(x.dtype());
} else {
PADDLE_ENFORCE_EQ(
b_dims[1],
4 * frame_size,
common::errors::InvalidArgument(
"The second dimension of Input(Bias) should be "
"4 * %d if disable peepholes, but received Bias dim is:[%s]",
frame_size,
b_dims));
}
auto out_dims = make_ddim({x_dims[0], frame_size});
hidden->set_dims(out_dims);
cell->set_dims(out_dims);
hidden->share_lod(x);
cell->share_lod(x);
hidden->set_dtype(x.dtype());
cell->set_dtype(x.dtype());
int64_t xx_width = 0;
if (use_seq) {
xx_width = wx_dims[1];
} else {
xx_width = x_dims[1] > wx_dims[1] ? wx_dims[1] : x_dims[1];
batched_input->set_dims(make_ddim({x_dims[0], wx_dims[1]}));
batched_hidden->set_dims(out_dims);
batched_cell->set_dims(out_dims);
batched_input->set_dtype(x.dtype());
batched_hidden->set_dtype(x.dtype());
batched_cell->set_dtype(x.dtype());
}
xx->set_dims(make_ddim({x_dims[0], xx_width}));
xx->set_dtype(x.dtype());
xx->share_lod(x);
}
void RoformerRelativePosXPUInferMeta(const MetaTensor& x,
const MetaTensor& sin_emb,
const MetaTensor& cos_emb,
int max_pos_len,
MetaTensor* out) {
auto x_dims = x.dims();
auto x_dims_size = x_dims.size();
auto sin_emb_dims = sin_emb.dims();
auto sin_emb_dims_size = sin_emb_dims.size();
auto cos_emb_dims = cos_emb.dims();
auto cos_emb_dims_size = cos_emb_dims.size();
PADDLE_ENFORCE_EQ(
x_dims_size,
4,
common::errors::InvalidArgument(
"x_dims_size should be 4, but received x_dims_size is %d",
x_dims_size));
PADDLE_ENFORCE_EQ(
sin_emb_dims_size,
4,
common::errors::InvalidArgument("sin_emb_dims_size should be 4, but "
"received sin_emb_dims_size is %d",
sin_emb_dims_size));
PADDLE_ENFORCE_EQ(
cos_emb_dims_size,
4,
common::errors::InvalidArgument("cos_emb_dims_size should be 4, but "
"received cos_emb_dims_size is %d",
cos_emb_dims_size));
for (int i = 0; i < sin_emb_dims_size; i++) {
PADDLE_ENFORCE_EQ(
sin_emb_dims[i],
cos_emb_dims[i],
common::errors::InvalidArgument(
"sin_emb_dims[i] should be equal to cos_emb_dims[i], index i is "
"%d, sin_emb_dims[i] is %d, cos_emb_dims[i] is %d",
i,
sin_emb_dims[i],
cos_emb_dims[i]));
}
PADDLE_ENFORCE_EQ(x_dims[3],
cos_emb_dims[3],
common::errors::InvalidArgument(
"x_dims[3] should be equal to cos_dims[3], "
"but sin_dims[3] is %d, cos_dims[3] is %d",
x_dims[3],
cos_emb_dims[3]));
out->set_dims(x_dims);
out->set_dtype(x.dtype());
}
void FusedSeqpoolCvmInferMeta(const std::vector<const MetaTensor*>& x,
const MetaTensor& cvm,
const std::string& pooltype,
float pad_value,
bool use_cvm,
int cvm_offset,
std::vector<MetaTensor*> out,
MetaConfig config) {
PADDLE_ENFORCE_GE(x.size(),
1UL,
common::errors::InvalidArgument(
"Inputs(X) of FusedSeqpoolCVMOp should not be empty."));
PADDLE_ENFORCE_GE(
out.size(),
1UL,
common::errors::InvalidArgument(
"Outputs(Out) of FusedSeqpoolCVMOp should not be empty."));
const auto& cvm_dims = cvm.dims();
PADDLE_ENFORCE_EQ(
cvm_dims.size(),
2UL,
common::errors::InvalidArgument("Input(CVM)'s rank should be 2."));
PADDLE_ENFORCE_EQ(cvm_dims[1],
2UL,
common::errors::InvalidArgument("The 2nd dimension of "
"Input(CVM) should be 2."));
const size_t num_inputs = x.size();
std::vector<DDim> outs_dims;
outs_dims.resize(num_inputs);
PADDLE_ENFORCE_GT(num_inputs,
0UL,
common::errors::InvalidArgument(
"Input tensors count should be greater than 0, "
"but received value is %d.",
num_inputs));
// The output height should be confirmed in Compute,
// since input lod is not accessible here.
auto size_tmp = x[0]->dims().size();
PADDLE_ENFORCE_EQ(size_tmp,
2,
common::errors::InvalidArgument(
"The dims size of first input should be equal to 2, "
"but received value is %d.",
size_tmp));
for (size_t i = 0; i < num_inputs; ++i) {
const auto dims = x[i]->dims();
int rank = dims.size();
if (use_cvm) {
PADDLE_ENFORCE_GT(
dims[rank - 1],
2,
common::errors::InvalidArgument(
"Shape error in %lu id, the last dimension(embedding) of the "
"'X' tensor must be larger than 2.",
i));
}
// input lod is not accessible here
std::vector<int64_t> out_dim;
if (use_cvm) {
out_dim = {-1, dims[rank - 1]};
} else {
out_dim = {-1, dims[rank - 1] - cvm_offset};
}
outs_dims[i] = make_ddim(out_dim);
}
for (size_t i = 0; i < out.size(); ++i) {
out[i]->set_dims(outs_dims[i]);
}
for (size_t i = 0; i < out.size(); ++i) {
out[i]->share_lod(*x[i]);
out[i]->set_dtype(x[i]->dtype());
}
}
void FusedSeqpoolCvmGradInferMeta(
const std::vector<const MetaTensor*>& x,
const MetaTensor& cvm,
const std::vector<const MetaTensor*>& out_grad,
const std::string& pooltype,
float pad_value,
bool use_cvm,
int cvm_offset,
std::vector<MetaTensor*> x_grad,
MetaTensor* cvm_grad,
MetaConfig config) {
std::vector<DDim> og_dims;
std::vector<DDim> x_dims;
og_dims.resize(out_grad.size());
x_dims.resize(x.size());
for (size_t i = 0; i < out_grad.size(); ++i) {
og_dims[i] = out_grad[i]->dims();
}
for (size_t i = 0; i < x.size(); ++i) {
x_dims[i] = x[i]->dims();
}
auto cvm_dims = cvm.dims();
PADDLE_ENFORCE_EQ(
cvm_dims.size(),
2,
common::errors::InvalidArgument("Input(CVM)'s rank should be 2."));
for (size_t i = 0; i < og_dims.size(); i++) {
PADDLE_ENFORCE_EQ(og_dims[i].size(),
x_dims[i].size(),
common::errors::InvalidArgument(
"The rank of output grad must equal to Input(X). But "
"received: input rank %u, input shape [%s].",
og_dims[i].size(),
og_dims[i]));
if (use_cvm) {
auto o_dim = og_dims[i][og_dims[i].size() - 1];
PADDLE_ENFORCE_EQ(
o_dim,
x_dims[i][og_dims[i].size() - 1],
common::errors::InvalidArgument(
"The dimension mismatch between Input(OUT@GRAD) and "
"Input(X). Received Input(OUT@GRAD): input rank %u, "
"input shape [%s]; received Input(X): input rank %u, "
"input shape [%s].",
og_dims[i].size(),
og_dims[i],
x_dims[i].size(),
x_dims[i]));
} else {
PADDLE_ENFORCE_EQ(
og_dims[i][og_dims[i].size() - 1],
x_dims[i][og_dims[i].size() - 1] - cvm_offset,
common::errors::InvalidArgument(
"The dimension mismatch between Input(OUT@GRAD) and "
"Input(X). Received Input(OUT@GRAD): input rank %u, "
"input shape [%s]; received Input(X): input rank %u, "
"input shape [%s].",
og_dims[i].size(),
og_dims[i],
x_dims[i].size(),
x_dims[i]));
}
}
for (size_t i = 0; i < x_dims.size(); ++i) {
x_grad[i]->share_lod(*x[i]);
x_grad[i]->set_dims(x[i]->dims());
x_grad[i]->set_dtype(x[i]->dtype());
}
}
void FusionSeqpoolCvmConcatInferMeta(const std::vector<const MetaTensor*>& x,
const MetaTensor& cvm,
const std::string& pooltype,
bool use_cvm,
int axis,
MetaTensor* out,
MetaConfig config) {
PADDLE_ENFORCE_GE(
x.size(),
1UL,
common::errors::InvalidArgument(
"Inputs(X) of FusionSeqPoolCVMConcatOp should not be empty."));
PADDLE_ENFORCE_NE(
out,
nullptr,
common::errors::InvalidArgument(
"Output(Out) of FusionSeqPoolCVMConcatOp should not be null."));
PADDLE_ENFORCE_EQ(
axis,
1,
common::errors::InvalidArgument("FusionSeqPoolCVMConcatOp only supports "
"concat axis=1 yet, but received %d.",
axis));
PADDLE_ENFORCE_EQ(
use_cvm,
true,
common::errors::InvalidArgument("FusionSeqPoolCVMConcatOp only supports "
"use_cvm is true yet, but received %d.",
use_cvm));
auto ins_dims = x[0]->dims();
const size_t n = x.size();
PADDLE_ENFORCE_GT(
n,
0UL,
common::errors::InvalidArgument("Input tensors count should > 0."));
// The output height should be confirmed in Compute,
// since input lod is not accessible here.
PADDLE_ENFORCE_EQ(ins_dims.size(),
2,
common::errors::InvalidArgument(
"The dims size of first input should be 2."));
out->set_dims(make_ddim({-1, ins_dims[axis] * static_cast<int64_t>(n)}));
out->set_dtype((*x[0]).dtype());
}
void FusedTokenPruneInferMeta(const MetaTensor& attn,
const MetaTensor& x,
const MetaTensor& mask,
const MetaTensor& new_mask,
bool keep_first_token,
bool keep_order,
MetaTensor* slimmed_x,
MetaTensor* cls_inds) {
const auto& mask_dim = mask.dims();
const auto& attn_dim = attn.dims();
const auto& x_dim = x.dims();
const auto& new_mask_dim = new_mask.dims();
// check input dims number
PADDLE_ENFORCE_EQ(
mask_dim.size(),
4,
common::errors::InvalidArgument("The input mask must be 4-dimension"));
PADDLE_ENFORCE_EQ(
attn_dim.size(),
4,
common::errors::InvalidArgument("The input attn must be 4-dimension"));
PADDLE_ENFORCE_EQ(
x_dim.size(),
3,
common::errors::InvalidArgument("The input x must be 4-dimension"));
PADDLE_ENFORCE_EQ(
new_mask_dim.size(),
4,
common::errors::InvalidArgument("The input attn must be 4-dimension"));
// check input dims relations
PADDLE_ENFORCE_EQ(mask_dim[0],
attn_dim[0],
common::errors::InvalidArgument(
"The first dim of mask and attn should be the same "
"which is batch size"));
PADDLE_ENFORCE_EQ(mask_dim[1],
attn_dim[1],
common::errors::InvalidArgument(
"The second dim of mask and attn should be the same "
"which is nb_head"));
PADDLE_ENFORCE_EQ(mask_dim[0],
x_dim[0],
common::errors::InvalidArgument(
"The first dim of mask and x should be the same "
"which is batch size"));
PADDLE_ENFORCE_EQ(
mask_dim[2],
mask_dim[3],
common::errors::InvalidArgument(
"The third dim and the fourth dim of mask should be the same "
"which is max seq len"));
PADDLE_ENFORCE_EQ(
attn_dim[2],
attn_dim[3],
common::errors::InvalidArgument(
"The third dim and the fourth dim of mask should be the same "
"which is max seq len"));
PADDLE_ENFORCE_EQ(attn_dim[2],
mask_dim[2],
common::errors::InvalidArgument(
"The third dim of mask and attn should be the same "
"which is max seq len"));
PADDLE_ENFORCE_EQ(attn_dim[2],
x_dim[1],
common::errors::InvalidArgument(
"The third dim of mask and the second dim of attn "
"should be the same which is max seq len"));
auto bsz = mask_dim[0];
auto c = x_dim[2];
auto slim_seq_len = new_mask_dim[2];
slimmed_x->set_dims({bsz, slim_seq_len, c});
cls_inds->set_dims({bsz, slim_seq_len});
slimmed_x->set_dtype(x.dtype());
cls_inds->set_dtype(DataType::INT64);
}
void FusedElemwiseActivationInferMeta(
const MetaTensor& x,
const MetaTensor& y,
const std::vector<std::string>& functor_list,
int axis,
float scale,
bool save_intermediate_out,
MetaTensor* out,
MetaTensor* intermediate_out,
MetaConfig config) {
const auto& x_dim = x.dims();
const auto& y_dim = y.dims();
// Whether the shape of Y is a continuous subsequence of X,
// For more information please refer to the op's introduction.
bool bcast_y = funcs::IsBcastY(x_dim, y_dim);
const auto& out_dim = bcast_y ? x_dim : y_dim;
const auto& out_lod = bcast_y ? x : y;
auto out_dtype = bcast_y ? x.dtype() : y.dtype();
if (save_intermediate_out) {
PADDLE_ENFORCE_EQ(
intermediate_out->initialized(),
true,
common::errors::InvalidArgument(
"Output(IntermediateOut) of FusedElemwiseActivationOp "
"should not be null."));
if (funcs::IsUnaryCompound(functor_list)) {
// for Unary(Binary(X, Y)), the shape and lod of out and
// intermediate_out are the same.
intermediate_out->set_dims(out_dim);
// set the lod of intermediate_out
intermediate_out->share_lod(out_lod);
intermediate_out->set_dtype(out_dtype);
} else {
// for Binary(X, Unary(Y)), the shape and lod of Y and
// intermediate_out are the same.
intermediate_out->set_dims(y_dim);
// set the lod of intermediate_out
intermediate_out->share_lod(y);
intermediate_out->set_dtype(y.dtype());
}
}
out->set_dims(out_dim);
out->share_lod(out_lod);
out->set_dtype(out_dtype);
}
void FusedElemwiseActivationGradInferMeta(
const MetaTensor& x,
const MetaTensor& y,
const MetaTensor& out,
const MetaTensor& intermediate_out,
const MetaTensor& out_grad,
const std::vector<std::string>& functor_list,
int axis,
float scale,
bool save_intermediate_out,
MetaTensor* x_grad,
MetaTensor* y_grad,
MetaConfig config) {
PADDLE_ENFORCE_EQ(
out_grad.initialized(),
true,
common::errors::InvalidArgument("Input(Out@GRAD) should not be null."));
if (save_intermediate_out) {
PADDLE_ENFORCE_EQ(intermediate_out.initialized(),
true,
common::errors::InvalidArgument(
"Input(IntermediateOut) should not be null."));
} else {
if (!funcs::InputXCanBeAbsent(functor_list)) {
PADDLE_ENFORCE_EQ(
x.initialized(),
true,
common::errors::InvalidArgument("Input(X) should not be null."));
}
}
if (x_grad != nullptr) {
if (x.initialized()) {
x_grad->set_dims(x.dims());
x_grad->share_lod(x);
x_grad->set_dtype(x.dtype());
} else {
// Currently, only when Binary is elementwise_add or elementwise_sub,
// the "X" could be absent.
PADDLE_ENFORCE_EQ(
funcs::InputXCanBeAbsent(functor_list),
true,
common::errors::InvalidArgument(
"Only when BinaryFunctor is elementwise_add, the 'X' "
"could be absent."));
// Node: If "X" is absence, the shape of Y should be a continuous
// subsequence of X, otherwise, we could not infer the shape of dx.
x_grad->set_dims(out_grad.dims());
x_grad->share_lod(out_grad);
x_grad->set_dtype(out_grad.dtype());
}
}
if (y_grad != nullptr) {
PADDLE_ENFORCE_EQ(
y.initialized(),
true,
common::errors::InvalidArgument("Input(Y) should not be null."));
y_grad->set_dims(y.dims());
y_grad->share_lod(y);
y_grad->set_dtype(y.dtype());
}
}
void FP8OutHalfGemmFusedInferMeta(
const MetaTensor& x,
const MetaTensor& y,
const MetaTensor& bias,
const bool trans_x,
const bool trans_y,
const float scale, // only support per-tensor quantization
const std::string& output_dtype,
const std::string& activation_type,
MetaTensor* out) {
std::vector<int64_t> dims_x = vectorize(x.dims());
std::vector<int64_t> dims_y = vectorize(y.dims());
auto ndims_x = dims_x.size();
auto ndims_y = dims_y.size();
PADDLE_ENFORCE_GT(ndims_x,
0UL,
common::errors::InvalidArgument(
"The Input(x) dims size must be greater than 0,"
" but received dims size is 0. "));
PADDLE_ENFORCE_GT(ndims_y,
0UL,
common::errors::InvalidArgument(
"The Input(y) dims size must be greater than 0,"
" but received dims size is 0. "));
bool x_broadcasted = false, y_broadcasted = false;
if (ndims_x == 1) {
dims_x.insert(dims_x.begin(), 1);
ndims_x = 2;
x_broadcasted = true;
}
if (ndims_y == 1) {
dims_y.push_back(1);
ndims_y = 2;
y_broadcasted = true;
}
size_t M = 0, N = 0;
if (trans_x) {
M = dims_x[ndims_x - 1];
} else {
M = dims_x[ndims_x - 2];
}
if (trans_y) {
N = dims_y[ndims_y - 2];
} else {
N = dims_y[ndims_y - 1];
}
std::vector<int64_t> new_dims;
if (ndims_x > ndims_y) {
new_dims.assign(dims_x.begin(), dims_x.end() - 2);
} else if (ndims_x < ndims_y) {
new_dims.assign(dims_y.begin(), dims_y.end() - 2);
} else {
new_dims.reserve(ndims_x);
for (size_t i = 0; i < ndims_x - 2; ++i) {
new_dims.push_back(std::max(dims_x[i], dims_y[i]));
}
}
if (!x_broadcasted) {
new_dims.push_back(M); // NOLINT
}
if (!y_broadcasted) {
new_dims.push_back(N); // NOLINT
}
auto ddim_out = make_ddim(new_dims);
out->set_dims(ddim_out);
out->set_layout(x.layout());
if (output_dtype == "bfloat16") {
out->set_dtype(DataType::BFLOAT16);
} else if (output_dtype == "float16") {
out->set_dtype(DataType::FLOAT16);
} else {
PADDLE_THROW(common::errors::Fatal(
"fp8_fp8_half_gemm_fused only support bfloat16 and float16 output"));
}
}
void FusedEmbeddingFcLstmInferMeta(const MetaTensor& ids,
const MetaTensor& embeddings,
const MetaTensor& weight_h,
const MetaTensor& bias,
const MetaTensor& h0,
const MetaTensor& c0,
bool use_peepholes,
bool is_reverse,
bool use_seq,
const std::string& gate_activation,
const std::string& cell_activation,
const std::string& candidate_activation,
MetaTensor* hidden,
MetaTensor* cell,
MetaTensor* xx,
MetaTensor* batched_input,
MetaTensor* batched_hidden,
MetaTensor* batched_cell,
MetaTensor* reordered_h0,
MetaTensor* reordered_c0) {
const auto& table_dims = embeddings.dims();
const auto& ids_dims = ids.dims();
int ids_rank = ids_dims.size();
PADDLE_ENFORCE_EQ(
table_dims.size(),
2,
common::errors::InvalidArgument(
"The Embeddings's rank should be 2, but received value is:%d.",
table_dims.size()));
PADDLE_ENFORCE_EQ(ids_dims[ids_rank - 1],
1,
common::errors::InvalidArgument(
"The last dimension of the 'Ids' tensor must be 1, but "
"received value is:%d.",
ids_dims[ids_rank - 1]));
const auto& x_dims = ids.dims();
PADDLE_ENFORCE_EQ(
x_dims.size(),
2,
common::errors::InvalidArgument(
"Input(Ids)'s rank must be 2, but received value is:%d.",
x_dims.size()));
if (h0.initialized()) {
PADDLE_ENFORCE_EQ(c0.initialized(),
true,
common::errors::InvalidArgument(
"Input(Cell) and Input(Hidden) of LSTM should exist "
"at the same time."));
const auto& h_dims = h0.dims();
const auto& c_dims = c0.dims();
PADDLE_ENFORCE_EQ(
h_dims,
c_dims,
common::errors::InvalidArgument(
"The dimension of Input(H0) and Input(C0) "
"should be the same, but received H0 dim is:[%s], C0 dim is[%s]",
h_dims,
c_dims));
}
const auto& wh_dims = weight_h.dims();
int64_t frame_size = wh_dims[1] / 4;
PADDLE_ENFORCE_EQ(
wh_dims.size(),
2,
common::errors::InvalidArgument(
"The rank of Input(WeightH) should be 2, but received value is:%d.",
wh_dims.size()));
PADDLE_ENFORCE_EQ(wh_dims[0],
frame_size,
common::errors::InvalidArgument(
"The first dimension of Input(WeightH) should equal to "
"frame size:%d, but received value is:%d.",
frame_size,
wh_dims[0]));
PADDLE_ENFORCE_EQ(wh_dims[1],
4 * frame_size,
common::errors::InvalidArgument(
"The second dimension of Input(WeightH) should equal "
"to 4 * %d, but received value is:%d.",
frame_size,
wh_dims[1]));
const auto& b_dims = bias.dims();
PADDLE_ENFORCE_EQ(
b_dims.size(),
2,
common::errors::InvalidArgument(
"The rank of Input(Bias) should be 2, but received value is:%d.",
b_dims.size()));
PADDLE_ENFORCE_EQ(
b_dims[0],
1,
common::errors::InvalidArgument("The first dimension of Input(Bias) "
"should be 1, but received value is:%d.",
b_dims[0]));
PADDLE_ENFORCE_EQ(
b_dims[1],
(use_peepholes ? 7 : 4) * frame_size,
common::errors::InvalidArgument(
"The second dimension of Input(Bias) should be "
"7 * %d if enable peepholes connection or"
"4 * %d if disable peepholes, bias dim is:%d, use_peepholes:%d",
frame_size,
frame_size,
b_dims[1],
use_peepholes));
DDim out_dims({x_dims[0], frame_size});
hidden->set_dims(out_dims);
cell->set_dims(out_dims);
hidden->share_lod(ids);
cell->share_lod(ids);
hidden->set_dtype(embeddings.dtype());
cell->set_dtype(embeddings.dtype());
if (!use_seq) {
batched_input->set_dims({x_dims[0], wh_dims[1]});
batched_hidden->set_dims(out_dims);
batched_cell->set_dims(out_dims);
batched_input->set_dtype(embeddings.dtype());
batched_hidden->set_dtype(embeddings.dtype());
batched_cell->set_dtype(embeddings.dtype());
}
xx->set_dims({x_dims[0], wh_dims[1]});
xx->share_lod(ids);
xx->set_dtype(embeddings.dtype());
}
void FusionSeqpoolConcatInferMeta(const std::vector<const MetaTensor*>& x,
const std::string& pooltype,
int axis,
MetaTensor* out,
MetaConfig config) {
PADDLE_ENFORCE_GE(x.size(),
1UL,
common::errors::InvalidArgument(
"Inputs(X) of FusionSeqPoolConcatOp should be greater "
"than 1, but received value is %d.",
x.size()));
PADDLE_ENFORCE_EQ(axis,
1,
common::errors::InvalidArgument(
"FusionSeqPoolConcatOp only supports concat "
"axis=1 yet, but received axis value is %d",
axis));
std::vector<DDim> ins_dims;
ins_dims.reserve(x.size());
std::transform(x.begin(),
x.end(),
std::back_inserter(ins_dims),
[](const MetaTensor* var) { return var->dims(); });
const size_t n = ins_dims.size();
PADDLE_ENFORCE_GT(n,
0UL,
common::errors::InvalidArgument(
"Input tensors count should be greater than 0, "
"but received value is %d.",
n));
// The output height should be confirmed in Compute,
// since input lod is not accessible here.
PADDLE_ENFORCE_EQ(ins_dims[0].size(),
2,
common::errors::InvalidArgument(
"The dims size of first input should be equal to 2, "
"but received value is %d.",
ins_dims[0].size()));
out->set_dims({-1, ins_dims[0][axis] * static_cast<int64_t>(n)});
out->set_dtype(x[0]->dtype());
}
// Shape of bitmask
static DDim GetBitmaskDims(std::vector<int64_t> out_shape) {
int64_t c = out_shape.back();
int64_t nhw = std::accumulate(out_shape.begin(),
out_shape.end(),
1,
std::multiplies<int64_t>()) / // NOLINT
c;
int64_t c_int32_elems = ((c + 63) & ~63) / 32;
int64_t nhw_int32_elems = ((nhw + 31) & ~31);
std::vector<int64_t> bitmask_shape = {nhw_int32_elems, c_int32_elems, 1};
return make_ddim(bitmask_shape);
}
void FusedSwigluWeightedBwdInferMeta(const MetaTensor& o1,
const MetaTensor& do2_s,
const MetaTensor& unzipped_probs,
MetaTensor* do1,
MetaTensor* probs_grad,
MetaTensor* o2_s) {
PADDLE_ENFORCE_EQ(
o1.dtype(),
DataType::BFLOAT16,
common::errors::InvalidArgument("The data type of o1 must be bfloat16. "
"But received o1 dtype: %s",
DataTypeToString(o1.dtype())));
PADDLE_ENFORCE_EQ(do2_s.dtype(),
DataType::BFLOAT16,
common::errors::InvalidArgument(
"The data type of do2_s must be bfloat16. "
"But received do2_s dtype: %s",
DataTypeToString(do2_s.dtype())));
PADDLE_ENFORCE_EQ(unzipped_probs.dtype(),
DataType::FLOAT32,
common::errors::InvalidArgument(
"The data type of unzipped_probs must be float32. "
"But received unzipped_probs dtype: %s",
DataTypeToString(unzipped_probs.dtype())));
auto o1_dims = o1.dims();
auto do2_s_dims = do2_s.dims();
auto probs_dims = unzipped_probs.dims();
PADDLE_ENFORCE_EQ(
o1_dims.size(),
do2_s_dims.size(),
common::errors::InvalidArgument(
"o1 and do2_s should have the same number of dimensions. "
"But received o1 dims: %d, do2_s dims: %d",
o1_dims.size(),
do2_s_dims.size()));
PADDLE_ENFORCE_EQ(
o1_dims.size(),
probs_dims.size(),
common::errors::InvalidArgument(
"o1 and unzipped_probs should have the same number of dimensions. "
"But received o1 dims: %d, unzipped_probs dims: %d",
o1_dims.size(),
probs_dims.size()));
int64_t o1_last_dim = o1_dims[o1_dims.size() - 1];
int64_t do2_s_last_dim = do2_s_dims[do2_s_dims.size() - 1];
PADDLE_ENFORCE_EQ(o1_last_dim,
do2_s_last_dim * 2,
common::errors::InvalidArgument(
"The last dimension of o1 should be twice the last "
"dimension of do2_s. "
"But received o1 last dim: %d, do2_s last dim: %d",
o1_last_dim,
do2_s_last_dim));
int64_t o1_batch_size = 1;
int64_t do2_s_batch_size = 1;
int64_t probs_batch_size = 1;
for (int i = 0; i < o1_dims.size() - 1; i++) {
o1_batch_size *= o1_dims[i];
do2_s_batch_size *= do2_s_dims[i];
probs_batch_size *= probs_dims[i];
}
PADDLE_ENFORCE_EQ(o1_batch_size,
do2_s_batch_size,
common::errors::InvalidArgument(
"o1 and do2_s should have the same batch size (product "
"of all dimensions except last). "
"But received o1 batch size: %d, do2_s batch size: %d",
o1_batch_size,
do2_s_batch_size));
PADDLE_ENFORCE_EQ(o1_batch_size,
probs_batch_size,
common::errors::InvalidArgument(
"o1 and unzipped_probs should have the same batch size "
"(product of all dimensions except last). "
"But received o1 batch size: %d, probs batch size: %d",
o1_batch_size,
probs_batch_size));
do1->set_dims(o1_dims);
do1->set_dtype(o1.dtype());
do1->set_layout(o1.layout());
probs_grad->set_dims(probs_dims);
probs_grad->set_dtype(DataType::FLOAT32);
probs_grad->set_layout(unzipped_probs.layout());
o2_s->set_dims(do2_s_dims);
o2_s->set_dtype(do2_s.dtype());
o2_s->set_layout(do2_s.layout());
}
void FusedWeightedSwigluActQuantInferMeta(const MetaTensor& x,
const MetaTensor& prob,
bool using_pow2_scaling,
MetaTensor* out,
MetaTensor* scale) {
PADDLE_ENFORCE_EQ(
x.dtype(),
DataType::BFLOAT16,
common::errors::InvalidArgument(
"The dtype of Input(x) must be BFLOAT16, but received %s",
x.dtype()));
if (prob) {
PADDLE_ENFORCE_EQ(
prob.dtype(),
DataType::FLOAT32,
common::errors::InvalidArgument(
"The dtype of Input(prob) must be FLOAT32, but received %s",
prob.dtype()));
}
int64_t rows = 1;
for (int i = 0; i < x.dims().size() - 1; ++i) {
rows *= x.dims()[i];
}
int64_t cols = x.dims()[x.dims().size() - 1];
PADDLE_ENFORCE_EQ(cols % 2,
0,
common::errors::InvalidArgument(
"The last dim of Input(X) should be exactly divided "
"by 2 , but got %d",
cols));
if (prob) {
PADDLE_ENFORCE_EQ(prob.dims()[0],
rows,
common::errors::InvalidArgument(
"The first dim of Input(x) should be equal to the "
"first dim of Input(prob) but got X.shape[0]: %d, "
"prob.shape[0]: %d",
rows,
prob.dims()[0]));
}
out->set_dims(make_ddim({rows, cols / 2}));
out->set_dtype(DataType::FLOAT8_E4M3FN);
scale->set_dims(make_ddim({rows, ((cols / 2) + 127) / 128}));
scale->set_dtype(DataType::FLOAT32);
}
void ResnetUnitInferMeta(const MetaTensor& x,
const MetaTensor& filter_x,
const MetaTensor& scale_x,
const MetaTensor& bias_x,
const MetaTensor& mean_x,
const MetaTensor& var_x,
const MetaTensor& z,
const MetaTensor& filter_z,
const MetaTensor& scale_z,
const MetaTensor& bias_z,
const MetaTensor& mean_z,
const MetaTensor& var_z,
int stride,
int stride_z,
int padding,
int dilation,
int group,
float momentum,
float epsilon,
const std::string& data_format,
bool fuse_add,
bool has_shortcut,
bool use_global_stats,
bool is_test,
bool use_addto,
const std::string& act_type,
MetaTensor* out,
MetaTensor* bit_mask,
MetaTensor* conv_x,
MetaTensor* saved_mean_x,
MetaTensor* saved_invstd_x,
MetaTensor* running_mean_x,
MetaTensor* running_var_x,
MetaTensor* conv_z,
MetaTensor* saved_mean_z,
MetaTensor* saved_invstd_z,
MetaTensor* running_mean_z,
MetaTensor* running_var_z) {
// Check dims of inputs
const auto& x_dims = x.dims();
const auto& w_dims = filter_x.dims();
std::vector<int64_t> bn_param_shape = vectorize(scale_x.dims());
if (1 == bn_param_shape.size()) {
bn_param_shape = {1, 1, 1, bn_param_shape[0]};
}
DDim bn_param_dims = make_ddim(bn_param_shape);
PADDLE_ENFORCE_EQ(
x_dims.size(),
4,
common::errors::InvalidArgument("The dimensions of input "
"must equal to 4."
"But received: the shape of input "
"= [%s], the dimension of input = "
"[%d]",
x_dims,
x_dims.size()));
PADDLE_ENFORCE_EQ(
w_dims.size(),
4,
common::errors::InvalidArgument("The dimensions of filter "
"must equal to 4."
"But received: the shape of filter "
"= [%s], the dimension of filter = [%d] ",
w_dims,
w_dims.size()));
PADDLE_ENFORCE_EQ(bn_param_dims.size(),
4,
common::errors::InvalidArgument(
"The dimensions of bn param "
"must equal to 4."
"But received: the shape of bn param "
"= [%s], the dimension of bn param = [%d] ",
bn_param_dims,
bn_param_dims.size()));
bool is_nchw = (data_format == "NCHW");
// Calculate the dims of outputs
int64_t batch = x_dims[0];
int64_t output_channel = w_dims[0];
int64_t filter_size = w_dims[2];
std::vector<int64_t> out_shape;
out_shape.push_back(batch);
if (is_nchw) {
int64_t out_h = (x_dims[2] + padding * 2 - filter_size) / stride + 1;
int64_t out_w = (x_dims[3] + padding * 2 - filter_size) / stride + 1;
out_shape.push_back(output_channel);
out_shape.push_back(out_h);
out_shape.push_back(out_w);
} else {
int64_t out_h = (x_dims[1] + padding * 2 - filter_size) / stride + 1;
int64_t out_w = (x_dims[2] + padding * 2 - filter_size) / stride + 1;
out_shape.push_back(out_h);
out_shape.push_back(out_w);
out_shape.push_back(output_channel);
}
auto y_dims = make_ddim(out_shape);
auto bitmask_dims = GetBitmaskDims(out_shape);
// Set dims of outputs
out->set_dims(y_dims);
bit_mask->set_dims(bitmask_dims);
conv_x->set_dims(y_dims);
saved_mean_x->set_dims(bn_param_dims);
saved_invstd_x->set_dims(bn_param_dims);
running_mean_x->set_dims(bn_param_dims);
running_var_x->set_dims(bn_param_dims);
out->set_dtype(x.dtype());
bit_mask->set_dtype(filter_x.dtype());
conv_x->set_dtype(x.dtype());
saved_mean_x->set_dtype(mean_x.dtype());
saved_invstd_x->set_dtype(var_x.dtype());
running_mean_x->set_dtype(mean_x.dtype());
running_var_x->set_dtype(var_x.dtype());
if (has_shortcut) {
conv_z->set_dims(y_dims);
saved_mean_z->set_dims(bn_param_dims);
saved_invstd_z->set_dims(bn_param_dims);
running_mean_z->set_dims(bn_param_dims);
running_var_z->set_dims(bn_param_dims);
conv_z->set_dtype(z.dtype());
saved_mean_z->set_dtype(mean_z.dtype());
saved_invstd_z->set_dtype(var_z.dtype());
running_mean_z->set_dtype(mean_z.dtype());
running_var_z->set_dtype(var_z.dtype());
}
}
void ResnetUnitGradInferMeta(const MetaTensor& x,
const MetaTensor& filter_x,
const MetaTensor& conv_x,
const MetaTensor& scale_x,
const MetaTensor& bias_x,
const MetaTensor& saved_mean_x,
const MetaTensor& saved_invstd_x,
const MetaTensor& z,
const MetaTensor& filter_z,
const MetaTensor& conv_z,
const MetaTensor& scale_z,
const MetaTensor& bias_z,
const MetaTensor& saved_mean_z,
const MetaTensor& saved_invstd_z,
const MetaTensor& out,
const MetaTensor& bit_mask,
const MetaTensor& out_grad,
int stride,
int stride_z,
int padding,
int dilation,
int group,
float momentum,
float epsilon,
const std::string& data_format,
bool fuse_add,
bool has_shortcut,
bool use_global_stats,
bool is_test,
bool use_addto,
const std::string& act_type,
MetaTensor* x_grad,
MetaTensor* filter_x_grad,
MetaTensor* scale_x_grad,
MetaTensor* bias_x_grad,
MetaTensor* z_grad,
MetaTensor* filter_z_grad,
MetaTensor* scale_z_grad,
MetaTensor* bias_z_grad) {
const auto& x_dims = x.dims();
const auto& filter_x_dims = filter_x.dims();
const auto& param_dims = scale_x.dims();
x_grad->set_dims(x_dims);
filter_x_grad->set_dims(filter_x_dims);
scale_x_grad->set_dims(param_dims);
bias_x_grad->set_dims(param_dims);
x_grad->set_dtype(x.dtype());
filter_x_grad->set_dtype(filter_x.dtype());
scale_x_grad->set_dtype(scale_x.dtype());
bias_x_grad->set_dtype(bias_x.dtype());
if (fuse_add || has_shortcut) {
const auto& z_dims = z.dims();
z_grad->set_dims(z_dims);
z_grad->set_dtype(z.dtype());
}
if (has_shortcut) {
const auto filter_z_dims = filter_z.dims();
filter_z_grad->set_dims(filter_z_dims);
scale_z_grad->set_dims(param_dims);
bias_z_grad->set_dims(param_dims);
filter_z_grad->set_dtype(filter_z.dtype());
scale_z_grad->set_dtype(scale_z.dtype());
bias_z_grad->set_dtype(bias_z.dtype());
}
}
void FusedGateAttentionInferMeta(const MetaTensor& query,
const MetaTensor& key,
const MetaTensor& query_weight,
const MetaTensor& key_weight,
const MetaTensor& value_weight,
const MetaTensor& qkv_weight,
const MetaTensor& nonbatched_bias,
const MetaTensor& src_mask,
const MetaTensor& gate_weight,
const MetaTensor& gate_bias,
const MetaTensor& out_linear_weight,
const MetaTensor& out_linear_bias,
bool has_gating,
bool merge_qkv,
bool use_flash_attn,
MetaTensor* query_transpose_out,
MetaTensor* key_transpose_out,
MetaTensor* value_transpose_out,
MetaTensor* qkv_transpose_out,
MetaTensor* softmax_out,
MetaTensor* softmax_lse,
MetaTensor* fmha_out,
MetaTensor* gate_out,
MetaTensor* out,
MetaConfig config) {
const auto& input_q_dims = query.dims();
int64_t batch_size = input_q_dims[0];
int64_t seq_len_m = input_q_dims[1];
int64_t seq_len_r = input_q_dims[2];
int64_t num_head, m_size, head_dim;
if (merge_qkv) {
// QKV's input: [batch_size, seq_len_m, seq_len_r, qkv_dim]
// QKV's weight: [3, num_head, head_dim, qkv_dim]
const auto& qkv_w_dims = qkv_weight.dims();
num_head = qkv_w_dims[1];
head_dim = qkv_w_dims[2];
m_size = seq_len_r;
qkv_transpose_out->set_dims(
{3, batch_size, seq_len_m, num_head, seq_len_r, head_dim});
qkv_transpose_out->set_dtype(query.dtype());
} else {
const auto& input_k_dims = key.dims();
const auto& q_w_dims = query_weight.dims();
num_head = q_w_dims[1];
head_dim = q_w_dims[2];
m_size = input_k_dims[2];
query_transpose_out->set_dims(
{batch_size, seq_len_m, num_head, seq_len_r, head_dim});
key_transpose_out->set_dims(
{batch_size, seq_len_m, num_head, m_size, head_dim});
value_transpose_out->set_dims(
{batch_size, seq_len_m, num_head, m_size, head_dim});
query_transpose_out->set_dtype(query.dtype());
key_transpose_out->set_dtype(query.dtype());
value_transpose_out->set_dtype(query.dtype());
}
softmax_out->set_dims({batch_size, seq_len_m, num_head, seq_len_r, m_size});
fmha_out->set_dims({batch_size, seq_len_m, seq_len_r, num_head, head_dim});
softmax_out->set_dtype(query.dtype());
fmha_out->set_dtype(query.dtype());
if (has_gating) {
gate_out->set_dims({batch_size, seq_len_m, seq_len_r, num_head, head_dim});
gate_out->set_dtype(query.dtype());
}
out->set_dims(query.dims());
out->set_dtype(query.dtype());
}
void FusedGateAttentionGradInferMeta(const MetaTensor& query,
const MetaTensor& key,
const MetaTensor& query_weight,
const MetaTensor& key_weight,
const MetaTensor& value_weight,
const MetaTensor& qkv_weight,
const MetaTensor& nonbatched_bias,
const MetaTensor& src_mask,
const MetaTensor& gate_weight,
const MetaTensor& gate_bias,
const MetaTensor& out_linear_weight,
const MetaTensor& out_linear_bias,
const MetaTensor& query_transpose_out,
const MetaTensor& key_transpose_out,
const MetaTensor& value_transpose_out,
const MetaTensor& qkv_transpose_out,
const MetaTensor& softmax_out,
const MetaTensor& softmax_lse,
const MetaTensor& fmha_out,
const MetaTensor& gate_out,
const MetaTensor& out_grad,
bool has_gating,
bool merge_qkv,
bool use_flash_attn,
MetaTensor* query_grad,
MetaTensor* key_grad,
MetaTensor* query_weight_grad,
MetaTensor* key_weight_grad,
MetaTensor* value_weight_grad,
MetaTensor* qkv_weight_grad,
MetaTensor* nonbatched_bias_grad,
MetaTensor* gate_weight_grad,
MetaTensor* gate_bias_grad,
MetaTensor* out_linear_weight_grad,
MetaTensor* out_linear_bias_grad,
MetaConfig config) {
if (query_grad != nullptr) {
query_grad->set_dims(query.dims());
query_grad->set_dtype(query.dtype());
}
if (key_grad != nullptr) {
key_grad->set_dims(key.dims());
key_grad->set_dtype(key.dtype());
}
if (merge_qkv) {
qkv_weight_grad->set_dims(qkv_weight.dims());
qkv_weight_grad->set_dtype(qkv_weight.dtype());
} else {
query_weight_grad->set_dims(query_weight.dims());
key_weight_grad->set_dims(key_weight.dims());
value_weight_grad->set_dims(value_weight.dims());
query_weight_grad->set_dtype(query_weight.dtype());
key_weight_grad->set_dtype(key_weight.dtype());
value_weight_grad->set_dtype(value_weight.dtype());
}
if (has_gating) {
gate_weight_grad->set_dims(gate_weight.dims());
gate_bias_grad->set_dims(gate_bias.dims());
gate_weight_grad->set_dtype(gate_weight.dtype());
gate_bias_grad->set_dtype(gate_bias.dtype());
}
if (nonbatched_bias_grad != nullptr) {
nonbatched_bias_grad->set_dims(nonbatched_bias.dims());
nonbatched_bias_grad->set_dtype(nonbatched_bias.dtype());
}
out_linear_weight_grad->set_dims(out_linear_weight.dims());
out_linear_bias_grad->set_dims(out_linear_bias.dims());
out_linear_weight_grad->set_dtype(out_linear_weight.dtype());
out_linear_bias_grad->set_dtype(out_linear_bias.dtype());
}
void ResnetBasicBlockInferMeta(const MetaTensor& x,
const MetaTensor& filter1,
const MetaTensor& scale1,
const MetaTensor& bias1,
const MetaTensor& mean1,
const MetaTensor& var1,
const MetaTensor& filter2,
const MetaTensor& scale2,
const MetaTensor& bias2,
const MetaTensor& mean2,
const MetaTensor& var2,
const MetaTensor& filter3,
const MetaTensor& scale3,
const MetaTensor& bias3,
const MetaTensor& mean3,
const MetaTensor& var3,
int stride1,
int stride2,
int stride3,
int padding1,
int padding2,
int padding3,
int dilation1,
int dilation2,
int dilation3,
int group,
float momentum,
float epsilon,
const std::string& data_format,
bool has_shortcut,
bool use_global_stats,
bool is_test,
bool trainable_statistics,
const std::string& act_type,
bool find_conv_input_max,
MetaTensor* out,
MetaTensor* conv1,
MetaTensor* saved_mean1,
MetaTensor* saved_invstd1,
MetaTensor* mean1_out,
MetaTensor* var1_out,
MetaTensor* conv2,
MetaTensor* conv2_input,
MetaTensor* saved_mean2,
MetaTensor* saved_invstd2,
MetaTensor* mean2_out,
MetaTensor* var2_out,
MetaTensor* conv3,
MetaTensor* saved_mean3,
MetaTensor* saved_invstd3,
MetaTensor* mean3_out,
MetaTensor* var3_out,
MetaTensor* max_input1,
MetaTensor* max_filter1,
MetaTensor* max_input2,
MetaTensor* max_filter2,
MetaTensor* max_input3,
MetaTensor* max_filter3,
MetaConfig config) {
PADDLE_ENFORCE_EQ(
data_format,
"NCHW",
common::errors::InvalidArgument("The data format must equal to NCHW. "
"But received: the data format "
"= [%s]",
data_format));
const auto& x1_dims = x.dims();
const auto& w1_dims = filter1.dims();
const auto& bn1_param_dims = scale1.dims();
PADDLE_ENFORCE_EQ(
x1_dims.size(),
4,
common::errors::InvalidArgument("The dimensions of input "
"must equal to 4."
"But received: the shape of input "
"= [%s], the dimension of input = "
"[%d]",
x1_dims,
x1_dims.size()));
// Calculate the dims of output1
int64_t batch = x1_dims[0];
int64_t output1_channel = w1_dims[0];
int64_t filter1_size = w1_dims[2];
int64_t out1_h = (x1_dims[2] + padding1 * 2 - filter1_size) / stride1 + 1;
int64_t out1_w = (x1_dims[3] + padding1 * 2 - filter1_size) / stride1 + 1;
std::vector<int64_t> out1_shape = {batch, output1_channel, out1_h, out1_w};
const auto& w2_dims = filter2.dims();
const auto& bn2_param_dims = scale2.dims();
int64_t output2_channel = w2_dims[0];
int64_t filter2_size = w2_dims[2];
int64_t out2_h = (out1_h + padding2 * 2 - filter2_size) / stride2 + 1;
int64_t out2_w = (out1_w + padding2 * 2 - filter2_size) / stride2 + 1;
std::vector<int64_t> out2_shape = {batch, output2_channel, out2_h, out2_w};
auto y_dims = make_ddim(out2_shape);
auto conv1_dims = make_ddim(out1_shape);
out->set_dims(y_dims);
conv1->set_dims(conv1_dims);
saved_mean1->set_dims(bn1_param_dims);
saved_invstd1->set_dims(bn1_param_dims);
mean1_out->set_dims(bn1_param_dims);
var1_out->set_dims(bn1_param_dims);
conv2->set_dims(y_dims);
conv2_input->set_dims(conv1_dims);
saved_mean2->set_dims(bn2_param_dims);
saved_invstd2->set_dims(bn2_param_dims);
mean2_out->set_dims(bn2_param_dims);
var2_out->set_dims(bn2_param_dims);
out->set_dtype(x.dtype());
conv1->set_dtype(x.dtype());
saved_mean1->set_dtype(DataType::FLOAT32);
saved_invstd1->set_dtype(DataType::FLOAT32);
mean1_out->set_dtype(DataType::FLOAT32);
var1_out->set_dtype(DataType::FLOAT32);
conv2->set_dtype(x.dtype());
conv2_input->set_dtype(x.dtype());
saved_mean2->set_dtype(DataType::FLOAT32);
saved_invstd2->set_dtype(DataType::FLOAT32);
mean2_out->set_dtype(DataType::FLOAT32);
var2_out->set_dtype(DataType::FLOAT32);
if (has_shortcut) {
conv3->set_dims(y_dims);
saved_mean3->set_dims(bn2_param_dims);
saved_invstd3->set_dims(bn2_param_dims);
mean3_out->set_dims(bn2_param_dims);
var3_out->set_dims(bn2_param_dims);
conv3->set_dtype(x.dtype());
saved_mean3->set_dtype(DataType::FLOAT32);
saved_invstd3->set_dtype(DataType::FLOAT32);
mean3_out->set_dtype(DataType::FLOAT32);
var3_out->set_dtype(DataType::FLOAT32);
}
bool find_max = find_conv_input_max;
if (find_max) {
auto max_dims = make_ddim({6});
max_input1->set_dims(max_dims);
max_filter1->set_dims(max_dims);
max_input2->set_dims(max_dims);
max_filter2->set_dims(max_dims);
max_input1->set_dtype(x.dtype());
max_filter1->set_dtype(filter1.dtype());
max_input2->set_dtype(DataType::FLOAT32);
max_filter2->set_dtype(DataType::FLOAT32);
if (has_shortcut) {
max_input3->set_dims(max_dims);
max_filter3->set_dims(max_dims);
max_input3->set_dtype(DataType::FLOAT32);
max_filter3->set_dtype(DataType::FLOAT32);
}
}
}
void ResnetBasicBlockGradInferMeta(const MetaTensor& x,
const MetaTensor& filter1,
const MetaTensor& conv1,
const MetaTensor& scale1,
const MetaTensor& bias1,
const MetaTensor& saved_mean1,
const MetaTensor& saved_invstd1,
const MetaTensor& filter2,
const MetaTensor& conv2,
const MetaTensor& conv2_input,
const MetaTensor& scale2,
const MetaTensor& bias2,
const MetaTensor& saved_mean2,
const MetaTensor& saved_invstd2,
const MetaTensor& filter3,
const MetaTensor& conv3,
const MetaTensor& scale3,
const MetaTensor& bias3,
const MetaTensor& saved_mean3,
const MetaTensor& saved_invstd3,
const MetaTensor& max_input1,
const MetaTensor& max_filter1,
const MetaTensor& max_input2,
const MetaTensor& max_filter2,
const MetaTensor& max_input3,
const MetaTensor& max_filter3,
const MetaTensor& out,
const MetaTensor& out_grad,
int stride1,
int stride2,
int stride3,
int padding1,
int padding2,
int padding3,
int dilation1,
int dilation2,
int dilation3,
int group,
float momentum,
float epsilon,
const std::string& data_format,
bool has_shortcut,
bool use_global_stats,
bool is_test,
bool trainable_statistics,
const std::string& act_type,
bool find_conv_input_max,
MetaTensor* x_grad,
MetaTensor* filter1_grad,
MetaTensor* scale1_grad,
MetaTensor* bias1_grad,
MetaTensor* filter2_grad,
MetaTensor* scale2_grad,
MetaTensor* bias2_grad,
MetaTensor* filter3_grad,
MetaTensor* scale3_grad,
MetaTensor* bias3_grad,
MetaConfig config) {
const auto& x1_dims = x.dims();
const auto& filter1_x_dims = filter1.dims();
const auto& param1_dims = scale1.dims();
const auto& filter2_x_dims = filter2.dims();
const auto& param2_dims = scale2.dims();
x_grad->set_dims(x1_dims);
filter1_grad->set_dims(filter1_x_dims);
scale1_grad->set_dims(param1_dims);
bias1_grad->set_dims(param1_dims);
filter2_grad->set_dims(filter2_x_dims);
scale2_grad->set_dims(param2_dims);
bias2_grad->set_dims(param2_dims);
x_grad->set_dtype(x.dtype());
filter1_grad->set_dtype(x.dtype());
filter2_grad->set_dtype(x.dtype());
scale1_grad->set_dtype(DataType::FLOAT32);
bias1_grad->set_dtype(DataType::FLOAT32);
scale2_grad->set_dtype(DataType::FLOAT32);
bias2_grad->set_dtype(DataType::FLOAT32);
if (has_shortcut) {
const auto& filter_z_dims = filter3.dims();
filter3_grad->set_dims(filter_z_dims);
scale3_grad->set_dims(param2_dims);
bias3_grad->set_dims(param2_dims);
filter3_grad->set_dtype(x.dtype());
scale3_grad->set_dtype(DataType::FLOAT32);
bias3_grad->set_dtype(DataType::FLOAT32);
}
}
} // namespace phi