diff --git a/paddle/fluid/framework/operator.cc b/paddle/fluid/framework/operator.cc index eb1889ae1d8ef..213c7451b43dd 100644 --- a/paddle/fluid/framework/operator.cc +++ b/paddle/fluid/framework/operator.cc @@ -1959,27 +1959,51 @@ pt::KernelContext OperatorWithKernel::ConstructPtKernelContext( op_kernel_ctx.EmplaceBackOutputs(tmp_outputs); } - for (size_t i = 0; i < attr_pairs.size(); ++i) { - // TODO(chenweihang): support other attrs - // In principle, the attr required by the dynamic mode should be - // passed in from the Python side, and there is no need to look up - // from the default_map, but now this nor work - switch (attr_pairs[i].second) { - case framework::proto::AttrType::INT: + for (size_t i = 0; i < attr_defs.size(); ++i) { + paddle::any attr_item; + if (attr_defs[i].type_index == std::type_index(typeid(pt::Scalar))) { + // TODO(chenweihang): support other attrs + // In principle, the attr required by the dynamic mode should be + // passed in from the Python side, and there is no need to look up + // from the default_map, but now this nor work + switch (attr_pairs[i].second) { + case framework::proto::AttrType::INT: + op_kernel_ctx.EmplaceBackAttr( + pt::Scalar(Attr(attr_pairs[i].first))); + break; + case framework::proto::AttrType::FLOAT: + op_kernel_ctx.EmplaceBackAttr( + pt::Scalar(Attr(attr_pairs[i].first))); + break; + case framework::proto::AttrType::BOOLEAN: + op_kernel_ctx.EmplaceBackAttr( + pt::Scalar(Attr(attr_pairs[i].first))); + break; + default: + // TODO(chenweihang): support other attrs type + PADDLE_THROW(platform::errors::Unimplemented( + "unsupported cast op attribute `%s` when construct " + "KernelContext.", + attr_pairs[i].first)); + } + } else { + // TODO(chenweihang): support other attrs + // In principle, the attr required by the dynamic mode should be + // passed in from the Python side, and there is no need to look up + // from the default_map, but now this nor work + if (attr_defs[i].type_index == std::type_index(typeid(int))) { op_kernel_ctx.EmplaceBackAttr(Attr(attr_pairs[i].first)); - break; - case framework::proto::AttrType::FLOAT: + } else if (attr_defs[i].type_index == std::type_index(typeid(float))) { op_kernel_ctx.EmplaceBackAttr(Attr(attr_pairs[i].first)); - break; - case framework::proto::AttrType::BOOLEAN: + } else if (attr_defs[i].type_index == std::type_index(typeid(bool))) { op_kernel_ctx.EmplaceBackAttr(Attr(attr_pairs[i].first)); - break; - default: + } else { // TODO(chenweihang): support other attrs type PADDLE_THROW(platform::errors::Unimplemented( "unsupported cast op attribute `%s` when construct " "KernelContext.", attr_pairs[i].first)); + } } } diff --git a/paddle/fluid/imperative/prepared_operator.cc b/paddle/fluid/imperative/prepared_operator.cc index 645343316a5b9..6fcb3641ee7b0 100644 --- a/paddle/fluid/imperative/prepared_operator.cc +++ b/paddle/fluid/imperative/prepared_operator.cc @@ -365,30 +365,53 @@ static pt::KernelContext BuildDygraphKernelContext( op_kernel_ctx.EmplaceBackOutputs(tmp_outputs); } - for (size_t i = 0; i < attr_pairs.size(); ++i) { - // TODO(chenweihang): support other attrs - // In principle, the attr required by the dynamic mode should be - // passed in from the Python side, and there is no need to look up - // from the default_map, but now this nor work - switch (attr_pairs[i].second) { - case framework::proto::AttrType::INT: + for (size_t i = 0; i < attr_defs.size(); ++i) { + if (attr_defs[i].type_index == std::type_index(typeid(pt::Scalar))) { + // TODO(chenweihang): support other attrs + // In principle, the attr required by the dynamic mode should be + // passed in from the Python side, and there is no need to look up + // from the default_map, but now this nor work + switch (attr_pairs[i].second) { + case framework::proto::AttrType::INT: + op_kernel_ctx.EmplaceBackAttr(pt::Scalar( + GetAttr(attrs, default_attrs, attr_pairs[i].first))); + break; + case framework::proto::AttrType::FLOAT: + op_kernel_ctx.EmplaceBackAttr(pt::Scalar( + GetAttr(attrs, default_attrs, attr_pairs[i].first))); + break; + case framework::proto::AttrType::BOOLEAN: + op_kernel_ctx.EmplaceBackAttr(pt::Scalar( + GetAttr(attrs, default_attrs, attr_pairs[i].first))); + break; + default: + // TODO(chenweihang): support other attrs type + PADDLE_THROW(platform::errors::Unimplemented( + "unsupported cast op attribute `%s` when construct " + "KernelContext.", + attr_pairs[i].first)); + } + } else { + // TODO(chenweihang): support other attrs + // In principle, the attr required by the dynamic mode should be + // passed in from the Python side, and there is no need to look up + // from the default_map, but now this nor work + if (attr_defs[i].type_index == std::type_index(typeid(int))) { op_kernel_ctx.EmplaceBackAttr( GetAttr(attrs, default_attrs, attr_pairs[i].first)); - break; - case framework::proto::AttrType::FLOAT: + } else if (attr_defs[i].type_index == std::type_index(typeid(float))) { op_kernel_ctx.EmplaceBackAttr( GetAttr(attrs, default_attrs, attr_pairs[i].first)); - break; - case framework::proto::AttrType::BOOLEAN: + } else if (attr_defs[i].type_index == std::type_index(typeid(bool))) { op_kernel_ctx.EmplaceBackAttr( GetAttr(attrs, default_attrs, attr_pairs[i].first)); - break; - default: + } else { // TODO(chenweihang): support other attrs type PADDLE_THROW(platform::errors::Unimplemented( "unsupported cast op attribute `%s` when construct " "KernelContext.", attr_pairs[i].first)); + } } } diff --git a/paddle/tcmpt/api/include/core.h b/paddle/tcmpt/api/include/core.h index 687dc72bb351f..7e02f600a5e7c 100644 --- a/paddle/tcmpt/api/include/core.h +++ b/paddle/tcmpt/api/include/core.h @@ -20,4 +20,5 @@ limitations under the License. */ #include "paddle/tcmpt/core/kernel_context.h" #include "paddle/tcmpt/core/kernel_factory.h" #include "paddle/tcmpt/core/mkldnn_dense_tensor.h" +#include "paddle/tcmpt/core/scalar.h" #include "paddle/tcmpt/core/selected_rows_tensor.h" diff --git a/paddle/tcmpt/core/kernel_utils.h b/paddle/tcmpt/core/kernel_utils.h index 05503dbd36116..a25c5a71c8c67 100644 --- a/paddle/tcmpt/core/kernel_utils.h +++ b/paddle/tcmpt/core/kernel_utils.h @@ -17,6 +17,7 @@ #include "paddle/tcmpt/core/dense_tensor.h" #include "paddle/tcmpt/core/kernel_context.h" #include "paddle/tcmpt/core/kernel_def.h" +#include "paddle/tcmpt/core/scalar.h" #include "paddle/tcmpt/core/selected_rows_tensor.h" // See Note [ Why still include the fluid headers? ] @@ -162,6 +163,7 @@ struct KernelImpl { PT_SPECIALIZE_KernelCallHelper_FOR_ATTRIBUTE(int); PT_SPECIALIZE_KernelCallHelper_FOR_ATTRIBUTE(int64_t); PT_SPECIALIZE_KernelCallHelper_FOR_ATTRIBUTE(paddle::platform::float16); + PT_SPECIALIZE_KernelCallHelper_FOR_ATTRIBUTE(const pt::Scalar&); /* Output Helpers */ diff --git a/paddle/tcmpt/core/scalar.h b/paddle/tcmpt/core/scalar.h new file mode 100644 index 0000000000000..8f30d81bcfb28 --- /dev/null +++ b/paddle/tcmpt/core/scalar.h @@ -0,0 +1,63 @@ +/* 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. */ + +#pragma once + +namespace pt { + +class Scalar { + public: + // Constructor support implicit + Scalar(float val) : tag(Tag::HAS_F) { data_.f = val; } // NOLINT + + Scalar(double val) : tag(Tag::HAS_D) { data_.d = val; } // NOLINT + + Scalar(int32_t val) : tag(Tag::HAS_I32) { data_.i32 = val; } // NOLINT + + Scalar(int64_t val) : tag(Tag::HAS_I64) { data_.i64 = val; } // NOLINT + + Scalar(bool val) : tag(Tag::HAS_B) { data_.b = val; } // NOLINT + + template + inline T to() const { + switch (tag) { + case Tag::HAS_F: + return static_cast(data_.f); + case Tag::HAS_D: + return static_cast(data_.d); + case Tag::HAS_I32: + return static_cast(data_.i32); + case Tag::HAS_I64: + return static_cast(data_.i64); + case Tag::HAS_B: + return static_cast(data_.b); + default: + throw std::runtime_error("Invalid Scalar type."); + } + } + + private: + enum class Tag { HAS_F, HAS_D, HAS_I32, HAS_I64, HAS_B }; + Tag tag; + + union data { + float f; + double d; + int32_t i32; + int64_t i64; + bool b; + } data_; +}; + +} // namespace pt diff --git a/paddle/tcmpt/cpu/creation.cc b/paddle/tcmpt/cpu/creation.cc index b117209fd35b0..8e4399c41bf17 100644 --- a/paddle/tcmpt/cpu/creation.cc +++ b/paddle/tcmpt/cpu/creation.cc @@ -22,13 +22,9 @@ namespace pt { template void FillAnyLike(const CPUContext& dev_ctx, const DenseTensor& x, - float val, + const Scalar& val, DenseTensor* out) { - PADDLE_ENFORCE_EQ( - std::isnan(val), - false, - paddle::platform::errors::InvalidArgument("The filled value is NaN.")); - eigen::fill(dev_ctx, out, val); + eigen::fill(dev_ctx, out, val.to()); } } // namespace pt diff --git a/paddle/tcmpt/cpu/creation.h b/paddle/tcmpt/cpu/creation.h index 090112911bbab..2c67945892b82 100644 --- a/paddle/tcmpt/cpu/creation.h +++ b/paddle/tcmpt/cpu/creation.h @@ -15,6 +15,7 @@ #pragma once #include "paddle/tcmpt/core/dense_tensor.h" +#include "paddle/tcmpt/core/scalar.h" #include "paddle/fluid/platform/device_context.h" @@ -25,7 +26,7 @@ using CPUContext = paddle::platform::CPUDeviceContext; template void FillAnyLike(const CPUContext& dev_ctx, const DenseTensor& x, - float val, + const Scalar& val, DenseTensor* out); } // namespace pt diff --git a/paddle/tcmpt/cuda/creation.cu b/paddle/tcmpt/cuda/creation.cu index 07fc5ee5f9b2b..cca9199b76cfd 100644 --- a/paddle/tcmpt/cuda/creation.cu +++ b/paddle/tcmpt/cuda/creation.cu @@ -22,13 +22,9 @@ namespace pt { template void FillAnyLike(const CUDAContext& dev_ctx, const DenseTensor& x, - float val, + const Scalar& val, DenseTensor* out) { - PADDLE_ENFORCE_EQ( - std::isnan(val), - false, - paddle::platform::errors::InvalidArgument("The filled value is NaN.")); - eigen::fill(dev_ctx, out, val); + eigen::fill(dev_ctx, out, val.to()); } } // namespace pt diff --git a/paddle/tcmpt/cuda/creation.h b/paddle/tcmpt/cuda/creation.h index ff26ca11ca2a5..7de9ce1371fff 100644 --- a/paddle/tcmpt/cuda/creation.h +++ b/paddle/tcmpt/cuda/creation.h @@ -18,6 +18,7 @@ #if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP) #include "paddle/tcmpt/core/dense_tensor.h" +#include "paddle/tcmpt/core/scalar.h" #include "paddle/fluid/platform/device_context.h" @@ -28,7 +29,7 @@ using CUDAContext = paddle::platform::CUDADeviceContext; template void FillAnyLike(const CUDAContext& dev_ctx, const DenseTensor& x, - float val, + const Scalar& val, DenseTensor* out); } // namespace pt diff --git a/paddle/tcmpt/hapi/include/creation.h b/paddle/tcmpt/hapi/include/creation.h index 98044636b12bb..f502adb2e2472 100644 --- a/paddle/tcmpt/hapi/include/creation.h +++ b/paddle/tcmpt/hapi/include/creation.h @@ -14,12 +14,20 @@ #pragma once +#include "paddle/tcmpt/core/dtype.h" +#include "paddle/tcmpt/core/scalar.h" #include "paddle/tcmpt/hapi/include/tensor.h" namespace paddle { namespace experimental { -Tensor full_like(const Tensor& x, float value); +Tensor full_like(const Tensor& x, + const pt::Scalar& value, + pt::DataType dtype = pt::DataType::kUndef); + +Tensor ones_like(const Tensor& x, pt::DataType dtype = pt::DataType::kUndef); + +Tensor zeros_like(const Tensor& x, pt::DataType dtype = pt::DataType::kUndef); } // namespace experimental } // namespace paddle diff --git a/paddle/tcmpt/hapi/lib/creation.cc b/paddle/tcmpt/hapi/lib/creation.cc index e182a496df262..87fdd204dadd5 100644 --- a/paddle/tcmpt/hapi/lib/creation.cc +++ b/paddle/tcmpt/hapi/lib/creation.cc @@ -25,7 +25,7 @@ limitations under the License. */ namespace paddle { namespace experimental { -Tensor full_like(const Tensor& x, float value) { +Tensor full_like(const Tensor& x, const pt::Scalar& value, pt::DataType dtype) { // 1. Get kernel signature and kernel auto kernel_signature = ParseKernelNameAndKeyByArgs("fill_any_like", x); VLOG(1) << kernel_signature.first; @@ -52,6 +52,10 @@ Tensor full_like(const Tensor& x, float value) { // 5. Prepare outputs Tensor out; auto out_def = kernel.args_def().output_defs()[0]; + // InferDataType + if (dtype != pt::DataType::kUndef) { + out_def.SetDataType(dtype); + } auto dense_out = std::make_shared( pt::TensorMeta(out_dims, out_def.backend, out_def.dtype, out_def.layout), pt::TensorStatus()); @@ -64,5 +68,13 @@ Tensor full_like(const Tensor& x, float value) { return out; } +Tensor ones_like(const Tensor& x, pt::DataType dtype) { + return full_like(x, 1, dtype); +} + +Tensor zeros_like(const Tensor& x, pt::DataType dtype) { + return full_like(x, 0, dtype); +} + } // namespace experimental } // namespace paddle diff --git a/paddle/tcmpt/tests/test_fill_api.cc b/paddle/tcmpt/tests/test_fill_api.cc index 39a23a44bfa59..0ed7248604654 100644 --- a/paddle/tcmpt/tests/test_fill_api.cc +++ b/paddle/tcmpt/tests/test_fill_api.cc @@ -29,7 +29,7 @@ PT_DECLARE_MODULE(CreationCUDA); namespace framework = paddle::framework; using DDim = paddle::framework::DDim; -TEST(API, fill) { +TEST(API, full_like) { // 1. create tensor auto dense_x = std::make_shared( pt::TensorMeta(framework::make_ddim({3, 2}), @@ -45,7 +45,7 @@ TEST(API, fill) { paddle::experimental::Tensor x(dense_x); // 2. test API - auto out = paddle::experimental::full_like(x, val); + auto out = paddle::experimental::full_like(x, val, pt::DataType::kFLOAT32); // 3. check result ASSERT_EQ(out.shape().size(), 2); @@ -62,3 +62,67 @@ TEST(API, fill) { ASSERT_NEAR(actual_result[i], val, 1e-6f); } } + +TEST(API, zeros_like) { + // 1. create tensor + auto dense_x = std::make_shared( + pt::TensorMeta(framework::make_ddim({3, 2}), + pt::Backend::kCPU, + pt::DataType::kFLOAT32, + pt::DataLayout::kNCHW), + pt::TensorStatus()); + auto* dense_x_data = dense_x->mutable_data(); + dense_x_data[0] = 1; + + paddle::experimental::Tensor x(dense_x); + + // 2. test API + auto out = paddle::experimental::zeros_like(x, pt::DataType::kFLOAT32); + + // 3. check result + ASSERT_EQ(out.shape().size(), 2); + ASSERT_EQ(out.shape()[0], 3); + ASSERT_EQ(out.numel(), 6); + ASSERT_EQ(out.is_cpu(), true); + ASSERT_EQ(out.type(), pt::DataType::kFLOAT32); + ASSERT_EQ(out.layout(), pt::DataLayout::kNCHW); + ASSERT_EQ(out.initialized(), true); + + auto dense_out = std::dynamic_pointer_cast(out.impl()); + auto* actual_result = dense_out->data(); + for (auto i = 0; i < 6; i++) { + ASSERT_NEAR(actual_result[i], 0, 1e-6f); + } +} + +TEST(API, ones_like) { + // 1. create tensor + auto dense_x = std::make_shared( + pt::TensorMeta(framework::make_ddim({3, 2}), + pt::Backend::kCPU, + pt::DataType::kFLOAT32, + pt::DataLayout::kNCHW), + pt::TensorStatus()); + auto* dense_x_data = dense_x->mutable_data(); + dense_x_data[0] = 0; + + paddle::experimental::Tensor x(dense_x); + + // 2. test API + auto out = paddle::experimental::ones_like(x, pt::DataType::kINT32); + + // 3. check result + ASSERT_EQ(out.shape().size(), 2); + ASSERT_EQ(out.shape()[0], 3); + ASSERT_EQ(out.numel(), 6); + ASSERT_EQ(out.is_cpu(), true); + ASSERT_EQ(out.type(), pt::DataType::kINT32); + ASSERT_EQ(out.layout(), pt::DataLayout::kNCHW); + ASSERT_EQ(out.initialized(), true); + + auto dense_out = std::dynamic_pointer_cast(out.impl()); + auto* actual_result = dense_out->data(); + for (auto i = 0; i < 6; i++) { + ASSERT_EQ(actual_result[i], 1); + } +}