diff --git a/paddle/fluid/operators/addmm_op.cc b/paddle/fluid/operators/addmm_op.cc index 863e64c686d7b8447ef5bee8a5744c3a9180038a..de4d7818020dd586547ff9eedb53108285048c09 100644 --- a/paddle/fluid/operators/addmm_op.cc +++ b/paddle/fluid/operators/addmm_op.cc @@ -16,7 +16,10 @@ limitations under the License. */ #include #include #include +#include "paddle/fluid/framework/infershape_utils.h" #include "paddle/fluid/framework/op_registry.h" +#include "paddle/phi/core/infermeta_utils.h" +#include "paddle/phi/infermeta/ternary.h" #ifdef PADDLE_WITH_MKLDNN #include "paddle/fluid/platform/mkldnn_helper.h" #endif @@ -33,85 +36,6 @@ class AddMMOp : public framework::OperatorWithKernel { public: using framework::OperatorWithKernel::OperatorWithKernel; - void InferShape(framework::InferShapeContext* ctx) const override { - PADDLE_ENFORCE_EQ(ctx->HasInput("Input"), true, - platform::errors::NotFound( - "Input(Input) of AddMMOp should not be null.")); - PADDLE_ENFORCE_EQ( - ctx->HasInput("X"), true, - platform::errors::NotFound("Input(X) of AddMMOp should not be null.")); - PADDLE_ENFORCE_EQ( - ctx->HasInput("Y"), true, - platform::errors::NotFound("Input(Y) of AddMMOp should not be null.")); - PADDLE_ENFORCE_EQ(ctx->HasOutput("Out"), true, - platform::errors::NotFound( - "Output(Out) of AddMMOp should not be null.")); - - auto input_dims = ctx->GetInputDim("Input"); - auto x_dims = ctx->GetInputDim("X"); - auto y_dims = ctx->GetInputDim("Y"); - - auto ndim_input = input_dims.size(); - auto ndim_x = x_dims.size(); - auto ndim_y = y_dims.size(); - - float alpha = ctx->Attrs().Get("Alpha"); - float beta = ctx->Attrs().Get("Beta"); - - VLOG(3) << "addmm operator input.shape=" << input_dims - << " x.shape=" << x_dims << " y.shape=" << y_dims - << " beta=" << beta << " alpha=" << alpha - << " ndim_input=" << ndim_input << " ndim_x=" << ndim_x - << " ndim_y=" << ndim_y; - - PADDLE_ENFORCE_NE(phi::product(input_dims), 0, - platform::errors::PreconditionNotMet( - "The Input variable Input(%s) has not " - "been initialized. You may need to confirm " - "if you put exe.run(startup_program) " - "after optimizer.minimize function.", - ctx->Inputs("Input").front())); - - PADDLE_ENFORCE_NE(phi::product(x_dims), 0, - platform::errors::PreconditionNotMet( - "The Input variable X(%s) has not " - "been initialized. You may need to confirm " - "if you put exe.run(startup_program) " - "after optimizer.minimize function.", - ctx->Inputs("X").front())); - - PADDLE_ENFORCE_NE(phi::product(y_dims), 0, - platform::errors::PreconditionNotMet( - "The Input variable Y(%s) has not " - "been initialized. You may need to confirm " - "if you put exe.run(startup_program) " - "after optimizer.minimize function.", - ctx->Inputs("Y").front())); - // dim check - PADDLE_ENFORCE_EQ(ndim_input, 2, - platform::errors::InvalidArgument( - "The input tensor input's dimension must be 2. " - "But received input's dimension = [%s].", - ndim_input)); - PADDLE_ENFORCE_EQ(ndim_x, 2, - platform::errors::InvalidArgument( - "The input tensor x's dimension must be 2. " - "But received x's dimension = [%s].", - ndim_x)); - PADDLE_ENFORCE_EQ(ndim_y, 2, - platform::errors::InvalidArgument( - "The input tensor y's dimension must be 2. " - "But received y's dimension = [%s].", - ndim_y)); - - std::vector output_dims; - output_dims.push_back(x_dims[0]); - output_dims.push_back(y_dims[1]); - - ctx->SetOutputDim("Out", phi::make_ddim(output_dims)); - ctx->ShareLoD("Input", /*->*/ "Out"); - } - framework::OpKernelType GetExpectedKernelType( const framework::ExecutionContext& ctx) const { framework::LibraryType library = framework::LibraryType::kPlain; @@ -223,9 +147,11 @@ class AddMMOpGradMaker : public framework::SingleGradOpMaker { } // namespace paddle namespace ops = paddle::operators; - +DELCARE_INFER_SHAPE_FUNCTOR(addmm, AddmmInferShapeFunctor, + PT_INFER_META(phi::AddmmInferMeta)); REGISTER_OPERATOR(addmm, ops::AddMMOp, ops::AddMMOpMaker, ops::AddMMOpGradMaker, - ops::AddMMOpGradMaker); + ops::AddMMOpGradMaker, + AddmmInferShapeFunctor); REGISTER_OPERATOR(addmm_grad, ops::AddMMGradOp); diff --git a/paddle/fluid/operators/cholesky_op.cc b/paddle/fluid/operators/cholesky_op.cc index 93dee0df7b9546eb852b619fbccf271c17cdd789..09e915a6bafd4a8b72f35995b3ebbfeafa00476a 100644 --- a/paddle/fluid/operators/cholesky_op.cc +++ b/paddle/fluid/operators/cholesky_op.cc @@ -12,7 +12,10 @@ 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/fluid/framework/infershape_utils.h" #include "paddle/fluid/framework/op_registry.h" +#include "paddle/phi/core/infermeta_utils.h" +#include "paddle/phi/infermeta/unary.h" namespace paddle { namespace operators { @@ -23,26 +26,6 @@ using framework::Tensor; class CholeskyOp : public framework::OperatorWithKernel { public: using framework::OperatorWithKernel::OperatorWithKernel; - - void InferShape(framework::InferShapeContext* ctx) const override { - OP_INOUT_CHECK(ctx->HasInput("X"), "Input", "X", "Cholesky"); - OP_INOUT_CHECK(ctx->HasOutput("Out"), "Output", "Out", "Cholesky"); - auto dims = ctx->GetInputDim("X"); - auto rank = dims.size(); - PADDLE_ENFORCE_GE(rank, 2, - platform::errors::InvalidArgument( - "The Input(X) should have at least 2 dimensions. But " - "received a %d dimension tensor.", - rank)); - PADDLE_ENFORCE_EQ( - dims[rank - 2], dims[rank - 1], - platform::errors::InvalidArgument( - "The inner-most 2 dimensions of Input(X) all should be symmetric " - "positive-definite matrices and have the same size. But received " - "X's shape[-2] = %d and shape[-1] = %d.", - dims[rank - 2], dims[rank - 1])); - ctx->SetOutputDim("Out", ctx->GetInputDim("X")); - } }; class CholeskyOpMaker : public framework::OpProtoAndCheckerMaker { @@ -107,7 +90,10 @@ class CholeskyGradOpMaker : public framework::SingleGradOpMaker { } // namespace paddle namespace ops = paddle::operators; +DELCARE_INFER_SHAPE_FUNCTOR(cholesky, CholeskyInferShapeFunctor, + PT_INFER_META(phi::CholeskyInferMeta)); REGISTER_OPERATOR(cholesky, ops::CholeskyOp, ops::CholeskyOpMaker, ops::CholeskyGradOpMaker, - ops::CholeskyGradOpMaker); + ops::CholeskyGradOpMaker, + CholeskyInferShapeFunctor); REGISTER_OPERATOR(cholesky_grad, ops::CholeskyGradOp); diff --git a/paddle/fluid/operators/increment_op.cc b/paddle/fluid/operators/increment_op.cc index 3d8e80bfaeb8fc8bae393d6655fd5f1cee3ca019..105d818e197434c4ed85126228e06d45bf06e498 100644 --- a/paddle/fluid/operators/increment_op.cc +++ b/paddle/fluid/operators/increment_op.cc @@ -12,7 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "paddle/fluid/framework/infershape_utils.h" #include "paddle/fluid/framework/op_registry.h" +#include "paddle/phi/core/infermeta_utils.h" +#include "paddle/phi/infermeta/unary.h" namespace paddle { namespace framework { @@ -37,18 +40,6 @@ class IncrementOp : public framework::OperatorWithKernel { const framework::AttributeMap &attrs) : OperatorWithKernel(type, inputs, outputs, attrs) {} - void InferShape(framework::InferShapeContext *ctx) const override { - PADDLE_ENFORCE_EQ(phi::product(ctx->GetInputDim("X")), 1UL, - platform::errors::InvalidArgument( - "The number of elements in Input(X) should be 1." - "Now the number is %d.", - phi::product(ctx->GetInputDim("X")))); - OP_INOUT_CHECK(ctx->HasInput("X"), "Input", "X", "increment"); - OP_INOUT_CHECK(ctx->HasOutput("Out"), "Output", "Out", "increment"); - ctx->SetOutputDim("Out", ctx->GetInputDim("X")); - ctx->ShareLoD("X", "Out"); - } - protected: framework::OpKernelType GetExpectedKernelType( const framework::ExecutionContext &ctx) const override { @@ -96,6 +87,9 @@ class IncrementGradOpMaker : public framework::SingleGradOpMaker { } // namespace paddle namespace ops = paddle::operators; +DELCARE_INFER_SHAPE_FUNCTOR(increment, IncrementInferShapeFunctor, + PT_INFER_META(phi::IncrementInferMeta)); REGISTER_OPERATOR(increment, ops::IncrementOp, ops::IncrementOpMaker, ops::IncrementGradOpMaker, - ops::IncrementGradOpMaker); + ops::IncrementGradOpMaker, + IncrementInferShapeFunctor); diff --git a/paddle/fluid/operators/multinomial_op.cc b/paddle/fluid/operators/multinomial_op.cc index 00eaa2f8e77cf71d688c31e7bf5559a347947214..1143f9cb37aa54bea430d3a8bca8b62b02da4e2b 100644 --- a/paddle/fluid/operators/multinomial_op.cc +++ b/paddle/fluid/operators/multinomial_op.cc @@ -16,10 +16,11 @@ limitations under the License. */ #include #include -#include "paddle/fluid/framework/generator.h" +#include "paddle/fluid/framework/infershape_utils.h" #include "paddle/fluid/framework/op_registry.h" #include "paddle/fluid/framework/operator.h" -#include "paddle/fluid/operators/common_infer_shape_functions.h" +#include "paddle/phi/core/infermeta_utils.h" +#include "paddle/phi/infermeta/unary.h" namespace paddle { namespace operators { @@ -45,38 +46,6 @@ This OP returns a Tensor filled with the sampled categoris according to Multinom class MultinomialOp : public framework::OperatorWithKernel { public: using framework::OperatorWithKernel::OperatorWithKernel; - - void InferShape(framework::InferShapeContext *ctx) const override { - OP_INOUT_CHECK(ctx->HasInput("X"), "Input", "X", "Multinomial"); - OP_INOUT_CHECK(ctx->HasOutput("Out"), "Output", "Out", "Multinomial"); - - auto x_dim = ctx->GetInputDim("X"); - int64_t x_rank = x_dim.size(); - PADDLE_ENFORCE_GT(x_rank, 0, - platform::errors::InvalidArgument( - "The number of dimensions of the input probability " - "distribution should be > 0, but got %d.", - x_rank)); - PADDLE_ENFORCE_LE(x_rank, 2, - platform::errors::InvalidArgument( - "The number of dimensions of the input probability " - "distribution should be <= 2, but got %d.", - x_rank)); - - std::vector out_dims(x_rank); - for (int64_t i = 0; i < x_rank - 1; i++) { - out_dims[i] = x_dim[i]; - } - - int64_t num_samples = ctx->Attrs().Get("num_samples"); - PADDLE_ENFORCE_GT( - num_samples, 0, - platform::errors::InvalidArgument( - "The number of samples should be > 0, but got %d.", num_samples)); - out_dims[x_rank - 1] = num_samples; - - ctx->SetOutputDim("Out", phi::make_ddim(out_dims)); - } }; } // namespace operators @@ -84,7 +53,10 @@ class MultinomialOp : public framework::OperatorWithKernel { namespace ops = paddle::operators; namespace plat = paddle::platform; +DELCARE_INFER_SHAPE_FUNCTOR(multinomial, MultinomialInferShapeFunctor, + PT_INFER_META(phi::MultinomialInferMeta)); REGISTER_OPERATOR( multinomial, ops::MultinomialOp, ops::MultinomialOpMaker, paddle::framework::EmptyGradOpMaker, - paddle::framework::EmptyGradOpMaker); + paddle::framework::EmptyGradOpMaker, + MultinomialInferShapeFunctor); diff --git a/paddle/phi/infermeta/CMakeLists.txt b/paddle/phi/infermeta/CMakeLists.txt index c077e7b4c55636e07eaf9353d009e857c239b8ec..f7102629d213c08ecb3da1dfdd974e3354105e61 100644 --- a/paddle/phi/infermeta/CMakeLists.txt +++ b/paddle/phi/infermeta/CMakeLists.txt @@ -1,2 +1,2 @@ -cc_library(infermeta SRCS nullary.cc unary.cc binary.cc multiary.cc DEPS convert_utils meta_tensor infermeta_utils) +cc_library(infermeta SRCS nullary.cc unary.cc binary.cc ternary.cc multiary.cc DEPS convert_utils meta_tensor infermeta_utils) cc_library(backward_infermeta SRCS backward.cc DEPS meta_tensor convert_utils) diff --git a/paddle/phi/infermeta/ternary.cc b/paddle/phi/infermeta/ternary.cc new file mode 100644 index 0000000000000000000000000000000000000000..52aeaef8438548542e2ecac4219f6eb2a8e8462b --- /dev/null +++ b/paddle/phi/infermeta/ternary.cc @@ -0,0 +1,92 @@ +/* Copyright (c) 2022 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/ternary.h" +#include "paddle/phi/core/ddim.h" +#include "paddle/phi/kernels/funcs/common_shape.h" + +namespace phi { + +void AddmmInferMeta(const MetaTensor& input, + const MetaTensor& x, + const MetaTensor& y, + float alpha, + float beta, + MetaTensor* out) { + auto input_dims = input.dims(); + auto x_dims = x.dims(); + auto y_dims = y.dims(); + + auto ndim_input = input_dims.size(); + auto ndim_x = x_dims.size(); + auto ndim_y = y_dims.size(); + + VLOG(3) << "addmm operator input.shape=" << input_dims + << " x.shape=" << x_dims << " y.shape=" << y_dims << " beta=" << beta + << " alpha=" << alpha << " ndim_input=" << ndim_input + << " ndim_x=" << ndim_x << " ndim_y=" << ndim_y; + + PADDLE_ENFORCE_NE( + product(input_dims), + 0, + errors::PreconditionNotMet("The Input variable 'input' has not " + "been initialized. You may need to confirm " + "if you put exe.run(startup_program) " + "after optimizer.minimize function.")); + + PADDLE_ENFORCE_NE( + product(x_dims), + 0, + errors::PreconditionNotMet("The Input variable 'x' has not " + "been initialized. You may need to confirm " + "if you put exe.run(startup_program) " + "after optimizer.minimize function.")); + + PADDLE_ENFORCE_NE( + product(y_dims), + 0, + 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.")); + // dim check + PADDLE_ENFORCE_EQ( + ndim_input, + 2, + errors::InvalidArgument("The input tensor input's dimension must be 2. " + "But received input's dimension = [%s].", + ndim_input)); + PADDLE_ENFORCE_EQ( + ndim_x, + 2, + errors::InvalidArgument("The input tensor x's dimension must be 2. " + "But received x's dimension = [%s].", + ndim_x)); + PADDLE_ENFORCE_EQ( + ndim_y, + 2, + errors::InvalidArgument("The input tensor y's dimension must be 2. " + "But received y's dimension = [%s].", + ndim_y)); + + std::vector output_dims; + output_dims.push_back(x_dims[0]); + output_dims.push_back(y_dims[1]); + + out->set_dims(make_ddim(output_dims)); + out->share_lod(input); + out->set_dtype(input.dtype()); +} + +} // namespace phi diff --git a/paddle/phi/infermeta/ternary.h b/paddle/phi/infermeta/ternary.h new file mode 100644 index 0000000000000000000000000000000000000000..d6223dd87aaf8e8c20c00ad72523e160ee15faee --- /dev/null +++ b/paddle/phi/infermeta/ternary.h @@ -0,0 +1,40 @@ +/* Copyright (c) 2022 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. */ + +#pragma once + +#include "paddle/phi/core/meta_tensor.h" + +namespace phi { + +// Common InferMeta Functions for ternary operators, The format like: +// +// 1. void [FunctionDesc|OpName]InferMeta(const MetaTensor& x, +// const MetaTensor& y, +// const MetaTensor& z, +// ..., +// MetaTensor* out) {} +// +// NOTE: The name "InferShape" may be not appropriate. "InferMeta" may be good. +// Because functions in this file not only can infer shape, but also need +// infer lod or other useful data. + +void AddmmInferMeta(const MetaTensor& input, + const MetaTensor& x, + const MetaTensor& y, + float alpha, + float beta, + MetaTensor* out); + +} // namespace phi diff --git a/paddle/phi/infermeta/unary.cc b/paddle/phi/infermeta/unary.cc index 72b88f537faf26d77f21da8375ab50e84ad86726..9b2f310e85d4bbf7b9acc6057bcef124d730449d 100644 --- a/paddle/phi/infermeta/unary.cc +++ b/paddle/phi/infermeta/unary.cc @@ -81,6 +81,28 @@ void CastInferMeta(const MetaTensor& x, DataType out_dtype, MetaTensor* out) { out->set_layout(x.layout()); } +void CholeskyInferMeta(const MetaTensor& x, bool upper, MetaTensor* out) { + auto dims = x.dims(); + auto rank = dims.size(); + PADDLE_ENFORCE_GE(rank, + 2, + errors::InvalidArgument( + "The Input(X) should have at least 2 dimensions. But " + "received a %d dimension tensor.", + rank)); + PADDLE_ENFORCE_EQ( + dims[rank - 2], + dims[rank - 1], + errors::InvalidArgument( + "The inner-most 2 dimensions of Input(X) all should be symmetric " + "positive-definite matrices and have the same size. But received " + "X's shape[-2] = %d and shape[-1] = %d.", + dims[rank - 2], + dims[rank - 1])); + out->set_dims(x.dims()); + out->set_dtype(x.dtype()); +} + void CopyToInferMeta(const MetaTensor& x, Backend backend, bool blocking, @@ -94,6 +116,18 @@ void CreateLikeInferMeta(const MetaTensor& x, DataType dtype, MetaTensor* out) { out->set_layout(x.layout()); } +void IncrementInferMeta(const MetaTensor& x, float value, MetaTensor* out) { + PADDLE_ENFORCE_EQ( + product(x.dims()), + 1UL, + errors::InvalidArgument("The number of elements in Input(X) should be 1." + "Now the number is %d.", + product(x.dims()))); + out->set_dims(x.dims()); + out->share_lod(x); + out->set_dtype(x.dtype()); +} + static phi::DDim ValidateShape(const std::vector shape, const phi::DDim& in_dims) { const int64_t in_size = phi::product(in_dims); @@ -234,6 +268,41 @@ void InferMetaFromVecValue(const MetaTensor& x, } } +void MultinomialInferMeta(const MetaTensor& x, + int num_samples, + bool replacement, + MetaTensor* out) { + auto x_dim = x.dims(); + int64_t x_rank = x_dim.size(); + PADDLE_ENFORCE_GT(x_rank, + 0, + errors::InvalidArgument( + "The number of dimensions of the input probability " + "distribution should be > 0, but got %d.", + x_rank)); + PADDLE_ENFORCE_LE(x_rank, + 2, + errors::InvalidArgument( + "The number of dimensions of the input probability " + "distribution should be <= 2, but got %d.", + x_rank)); + + std::vector out_dims(x_rank); + for (int64_t i = 0; i < x_rank - 1; i++) { + out_dims[i] = x_dim[i]; + } + + PADDLE_ENFORCE_GT( + num_samples, + 0, + errors::InvalidArgument( + "The number of samples should be > 0, but got %d.", num_samples)); + out_dims[x_rank - 1] = num_samples; + + out->set_dims(make_ddim(out_dims)); + out->set_dtype(DataType::INT64); +} + void ReshapeInferMeta(const MetaTensor& x, const ScalarArray& shape, MetaTensor* out, diff --git a/paddle/phi/infermeta/unary.h b/paddle/phi/infermeta/unary.h index 1a1605bb1ce4a79b162c4d38a0aa6de6e1b83753..40bf4e333569ce217d1180d1f02f3ac59062cd82 100644 --- a/paddle/phi/infermeta/unary.h +++ b/paddle/phi/infermeta/unary.h @@ -41,6 +41,8 @@ void FlattenInferMeta(const MetaTensor& x, void CastInferMeta(const MetaTensor& x, DataType out_dtype, MetaTensor* out); +void CholeskyInferMeta(const MetaTensor& x, bool upper, MetaTensor* out); + void CopyToInferMeta(const MetaTensor& x, Backend backend, bool blocking, @@ -48,10 +50,17 @@ void CopyToInferMeta(const MetaTensor& x, void CreateLikeInferMeta(const MetaTensor& x, DataType dtype, MetaTensor* out); +void IncrementInferMeta(const MetaTensor& x, float value, MetaTensor* out); + void InferMetaFromVecValue(const MetaTensor& x, const std::vector& shape, MetaTensor* out); +void MultinomialInferMeta(const MetaTensor& x, + int num_samples, + bool replacement, + MetaTensor* out); + void ReshapeInferMeta(const MetaTensor& x, const ScalarArray& shape, MetaTensor* out, diff --git a/paddle/phi/kernels/cholesky_grad_kernel.h b/paddle/phi/kernels/cholesky_grad_kernel.h index 3fb532d9af7f989ba017f8fa922110d126476b19..b170a3d7ffcfacdf8186d0f54450a38b536949d5 100644 --- a/paddle/phi/kernels/cholesky_grad_kernel.h +++ b/paddle/phi/kernels/cholesky_grad_kernel.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. +/* Copyright (c) 2022 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. diff --git a/paddle/phi/kernels/cpu/multinomial_kernel.cc b/paddle/phi/kernels/cpu/multinomial_kernel.cc index 67e7d5bb68c61f523ef50f805a6d529d96ad21b5..e9c2a569e0650dececa4541b3fdc7eba9b3f022e 100644 --- a/paddle/phi/kernels/cpu/multinomial_kernel.cc +++ b/paddle/phi/kernels/cpu/multinomial_kernel.cc @@ -16,6 +16,7 @@ limitations under the License. */ #include "paddle/phi/backends/cpu/cpu_context.h" #include "paddle/phi/core/kernel_registry.h" +#include "paddle/phi/kernels/funcs/multinomial_functor.h" namespace phi { @@ -32,12 +33,13 @@ void MultinomialKernel(const Context& dev_ctx, const int64_t num_categories = in_dims[in_rank - 1]; const int64_t num_distributions = in_rank > 1 ? in_dims[in_rank - 2] : 1; - MultinomialFunctor(out_data, - in_data, - num_samples, - replacement, - num_categories, - num_distributions); + funcs::MultinomialFunctor(dev_ctx, + out_data, + in_data, + num_samples, + replacement, + num_categories, + num_distributions); } } // namespace phi diff --git a/paddle/phi/kernels/funcs/multinomial_functor.h b/paddle/phi/kernels/funcs/multinomial_functor.h new file mode 100644 index 0000000000000000000000000000000000000000..05a5a0faf6774650facc082d9a04a46866e61db5 --- /dev/null +++ b/paddle/phi/kernels/funcs/multinomial_functor.h @@ -0,0 +1,122 @@ +/* Copyright (c) 2022 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. */ + +#pragma once + +#include "paddle/phi/core/device_context.h" +#include "paddle/phi/core/enforce.h" + +namespace phi { +namespace funcs { + +template +void MultinomialFunctor(const Context& dev_ctx, + int64_t* out_data, + const T* in_data, + const int64_t num_samples, + const bool replacement, + const int64_t num_categories, + const int64_t num_distributions) { + std::vector cumulative_probs(num_categories); + + std::uniform_real_distribution dist(0, 1); + auto engine = dev_ctx.GetHostGenerator()->GetCPUEngine(); + + for (int64_t i = 0; i < num_distributions; i++) { + T probs_sum = 0; + T prob_value; + int64_t num_zeros = 0; + for (int64_t j = 0; j < num_categories; j++) { + prob_value = in_data[i * num_categories + j]; + PADDLE_ENFORCE_GE( + prob_value, + 0.0, + errors::InvalidArgument("The input of multinomial distribution " + "should be >= 0, but got %f.", + prob_value)); + + probs_sum += prob_value; + if (prob_value == 0) { + num_zeros += 1; + } + cumulative_probs[j] = probs_sum; + } + PADDLE_ENFORCE_GT( + probs_sum, + 0.0, + errors::InvalidArgument("The sum of one multinomial distribution " + "probability should be > 0, but got %f.", + probs_sum)); + PADDLE_ENFORCE_EQ( + (replacement || (num_categories - num_zeros >= num_samples)), + true, + errors::InvalidArgument("When replacement is False, number of " + "samples should be less than non-zero " + "categories.")); + + for (int64_t j = 0; j < num_categories; j++) { + cumulative_probs[j] /= probs_sum; + } + + for (int64_t s = 0; s < num_samples; s++) { + T uniform_rand = dist(*engine); + // use binary search to get the selected category sample id. + // let cumulative_probs[id-1] < uniform_rand < cumulative_probs[id]. + int64_t left = 0; + int64_t right = num_categories; + int64_t mid; + int64_t sample_id; + T temp_prob; + cumulative_probs[(num_categories - 1)] = 1; + + while (right > left) { + mid = left + (right - left) / 2; + temp_prob = cumulative_probs[mid]; + if (temp_prob < uniform_rand) { + left = mid + 1; + } else { + right = mid; + } + } + sample_id = left; + + out_data[i * num_samples + s] = sample_id; + + // if replacement is false, the selected category should be removed. + if (!replacement && s < num_samples - 1) { + T sample_prob; + T new_prob = 0; + T new_sum; + + if (sample_id != 0) { + new_prob = cumulative_probs[sample_id - 1]; + } + sample_prob = cumulative_probs[sample_id] - new_prob; + new_sum = 1.0 - sample_prob; + + for (int64_t j = 0; j < num_categories; j++) { + new_prob = cumulative_probs[j]; + if (j >= sample_id) { + new_prob -= sample_prob; + } + new_prob /= new_sum; + cumulative_probs[j] = new_prob; + } + } + } + } +} + +} // namespace funcs +} // namespace phi diff --git a/paddle/phi/kernels/gpu/multinomial_kernel.cu b/paddle/phi/kernels/gpu/multinomial_kernel.cu index ea1cf361958aac3f6db1b1496099c2cc555b14c4..4918495ff7bed83d8fee7e811017927b53faf5f9 100644 --- a/paddle/phi/kernels/gpu/multinomial_kernel.cu +++ b/paddle/phi/kernels/gpu/multinomial_kernel.cu @@ -27,6 +27,7 @@ limitations under the License. */ #include "paddle/phi/backends/gpu/gpu_context.h" #include "paddle/phi/core/kernel_registry.h" #include "paddle/phi/kernels/funcs/eigen/common.h" +#include "paddle/phi/kernels/funcs/multinomial_functor.h" namespace phi { @@ -154,7 +155,7 @@ void MultinomialKernel(const Context& dev_ctx, // can // be used only once. So after every sample, probability of the distribution // will change. The implementation can't be parallelizable. Thus, call CPU - // implementation ``MultinomialFunctor`` to sample the distribution. + // implementation ``funcs::MultinomialFunctor`` to sample the distribution. if (!replacement) { int64_t in_data_numel = x.numel(); int64_t out_data_numel = out->numel(); @@ -172,12 +173,13 @@ void MultinomialKernel(const Context& dev_ctx, cudaMemcpyDeviceToHost); #endif - MultinomialFunctor(cpu_out_data, - cpu_in_data, - num_samples, - replacement, - num_categories, - num_distributions); + funcs::MultinomialFunctor(dev_ctx, + cpu_out_data, + cpu_in_data, + num_samples, + replacement, + num_categories, + num_distributions); #ifdef PADDLE_WITH_HIP hipMemcpy(out_data, diff --git a/paddle/phi/kernels/multinomial_kernel.h b/paddle/phi/kernels/multinomial_kernel.h index 70be21dc2861f72ba22bcd43087e13d02f6584b7..f3d8770bc1b606cb13e23256b1d9dabd7f172df0 100644 --- a/paddle/phi/kernels/multinomial_kernel.h +++ b/paddle/phi/kernels/multinomial_kernel.h @@ -15,109 +15,14 @@ #pragma once #include "paddle/phi/core/dense_tensor.h" -#include "paddle/fluid/framework/generator.h" namespace phi { template void MultinomialKernel(const Context& dev_ctx, - const DenseTensor& x, - int num_samples, - bool replacement, - DenseTensor* out); - -template -void MultinomialFunctor(int64_t* out_data, const T* in_data, - const int64_t num_samples, const bool replacement, - const int64_t num_categories, - const int64_t num_distributions) { - std::vector cumulative_probs(num_categories); - - std::uniform_real_distribution dist(0, 1); - auto gen_ptr = paddle::framework::DefaultCPUGenerator(); - auto engine = gen_ptr->GetCPUEngine(); - - for (int64_t i = 0; i < num_distributions; i++) { - T probs_sum = 0; - T prob_value; - int64_t num_zeros = 0; - for (int64_t j = 0; j < num_categories; j++) { - prob_value = in_data[i * num_categories + j]; - PADDLE_ENFORCE_GE(prob_value, 0.0, - errors::InvalidArgument( - "The input of multinomial distribution " - "should be >= 0, but got %f.", - prob_value)); - - probs_sum += prob_value; - if (prob_value == 0) { - num_zeros += 1; - } - cumulative_probs[j] = probs_sum; - } - PADDLE_ENFORCE_GT(probs_sum, 0.0, - errors::InvalidArgument( - "The sum of one multinomial distribution " - "probability should be > 0, but got %f.", - probs_sum)); - PADDLE_ENFORCE_EQ( - (replacement || (num_categories - num_zeros >= num_samples)), true, - errors::InvalidArgument( - "When replacement is False, number of " - "samples should be less than non-zero " - "categories.")); - - for (int64_t j = 0; j < num_categories; j++) { - cumulative_probs[j] /= probs_sum; - } - - for (int64_t s = 0; s < num_samples; s++) { - T uniform_rand = dist(*engine); - // use binary search to get the selected category sample id. - // let cumulative_probs[id-1] < uniform_rand < cumulative_probs[id]. - int64_t left = 0; - int64_t right = num_categories; - int64_t mid; - int64_t sample_id; - T temp_prob; - cumulative_probs[(num_categories - 1)] = 1; - - while (right > left) { - mid = left + (right - left) / 2; - temp_prob = cumulative_probs[mid]; - if (temp_prob < uniform_rand) { - left = mid + 1; - } else { - right = mid; - } - } - sample_id = left; - - out_data[i * num_samples + s] = sample_id; - - // if replacement is false, the selected category should be removed. - if (!replacement && s < num_samples - 1) { - T sample_prob; - T new_prob = 0; - T new_sum; - - if (sample_id != 0) { - new_prob = cumulative_probs[sample_id - 1]; - } - sample_prob = cumulative_probs[sample_id] - new_prob; - new_sum = 1.0 - sample_prob; - - for (int64_t j = 0; j < num_categories; j++) { - new_prob = cumulative_probs[j]; - if (j >= sample_id) { - new_prob -= sample_prob; - } - new_prob /= new_sum; - cumulative_probs[j] = new_prob; - } - } - } - } -} + const DenseTensor& x, + int num_samples, + bool replacement, + DenseTensor* out); } // namespace phi diff --git a/paddle/phi/ops/compat/addmm_sig.cc b/paddle/phi/ops/compat/addmm_sig.cc index 34da5fe9fe95430c3a5d4be6cc95ea93dbe8656b..b3bc0bb23a71e25aafe1c2e5038a60fdcf865a12 100644 --- a/paddle/phi/ops/compat/addmm_sig.cc +++ b/paddle/phi/ops/compat/addmm_sig.cc @@ -16,11 +16,6 @@ namespace phi { -KernelSignature AddmmOpArgumentMapping(const ArgumentMappingContext& ctx) { - return KernelSignature( - "addmm", {"Input", "X", "Y"}, {"Alpha", "Beta"}, {"Out"}); -} - KernelSignature AddmmGradOpArgumentMapping(const ArgumentMappingContext& ctx) { return KernelSignature( "addmm_grad", @@ -31,5 +26,4 @@ KernelSignature AddmmGradOpArgumentMapping(const ArgumentMappingContext& ctx) { } // namespace phi -PD_REGISTER_ARG_MAPPING_FN(addmm, phi::AddmmOpArgumentMapping); PD_REGISTER_ARG_MAPPING_FN(addmm_grad, phi::AddmmGradOpArgumentMapping); diff --git a/paddle/phi/ops/compat/cholesky_sig.cc b/paddle/phi/ops/compat/cholesky_sig.cc index 068c7f4f0a77afca717e5d4bdaf0c8c8d6e9759e..8c7ca75704669bf3af3c3b698deb8f61a6501693 100644 --- a/paddle/phi/ops/compat/cholesky_sig.cc +++ b/paddle/phi/ops/compat/cholesky_sig.cc @@ -16,10 +16,6 @@ namespace phi { -KernelSignature CholeskyOpArgumentMapping(const ArgumentMappingContext& ctx) { - return KernelSignature("cholesky", {"X"}, {"upper"}, {"Out"}); -} - KernelSignature CholeskyGradOpArgumentMapping( const ArgumentMappingContext& ctx) { return KernelSignature("cholesky_grad", @@ -30,5 +26,4 @@ KernelSignature CholeskyGradOpArgumentMapping( } // namespace phi -PD_REGISTER_ARG_MAPPING_FN(cholesky, phi::CholeskyOpArgumentMapping); PD_REGISTER_ARG_MAPPING_FN(cholesky_grad, phi::CholeskyGradOpArgumentMapping);