5148 lines
180 KiB
C++
5148 lines
180 KiB
C++
/* Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License. */
|
|
|
|
#include "paddle/phi/infermeta/binary.h"
|
|
|
|
#include <algorithm>
|
|
#include <vector>
|
|
|
|
#include "glog/logging.h"
|
|
#include "paddle/common/ddim.h"
|
|
#include "paddle/common/flags.h"
|
|
#include "paddle/common/layout.h"
|
|
#include "paddle/phi/api/lib/data_type_set.h"
|
|
#include "paddle/phi/backends/onednn/onednn_helper.h"
|
|
#include "paddle/phi/common/data_type.h"
|
|
#include "paddle/phi/common/type_traits.h"
|
|
#include "paddle/phi/core/infermeta_utils.h"
|
|
#include "paddle/phi/core/utils/data_type.h"
|
|
#include "paddle/phi/infermeta/unary.h"
|
|
#include "paddle/phi/kernels/cpu/conv_util.h"
|
|
#include "paddle/phi/kernels/funcs/axis_utils.h"
|
|
#include "paddle/phi/kernels/funcs/common_infer_shape_functions.h"
|
|
#include "paddle/phi/kernels/funcs/common_shape.h"
|
|
#include "paddle/phi/kernels/funcs/correlation_funcs.h"
|
|
|
|
COMMON_DECLARE_bool(manually_trans_conv_filter);
|
|
|
|
namespace phi {
|
|
namespace detail {
|
|
|
|
static void BinarySameInputDimsCheck(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
MetaConfig config) {
|
|
auto input_dim = x.dims();
|
|
auto other_dim = y.dims();
|
|
PADDLE_ENFORCE_EQ(input_dim.size(),
|
|
other_dim.size(),
|
|
common::errors::PreconditionNotMet(
|
|
"Input(Input) and Input(Other) must have the same "
|
|
"dimension size."));
|
|
int n = input_dim.size();
|
|
bool is_runtime = config.is_runtime;
|
|
for (int i = 0; i < n; i++) {
|
|
if (is_runtime) {
|
|
PADDLE_ENFORCE_EQ(input_dim[i],
|
|
other_dim[i],
|
|
common::errors::PreconditionNotMet(
|
|
"The value at dim %d of Input(Input) is not "
|
|
"equal to the Input(Other): %ld != %ld.",
|
|
i,
|
|
input_dim[i],
|
|
other_dim[i]));
|
|
} else {
|
|
if (!(input_dim[i] < 0 || other_dim[i] < 0)) {
|
|
PADDLE_ENFORCE_EQ(input_dim[i],
|
|
other_dim[i],
|
|
common::errors::PreconditionNotMet(
|
|
"The value at dim %d of Input(Input) is not "
|
|
"equal to the Input(Other): %ld != %ld.",
|
|
i,
|
|
input_dim[i],
|
|
other_dim[i]));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Used in MatrixRankTolInferMeta
|
|
static DDim CheckAndGetOutputDim(const DDim& dim_x) {
|
|
auto x_vec = vectorize(dim_x);
|
|
if (x_vec.size() == 2) {
|
|
return make_ddim({});
|
|
}
|
|
x_vec.erase(x_vec.end() - 2, x_vec.end());
|
|
return make_ddim(x_vec);
|
|
}
|
|
|
|
} // namespace detail
|
|
|
|
void AllValueCompareInferMeta(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
if (x.numel() != 0 && y.numel() != 0) {
|
|
detail::BinarySameInputDimsCheck(x, y, config);
|
|
}
|
|
out->set_dims(make_ddim({}));
|
|
out->set_dtype(DataType::BOOL);
|
|
}
|
|
|
|
void KLDivInferMeta(const MetaTensor& x,
|
|
const MetaTensor& label,
|
|
const std::string& reduction,
|
|
bool log_target,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
auto dim_x = x.dims();
|
|
auto dim_target = label.dims();
|
|
PADDLE_ENFORCE_EQ(dim_x.size(),
|
|
dim_target.size(),
|
|
common::errors::InvalidArgument(
|
|
"Input(X) rank and Input(Target) rank should be "
|
|
"same, but received X rank(%d) != Target rank(%d)",
|
|
dim_x.size(),
|
|
dim_target.size()));
|
|
for (int i = 0; i < dim_x.size(); i++) {
|
|
if (config.is_runtime || (dim_x[i] > 0 && dim_target[i] > 0)) {
|
|
PADDLE_ENFORCE_EQ(
|
|
dim_x[i],
|
|
dim_target[i],
|
|
common::errors::InvalidArgument(
|
|
"Input(X) and Input(Target) should in same shape. but received "
|
|
"X dimension[%d](%d) != Target dimension[%d](%d)",
|
|
i,
|
|
dim_x[i],
|
|
i,
|
|
dim_target[i]));
|
|
}
|
|
}
|
|
|
|
auto reduction_valid = "mean" == reduction || "sum" == reduction ||
|
|
"batchmean" == reduction || "none" == reduction;
|
|
PADDLE_ENFORCE_EQ(
|
|
reduction_valid,
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"Attr(reduction) can only be 'none'|'batchmean'|'sum'|'mean'."));
|
|
|
|
if ("none" == reduction) {
|
|
out->set_dims(dim_x);
|
|
} else {
|
|
out->set_dims(make_ddim({}));
|
|
}
|
|
out->set_dtype(x.dtype());
|
|
}
|
|
|
|
void ArrayWriteInferMeta(const MetaTensor& array,
|
|
const MetaTensor& x,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
DataType out_dtype = array.dtype();
|
|
if (x.dtype() != DataType::UNDEFINED) {
|
|
if (array.dtype() == DataType::UNDEFINED) {
|
|
out_dtype = x.dtype();
|
|
} else {
|
|
PADDLE_ENFORCE_EQ(array.dtype(),
|
|
x.dtype(),
|
|
common::errors::InvalidArgument(
|
|
"The dtype (%s) of input x shall be same as "
|
|
"dtype (%d) of array.",
|
|
x.dtype(),
|
|
array.dtype()));
|
|
}
|
|
}
|
|
out->set_dtype(out_dtype);
|
|
out->set_layout(array.layout());
|
|
}
|
|
|
|
void ArrayReadInferMeta(const MetaTensor& array,
|
|
const Scalar& i,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
if (!config.is_runtime) {
|
|
auto dims = array.dims();
|
|
if (dims.size() > 1) {
|
|
for (int i = 0; i < dims.size(); ++i) {
|
|
dims[i] = -1;
|
|
}
|
|
out->set_dims(dims);
|
|
} else {
|
|
out->set_dims({-1});
|
|
}
|
|
} else {
|
|
double index = i.to<int64_t>();
|
|
out->set_dims(array.dims(index)); // NOLINT
|
|
out->share_lod(array, index); // NOLINT
|
|
}
|
|
out->set_dtype(array.dtype());
|
|
out->set_layout(array.layout());
|
|
}
|
|
|
|
void Atan2InferMeta(const MetaTensor& x, const MetaTensor& y, MetaTensor* out) {
|
|
ElementwiseInferMeta(x, y, out);
|
|
if (out->dtype() == DataType::INT32 || out->dtype() == DataType::INT64) {
|
|
out->set_dtype(DataType::FLOAT64);
|
|
}
|
|
}
|
|
|
|
void BCELossInferMeta(const MetaTensor& input,
|
|
const MetaTensor& label,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
auto input_dims = input.dims();
|
|
auto label_dims = label.dims();
|
|
|
|
int rank = input_dims.size();
|
|
PADDLE_ENFORCE_EQ(rank,
|
|
label_dims.size(),
|
|
common::errors::InvalidArgument(
|
|
"Input(X) and Input(Label) shall have the same rank."
|
|
"But received: the rank of Input(X) is [%d], "
|
|
"the rank of Input(Label) is [%d].",
|
|
rank,
|
|
label_dims.size()));
|
|
|
|
bool check = true;
|
|
if ((!config.is_runtime) &&
|
|
(contain_unknown_dim(input_dims) || contain_unknown_dim(label_dims))) {
|
|
check = false;
|
|
}
|
|
|
|
if (check) {
|
|
PADDLE_ENFORCE_EQ(input_dims,
|
|
label_dims,
|
|
common::errors::InvalidArgument(
|
|
"Input(X) and Input(Label) shall have the same "
|
|
"shape. But received: the shape of Input(X) is "
|
|
"[%s], the shape of Input(Label) is [%s].",
|
|
input_dims,
|
|
label_dims));
|
|
}
|
|
|
|
out->set_dims(input_dims);
|
|
out->set_dtype(input.dtype());
|
|
out->share_lod(input);
|
|
}
|
|
|
|
void BeamSearchDecodeInferMeta(const MetaTensor& ids,
|
|
const MetaTensor& scores,
|
|
int beam_size,
|
|
int end_id,
|
|
MetaTensor* sentence_ids,
|
|
MetaTensor* sentence_scores,
|
|
MetaConfig config) {}
|
|
|
|
void BincountInferMeta(const MetaTensor& x,
|
|
const MetaTensor& weights,
|
|
const Scalar& minlength,
|
|
MetaTensor* out) {
|
|
auto input_dim = x.dims();
|
|
|
|
PADDLE_ENFORCE_EQ(input_dim.size(),
|
|
1,
|
|
common::errors::InvalidArgument(
|
|
"The 'shape' of Input(X) must be 1-D tensor."
|
|
"But the dimension of Input(X) is [%d]",
|
|
input_dim.size()));
|
|
|
|
VLOG(4) << "####### CHECK weights";
|
|
if (weights) {
|
|
auto weights_dim = weights.dims();
|
|
VLOG(4) << "##### weights_dim " << weights_dim;
|
|
PADDLE_ENFORCE_EQ(weights_dim.size(),
|
|
1,
|
|
common::errors::InvalidArgument(
|
|
"The 'shape' of Input(Weights) must be 1-D tensor."
|
|
"But the dimension of Input(Weights) is [%d]",
|
|
weights_dim.size()));
|
|
|
|
if (input_dim[0] != 0) {
|
|
PADDLE_ENFORCE_EQ(
|
|
weights_dim[0],
|
|
input_dim[0],
|
|
common::errors::InvalidArgument(
|
|
"The 'shape' of Input(Weights) must be equal to the 'shape' of "
|
|
"Input(X)."
|
|
"But received: the 'shape' of Input(Weights) is [%s],"
|
|
"the 'shape' of Input(X) is [%s]",
|
|
weights_dim,
|
|
input_dim));
|
|
}
|
|
}
|
|
out->set_dims(make_ddim({-1}));
|
|
if (weights) {
|
|
out->set_dtype(weights.dtype());
|
|
} else {
|
|
out->set_dtype(DataType::INT64);
|
|
}
|
|
|
|
out->share_lod(x);
|
|
}
|
|
|
|
void BinomialInferMeta(const MetaTensor& count,
|
|
const MetaTensor& prob,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
auto count_dims = count.dims();
|
|
auto prob_dims = prob.dims();
|
|
|
|
bool check = true;
|
|
if ((!config.is_runtime) &&
|
|
(phi::product(count_dims) <= 0 || phi::product(prob_dims) <= 0)) {
|
|
check = false;
|
|
}
|
|
|
|
if (check) {
|
|
PADDLE_ENFORCE_EQ(count_dims,
|
|
prob_dims,
|
|
common::errors::InvalidArgument(
|
|
"Input(count) and Input(prob) shall have the same "
|
|
"shape. But received: the shape of Input(count) is "
|
|
"[%s], the shape of Input(prob) is [%s].",
|
|
count_dims,
|
|
prob_dims));
|
|
}
|
|
|
|
out->set_dims(count_dims);
|
|
out->set_dtype(DataType::INT64);
|
|
}
|
|
|
|
void BmmInferMeta(const MetaTensor& x, const MetaTensor& y, MetaTensor* out) {
|
|
std::vector<int64_t> x_dims = vectorize(x.dims());
|
|
std::vector<int64_t> y_dims = vectorize(y.dims());
|
|
std::size_t x_ndims = x_dims.size();
|
|
std::size_t y_ndims = y_dims.size();
|
|
|
|
PADDLE_ENFORCE_EQ(x_ndims,
|
|
3,
|
|
common::errors::InvalidArgument(
|
|
"Input(X) of BmmOp must be 3-dimensional in BmmOp, "
|
|
"but received X's shape: [%s].",
|
|
x_ndims));
|
|
PADDLE_ENFORCE_EQ(y_ndims,
|
|
3,
|
|
common::errors::InvalidArgument(
|
|
"Input(Y) of BmmOp must be 3-dimensional in BmmOp, "
|
|
"but received Y's shape: [%s].",
|
|
y_ndims));
|
|
std::vector<int64_t> dim_out;
|
|
auto cal_shape_fn = [](int64_t x, int64_t y, const std::string& error_str) {
|
|
if (x == -1) {
|
|
return y;
|
|
} else if (y == -1) {
|
|
return x;
|
|
}
|
|
PADDLE_ENFORCE_EQ(x, y, common::errors::InvalidArgument(error_str, x, y));
|
|
return x;
|
|
};
|
|
cal_shape_fn(x_dims[2],
|
|
y_dims[1],
|
|
"Input(X)'s width must be equal with Input(Y)'s height in BmmOp,"
|
|
"but receive X's width: [%s],"
|
|
"Y's height: [%s].");
|
|
dim_out.push_back(cal_shape_fn(
|
|
x_dims[0],
|
|
y_dims[0],
|
|
"Input(X) and Input(Y) must have the same batch size in BmmOp, "
|
|
"but received X's batch size: [%s],"
|
|
"Y's batch size [%s]"));
|
|
dim_out.push_back(x_dims[1]);
|
|
dim_out.push_back(y_dims[2]);
|
|
out->set_dims(make_ddim(dim_out));
|
|
out->share_lod(x);
|
|
out->set_dtype(x.dtype());
|
|
out->set_layout(x.layout());
|
|
}
|
|
|
|
void BoxClipInferMeta(const MetaTensor& input,
|
|
const MetaTensor& im_info,
|
|
MetaTensor* output,
|
|
MetaConfig config) {
|
|
const auto& input_box_dims = input.dims();
|
|
const auto& im_info_dims = im_info.dims();
|
|
|
|
if (config.is_runtime) {
|
|
auto input_box_size = input_box_dims.size();
|
|
PADDLE_ENFORCE_EQ(
|
|
input_box_dims[input_box_size - 1],
|
|
4,
|
|
common::errors::InvalidArgument(
|
|
"The last dimension of Input(Input) in BoxClipOp must be 4. "
|
|
"But received last dimension = %d",
|
|
input_box_dims[input_box_size - 1]));
|
|
PADDLE_ENFORCE_EQ(im_info_dims.size(),
|
|
2,
|
|
common::errors::InvalidArgument(
|
|
"The rank of Input(Input) in BoxClipOp must be 2."
|
|
" But received rank = %d",
|
|
im_info_dims.size()));
|
|
PADDLE_ENFORCE_EQ(
|
|
im_info_dims[1],
|
|
3,
|
|
common::errors::InvalidArgument(
|
|
"The last dimension of Input(ImInfo) of BoxClipOp must be 3. "
|
|
"But received last dimension = %d",
|
|
im_info_dims[1]));
|
|
}
|
|
output->set_dims(input.dims());
|
|
output->set_dtype(input.dtype());
|
|
output->share_lod(input);
|
|
}
|
|
|
|
void CholeskySolveInferMeta(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
bool upper,
|
|
MetaTensor* out) {
|
|
auto x_dims = x.dims();
|
|
auto y_dims = y.dims();
|
|
|
|
auto x_dims_n = x_dims.size();
|
|
auto y_dims_n = y_dims.size();
|
|
|
|
PADDLE_ENFORCE_GE(x_dims_n,
|
|
2,
|
|
common::errors::InvalidArgument(
|
|
"the rank of input Y must greater or equal to 2"));
|
|
PADDLE_ENFORCE_GE(y_dims_n,
|
|
2,
|
|
common::errors::InvalidArgument(
|
|
"the rank of input X must greater or equal to 2"));
|
|
PADDLE_ENFORCE_EQ(
|
|
y_dims[y_dims_n - 1],
|
|
y_dims[y_dims_n - 2],
|
|
common::errors::InvalidArgument("input Matrix Y should be square matrix,"
|
|
"But Got last shape of %ld x %ld",
|
|
y_dims[y_dims_n - 1],
|
|
y_dims[y_dims_n - 2]));
|
|
PADDLE_ENFORCE_EQ(x_dims[x_dims_n - 2],
|
|
y_dims[y_dims_n - 2],
|
|
common::errors::InvalidArgument(
|
|
"the first dim of Matrix X must be equal to "
|
|
"the first dim of Matrix Y,"
|
|
"But Got %ld and %ld",
|
|
x_dims[x_dims_n - 2],
|
|
y_dims[y_dims_n - 2]));
|
|
|
|
std::vector<int64_t> x_dims_vec = vectorize(x_dims);
|
|
std::vector<int64_t> y_dims_vec = vectorize(y_dims);
|
|
|
|
std::vector<int64_t> x_dims_vec_cut(x_dims_vec.begin(), x_dims_vec.end() - 2);
|
|
std::vector<int64_t> y_dims_vec_cut(y_dims_vec.begin(), y_dims_vec.end() - 2);
|
|
|
|
std::vector<int64_t> expand_batch_portion =
|
|
funcs::MatrixGetBroadcastBatchPortion(x_dims_vec_cut, y_dims_vec_cut);
|
|
|
|
std::vector<int64_t> x_broadcast_dims({expand_batch_portion});
|
|
x_broadcast_dims.insert(x_broadcast_dims.end(),
|
|
{x_dims_vec[x_dims_n - 2], x_dims_vec[x_dims_n - 1]});
|
|
|
|
// dim of 'out' is the same with 'X' after broadcast
|
|
out->set_dims(make_ddim(x_broadcast_dims));
|
|
out->set_dtype(x.dtype());
|
|
out->set_layout(x.layout());
|
|
out->share_lod(x);
|
|
}
|
|
|
|
void CompareRawInferMeta(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
int axis,
|
|
MetaTensor* out) {
|
|
auto dim_x = x.dims();
|
|
auto dim_y = y.dims();
|
|
|
|
if (dim_x == dim_y) {
|
|
out->share_meta(x);
|
|
} else {
|
|
int max_dim = std::max(dim_x.size(), dim_y.size());
|
|
int axis = std::abs(dim_x.size() - dim_y.size());
|
|
std::vector<int64_t> x_dims_array(max_dim);
|
|
std::vector<int64_t> y_dims_array(max_dim);
|
|
std::vector<int64_t> out_dims_array(max_dim);
|
|
funcs::GetBroadcastDimsArrays(dim_x,
|
|
dim_y,
|
|
x_dims_array.data(),
|
|
y_dims_array.data(),
|
|
out_dims_array.data(),
|
|
max_dim,
|
|
axis);
|
|
out->set_dims(make_ddim(out_dims_array));
|
|
out->share_lod(x);
|
|
}
|
|
if (!out->is_same_tensor(x)) {
|
|
out->set_dtype(DataType::BOOL);
|
|
}
|
|
}
|
|
|
|
void CompareInferMeta(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
MetaTensor* out) {
|
|
CompareRawInferMeta(x, y, -1, out);
|
|
}
|
|
|
|
void CompareAllInferMeta(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
MetaTensor* out) {
|
|
out->share_lod(x);
|
|
out->set_dims(make_ddim({}));
|
|
}
|
|
|
|
void ComplexInferMeta(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
MetaTensor* out) {
|
|
if (x.dims() == y.dims()) {
|
|
auto sizes = vectorize(x.dims());
|
|
out->set_dims(make_ddim(sizes));
|
|
out->set_dtype(dtype::ToComplex(x.dtype()));
|
|
// NOTE(chenfeiyu): lod & broadcasting is intrinsically contradictory
|
|
// so tensors with lod are not supported here
|
|
} else {
|
|
auto x_dims = x.dims();
|
|
auto y_dims = y.dims();
|
|
int max_dim = std::max(x_dims.size(), y_dims.size());
|
|
|
|
// start align axis
|
|
int axis = std::abs(x_dims.size() - y_dims.size());
|
|
std::vector<int64_t> x_dims_array(max_dim);
|
|
std::vector<int64_t> y_dims_array(max_dim);
|
|
std::vector<int64_t> out_dims_array(max_dim);
|
|
funcs::GetBroadcastDimsArrays(x_dims,
|
|
y_dims,
|
|
x_dims_array.data(),
|
|
y_dims_array.data(),
|
|
out_dims_array.data(),
|
|
max_dim,
|
|
axis);
|
|
out->set_dims(make_ddim(out_dims_array));
|
|
out->set_dtype(dtype::ToComplex(x.dtype()));
|
|
}
|
|
}
|
|
|
|
void ConvInferMeta(const MetaTensor& input,
|
|
const MetaTensor& filter,
|
|
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,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
std::vector<int> paddings_ = paddings;
|
|
std::vector<int> dilations_ = dilations;
|
|
auto in_dims = input.dims();
|
|
auto filter_dims = filter.dims();
|
|
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]));
|
|
}
|
|
const bool channel_last = (config.is_run_onednn_kernel == false) &&
|
|
(data_format == "NHWC" || data_format == "NDHWC");
|
|
|
|
PADDLE_ENFORCE_EQ(
|
|
in_dims.size() == 4 || in_dims.size() == 5,
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"The input of Op(Conv) should be a 4-D or 5-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) 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()));
|
|
|
|
int stride_size = static_cast<int>(strides.size());
|
|
for (int i = 0; i < stride_size; ++i) {
|
|
PADDLE_ENFORCE_GT(
|
|
strides[i],
|
|
0,
|
|
common::errors::InvalidArgument(
|
|
"The stride of Op(Conv) should be larger than 0, but received "
|
|
"stride is %d.",
|
|
strides[i]));
|
|
}
|
|
|
|
int in_sub_stride_size = in_dims.size() - stride_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). "
|
|
"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));
|
|
|
|
const auto input_channels =
|
|
channel_last ? in_dims[in_dims.size() - 1] : in_dims[1];
|
|
const auto filter_channels = channel_last && FLAGS_manually_trans_conv_filter
|
|
? filter_dims[filter_dims.size() - 1]
|
|
: filter_dims[1];
|
|
|
|
if (config.is_runtime) {
|
|
PADDLE_ENFORCE_EQ(
|
|
input_channels,
|
|
filter_channels * groups,
|
|
common::errors::InvalidArgument(
|
|
"The number of input's channels should be equal to filter's "
|
|
"channels "
|
|
"* groups for Op(Conv). 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, the data_format is %s. "
|
|
"The error may come from wrong data_format setting.",
|
|
input_channels,
|
|
in_dims,
|
|
filter_channels,
|
|
filter_dims,
|
|
groups,
|
|
data_format));
|
|
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));
|
|
PADDLE_ENFORCE_GT(
|
|
filter_dims[0],
|
|
0,
|
|
common::errors::InvalidArgument(
|
|
"the size of filter at axis 0 should be greater than 0"));
|
|
for (int i = 2; i < filter_dims.size(); ++i) {
|
|
PADDLE_ENFORCE_GT(
|
|
filter_dims[i],
|
|
0,
|
|
common::errors::InvalidArgument(
|
|
"The kernel size of Op(Conv) should be greater than 0, but "
|
|
"received kernel size at dimension %d is %d. The filter's shape "
|
|
"is [%s].",
|
|
i,
|
|
filter_dims[i],
|
|
filter_dims));
|
|
}
|
|
}
|
|
|
|
DDim in_data_dims;
|
|
if (channel_last) {
|
|
in_data_dims = slice_ddim(in_dims, 1, in_dims.size() - 1);
|
|
} else {
|
|
in_data_dims = slice_ddim(in_dims, 2, in_dims.size());
|
|
}
|
|
|
|
DDim filter_data_dims;
|
|
if (channel_last && FLAGS_manually_trans_conv_filter) {
|
|
filter_data_dims = slice_ddim(filter_dims, 1, filter_dims.size() - 1);
|
|
} else {
|
|
filter_data_dims = slice_ddim(filter_dims, 2, filter_dims.size());
|
|
}
|
|
|
|
std::vector<int> ksize = vectorize<int>(filter_data_dims);
|
|
phi::UpdatePaddingAndDilation(
|
|
&paddings_, &dilations_, padding_algorithm, in_data_dims, strides, ksize);
|
|
|
|
std::vector<int64_t> output_shape({in_dims[0]});
|
|
if (!channel_last) {
|
|
if (filter_dims[1] == 0) {
|
|
output_shape.push_back(0);
|
|
} else {
|
|
output_shape.push_back(filter_dims[0]);
|
|
}
|
|
}
|
|
for (int i = 0; i < in_data_dims.size(); ++i) {
|
|
if ((!config.is_runtime) &&
|
|
(in_data_dims[i] < 0 || filter_dims[i + 2] < 0)) {
|
|
output_shape.push_back(-1);
|
|
} else {
|
|
const int64_t dkernel = dilations_[i] * (filter_data_dims[i] - 1) + 1;
|
|
int64_t output_size = (in_data_dims[i] + paddings_[2 * i] +
|
|
paddings_[2 * i + 1] - dkernel) /
|
|
strides[i] +
|
|
1;
|
|
output_shape.push_back(output_size);
|
|
}
|
|
}
|
|
if (channel_last) {
|
|
if (filter_dims[1] == 0) {
|
|
output_shape.push_back(0);
|
|
} else {
|
|
output_shape.push_back(filter_dims[0]);
|
|
}
|
|
}
|
|
|
|
out->set_dims(make_ddim(output_shape));
|
|
out->set_dtype(input.dtype());
|
|
}
|
|
|
|
void Conv3DInferMeta(const MetaTensor& input,
|
|
const MetaTensor& filter,
|
|
const std::vector<int>& strides,
|
|
const std::vector<int>& paddings,
|
|
const std::string& padding_algorithm,
|
|
int groups,
|
|
const std::vector<int>& dilations,
|
|
const std::string& data_format,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
ConvInferMeta(input,
|
|
filter,
|
|
strides,
|
|
paddings,
|
|
padding_algorithm,
|
|
dilations,
|
|
groups,
|
|
data_format,
|
|
out,
|
|
config);
|
|
}
|
|
|
|
void ConvTransposeInferMeta(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,
|
|
MetaConfig config) {
|
|
auto x_dims = x.dims();
|
|
auto filter_dims = filter.dims();
|
|
|
|
std::vector<int> paddings_ = paddings;
|
|
std::vector<int> dilations_ = dilations;
|
|
|
|
const DataLayout data_layout = config.is_run_onednn_kernel
|
|
? DataLayout::NCHW
|
|
: StringToDataLayout(data_format);
|
|
|
|
PADDLE_ENFORCE_EQ(
|
|
x_dims.size() == 4 || x_dims.size() == 5,
|
|
true,
|
|
errors::InvalidArgument("Input of Op(conv_transpose) should be 4-D or "
|
|
"5-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_layout != DataLayout::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_layout != DataLayout::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_layout != DataLayout::NHWC) {
|
|
output_shape.push_back(filter_dims[1] * groups);
|
|
}
|
|
const int offset = (data_layout != DataLayout::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 = (config.is_runtime || 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()) {
|
|
if (config.is_runtime) {
|
|
PADDLE_ENFORCE_GE(
|
|
output_size[i],
|
|
infer_shape,
|
|
errors::InvalidArgument(
|
|
"output_size of Op(ConvTransposeOp) should not be less than "
|
|
"the inferred output size. But received output_size = [%s], "
|
|
"whose dim %d is less than the inferred output size [%s]",
|
|
make_ddim(output_size).to_str(),
|
|
i,
|
|
infer_shape));
|
|
if (common::product(x_dims) != 0) {
|
|
PADDLE_ENFORCE_LT(
|
|
output_size[i],
|
|
infer_shape + strides[i],
|
|
errors::InvalidArgument(
|
|
"output_size of Op(ConvTransposeOp) should be less "
|
|
"than inferred size + stride. But received output_size = "
|
|
"[%s], "
|
|
"whose dim %d is not less than the inferred output size (%d) "
|
|
"+ "
|
|
"stride (%d) = %d",
|
|
make_ddim(output_size).to_str(),
|
|
i,
|
|
infer_shape,
|
|
strides[i],
|
|
infer_shape + strides[i]));
|
|
}
|
|
}
|
|
output_shape.push_back(output_size[i]);
|
|
} else if (!output_padding.empty()) {
|
|
if (config.is_runtime) {
|
|
PADDLE_ENFORCE_GE(
|
|
output_padding[i],
|
|
0,
|
|
errors::InvalidArgument(
|
|
"output_padding of Op(ConvTransposeOp) should not be "
|
|
"less than the 0. But received output_padding = "
|
|
"[%s], whose dim %d is less than 0",
|
|
make_ddim(output_padding).to_str(),
|
|
i));
|
|
PADDLE_ENFORCE_LT(
|
|
output_padding[i],
|
|
std::max(strides[i], dilations_[i]),
|
|
errors::InvalidArgument(
|
|
"output_padding of Op(ConvTransposeOp) should be less "
|
|
"than either stride or dilation. But received output_size = "
|
|
"[%s], "
|
|
"whose dim %d is not less than either stride (%d) or "
|
|
"dilation (%d)",
|
|
make_ddim(output_size).to_str(),
|
|
i,
|
|
strides[i],
|
|
dilations_[i]));
|
|
}
|
|
output_shape.push_back((infer_shape + output_padding[i]));
|
|
} else {
|
|
output_shape.push_back(infer_shape);
|
|
}
|
|
}
|
|
if (data_layout == DataLayout::NHWC) {
|
|
output_shape.push_back(filter_dims[1] * groups);
|
|
}
|
|
|
|
out->set_dims(make_ddim(output_shape));
|
|
out->set_dtype(x.dtype());
|
|
}
|
|
|
|
void Conv2dTransposeInferMeta(const MetaTensor& x,
|
|
const MetaTensor& filter,
|
|
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,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
std::vector<int32_t> vec_output_size(output_size.GetData().begin(),
|
|
output_size.GetData().end());
|
|
ConvTransposeInferMeta(x,
|
|
filter,
|
|
strides,
|
|
paddings,
|
|
output_padding,
|
|
vec_output_size,
|
|
padding_algorithm,
|
|
groups,
|
|
dilations,
|
|
data_format,
|
|
out,
|
|
config);
|
|
}
|
|
|
|
void CorrelationInferMeta(const MetaTensor& input1,
|
|
const MetaTensor& input2,
|
|
int pad_size,
|
|
int kernel_size,
|
|
int max_displacement,
|
|
int stride1,
|
|
int stride2,
|
|
int corr_type_multiply,
|
|
MetaTensor* out) {
|
|
auto in_dims = input1.dims();
|
|
auto in2_dims = input2.dims();
|
|
|
|
PADDLE_ENFORCE_EQ(in_dims.size() == 4,
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"Input(X) of CorrelationOp must be 4 dims."
|
|
"But received dims is %d.",
|
|
in_dims.size()));
|
|
|
|
PADDLE_ENFORCE_EQ(in2_dims.size() == 4,
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"Input(Y) of CorrelationOp must be 4 dims."
|
|
"But received dims is %d.",
|
|
in2_dims.size()));
|
|
|
|
PADDLE_ENFORCE_GT(stride1,
|
|
0,
|
|
common::errors::InvalidArgument(
|
|
"stride1 of CorrelationOp must be greater than 0. "
|
|
"But received stride1 = %d.",
|
|
stride1));
|
|
|
|
PADDLE_ENFORCE_GT(stride2,
|
|
0,
|
|
common::errors::InvalidArgument(
|
|
"stride2 of CorrelationOp must be greater than 0. "
|
|
"But received stride2 = %d.",
|
|
stride2));
|
|
|
|
std::vector<int64_t> output_shape = CorrelationOutputSize(in_dims[0],
|
|
in_dims[2],
|
|
in_dims[3],
|
|
stride1,
|
|
stride2,
|
|
kernel_size,
|
|
pad_size,
|
|
max_displacement);
|
|
out->set_dims(make_ddim(output_shape));
|
|
out->set_dtype(input1.dtype());
|
|
}
|
|
|
|
void CrossInferMeta(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
int axis,
|
|
MetaTensor* out) {
|
|
auto x_dim = x.dims();
|
|
auto y_dim = y.dims();
|
|
auto dim = axis;
|
|
|
|
bool dims_match = funcs::CheckDims(x_dim, y_dim);
|
|
PADDLE_ENFORCE_EQ(dims_match,
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"The 'shape' of Input(X) should be equal to "
|
|
"the 'shape' of Input(Y). But received "
|
|
"Input(X).dimensions = [%s], "
|
|
"Input(Y).dimensions = [%s]",
|
|
x_dim,
|
|
y_dim));
|
|
|
|
if (dim != DDim::kMaxRank) {
|
|
PADDLE_ENFORCE_EQ(
|
|
dim < x_dim.size() && dim >= (0 - x_dim.size()),
|
|
true,
|
|
common::errors::OutOfRange(
|
|
"Attr(dim) is out of range, It's expected "
|
|
"to be in range of [-%d, %d]. But received Attr(dim) = %d.",
|
|
x_dim.size(),
|
|
x_dim.size() - 1,
|
|
dim));
|
|
if (dim < 0) {
|
|
dim += x_dim.size();
|
|
}
|
|
PADDLE_ENFORCE_EQ(x_dim[dim] == 3 && y_dim[dim] == 3,
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"Input(X/Y).dims()[dim] should be equal to 3."
|
|
"But received Input(X/Y).dims()[dim] = %d.",
|
|
x_dim[dim]));
|
|
}
|
|
out->set_dims(x_dim);
|
|
out->set_dtype(x.dtype());
|
|
out->set_layout(x.layout());
|
|
out->share_lod(x);
|
|
}
|
|
|
|
void CrossEntropyInferMeta(const MetaTensor& x,
|
|
const MetaTensor& label,
|
|
bool soft_label,
|
|
int ignore_index,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
const auto& x_dims = x.dims();
|
|
const auto& label_dims = label.dims();
|
|
int rank = x_dims.size();
|
|
|
|
bool contain_unknown_dim = common::contain_unknown_dim(x_dims) ||
|
|
common::contain_unknown_dim(label_dims);
|
|
bool check = config.is_runtime || !contain_unknown_dim;
|
|
|
|
if (check) {
|
|
PADDLE_ENFORCE_EQ(
|
|
slice_ddim(x_dims, 0, rank - 1),
|
|
slice_ddim(label_dims, 0, rank - 1),
|
|
common::errors::InvalidArgument(
|
|
"Input(X) and Input(Label) shall have the same shape "
|
|
"except the last dimension. But received: the shape of Input(X) "
|
|
"is "
|
|
"[%s], the shape of Input(Label) is [%s].",
|
|
x_dims,
|
|
label_dims));
|
|
}
|
|
|
|
if (soft_label) {
|
|
PADDLE_ENFORCE_EQ(
|
|
rank,
|
|
label_dims.size(),
|
|
common::errors::InvalidArgument(
|
|
"If Attr(soft_label) == true, Input(X) and Input(Label) "
|
|
"shall have the same dimensions. But received: the dimensions of "
|
|
"Input(X) is [%d],"
|
|
"the shape of Input(X) is [%s], the dimensions of Input(Label) "
|
|
"is [%d], the shape of "
|
|
"Input(Label) is [%s]",
|
|
rank,
|
|
x_dims,
|
|
label_dims.size(),
|
|
label_dims));
|
|
|
|
if (check) {
|
|
PADDLE_ENFORCE_EQ(
|
|
x_dims[rank - 1],
|
|
label_dims[rank - 1],
|
|
common::errors::InvalidArgument(
|
|
"If Attr(soft_label) == true, the last dimension of "
|
|
"Input(X) and Input(Label) should be equal. But received: the "
|
|
"last dimension of Input(X) is [%d], the shape of Input(X) is "
|
|
"[%s], "
|
|
"the last dimension of Input(Label) is [%d], the shape of "
|
|
"Input(Label) "
|
|
"is [%s], the last dimension is [%d].",
|
|
x_dims[rank - 1],
|
|
x_dims,
|
|
label_dims[rank - 1],
|
|
label_dims,
|
|
rank - 1));
|
|
}
|
|
} else {
|
|
if (rank == label_dims.size()) {
|
|
PADDLE_ENFORCE_EQ(
|
|
label_dims[rank - 1],
|
|
1UL,
|
|
common::errors::InvalidArgument(
|
|
"the last dimension of Input(Label) should be 1."
|
|
"But received: the last dimension of Input(Label) is [%d],"
|
|
"the last dimension is [%d]",
|
|
label_dims[rank - 1],
|
|
rank - 1));
|
|
} else {
|
|
PADDLE_ENFORCE_EQ(
|
|
rank,
|
|
label_dims.size() + 1,
|
|
common::errors::InvalidArgument(
|
|
"ShapeError: The rank of Input(X) should be equal to "
|
|
"Input(Label) plus 1."
|
|
"But received: The dimension of Input(X) is [%d], "
|
|
"the shape of Input(X) is [%s],"
|
|
"the dimension of Input(Label) is [%d], the shape of "
|
|
"Input(Label) is [%s]",
|
|
rank,
|
|
x_dims,
|
|
label_dims.size(),
|
|
label_dims));
|
|
}
|
|
}
|
|
|
|
auto y_dims = label_dims;
|
|
if (rank == label_dims.size()) {
|
|
y_dims[rank - 1] = 1;
|
|
}
|
|
out->set_dims(y_dims);
|
|
out->set_dtype(x.dtype());
|
|
out->share_lod(x);
|
|
}
|
|
|
|
void CrossEntropy2InferMeta(const MetaTensor& x,
|
|
const MetaTensor& label,
|
|
int ignore_index,
|
|
MetaTensor* out,
|
|
MetaTensor* x_shape,
|
|
MetaTensor* match_x,
|
|
MetaConfig config) {
|
|
CrossEntropyInferMeta(x, label, false, ignore_index, out);
|
|
|
|
auto x_dims = x.dims();
|
|
auto x_dims_vec = vectorize(x_dims);
|
|
x_dims_vec.push_back(0);
|
|
x_shape->set_dims(make_ddim(x_dims_vec));
|
|
x_dims[x_dims.size() - 1] = 1;
|
|
match_x->set_dims(x_dims);
|
|
x_shape->set_dtype(x.dtype());
|
|
match_x->set_dtype(x.dtype());
|
|
x_shape->share_lod(x);
|
|
}
|
|
|
|
void CrossEntropyWithSoftmaxInferMeta(const MetaTensor& logits,
|
|
const MetaTensor& label,
|
|
bool soft_label,
|
|
bool use_softmax,
|
|
bool numeric_stable_mode,
|
|
int ignore_index,
|
|
int axis,
|
|
MetaTensor* softmax,
|
|
MetaTensor* loss,
|
|
MetaConfig config) {
|
|
auto logits_dims = logits.dims();
|
|
auto labels_dims = label.dims();
|
|
auto logits_rank = logits_dims.size();
|
|
PADDLE_ENFORCE_GE(axis,
|
|
-logits_rank,
|
|
common::errors::InvalidArgument(
|
|
"Attr(axis) value should be in range [-R, R-1], "
|
|
"R is the rank of Input(Logits)."));
|
|
PADDLE_ENFORCE_LT(axis,
|
|
logits_rank,
|
|
common::errors::InvalidArgument(
|
|
"Attr(axis) value should be in range [-R, R-1], "
|
|
"R is the rank of Input(Logits)."));
|
|
|
|
axis = funcs::CanonicalAxis(axis, logits_rank);
|
|
for (int i = 0; i < logits_rank; i++) {
|
|
if (i != axis) {
|
|
if (config.is_runtime || (logits_dims[i] > 0 && labels_dims[i] > 0)) {
|
|
PADDLE_ENFORCE_EQ(logits_dims[i],
|
|
labels_dims[i],
|
|
common::errors::InvalidArgument(
|
|
"Input(Logits) and Input(Label) should in "
|
|
"same shape in dimensions except axis."));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (axis != logits_rank - 1) {
|
|
PADDLE_ENFORCE_EQ(
|
|
numeric_stable_mode,
|
|
true,
|
|
common::errors::InvalidArgument("Attr(axis) can only be -1 "
|
|
"when not in numeric_stable_mode."));
|
|
}
|
|
|
|
if (soft_label) {
|
|
if (config.is_runtime || (logits_dims[axis] > 0 && labels_dims[axis] > 0)) {
|
|
PADDLE_ENFORCE_EQ(logits_dims[axis],
|
|
labels_dims[axis],
|
|
common::errors::InvalidArgument(
|
|
"If Attr(soft_label) == true, "
|
|
"the axis dimension of "
|
|
"Input(X) and Input(Label) should be equal."));
|
|
}
|
|
} else {
|
|
if (config.is_runtime || labels_dims[axis] > 0) {
|
|
PADDLE_ENFORCE_EQ(
|
|
labels_dims[axis],
|
|
1UL,
|
|
common::errors::InvalidArgument("If Attr(soft_label) == false, "
|
|
"the axis dimension of "
|
|
"Input(Label) should be 1."));
|
|
}
|
|
}
|
|
|
|
softmax->set_dims(logits_dims);
|
|
if (softmax->dtype() == DataType::BFLOAT16) {
|
|
softmax->set_dtype(DataType::FLOAT32);
|
|
} else {
|
|
softmax->set_dtype(logits.dtype());
|
|
}
|
|
|
|
logits_dims[axis] = 1;
|
|
loss->set_dims(logits_dims);
|
|
if (logits.dtype() == DataType::BFLOAT16) {
|
|
loss->set_dtype(DataType::FLOAT32);
|
|
} else {
|
|
loss->set_dtype(logits.dtype());
|
|
}
|
|
|
|
softmax->share_lod(logits);
|
|
loss->share_lod(logits);
|
|
}
|
|
|
|
void CSoftmaxWithCrossEntropyInferMeta(const MetaTensor& logits,
|
|
const MetaTensor& label,
|
|
int64_t ignore_index,
|
|
int rank,
|
|
int nranks,
|
|
MetaTensor* softmax,
|
|
MetaTensor* loss,
|
|
MetaConfig config) {
|
|
auto logits_dims = logits.dims();
|
|
auto labels_dims = label.dims();
|
|
|
|
auto logits_rank = logits_dims.size();
|
|
auto axis = logits_rank - 1;
|
|
for (int i = 0; i < logits_rank; i++) {
|
|
if (i != axis) {
|
|
if (config.is_runtime || (logits_dims[i] > 0 && labels_dims[i] > 0)) {
|
|
PADDLE_ENFORCE_EQ(logits_dims[i],
|
|
labels_dims[i],
|
|
common::errors::InvalidArgument(
|
|
"Input(Logits) and Input(Label) should in "
|
|
"same shape in dimensions except axis."));
|
|
}
|
|
}
|
|
}
|
|
|
|
PADDLE_ENFORCE_EQ(
|
|
labels_dims[logits_rank - 1],
|
|
1UL,
|
|
common::errors::InvalidArgument(
|
|
"the last dimension of Input(Label) should be 1."
|
|
"But received: the last dimension of Input(Label) is [%d],"
|
|
"the last dimension is [%d]",
|
|
labels_dims[logits_rank - 1],
|
|
logits_rank - 1));
|
|
|
|
softmax->set_dims(logits_dims);
|
|
logits_dims[axis] = 1;
|
|
loss->set_dims(logits_dims);
|
|
softmax->share_lod(logits);
|
|
loss->share_lod(logits);
|
|
}
|
|
|
|
void CtcAlignInferMeta(const MetaTensor& input,
|
|
const MetaTensor& input_length,
|
|
int blank,
|
|
bool merge_repeated,
|
|
int padding_value,
|
|
MetaTensor* output,
|
|
MetaTensor* output_length) {
|
|
auto input_dims = input.dims();
|
|
output->set_dims(input_dims);
|
|
if (input_length.initialized()) {
|
|
output_length->set_dims({input_dims[0], 1});
|
|
}
|
|
output->set_dtype(input.dtype());
|
|
}
|
|
|
|
void DepthwiseConvInferMeta(const MetaTensor& input,
|
|
const MetaTensor& filter,
|
|
const std::vector<int>& strides,
|
|
const std::vector<int>& paddings,
|
|
const std::string& padding_algorithm,
|
|
int groups,
|
|
const std::vector<int>& dilations,
|
|
const std::string& data_format,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
ConvInferMeta(input,
|
|
filter,
|
|
strides,
|
|
paddings,
|
|
padding_algorithm,
|
|
dilations,
|
|
groups,
|
|
data_format,
|
|
out,
|
|
config);
|
|
}
|
|
|
|
void DepthwiseConv2dBiasInferMeta(const MetaTensor& input,
|
|
const MetaTensor& filter,
|
|
const MetaTensor& bias,
|
|
const std::vector<int>& strides,
|
|
const std::vector<int>& paddings,
|
|
const std::string& padding_algorithm,
|
|
int groups,
|
|
const std::vector<int>& dilations,
|
|
const std::string& data_format,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
ConvInferMeta(input,
|
|
filter,
|
|
strides,
|
|
paddings,
|
|
padding_algorithm,
|
|
dilations,
|
|
groups,
|
|
data_format,
|
|
out,
|
|
config);
|
|
}
|
|
|
|
void DepthwiseConv3dBiasInferMeta(const MetaTensor& input,
|
|
const MetaTensor& filter,
|
|
const MetaTensor& bias,
|
|
const std::vector<int>& strides,
|
|
const std::vector<int>& paddings,
|
|
const std::string& padding_algorithm,
|
|
int groups,
|
|
const std::vector<int>& dilations,
|
|
const std::string& data_format,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
ConvInferMeta(input,
|
|
filter,
|
|
strides,
|
|
paddings,
|
|
padding_algorithm,
|
|
dilations,
|
|
groups,
|
|
data_format,
|
|
out,
|
|
config);
|
|
}
|
|
|
|
void CvmInferMeta(const MetaTensor& x,
|
|
const MetaTensor& cvm,
|
|
bool use_cvm,
|
|
MetaTensor* out) {
|
|
const auto& x_dims = x.dims();
|
|
PADDLE_ENFORCE_EQ(
|
|
x_dims.size(),
|
|
2UL,
|
|
common::errors::InvalidArgument("Input(X)'s rank should be 2, but got %d",
|
|
x_dims.size()));
|
|
|
|
if (use_cvm) {
|
|
out->set_dims({x_dims[0], x_dims[1]});
|
|
} else {
|
|
out->set_dims({x_dims[0], x_dims[1] - 2});
|
|
}
|
|
out->share_lod(x);
|
|
out->set_dtype(x.dtype());
|
|
}
|
|
|
|
void DequantizeAbsMaxInferMeta(const MetaTensor& x,
|
|
const MetaTensor& scale,
|
|
float max_range,
|
|
MetaTensor* out) {
|
|
out->set_dtype(x.dtype());
|
|
out->share_dims(x);
|
|
out->share_lod(x);
|
|
}
|
|
|
|
void DequantizeLogInferMeta(const MetaTensor& x,
|
|
const MetaTensor& dict,
|
|
MetaTensor* out) {
|
|
out->set_dtype(x.dtype());
|
|
out->share_dims(x);
|
|
out->share_lod(x);
|
|
}
|
|
|
|
void DistInferMeta(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
float p,
|
|
MetaTensor* out) {
|
|
out->set_dims(make_ddim({}));
|
|
out->set_dtype(x.dtype());
|
|
}
|
|
|
|
void DistributeLookupTableInferMeta(
|
|
const std::vector<const phi::MetaTensor*>& ids,
|
|
const MetaTensor& w,
|
|
int table_id,
|
|
bool is_distributed,
|
|
const std::string& lookup_table_version,
|
|
int64_t padding_idx,
|
|
DataType dtype,
|
|
bool is_test,
|
|
std::vector<MetaTensor*> outputs) {
|
|
auto table_dims = w.dims();
|
|
|
|
PADDLE_ENFORCE_EQ(w.dims().size(),
|
|
2,
|
|
errors::InvalidArgument(
|
|
"Only 2 dimensions of the 'Embedding' is supported."));
|
|
|
|
for (auto& id : ids) {
|
|
PADDLE_ENFORCE_EQ(id->dims().size(),
|
|
2,
|
|
errors::InvalidArgument(
|
|
"The dimension of the 'Ids' tensor must be 2."));
|
|
}
|
|
|
|
// for fluid.embedding
|
|
for (size_t i = 0; i < ids.size(); ++i) {
|
|
MetaTensor* output = outputs[i];
|
|
auto id_dims = ids[i]->dims();
|
|
if (lookup_table_version == "lookup_table") {
|
|
output->set_dims(make_ddim({id_dims[0], table_dims[1]}));
|
|
output->share_lod(*ids[i]);
|
|
output->set_dtype(w.dtype());
|
|
} else if (lookup_table_version == "lookup_table_v2") {
|
|
output->set_dims(make_ddim({static_cast<int64_t>(id_dims[0]),
|
|
static_cast<int64_t>(id_dims[1]),
|
|
static_cast<int64_t>(table_dims[1])}));
|
|
output->share_lod(*ids[i]);
|
|
output->set_dtype(w.dtype());
|
|
}
|
|
}
|
|
}
|
|
|
|
void DistributeFpnProposalsInferMeta(
|
|
const MetaTensor& fpn_rois,
|
|
const MetaTensor& rois_num,
|
|
int min_level,
|
|
int max_level,
|
|
int refer_level,
|
|
int refer_scale,
|
|
bool pixel_offset,
|
|
std::vector<MetaTensor*> multi_fpn_rois,
|
|
std::vector<MetaTensor*> multi_level_rois_num,
|
|
MetaTensor* restore_index,
|
|
MetaConfig config) {
|
|
PADDLE_ENFORCE_GE(
|
|
multi_fpn_rois.size(),
|
|
1UL,
|
|
errors::InvalidArgument("Outputs(MultiFpnRois) of "
|
|
"DistributeFpnProposalsOp should not be empty"));
|
|
PADDLE_ENFORCE_GE(
|
|
max_level,
|
|
min_level,
|
|
errors::InvalidArgument(
|
|
"max_level must not lower than "
|
|
"min_level. But received max_level = %d, min_level = %d",
|
|
max_level,
|
|
min_level));
|
|
// Set the output shape
|
|
for (auto& multi_fpn_roi : multi_fpn_rois) {
|
|
DDim out_dim = {-1, 4};
|
|
if (multi_fpn_roi == nullptr) {
|
|
continue;
|
|
}
|
|
multi_fpn_roi->set_dims(out_dim);
|
|
multi_fpn_roi->set_dtype(fpn_rois.dtype());
|
|
}
|
|
restore_index->set_dims({-1, 1});
|
|
restore_index->set_dtype(DataType::INT32);
|
|
for (auto& item : multi_level_rois_num) {
|
|
if (item == nullptr) {
|
|
continue;
|
|
}
|
|
item->set_dims({-1});
|
|
item->set_dtype(DataType::INT32);
|
|
}
|
|
|
|
if (!config.is_runtime) {
|
|
for (auto& multi_fpn_roi : multi_fpn_rois) {
|
|
multi_fpn_roi->share_lod(fpn_rois);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DistributedFusedLambInitInferMeta(
|
|
const std::vector<const MetaTensor*>& param,
|
|
const std::vector<const MetaTensor*>& grad,
|
|
float beta1,
|
|
float beta2,
|
|
const std::vector<int>& apply_weight_decay,
|
|
int alignment,
|
|
int rank,
|
|
int nranks,
|
|
MetaTensor* fp32_fused_param,
|
|
MetaTensor* fp32_fused_grad,
|
|
MetaTensor* fp16_fused_param,
|
|
MetaTensor* fp16_fused_grad,
|
|
MetaTensor* moment1,
|
|
MetaTensor* moment2,
|
|
MetaTensor* beta1_pow,
|
|
MetaTensor* beta2_pow,
|
|
MetaTensor* fused_param_offsets,
|
|
MetaTensor* fp32_shard_fused_param_offsets,
|
|
MetaTensor* fp16_shard_fused_param_offsets,
|
|
MetaTensor* param_info,
|
|
MetaTensor* param_order,
|
|
std::vector<MetaTensor*> param_out,
|
|
std::vector<MetaTensor*> master_param_out,
|
|
std::vector<MetaTensor*> grad_out,
|
|
MetaTensor* global_scale,
|
|
MetaTensor* step) {
|
|
fp32_fused_param->set_dtype(DataType::FLOAT32);
|
|
fp32_fused_grad->set_dtype(DataType::FLOAT32);
|
|
fp16_fused_param->set_dtype(DataType::FLOAT16);
|
|
fp16_fused_grad->set_dtype(DataType::FLOAT16);
|
|
moment1->set_dtype(DataType::FLOAT32);
|
|
moment2->set_dtype(DataType::FLOAT32);
|
|
beta1_pow->set_dtype(DataType::FLOAT32);
|
|
beta2_pow->set_dtype(DataType::FLOAT32);
|
|
fused_param_offsets->set_dtype(DataType::INT32);
|
|
fp32_shard_fused_param_offsets->set_dtype(DataType::INT32);
|
|
fp16_shard_fused_param_offsets->set_dtype(DataType::INT32);
|
|
param_info->set_dtype(DataType::INT32);
|
|
param_order->set_dtype(DataType::INT32);
|
|
|
|
for (size_t i = 0; i < param.size(); ++i) {
|
|
param_out[i]->set_dtype(param[i]->dtype());
|
|
master_param_out[i]->set_dtype(DataType::FLOAT32);
|
|
}
|
|
|
|
for (size_t i = 0; i < grad.size(); ++i) {
|
|
grad_out[i]->set_dtype(grad[i]->dtype());
|
|
}
|
|
|
|
global_scale->set_dtype(DataType::FLOAT32);
|
|
step->set_dtype(DataType::INT64);
|
|
}
|
|
|
|
void DropoutInferMeta(const MetaTensor& x,
|
|
const MetaTensor& seed_tensor,
|
|
const Scalar& p,
|
|
bool is_test,
|
|
const std::string& mode,
|
|
int seed,
|
|
bool fix_seed,
|
|
MetaTensor* out,
|
|
MetaTensor* mask) {
|
|
auto x_dims = x.dims();
|
|
out->set_dims(x_dims);
|
|
out->share_lod(x);
|
|
out->set_dtype(x.dtype());
|
|
|
|
if (mask != nullptr) {
|
|
mask->set_dims(x_dims);
|
|
mask->set_dtype(DataType::UINT8);
|
|
}
|
|
}
|
|
|
|
void DropoutNdInferMeta(const MetaTensor& x,
|
|
const MetaTensor& seed_tensor,
|
|
const Scalar& p,
|
|
bool is_test,
|
|
const std::string& mode,
|
|
int seed,
|
|
bool fix_seed,
|
|
const std::vector<int>& axis,
|
|
MetaTensor* out,
|
|
MetaTensor* mask) {
|
|
auto x_dims = x.dims();
|
|
|
|
PADDLE_ENFORCE_LE(
|
|
axis.size(),
|
|
x_dims.size(),
|
|
common::errors::InvalidArgument(
|
|
"The length of axis is expected to be less than or equal to the "
|
|
"dimension size of x. But received the length of axis is %d, the "
|
|
"dimension size of x is %d, x's shape is {%s}.",
|
|
axis.size(),
|
|
x_dims.size(),
|
|
x_dims));
|
|
for (size_t i = 0; i < axis.size(); ++i) {
|
|
PADDLE_ENFORCE_EQ(
|
|
axis[i] >= 0 && axis[i] <= x_dims.size() - 1,
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"The %d-th value of axis is expected to be greater ot "
|
|
"equal to 0 and less than the dimensions of x. But "
|
|
"received axis is {%s}, the dimension size of x is %d.",
|
|
i,
|
|
make_ddim(axis),
|
|
x_dims.size()));
|
|
}
|
|
|
|
out->set_dims(x_dims);
|
|
out->share_lod(x);
|
|
out->set_dtype(x.dtype());
|
|
|
|
if (mask != nullptr) {
|
|
std::vector<int64_t> mask_dims(x.dims().size(), 1);
|
|
|
|
std::for_each(
|
|
axis.begin(), axis.end(), [&mask_dims, &x_dims](const int64_t& t) {
|
|
mask_dims[t] = x_dims[static_cast<int>(t)];
|
|
});
|
|
|
|
mask->set_dims(make_ddim(mask_dims));
|
|
mask->set_dtype(DataType::UINT8);
|
|
}
|
|
}
|
|
|
|
void DotInferMeta(const MetaTensor& x, const MetaTensor& y, MetaTensor* out) {
|
|
auto x_dims = x.dims();
|
|
int x_rank = static_cast<int>(x_dims.size());
|
|
PADDLE_ENFORCE_EQ(true,
|
|
1 == x_rank || 2 == x_rank,
|
|
common::errors::PreconditionNotMet(
|
|
"ShapeError: The dimensions of input tensor X (%s) "
|
|
"should be 1 or 2",
|
|
x_dims.to_str()));
|
|
|
|
auto y_dims = y.dims();
|
|
PADDLE_ENFORCE_EQ(
|
|
true,
|
|
x_rank == static_cast<int>(y_dims.size()),
|
|
common::errors::PreconditionNotMet(
|
|
"ShapeError: The shape of input tensor Y: %s should match with "
|
|
"input tensor X: %s",
|
|
y_dims.to_str(),
|
|
x_dims.to_str()));
|
|
bool shape_match = true;
|
|
for (int i = 0; i < x_rank; ++i) {
|
|
if (x_dims[i] == 0 || y_dims[i] == 0) {
|
|
continue;
|
|
}
|
|
if (x_dims[i] != y_dims[i]) {
|
|
shape_match = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
PADDLE_ENFORCE_EQ(true,
|
|
shape_match,
|
|
common::errors::PreconditionNotMet(
|
|
"ShapeError: The shape of input tensor X: %s should "
|
|
"be exactly the same "
|
|
"with input tensor Y: %s",
|
|
x_dims.to_str(),
|
|
y_dims.to_str()));
|
|
|
|
auto out_dims = x_dims;
|
|
// The output dims need to be modified.
|
|
if (x_rank == 2 && x_dims[0] != 0 && y_dims[0] == 0) {
|
|
out_dims[0] = 0;
|
|
}
|
|
std::vector<int64_t> out_dims_vec = vectorize(out_dims);
|
|
std::vector<int64_t> out_dims_vec_cut(out_dims_vec.begin(),
|
|
out_dims_vec.end() - 1);
|
|
out->set_dims(make_ddim(out_dims_vec_cut));
|
|
out->set_dtype(x.dtype());
|
|
out->set_layout(x.layout());
|
|
}
|
|
|
|
void ElementwiseInferMeta(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
MetaTensor* out) {
|
|
return ElementwiseRawInferMeta(x, y, -1, out);
|
|
}
|
|
|
|
void BitwiseShiftInferMeta(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
bool is_arithmetic,
|
|
MetaTensor* out) {
|
|
return ElementwiseRawInferMeta(x, y, -1, out);
|
|
}
|
|
|
|
void ElementwiseRawInferMeta(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
int axis,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
if (x.dims() != y.dims()) {
|
|
auto x_dims = x.dims();
|
|
auto y_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<int64_t> x_dims_array(max_dim);
|
|
std::vector<int64_t> y_dims_array(max_dim);
|
|
std::vector<int64_t> out_dims_array(max_dim);
|
|
|
|
#ifdef PADDLE_WITH_DNNL
|
|
bool should_rotate =
|
|
config.is_run_onednn_kernel &&
|
|
(phi::OneDNNContext::tls().get_cur_paddle_data_layout() ==
|
|
DataLayout::NHWC) &&
|
|
(x_dims.size() >= 3 || y_dims.size() >= 3);
|
|
if (should_rotate) {
|
|
// Pick bigger shape and rotate this one
|
|
bool x_over_y = (common::product(x_dims) > common::product(y_dims));
|
|
auto vdims =
|
|
x_over_y ? vectorize<int64_t>(x_dims) : vectorize<int64_t>(y_dims);
|
|
std::rotate(vdims.begin() + 1, vdims.begin() + 2, vdims.end());
|
|
if (x_over_y) {
|
|
x_dims = make_ddim(vdims);
|
|
} else {
|
|
y_dims = make_ddim(vdims);
|
|
}
|
|
}
|
|
#endif
|
|
funcs::GetBroadcastDimsArrays(x_dims,
|
|
y_dims,
|
|
x_dims_array.data(),
|
|
y_dims_array.data(),
|
|
out_dims_array.data(),
|
|
max_dim,
|
|
axis);
|
|
#ifdef PADDLE_WITH_DNNL
|
|
if (should_rotate) {
|
|
std::rotate(out_dims_array.begin() + 1,
|
|
out_dims_array.end() - 1,
|
|
out_dims_array.end());
|
|
}
|
|
#endif
|
|
auto out_dims = make_ddim(out_dims_array);
|
|
out->set_dims(out_dims);
|
|
} else {
|
|
out->set_dims(x.dims());
|
|
}
|
|
// dtype need promote when meet input dtype with more precision
|
|
paddle::experimental::DataTypeSet dtype_set{x.dtype()};
|
|
dtype_set = dtype_set | paddle::experimental::DataTypeSet(y.dtype());
|
|
DataType promote_result = PromoteTypes(dtype_set);
|
|
if (promote_result == DataType::UNDEFINED) {
|
|
promote_result = x.dtype();
|
|
}
|
|
out->set_dtype(promote_result);
|
|
|
|
// layout need change when meet input layout contain NHWC
|
|
auto layout = [&]() {
|
|
if (x.layout() == DataLayout::NHWC || y.layout() == DataLayout::NHWC)
|
|
return DataLayout::NHWC;
|
|
return x.layout();
|
|
}();
|
|
|
|
out->set_layout(layout);
|
|
out->share_lod(x);
|
|
}
|
|
|
|
void EmbeddingInferMeta(const MetaTensor& x,
|
|
const MetaTensor& weight,
|
|
int64_t padding_idx,
|
|
MetaTensor* out) {
|
|
const auto& table_dims = weight.dims();
|
|
const auto& ids_dims = x.dims();
|
|
int ids_rank = ids_dims.size();
|
|
VLOG(5) << "ids rank is " << ids_rank << std::endl;
|
|
PADDLE_ENFORCE_EQ(
|
|
table_dims.size(),
|
|
2,
|
|
common::errors::InvalidArgument(
|
|
"ShapeError: The dimensions of the 'lookup table' must be 2. "
|
|
"But received lookup table's dimensions = %d, "
|
|
"lookup table's shape = [%s].",
|
|
table_dims.size(),
|
|
table_dims));
|
|
|
|
auto output_dims = vectorize(ids_dims);
|
|
output_dims.push_back(table_dims[1]);
|
|
out->set_dims(make_ddim(output_dims));
|
|
out->set_dtype(weight.dtype());
|
|
out->share_lod(x);
|
|
}
|
|
|
|
void CEmbeddingInferMeta(const MetaTensor& weight,
|
|
const MetaTensor& x,
|
|
int64_t start_index,
|
|
MetaTensor* out) {
|
|
const auto& table_dims = weight.dims();
|
|
const auto& ids_dims = x.dims();
|
|
int ids_rank = ids_dims.size();
|
|
|
|
VLOG(5) << "ids rank is " << ids_rank << std::endl;
|
|
PADDLE_ENFORCE_EQ(
|
|
table_dims.size(),
|
|
2,
|
|
common::errors::InvalidArgument(
|
|
"ShapeError: The dimensions of the 'c_embedding' must be 2. "
|
|
"But received c_embedding's dimensions = %d, "
|
|
"c_embedding's shape = [%s].",
|
|
table_dims.size(),
|
|
table_dims));
|
|
|
|
auto output_dims = vectorize(ids_dims);
|
|
output_dims.push_back(table_dims[1]);
|
|
out->set_dims(make_ddim(output_dims));
|
|
out->set_dtype(weight.dtype());
|
|
out->share_lod(x);
|
|
|
|
const auto height = table_dims[0];
|
|
const auto width = table_dims[1];
|
|
PADDLE_ENFORCE_EQ(
|
|
(height > 0 && width > 0 && start_index >= 0),
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"height:%ld width:%ld start_index:%ld must not have negative values",
|
|
height,
|
|
width,
|
|
start_index));
|
|
}
|
|
|
|
void ExpandAsInferMeta(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
const std::vector<int64_t>& target_shape,
|
|
MetaTensor* out) {
|
|
#define MAX_RANK_SUPPORTED 8
|
|
auto x_dims = x.dims();
|
|
PADDLE_ENFORCE_GE(
|
|
target_shape.size(),
|
|
static_cast<size_t>(x_dims.size()),
|
|
common::errors::InvalidArgument(
|
|
"The rank of target_shape must be greater than or equal "
|
|
"to the rank of Input(X). But received Input(X): input "
|
|
"rank %u; received target_shape: rank %u.",
|
|
x_dims.size(),
|
|
target_shape.size()));
|
|
PADDLE_ENFORCE_LE(target_shape.size(),
|
|
MAX_RANK_SUPPORTED,
|
|
common::errors::InvalidArgument(
|
|
"The rank of target_shape must be less than or equal "
|
|
"to %d. But received: rank %u.",
|
|
MAX_RANK_SUPPORTED,
|
|
target_shape.size()));
|
|
out->set_dims(make_ddim(target_shape));
|
|
out->set_dtype(x.dtype());
|
|
#undef MAX_RANK_SUPPORTED
|
|
}
|
|
|
|
void FastRMSNormInfermeta(const MetaTensor& x,
|
|
const MetaTensor& scale,
|
|
float epsilon,
|
|
MetaTensor* y,
|
|
MetaTensor* invvar) {
|
|
auto x_dim = x.dims();
|
|
auto x_ndim = x_dim.size();
|
|
|
|
auto matrix_dim = flatten_to_2d(x_dim, x_ndim - 1);
|
|
|
|
int64_t right = matrix_dim[1];
|
|
if (scale) {
|
|
PADDLE_ENFORCE_EQ(scale.dims().size(),
|
|
1,
|
|
common::errors::InvalidArgument(
|
|
"The dimensions of Input(Scale) must be 1, but "
|
|
"received dimensions of "
|
|
"Input(Scale) is [%d]",
|
|
scale.dims().size()));
|
|
}
|
|
|
|
PADDLE_ENFORCE_EQ(
|
|
scale.dims()[0],
|
|
right,
|
|
common::errors::InvalidArgument(
|
|
"The first dimension value of Input(Scale) must equal to be the "
|
|
"second dimension value of the flattened 2D matrix of Input(X), "
|
|
"But received the first dimension value of Input(Scale) is "
|
|
"[%d], the second dimension value of the flattened 2D matrix of "
|
|
" Input(Scale) is [%d].",
|
|
scale.dims()[0],
|
|
right));
|
|
|
|
PADDLE_ENFORCE_EQ(epsilon >= 0.0f && epsilon <= 0.001f,
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"'epsilon' in Op(LayerNorm) should be between"
|
|
"0.0 and 0.001, But received [%s].",
|
|
epsilon));
|
|
|
|
DataType scale_dtype = scale.dtype();
|
|
y->set_dims(x_dim);
|
|
y->set_dtype(scale_dtype);
|
|
|
|
auto row_shape = slice_ddim(x_dim, 0, x_dim.size() - 1);
|
|
invvar->set_dims({row_shape});
|
|
invvar->set_dtype(DataType::FLOAT32);
|
|
}
|
|
|
|
void FakeDequantizeMaxAbsInferMeta(const MetaTensor& x,
|
|
const MetaTensor& scale,
|
|
float max_range,
|
|
MetaTensor* out) {
|
|
out->set_dtype(x.dtype());
|
|
out->share_dims(x);
|
|
out->share_lod(x);
|
|
}
|
|
|
|
void FillDiagonalTensorInferMeta(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
int64_t offset,
|
|
int dim1,
|
|
int dim2,
|
|
MetaTensor* out) {
|
|
PADDLE_ENFORCE_NOT_NULL(out,
|
|
common::errors::InvalidArgument(
|
|
"Output Tensor (out) should not be nullptr."));
|
|
out->set_dims(x.dims());
|
|
out->set_dtype(x.dtype());
|
|
}
|
|
|
|
void FusedDropoutAddInferMeta(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
MetaTensor* out,
|
|
MetaTensor* seed_offset) {
|
|
out->share_meta(x);
|
|
if (seed_offset) {
|
|
seed_offset->set_dims({2});
|
|
seed_offset->set_dtype(DataType::INT64);
|
|
}
|
|
}
|
|
|
|
// Used in FusedMatmulInferMeta
|
|
static std::vector<int64_t> GetInputShape(DDim dim,
|
|
std::vector<int> shape,
|
|
std::vector<int> axis) {
|
|
PADDLE_ENFORCE_GT(
|
|
dim.size(),
|
|
0,
|
|
common::errors::InvalidArgument(
|
|
"The input has not been initialized properly. The shape of input = "
|
|
"[%s].",
|
|
dim));
|
|
|
|
auto is_input_fused = (!shape.empty() && !axis.empty());
|
|
if (is_input_fused) {
|
|
dim = dim.reshape(shape).transpose(axis);
|
|
}
|
|
return vectorize(dim);
|
|
}
|
|
|
|
void FusedMatmulInferMeta(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
const MetaTensor& residual_data,
|
|
bool transpose_x,
|
|
bool transpose_y,
|
|
const float matmul_alpha,
|
|
const std::string& fuse_activation,
|
|
const float fuse_alpha,
|
|
const float fuse_beat,
|
|
const float fused_output_scale,
|
|
const std::vector<int>& fused_reshape_X,
|
|
const std::vector<int>& fused_transpose_X,
|
|
const std::vector<int>& fused_reshape_Y,
|
|
const std::vector<int>& fused_transpose_Y,
|
|
const std::vector<int>& fused_reshape_Out,
|
|
const std::vector<int>& fused_transpose_Out,
|
|
const std::string& onednn_data_type,
|
|
const float scale_x,
|
|
const float scale_y,
|
|
const float scale_scale_in_eltwise,
|
|
const float scale_out,
|
|
const bool force_fp32_output,
|
|
MetaTensor* out) {
|
|
std::vector<int64_t> dims_x =
|
|
GetInputShape(x.dims(), fused_reshape_X, fused_transpose_X);
|
|
std::vector<int64_t> dims_y =
|
|
GetInputShape(y.dims(), fused_reshape_Y, fused_transpose_Y);
|
|
auto ndims_x = dims_x.size();
|
|
auto ndims_y = dims_y.size();
|
|
PADDLE_ENFORCE_GT(ndims_x,
|
|
0,
|
|
common::errors::InvalidArgument(
|
|
"The Input(X) dims size must be greater than 0,"
|
|
" but received dims size is 0. "));
|
|
PADDLE_ENFORCE_GT(ndims_y,
|
|
0,
|
|
common::errors::InvalidArgument(
|
|
"The Input(Y) dims size must be greater than 0,"
|
|
" but received dims size is 0. "));
|
|
bool x_broadcasted = false;
|
|
bool 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 (transpose_x) {
|
|
M = dims_x[ndims_x - 1];
|
|
} else {
|
|
M = dims_x[ndims_x - 2];
|
|
}
|
|
if (transpose_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
|
|
}
|
|
if (x_broadcasted && y_broadcasted) {
|
|
new_dims.push_back(1);
|
|
}
|
|
|
|
auto ddim_out = make_ddim(new_dims);
|
|
|
|
std::vector<int> shape = fused_reshape_Out;
|
|
const std::vector<int>& axis = fused_transpose_Out;
|
|
|
|
auto is_output_fused = (!shape.empty() && !axis.empty());
|
|
if (is_output_fused) {
|
|
ddim_out = ddim_out.transpose(axis).reshape(shape);
|
|
}
|
|
out->set_dims(ddim_out);
|
|
bool is_int8 = (x.dtype() == DataType::UINT8 || x.dtype() == DataType::INT8);
|
|
bool is_bfloat16 = (x.dtype() == DataType::BFLOAT16);
|
|
bool fuse_relu = false;
|
|
if (fuse_activation == "relu" || fuse_activation == "relu6") {
|
|
fuse_relu = true;
|
|
}
|
|
if (force_fp32_output || ((!is_int8) && (!is_bfloat16))) {
|
|
out->set_dtype(DataType::FLOAT32);
|
|
} else if (is_bfloat16) {
|
|
out->set_dtype(DataType::BFLOAT16);
|
|
} else if (fuse_relu) {
|
|
out->set_dtype(DataType::UINT8);
|
|
} else {
|
|
out->set_dtype(DataType::INT8);
|
|
}
|
|
}
|
|
|
|
void GatherInferMeta(const MetaTensor& x,
|
|
const MetaTensor& index,
|
|
const Scalar& axis,
|
|
MetaTensor* out) {
|
|
auto index_dims = index.dims();
|
|
|
|
if (index_dims.size() == 2) {
|
|
if (index_dims[1] != 0) {
|
|
PADDLE_ENFORCE_EQ(
|
|
index_dims[1],
|
|
1,
|
|
common::errors::InvalidArgument("The last dim of index should be 0 "
|
|
"or 1 when it is 2D, but we get %d",
|
|
index_dims[1]));
|
|
}
|
|
} else {
|
|
PADDLE_ENFORCE_EQ(
|
|
index_dims.size() == 1 || index_dims.size() == 0,
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"The index should be 0D or 1D, when it is not 2D, but we get %d",
|
|
index_dims.size()));
|
|
}
|
|
|
|
auto input_dim = x.dims();
|
|
auto axis_v = axis.to<int>();
|
|
if (axis_v < 0) axis_v += static_cast<int>(input_dim.size());
|
|
|
|
PADDLE_ENFORCE_GE(
|
|
axis_v,
|
|
(0 - input_dim.size()),
|
|
common::errors::OutOfRange(
|
|
"Attr(axis) is out of range, It's expected "
|
|
"to be in range of [%d, %d]. But received Attr(axis) = %d.",
|
|
-input_dim.size(),
|
|
input_dim.size() - 1,
|
|
axis_v));
|
|
PADDLE_ENFORCE_LT(
|
|
axis_v,
|
|
input_dim.size(),
|
|
common::errors::OutOfRange(
|
|
"Attr(axis) is out of range, It's expected "
|
|
"to be in range of [%d, %d]. But received Attr(axis) = %d.",
|
|
-input_dim.size(),
|
|
input_dim.size() - 1,
|
|
axis_v));
|
|
|
|
if (index_dims.size() == 0) {
|
|
// 0D index will decrease the dimension
|
|
if (input_dim.size() == 1) {
|
|
// the index is a 0D tensor and the x is a 1D tensor
|
|
out->set_dims(DDim(phi::Dim<0>()));
|
|
out->set_dtype(x.dtype());
|
|
out->share_lod(x);
|
|
} else {
|
|
if (axis.FromTensor() || axis_v == 0) {
|
|
// decrease the output dimension
|
|
std::vector<int64_t> out_dim_vec;
|
|
for (int i = 1; i < input_dim.size(); ++i) {
|
|
out_dim_vec.emplace_back(input_dim[i]);
|
|
}
|
|
auto output_dims = make_ddim(out_dim_vec);
|
|
out->set_dims(output_dims);
|
|
out->set_dtype(x.dtype());
|
|
out->share_lod(x);
|
|
} else {
|
|
std::vector<int64_t> out_dim_vec;
|
|
for (int i = 0; i < axis_v; i++) {
|
|
out_dim_vec.push_back(input_dim[i]); // NOLINT
|
|
}
|
|
for (int i = axis_v + 1; i < input_dim.size(); i++) {
|
|
out_dim_vec.push_back(input_dim[i]); // NOLINT
|
|
}
|
|
auto output_dims = make_ddim(out_dim_vec);
|
|
out->set_dims(output_dims);
|
|
out->set_dtype(x.dtype());
|
|
out->share_lod(x);
|
|
}
|
|
}
|
|
} else {
|
|
if (axis.FromTensor() || axis_v == 0) {
|
|
// if axis.FromTensor(), we can not obtain correct shape of output
|
|
int64_t batch_size = static_cast<int64_t>(index_dims[0]);
|
|
if (index_dims.size() == 2 && index_dims[1] == 0) {
|
|
batch_size = 0;
|
|
}
|
|
DDim output_dims(input_dim);
|
|
output_dims[0] = batch_size;
|
|
out->set_dims(output_dims);
|
|
out->set_dtype(x.dtype());
|
|
out->share_lod(x);
|
|
} else {
|
|
int64_t index_size = static_cast<int64_t>(index_dims[0]);
|
|
if (index_dims.size() == 2 && index_dims[1] == 0) {
|
|
index_size = 0;
|
|
}
|
|
std::vector<int64_t> out_dim_vec;
|
|
for (int i = 0; i < axis_v; i++) {
|
|
out_dim_vec.push_back(input_dim[i]); // NOLINT
|
|
}
|
|
out_dim_vec.push_back(index_size);
|
|
for (int i = axis_v + 1; i < input_dim.size(); i++) {
|
|
out_dim_vec.push_back(input_dim[i]); // NOLINT
|
|
}
|
|
auto output_dims = make_ddim(out_dim_vec);
|
|
out->set_dims(output_dims);
|
|
out->set_dtype(x.dtype());
|
|
out->share_lod(x);
|
|
}
|
|
}
|
|
}
|
|
|
|
void GatherNdInferMeta(const MetaTensor& x,
|
|
const MetaTensor& index,
|
|
MetaTensor* out) {
|
|
auto x_dims = x.dims();
|
|
auto x_dims_size = x_dims.size();
|
|
auto index_dims = index.dims();
|
|
int index_dims_size = index_dims.size();
|
|
|
|
PADDLE_ENFORCE_LE(
|
|
index_dims[index_dims_size - 1],
|
|
x_dims_size,
|
|
common::errors::InvalidArgument(
|
|
"Input(Index).shape[-1] should be no greater than Input(X).rank"));
|
|
PADDLE_ENFORCE_GE(index_dims_size,
|
|
1UL,
|
|
common::errors::InvalidArgument(
|
|
"The rank of Input(Index) should be greater than 1"));
|
|
|
|
std::vector<int64_t> result_dims;
|
|
// The result dims is
|
|
// Index.shape[:-1] + X.shape[Index.shape[-1]:]
|
|
for (int i = 0; i < index_dims_size - 1; ++i) {
|
|
result_dims.emplace_back(index_dims[i]);
|
|
}
|
|
for (int64_t i = index_dims[index_dims_size - 1]; i < x_dims_size; ++i) {
|
|
result_dims.emplace_back(x_dims[i]);
|
|
}
|
|
|
|
out->set_dims(make_ddim(result_dims));
|
|
out->share_lod(x);
|
|
out->set_dtype(x.dtype());
|
|
}
|
|
|
|
void GatherTreeMeta(const MetaTensor& ids,
|
|
const MetaTensor& parents,
|
|
MetaTensor* out) {
|
|
auto ids_dims = ids.dims();
|
|
auto parents_dims = parents.dims();
|
|
if (common::product(ids_dims) != 0) {
|
|
PADDLE_ENFORCE_EQ(ids_dims == parents_dims,
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"The shape of Input(Parents) must be same with the "
|
|
"shape of Input(Ids)."));
|
|
}
|
|
out->set_dims(ids_dims);
|
|
out->set_dtype(ids.dtype());
|
|
}
|
|
|
|
void GridSampleBaseInferMeta(const MetaTensor& x,
|
|
const MetaTensor& grid,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
auto x_dims = x.dims();
|
|
auto grid_dims = grid.dims();
|
|
PADDLE_ENFORCE_GE(x_dims.size(),
|
|
4,
|
|
common::errors::InvalidArgument(
|
|
"Input(X) of GridSampleOp should be 4-D Tensor, but "
|
|
"received X dimension size(%d)",
|
|
x_dims.size()));
|
|
PADDLE_ENFORCE_LE(x_dims.size(),
|
|
5,
|
|
common::errors::InvalidArgument(
|
|
"Input(X) of GridSampleOp should be 4-D Tensor, but "
|
|
"received X dimension size(%d)",
|
|
x_dims.size()));
|
|
PADDLE_ENFORCE_GE(grid_dims.size(),
|
|
4,
|
|
common::errors::InvalidArgument(
|
|
"Input(Grid) of GridSampleOp should be 4-D Tensor, "
|
|
"but received X dimension size(%d)",
|
|
grid_dims.size()));
|
|
PADDLE_ENFORCE_LE(grid_dims.size(),
|
|
5,
|
|
common::errors::InvalidArgument(
|
|
"Input(Grid) of GridSampleOp should be 4-D Tensor, "
|
|
"but received X dimension size(%d)",
|
|
grid_dims.size()));
|
|
if (grid_dims.size() == 4 && (config.is_runtime || grid_dims[3] > 0)) {
|
|
PADDLE_ENFORCE_EQ(
|
|
grid_dims[3],
|
|
2,
|
|
common::errors::InvalidArgument(
|
|
"Input(Grid) dimension[3] should be 2, but received %d",
|
|
grid_dims[3]));
|
|
}
|
|
if (grid_dims.size() == 5 && (config.is_runtime || grid_dims[4] > 0)) {
|
|
PADDLE_ENFORCE_EQ(
|
|
grid_dims[4],
|
|
3,
|
|
common::errors::InvalidArgument(
|
|
"Input(Grid) dimension[4] should be 3, but received %d",
|
|
grid_dims[4]));
|
|
}
|
|
if (config.is_runtime) {
|
|
PADDLE_ENFORCE_EQ(
|
|
grid_dims[0],
|
|
x_dims[0],
|
|
common::errors::InvalidArgument(
|
|
"Input(X) and Input(Grid) dimension[0] should be equal, but "
|
|
"received X dimension[0](%d) != Grid dimension[0](%d)",
|
|
x_dims[0],
|
|
grid_dims[0]));
|
|
}
|
|
if (grid_dims.size() == 4) {
|
|
out->set_dims({x_dims[0], x_dims[1], grid_dims[1], grid_dims[2]});
|
|
} else {
|
|
out->set_dims(
|
|
{x_dims[0], x_dims[1], grid_dims[1], grid_dims[2], grid_dims[3]});
|
|
}
|
|
out->set_dtype(x.dtype());
|
|
out->share_lod(x);
|
|
}
|
|
|
|
void HingeLossInferMeta(const MetaTensor& logits,
|
|
const MetaTensor& labels,
|
|
MetaTensor* loss) {
|
|
const auto& pred_dims = logits.dims();
|
|
const auto& label_dims = labels.dims();
|
|
|
|
PADDLE_ENFORCE_EQ(
|
|
pred_dims,
|
|
label_dims,
|
|
common::errors::InvalidArgument(
|
|
"The Input(input) and Input(label) should have the same "
|
|
"shape, but received input shape [%s] != label shape [%s]",
|
|
pred_dims,
|
|
label_dims));
|
|
|
|
PADDLE_ENFORCE_EQ(
|
|
pred_dims.size(),
|
|
2,
|
|
common::errors::InvalidArgument("Input(input) rank should be 2, "
|
|
"but received input rank(%d) != 2",
|
|
pred_dims.size()));
|
|
|
|
PADDLE_ENFORCE_EQ(pred_dims[1],
|
|
1,
|
|
common::errors::InvalidArgument(
|
|
"The second dimension of Input(input) should be 1, "
|
|
"as each row of input contains a real value, "
|
|
"but received second dimension of input (%d) != 1",
|
|
pred_dims[1]));
|
|
|
|
loss->set_dims({pred_dims[0], 1});
|
|
loss->share_lod(logits);
|
|
loss->set_dtype(logits.dtype());
|
|
}
|
|
|
|
void HistogramInferMeta(const MetaTensor& input,
|
|
const MetaTensor& weight,
|
|
int64_t bins,
|
|
float min,
|
|
float max,
|
|
bool density,
|
|
MetaTensor* out) {
|
|
PADDLE_ENFORCE_GE(bins,
|
|
1,
|
|
common::errors::InvalidArgument(
|
|
"The bins should be greater than or equal to 1."
|
|
"But received nbins is %d",
|
|
bins));
|
|
PADDLE_ENFORCE_GE(
|
|
max,
|
|
min,
|
|
common::errors::InvalidArgument("max must be larger or equal to min."
|
|
"But received max is %f, min is %f",
|
|
max,
|
|
min));
|
|
if (weight) {
|
|
auto weight_dims = weight.dims();
|
|
PADDLE_ENFORCE_EQ(
|
|
weight_dims,
|
|
input.dims(),
|
|
common::errors::InvalidArgument(
|
|
"The shape of weight should be equal to the shape of input."
|
|
"But received weight shape is [%s], input shape is [%s]",
|
|
weight_dims,
|
|
input.dims()));
|
|
}
|
|
|
|
out->set_dims({bins});
|
|
out->share_lod(input);
|
|
if (density || weight) {
|
|
out->set_dtype(DataType::FLOAT32);
|
|
} else {
|
|
out->set_dtype(DataType::INT64);
|
|
}
|
|
}
|
|
|
|
void HuberLossInferMeta(const MetaTensor& input,
|
|
const MetaTensor& label,
|
|
float delta,
|
|
MetaTensor* out,
|
|
MetaTensor* residual,
|
|
MetaConfig config) {
|
|
auto input_dims = input.dims();
|
|
auto label_dims = label.dims();
|
|
|
|
PADDLE_ENFORCE_EQ(input_dims.size(),
|
|
label_dims.size(),
|
|
common::errors::InvalidArgument(
|
|
"Input(input) rank and Input(label) rank should be "
|
|
"same, but received input rank(%d) != label rank(%d)",
|
|
input_dims.size(),
|
|
label_dims.size()));
|
|
|
|
bool contain_unknown_dim = common::contain_unknown_dim(input_dims) ||
|
|
common::contain_unknown_dim(label_dims);
|
|
if (config.is_runtime || !contain_unknown_dim) {
|
|
PADDLE_ENFORCE_EQ(
|
|
input_dims,
|
|
label_dims,
|
|
common::errors::InvalidArgument(
|
|
"The Input(input) and Input(label) should have the same "
|
|
"shape, but received input shape [%s] != label shape [%s]",
|
|
input_dims,
|
|
label_dims));
|
|
}
|
|
|
|
auto out_dims = label_dims;
|
|
residual->set_dims(out_dims);
|
|
out->set_dims(out_dims);
|
|
out->set_dtype(input.dtype());
|
|
residual->set_dtype(input.dtype());
|
|
out->share_lod(input);
|
|
}
|
|
|
|
void IdentityLossGradInferMeta(const MetaTensor& x,
|
|
const MetaTensor& out_grad,
|
|
const int reduction,
|
|
MetaTensor* x_grad) {
|
|
x_grad->set_dims(x.dims());
|
|
x_grad->share_lod(x);
|
|
x_grad->set_dtype(out_grad.dtype());
|
|
}
|
|
|
|
void IndexSampleInferMeta(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
auto input_dims = x.dims();
|
|
PADDLE_ENFORCE_EQ(input_dims.size(),
|
|
2,
|
|
errors::InvalidArgument(
|
|
"Inputs(X) shape of IndexSample op should be 2-D, but "
|
|
"got X's shape = [%s], please check X shape.",
|
|
input_dims));
|
|
|
|
auto index_dims = y.dims();
|
|
PADDLE_ENFORCE_EQ(
|
|
index_dims.size(),
|
|
2,
|
|
errors::InvalidArgument(
|
|
"Inputs(Index) shape of IndexSample op should be 2-D, but "
|
|
"got Index's shape [%s] , please check index shape.",
|
|
input_dims));
|
|
if (config.is_runtime && index_dims[0] != 0) { // 0-size not check
|
|
PADDLE_ENFORCE_EQ(input_dims[0],
|
|
index_dims[0],
|
|
errors::InvalidArgument(
|
|
"Inputs(X)'s value of dimension 0 must same with "
|
|
"Inputs(Index)'s value of dimension 0, but "
|
|
"got %d of Inputs(X), and got %d of Inputs(Index), "
|
|
"please check Inputs shape.",
|
|
input_dims[0],
|
|
index_dims[0]));
|
|
}
|
|
out->set_dtype(x.dtype());
|
|
out->set_dims(index_dims);
|
|
out->share_lod(y);
|
|
}
|
|
|
|
void Im2sequenceInferMeta(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
const std::vector<int>& kernels,
|
|
const std::vector<int>& strides,
|
|
const std::vector<int>& paddings,
|
|
const std::vector<int>& out_stride,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
PADDLE_ENFORCE_EQ(
|
|
x.initialized(),
|
|
true,
|
|
common::errors::NotFound("The input 'X' of Im2SequenceOp is not found."));
|
|
PADDLE_ENFORCE_EQ(out != nullptr,
|
|
true,
|
|
common::errors::NotFound(
|
|
"The output 'Out' of Im2SequenceOp is not found."));
|
|
const auto& in_dim = x.dims();
|
|
|
|
PADDLE_ENFORCE_EQ(in_dim.size(),
|
|
4,
|
|
common::errors::InvalidArgument(
|
|
"The dimensions size of input 'X' in Im2SequenceOp "
|
|
"should be 4. But "
|
|
"received dimensions size=[%d], dimensions=[%s].",
|
|
in_dim.size(),
|
|
in_dim));
|
|
auto img_channels = in_dim[1];
|
|
|
|
out->set_dims({in_dim[0], img_channels * kernels[0] * kernels[1]});
|
|
out->set_dtype(x.dtype());
|
|
}
|
|
|
|
void IndexSelectInferMeta(const MetaTensor& x,
|
|
const MetaTensor& index,
|
|
int dim,
|
|
MetaTensor* output) {
|
|
auto input_dim = x.dims();
|
|
auto index_dim = index.dims();
|
|
|
|
PADDLE_ENFORCE_EQ(
|
|
dim < input_dim.size() && dim >= (0 - input_dim.size()),
|
|
true,
|
|
common::errors::OutOfRange(
|
|
"Attr(dim) is out of range, It's expected "
|
|
"to be in range of [-%d, %d]. But received Attr(dim) = %d.",
|
|
input_dim.size(),
|
|
input_dim.size() - 1,
|
|
dim));
|
|
|
|
PADDLE_ENFORCE_EQ(
|
|
index_dim.size() == 1 || (index_dim.size() == 2 && index_dim[1] == 1),
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"The 'shape' of Input(Index) must be 1-D tensor. "
|
|
"But received: the 'shape' of Input(Index) is [%s], "
|
|
"the dimension of Input(Index) is [%d].",
|
|
index_dim,
|
|
index_dim.size()));
|
|
if (dim < 0) {
|
|
dim += input_dim.size();
|
|
}
|
|
|
|
auto output_dim = vectorize(input_dim);
|
|
|
|
output_dim[dim] = index_dim[0];
|
|
output->set_dims(make_ddim(output_dim));
|
|
output->set_dtype(x.dtype());
|
|
output->set_layout(x.layout());
|
|
output->share_lod(x);
|
|
}
|
|
|
|
void IndexSelectStridedInferMeta(const MetaTensor& x,
|
|
int64_t index,
|
|
int dim,
|
|
MetaTensor* output) {
|
|
auto input_dim = x.dims();
|
|
|
|
PADDLE_ENFORCE_EQ(
|
|
dim < input_dim.size() && dim >= (0 - input_dim.size()),
|
|
true,
|
|
common::errors::OutOfRange(
|
|
"Attr(dim) is out of range, It's expected "
|
|
"to be in range of [-%d, %d]. But received Attr(dim) = %d.",
|
|
input_dim.size(),
|
|
input_dim.size() - 1,
|
|
dim));
|
|
|
|
auto output_dim = vectorize(input_dim);
|
|
if (dim < 0) {
|
|
dim += input_dim.size();
|
|
}
|
|
output_dim.erase(output_dim.begin() + dim);
|
|
output->set_dims(make_ddim(output_dim));
|
|
output->set_dtype(x.dtype());
|
|
output->set_layout(x.layout());
|
|
output->share_lod(x);
|
|
}
|
|
|
|
void IndexAddInferMeta(const MetaTensor& x,
|
|
const MetaTensor& index,
|
|
const MetaTensor& add_value,
|
|
int axis,
|
|
MetaTensor* output) {
|
|
auto input_dim = x.dims();
|
|
if (common::product(input_dim) == 0) {
|
|
output->set_dims(input_dim);
|
|
output->set_dtype(x.dtype());
|
|
output->set_layout(x.layout());
|
|
return;
|
|
}
|
|
if (index.dims().size() == 1 && index.dims()[0] == 0) {
|
|
output->set_dims(input_dim);
|
|
output->set_dtype(x.dtype());
|
|
output->set_layout(x.layout());
|
|
output->share_lod(x);
|
|
return;
|
|
}
|
|
auto index_dim = index.dims();
|
|
auto add_value_dim = add_value.dims();
|
|
|
|
PADDLE_ENFORCE_EQ(
|
|
axis < input_dim.size() && axis >= (0 - input_dim.size()),
|
|
true,
|
|
common::errors::OutOfRange(
|
|
"Attr(dim) is out of range, It's expected "
|
|
"to be in range of [-%d, %d]. But received Attr(axis) = %d.",
|
|
input_dim.size(),
|
|
input_dim.size() - 1,
|
|
axis));
|
|
|
|
int real_axis = axis >= 0 ? axis : axis + input_dim.size();
|
|
|
|
PADDLE_ENFORCE_EQ(index_dim.size() == 1,
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"The 'shape' of Input(Index) must be 1-D tensor. "
|
|
"But received: the 'shape' of Input(Index) is [%s], "
|
|
"the dimension of Input(Index) is [%d].",
|
|
index_dim,
|
|
index_dim.size()));
|
|
if (common::product(add_value_dim) == 0) {
|
|
output->set_dims(input_dim);
|
|
output->set_dtype(x.dtype());
|
|
output->set_layout(x.layout());
|
|
output->share_lod(x);
|
|
return;
|
|
}
|
|
// Note, add_value does not support broadcast now.
|
|
PADDLE_ENFORCE_EQ(input_dim.size() == add_value_dim.size(),
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"The add_value must be the same dimension as x."));
|
|
for (int i = 0; i < input_dim.size(); i++) {
|
|
if (i != real_axis) {
|
|
PADDLE_ENFORCE_EQ(input_dim[i] == add_value_dim[i],
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"The add_value parameter does not supported "
|
|
"broadcast, so input_dim[i](%d) must be equal to "
|
|
"add_value_dim[i](%d) when i(%d) != axis(%d).",
|
|
input_dim[i],
|
|
add_value_dim[i],
|
|
i,
|
|
real_axis));
|
|
}
|
|
}
|
|
|
|
const auto& index_type = index.dtype();
|
|
bool index_type_match =
|
|
index_type == DataType::INT64 || index_type == DataType::INT32;
|
|
PADDLE_ENFORCE_EQ(index_type_match,
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"Input(Index) holds the wrong type, it holds %s, but "
|
|
"desires to be %s or %s",
|
|
index_type,
|
|
DataType::INT32,
|
|
DataType::INT64));
|
|
|
|
output->set_dims(x.dims());
|
|
output->set_dtype(x.dtype());
|
|
output->set_layout(x.layout());
|
|
output->share_lod(x);
|
|
}
|
|
|
|
void IndexElementwisePutInferMeta(const MetaTensor& x,
|
|
const std::vector<const MetaTensor*>& index,
|
|
const Scalar& value,
|
|
const std::vector<int64_t>& input_dims,
|
|
const std::vector<int64_t>& input_strides,
|
|
const std::vector<int64_t>& index_dims,
|
|
const std::vector<int64_t>& index_strides,
|
|
const int64_t slice_offset,
|
|
MetaTensor* out) {
|
|
out->set_dims(x.dims());
|
|
out->set_dtype(x.dtype());
|
|
}
|
|
|
|
void IndexElementwisePutWithTensorInferMeta(
|
|
const MetaTensor& x,
|
|
const std::vector<const MetaTensor*>& index,
|
|
const MetaTensor& value,
|
|
const std::vector<int64_t>& input_dims,
|
|
const std::vector<int64_t>& input_strides,
|
|
const std::vector<int64_t>& index_dims,
|
|
const std::vector<int64_t>& index_strides,
|
|
const int64_t slice_offset,
|
|
MetaTensor* out) {
|
|
out->set_dims(x.dims());
|
|
out->set_dtype(x.dtype());
|
|
}
|
|
|
|
void IndexElementwiseGetInferMeta(const MetaTensor& x,
|
|
const std::vector<const MetaTensor*>& index,
|
|
const std::vector<int64_t>& input_dims,
|
|
const std::vector<int64_t>& input_strides,
|
|
const std::vector<int64_t>& index_dims,
|
|
const std::vector<int64_t>& index_stride,
|
|
const int64_t slice_offset,
|
|
const bool accumulate,
|
|
const bool is_combined,
|
|
MetaTensor* out) {
|
|
out->set_dims(make_ddim(input_dims));
|
|
out->set_dtype(x.dtype());
|
|
}
|
|
|
|
void KronInferMeta(const MetaTensor& x, const MetaTensor& y, MetaTensor* out) {
|
|
auto dim_x = x.dims();
|
|
auto dim_y = y.dims();
|
|
auto rank_x = dim_x.size();
|
|
auto rank_y = dim_y.size();
|
|
auto rank = (rank_x > rank_y) ? rank_x : rank_y;
|
|
|
|
std::vector<int64_t> dim_out;
|
|
dim_out.reserve(rank);
|
|
for (int i = 0; i < rank; i++) {
|
|
int64_t dim_xi = (i < rank - rank_x) ? 1 : dim_x.at(i - (rank - rank_x));
|
|
int64_t dim_yi = (i < rank - rank_y) ? 1 : dim_y.at(i - (rank - rank_y));
|
|
dim_out.push_back(dim_xi == -1 || dim_yi == -1 ? -1 : dim_xi * dim_yi);
|
|
}
|
|
out->set_dims(make_ddim(dim_out));
|
|
out->set_dtype(x.dtype());
|
|
}
|
|
|
|
void LegacyCropInferMeta(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
const IntArray& offsets,
|
|
const std::vector<int>& shape,
|
|
MetaTensor* out) {
|
|
const auto& x_dim = x.dims();
|
|
if (!y.initialized()) {
|
|
PADDLE_ENFORCE_EQ(
|
|
int64_t(shape.size()),
|
|
x_dim.size(),
|
|
common::errors::InvalidArgument(
|
|
"The number of elements (%d) of CropOp's "
|
|
"'shape' attribute should be equal to the number of dimensions "
|
|
"(%d) of the Input(X).",
|
|
shape.size(),
|
|
x_dim.size()));
|
|
std::vector<int64_t> tensor_shape(shape.size());
|
|
for (size_t i = 0; i < shape.size(); ++i) {
|
|
tensor_shape[i] = static_cast<int64_t>(shape[i]);
|
|
}
|
|
out->set_dims(make_ddim(tensor_shape));
|
|
out->set_dtype(x.dtype());
|
|
} else {
|
|
const auto& y_dim = y.dims();
|
|
PADDLE_ENFORCE_EQ(common::arity(x_dim),
|
|
common::arity(y_dim),
|
|
common::errors::InvalidArgument(
|
|
"The number of dimensions (%d) of CropOp's input(X)"
|
|
" must be equal to that (%d) of input(Y).",
|
|
common::arity(x_dim),
|
|
common::arity(y_dim)));
|
|
out->set_dims(y_dim);
|
|
out->set_dtype(y.dtype());
|
|
}
|
|
}
|
|
|
|
void LimitByCapacityInferMeta(const MetaTensor& expert_count,
|
|
const MetaTensor& capacity,
|
|
int n_worker,
|
|
MetaTensor* out) {
|
|
out->share_dims(expert_count);
|
|
out->share_lod(expert_count);
|
|
out->set_dtype(expert_count.dtype());
|
|
}
|
|
|
|
void LodResetInferMeta(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
const std::vector<int>& target_lod,
|
|
bool append,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
if (y.initialized()) {
|
|
auto level0 = target_lod;
|
|
PADDLE_ENFORCE_GT(
|
|
static_cast<int64_t>(level0.size()),
|
|
0,
|
|
common::errors::InvalidArgument(
|
|
"If Input(Y) is not provided, the output's LoD should be "
|
|
"specified by attribute 'target_lod'. But the size of "
|
|
"'target_lod' is 0."));
|
|
} else if (config.is_runtime) {
|
|
out->share_lod(y);
|
|
}
|
|
if (append) {
|
|
out->share_lod(x);
|
|
}
|
|
|
|
out->set_dims(x.dims());
|
|
out->set_dtype(x.dtype());
|
|
}
|
|
|
|
void LogLossInferMeta(const MetaTensor& input,
|
|
const MetaTensor& label,
|
|
float epsilon,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
auto pred_dims = input.dims();
|
|
auto label_dims = label.dims();
|
|
|
|
if (config.is_runtime ||
|
|
(common::product(pred_dims) > 0 && common::product(label_dims) > 0)) {
|
|
PADDLE_ENFORCE_EQ(
|
|
pred_dims,
|
|
label_dims,
|
|
common::errors::InvalidArgument(
|
|
"The dimensions of Input(Predicted) must be equal to the "
|
|
"dimensions of Input(Labels), but received dimensions of "
|
|
"Input(Predicted) "
|
|
"is [%s], received dimensions of Input(Labels) is [%s].",
|
|
pred_dims,
|
|
label_dims));
|
|
}
|
|
PADDLE_ENFORCE_EQ(pred_dims.size(),
|
|
2,
|
|
common::errors::InvalidArgument(
|
|
"The dimensions of Input(Predicted) must be 2,"
|
|
"But received dimensions of Input(Predicted)"
|
|
"is [%d]",
|
|
pred_dims.size()));
|
|
if (config.is_runtime) {
|
|
PADDLE_ENFORCE_EQ(pred_dims[1],
|
|
1,
|
|
common::errors::InvalidArgument(
|
|
"Each row of Input(Predicted) contains a real value, "
|
|
"so the 2nd dimension of Input(X) must be 1,"
|
|
"But got [%d]",
|
|
pred_dims[1]));
|
|
}
|
|
out->set_dims({pred_dims[0], 1});
|
|
out->set_dtype(input.dtype());
|
|
out->share_lod(input);
|
|
}
|
|
|
|
void LookupTableDequantInferMeta(const MetaTensor& w,
|
|
const MetaTensor& ids,
|
|
int64_t padding_idx,
|
|
MetaTensor* out) {
|
|
PADDLE_ENFORCE_EQ(
|
|
w.initialized(),
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"Input(W) of LookupTableDequantOp should not be null."));
|
|
PADDLE_ENFORCE_EQ(
|
|
ids.initialized(),
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"Input(Ids) of LookupTableDequantOp should not be null."));
|
|
PADDLE_ENFORCE_EQ(
|
|
out != nullptr,
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"Output(Out) of LookupTableDequantOp should not be null."));
|
|
|
|
const auto& table_dims = w.dims();
|
|
const auto& ids_dims = ids.dims();
|
|
int ids_rank = ids_dims.size();
|
|
VLOG(5) << "ids rank is " << ids_rank << std::endl;
|
|
PADDLE_ENFORCE_EQ(
|
|
table_dims.size(),
|
|
2,
|
|
common::errors::InvalidArgument(
|
|
"ShapeError: The dimensions of the 'lookup table' must be 2. "
|
|
"But received lookup table's dimensions = %d, "
|
|
"lookup table's shape = [%s].",
|
|
table_dims.size(),
|
|
table_dims));
|
|
PADDLE_ENFORCE_EQ(
|
|
ids_dims[ids_rank - 1],
|
|
1,
|
|
common::errors::InvalidArgument(
|
|
"ShapeError: The last dimensions of the 'Ids' tensor must be 1. "
|
|
"But received Ids's last dimensions = %d, Ids's shape = [%s].",
|
|
ids_dims[ids_rank - 1],
|
|
ids_dims));
|
|
|
|
auto output_dims = vectorize(slice_ddim(ids_dims, 0, ids_rank - 1));
|
|
PADDLE_ENFORCE_GE(table_dims[1],
|
|
2,
|
|
common::errors::InvalidArgument(
|
|
"the second dim of table_dims should be "
|
|
"greater or equal to 2, but the actual shape "
|
|
"is [%s]",
|
|
table_dims));
|
|
|
|
output_dims.push_back((table_dims[1] - 2) * 4);
|
|
|
|
out->set_dims(make_ddim(output_dims));
|
|
out->share_lod(ids);
|
|
out->set_dtype(w.dtype());
|
|
}
|
|
|
|
void LogicalBinaryInferMeta(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
MetaTensor* out) {
|
|
ElementwiseInferMeta(x, y, out);
|
|
if (!(out->is_same_tensor(x))) {
|
|
out->set_dtype(DataType::BOOL);
|
|
}
|
|
}
|
|
|
|
void LUUnpackInferMeta(const MetaTensor& x,
|
|
const MetaTensor& pivots,
|
|
bool unpack_ludata,
|
|
bool unpack_pivots,
|
|
MetaTensor* pmat,
|
|
MetaTensor* l,
|
|
MetaTensor* u) {
|
|
PADDLE_ENFORCE_NOT_NULL(
|
|
pmat,
|
|
common::errors::InvalidArgument("Output(Pmat) should not be nullptr."));
|
|
PADDLE_ENFORCE_NOT_NULL(
|
|
l, common::errors::InvalidArgument("Output(L) should not be nullptr."));
|
|
PADDLE_ENFORCE_NOT_NULL(
|
|
u, common::errors::InvalidArgument("Output(U) should not be nullptr."));
|
|
|
|
auto x_dims = x.dims();
|
|
int x_rank = x_dims.size();
|
|
PADDLE_ENFORCE_GE(x_rank,
|
|
2,
|
|
common::errors::InvalidArgument(
|
|
"The rank of input must greater than 2."));
|
|
|
|
int64_t m = x_dims[x_rank - 2];
|
|
int64_t n = x_dims[x_rank - 1];
|
|
int64_t min_mn = std::min(m, n);
|
|
if (unpack_ludata) {
|
|
auto ldims = x_dims;
|
|
auto udims = x_dims;
|
|
if (m >= n) {
|
|
udims[x_rank - 2] = min_mn;
|
|
} else {
|
|
ldims[x_rank - 1] = min_mn;
|
|
}
|
|
u->set_dims(udims);
|
|
u->set_dtype(x.dtype());
|
|
l->set_dims(ldims);
|
|
l->set_dtype(x.dtype());
|
|
}
|
|
if (unpack_pivots) {
|
|
auto pdims = x_dims;
|
|
pdims[x_rank - 1] = m;
|
|
pmat->set_dims(pdims);
|
|
pmat->set_dtype(x.dtype());
|
|
}
|
|
}
|
|
|
|
void LookupTableInferMeta(const MetaTensor& w,
|
|
const MetaTensor& ids,
|
|
MetaTensor* out) {
|
|
const auto& table_dims = w.dims();
|
|
const auto& ids_dims = ids.dims();
|
|
int ids_rank = ids_dims.size();
|
|
VLOG(5) << "ids rank is " << ids_rank << std::endl;
|
|
PADDLE_ENFORCE_EQ(
|
|
table_dims.size(),
|
|
2,
|
|
common::errors::InvalidArgument(
|
|
"ShapeError: The dimensions of the 'lookup table' must be 2. "
|
|
"But received lookup table's dimensions = %d, "
|
|
"lookup table's shape = [%s].",
|
|
table_dims.size(),
|
|
table_dims));
|
|
PADDLE_ENFORCE_EQ(
|
|
ids_dims[ids_rank - 1],
|
|
1,
|
|
common::errors::InvalidArgument(
|
|
"ShapeError: The last dimensions of the 'Ids' tensor must be 1. "
|
|
"But received Ids's last dimensions = %d, Ids's shape = [%s].",
|
|
ids_dims[ids_rank - 1],
|
|
ids_dims));
|
|
|
|
auto output_dims = vectorize(slice_ddim(ids_dims, 0, ids_rank - 1));
|
|
output_dims.push_back(table_dims[1]);
|
|
out->set_dims(make_ddim(output_dims));
|
|
out->set_dtype(w.dtype());
|
|
out->share_lod(ids);
|
|
}
|
|
|
|
void MarginCrossEntropyInferMeta(const MetaTensor& logits,
|
|
const MetaTensor& label,
|
|
bool return_softmax,
|
|
int ring_id,
|
|
int rank,
|
|
int nranks,
|
|
float margin1,
|
|
float margin2,
|
|
float margin3,
|
|
float scale,
|
|
MetaTensor* softmax,
|
|
MetaTensor* loss,
|
|
MetaConfig config) {
|
|
PADDLE_ENFORCE_NOT_NULL(
|
|
logits,
|
|
common::errors::InvalidArgument("Input of logits should not be null."));
|
|
PADDLE_ENFORCE_NOT_NULL(
|
|
label,
|
|
common::errors::InvalidArgument("Input of label should not be null."));
|
|
auto logits_dims = logits.dims();
|
|
auto labels_dims = label.dims();
|
|
|
|
auto logits_rank = logits_dims.size();
|
|
auto axis = logits_rank - 1;
|
|
for (int i = 0; i < logits_rank; i++) {
|
|
if (i != axis) {
|
|
if (config.is_runtime || (logits_dims[i] > 0 && labels_dims[i] > 0)) {
|
|
PADDLE_ENFORCE_EQ(logits_dims[i],
|
|
labels_dims[i],
|
|
common::errors::InvalidArgument(
|
|
"Input(Logits) and Input(Label) should in "
|
|
"same shape in dimensions except axis."));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (labels_dims.size() > 1) {
|
|
PADDLE_ENFORCE_EQ(
|
|
labels_dims[logits_rank - 1],
|
|
1UL,
|
|
common::errors::InvalidArgument(
|
|
"the last dimension of Input(Label) should be 1."
|
|
"But received: the last dimension of Input(Label) is [%d],"
|
|
"the last dimension is [%d]",
|
|
labels_dims[logits_rank - 1],
|
|
logits_rank - 1));
|
|
}
|
|
|
|
softmax->set_dims(logits_dims);
|
|
softmax->set_dtype(logits.dtype());
|
|
|
|
logits_dims[axis] = 1;
|
|
loss->set_dims(logits_dims);
|
|
loss->set_dtype(logits.dtype());
|
|
|
|
softmax->share_lod(logits);
|
|
loss->share_lod(logits);
|
|
}
|
|
|
|
void MaskedSelectInferMeta(const MetaTensor& x,
|
|
const MetaTensor& mask,
|
|
MetaTensor* out) {
|
|
out->set_dims({-1}); // can not infer
|
|
out->set_dtype(x.dtype());
|
|
}
|
|
|
|
void MaskedFillInferMeta(const MetaTensor& x,
|
|
const MetaTensor& mask,
|
|
const MetaTensor& value,
|
|
MetaTensor* out) {
|
|
auto x_dims = x.dims();
|
|
auto mask_dims = mask.dims();
|
|
auto expanded_dims = funcs::BroadcastTwoDims(x_dims, mask_dims, -1);
|
|
out->set_dims(expanded_dims);
|
|
out->set_dtype(x.dtype());
|
|
}
|
|
|
|
void MatmulInferMeta(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
bool trans_x,
|
|
bool trans_y,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
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();
|
|
const int64_t lhs_reduce_dim = (ndims_x == 1) ? 0 : ndims_x - 1 - trans_x;
|
|
const int64_t rhs_reduce_dim = (ndims_y == 1) ? 0 : ndims_y - 2 + trans_y;
|
|
const int64_t K_lhs = dims_x[lhs_reduce_dim];
|
|
const int64_t K_rhs = dims_y[rhs_reduce_dim];
|
|
if (config.is_runtime || (K_rhs != -1 && K_lhs != -1)) {
|
|
PADDLE_ENFORCE_EQ(
|
|
K_lhs,
|
|
K_rhs,
|
|
common::errors::InvalidArgument(
|
|
"In operator matmul, the [%d] dimension of Input(X) must be equal "
|
|
"to "
|
|
"the [%d] dimension of Input(Y). But receiving the [%d]"
|
|
"dimension of Input(X) is [%d], and the [%d] dimension of "
|
|
"Input(Y) is [%d].",
|
|
lhs_reduce_dim,
|
|
rhs_reduce_dim,
|
|
lhs_reduce_dim,
|
|
K_lhs,
|
|
rhs_reduce_dim,
|
|
K_rhs));
|
|
}
|
|
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) {
|
|
// If one of them is 0, choose 0.
|
|
if (dims_x[i] == 0 || dims_y[i] == 0) {
|
|
new_dims.push_back(0);
|
|
} else {
|
|
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);
|
|
if (x.dtype() == DataType::INT8) {
|
|
out->set_dtype(DataType::INT32);
|
|
} else if (x.dtype() == DataType::FLOAT8_E4M3FN ||
|
|
x.dtype() == DataType::FLOAT8_E5M2) {
|
|
out->set_dtype(DataType::FLOAT16);
|
|
} else {
|
|
out->set_dtype(x.dtype());
|
|
}
|
|
out->set_layout(x.layout());
|
|
out->share_lod(x);
|
|
}
|
|
|
|
void MmOutDtypeInferMeta(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
DataType out_dtype,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
PADDLE_ENFORCE_EQ(
|
|
out_dtype,
|
|
DataType::FLOAT32,
|
|
common::errors::InvalidArgument(
|
|
"The out_dtype of paddle.mm currently only supports float32."));
|
|
PADDLE_ENFORCE_EQ(
|
|
x.dtype(),
|
|
DataType::BFLOAT16,
|
|
common::errors::InvalidArgument(
|
|
"The out_dtype of paddle.mm currently only supports bfloat16 "
|
|
"Input(X)."));
|
|
PADDLE_ENFORCE_EQ(
|
|
y.dtype(),
|
|
DataType::BFLOAT16,
|
|
common::errors::InvalidArgument(
|
|
"The out_dtype of paddle.mm currently only supports bfloat16 "
|
|
"Input(Y)."));
|
|
|
|
auto dims_x = vectorize(x.dims());
|
|
auto dims_y = vectorize(y.dims());
|
|
PADDLE_ENFORCE_EQ(
|
|
dims_x.size(),
|
|
2UL,
|
|
common::errors::InvalidArgument(
|
|
"The out_dtype of paddle.mm currently only supports 2-D Input(X)."));
|
|
PADDLE_ENFORCE_EQ(
|
|
dims_y.size(),
|
|
2UL,
|
|
common::errors::InvalidArgument(
|
|
"The out_dtype of paddle.mm currently only supports 2-D Input(Y)."));
|
|
const int64_t K_lhs = dims_x[1];
|
|
const int64_t K_rhs = dims_y[0];
|
|
if (config.is_runtime || (K_lhs >= 0 && K_rhs >= 0)) {
|
|
PADDLE_ENFORCE_EQ(
|
|
K_lhs,
|
|
K_rhs,
|
|
common::errors::InvalidArgument(
|
|
"Input(X)'s width must equal Input(Y)'s height, but received %d "
|
|
"and %d.",
|
|
K_lhs,
|
|
K_rhs));
|
|
}
|
|
|
|
out->set_dims(make_ddim({dims_x[0], dims_y[1]}));
|
|
out->set_dtype(DataType::FLOAT32);
|
|
out->set_layout(x.layout());
|
|
out->share_lod(x);
|
|
}
|
|
|
|
void MatmulWithFlattenInferMeta(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
int x_num_col_dims,
|
|
int y_num_col_dims,
|
|
MetaTensor* out) {
|
|
auto x_dims = x.dims();
|
|
auto y_dims = y.dims();
|
|
|
|
VLOG(3) << "mul operator x.shape=" << x_dims << " y.shape=" << y_dims
|
|
<< " x_num_col_dims=" << x_num_col_dims
|
|
<< " y_num_col_dims=" << y_num_col_dims;
|
|
|
|
PADDLE_ENFORCE_NE(common::product(y_dims),
|
|
0,
|
|
common::errors::PreconditionNotMet(
|
|
"The Input variable Y has not "
|
|
"been initialized. You may need to confirm "
|
|
"if you put exe.run(startup_program) "
|
|
"after optimizer.minimize function."));
|
|
PADDLE_ENFORCE_GT(
|
|
x_dims.size(),
|
|
x_num_col_dims,
|
|
common::errors::InvalidArgument(
|
|
"The input tensor X's dimensions of MulOp "
|
|
"should be larger than x_num_col_dims. But received X's "
|
|
"dimensions = %d, X's shape = [%s], x_num_col_dims = %d.",
|
|
x_dims.size(),
|
|
x_dims,
|
|
x_num_col_dims));
|
|
PADDLE_ENFORCE_GT(
|
|
y_dims.size(),
|
|
y_num_col_dims,
|
|
common::errors::InvalidArgument(
|
|
"The input tensor Y's dimensions of MulOp "
|
|
"should be larger than y_num_col_dims. But received Y's "
|
|
"dimensions = %d, Y's shape = [%s], y_num_col_dims = %d.",
|
|
y_dims.size(),
|
|
y_dims,
|
|
y_num_col_dims));
|
|
|
|
auto x_mat_dims = flatten_to_2d(x_dims, x_num_col_dims);
|
|
auto y_mat_dims = flatten_to_2d(y_dims, y_num_col_dims);
|
|
|
|
PADDLE_ENFORCE_EQ(
|
|
x_mat_dims[1],
|
|
y_mat_dims[0],
|
|
common::errors::InvalidArgument(
|
|
"After flatten the input tensor X and Y to 2-D dimensions matrix "
|
|
"X1 and Y1, the matrix X1's width must be equal with matrix Y1's "
|
|
"height. But received X's shape = [%s], X1's shape = [%s], X1's "
|
|
"width = %s; Y's shape = [%s], Y1's shape = [%s], Y1's height = "
|
|
"%s.",
|
|
x_dims,
|
|
x_mat_dims,
|
|
x_mat_dims[1],
|
|
y_dims,
|
|
y_mat_dims,
|
|
y_mat_dims[0]));
|
|
std::vector<int64_t> output_dims;
|
|
output_dims.reserve(
|
|
static_cast<size_t>(x_num_col_dims + y_dims.size() - y_num_col_dims));
|
|
|
|
for (int i = 0; i < x_num_col_dims; ++i) {
|
|
output_dims.push_back(x_dims[i]);
|
|
}
|
|
|
|
for (int i = y_num_col_dims; i < y_dims.size(); ++i) {
|
|
output_dims.push_back(y_dims[i]);
|
|
}
|
|
|
|
out->set_dims(make_ddim(output_dims));
|
|
if (x.dtype() == DataType::INT8) {
|
|
out->set_dtype(DataType::INT32);
|
|
} else {
|
|
out->set_dtype(x.dtype());
|
|
}
|
|
out->share_lod(x);
|
|
}
|
|
|
|
void MatrixNMSInferMeta(const MetaTensor& bboxes,
|
|
const MetaTensor& scores,
|
|
float score_threshold,
|
|
int nms_top_k,
|
|
int keep_top_k,
|
|
float post_threshold,
|
|
bool use_gaussian,
|
|
float gaussian_sigma,
|
|
int background_label,
|
|
bool normalized,
|
|
MetaTensor* out,
|
|
MetaTensor* index,
|
|
MetaTensor* roisnum,
|
|
MetaConfig config) {
|
|
auto box_dims = bboxes.dims();
|
|
auto score_dims = scores.dims();
|
|
auto score_size = score_dims.size();
|
|
|
|
if (config.is_runtime) {
|
|
PADDLE_ENFORCE_EQ(
|
|
score_size == 3,
|
|
true,
|
|
errors::InvalidArgument("The rank of Input(Scores) must be 3. "
|
|
"But received rank = %d.",
|
|
score_size));
|
|
PADDLE_ENFORCE_EQ(
|
|
box_dims.size(),
|
|
3,
|
|
errors::InvalidArgument("The rank of Input(BBoxes) must be 3."
|
|
"But received rank = %d.",
|
|
box_dims.size()));
|
|
PADDLE_ENFORCE_EQ(box_dims[2] == 4,
|
|
true,
|
|
errors::InvalidArgument(
|
|
"The last dimension of Input (BBoxes) must be 4, "
|
|
"represents the layout of coordinate "
|
|
"[xmin, ymin, xmax, ymax]."));
|
|
PADDLE_ENFORCE_EQ(
|
|
box_dims[1],
|
|
score_dims[2],
|
|
errors::InvalidArgument(
|
|
"The 2nd dimension of Input(BBoxes) must be equal to "
|
|
"last dimension of Input(Scores), which represents the "
|
|
"predicted bboxes."
|
|
"But received box_dims[1](%s) != score_dims[2](%s)",
|
|
box_dims[1],
|
|
score_dims[2]));
|
|
}
|
|
out->set_dims({-1, box_dims[2] + 2});
|
|
out->set_dtype(bboxes.dtype());
|
|
index->set_dims({-1, 1});
|
|
index->set_dtype(DataType::INT32);
|
|
if (roisnum != nullptr) {
|
|
roisnum->set_dims({score_dims[0]});
|
|
roisnum->set_dtype(DataType::INT32);
|
|
}
|
|
}
|
|
|
|
void MatrixRankStaticInferMeta(const MetaTensor& x,
|
|
const MetaTensor& atol_tensor,
|
|
bool use_default_tol,
|
|
bool hermitian,
|
|
MetaTensor* out) {
|
|
if (atol_tensor) {
|
|
MatrixRankTolInferMeta(x, atol_tensor, use_default_tol, hermitian, out);
|
|
} else {
|
|
MatrixRankInferMeta(x, use_default_tol, hermitian, out);
|
|
}
|
|
}
|
|
|
|
void MatrixRankTolInferMeta(const MetaTensor& x,
|
|
const MetaTensor& atol_tensor,
|
|
bool use_default_tol,
|
|
bool hermitian,
|
|
MetaTensor* out) {
|
|
auto dim_x = x.dims();
|
|
PADDLE_ENFORCE_GE(dim_x.size(),
|
|
2,
|
|
common::errors::InvalidArgument(
|
|
"The dims of input must be greater than 2"));
|
|
|
|
if (hermitian && x.numel() != 0) {
|
|
int64_t rows = static_cast<int64_t>(dim_x[dim_x.size() - 2]);
|
|
int64_t cols = static_cast<int64_t>(dim_x[dim_x.size() - 1]);
|
|
// if x is 0 size tensor,ignore rows == cols check.
|
|
PADDLE_ENFORCE_EQ(rows,
|
|
cols,
|
|
common::errors::InvalidArgument(
|
|
"if hermitian == true, matrix should be n*n"));
|
|
}
|
|
DDim dim_x_batch = detail::CheckAndGetOutputDim(dim_x);
|
|
auto dim_tol = atol_tensor.dims();
|
|
if (x.numel() == 0) {
|
|
if (dim_x.size() == 2) {
|
|
out->set_dims(make_ddim({}));
|
|
} else {
|
|
out->set_dims(dim_x_batch);
|
|
}
|
|
} else if (dim_x_batch == dim_tol) {
|
|
out->set_dims(dim_x_batch);
|
|
} else {
|
|
int max_dim = std::max(dim_x_batch.size(), dim_tol.size());
|
|
int axis = std::abs(dim_x_batch.size() - dim_tol.size());
|
|
std::vector<int64_t> x_batch_dims_array(max_dim);
|
|
std::vector<int64_t> tol_dims_array(max_dim);
|
|
std::vector<int64_t> out_dims_array(max_dim);
|
|
funcs::GetBroadcastDimsArrays(dim_x_batch,
|
|
dim_tol,
|
|
x_batch_dims_array.data(),
|
|
tol_dims_array.data(),
|
|
out_dims_array.data(),
|
|
max_dim,
|
|
axis);
|
|
out->set_dims(make_ddim(out_dims_array));
|
|
}
|
|
out->share_lod(x);
|
|
}
|
|
|
|
void MulticlassNmsv1InferMeta(const MetaTensor& bboxes,
|
|
const MetaTensor& scores,
|
|
float score_threshold,
|
|
int nms_top_k,
|
|
int keep_top_k,
|
|
float nms_threshold,
|
|
float nms_eta,
|
|
bool normalized,
|
|
int background_label,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
const auto& box_dims = bboxes.dims();
|
|
const auto& score_dims = scores.dims();
|
|
int score_size = static_cast<int>(score_dims.size());
|
|
|
|
if (config.is_runtime) {
|
|
PADDLE_ENFORCE_EQ(score_size == 2 || score_size == 3,
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"The rank of Input(Scores) must be 2 or 3"
|
|
". But received rank = %d",
|
|
score_size));
|
|
PADDLE_ENFORCE_EQ(
|
|
box_dims.size(),
|
|
3,
|
|
common::errors::InvalidArgument("The rank of Input(BBoxes) must be 3"
|
|
". But received rank = %d",
|
|
box_dims.size()));
|
|
if (score_size == 3) {
|
|
PADDLE_ENFORCE_EQ(box_dims[2] == 4 || box_dims[2] == 8 ||
|
|
box_dims[2] == 16 || box_dims[2] == 24 ||
|
|
box_dims[2] == 32,
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"The last dimension of Input"
|
|
"(BBoxes) must be 4 or 8, "
|
|
"represents the layout of coordinate "
|
|
"[xmin, ymin, xmax, ymax] or "
|
|
"4 points: [x1, y1, x2, y2, x3, y3, x4, y4] or "
|
|
"8 points: [xi, yi] i= 1,2,...,8 or "
|
|
"12 points: [xi, yi] i= 1,2,...,12 or "
|
|
"16 points: [xi, yi] i= 1,2,...,16"));
|
|
PADDLE_ENFORCE_EQ(
|
|
box_dims[1],
|
|
score_dims[2],
|
|
common::errors::InvalidArgument(
|
|
"The 2nd dimension of Input(BBoxes) must be equal to "
|
|
"last dimension of Input(Scores), which represents the "
|
|
"predicted bboxes."
|
|
"But received box_dims[1](%s) != score_dims[2](%s)",
|
|
box_dims[1],
|
|
score_dims[2]));
|
|
} else {
|
|
PADDLE_ENFORCE_EQ(box_dims[2],
|
|
4,
|
|
common::errors::InvalidArgument(
|
|
"The last dimension of Input"
|
|
"(BBoxes) must be 4. But received dimension = %d",
|
|
box_dims[2]));
|
|
PADDLE_ENFORCE_EQ(
|
|
box_dims[1],
|
|
score_dims[1],
|
|
common::errors::InvalidArgument(
|
|
"The 2nd dimension of Input"
|
|
"(BBoxes) must be equal to the 2nd dimension of Input(Scores). "
|
|
"But received box dimension = %d, score dimension = %d",
|
|
box_dims[1],
|
|
score_dims[1]));
|
|
}
|
|
}
|
|
// Here the box_dims[0] is not the real dimension of output.
|
|
// It will be rewritten in the computing kernel.
|
|
out->set_dims({-1, box_dims[2] + 2});
|
|
out->set_dtype(scores.dtype());
|
|
}
|
|
|
|
void MvInferMeta(const MetaTensor& x, const MetaTensor& vec, MetaTensor* out) {
|
|
auto dim_x = x.dims();
|
|
auto dim_vec = vec.dims();
|
|
PADDLE_ENFORCE_EQ(
|
|
dim_x.size(),
|
|
2,
|
|
common::errors::InvalidArgument(
|
|
"The rank of input X should be 2, but is %d", dim_x.size()));
|
|
PADDLE_ENFORCE_EQ(
|
|
dim_vec.size(),
|
|
1,
|
|
common::errors::InvalidArgument(
|
|
"The rank of input Vec should be 1, but is %d", dim_vec.size()));
|
|
PADDLE_ENFORCE_EQ(dim_x[1],
|
|
dim_vec[0],
|
|
common::errors::InvalidArgument(
|
|
"X's second dimension is expected to be equal to "
|
|
"Vec's first dimension, "
|
|
"but received X'shape = [%s], Vec's shape = [%s]",
|
|
dim_x,
|
|
dim_vec));
|
|
|
|
auto dim_out = make_ddim({dim_x[0]});
|
|
|
|
out->set_dims(dim_out);
|
|
out->set_dtype(x.dtype());
|
|
out->set_layout(x.layout());
|
|
out->share_lod(x);
|
|
}
|
|
|
|
void PReluInferMeta(const MetaTensor& x,
|
|
const MetaTensor& alpha,
|
|
const std::string& data_format,
|
|
const std::string& mode,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
auto x_dim = x.dims();
|
|
if (mode == "all") {
|
|
PADDLE_ENFORCE_EQ(common::product(alpha.dims()),
|
|
1,
|
|
common::errors::InvalidArgument(
|
|
"For mode 'all', size of weight Alpha must be one. "
|
|
"But received alpha's size: %d.",
|
|
product(alpha.dims())));
|
|
} else if (mode == "channel") {
|
|
auto x_rank = x_dim.size();
|
|
PADDLE_ENFORCE_GE(x_rank,
|
|
2,
|
|
common::errors::InvalidArgument(
|
|
"For mode 'channel', rank of input X must be "
|
|
"equal or larger than 2. But received X's "
|
|
"rank: %d",
|
|
x_rank));
|
|
PADDLE_ENFORCE_EQ(data_format == "NCHW" || data_format == "NHWC",
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"For mode 'channel', data_format must be one of "
|
|
"NCHW and NHWC. But received data_format: %s",
|
|
data_format));
|
|
if (data_format == "NCHW" || config.is_run_onednn_kernel) {
|
|
PADDLE_ENFORCE_EQ(product(alpha.dims()) == x_dim[1],
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"For mode 'channel', size of weight Alpha must be "
|
|
"equal to the number of channels of input(x). But "
|
|
"received alpha's size: %d, x_dim[1]: %d",
|
|
product(alpha.dims()),
|
|
x_dim[1]));
|
|
} else {
|
|
PADDLE_ENFORCE_EQ(product(alpha.dims()) == x_dim[x_rank - 1],
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"For mode 'channel', size of weight Alpha must be "
|
|
"equal to the number of channels of input(x). But "
|
|
"received alpha's size: %d, x_dim[%d]: %d",
|
|
product(alpha.dims()),
|
|
x_rank - 1,
|
|
x_dim[x_rank - 1]));
|
|
}
|
|
} else if (mode == "element") {
|
|
auto alpha_dim = alpha.dims();
|
|
auto alpha_rank = alpha_dim.size();
|
|
int x_rank = x_dim.size();
|
|
PADDLE_ENFORCE_GE(x_rank,
|
|
1,
|
|
common::errors::InvalidArgument(
|
|
"For mode 'element', rank of input X must be "
|
|
"equal or larger than 1. But received X's "
|
|
"rank: %d",
|
|
x_rank));
|
|
PADDLE_ENFORCE_EQ(
|
|
alpha_rank,
|
|
x_rank,
|
|
common::errors::InvalidArgument(
|
|
"For mode 'element', rank of weight Alpha must be equal to the "
|
|
"rank of input(x). But received alpha's rank: %d, x's rank: %d.",
|
|
alpha_rank,
|
|
x_rank));
|
|
size_t x_product = 1;
|
|
size_t alpha_product = 1;
|
|
for (int i = x_rank - 1; i > 0; i--) {
|
|
x_product *= x_dim[i];
|
|
alpha_product *= alpha_dim[i];
|
|
}
|
|
PADDLE_ENFORCE_EQ(
|
|
alpha_product,
|
|
x_product,
|
|
common::errors::InvalidArgument(
|
|
"For mode 'element', the size of weight Alpha must be "
|
|
"equal to the size of input(x). But received alpha's size: %d, "
|
|
"x's size: %d.",
|
|
alpha_product,
|
|
x_product));
|
|
} else {
|
|
PADDLE_THROW(common::errors::InvalidArgument(
|
|
"Attr(mode) of prelu must be one of 'all', 'channel', or 'element'. "
|
|
"But received "
|
|
"mode: '%s'.",
|
|
mode));
|
|
}
|
|
out->set_dims(x_dim);
|
|
out->set_dtype(x.dtype());
|
|
out->set_layout(x.layout());
|
|
out->share_lod(x);
|
|
}
|
|
|
|
void PullGpupsSparseInferMeta(const MetaTensor& w,
|
|
const std::vector<const MetaTensor*>& ids,
|
|
const std::vector<int>& size,
|
|
bool is_sparse,
|
|
bool is_distributed,
|
|
std::vector<MetaTensor*> out) {
|
|
PADDLE_ENFORCE_GE(
|
|
ids.size(),
|
|
1UL,
|
|
common::errors::InvalidArgument(
|
|
"Inputs(Ids) of PullGpuPSSparseOp should not be empty."));
|
|
PADDLE_ENFORCE_GE(
|
|
out.size(),
|
|
1UL,
|
|
common::errors::InvalidArgument(
|
|
"Outputs(Out) of PullGpuPSSparseOp should not be empty."));
|
|
PADDLE_ENFORCE_EQ(
|
|
ids.size(),
|
|
size.size(),
|
|
common::errors::InvalidArgument("The ids size: %lu must be equal to "
|
|
"the length of embedding size: %lu.",
|
|
ids.size(),
|
|
size.size()));
|
|
const size_t n_ids = ids.size();
|
|
std::vector<DDim> outs_dims;
|
|
outs_dims.resize(n_ids);
|
|
for (size_t i = 0; i < n_ids; ++i) {
|
|
int64_t embedding_size = size[i];
|
|
const auto ids_dims = ids[i]->dims();
|
|
int ids_rank = ids_dims.size();
|
|
PADDLE_ENFORCE_EQ(ids_dims[ids_rank - 1],
|
|
1,
|
|
common::errors::InvalidArgument(
|
|
"Shape error in %lu id, the last dimension of the "
|
|
"'Ids' tensor must be 1.",
|
|
i));
|
|
auto out_dim = vectorize(slice_ddim(ids_dims, 0, ids_rank - 1));
|
|
out_dim.push_back(embedding_size);
|
|
outs_dims[i] = make_ddim(out_dim);
|
|
}
|
|
|
|
for (size_t i = 0; i < n_ids; ++i) {
|
|
out[i]->set_dims(outs_dims[i]);
|
|
out[i]->share_lod(*ids[i], i);
|
|
out[i]->set_dtype(w.dtype());
|
|
}
|
|
}
|
|
|
|
void PullSparseV2InferMeta(const std::vector<const MetaTensor*>& ids,
|
|
const std::vector<const MetaTensor*>& w,
|
|
int embedding_dim,
|
|
int table_id,
|
|
const std::string& accessor_class,
|
|
const std::string& ctrlabel_name,
|
|
int padding_id,
|
|
bool scale_sparse_grad,
|
|
const std::vector<std::string>& input_names,
|
|
bool is_distributed,
|
|
std::vector<MetaTensor*> out) {
|
|
PADDLE_ENFORCE_GE(ids.size(),
|
|
1UL,
|
|
common::errors::InvalidArgument(
|
|
"Input(Ids) of PullSparseV2Op can not be null"));
|
|
PADDLE_ENFORCE_GE(out.size(),
|
|
1UL,
|
|
common::errors::InvalidArgument(
|
|
"Output(Out) of PullSparseV2Op can not be null"));
|
|
|
|
auto hidden_size = embedding_dim;
|
|
const size_t n_ids = ids.size();
|
|
std::vector<DDim> outs_dims;
|
|
outs_dims.resize(n_ids);
|
|
for (size_t i = 0; i < n_ids; ++i) {
|
|
const auto ids_dims = ids[i]->dims();
|
|
auto out_dim = vectorize(ids_dims);
|
|
out_dim.push_back(hidden_size);
|
|
outs_dims[i] = make_ddim(out_dim);
|
|
}
|
|
|
|
for (size_t i = 0; i < n_ids; ++i) {
|
|
out[i]->set_dims(outs_dims[i]);
|
|
out[i]->share_lod(*ids[i], i);
|
|
out[i]->set_dtype(w[i]->dtype());
|
|
}
|
|
}
|
|
|
|
void ApplyPerChannelScaleInferMeta(const MetaTensor& x,
|
|
const MetaTensor& scales,
|
|
MetaTensor* out) {
|
|
auto x_dim = x.dims();
|
|
auto scales_dim = scales.dims();
|
|
PADDLE_ENFORCE_EQ(
|
|
x_dim.size(),
|
|
2,
|
|
common::errors::InvalidArgument(
|
|
"The rank of Input(x) must be 2, but received %d.", x_dim.size()));
|
|
|
|
PADDLE_ENFORCE_EQ(scales_dim.size(),
|
|
1,
|
|
common::errors::InvalidArgument(
|
|
"The rank of Input(scales) must be 1, but received %d.",
|
|
scales_dim.size()));
|
|
|
|
PADDLE_ENFORCE_EQ(
|
|
x_dim[1],
|
|
scales_dim[0],
|
|
common::errors::InvalidArgument(
|
|
"The second dim of Input(x) must be equal to the first dim of scales,"
|
|
"but received %d and %d.",
|
|
x_dim[2],
|
|
scales_dim[1]));
|
|
|
|
out->set_dtype(x.dtype());
|
|
out->set_dims(x_dim);
|
|
out->set_layout(x.layout());
|
|
}
|
|
|
|
inline void ExpandAspectRatios(const std::vector<float>& input_aspect_ratio,
|
|
bool flip,
|
|
std::vector<float>* output_aspect_ratio) {
|
|
constexpr float epsilon = 1e-6;
|
|
output_aspect_ratio->clear();
|
|
output_aspect_ratio->push_back(1.0f);
|
|
for (auto ar : input_aspect_ratio) {
|
|
bool already_exist = false;
|
|
for (auto item : *output_aspect_ratio) {
|
|
if (fabs(ar - item) < epsilon) {
|
|
already_exist = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!already_exist) {
|
|
output_aspect_ratio->push_back(ar);
|
|
if (flip) {
|
|
output_aspect_ratio->push_back(1.0f / ar);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void PriorBoxInferMeta(const MetaTensor& input,
|
|
const MetaTensor& image,
|
|
const std::vector<float>& min_sizes,
|
|
const std::vector<float>& max_sizes,
|
|
const std::vector<float>& aspect_ratios,
|
|
const std::vector<float>& variances,
|
|
bool flip,
|
|
bool clip,
|
|
float step_w,
|
|
float step_h,
|
|
float offset,
|
|
bool min_max_aspect_ratios_order,
|
|
MetaTensor* out,
|
|
MetaTensor* var) {
|
|
auto image_dims = image.dims();
|
|
auto input_dims = input.dims();
|
|
|
|
PADDLE_ENFORCE_EQ(
|
|
image_dims.size(),
|
|
4,
|
|
common::errors::InvalidArgument(
|
|
"The Input(Image) of Op(PriorBoxOp) should be a 4-D Tensor "
|
|
"and data format is NCHW. But received Image's dimensions = %d, "
|
|
"shape = [%s].",
|
|
image_dims.size(),
|
|
image_dims));
|
|
PADDLE_ENFORCE_EQ(
|
|
input_dims.size(),
|
|
4,
|
|
common::errors::InvalidArgument(
|
|
"The Input(Input) of Op(PriorBoxOp) should be a 4-D Tensor "
|
|
"and data format is NCHW. But received Input's dimensions = %d, "
|
|
"shape = [%s].",
|
|
input_dims.size(),
|
|
input_dims));
|
|
|
|
std::vector<float> aspect_ratios_vec;
|
|
ExpandAspectRatios(aspect_ratios, flip, &aspect_ratios_vec);
|
|
|
|
size_t num_priors = aspect_ratios_vec.size() * min_sizes.size();
|
|
if (!max_sizes.empty()) {
|
|
PADDLE_ENFORCE_EQ(
|
|
max_sizes.size(),
|
|
min_sizes.size(),
|
|
common::errors::InvalidArgument(
|
|
"The length of min_size and "
|
|
"max_size must be equal. But received: min_size's length is %d, "
|
|
"max_size's length is %d.",
|
|
min_sizes.size(),
|
|
max_sizes.size()));
|
|
num_priors += max_sizes.size();
|
|
for (size_t i = 0; i < max_sizes.size(); ++i) {
|
|
PADDLE_ENFORCE_GT(
|
|
max_sizes[i],
|
|
min_sizes[i],
|
|
common::errors::InvalidArgument(
|
|
"max_size[%d] must be greater "
|
|
"than min_size[%d]. But received: max_size[%d] is %f, "
|
|
"min_size[%d] is %f.",
|
|
i,
|
|
i,
|
|
i,
|
|
max_sizes[i],
|
|
i,
|
|
min_sizes[i]));
|
|
}
|
|
}
|
|
|
|
std::vector<int64_t> dim_vec(4);
|
|
dim_vec[0] = input_dims[2];
|
|
dim_vec[1] = input_dims[3];
|
|
dim_vec[2] = static_cast<int64_t>(num_priors);
|
|
dim_vec[3] = 4;
|
|
|
|
out->set_dtype(input.dtype());
|
|
var->set_dtype(input.dtype());
|
|
out->set_dims(make_ddim(dim_vec));
|
|
var->set_dims(make_ddim(dim_vec));
|
|
}
|
|
|
|
void PruneGateByCapacityInferMeta(const MetaTensor& gate_idx,
|
|
const MetaTensor& expert_count,
|
|
int64_t n_expert,
|
|
int64_t n_worker,
|
|
MetaTensor* new_gate_idx) {
|
|
auto expert_count_dims = expert_count.dims();
|
|
|
|
int64_t expert_count_num_ele = 1;
|
|
for (int i = 0; i < static_cast<int>(expert_count_dims.size()); i++) {
|
|
expert_count_num_ele *= expert_count_dims[i];
|
|
}
|
|
|
|
PADDLE_ENFORCE_EQ(
|
|
expert_count_num_ele,
|
|
n_expert * n_worker,
|
|
common::errors::Unavailable(
|
|
"The number of elements for expert_count is ( %ld ) incorrect. "
|
|
"Because the number of expert_count must equal the "
|
|
"product of n_worker ( %ld ) and n_expert ( %ld ). "
|
|
"Please input appropriate expert_count again!",
|
|
expert_count_num_ele,
|
|
n_worker,
|
|
n_expert));
|
|
|
|
auto gate_idx_in_dims = gate_idx.dims();
|
|
new_gate_idx->set_dims(gate_idx_in_dims);
|
|
new_gate_idx->set_dtype(gate_idx.dtype());
|
|
}
|
|
|
|
void PullBoxSparseInferMeta(const MetaTensor& w,
|
|
const std::vector<const MetaTensor*>& ids,
|
|
bool is_sparse,
|
|
bool is_distributed,
|
|
int size,
|
|
std::vector<MetaTensor*> out) {
|
|
auto hidden_size = static_cast<int64_t>(size);
|
|
const size_t n_ids = ids.size();
|
|
for (size_t i = 0; i < n_ids; ++i) {
|
|
MetaTensor* output = out[i];
|
|
auto ids_dims = ids[i]->dims();
|
|
int ids_rank = ids_dims.size();
|
|
PADDLE_ENFORCE_EQ(ids_dims[ids_rank - 1],
|
|
1UL,
|
|
common::errors::InvalidArgument(
|
|
"Shape error in %lu id, the last dimension of the "
|
|
"'Ids' tensor must be 1.",
|
|
i));
|
|
auto out_dim = vectorize(slice_ddim(ids_dims, 0, ids_rank - 1));
|
|
out_dim.push_back(hidden_size);
|
|
output->set_dims(make_ddim(out_dim));
|
|
output->share_lod(*ids[i]);
|
|
output->set_dtype(w.dtype());
|
|
}
|
|
}
|
|
|
|
void RepeatInterleaveWithTensorIndexInferMeta(const MetaTensor& x,
|
|
const MetaTensor& repeats,
|
|
int dim,
|
|
int64_t output_size,
|
|
MetaTensor* out) {
|
|
const auto& input_dim = x.dims();
|
|
auto output_dim = vectorize(input_dim);
|
|
PADDLE_ENFORCE_EQ(
|
|
dim < input_dim.size() && dim >= (0 - input_dim.size()),
|
|
true,
|
|
common::errors::OutOfRange(
|
|
"Attr(dim) is out of range, It's expected "
|
|
"to be in range of [-%d, %d]. But received Attr(dim) = %d.",
|
|
input_dim.size(),
|
|
input_dim.size() - 1,
|
|
dim));
|
|
|
|
auto repeats_dim = repeats.dims();
|
|
|
|
PADDLE_ENFORCE_EQ(
|
|
repeats_dim.size() == 1 ||
|
|
(repeats_dim.size() == 2 && repeats_dim[1] == 1),
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"The 'shape' of Input(RepeatsTensor) must be 1-D tensor. "
|
|
"But received: the 'shape' of Input(Index) is [%s], "
|
|
"the dimension of Input(Index) is [%d].",
|
|
repeats_dim,
|
|
repeats_dim.size()));
|
|
|
|
if (input_dim.size() == 1 && input_dim[0] == 0) {
|
|
output_dim[0] = 0;
|
|
} else {
|
|
PADDLE_ENFORCE_EQ(repeats_dim[0] != 0,
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"The length of Input(RepeatsTensor) can't be 0."));
|
|
PADDLE_ENFORCE_NE(
|
|
out,
|
|
nullptr,
|
|
common::errors::InvalidArgument(
|
|
"repeat_interleave's output tensor can't be nullptr"));
|
|
if (dim < 0) {
|
|
dim += input_dim.size();
|
|
}
|
|
if (output_size > 0) {
|
|
// Use provided output_size to avoid stream synchronization
|
|
output_dim[dim] = output_size;
|
|
} else {
|
|
output_dim[dim] = -1;
|
|
}
|
|
}
|
|
|
|
out->set_dims(make_ddim(output_dim));
|
|
out->share_lod(x);
|
|
out->set_dtype(x.dtype());
|
|
}
|
|
|
|
void RmsNormInferMeta(const MetaTensor& x,
|
|
const MetaTensor& scale,
|
|
const std::vector<int64_t>& normalized_shape,
|
|
double epsilon,
|
|
MetaTensor* y,
|
|
MetaTensor* invvar) {
|
|
auto x_dim = x.dims();
|
|
// std::vector<int64_t> normalized_shape_data = normalized_shape.GetData();
|
|
int normalized_shape_size = normalized_shape.size();
|
|
int x_dims_size = x_dim.size();
|
|
int begin_norm_axis = x_dims_size - normalized_shape_size;
|
|
|
|
PADDLE_ENFORCE_GT(begin_norm_axis,
|
|
0,
|
|
common::errors::InvalidArgument(
|
|
"'begin_norm_axis' in Op(LayerNorm) should be "
|
|
"greater than zero. But received [%d].",
|
|
begin_norm_axis));
|
|
|
|
PADDLE_ENFORCE_LT(
|
|
begin_norm_axis,
|
|
x_dims_size,
|
|
common::errors::InvalidArgument(
|
|
"'begin_norm_axis' must be less than the dimensions of X,"
|
|
"But received 'begin_norm_axis' is [%d],"
|
|
"received the dimensions of X is [%d].",
|
|
begin_norm_axis,
|
|
x_dims_size));
|
|
|
|
for (int i = 0; i < normalized_shape_size; i++) {
|
|
PADDLE_ENFORCE_EQ(x_dim[x_dims_size - i - 1],
|
|
normalized_shape[normalized_shape_size - i - 1],
|
|
common::errors::InvalidArgument(
|
|
"The %d-th dimension of X is not equal to the %d-th "
|
|
"dimension of NormalizedShape.",
|
|
x_dims_size - i - 1,
|
|
normalized_shape_size - i - 1));
|
|
}
|
|
|
|
if (scale) {
|
|
auto scale_dim = scale.dims();
|
|
PADDLE_ENFORCE_EQ(scale_dim.size(),
|
|
normalized_shape_size,
|
|
common::errors::InvalidArgument(
|
|
"The dimensions of Input(Scale) must be equal to the "
|
|
"dimensions of NormalizedShape. "
|
|
"But received: the dimensions of Input(Scale) is "
|
|
"[%d], the dimensions of NormalizedShape is [%d].",
|
|
scale_dim.size(),
|
|
normalized_shape_size));
|
|
for (int i = 0; i < normalized_shape_size; i++) {
|
|
PADDLE_ENFORCE_EQ(scale_dim[i],
|
|
normalized_shape[i],
|
|
common::errors::InvalidArgument(
|
|
"The %d-th dimension of Input(Scale) is not equal "
|
|
"to the %d-th dimension of NormalizedShape.",
|
|
i,
|
|
i));
|
|
}
|
|
}
|
|
|
|
auto before_norm_dims = slice_ddim(x_dim, 0, begin_norm_axis);
|
|
|
|
PADDLE_ENFORCE_EQ(epsilon >= 0.0f && epsilon <= 0.001f,
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"'epsilon' in Op(LayerNorm) should be between"
|
|
"0.0 and 0.001, But received [%s].",
|
|
epsilon));
|
|
|
|
DataType x_dtype = x.dtype();
|
|
y->set_dims(x_dim);
|
|
y->set_dtype(x_dtype);
|
|
|
|
DataType param_type =
|
|
(x_dtype == DataType::BFLOAT16 || x_dtype == DataType::FLOAT16)
|
|
? DataType::FLOAT32
|
|
: x_dtype;
|
|
invvar->set_dims({before_norm_dims});
|
|
invvar->set_dtype(param_type);
|
|
}
|
|
|
|
void RowConvInferMeta(const MetaTensor& x,
|
|
const MetaTensor& filter,
|
|
MetaTensor* out) {
|
|
auto filter_dims = filter.dims();
|
|
PADDLE_ENFORCE_EQ(filter_dims.size(),
|
|
2,
|
|
common::errors::InvalidArgument(
|
|
"Input(Filter)'s dimensions should be 2. Received: "
|
|
"Input(Filter)'s shape: [%s].",
|
|
filter_dims));
|
|
out->set_dims(x.dims());
|
|
out->share_lod(x);
|
|
out->set_dtype(x.dtype());
|
|
}
|
|
|
|
void SearchsortedInferMeta(const MetaTensor& sorted_sequence,
|
|
const MetaTensor& value,
|
|
bool out_int32,
|
|
bool right,
|
|
MetaTensor* out) {
|
|
auto sequences_dims = sorted_sequence.dims();
|
|
auto values_dims = value.dims();
|
|
PADDLE_ENFORCE_GE(
|
|
sequences_dims.size(),
|
|
1,
|
|
common::errors::InvalidArgument(
|
|
"Input sequences's dimension(%d) must be greater or equal than 1",
|
|
sequences_dims.size()));
|
|
|
|
bool flag = true;
|
|
if (sequences_dims.size() != values_dims.size()) {
|
|
flag = false;
|
|
}
|
|
const int& sequences_dims_size = sequences_dims.size();
|
|
for (int dim = 0; dim < sequences_dims_size - 1; ++dim) {
|
|
if (sequences_dims[dim] != values_dims[dim]) {
|
|
flag = false;
|
|
break;
|
|
}
|
|
}
|
|
if (sequences_dims.size() != 1) {
|
|
PADDLE_ENFORCE_EQ(
|
|
flag,
|
|
true,
|
|
common::errors::Unavailable(
|
|
"The dimensions of sorted_sequence tensor ( %s ) and values "
|
|
"tensor ( %s ) can not match. Because the input sorted_sequence "
|
|
"tensor must be 1 dimension or the first N-1 dimensions of "
|
|
"sorted_sequence tensor and input values tensor must match. "
|
|
"Please input appropriate sorted_sequence and values again! ",
|
|
sequences_dims,
|
|
values_dims));
|
|
}
|
|
|
|
if (out_int32) {
|
|
PADDLE_ENFORCE_LT(
|
|
sequences_dims[sequences_dims.size() - 1],
|
|
std::numeric_limits<int>::max(),
|
|
common::errors::Unavailable(
|
|
"The size of sorted_sequence %d exceed the maximum limit %d. "
|
|
"Because the size of sorted_sequence should be less than the "
|
|
"output maximum value for int32 bit. Please set appropriate "
|
|
"sorted_sequence to meet this requirement! ",
|
|
sequences_dims[sequences_dims.size() - 1],
|
|
std::numeric_limits<int>::max()));
|
|
}
|
|
|
|
out->set_dims(values_dims);
|
|
if (out_int32) {
|
|
out->set_dtype(DataType::INT32);
|
|
} else {
|
|
out->set_dtype(DataType::INT64);
|
|
}
|
|
}
|
|
|
|
void SequenceExpandInferMeta(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
int ref_level,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
const auto& x_dims = x.dims();
|
|
auto out_dims = x_dims;
|
|
|
|
PADDLE_ENFORCE_GE(
|
|
x_dims.size(),
|
|
2,
|
|
common::errors::InvalidArgument(
|
|
"Dimension number of Input(X) should be at least 2. But "
|
|
"received: input rank %u, input shape [%s].",
|
|
x_dims.size(),
|
|
x_dims));
|
|
|
|
if (config.is_runtime) {
|
|
} else {
|
|
out_dims[0] = -1;
|
|
}
|
|
out->set_dims(out_dims);
|
|
out->share_lod(x);
|
|
out->set_dtype(x.dtype());
|
|
}
|
|
|
|
void ShapeBroadcastInferMeta(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
MetaTensor* out) {
|
|
const auto& x_dims = x.dims();
|
|
const auto& y_dims = y.dims();
|
|
PADDLE_ENFORCE_EQ(
|
|
x_dims.size(),
|
|
1,
|
|
common::errors::InvalidArgument(
|
|
"The rank of x must be 1. But received: %d", x_dims.size()));
|
|
PADDLE_ENFORCE_EQ(
|
|
y_dims.size(),
|
|
1,
|
|
common::errors::InvalidArgument(
|
|
"The rank of y must be 1. But received: %d", y_dims.size()));
|
|
|
|
if (x_dims[0] <= y_dims[0]) {
|
|
out->set_dims(y_dims);
|
|
} else {
|
|
out->set_dims(x_dims);
|
|
}
|
|
out->set_dtype(x.dtype());
|
|
}
|
|
|
|
void ShuffleBatchInferMeta(const MetaTensor& x,
|
|
const MetaTensor& seed,
|
|
int startup_seed,
|
|
MetaTensor* out,
|
|
MetaTensor* shuffle_idx,
|
|
MetaTensor* seed_out
|
|
|
|
) {
|
|
out->share_dims(x);
|
|
out->share_lod(x);
|
|
out->set_dtype(x.dtype());
|
|
seed_out->share_dims(seed);
|
|
seed_out->share_lod(seed);
|
|
seed_out->set_dtype(seed.dtype());
|
|
shuffle_idx->set_dims(make_ddim({-1}));
|
|
}
|
|
|
|
void SlowConvDilatedInferMeta(const MetaTensor& input,
|
|
const MetaTensor& filter,
|
|
const MetaTensor& bias,
|
|
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,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
ConvInferMeta(input,
|
|
filter,
|
|
strides,
|
|
paddings,
|
|
padding_algorithm,
|
|
dilations,
|
|
groups,
|
|
data_format,
|
|
out,
|
|
config);
|
|
}
|
|
|
|
void SlowConv3DDilatedInferMeta(const MetaTensor& input,
|
|
const MetaTensor& filter,
|
|
const MetaTensor& bias,
|
|
const std::vector<int>& strides,
|
|
const std::vector<int>& paddings,
|
|
const std::string& padding_algorithm,
|
|
int groups,
|
|
const std::vector<int>& dilations,
|
|
const std::string& data_format,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
ConvInferMeta(input,
|
|
filter,
|
|
strides,
|
|
paddings,
|
|
padding_algorithm,
|
|
dilations,
|
|
groups,
|
|
data_format,
|
|
out,
|
|
config);
|
|
}
|
|
|
|
void SequenceMaskInferMeta(const MetaTensor& x,
|
|
const MetaTensor& max_len_tensor,
|
|
int maxlen,
|
|
DataType out_dtype,
|
|
MetaTensor* y) {
|
|
auto dim = vectorize<int>(x.dims());
|
|
|
|
if (max_len_tensor) {
|
|
dim.push_back(-1);
|
|
} else {
|
|
dim.push_back(maxlen > 0 ? maxlen : -1);
|
|
}
|
|
|
|
y->set_dims(make_ddim(dim));
|
|
y->set_dtype(out_dtype);
|
|
}
|
|
|
|
void ReduceAsInferMeta(const MetaTensor& x,
|
|
const MetaTensor& target,
|
|
MetaTensor* out) {
|
|
DataType out_dtype;
|
|
if (x.dtype() == DataType::BOOL || x.dtype() == DataType::INT32) {
|
|
out_dtype = DataType::INT64;
|
|
} else {
|
|
out_dtype = x.dtype();
|
|
}
|
|
out->set_dtype(out_dtype);
|
|
out->set_dims(target.dims());
|
|
out->set_layout(x.layout());
|
|
}
|
|
|
|
void SoftmaxMaskFuseInferMeta(const MetaTensor& x,
|
|
const MetaTensor& mask,
|
|
MetaTensor* out) {
|
|
auto x_dims = x.dims();
|
|
auto mask_dims = mask.dims();
|
|
|
|
PADDLE_ENFORCE_EQ(
|
|
x_dims.size(),
|
|
4,
|
|
common::errors::InvalidArgument("Input x must be in 4D dimension but "
|
|
"received the dimension of X is %d",
|
|
x_dims.size()));
|
|
PADDLE_ENFORCE_EQ(
|
|
mask_dims.size(),
|
|
4,
|
|
common::errors::InvalidArgument("Input mask must be in 4D dimension but "
|
|
"received the dimension of mask is %d",
|
|
mask_dims.size()));
|
|
|
|
out->share_meta(x);
|
|
}
|
|
|
|
void SegmentPoolInferMeta(const MetaTensor& x,
|
|
const MetaTensor& segment_ids,
|
|
const std::string& pooltype,
|
|
MetaTensor* out,
|
|
MetaTensor* summed_ids,
|
|
MetaConfig config) {
|
|
auto x_dims = x.dims();
|
|
auto seg_dims = segment_ids.dims();
|
|
|
|
auto dims = x_dims;
|
|
dims[0] = -1;
|
|
out->set_dims(dims);
|
|
out->set_dtype(x.dtype());
|
|
out->set_layout(x.layout());
|
|
|
|
if (pooltype == "MEAN") {
|
|
summed_ids->set_dims({-1, 1});
|
|
summed_ids->set_dtype(x.dtype());
|
|
summed_ids->set_layout(x.layout());
|
|
}
|
|
|
|
// Dimension validation: check only at runtime or when dimensions are known
|
|
// Runtime: config.is_runtime = true (dynamic graph/PIR)
|
|
// Compile time: config.is_runtime = false (static graph building)
|
|
bool contain_unknown_dim = common::contain_unknown_dim(x_dims) ||
|
|
common::contain_unknown_dim(seg_dims);
|
|
bool check = config.is_runtime || !contain_unknown_dim;
|
|
|
|
if (check) {
|
|
PADDLE_ENFORCE_EQ(
|
|
seg_dims[0],
|
|
x_dims[0],
|
|
common::errors::InvalidArgument(
|
|
"Segment_ids should be the same size as dimension 0 of input X."));
|
|
|
|
PADDLE_ENFORCE_EQ(seg_dims.size(),
|
|
1UL,
|
|
common::errors::InvalidArgument(
|
|
"Segment_ids should be 1-D tensor, or it's other "
|
|
"dimension size is 1. Segment_ids's shape is: [%s].",
|
|
seg_dims));
|
|
}
|
|
}
|
|
|
|
void StftInferMeta(const MetaTensor& x,
|
|
const MetaTensor& window,
|
|
int n_fft,
|
|
int hop_length,
|
|
bool normalized,
|
|
bool onesided,
|
|
MetaTensor* out) {
|
|
const auto& x_dims = x.dims();
|
|
const int x_rank = x_dims.size();
|
|
const auto& window_dims = window.dims();
|
|
const int64_t window_size = window_dims[0];
|
|
|
|
PADDLE_ENFORCE_EQ(
|
|
x_rank,
|
|
2,
|
|
common::errors::InvalidArgument(
|
|
"Input(X) of StftOp should be a tensor with shape [N, T], "
|
|
"but got rank %s.",
|
|
x_rank));
|
|
PADDLE_ENFORCE_GT(
|
|
hop_length,
|
|
0,
|
|
common::errors::InvalidArgument(
|
|
"Attribute(hop_length) should be greater than 0, but got %s.",
|
|
hop_length));
|
|
PADDLE_ENFORCE_EQ(
|
|
window_size,
|
|
n_fft,
|
|
common::errors::InvalidArgument(
|
|
"Input(Window) of StftOp should be equal with n_fft %s, "
|
|
"but got %s.",
|
|
n_fft,
|
|
window_size));
|
|
|
|
int64_t seq_length = x_dims[x_rank - 1];
|
|
int64_t n_frames = 1 + (seq_length - n_fft) / hop_length;
|
|
|
|
PADDLE_ENFORCE_LE(n_fft,
|
|
seq_length,
|
|
common::errors::InvalidArgument(
|
|
"Attribute(frame_length) should be less equal than "
|
|
"sequence length, but got (%s) > (%s).",
|
|
n_fft,
|
|
seq_length));
|
|
|
|
std::vector<int64_t> output_shape;
|
|
output_shape.push_back(x_dims[0]);
|
|
if (onesided) {
|
|
output_shape.push_back(n_fft / 2 + 1);
|
|
} else {
|
|
output_shape.push_back(n_fft);
|
|
}
|
|
output_shape.push_back(n_frames);
|
|
|
|
out->set_dims(make_ddim(output_shape));
|
|
out->set_dtype(phi::dtype::ToComplex(x.dtype()));
|
|
}
|
|
|
|
void TakeAlongAxisInferMeta(const MetaTensor& x,
|
|
const MetaTensor& index,
|
|
int axis,
|
|
MetaTensor* out) {
|
|
auto input_dim = x.dims();
|
|
auto index_dim = index.dims();
|
|
|
|
PADDLE_ENFORCE_GT(
|
|
input_dim.size(),
|
|
0,
|
|
common::errors::InvalidArgument(
|
|
"Dimension of the input(Input) of TakeAlongAxisOp should be greater "
|
|
"than 0, but received %d.",
|
|
input_dim.size()));
|
|
|
|
PADDLE_ENFORCE_GT(
|
|
index_dim.size(),
|
|
0,
|
|
common::errors::InvalidArgument(
|
|
"Dimension of the input(Index) of TakeAlongAxisOp should be greater "
|
|
"than 0, but received %d.",
|
|
index_dim.size()));
|
|
|
|
out->set_dims(index_dim);
|
|
out->set_dtype(x.dtype());
|
|
}
|
|
|
|
void TdmChildInferMeta(const MetaTensor& x,
|
|
const MetaTensor& tree_info,
|
|
int child_nums,
|
|
DataType dtype,
|
|
MetaTensor* child,
|
|
MetaTensor* leaf_mask) {
|
|
PADDLE_ENFORCE_GT(
|
|
child_nums,
|
|
0,
|
|
common::errors::InvalidArgument(
|
|
"ValueError: The value of the 'child_nums' must greater than 0. "
|
|
"But received child_nums value = %d, ",
|
|
child_nums));
|
|
|
|
const auto& info_dims = tree_info.dims();
|
|
const auto& input_dims = x.dims();
|
|
|
|
PADDLE_ENFORCE_EQ(
|
|
info_dims.size(),
|
|
2,
|
|
common::errors::InvalidArgument(
|
|
"ShapeError: The dimensions of the 'tree info' must be 2. "
|
|
"But received tree info's dimensions = %d, "
|
|
"tree info's shape = [%s].",
|
|
info_dims.size(),
|
|
info_dims));
|
|
|
|
auto output_dims = vectorize(input_dims);
|
|
output_dims.push_back(child_nums);
|
|
if (child != nullptr) {
|
|
child->set_dims(make_ddim(output_dims));
|
|
leaf_mask->set_dims(make_ddim(output_dims));
|
|
child->share_lod(x);
|
|
leaf_mask->share_lod(x);
|
|
child->set_dtype(x.dtype());
|
|
leaf_mask->set_dtype(x.dtype());
|
|
}
|
|
}
|
|
|
|
void TriangularSolveInferMeta(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
bool upper,
|
|
bool transpose,
|
|
bool unitriangular,
|
|
MetaTensor* out) {
|
|
auto x_dims = x.dims();
|
|
auto y_dims = y.dims();
|
|
|
|
auto x_dims_n = x_dims.size();
|
|
auto y_dims_n = y_dims.size();
|
|
|
|
PADDLE_ENFORCE_GE(x_dims_n,
|
|
2,
|
|
common::errors::InvalidArgument(
|
|
"The input tensor X's dimensions of TriangularSolveOp "
|
|
"should be >= 2. But received X's "
|
|
"dimensions = %d, X's shape = [%s]",
|
|
x_dims.size(),
|
|
x_dims));
|
|
|
|
PADDLE_ENFORCE_GE(y_dims_n,
|
|
2,
|
|
common::errors::InvalidArgument(
|
|
"The input tensor Y's dimensions of TriangularSolveOp "
|
|
"should be >=2. But received Y's "
|
|
"dimensions = %d, Y's shape = [%s]",
|
|
y_dims.size(),
|
|
y_dims));
|
|
|
|
PADDLE_ENFORCE_EQ(x_dims[x_dims_n - 2],
|
|
x_dims[x_dims_n - 1],
|
|
common::errors::InvalidArgument(
|
|
"The inner-most 2 dimensions of Input(X) all should "
|
|
"be square matrices "
|
|
"But received X's shape[-2] = %d and shape[-1] = %d.",
|
|
x_dims[x_dims_n - 2],
|
|
x_dims[x_dims_n - 1]));
|
|
|
|
std::vector<int64_t> x_dims_vec = vectorize(x_dims);
|
|
std::vector<int64_t> y_dims_vec = vectorize(y_dims);
|
|
|
|
std::vector<int64_t> x_dims_vec_cut(x_dims_vec.begin(), x_dims_vec.end() - 2);
|
|
std::vector<int64_t> y_dims_vec_cut(y_dims_vec.begin(), y_dims_vec.end() - 2);
|
|
|
|
std::vector<int64_t> expand_batch_portion =
|
|
funcs::MatrixGetBroadcastBatchPortion(x_dims_vec_cut, y_dims_vec_cut);
|
|
|
|
std::vector<int64_t> y_broadcast_dims({expand_batch_portion});
|
|
y_broadcast_dims.insert(y_broadcast_dims.end(),
|
|
{y_dims_vec[y_dims_n - 2], y_dims_vec[y_dims_n - 1]});
|
|
|
|
// dim of 'out' is the same with 'Y' after broadcast
|
|
out->set_dims(make_ddim(y_broadcast_dims));
|
|
out->set_dtype(y.dtype());
|
|
out->set_layout(y.layout());
|
|
out->share_lod(y);
|
|
}
|
|
|
|
void LstsqInferMeta(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
const Scalar& rcond,
|
|
const std::string& driver,
|
|
MetaTensor* solution,
|
|
MetaTensor* residuals,
|
|
MetaTensor* rank,
|
|
MetaTensor* singular_values) {
|
|
auto x_dims = x.dims();
|
|
auto y_dims = y.dims();
|
|
int x_rank = x_dims.size();
|
|
int y_rank = y_dims.size();
|
|
|
|
int64_t m = x_dims[x_rank - 2];
|
|
int64_t n = x_dims[x_rank - 1];
|
|
int64_t nrhs = y_dims[x_rank - 1];
|
|
|
|
PADDLE_ENFORCE_GE(x_rank,
|
|
2,
|
|
common::errors::InvalidArgument(
|
|
"Expects input tensor x to be not less than "
|
|
"2 dimensions, but got dimension %d",
|
|
x_rank));
|
|
PADDLE_ENFORCE_GE(y_rank,
|
|
2,
|
|
common::errors::InvalidArgument(
|
|
"Expects input tensor y to be not less than "
|
|
"2 dimensions, but got dimension %d",
|
|
y_rank));
|
|
|
|
PADDLE_ENFORCE_EQ(
|
|
x_rank,
|
|
y_rank,
|
|
common::errors::InvalidArgument(
|
|
"Expects input tensor x and y to have the same dimension "
|
|
"but got x's dimension [%d] and y's dimension [%d]",
|
|
x_rank,
|
|
y_rank));
|
|
|
|
std::vector<int> batch_dims_vec{};
|
|
for (int i = 0; i < x_rank - 2; ++i) {
|
|
PADDLE_ENFORCE_EQ(x_dims[i],
|
|
y_dims[i],
|
|
common::errors::InvalidArgument(
|
|
"Expects input tensor x and y to have the same batch "
|
|
"dimension, but got x's batch dimension [%d] and "
|
|
"y's batch dimension [%d] in %d-th dim",
|
|
x_dims[i],
|
|
y_dims[i],
|
|
i));
|
|
batch_dims_vec.emplace_back(x_dims[i]);
|
|
}
|
|
|
|
PADDLE_ENFORCE_EQ(
|
|
m,
|
|
y_dims[y_rank - 2],
|
|
common::errors::InvalidArgument(
|
|
"Expects input tensor x and y to have the same row dimension "
|
|
"of the inner-most 2-dims matrix, "
|
|
"but got x's row dimension [%d] and y's row dimension [%d]",
|
|
m,
|
|
y_dims[y_rank - 2]));
|
|
|
|
if (x.numel() == 0 || y.numel() == 0) {
|
|
rank->set_dims(make_ddim({0}));
|
|
} else {
|
|
rank->set_dims(make_ddim(batch_dims_vec));
|
|
}
|
|
|
|
if (m > n && driver != "gelsy") {
|
|
if (driver == "gelss" || driver == "gelsd") {
|
|
residuals->set_dims(make_ddim({-1}));
|
|
} else {
|
|
batch_dims_vec.emplace_back(nrhs);
|
|
residuals->set_dims(make_ddim(batch_dims_vec));
|
|
batch_dims_vec.pop_back();
|
|
}
|
|
} else {
|
|
residuals->set_dims(make_ddim({0}));
|
|
}
|
|
residuals->set_dtype(y.dtype());
|
|
|
|
batch_dims_vec.emplace_back(std::min(m, n));
|
|
if (x.numel() == 0 || y.numel() == 0) {
|
|
singular_values->set_dims(make_ddim({0}));
|
|
} else {
|
|
singular_values->set_dims(make_ddim(batch_dims_vec));
|
|
}
|
|
singular_values->set_dtype(y.dtype());
|
|
|
|
batch_dims_vec[x_rank - 2] = n;
|
|
batch_dims_vec.emplace_back(nrhs);
|
|
solution->set_dims(make_ddim(batch_dims_vec));
|
|
solution->set_dtype(y.dtype());
|
|
}
|
|
|
|
void YoloBoxInferMeta(const MetaTensor& x,
|
|
const MetaTensor& img_size,
|
|
const std::vector<int>& anchors,
|
|
int class_num,
|
|
float conf_thresh,
|
|
int downsample_ratio,
|
|
bool clip_bbox,
|
|
float scale_x_y,
|
|
bool iou_aware,
|
|
float iou_aware_factor,
|
|
MetaTensor* boxes,
|
|
MetaTensor* scores,
|
|
MetaConfig config) {
|
|
auto dim_x = x.dims();
|
|
auto dim_imgsize = img_size.dims();
|
|
int anchor_num = static_cast<int>(anchors.size() / 2);
|
|
|
|
PADDLE_ENFORCE_EQ(
|
|
dim_x.size(),
|
|
4,
|
|
common::errors::InvalidArgument("Input(X) should be a 4-D tensor."
|
|
"But received X dimension(%s)",
|
|
dim_x.size()));
|
|
if (iou_aware) {
|
|
PADDLE_ENFORCE_EQ(
|
|
dim_x[1],
|
|
anchor_num * (6 + class_num),
|
|
common::errors::InvalidArgument(
|
|
"Input(X) dim[1] should be equal to (anchor_mask_number * (6 "
|
|
"+ class_num)) while iou_aware is true."
|
|
"But received dim[1](%s) != (anchor_mask_number * "
|
|
"(6+class_num)(%s).",
|
|
dim_x[1],
|
|
anchor_num * (6 + class_num)));
|
|
PADDLE_ENFORCE_GE(
|
|
iou_aware_factor,
|
|
0,
|
|
common::errors::InvalidArgument(
|
|
"Attr(iou_aware_factor) should greater than or equal to 0."
|
|
"But received iou_aware_factor (%s)",
|
|
iou_aware_factor));
|
|
PADDLE_ENFORCE_LE(
|
|
iou_aware_factor,
|
|
1,
|
|
common::errors::InvalidArgument(
|
|
"Attr(iou_aware_factor) should less than or equal to 1."
|
|
"But received iou_aware_factor (%s)",
|
|
iou_aware_factor));
|
|
} else {
|
|
PADDLE_ENFORCE_EQ(
|
|
dim_x[1],
|
|
anchor_num * (5 + class_num),
|
|
common::errors::InvalidArgument(
|
|
"Input(X) dim[1] should be equal to (anchor_mask_number * (5 "
|
|
"+ class_num))."
|
|
"But received dim[1](%s) != (anchor_mask_number * "
|
|
"(5+class_num)(%s).",
|
|
dim_x[1],
|
|
anchor_num * (5 + class_num)));
|
|
}
|
|
PADDLE_ENFORCE_EQ(
|
|
dim_imgsize.size(),
|
|
2,
|
|
common::errors::InvalidArgument("Input(ImgSize) should be a 2-D tensor."
|
|
"But received Imgsize size(%s)",
|
|
dim_imgsize.size()));
|
|
if ((dim_imgsize[0] > 0 && dim_x[0] > 0) || config.is_runtime) {
|
|
PADDLE_ENFORCE_EQ(
|
|
dim_imgsize[0],
|
|
dim_x[0],
|
|
common::errors::InvalidArgument(
|
|
"Input(ImgSize) dim[0] and Input(X) dim[0] should be same."));
|
|
}
|
|
PADDLE_ENFORCE_EQ(
|
|
dim_imgsize[1],
|
|
2,
|
|
common::errors::InvalidArgument("Input(ImgSize) dim[1] should be 2."
|
|
"But received imgsize dim[1](%s).",
|
|
dim_imgsize[1]));
|
|
PADDLE_ENFORCE_GT(anchors.size(),
|
|
0,
|
|
common::errors::InvalidArgument(
|
|
"Attr(anchors) length should be greater than 0."
|
|
"But received anchors length(%s).",
|
|
anchors.size()));
|
|
PADDLE_ENFORCE_EQ(anchors.size() % 2,
|
|
0,
|
|
common::errors::InvalidArgument(
|
|
"Attr(anchors) length should be even integer."
|
|
"But received anchors length (%s)",
|
|
anchors.size()));
|
|
PADDLE_ENFORCE_GT(class_num,
|
|
0,
|
|
common::errors::InvalidArgument(
|
|
"Attr(class_num) should be an integer greater than 0."
|
|
"But received class_num (%s)",
|
|
class_num));
|
|
|
|
int64_t box_num = 0;
|
|
if ((dim_x[2] > 0 && dim_x[3] > 0) || config.is_runtime) {
|
|
box_num = dim_x[2] * dim_x[3] * anchor_num;
|
|
} else {
|
|
box_num = -1;
|
|
}
|
|
std::vector<int64_t> dim_boxes({dim_x[0], box_num, 4});
|
|
boxes->set_dims(make_ddim(dim_boxes));
|
|
boxes->set_dtype(x.dtype());
|
|
|
|
std::vector<int64_t> dim_scores({dim_x[0], box_num, class_num});
|
|
scores->set_dims(make_ddim(dim_scores));
|
|
}
|
|
|
|
void YoloBoxHeadInferMeta(const MetaTensor& x,
|
|
const std::vector<int>& anchors UNUSED,
|
|
int class_num UNUSED,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
out->set_dims(x.dims());
|
|
out->set_dtype(x.dtype());
|
|
}
|
|
|
|
void ValueCompareInferMeta(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
detail::BinarySameInputDimsCheck(x, y, config);
|
|
|
|
out->set_dims(x.dims());
|
|
out->set_dtype(DataType::BOOL);
|
|
}
|
|
|
|
void SolveInferMeta(const MetaTensor& x, const MetaTensor& y, MetaTensor* out) {
|
|
auto x_dims = x.dims();
|
|
auto y_dims = y.dims();
|
|
|
|
std::vector<int64_t> x_dims_vec = vectorize(x.dims());
|
|
std::vector<int64_t> y_dims_vec = vectorize(y.dims());
|
|
|
|
auto x_dims_n = x_dims_vec.size();
|
|
auto y_dims_n = y_dims_vec.size();
|
|
|
|
PADDLE_ENFORCE_GT(x_dims_n,
|
|
1,
|
|
common::errors::InvalidArgument(
|
|
"The input tensor X's dimensions of SolveOp "
|
|
"should be larger than 1. But received X's "
|
|
"dimensions = %d, X's shape = [%s]",
|
|
x_dims_n,
|
|
x_dims));
|
|
|
|
PADDLE_ENFORCE_GE(y_dims_n,
|
|
1,
|
|
common::errors::InvalidArgument(
|
|
"The input tensor Y's dimensions of SolveOp "
|
|
"should be larger than or equal 1. But received Y's "
|
|
"dimensions = %d, Y's shape = [%s]",
|
|
y_dims_n,
|
|
y_dims));
|
|
|
|
PADDLE_ENFORCE_EQ(x_dims[x_dims_n - 2],
|
|
x_dims[x_dims_n - 1],
|
|
common::errors::InvalidArgument(
|
|
"The inner-most 2 dimensions of Input(X) all should "
|
|
"be square matrices "
|
|
"But received X's shape[-2] = %d and shape[-1] = %d.",
|
|
x_dims[x_dims_n - 2],
|
|
x_dims[x_dims_n - 1]));
|
|
|
|
bool x_broadcasted = false, y_broadcasted = false;
|
|
bool trans_x = false, trans_y = false;
|
|
if (x_dims_n == 1) {
|
|
x_dims_vec.insert(x_dims_vec.begin(), 1);
|
|
x_dims_n = 2;
|
|
x_broadcasted = true;
|
|
}
|
|
|
|
if (y_dims_n == 1) {
|
|
y_dims_vec.push_back(1);
|
|
y_dims_n = 2;
|
|
y_broadcasted = true;
|
|
}
|
|
|
|
size_t M = 0, N = 0;
|
|
if (trans_x) {
|
|
M = x_dims_vec[x_dims_n - 1];
|
|
} else {
|
|
M = x_dims_vec[x_dims_n - 2];
|
|
}
|
|
if (trans_y) {
|
|
N = y_dims_vec[y_dims_n - 2];
|
|
} else {
|
|
N = y_dims_vec[y_dims_n - 1];
|
|
}
|
|
|
|
std::vector<int64_t> new_dims;
|
|
if (x_dims_n >= y_dims_n) {
|
|
new_dims.assign(x_dims_vec.begin(), x_dims_vec.end() - 2);
|
|
} else {
|
|
new_dims.assign(y_dims_vec.begin(), y_dims_vec.end() - 2);
|
|
}
|
|
if (!x_broadcasted) {
|
|
new_dims.push_back(M); // NOLINT
|
|
}
|
|
if (!y_broadcasted) {
|
|
new_dims.push_back(N); // NOLINT
|
|
}
|
|
if (x_broadcasted && y_broadcasted) {
|
|
new_dims.push_back(1);
|
|
}
|
|
|
|
auto out_dims = make_ddim(new_dims);
|
|
|
|
out->set_dims(out_dims);
|
|
out->set_dtype(x.dtype());
|
|
out->set_layout(x.layout());
|
|
out->share_lod(x);
|
|
}
|
|
|
|
void SwiGLUInferMeta(const MetaTensor& x,
|
|
const MetaTensor& y,
|
|
MetaTensor* out) {
|
|
if (y) {
|
|
auto x_numel = common::product(x.dims());
|
|
auto y_numel = common::product(y.dims());
|
|
// skip 0-size
|
|
if (x_numel != 0 && y_numel != 0) {
|
|
PADDLE_ENFORCE_EQ(
|
|
x.dims(),
|
|
y.dims(),
|
|
common::errors::InvalidArgument("The shape of Input(X) should be "
|
|
"equal of the shape of Input(Y)."));
|
|
}
|
|
out->share_meta(x);
|
|
// If y is 0-size, out is 0-size
|
|
if (x_numel != 0 && y_numel == 0) {
|
|
out->set_dims(y.dims());
|
|
}
|
|
} else {
|
|
auto dims = x.dims();
|
|
PADDLE_ENFORCE_EQ(
|
|
dims[dims.size() - 1] % 2,
|
|
0,
|
|
common::errors::InvalidArgument(
|
|
"The last dim of Input(X) should be exactly divided by 2."));
|
|
dims[dims.size() - 1] /= 2;
|
|
out->set_dims(dims);
|
|
out->set_dtype(x.dtype());
|
|
out->set_layout(x.layout());
|
|
out->share_lod(x);
|
|
}
|
|
}
|
|
|
|
void UnpoolInferMeta(const MetaTensor& x,
|
|
const MetaTensor& indices,
|
|
const std::vector<int>& ksize,
|
|
const std::vector<int>& strides,
|
|
const std::vector<int>& paddings,
|
|
const IntArray& output_size,
|
|
const std::string& data_format,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
auto in_x_dims = x.dims();
|
|
auto in_y_dims = indices.dims();
|
|
|
|
PADDLE_ENFORCE_EQ(in_x_dims.size() == 4,
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"Unpool Input(X) must be of 4-dimensional, but "
|
|
"received Input(X)'s dimensions is %d.",
|
|
in_x_dims.size()));
|
|
PADDLE_ENFORCE_EQ(in_x_dims,
|
|
in_y_dims,
|
|
common::errors::InvalidArgument(
|
|
"The dimensions of Input(X) must equal to be "
|
|
"the dimensions of Input(Indices), but received "
|
|
"dimensions of Input(X) is [%d], received dimensions "
|
|
"of Input(Indices) is [%d]",
|
|
in_x_dims,
|
|
in_y_dims));
|
|
|
|
std::vector<int64_t> output_shape({in_x_dims[0], in_x_dims[1]});
|
|
|
|
std::vector<int64_t> output_size_val(output_size.size(), -1);
|
|
if (config.is_runtime || !output_size.FromTensor()) {
|
|
output_size_val = output_size.GetData();
|
|
}
|
|
for (int i = 0; i < static_cast<int>(ksize.size()); ++i) {
|
|
if (!config.is_runtime && in_x_dims[i + 2] <= 0) {
|
|
output_shape.push_back(-1);
|
|
} else {
|
|
output_shape.push_back(output_size_val[i]);
|
|
}
|
|
}
|
|
if (out != nullptr) {
|
|
out->set_dims(make_ddim(output_shape));
|
|
out->set_dtype(x.dtype());
|
|
}
|
|
}
|
|
void Unpool3dInferMeta(const MetaTensor& x,
|
|
const MetaTensor& indices,
|
|
const std::vector<int>& ksize,
|
|
const std::vector<int>& strides,
|
|
const std::vector<int>& paddings,
|
|
const std::vector<int>& output_size,
|
|
const std::string& data_format,
|
|
MetaTensor* out,
|
|
MetaConfig config) {
|
|
auto in_x_dims = x.dims();
|
|
auto in_y_dims = indices.dims();
|
|
|
|
PADDLE_ENFORCE_EQ(in_x_dims.size() == 5,
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"Unpool Input(X) must be of 5-dimensional, but "
|
|
"received Input(X)'s dimensions is %d.",
|
|
in_x_dims.size()));
|
|
PADDLE_ENFORCE_EQ(in_x_dims,
|
|
in_y_dims,
|
|
common::errors::InvalidArgument(
|
|
"The dimensions of Input(X) must equal to be "
|
|
"the dimensions of Input(Indices), but received "
|
|
"dimensions of Input(X) is [%d], received dimensions "
|
|
"of Input(Indices) is [%d]",
|
|
in_x_dims,
|
|
in_y_dims));
|
|
|
|
std::vector<int64_t> output_shape({in_x_dims[0], in_x_dims[1]});
|
|
for (int i = 0; i < static_cast<int>(ksize.size()); ++i) {
|
|
if (!config.is_runtime && in_x_dims[i + 2] <= 0) {
|
|
output_shape.push_back(-1);
|
|
} else {
|
|
output_shape.push_back(output_size[i]);
|
|
}
|
|
}
|
|
if (out != nullptr) {
|
|
out->set_dims(make_ddim(output_shape));
|
|
out->set_dtype(x.dtype());
|
|
}
|
|
}
|
|
|
|
void WeightDequantizeInferMeta(const MetaTensor& x,
|
|
const MetaTensor& scale,
|
|
const std::string& algo,
|
|
const int32_t group_size,
|
|
MetaTensor* out) {
|
|
PADDLE_ENFORCE_EQ(x.dims().size(),
|
|
2UL,
|
|
common::errors::InvalidArgument(
|
|
"The x tensor of dequantize op must be 2D, but got[%d]",
|
|
x.dims().size()));
|
|
PADDLE_ENFORCE_EQ(
|
|
(group_size == -1 || group_size == 64 || group_size == 128),
|
|
true,
|
|
common::errors::InvalidArgument("group_size must be -1, 64 or 128."));
|
|
|
|
auto dim_scale = scale.dims();
|
|
int64_t real_channel_shape = -1;
|
|
if (algo == "weight_only_int8") {
|
|
real_channel_shape = x.dims()[0];
|
|
} else if (algo == "weight_only_int4") {
|
|
real_channel_shape = x.dims()[0] * 2;
|
|
} else {
|
|
PADDLE_THROW(common::errors::InvalidArgument(
|
|
"Currently, we only support weight_only_int8"
|
|
" and weight_only_int4 algo."));
|
|
}
|
|
|
|
// per-channel dequantization
|
|
if (group_size == -1) {
|
|
PADDLE_ENFORCE_EQ(dim_scale.size(),
|
|
1UL,
|
|
common::errors::InvalidArgument(
|
|
"The scale tensor of dequantize op must "
|
|
"be 1D in per-channel mode, but got[%d]",
|
|
scale.dims().size()));
|
|
PADDLE_ENFORCE_EQ(dim_scale[0],
|
|
real_channel_shape,
|
|
common::errors::InvalidArgument(
|
|
"The scale tensor's shape must be equal to the x "
|
|
"tensor's shape, but got [%d] not equal to [%d]",
|
|
scale.dims()[0],
|
|
x.dims()[0]));
|
|
} else /* groupwise dequantization */ {
|
|
PADDLE_ENFORCE_EQ(dim_scale.size(),
|
|
2UL,
|
|
common::errors::InvalidArgument(
|
|
"The scale tensor of dequantize op must "
|
|
"be 2D in group-wise mode, but got[%d]",
|
|
scale.dims().size()));
|
|
PADDLE_ENFORCE_EQ(
|
|
dim_scale[0],
|
|
(x.dims()[1] + (group_size - 1)) / group_size,
|
|
errors::InvalidArgument("The input(weight_scale) dim[0] must be equal "
|
|
"to (Input(weight).dim[1] + (group_size -1))"
|
|
" / group_size. "
|
|
"But receive %d and %d",
|
|
dim_scale[0],
|
|
(x.dims()[1] + (group_size - 1)) / group_size));
|
|
PADDLE_ENFORCE_EQ(dim_scale[1],
|
|
real_channel_shape,
|
|
common::errors::InvalidArgument(
|
|
"The scale tensor's shape must be equal to the real "
|
|
"channel size, but got [%d] not equal to [%d]",
|
|
scale.dims()[0],
|
|
real_channel_shape));
|
|
}
|
|
int64_t n = x.dims()[1];
|
|
int64_t k = real_channel_shape;
|
|
out->set_dims(make_ddim({n, k}));
|
|
out->set_dtype(scale.dtype());
|
|
}
|
|
|
|
void FusedRMSNormInferMeta(const MetaTensor& x,
|
|
const MetaTensor& scale,
|
|
float epsilon,
|
|
MetaTensor* y,
|
|
MetaTensor* invvar) {
|
|
auto x_shape = x.dims();
|
|
auto scale_shape = scale.dims();
|
|
PADDLE_ENFORCE_EQ(
|
|
scale_shape.size(),
|
|
1,
|
|
common::errors::InvalidArgument(
|
|
"The scale tensor must be 1D, but got[%d]", scale_shape.size()));
|
|
PADDLE_ENFORCE_EQ(scale_shape[0],
|
|
x_shape[x_shape.size() - 1],
|
|
common::errors::InvalidArgument(
|
|
"The scale tensor's shape must be equal to the last "
|
|
"dimension of x tensor, but got [%d] not equal to [%d]",
|
|
scale_shape[0],
|
|
x_shape[x_shape.size() - 1]));
|
|
PADDLE_ENFORCE_EQ(
|
|
x.dtype() == DataType::FLOAT32 || x.dtype() == DataType::FLOAT16 ||
|
|
x.dtype() == DataType::BFLOAT16,
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"The dtype of x must be FLOAT32, FLOAT16 or BFLOAT16, but got [%s]",
|
|
x.dtype()));
|
|
PADDLE_ENFORCE_EQ(
|
|
scale.dtype() == DataType::FLOAT32 ||
|
|
scale.dtype() == DataType::FLOAT16 ||
|
|
scale.dtype() == DataType::BFLOAT16,
|
|
true,
|
|
common::errors::InvalidArgument("The dtype of scale must be FLOAT32, "
|
|
"FLOAT16 or BFLOAT16, but got [%s]",
|
|
scale.dtype()));
|
|
|
|
y->set_dims(x.dims());
|
|
y->set_dtype(scale.dtype());
|
|
|
|
invvar->set_dims({-1});
|
|
invvar->set_dtype(DataType::FLOAT32);
|
|
}
|
|
|
|
void BatchedGemmInferMeta(const MetaTensor& lhs,
|
|
const MetaTensor& rhs,
|
|
const std::vector<int64_t>& batch_sizes,
|
|
const bool trans_lhs,
|
|
const bool trans_rhs,
|
|
MetaTensor* output) {
|
|
const bool is_layout_invalid = (trans_lhs == true) && (trans_rhs == true);
|
|
const auto lhs_shape = lhs.dims();
|
|
const auto rhs_shape = rhs.dims();
|
|
const int64_t total_tokens = lhs_shape[0];
|
|
const int64_t num_experts = batch_sizes.size();
|
|
PADDLE_ENFORCE_EQ(
|
|
is_layout_invalid,
|
|
false,
|
|
common::errors::InvalidArgument(
|
|
"We don't support both lhs and rhs are transposed at the same time"));
|
|
PADDLE_ENFORCE_EQ(
|
|
(lhs.dtype() == DataType::BFLOAT16 || lhs.dtype() == DataType::FLOAT32) &&
|
|
(rhs.dtype() == DataType::BFLOAT16 ||
|
|
rhs.dtype() == DataType::FLOAT32) &&
|
|
lhs.dtype() == rhs.dtype(),
|
|
true,
|
|
common::errors::InvalidArgument(
|
|
"The dtype of lhs and rhs must both be BFLOAT16 or both be FLOAT32, "
|
|
"but got [%s] and [%s]",
|
|
lhs.dtype(),
|
|
rhs.dtype()));
|
|
PADDLE_ENFORCE_EQ(
|
|
lhs_shape.size(),
|
|
2,
|
|
common::errors::InvalidArgument(
|
|
"The lhs's dimension must be 2, but got[%d]", lhs_shape.size()));
|
|
PADDLE_ENFORCE_EQ(
|
|
rhs_shape.size(),
|
|
trans_lhs ? 2 : 3,
|
|
common::errors::InvalidArgument(
|
|
"The rhs's dimension must be 3, but got[%d]", rhs_shape.size()));
|
|
|
|
// We expect layout below:
|
|
// 1. trans_lhs = false && trans_rhs = false (group forward) :
|
|
// [M_total, input_hidden_size] x [num_experts, input_hidden_size,
|
|
// output_hidden_size] output: [M_total, output_hidden_size]
|
|
//
|
|
// 2. trans_lhs = false && trans_rhs = true (backward for lhs_grad, or
|
|
// specialized forward):
|
|
// [M_total, output_hidden_size] x [num_experts, input_hidden_size,
|
|
// output_hidden_size]' output: [M_total, input_hidden_size]
|
|
//
|
|
// 3. trans_lhs = true && trans_rhs = false (backward for rhs_grad) :
|
|
// [M_total, input_hidden_size]' x [M_total, output_hidden_size]
|
|
// output: [num_experts, input_hidden_size, output_hidden_size]
|
|
|
|
if (!trans_lhs) {
|
|
// =============================================================================
|
|
// Case 1 and 2: group forward or lhs_grad (input_grad)
|
|
// Note that this case implements grouped gemm, mapping hidden_lhs to
|
|
// hidden_out For each expert i, This case views lhs as [Mi x K] and rhs as
|
|
// [E x K x N] or [E x N x K], so the output is [Mtotal x N], N could be
|
|
// input_hidden_size or output_hidden_size.
|
|
|
|
const int64_t hidden_out = trans_rhs ? rhs_shape[1] : rhs_shape[2];
|
|
output->set_dims(make_ddim({total_tokens, hidden_out}));
|
|
|
|
} else {
|
|
// =============================================================================
|
|
// Case 3: group backward for rhs_grad (weight_grad)
|
|
// Note that this case implements k-grouped gemm
|
|
// For each expert i, this case views lhs as [K x Mi] and rhs as [Mi x N],
|
|
// so the output is [E x K x N].
|
|
|
|
PADDLE_ENFORCE_EQ(lhs_shape[0],
|
|
rhs_shape[0],
|
|
common::errors::InvalidArgument(
|
|
"The lhs's first dim must be equal to the rhs's "
|
|
"proposal, but got[%d] instead of [%d]",
|
|
lhs_shape[0],
|
|
rhs_shape[0]));
|
|
|
|
const int64_t hidden_in = lhs_shape[1];
|
|
const int64_t hidden_out = rhs_shape[1];
|
|
output->set_dims(make_ddim({num_experts, hidden_in, hidden_out}));
|
|
}
|
|
output->set_dtype(DataType::BFLOAT16);
|
|
}
|
|
|
|
} // namespace phi
|
|
|
|
PD_REGISTER_INFER_META_FN(add_raw, phi::ElementwiseRawInferMeta);
|