未验证 提交 87b903a3 编写于 作者: A Aganlengzi 提交者: GitHub

[phi]migrate increment addmm multinomial cholesky InferShapes to phi (#39913)

* [phi]migrate increment addmm multinomial cholesky InferShapes to phi

* set_dtype and mod MultinomialFunctor
上级 37cb6f32
......@@ -16,7 +16,10 @@ limitations under the License. */
#include <string>
#include <unordered_map>
#include <vector>
#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<float>("Alpha");
float beta = ctx->Attrs().Get<float>("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<int64_t> 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<T> {
} // 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<paddle::framework::OpDesc>,
ops::AddMMOpGradMaker<paddle::imperative::OpBase>);
ops::AddMMOpGradMaker<paddle::imperative::OpBase>,
AddmmInferShapeFunctor);
REGISTER_OPERATOR(addmm_grad, ops::AddMMGradOp);
......@@ -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<T> {
} // 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<paddle::framework::OpDesc>,
ops::CholeskyGradOpMaker<paddle::imperative::OpBase>);
ops::CholeskyGradOpMaker<paddle::imperative::OpBase>,
CholeskyInferShapeFunctor);
REGISTER_OPERATOR(cholesky_grad, ops::CholeskyGradOp);
......@@ -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<T> {
} // 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<paddle::framework::OpDesc>,
ops::IncrementGradOpMaker<paddle::imperative::OpBase>);
ops::IncrementGradOpMaker<paddle::imperative::OpBase>,
IncrementInferShapeFunctor);
......@@ -16,10 +16,11 @@ limitations under the License. */
#include <string>
#include <vector>
#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<int64_t> 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<int>("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::OpDesc>,
paddle::framework::EmptyGradOpMaker<paddle::imperative::OpBase>);
paddle::framework::EmptyGradOpMaker<paddle::imperative::OpBase>,
MultinomialInferShapeFunctor);
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)
/* 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<int64_t> 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
/* 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
......@@ -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<int64_t> 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<int64_t> 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,
......
......@@ -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<int64_t>& 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,
......
/* 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.
......
......@@ -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<T>(out_data,
in_data,
num_samples,
replacement,
num_categories,
num_distributions);
funcs::MultinomialFunctor<T>(dev_ctx,
out_data,
in_data,
num_samples,
replacement,
num_categories,
num_distributions);
}
} // namespace phi
......
/* 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 <typename T, typename Context>
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<T> cumulative_probs(num_categories);
std::uniform_real_distribution<T> 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
......@@ -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<T>(cpu_out_data,
cpu_in_data,
num_samples,
replacement,
num_categories,
num_distributions);
funcs::MultinomialFunctor<T>(dev_ctx,
cpu_out_data,
cpu_in_data,
num_samples,
replacement,
num_categories,
num_distributions);
#ifdef PADDLE_WITH_HIP
hipMemcpy(out_data,
......
......@@ -15,109 +15,14 @@
#pragma once
#include "paddle/phi/core/dense_tensor.h"
#include "paddle/fluid/framework/generator.h"
namespace phi {
template <typename T, typename Context>
void MultinomialKernel(const Context& dev_ctx,
const DenseTensor& x,
int num_samples,
bool replacement,
DenseTensor* out);
template <typename T>
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<T> cumulative_probs(num_categories);
std::uniform_real_distribution<T> 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
......@@ -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);
......@@ -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);
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册