From 667d44a3e97c496f8eb386bb7d52208b124a9f68 Mon Sep 17 00:00:00 2001 From: 0x45f Date: Tue, 23 Aug 2022 02:25:37 +0000 Subject: [PATCH 1/2] Adapt minlength attr for bincount --- paddle/fluid/operators/bincount_op.cc | 3 ++- paddle/phi/infermeta/binary.cc | 14 +++++++------- paddle/phi/infermeta/binary.h | 2 +- paddle/phi/kernels/bincount_kernel.h | 3 ++- paddle/phi/kernels/cpu/bincount_kernel.cc | 8 +++++--- paddle/phi/kernels/gpu/bincount_kernel.cu | 8 +++++--- 6 files changed, 22 insertions(+), 16 deletions(-) diff --git a/paddle/fluid/operators/bincount_op.cc b/paddle/fluid/operators/bincount_op.cc index 140f98916ea18..d52de7ace64ab 100644 --- a/paddle/fluid/operators/bincount_op.cc +++ b/paddle/fluid/operators/bincount_op.cc @@ -50,7 +50,8 @@ class BincountOpMaker : public framework::OpProtoAndCheckerMaker { AddOutput("Out", "(Tensor) The output tensor of Bincount op,"); AddAttr("minlength", "(int) The minimal numbers of bins") .SetDefault(0) - .EqualGreaterThan(0); + .EqualGreaterThan(0) + .SupportTensor(); AddComment(R"DOC( Bincount Operator. Computes frequency of each value in the input tensor. diff --git a/paddle/phi/infermeta/binary.cc b/paddle/phi/infermeta/binary.cc index 909eee908b5c1..5a20f41a029c4 100644 --- a/paddle/phi/infermeta/binary.cc +++ b/paddle/phi/infermeta/binary.cc @@ -210,16 +210,16 @@ void BCELossInferMeta(const MetaTensor& input, void BincountInferMeta(const MetaTensor& x, const MetaTensor& weights, - int minlength, + const Scalar& minlength, MetaTensor* out) { auto input_dim = x.dims(); - PADDLE_ENFORCE_GE(minlength, - 0, - phi::errors::InvalidArgument( - "The minlength should be greater than or equal to 0." - "But received minlength is %d", - minlength)); + // PADDLE_ENFORCE_GE(minlength, + // 0, + // phi::errors::InvalidArgument( + // "The minlength should be greater than or equal to 0." + // "But received minlength is %d", + // minlength)); PADDLE_ENFORCE_EQ( input_dim.size(), diff --git a/paddle/phi/infermeta/binary.h b/paddle/phi/infermeta/binary.h index 7dcbe33e0a933..cde1a93085709 100644 --- a/paddle/phi/infermeta/binary.h +++ b/paddle/phi/infermeta/binary.h @@ -57,7 +57,7 @@ void BCELossInferMeta(const MetaTensor& input, void BincountInferMeta(const MetaTensor& x, const MetaTensor& weights, - int minlength, + const Scalar& minlength, MetaTensor* out); void BmmInferMeta(const MetaTensor& x, const MetaTensor& y, MetaTensor* out); diff --git a/paddle/phi/kernels/bincount_kernel.h b/paddle/phi/kernels/bincount_kernel.h index e110b6e014b4d..7b72a1fabd8f5 100644 --- a/paddle/phi/kernels/bincount_kernel.h +++ b/paddle/phi/kernels/bincount_kernel.h @@ -14,6 +14,7 @@ #pragma once +#include "paddle/phi/common/scalar.h" #include "paddle/phi/core/dense_tensor.h" namespace phi { @@ -22,7 +23,7 @@ template void BincountKernel(const Context& dev_ctx, const DenseTensor& x, const paddle::optional& weights, - int minlength, + const Scalar& minlength, DenseTensor* out); } // namespace phi diff --git a/paddle/phi/kernels/cpu/bincount_kernel.cc b/paddle/phi/kernels/cpu/bincount_kernel.cc index 8163953c1e00e..0f4f45b80deef 100644 --- a/paddle/phi/kernels/cpu/bincount_kernel.cc +++ b/paddle/phi/kernels/cpu/bincount_kernel.cc @@ -86,12 +86,14 @@ template void BincountKernel(const Context& dev_ctx, const DenseTensor& x, const paddle::optional& weights, - int minlength, + const Scalar& minlength, DenseTensor* out) { if (x.dtype() == DataType::INT32) { - BincountInner(dev_ctx, x, weights, minlength, out); + BincountInner( + dev_ctx, x, weights, minlength.to(), out); } else if (x.dtype() == DataType::INT64) { - BincountInner(dev_ctx, x, weights, minlength, out); + BincountInner( + dev_ctx, x, weights, minlength.to(), out); } } } // namespace phi diff --git a/paddle/phi/kernels/gpu/bincount_kernel.cu b/paddle/phi/kernels/gpu/bincount_kernel.cu index d6073193a1505..a44deb81ba5f9 100644 --- a/paddle/phi/kernels/gpu/bincount_kernel.cu +++ b/paddle/phi/kernels/gpu/bincount_kernel.cu @@ -138,12 +138,14 @@ template void BincountKernel(const Context& dev_ctx, const DenseTensor& x, const paddle::optional& weights, - int minlength, + const Scalar& minlength, DenseTensor* out) { if (x.dtype() == DataType::INT32) { - BincountCUDAInner(dev_ctx, x, weights, minlength, out); + BincountCUDAInner( + dev_ctx, x, weights, minlength.to(), out); } else if (x.dtype() == DataType::INT64) { - BincountCUDAInner(dev_ctx, x, weights, minlength, out); + BincountCUDAInner( + dev_ctx, x, weights, minlength.to(), out); } } } // namespace phi From 1cf53510e9b8789d706fa9b13907736208c4e8c2 Mon Sep 17 00:00:00 2001 From: 0x45f Date: Tue, 23 Aug 2022 08:08:08 +0000 Subject: [PATCH 2/2] Add UT --- paddle/phi/infermeta/binary.cc | 7 -- paddle/phi/kernels/cpu/bincount_kernel.cc | 14 ++-- paddle/phi/kernels/gpu/bincount_kernel.cu | 13 +++- .../fluid/tests/unittests/test_bincount_op.py | 64 +++++++++++++++++++ 4 files changed, 84 insertions(+), 14 deletions(-) diff --git a/paddle/phi/infermeta/binary.cc b/paddle/phi/infermeta/binary.cc index 5a20f41a029c4..1efdea7baafd2 100644 --- a/paddle/phi/infermeta/binary.cc +++ b/paddle/phi/infermeta/binary.cc @@ -214,13 +214,6 @@ void BincountInferMeta(const MetaTensor& x, MetaTensor* out) { auto input_dim = x.dims(); - // PADDLE_ENFORCE_GE(minlength, - // 0, - // phi::errors::InvalidArgument( - // "The minlength should be greater than or equal to 0." - // "But received minlength is %d", - // minlength)); - PADDLE_ENFORCE_EQ( input_dim.size(), 1, diff --git a/paddle/phi/kernels/cpu/bincount_kernel.cc b/paddle/phi/kernels/cpu/bincount_kernel.cc index 0f4f45b80deef..97f28f541df09 100644 --- a/paddle/phi/kernels/cpu/bincount_kernel.cc +++ b/paddle/phi/kernels/cpu/bincount_kernel.cc @@ -88,12 +88,18 @@ void BincountKernel(const Context& dev_ctx, const paddle::optional& weights, const Scalar& minlength, DenseTensor* out) { + int int_minlength = minlength.to(); + PADDLE_ENFORCE_GE(int_minlength, + 0, + phi::errors::InvalidArgument( + "The minlength should be greater than or equal to 0." + "But received minlength is %d", + int_minlength)); + if (x.dtype() == DataType::INT32) { - BincountInner( - dev_ctx, x, weights, minlength.to(), out); + BincountInner(dev_ctx, x, weights, int_minlength, out); } else if (x.dtype() == DataType::INT64) { - BincountInner( - dev_ctx, x, weights, minlength.to(), out); + BincountInner(dev_ctx, x, weights, int_minlength, out); } } } // namespace phi diff --git a/paddle/phi/kernels/gpu/bincount_kernel.cu b/paddle/phi/kernels/gpu/bincount_kernel.cu index a44deb81ba5f9..3b1e41d92e6b6 100644 --- a/paddle/phi/kernels/gpu/bincount_kernel.cu +++ b/paddle/phi/kernels/gpu/bincount_kernel.cu @@ -140,12 +140,19 @@ void BincountKernel(const Context& dev_ctx, const paddle::optional& weights, const Scalar& minlength, DenseTensor* out) { + int int_minlength = minlength.to(); + PADDLE_ENFORCE_GE(int_minlength, + 0, + phi::errors::InvalidArgument( + "The minlength should be greater than or equal to 0." + "But received minlength is %d", + int_minlength)); + if (x.dtype() == DataType::INT32) { - BincountCUDAInner( - dev_ctx, x, weights, minlength.to(), out); + BincountCUDAInner(dev_ctx, x, weights, int_minlength, out); } else if (x.dtype() == DataType::INT64) { BincountCUDAInner( - dev_ctx, x, weights, minlength.to(), out); + dev_ctx, x, weights, int_minlength, out); } } } // namespace phi diff --git a/python/paddle/fluid/tests/unittests/test_bincount_op.py b/python/paddle/fluid/tests/unittests/test_bincount_op.py index 2b99c92191150..ca0113fe7fcc0 100644 --- a/python/paddle/fluid/tests/unittests/test_bincount_op.py +++ b/python/paddle/fluid/tests/unittests/test_bincount_op.py @@ -14,13 +14,16 @@ from __future__ import print_function +import os import unittest +import tempfile import numpy as np import paddle import paddle.fluid as fluid import paddle.fluid.core as core from paddle.fluid import Program, program_guard from op_test import OpTest +import paddle.inference as paddle_infer paddle.enable_static() @@ -206,5 +209,66 @@ def init_test_case(self): self.Out = np.bincount(self.np_input, minlength=self.minlength) +class TestTensorMinlength(unittest.TestCase): + + def setUp(self): + paddle.disable_static() + paddle.seed(2022) + self.temp_dir = tempfile.TemporaryDirectory() + self.save_path = os.path.join(self.temp_dir.name, + 'tensor_minlength_bincount') + self.place = paddle.CUDAPlace( + 0) if paddle.is_compiled_with_cuda() else paddle.CPUPlace() + + def test_dygraph(self): + paddle.disable_static() + x = np.random.randint(0, 10, [20]) + minlength = 2 + np_out = np.bincount(x, minlength=minlength) + pd_out = paddle.bincount(paddle.to_tensor(x), + minlength=paddle.to_tensor([2], dtype='int32')) + np.testing.assert_allclose(np_out, pd_out.numpy()) + + def test_static_and_infer(self): + paddle.enable_static() + np_x = np.random.randn(100).astype('float32') + main_prog = paddle.static.Program() + starup_prog = paddle.static.Program() + with paddle.static.program_guard(main_prog, starup_prog): + # run static + x = paddle.static.data(shape=np_x.shape, name='x', dtype=np_x.dtype) + linear = paddle.nn.Linear(np_x.shape[0], np_x.shape[0]) + linear_out = linear(x) + relu_out = paddle.nn.functional.relu(linear_out) + minlength = paddle.full([1], 3, dtype='int32') + out = paddle.bincount(paddle.cast(relu_out, 'int32'), + minlength=minlength) + + exe = paddle.static.Executor(self.place) + exe.run(starup_prog) + static_out = exe.run(feed={'x': np_x}, fetch_list=[out]) + + # run infer + paddle.static.save_inference_model(self.save_path, [x], [out], exe) + config = paddle_infer.Config(self.save_path + '.pdmodel', + self.save_path + '.pdiparams') + if paddle.is_compiled_with_cuda(): + config.enable_use_gpu(100, 0) + else: + config.disable_gpu() + + predictor = paddle_infer.create_predictor(config) + input_names = predictor.get_input_names() + input_handle = predictor.get_input_handle(input_names[0]) + fake_input = np_x + input_handle.reshape(np_x.shape) + input_handle.copy_from_cpu(fake_input) + predictor.run() + output_names = predictor.get_output_names() + output_handle = predictor.get_output_handle(output_names[0]) + infer_out = output_handle.copy_to_cpu() + np.testing.assert_allclose(static_out[0], infer_out) + + if __name__ == "__main__": unittest.main()