/* Copyright (c) 2021 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 "paddle/phi/core/ddim.h" #include "paddle/phi/kernels/funcs/common_shape.h" namespace phi { void DotInferMeta(const MetaTensor& x, const MetaTensor& y, MetaTensor* out) { auto x_dims = x.dims(); auto x_rank = static_cast(x_dims.size()); PADDLE_ENFORCE_EQ(true, 1 == x_rank || 2 == x_rank, phi::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(y_dims.size()), phi::errors::PreconditionNotMet( "ShapeError: The shape of input tensor Y: %s should match with " "input tenosr X: %s", y_dims.to_str(), x_dims.to_str())); bool shape_match = true; for (size_t i = 0; i < x_rank; ++i) { if (x_dims[i] != y_dims[i]) { shape_match = false; break; } } PADDLE_ENFORCE_EQ(true, shape_match, phi::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())); x_dims[x_dims.size() - 1] = 1; out->set_dims(x_dims); out->set_dtype(x.dtype()); out->set_layout(x.layout()); } void MatmulInferMeta(const MetaTensor& x, const MetaTensor& y, bool trans_x, bool trans_y, MetaTensor* out) { std::vector dims_x = phi::vectorize(x.dims()); std::vector dims_y = phi::vectorize(y.dims()); auto ndims_x = dims_x.size(); auto ndims_y = dims_y.size(); PADDLE_ENFORCE_GT(ndims_x, 0UL, phi::errors::InvalidArgument( "The Input(x) dims size must be greater than 0," " but reviced dims size is 0. ")); PADDLE_ENFORCE_GT(ndims_y, 0UL, phi::errors::InvalidArgument( "The Input(y) dims size must be greater than 0," " but reviced 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, N; 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 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); } if (!y_broadcasted) { new_dims.push_back(N); } if (x_broadcasted && y_broadcasted) { new_dims.push_back(1); } auto ddim_out = phi::make_ddim(new_dims); out->set_dims(ddim_out); 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, std::move(out)); } void ElementwiseRawInferMeta(const MetaTensor& x, const MetaTensor& y, int axis, MetaTensor* out) { 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, phi::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, phi::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 x_dims_array(max_dim); std::vector y_dims_array(max_dim); std::vector 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); auto out_dims = phi::make_ddim(out_dims_array); out->set_dims(out_dims); } else { out->set_dims(x.dims()); } out->set_dtype(x.dtype()); out->set_layout(x.layout()); out->share_lod(x); } 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(), phi::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 = phi::contain_unknown_dim(input_dims) || phi::contain_unknown_dim(label_dims); if (config.is_runtime || !contain_unknown_dim) { PADDLE_ENFORCE_EQ( input_dims, label_dims, phi::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->share_lod(input); } void Atan2InferMeta(const MetaTensor& x, const MetaTensor& y, MetaTensor* out) { auto in_dims = x.dims(); out->set_dims(in_dims); } } // namespace phi