From f3d7db98f1182398db8e0bff1a4cc6d5b6203ecd Mon Sep 17 00:00:00 2001 From: wawltor Date: Mon, 13 Apr 2020 11:38:17 +0800 Subject: [PATCH] Add the support of bool list for assign_value op (#23774) * Add the support of bool list for assign value, test=develop * Fix the assign op test case for bool dtype, test=develop --- paddle/fluid/framework/tensor_util.h | 23 +++++++++++ paddle/fluid/operators/assign_value_op.cc | 8 +++- paddle/fluid/operators/assign_value_op.cu.cc | 3 +- paddle/fluid/operators/assign_value_op.h | 38 ++++++++++++++++++- python/paddle/fluid/layers/tensor.py | 7 +++- .../fluid/tests/unittests/test_assign_op.py | 6 +-- .../tests/unittests/test_assign_value_op.py | 19 ++++++++++ 7 files changed, 93 insertions(+), 11 deletions(-) diff --git a/paddle/fluid/framework/tensor_util.h b/paddle/fluid/framework/tensor_util.h index 9cbcf8f6286..65003d9a35c 100644 --- a/paddle/fluid/framework/tensor_util.h +++ b/paddle/fluid/framework/tensor_util.h @@ -83,6 +83,29 @@ void TensorFromDLPack(const ::DLTensor& dl_tensor, framework::Tensor* dst); // The implementation of template functions. // +template +void TensorFromArray(const T* src, const size_t& array_size, + const platform::DeviceContext& ctx, Tensor* dst) { + auto dst_place = ctx.GetPlace(); + auto src_ptr = static_cast(src); + platform::CPUPlace src_place; + dst->Resize({static_cast(array_size)}); + auto dst_ptr = static_cast(dst->mutable_data(dst_place)); + auto size = array_size * sizeof(T); + + if (platform::is_cpu_place(dst_place)) { + memory::Copy(boost::get(dst_place), dst_ptr, src_place, + src_ptr, size); + } +#ifdef PADDLE_WITH_CUDA + else if (platform::is_gpu_place(dst_place)) { // NOLINT + memory::Copy( + boost::get(dst_place), dst_ptr, src_place, src_ptr, + size, + reinterpret_cast(ctx).stream()); + } +#endif +} template void TensorFromVector(const std::vector& src, const platform::DeviceContext& ctx, Tensor* dst) { diff --git a/paddle/fluid/operators/assign_value_op.cc b/paddle/fluid/operators/assign_value_op.cc index d5b73fc2f65..a35e5a80a9e 100644 --- a/paddle/fluid/operators/assign_value_op.cc +++ b/paddle/fluid/operators/assign_value_op.cc @@ -52,9 +52,12 @@ class AssignValueOpMaker : public framework::OpProtoAndCheckerMaker { "(vector) " "Shape of values."); AddAttr("dtype", "data type of values") - .InEnum({framework::proto::VarType::INT32, + .InEnum({framework::proto::VarType::BOOL, + framework::proto::VarType::INT32, framework::proto::VarType::FP32, framework::proto::VarType::INT64}); + AddAttr>("bool_values", "store the bool values") + .SetDefault({}); AddAttr>("fp32_values", "store the float32 values") .SetDefault({}); AddAttr>("int32_values", "store the int32 values") @@ -78,6 +81,7 @@ REGISTER_OPERATOR( assign_value, ops::AssignValueOp, ops::AssignValueOpMaker, paddle::framework::EmptyGradOpMaker, paddle::framework::EmptyGradOpMaker); -REGISTER_OP_CPU_KERNEL(assign_value, ops::AssignValueKernel, +REGISTER_OP_CPU_KERNEL(assign_value, ops::AssignValueKernel, + ops::AssignValueKernel, ops::AssignValueKernel, ops::AssignValueKernel); diff --git a/paddle/fluid/operators/assign_value_op.cu.cc b/paddle/fluid/operators/assign_value_op.cu.cc index 7ec56e8af3b..6cb5958bd8f 100644 --- a/paddle/fluid/operators/assign_value_op.cu.cc +++ b/paddle/fluid/operators/assign_value_op.cu.cc @@ -15,6 +15,7 @@ limitations under the License. */ #include "paddle/fluid/operators/assign_value_op.h" namespace ops = paddle::operators; -REGISTER_OP_CUDA_KERNEL(assign_value, ops::AssignValueKernel, +REGISTER_OP_CUDA_KERNEL(assign_value, ops::AssignValueKernel, + ops::AssignValueKernel, ops::AssignValueKernel, ops::AssignValueKernel); diff --git a/paddle/fluid/operators/assign_value_op.h b/paddle/fluid/operators/assign_value_op.h index c458432d3ba..b462c43d23a 100644 --- a/paddle/fluid/operators/assign_value_op.h +++ b/paddle/fluid/operators/assign_value_op.h @@ -14,6 +14,7 @@ #pragma once +#include #include #include "paddle/fluid/framework/eigen.h" #include "paddle/fluid/framework/op_registry.h" @@ -22,6 +23,37 @@ namespace paddle { namespace operators { +using Tensor = framework::Tensor; + +template +typename std::enable_if::value>::type CopyVecotorToTensor( + const char* value_name, framework::Tensor* out, + const framework::ExecutionContext& ctx) { + // If attribute value dtype is vector, it will be converted to + // vector. + // at the same time, we can not use vector to hold the value, because + // the c++ use bit value to replace byte value. + auto values = ctx.Attr>(value_name); + framework::TensorFromVector(values, ctx.device_context(), out); + + // use the array to replace to vector + bool* array_ptr = new T[values.size()]; + for (unsigned int i = 0; i < values.size(); i++) { + array_ptr[i] = static_cast(values[i]); + } + framework::TensorFromArray(array_ptr, values.size(), ctx.device_context(), + out); + delete[] array_ptr; +} + +template +typename std::enable_if::value>::type +CopyVecotorToTensor(const char* value_name, framework::Tensor* out, + const framework::ExecutionContext& ctx) { + auto values = ctx.Attr>(value_name); + framework::TensorFromVector(values, ctx.device_context(), out); +} + template class AssignValueKernel : public framework::OpKernel { public: @@ -31,6 +63,9 @@ class AssignValueKernel : public framework::OpKernel { int dtype = ctx.Attr("dtype"); const char* value_name = nullptr; switch (dtype) { + case framework::proto::VarType::BOOL: + value_name = "bool_values"; + break; case framework::proto::VarType::INT32: value_name = "int32_values"; break; @@ -44,8 +79,7 @@ class AssignValueKernel : public framework::OpKernel { PADDLE_THROW("Unsupported dtype for assign_value_op: %d", dtype); break; } - auto values = ctx.Attr>(value_name); - framework::TensorFromVector(values, ctx.device_context(), out); + CopyVecotorToTensor(value_name, out, ctx); out->Resize(framework::make_ddim(shape)); } }; diff --git a/python/paddle/fluid/layers/tensor.py b/python/paddle/fluid/layers/tensor.py index 4be6c29a307..a5c6344b9fb 100644 --- a/python/paddle/fluid/layers/tensor.py +++ b/python/paddle/fluid/layers/tensor.py @@ -526,7 +526,10 @@ def assign(input, output=None): type='assign', inputs={'X': [input]}, outputs={'Out': [output]}) elif isinstance(input, numpy.ndarray): dtype = convert_np_dtype_to_dtype_(input.dtype) - if dtype == VarDesc.VarType.FP32: + if dtype == VarDesc.VarType.BOOL: + value_name = "bool_values" + values = [bool(v) for v in input.flat] + elif dtype == VarDesc.VarType.FP32: value_name = "fp32_values" values = [float(v) for v in input.flat] elif dtype == VarDesc.VarType.INT32: @@ -538,7 +541,7 @@ def assign(input, output=None): else: raise TypeError( "When the type of 'input' in assign is numpy.ndarray, " - "the data type of 'input' must be float32, int32 or int64, but " + "the data type of 'input' must be bool, float32, int32 or int64, but " "received %s." % convert_dtype(dtype)) if input.size > 1024 * 1024: raise ValueError("The size of input is too big. Please consider " diff --git a/python/paddle/fluid/tests/unittests/test_assign_op.py b/python/paddle/fluid/tests/unittests/test_assign_op.py index 17850c774f0..49c41823055 100644 --- a/python/paddle/fluid/tests/unittests/test_assign_op.py +++ b/python/paddle/fluid/tests/unittests/test_assign_op.py @@ -93,12 +93,10 @@ class TestAssignOpError(unittest.TestCase): x3 = fluid.layers.data(name='x3', shape=[4], dtype="uint8") self.assertRaises(TypeError, fluid.layers.assign, x3) # When the type of input is numpy.ndarray, the dtype of input must be float32, int32. - x4 = np.array([[2.5, 2.5]], dtype='bool') + x4 = np.array([[2.5, 2.5]], dtype='float64') self.assertRaises(TypeError, fluid.layers.assign, x4) - x5 = np.array([[2.5, 2.5]], dtype='float64') + x5 = np.array([[2.5, 2.5]], dtype='uint8') self.assertRaises(TypeError, fluid.layers.assign, x5) - x6 = np.array([[2.5, 2.5]], dtype='uint8') - self.assertRaises(TypeError, fluid.layers.assign, x6) if __name__ == '__main__': diff --git a/python/paddle/fluid/tests/unittests/test_assign_value_op.py b/python/paddle/fluid/tests/unittests/test_assign_value_op.py index 8764ffc34ca..adf238c43d2 100644 --- a/python/paddle/fluid/tests/unittests/test_assign_value_op.py +++ b/python/paddle/fluid/tests/unittests/test_assign_value_op.py @@ -54,6 +54,13 @@ class TestAssignValueOp3(TestAssignValueOp): self.attrs["int64_values"] = [int(v) for v in self.value.flat] +class TestAssignValueOp4(TestAssignValueOp): + def init_data(self): + self.value = numpy.random.choice( + a=[False, True], size=(2, 5)).astype(numpy.bool) + self.attrs["bool_values"] = [bool(v) for v in self.value.flat] + + class TestAssignApi(unittest.TestCase): def setUp(self): self.init_dtype() @@ -89,5 +96,17 @@ class TestAssignApi3(TestAssignApi): self.dtype = "int64" +class TestAssignApi4(TestAssignApi): + def setUp(self): + self.init_dtype() + self.value = numpy.random.choice( + a=[False, True], size=(2, 5)).astype(numpy.bool) + self.place = fluid.CUDAPlace(0) if fluid.is_compiled_with_cuda( + ) else fluid.CPUPlace() + + def init_dtype(self): + self.dtype = "bool" + + if __name__ == '__main__': unittest.main() -- GitLab