737 lines
26 KiB
C++
737 lines
26 KiB
C++
// Copyright (c) 2025 PaddlePaddle Authors. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
// Pre-Processing function.
|
|
// The function here will be called by the functions in
|
|
// paddle/fluid/pybind/static_op_function.cc and
|
|
// paddle/fluid/pybind/eager_op_function.cc. Mainly used to customize the
|
|
// processing of parameters originally done in the Python API
|
|
#include "paddle/fluid/pybind/arg_pre_process.h"
|
|
#include "paddle/common/ddim.h"
|
|
#include "paddle/fluid/eager/utils.h"
|
|
#include "paddle/fluid/pir/dialect/operator/utils/utils.h"
|
|
#include "paddle/fluid/pir/utils/general_functions.h"
|
|
#include "paddle/fluid/pybind/eager_utils.h"
|
|
#include "paddle/fluid/pybind/op_function_common.h"
|
|
#include "paddle/phi/common/data_type.h"
|
|
#include "paddle/phi/core/enforce.h"
|
|
#include "paddle/phi/kernels/funcs/common_infer_shape_functions.h"
|
|
|
|
namespace paddle {
|
|
namespace pybind {
|
|
constexpr char kStopGradientAttrName[] = "stop_gradient"; // NOLINT
|
|
|
|
// Helper to validate dimension equality for broadcast
|
|
static void ValidateBroadcastDim(int64_t actual,
|
|
int64_t expected,
|
|
const std::string& error_msg) {
|
|
// In static graph, unknown dimensions are often represented as -1.
|
|
if (actual < 0 || expected < 0) {
|
|
return;
|
|
}
|
|
PADDLE_ENFORCE_EQ(actual == expected || actual == 1,
|
|
true,
|
|
phi::errors::InvalidArgument(
|
|
"%s But received actual = %ld, expected = %ld.",
|
|
error_msg,
|
|
actual,
|
|
expected));
|
|
}
|
|
|
|
static void CheckDataType(const std::string& op_name,
|
|
const std::string var_name,
|
|
const DataType& var_dtype,
|
|
const std::vector<DataType>& expect_dtype) {
|
|
for (auto& t : expect_dtype) {
|
|
if (var_dtype == t) return;
|
|
}
|
|
PADDLE_THROW(common::errors::InvalidType(
|
|
"The dtype of %s of %s must be one of %s, but received %s.",
|
|
var_name,
|
|
op_name,
|
|
phi::DataTypeToString(expect_dtype),
|
|
phi::DataTypeToString(var_dtype)));
|
|
}
|
|
void ExpandAsPreProcess(Tensor* x,
|
|
paddle::optional<Tensor>* y,
|
|
std::vector<int64_t>* target_shape) {
|
|
if (target_shape->empty() && y->get_ptr() == nullptr) {
|
|
PADDLE_THROW(common::errors::InvalidArgument(
|
|
"The y of expand_as api must be specified."));
|
|
}
|
|
if (y->get_ptr() == nullptr) return;
|
|
*target_shape = common::vectorize<int64_t>(y->get_ptr()->dims());
|
|
}
|
|
void ExpandAsPreProcess(pir::Value* x,
|
|
paddle::optional<pir::Value>* y,
|
|
std::vector<int64_t>* target_shape) {
|
|
if (target_shape->empty() && y->get_ptr() == nullptr) {
|
|
PADDLE_THROW(common::errors::InvalidArgument(
|
|
"The y of expand_as api must be specified."));
|
|
}
|
|
if (y->get_ptr() == nullptr) return;
|
|
*target_shape = pir::GetShapeFromValue(*(y->get_ptr()));
|
|
|
|
/**
|
|
* if convert_dtype(x.dtype) == 'bool' and not x.stop_gradient:
|
|
* raise ValueError(
|
|
* "When the data type of input 'x' for expand_as is bool, "
|
|
* "you must set its stop_gradient to be False by "
|
|
* "some_var.stop_gradient = True, supporting "
|
|
* "some_var as the input 'x'."
|
|
* )
|
|
*
|
|
*/
|
|
auto dtype = pir::GetValueDtype(*x);
|
|
auto stop_gradient_attr =
|
|
x->attribute<pir::BoolAttribute>(kStopGradientAttrName);
|
|
auto stop_gradient = !stop_gradient_attr || stop_gradient_attr.data();
|
|
if (dtype == DataType::BOOL && !stop_gradient) {
|
|
PADDLE_THROW(common::errors::InvalidArgument(
|
|
"When the data type of input 'x' for expand_as is bool, "
|
|
"you must set its stop_gradient to be False by "
|
|
"some_var.stop_gradient = True, supporting "
|
|
"some_var as the input 'x'."));
|
|
}
|
|
}
|
|
void RollPreProcess(Tensor* x, IntArray* shifts, IntVector* axis) {
|
|
int64_t len_origin_shape = x->dims().size();
|
|
if (axis != NULL) {
|
|
int64_t axis_len = axis->size();
|
|
for (int64_t i = 0; i < axis_len; i++) {
|
|
PADDLE_ENFORCE_EQ(
|
|
((*axis)[i] < len_origin_shape && (*axis)[i] >= -len_origin_shape),
|
|
true,
|
|
common::errors::InvalidArgument("axis is out of range, it should be "
|
|
"in range [%d, %d), but received %ld",
|
|
-len_origin_shape,
|
|
len_origin_shape,
|
|
(*axis)[i]));
|
|
}
|
|
} else {
|
|
axis = new IntVector();
|
|
}
|
|
}
|
|
void RollPreProcess(Value* x, Value* shifts, IntVector* axis) {
|
|
std::vector<int64_t> x_shape = pir::GetShapeFromValue(*x);
|
|
int64_t len_origin_shape = x_shape.size();
|
|
if (axis != NULL) {
|
|
int64_t axis_len = axis->size();
|
|
for (int64_t i = 0; i < axis_len; i++) {
|
|
PADDLE_ENFORCE_EQ(
|
|
((*axis)[i] < len_origin_shape && (*axis)[i] >= -len_origin_shape),
|
|
true,
|
|
common::errors::InvalidArgument("axis is out of range, it should be "
|
|
"in range [%d, %d), but received %ld",
|
|
-len_origin_shape,
|
|
len_origin_shape,
|
|
(*axis)[i]));
|
|
}
|
|
} else {
|
|
axis = new IntVector();
|
|
}
|
|
}
|
|
|
|
void LogsumexpPreProcess(Tensor* x, std::vector<int>* axis, bool* reduce_all) {
|
|
/**
|
|
if axis == [] or len(axis) == len(x.shape):
|
|
reduce_all = True
|
|
else:
|
|
reduce_all = False
|
|
*/
|
|
if (axis->empty() || axis->size() == x->dims().size()) {
|
|
*reduce_all = true;
|
|
} else {
|
|
*reduce_all = false;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void LogsumexpPreProcess(pir::Value* x,
|
|
std::vector<int>* axis,
|
|
bool* reduce_all) {
|
|
std::vector<int64_t> x_shape = pir::GetShapeFromValue(*x);
|
|
if (axis->empty() || axis->size() == x_shape.size()) {
|
|
*reduce_all = true;
|
|
} else {
|
|
*reduce_all = false;
|
|
}
|
|
return;
|
|
}
|
|
void SumPreProcess(Value* x, Value* axis) {
|
|
paddle::dialect::SetStopGradient(axis);
|
|
}
|
|
|
|
void BinCountPreProcess(Tensor* x,
|
|
paddle::optional<Tensor>* weights,
|
|
Scalar* minlength) {
|
|
CheckDataType(
|
|
"bincount", "x", x->dtype(), {DataType::INT32, DataType::INT64});
|
|
}
|
|
|
|
void BinCountPreProcess(Value* x,
|
|
paddle::optional<Value>* weights,
|
|
Value* minlength) {
|
|
CheckDataType("bincount",
|
|
"x",
|
|
pir::GetValueDtype(*x),
|
|
{DataType::INT32, DataType::INT64});
|
|
}
|
|
|
|
void IsClosePreProcess(Value* x, Value* y, Value* rtol, Value* atol) {
|
|
/*
|
|
if in_pir_mode():
|
|
check_variable_and_dtype(
|
|
x,
|
|
"input",
|
|
['float16', 'float32', 'float64', 'complex64', 'complex128'],
|
|
'isclose',
|
|
)
|
|
check_variable_and_dtype(
|
|
y,
|
|
"input",
|
|
['float16', 'float32', 'float64', 'complex64', 'complex128'],
|
|
'isclose',
|
|
)
|
|
if isinstance(rtol, paddle.pir.Value):
|
|
check_variable_and_dtype(
|
|
rtol,
|
|
"input",
|
|
['float64'],
|
|
'isclose',
|
|
)
|
|
else:
|
|
check_type(rtol, 'rtol', float, 'isclose')
|
|
if isinstance(atol, paddle.pir.Value):
|
|
check_variable_and_dtype(
|
|
atol,
|
|
"input",
|
|
['float64'],
|
|
'isclose',
|
|
)
|
|
else:
|
|
check_type(atol, 'atol', float, 'isclose')
|
|
|
|
*/
|
|
// 'float16', 'float32', 'float64', 'complex64', 'complex128'
|
|
CheckDataType("is_close",
|
|
"x",
|
|
pir::GetValueDtype(*x),
|
|
{DataType::FLOAT16,
|
|
DataType::FLOAT32,
|
|
DataType::FLOAT64,
|
|
DataType::COMPLEX64,
|
|
DataType::COMPLEX128});
|
|
CheckDataType("is_close",
|
|
"y",
|
|
pir::GetValueDtype(*y),
|
|
{DataType::FLOAT16,
|
|
DataType::FLOAT32,
|
|
DataType::FLOAT64,
|
|
DataType::COMPLEX64,
|
|
DataType::COMPLEX128});
|
|
// 'float64'
|
|
CheckDataType(
|
|
"is_close", "rtol", pir::GetValueDtype(*rtol), {DataType::FLOAT64});
|
|
CheckDataType(
|
|
"is_close", "atol", pir::GetValueDtype(*atol), {DataType::FLOAT64});
|
|
}
|
|
|
|
void AllClosePreProcess(Value* x, Value* y, Value* rtol, Value* atol) {
|
|
CheckDataType("allclose",
|
|
"x",
|
|
pir::GetValueDtype(*x),
|
|
{DataType::BOOL,
|
|
DataType::INT32,
|
|
DataType::INT64,
|
|
DataType::FLOAT16,
|
|
DataType::FLOAT32,
|
|
DataType::FLOAT64});
|
|
CheckDataType("allclose",
|
|
"y",
|
|
pir::GetValueDtype(*y),
|
|
{DataType::BOOL,
|
|
DataType::INT32,
|
|
DataType::INT64,
|
|
DataType::FLOAT16,
|
|
DataType::FLOAT32,
|
|
DataType::FLOAT64});
|
|
CheckDataType(
|
|
"allclose", "rtol", pir::GetValueDtype(*rtol), {DataType::FLOAT64});
|
|
CheckDataType(
|
|
"allclose", "atol", pir::GetValueDtype(*atol), {DataType::FLOAT64});
|
|
}
|
|
|
|
void GridSamplePreProcess(Tensor* x,
|
|
Tensor* grid,
|
|
std::string* mode,
|
|
std::string* padding_mode,
|
|
bool* align_corners) {
|
|
// mode should be in ['bilinear', 'nearest']
|
|
// padding_mode should be in ['zeros', 'reflection', 'border']
|
|
if (mode->compare("bilinear") != 0 && mode->compare("nearest") != 0) {
|
|
PADDLE_THROW(common::errors::InvalidArgument(
|
|
"The mode of grid sample function should be in ['bilinear', "
|
|
"'nearest'], but got: %s",
|
|
*mode));
|
|
}
|
|
if (padding_mode->compare("zeros") != 0 &&
|
|
padding_mode->compare("reflection") != 0 &&
|
|
padding_mode->compare("border") != 0) {
|
|
PADDLE_THROW(common::errors::InvalidArgument(
|
|
"The padding mode of grid sample function should be in "
|
|
"['zeros', 'reflection', 'border'], but got: %s",
|
|
*padding_mode));
|
|
}
|
|
return;
|
|
}
|
|
|
|
void GridSamplePreProcess(pir::Value* x,
|
|
pir::Value* grid,
|
|
std::string* mode,
|
|
std::string* padding_mode,
|
|
bool* align_corners) {
|
|
// mode should be in ['bilinear', 'nearest']
|
|
// padding_mode should be in ['zeros', 'reflection', 'border']
|
|
if (mode->compare("bilinear") != 0 && mode->compare("nearest") != 0) {
|
|
PADDLE_THROW(common::errors::InvalidArgument(
|
|
"The mode of grid sample function should be in ['bilinear', "
|
|
"'nearest'], but got: %s",
|
|
*mode));
|
|
}
|
|
if (padding_mode->compare("zeros") != 0 &&
|
|
padding_mode->compare("reflection") != 0 &&
|
|
padding_mode->compare("border") != 0) {
|
|
PADDLE_THROW(common::errors::InvalidArgument(
|
|
"The padding mode of grid sample function should be in "
|
|
"['zeros', 'reflection', 'border'], but got: %s",
|
|
*padding_mode));
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Addmm broadcast validation for dygraph
|
|
void AddmmPreProcess(Tensor* input, Tensor* x, Tensor* y) {
|
|
auto input_shape = input->dims();
|
|
auto x_shape = x->dims();
|
|
auto y_shape = y->dims();
|
|
|
|
// Validate x and y are 2D
|
|
PADDLE_ENFORCE_EQ(
|
|
x_shape.size(),
|
|
2,
|
|
phi::errors::InvalidArgument(
|
|
"The dimension of x should be 2 but received x's shape: [%s]",
|
|
x_shape));
|
|
|
|
PADDLE_ENFORCE_EQ(
|
|
y_shape.size(),
|
|
2,
|
|
phi::errors::InvalidArgument(
|
|
"The dimension of y should be 2 but received y's shape: [%s]",
|
|
y_shape));
|
|
|
|
// Validate x's width equals y's height
|
|
PADDLE_ENFORCE_EQ(x_shape[1],
|
|
y_shape[0],
|
|
phi::errors::InvalidArgument(
|
|
"The input Variable x's width must be equal with "
|
|
"Variable y's height. "
|
|
"But received x's shape = [%s], y's shape = [%s].",
|
|
x_shape,
|
|
y_shape));
|
|
|
|
// Validate input shape broadcast compatibility
|
|
if (input_shape.size() == 2) {
|
|
ValidateBroadcastDim(input_shape[0],
|
|
x_shape[0],
|
|
"The dimension 0 of input must be equal to x's "
|
|
"dimension 0, or must be 1.");
|
|
ValidateBroadcastDim(input_shape[1],
|
|
y_shape[1],
|
|
"The dimension 1 of input must be equal to y's "
|
|
"dimension 1, or must be 1.");
|
|
} else if (input_shape.size() == 1) {
|
|
ValidateBroadcastDim(input_shape[0],
|
|
y_shape[1],
|
|
"The dimension 0 of input must be equal to y's "
|
|
"dimension 1, or must be 1.");
|
|
} else {
|
|
PADDLE_THROW(
|
|
phi::errors::InvalidArgument("The dimension of input should be 2 or 1 "
|
|
"but received input's shape: [%ld].",
|
|
input_shape.size()));
|
|
}
|
|
}
|
|
|
|
// Addmm broadcast validation for static graph
|
|
void AddmmPreProcess(pir::Value* input, pir::Value* x, pir::Value* y) {
|
|
auto input_shape = pir::GetShapeFromValue(*input);
|
|
auto x_shape = pir::GetShapeFromValue(*x);
|
|
auto y_shape = pir::GetShapeFromValue(*y);
|
|
|
|
// Validate x and y are 2D
|
|
PADDLE_ENFORCE_EQ(
|
|
x_shape.size(),
|
|
2,
|
|
phi::errors::InvalidArgument(
|
|
"The dimension of x should be 2 but received x's shape size: %d",
|
|
x_shape.size()));
|
|
|
|
PADDLE_ENFORCE_EQ(
|
|
y_shape.size(),
|
|
2,
|
|
phi::errors::InvalidArgument(
|
|
"The dimension of y should be 2 but received y's shape size: %d",
|
|
y_shape.size()));
|
|
|
|
// Validate x's width equals y's height
|
|
PADDLE_ENFORCE_EQ(x_shape[1],
|
|
y_shape[0],
|
|
phi::errors::InvalidArgument(
|
|
"The input Variable x's width must be equal with "
|
|
"Variable y's height. "
|
|
"But received x's shape[1] = %d, y's shape[0] = %d.",
|
|
x_shape[1],
|
|
y_shape[0]));
|
|
// Validate input shape broadcast compatibility
|
|
if (input_shape.size() == 2) {
|
|
ValidateBroadcastDim(input_shape[0],
|
|
x_shape[0],
|
|
"The dimension 0 of input must be equal to x's "
|
|
"dimension 0, or must be 1.");
|
|
ValidateBroadcastDim(input_shape[1],
|
|
y_shape[1],
|
|
"The dimension 1 of input must be equal to y's "
|
|
"dimension 1, or must be 1.");
|
|
} else if (input_shape.size() == 1) {
|
|
ValidateBroadcastDim(input_shape[0],
|
|
y_shape[1],
|
|
"The dimension 0 of input must be equal to y's "
|
|
"dimension 1, or must be 1.");
|
|
} else {
|
|
PADDLE_THROW(
|
|
phi::errors::InvalidArgument("The dimension of input should be 2 or 1 "
|
|
"but received input's dimension: %ld.",
|
|
input_shape.size()));
|
|
}
|
|
}
|
|
|
|
// Baddbmm broadcast validation for dygraph
|
|
void BaddbmmPreProcess(Tensor* input, Tensor* x, Tensor* y) {
|
|
auto input_shape = input->dims();
|
|
auto x_shape = x->dims();
|
|
auto y_shape = y->dims();
|
|
|
|
// Validate x and y are 3D
|
|
PADDLE_ENFORCE_EQ(
|
|
x_shape.size(),
|
|
3,
|
|
phi::errors::InvalidArgument(
|
|
"The dimension of x should be 3 but received x's shape size: %d.",
|
|
x_shape.size()));
|
|
|
|
PADDLE_ENFORCE_EQ(
|
|
y_shape.size(),
|
|
3,
|
|
phi::errors::InvalidArgument(
|
|
"The dimension of y should be 3 but received y's shape size: %d.",
|
|
y_shape.size()));
|
|
|
|
// Validate x's width equals y's height
|
|
PADDLE_ENFORCE_EQ(x_shape[2],
|
|
y_shape[1],
|
|
phi::errors::InvalidArgument(
|
|
"The input Variable x's width must be equal with "
|
|
"Variable y's height. "
|
|
"But received x's shape[2] = %d, y's shape[1] = %d.",
|
|
x_shape[2],
|
|
y_shape[1]));
|
|
|
|
// Validate input shape broadcast compatibility
|
|
if (input_shape.size() == 3) {
|
|
ValidateBroadcastDim(input_shape[0],
|
|
x_shape[0],
|
|
"The dimension 0 of input must be equal to x's "
|
|
"dimension 0, or must be 1.");
|
|
ValidateBroadcastDim(input_shape[1],
|
|
x_shape[1],
|
|
"The dimension 1 of input must be equal to x's "
|
|
"dimension 1, or must be 1.");
|
|
ValidateBroadcastDim(input_shape[2],
|
|
y_shape[2],
|
|
"The dimension 2 of input must be equal to y's "
|
|
"dimension 2, or must be 1.");
|
|
} else if (input_shape.size() == 2) {
|
|
ValidateBroadcastDim(input_shape[0],
|
|
x_shape[1],
|
|
"The dimension 0 of input must be equal to x's "
|
|
"dimension 1, or must be 1.");
|
|
ValidateBroadcastDim(input_shape[1],
|
|
y_shape[2],
|
|
"The dimension 1 of input must be equal to y's "
|
|
"dimension 2, or must be 1.");
|
|
} else {
|
|
PADDLE_THROW(
|
|
phi::errors::InvalidArgument("The dimension of input should be "
|
|
"3 or 2 but received input's "
|
|
"dimension: %ld.",
|
|
input_shape.size()));
|
|
}
|
|
}
|
|
|
|
// Baddbmm broadcast validation for static graph
|
|
void BaddbmmPreProcess(pir::Value* input, pir::Value* x, pir::Value* y) {
|
|
auto input_shape = pir::GetShapeFromValue(*input);
|
|
auto x_shape = pir::GetShapeFromValue(*x);
|
|
auto y_shape = pir::GetShapeFromValue(*y);
|
|
|
|
// Validate x and y are 3D
|
|
PADDLE_ENFORCE_EQ(
|
|
x_shape.size(),
|
|
3,
|
|
phi::errors::InvalidArgument(
|
|
"The dimension of x should be 3 but received x's shape size: %d",
|
|
x_shape.size()));
|
|
|
|
PADDLE_ENFORCE_EQ(
|
|
y_shape.size(),
|
|
3,
|
|
phi::errors::InvalidArgument(
|
|
"The dimension of y should be 3 but received y's shape size: %d",
|
|
y_shape.size()));
|
|
|
|
// Validate x's width equals y's height
|
|
PADDLE_ENFORCE_EQ(x_shape[2],
|
|
y_shape[1],
|
|
phi::errors::InvalidArgument(
|
|
"The input Variable x's width must be equal with "
|
|
"Variable y's height. "
|
|
"But received x's shape[2] = %d, y's shape[1] = %d.",
|
|
x_shape[2],
|
|
y_shape[1]));
|
|
|
|
// Validate input shape broadcast compatibility
|
|
if (input_shape.size() == 3) {
|
|
ValidateBroadcastDim(input_shape[0],
|
|
x_shape[0],
|
|
"The dimension 0 of input must be equal to x's "
|
|
"dimension 0, or must be 1.");
|
|
ValidateBroadcastDim(input_shape[1],
|
|
x_shape[1],
|
|
"The dimension 1 of input must be equal to x's "
|
|
"dimension 1, or must be 1.");
|
|
ValidateBroadcastDim(input_shape[2],
|
|
y_shape[2],
|
|
"The dimension 2 of input must be equal to y's "
|
|
"dimension 2, or must be 1.");
|
|
} else if (input_shape.size() == 2) {
|
|
ValidateBroadcastDim(input_shape[0],
|
|
x_shape[1],
|
|
"The dimension 0 of input must be equal to x's "
|
|
"dimension 1, or must be 1.");
|
|
ValidateBroadcastDim(input_shape[1],
|
|
y_shape[2],
|
|
"The dimension 1 of input must be equal to y's "
|
|
"dimension 2, or must be 1.");
|
|
} else {
|
|
PADDLE_THROW(
|
|
phi::errors::InvalidArgument("The dimension of input should be "
|
|
"3 or 2 but received input's "
|
|
"dimension: %ld.",
|
|
input_shape.size()));
|
|
}
|
|
}
|
|
|
|
void PixelShufflePreProcess(std::string* data_format) {
|
|
if (*data_format != "NCHW" && *data_format != "NHWC") {
|
|
PADDLE_THROW(common::errors::InvalidArgument(
|
|
"Attr(data_format) should be 'NCHW' or 'NHWC'."
|
|
"But receive Attr(data_format): %s",
|
|
*data_format));
|
|
}
|
|
}
|
|
|
|
// Eigh input validation for dygraph
|
|
void EighPreProcess(Tensor* x, std::string* UPLO) {
|
|
auto x_shape = x->dims();
|
|
int64_t rank = x_shape.size();
|
|
PADDLE_ENFORCE_GE(rank,
|
|
2,
|
|
phi::errors::InvalidArgument(
|
|
"Input(input) only support >=2 tensor, but received "
|
|
"length of Input(input) is %ld.",
|
|
rank));
|
|
PADDLE_ENFORCE_EQ(x_shape[rank - 1],
|
|
x_shape[rank - 2],
|
|
phi::errors::InvalidArgument(
|
|
"The input matrix must be batches of square matrices. "
|
|
"But received x's dimension: [%s]",
|
|
x_shape));
|
|
PADDLE_ENFORCE_EQ(
|
|
*UPLO == "L" || *UPLO == "U",
|
|
true,
|
|
phi::errors::InvalidArgument(
|
|
"UPLO must be L or U. But received UPLO is: %s", UPLO->c_str()));
|
|
}
|
|
|
|
// Eigh input validation for static graph
|
|
void EighPreProcess(Value* x, std::string* UPLO) {
|
|
auto x_shape = pir::GetShapeFromValue(*x);
|
|
int64_t rank = x_shape.size();
|
|
PADDLE_ENFORCE_GE(rank,
|
|
2,
|
|
phi::errors::InvalidArgument(
|
|
"Input(input) only support >=2 tensor, but received "
|
|
"length of Input(input) is %ld.",
|
|
rank));
|
|
if (x_shape[rank - 1] > 0 && x_shape[rank - 2] > 0) {
|
|
PADDLE_ENFORCE_EQ(
|
|
x_shape[rank - 1],
|
|
x_shape[rank - 2],
|
|
phi::errors::InvalidArgument(
|
|
"The input matrix must be batches of square matrices. "
|
|
"But received x's dimension."));
|
|
}
|
|
PADDLE_ENFORCE_EQ(
|
|
*UPLO == "L" || *UPLO == "U",
|
|
true,
|
|
phi::errors::InvalidArgument(
|
|
"UPLO must be L or U. But received UPLO is: %s", UPLO->c_str()));
|
|
}
|
|
|
|
// Cholesky input validation for dygraph
|
|
void CholeskyPreProcess(Tensor* x, bool* upper) {
|
|
auto x_shape = x->dims();
|
|
int64_t rank = x_shape.size();
|
|
PADDLE_ENFORCE_GE(
|
|
rank,
|
|
2,
|
|
phi::errors::InvalidArgument("Shape must have at least 2 dimensions. "
|
|
"But received x's dimension: %ld.",
|
|
rank));
|
|
PADDLE_ENFORCE_EQ(
|
|
x_shape[rank - 1],
|
|
x_shape[rank - 2],
|
|
phi::errors::InvalidArgument("The last two dimensions must be equal. "
|
|
"But received x's dimension: [%s]",
|
|
x_shape));
|
|
}
|
|
|
|
// Cholesky input validation for static graph
|
|
void CholeskyPreProcess(Value* x, bool* upper) {
|
|
auto x_shape = pir::GetShapeFromValue(*x);
|
|
int64_t rank = x_shape.size();
|
|
PADDLE_ENFORCE_GE(
|
|
rank,
|
|
2,
|
|
phi::errors::InvalidArgument("Shape must have at least 2 dimensions. "
|
|
"But received x's dimension: %ld.",
|
|
rank));
|
|
if (x_shape[rank - 1] > 0 && x_shape[rank - 2] > 0) {
|
|
PADDLE_ENFORCE_EQ(
|
|
x_shape[rank - 1],
|
|
x_shape[rank - 2],
|
|
phi::errors::InvalidArgument("The last two dimensions must be equal. "
|
|
"But received x's dimension."));
|
|
}
|
|
}
|
|
|
|
// Renorm preprocessing: handle negative axis
|
|
void NegativeAxisPreProcess(Tensor* x, int* axis) {
|
|
int rank = x->dims().size();
|
|
|
|
// Check upper bound first
|
|
PADDLE_ENFORCE_LT(
|
|
*axis,
|
|
rank,
|
|
common::errors::InvalidArgument(
|
|
"the axis:%d should be less than the shape's size %d", *axis, rank));
|
|
|
|
// If axis is negative, check lower bound then convert
|
|
if (*axis < 0) {
|
|
PADDLE_ENFORCE_GE(
|
|
*axis,
|
|
-rank,
|
|
common::errors::InvalidArgument(
|
|
"the axis:%d should not be less than -1 * length of input_shape:%d",
|
|
*axis,
|
|
-rank));
|
|
*axis = *axis + rank;
|
|
}
|
|
}
|
|
|
|
void NegativeAxisPreProcess(Value* x, int* axis) {
|
|
// Handle negative axis for static graph
|
|
auto x_shape = pir::GetShapeFromValue(*x);
|
|
int64_t rank = x_shape.size();
|
|
|
|
// Check upper bound first
|
|
PADDLE_ENFORCE_LT(
|
|
*axis,
|
|
static_cast<int>(rank),
|
|
common::errors::InvalidArgument(
|
|
"the axis:%d should be less than the shape's size %ld", *axis, rank));
|
|
|
|
// If axis is negative, check lower bound then convert
|
|
if (*axis < 0) {
|
|
PADDLE_ENFORCE_GE(
|
|
*axis,
|
|
-static_cast<int>(rank),
|
|
common::errors::InvalidArgument("the axis:%d should not be less than "
|
|
"-1 * length of input_shape:%ld",
|
|
*axis,
|
|
-static_cast<int>(rank)));
|
|
*axis = *axis + rank;
|
|
}
|
|
}
|
|
|
|
// Inplace API broadcast validation for dygraph
|
|
void InplaceShapePreProcess(Tensor* x, Tensor* y) {
|
|
auto x_shape = x->dims();
|
|
auto y_shape = y->dims();
|
|
|
|
auto out_shape = phi::funcs::BroadcastTwoDims(x_shape, y_shape);
|
|
|
|
PADDLE_ENFORCE_EQ(
|
|
out_shape,
|
|
x_shape,
|
|
phi::errors::InvalidArgument("The shape of broadcast output %s is "
|
|
"different from that of inplace "
|
|
"tensor %s in the Inplace operation.",
|
|
out_shape,
|
|
x_shape));
|
|
}
|
|
|
|
// Inplace API broadcast validation for static graph
|
|
void InplaceShapePreProcess(pir::Value* x, pir::Value* y) {
|
|
auto x_shape = pir::GetShapeFromValue(*x);
|
|
auto y_shape = pir::GetShapeFromValue(*y);
|
|
|
|
auto out_shape = phi::funcs::BroadcastTwoDims(common::make_ddim(x_shape),
|
|
common::make_ddim(y_shape));
|
|
|
|
PADDLE_ENFORCE_EQ(
|
|
out_shape,
|
|
common::make_ddim(x_shape),
|
|
phi::errors::InvalidArgument("The shape of broadcast output %s is "
|
|
"different from that of inplace "
|
|
"tensor %s in the Inplace operation.",
|
|
out_shape,
|
|
common::make_ddim(x_shape)));
|
|
}
|
|
|
|
} // namespace pybind
|
|
} // namespace paddle
|