chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:40:42 +08:00
commit e25996e7db
15472 changed files with 3536181 additions and 0 deletions
+26
View File
@@ -0,0 +1,26 @@
set(eager_deps
phi
common
hook_utils
utils
global_utils
backward
tracer
layer
autograd_meta
eager_nan_inf_utils
grad_node_info
grad_tensor_holder
custom_operator_node)
if(NOT (NOT WITH_PYTHON AND ON_INFER))
set(eager_deps ${eager_deps} accumulation_node prim_utils)
endif()
set(fluid_deps tracer layer proto_desc operator op_registry variable_helper)
set(generated_deps final_dygraph_function final_dygraph_node dygraph_function
dygraph_node)
add_subdirectory(data_structure_tests)
add_subdirectory(task_tests)
add_subdirectory(performance_tests)
+32
View File
@@ -0,0 +1,32 @@
if(WITH_CINN)
set(eager_deps ${eager_deps} python)
endif()
if(NOT WIN32)
cc_test(
test_egr_ds_eager_tensor
SRCS eager_tensor_test.cc
DEPS final_dygraph_function ${eager_deps})
endif()
cc_test(
test_egr_ds_auotgrad_meta
SRCS autograd_meta_test.cc
DEPS final_dygraph_function ${eager_deps})
if(NOT ((NOT WITH_PYTHON) AND ON_INFER))
cc_test(
test_egr_ds_grad_tensor_holder
SRCS grad_tensor_holder_test.cc
DEPS conditional_block_op ${eager_deps} ${generated_deps})
cc_test(
test_egr_ds_grad_node_info
SRCS grad_node_info_test.cc
DEPS conditional_block_op ${eager_deps} ${generated_deps})
cc_test(
test_egr_ds_accumulation_node
SRCS accumulation_node_test.cc
DEPS conditional_block_op ${eager_deps} ${generated_deps})
cc_test(
test_egr_ds_tensor_wrapper
SRCS tensor_wrapper_test.cc
DEPS conditional_block_op ${eager_deps} ${generated_deps})
endif()
@@ -0,0 +1,417 @@
// 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.
#include "paddle/fluid/eager/accumulation/accumulation_node.h"
#include <sstream>
#include "gtest/gtest.h"
#include "paddle/fluid/eager/api/utils/hook_utils.h"
#include "paddle/fluid/eager/eager_tensor.h"
#include "paddle/fluid/eager/grad_node_info.h"
#include "paddle/fluid/eager/grad_tensor_holder.h"
#include "paddle/fluid/eager/hooks.h"
#include "paddle/fluid/eager/utils.h"
#include "paddle/phi/api/lib/utils/allocator.h"
#include "paddle/phi/core/kernel_registry.h"
#include "paddle/phi/core/selected_rows.h"
// TODO(jiabin): remove nolint here!!!
using namespace egr; // NOLINT
TEST(AccumulationNode, SelectedRowsAddToTensor) {
// Construct Eager Tensor
phi::DenseTensorMeta meta =
phi::DenseTensorMeta(phi::DataType::FLOAT32, common::make_ddim({1, 1}));
std::vector<int64_t> rows = {0};
std::shared_ptr<phi::SelectedRows> sr0 =
std::make_shared<phi::SelectedRows>(rows, 1);
sr0->mutable_value()->Resize(common::make_ddim({1, 1}));
sr0->mutable_value()->mutable_data<float>(phi::CPUPlace())[0] =
static_cast<float>(10.0f);
paddle::Tensor et0 = paddle::Tensor(sr0);
std::shared_ptr<phi::DenseTensor> dt1 = std::make_shared<phi::DenseTensor>(
std::make_unique<paddle::experimental::DefaultAllocator>(phi::CPUPlace())
.get(),
meta);
dt1->mutable_data<float>(phi::CPUPlace())[0] = static_cast<float>(20.0f);
paddle::Tensor et1 = paddle::Tensor(dt1);
std::shared_ptr<phi::DenseTensor> input_dt =
std::make_shared<phi::DenseTensor>(
std::make_unique<paddle::experimental::DefaultAllocator>(
phi::CPUPlace())
.get(),
meta);
paddle::Tensor input_et = paddle::Tensor(input_dt);
auto grad_meta = EagerUtils::autograd_meta(&input_et);
// Initialize Grad Tensor
std::shared_ptr<phi::SelectedRows> grad_dt =
std::make_shared<phi::SelectedRows>(rows, 1);
grad_dt->mutable_value()->Resize(common::make_ddim({1, 1}));
grad_dt->mutable_value()->mutable_data<float>(phi::CPUPlace())[0] =
static_cast<float>(0.0f);
grad_meta->MutableGrad()->set_impl(grad_dt);
// AccumulationNode
auto node = std::make_shared<GradNodeAccumulation>(input_et);
grad_meta->SetGradNode(node);
grad_meta->SetStopGradient(false);
// operator()
paddle::small_vector<std::vector<paddle::Tensor>, kSlotSmallVectorSize>
et0_vec = {{et0}};
paddle::Tensor ret_et0 = node->operator()(et0_vec)[0][0];
auto* ret_et0_ptr =
std::dynamic_pointer_cast<phi::SelectedRows>(ret_et0.impl())
->value()
.data<float>();
PADDLE_ENFORCE_EQ(ret_et0_ptr[0],
static_cast<float>(10.0f),
common::errors::InvalidArgument(
"The value of the first element of the selected rows "
"should be 10.0f."));
paddle::small_vector<std::vector<paddle::Tensor>, kSlotSmallVectorSize>
et1_vec = {{et1}};
paddle::Tensor ret_et1 = node->operator()(et1_vec)[0][0];
auto* ret_et1_ptr =
std::dynamic_pointer_cast<phi::DenseTensor>(ret_et1.impl())
->data<float>();
PADDLE_ENFORCE_EQ(ret_et1_ptr[0],
static_cast<float>(20.0f),
common::errors::InvalidArgument(
"The value of the first element of the dense tensor "
"should be 20.0f"));
// Check Retain Grad
PADDLE_ENFORCE_EQ(
std::dynamic_pointer_cast<phi::SelectedRows>(et0.impl())
->value()
.data<float>()[0],
static_cast<float>(10.0f),
common::errors::InvalidArgument(
"The value of the first element of the dense tensor should be "
"10.0f"));
paddle::Tensor* grad = EagerUtils::mutable_grad(input_et);
auto* grad_ptr =
std::dynamic_pointer_cast<phi::DenseTensor>(grad->impl())->data<float>();
PADDLE_ENFORCE_EQ(grad_ptr[0],
static_cast<float>(30.0f),
common::errors::InvalidArgument(
"The value of the first element of the dense tensor "
"should be 30.0f"));
}
TEST(AccumulationNode, SelectedRowsMerge) {
// Construct Eager Tensor
phi::DenseTensorMeta meta =
phi::DenseTensorMeta(phi::DataType::FLOAT32, common::make_ddim({1, 1}));
std::vector<int64_t> rows = {0};
std::shared_ptr<phi::SelectedRows> sr0 =
std::make_shared<phi::SelectedRows>(rows, 1);
sr0->mutable_value()->Resize(common::make_ddim({1, 1}));
sr0->mutable_value()->mutable_data<float>(phi::CPUPlace())[0] =
static_cast<float>(10.0f);
paddle::Tensor et0 = paddle::Tensor(sr0);
std::shared_ptr<phi::SelectedRows> sr1 =
std::make_shared<phi::SelectedRows>(rows, 1);
sr1->mutable_value()->Resize(common::make_ddim({1, 1}));
sr1->mutable_value()->mutable_data<float>(phi::CPUPlace())[0] =
static_cast<float>(20.0f);
paddle::Tensor et1 = paddle::Tensor(sr1);
std::shared_ptr<phi::DenseTensor> input_dt =
std::make_shared<phi::DenseTensor>(
std::make_unique<paddle::experimental::DefaultAllocator>(
phi::CPUPlace())
.get(),
meta);
paddle::Tensor input_et = paddle::Tensor(input_dt);
auto grad_meta = EagerUtils::autograd_meta(&input_et);
// Initialize Grad Tensor
std::shared_ptr<phi::SelectedRows> grad_dt =
std::make_shared<phi::SelectedRows>(rows, 1);
grad_dt->mutable_value()->Resize(common::make_ddim({1, 1}));
grad_dt->mutable_value()->mutable_data<float>(phi::CPUPlace())[0] =
static_cast<float>(0.0f);
grad_meta->MutableGrad()->set_impl(grad_dt);
// AccumulationNode
auto node = std::make_shared<GradNodeAccumulation>(input_et);
grad_meta->SetGradNode(node);
grad_meta->SetStopGradient(false);
// operator()
paddle::small_vector<std::vector<paddle::Tensor>, kSlotSmallVectorSize>
et0_vec = {{et0}};
paddle::Tensor ret_et0 = node->operator()(et0_vec)[0][0];
auto* ret_et0_ptr =
std::dynamic_pointer_cast<phi::SelectedRows>(ret_et0.impl())
->value()
.data<float>();
PADDLE_ENFORCE_EQ(ret_et0_ptr[0],
static_cast<float>(10.0f),
common::errors::InvalidArgument(
"The value of the first element of the selected rows "
"should be 10.0f."));
paddle::small_vector<std::vector<paddle::Tensor>, kSlotSmallVectorSize>
et1_vec = {{et1}};
paddle::Tensor ret_et1 = node->operator()(et1_vec)[0][0];
auto* ret_et1_ptr =
std::dynamic_pointer_cast<phi::SelectedRows>(ret_et1.impl())
->value()
.data<float>();
PADDLE_ENFORCE_EQ(ret_et1_ptr[0],
static_cast<float>(20.0f),
common::errors::InvalidArgument(
"The value of the first element of the selected rows "
"should be 20.0f."));
// Check Retain Grad
PADDLE_ENFORCE_EQ(std::dynamic_pointer_cast<phi::SelectedRows>(et0.impl())
->value()
.data<float>()[0],
static_cast<float>(10.0f),
common::errors::InvalidArgument(
"The value of the first element of the selected rows "
"should be 10.0f."));
paddle::Tensor* grad = EagerUtils::mutable_grad(input_et);
auto* grad_ptr = std::dynamic_pointer_cast<phi::SelectedRows>(grad->impl())
->value()
.data<float>();
PADDLE_ENFORCE_EQ(grad_ptr[0],
static_cast<float>(30.0f),
common::errors::InvalidArgument(
"The value of the first element of the selected rows "
"should be 30.0f."));
}
TEST(AccumulationNode, SelectedRowsAddTensor) {
// Construct Eager Tensor
phi::DenseTensorMeta meta =
phi::DenseTensorMeta(phi::DataType::FLOAT32, common::make_ddim({1, 1}));
std::vector<int64_t> rows = {0};
std::shared_ptr<phi::SelectedRows> sr0 =
std::make_shared<phi::SelectedRows>(rows, 1);
sr0->mutable_value()->Resize(common::make_ddim({1, 1}));
sr0->mutable_value()->mutable_data<float>(phi::CPUPlace())[0] =
static_cast<float>(10.0f);
paddle::Tensor et0 = paddle::Tensor(sr0);
std::shared_ptr<phi::SelectedRows> sr1 =
std::make_shared<phi::SelectedRows>(rows, 1);
sr1->mutable_value()->Resize(common::make_ddim({1, 1}));
sr1->mutable_value()->mutable_data<float>(phi::CPUPlace())[0] =
static_cast<float>(20.0f);
paddle::Tensor et1 = paddle::Tensor(sr1);
std::shared_ptr<phi::DenseTensor> input_dt =
std::make_shared<phi::DenseTensor>(
std::make_unique<paddle::experimental::DefaultAllocator>(
phi::CPUPlace())
.get(),
meta);
paddle::Tensor input_et = paddle::Tensor(input_dt);
auto grad_meta = EagerUtils::autograd_meta(&input_et);
// Initialize Grad Tensor
std::shared_ptr<phi::DenseTensor> grad_dt =
std::make_shared<phi::DenseTensor>(
std::make_unique<paddle::experimental::DefaultAllocator>(
phi::CPUPlace())
.get(),
meta);
grad_dt->mutable_data<float>(phi::CPUPlace())[0] = static_cast<float>(0.0f);
grad_meta->MutableGrad()->set_impl(grad_dt);
// AccumulationNode
auto node = std::make_shared<GradNodeAccumulation>(input_et);
grad_meta->SetGradNode(node);
grad_meta->SetStopGradient(false);
// operator()
paddle::small_vector<std::vector<paddle::Tensor>, kSlotSmallVectorSize>
et0_vec = {{et0}};
paddle::Tensor ret_et0 = node->operator()(et0_vec)[0][0];
auto* ret_et0_ptr =
std::dynamic_pointer_cast<phi::SelectedRows>(ret_et0.impl())
->value()
.data<float>();
PADDLE_ENFORCE_EQ(ret_et0_ptr[0],
static_cast<float>(10.0f),
common::errors::InvalidArgument(
"The value of the first element of the selected rows "
"should be 10.0f."));
paddle::small_vector<std::vector<paddle::Tensor>, kSlotSmallVectorSize>
et1_vec = {{et1}};
paddle::Tensor ret_et1 = node->operator()(et1_vec)[0][0];
auto* ret_et1_ptr =
std::dynamic_pointer_cast<phi::SelectedRows>(ret_et1.impl())
->value()
.data<float>();
PADDLE_ENFORCE_EQ(ret_et1_ptr[0],
static_cast<float>(20.0f),
common::errors::InvalidArgument(
"The value of the first element of the selected rows "
"should be 20.0f"));
// Check Retain Grad
PADDLE_ENFORCE_EQ(std::dynamic_pointer_cast<phi::SelectedRows>(et0.impl())
->value()
.data<float>()[0],
static_cast<float>(10.0f),
common::errors::InvalidArgument(
"The value of the first element of the selected rows "
"should be 10.0f"));
paddle::Tensor* grad = EagerUtils::mutable_grad(input_et);
auto* grad_ptr =
std::dynamic_pointer_cast<phi::DenseTensor>(grad->impl())->data<float>();
PADDLE_ENFORCE_EQ(grad_ptr[0],
static_cast<float>(30.0f),
common::errors::InvalidArgument(
"The value of the first element of the dense tensor "
"should be 30.0f"));
}
TEST(AccumulationNode, Tensor) {
// Construct Eager Tensor
phi::DenseTensorMeta meta =
phi::DenseTensorMeta(phi::DataType::FLOAT16, common::make_ddim({1, 1}));
std::shared_ptr<phi::DenseTensor> dt0 = std::make_shared<phi::DenseTensor>(
std::make_unique<paddle::experimental::DefaultAllocator>(phi::CPUPlace())
.get(),
meta);
dt0->mutable_data<phi::dtype::float16>(phi::CPUPlace())[0] =
phi::dtype::float16(10.0f);
paddle::Tensor et0 = paddle::Tensor(dt0);
std::shared_ptr<phi::DenseTensor> dt1 = std::make_shared<phi::DenseTensor>(
std::make_unique<paddle::experimental::DefaultAllocator>(phi::CPUPlace())
.get(),
meta);
dt1->mutable_data<phi::dtype::float16>(phi::CPUPlace())[0] =
phi::dtype::float16(20.0f);
paddle::Tensor et1 = paddle::Tensor(dt1);
std::shared_ptr<phi::DenseTensor> input_dt =
std::make_shared<phi::DenseTensor>(
std::make_unique<paddle::experimental::DefaultAllocator>(
phi::CPUPlace())
.get(),
meta);
paddle::Tensor input_et = paddle::Tensor(input_dt);
auto grad_meta = EagerUtils::autograd_meta(&input_et);
// Initialize Grad Tensor
std::shared_ptr<phi::DenseTensor> grad_dt =
std::make_shared<phi::DenseTensor>(
std::make_unique<paddle::experimental::DefaultAllocator>(
phi::CPUPlace())
.get(),
meta);
grad_dt->mutable_data<phi::dtype::float16>(phi::CPUPlace())[0] =
phi::dtype::float16(0.0f);
grad_meta->MutableGrad()->set_impl(grad_dt);
// AccumulationNode
auto node = std::make_shared<GradNodeAccumulation>(input_et);
grad_meta->SetGradNode(node);
grad_meta->SetStopGradient(false);
// operator()
paddle::small_vector<std::vector<paddle::Tensor>, kSlotSmallVectorSize>
et0_vec = {{et0}};
paddle::Tensor ret_et0 = node->operator()(et0_vec)[0][0];
auto* ret_et0_ptr =
std::dynamic_pointer_cast<phi::DenseTensor>(ret_et0.impl())
->data<phi::dtype::float16>();
PADDLE_ENFORCE_EQ(ret_et0_ptr[0],
phi::dtype::float16(10.0f),
common::errors::InvalidArgument(
"The value of the first element of the dense tensor "
"should be 10.0f."));
paddle::small_vector<std::vector<paddle::Tensor>, kSlotSmallVectorSize>
et1_vec = {{et1}};
paddle::Tensor ret_et1 = node->operator()(et1_vec)[0][0];
auto* ret_et1_ptr =
std::dynamic_pointer_cast<phi::DenseTensor>(ret_et1.impl())
->data<phi::dtype::float16>();
PADDLE_ENFORCE_EQ(ret_et1_ptr[0],
phi::dtype::float16(20.0f),
common::errors::InvalidArgument(
"The value of the first element of the dense tensor "
"should be 20.0f"));
// Check Retain Grad
PADDLE_ENFORCE_EQ(std::dynamic_pointer_cast<phi::DenseTensor>(et0.impl())
->data<phi::dtype::float16>()[0],
phi::dtype::float16(10.0f),
common::errors::InvalidArgument(
"The value of the first element of the dense tensor "
"should be 10.0f"));
paddle::Tensor* grad = EagerUtils::mutable_grad(input_et);
auto* grad_ptr = std::dynamic_pointer_cast<phi::DenseTensor>(grad->impl())
->data<phi::dtype::float16>();
PADDLE_ENFORCE_EQ(grad_ptr[0],
phi::dtype::float16(30.0f),
common::errors::InvalidArgument(
"The value of the first element of the dense tensor "
"should be 30.0f"));
// Reduce Hook case 1: Call RegisterReduceHook and run operator()
VLOG(6) << "Test Reduce Hook";
PADDLE_ENFORCE_EQ(std::dynamic_pointer_cast<phi::DenseTensor>(et0.impl())
->data<phi::dtype::float16>()[0],
phi::dtype::float16(10.0f),
common::errors::InvalidArgument(
"The value of the first element of the dense tensor "
"should be 10.0f"));
auto reduce_hook_1 = [&]() -> void {
auto* input_et_ptr =
std::dynamic_pointer_cast<phi::DenseTensor>(input_et.impl())
->mutable_data<phi::dtype::float16>(phi::CPUPlace());
input_et_ptr[0] = 36.0;
VLOG(6) << "Running Reduce Hook";
};
node->RegisterReduceHook(std::make_shared<egr::CppVoidHook>(reduce_hook_1));
// operator()
paddle::Tensor _ret = node->operator()(et0_vec)[0][0];
// Check operator() result, should be 36.0
auto* _ret_ptr = std::dynamic_pointer_cast<phi::DenseTensor>(_ret.impl())
->data<phi::dtype::float16>();
PADDLE_ENFORCE_EQ(_ret_ptr[0],
phi::dtype::float16(10.0f),
common::errors::InvalidArgument(
"The value of the first element of the dense tensor "
"should be 10.0f"));
// Check Retain Grad, should be 36.0
auto* _ret_input_et_ptr =
std::dynamic_pointer_cast<phi::DenseTensor>(input_et.impl())
->data<phi::dtype::float16>();
PADDLE_ENFORCE_EQ(_ret_input_et_ptr[0],
phi::dtype::float16(36.0f),
common::errors::InvalidArgument(
"The value of the first element of the dense tensor "
"should be 36.0f"));
// Reduce Hook case 2: Call RegisterReduceHook and ApplyReduceHooks directly
VLOG(6) << "Test Reduce Hook";
auto reduce_hook_2 = [&]() -> void {
auto* ret_et0_ptr =
std::dynamic_pointer_cast<phi::DenseTensor>(et0.impl())
->mutable_data<phi::dtype::float16>(phi::CPUPlace());
ret_et0_ptr[0] = 100.0; // set to 100.0
VLOG(6) << "Running Reduce Hook";
};
node->RegisterReduceHook(std::make_shared<egr::CppVoidHook>(reduce_hook_2));
node->ApplyReduceHooks();
// Check ApplyReduceHooks result
PADDLE_ENFORCE_EQ(std::dynamic_pointer_cast<phi::DenseTensor>(et0.impl())
->data<phi::dtype::float16>()[0],
phi::dtype::float16(100.0f),
common::errors::InvalidArgument(
"The value of the first element of the dense tensor "
"should be 100.0f"));
}
@@ -0,0 +1,151 @@
// 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.
#include "paddle/fluid/eager/autograd_meta.h"
#include "glog/logging.h"
#include "gtest/gtest.h"
#include "paddle/fluid/eager/eager_tensor.h"
#include "paddle/fluid/eager/grad_node_info.h"
#include "paddle/phi/api/lib/utils/allocator.h"
#include "test/cpp/eager/data_structure_tests/grad_node_test.h"
TEST(AutogradMeta, Constructor) {
paddle::Tensor et1;
auto auto_grad = std::make_shared<egr::AutogradMeta>();
et1.set_autograd_meta(auto_grad);
auto* tmp_auto = static_cast<egr::AutogradMeta*>(et1.get_autograd_meta());
PADDLE_ENFORCE_EQ(
tmp_auto->OutRankInfo().first,
size_t(0),
common::errors::InvalidArgument(
"The first element of OutRankInfo should be 0, but received %d.",
tmp_auto->OutRankInfo().first));
PADDLE_ENFORCE_EQ(
tmp_auto->OutRankInfo().second,
size_t(0),
common::errors::InvalidArgument(
"The second element of OutRankInfo should be 0, but received %d.",
tmp_auto->OutRankInfo().second));
CHECK(tmp_auto->IsInitialized() == false);
}
TEST(AutogradMeta, MemberFunction) {
paddle::Tensor et1;
auto auto_grad = std::make_shared<egr::AutogradMeta>();
et1.set_autograd_meta(auto_grad);
auto* tmp_auto = static_cast<egr::AutogradMeta*>(et1.get_autograd_meta());
VLOG(6) << "Test Grad";
PADDLE_ENFORCE_EQ(tmp_auto->Grad().defined(),
false,
common::errors::Fatal("grad should not be defined now"));
auto* grad_t = tmp_auto->MutableGrad();
phi::DenseTensorMeta meta =
phi::DenseTensorMeta(phi::DataType::FLOAT32, common::make_ddim({1, 2}));
std::shared_ptr<phi::DenseTensor> dt = std::make_shared<phi::DenseTensor>(
std::make_unique<paddle::experimental::DefaultAllocator>(phi::CPUPlace())
.get(),
meta);
auto* dt_ptr = dt->mutable_data<float>(phi::CPUPlace());
dt_ptr[0] = 5.0f;
dt_ptr[1] = 10.0f;
grad_t->set_impl(dt);
VLOG(6) << "Test Mutable Grad";
auto impl_ptr =
std::dynamic_pointer_cast<phi::DenseTensor>(tmp_auto->Grad().impl());
PADDLE_ENFORCE_EQ(
impl_ptr->data<float>()[0],
5.0f,
common::errors::InvalidArgument(
"The first element of grad tensor should be 5.0, but received %f.",
impl_ptr->data<float>()[0]));
PADDLE_ENFORCE_EQ(
impl_ptr->data<float>()[1],
10.0f,
common::errors::InvalidArgument(
"The second element of grad tensor should be 10.0, but received %f.",
impl_ptr->data<float>()[1]));
VLOG(6) << "Test IsInitialized";
PADDLE_ENFORCE_EQ(
tmp_auto->IsInitialized(),
false,
common::errors::Fatal(
"egr::AutogradMeta variable tmp_auto should not be initialized now"));
VLOG(6) << "Test GradNodeSetter Getter";
auto grad_node = std::make_shared<eager_test::GradTestNode>();
tmp_auto->SetGradNode(grad_node);
PADDLE_ENFORCE_EQ(
tmp_auto->IsInitialized(),
true,
common::errors::Fatal(
"egr::AutogradMeta variable tmp_auto should be initialized now"));
auto tmp_grad_node = tmp_auto->GetMutableGradNode();
std::dynamic_pointer_cast<eager_test::GradTestNode>(tmp_grad_node)->val_ =
5.0;
PADDLE_ENFORCE_EQ(
dynamic_cast<eager_test::GradTestNode*>(tmp_auto->GradNode())->val_,
5.0,
common::errors::InvalidArgument(
"The value of GradTestNode should be 5.0, but received %f.",
dynamic_cast<eager_test::GradTestNode*>(tmp_auto->GradNode())->val_));
VLOG(6) << "Test rank Setter Getter";
PADDLE_ENFORCE_EQ(
tmp_auto->OutRankInfo().first,
size_t(0),
common::errors::InvalidArgument(
"The first element of OutRankInfo should be 0, but received %d.",
tmp_auto->OutRankInfo().first));
PADDLE_ENFORCE_EQ(
tmp_auto->OutRankInfo().second,
size_t(0),
common::errors::InvalidArgument(
"The second element of OutRankInfo should be 0, but received %d.",
tmp_auto->OutRankInfo().second));
tmp_auto->SetSingleOutRankWithSlot(2, 3);
PADDLE_ENFORCE_EQ(
tmp_auto->OutRankInfo().first,
size_t(2),
common::errors::InvalidArgument(
"The first element of OutRankInfo should be 2, but received %d.",
tmp_auto->OutRankInfo().first));
PADDLE_ENFORCE_EQ(
tmp_auto->OutRankInfo().second,
size_t(3),
common::errors::InvalidArgument(
"The second element of OutRankInfo should be 3, but received %d.",
tmp_auto->OutRankInfo().second));
VLOG(6) << "Test stop gradient Setter Getter";
PADDLE_ENFORCE_EQ(
tmp_auto->NumericStopGradient(),
-1,
common::errors::InvalidArgument(
"The NumericStopGradient value should be -1, but received %d.",
tmp_auto->NumericStopGradient()));
tmp_auto->SetStopGradient(true);
PADDLE_ENFORCE_EQ(
tmp_auto->StopGradient(),
true,
common::errors::Fatal("tmp_auto->StopGradient() should be true now"));
VLOG(6) << "Test Persistable Setter Getter";
PADDLE_ENFORCE_EQ(
tmp_auto->Persistable(),
false,
common::errors::Fatal("tmp_auto->Persistable() should be false now"));
tmp_auto->SetPersistable(true);
PADDLE_ENFORCE_EQ(
tmp_auto->Persistable(),
true,
common::errors::Fatal(
"tmp_auto->Persistable() should be true now after SetPersistable()"));
}
@@ -0,0 +1,439 @@
// 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.
#include "paddle/fluid/eager/eager_tensor.h"
#include "glog/logging.h"
#include "gtest/gtest.h"
#include "paddle/common/layout.h"
#include "paddle/fluid/imperative/var_helper.h"
#include "paddle/phi/api/lib/utils/allocator.h"
#include "paddle/phi/core/kernel_registry.h"
namespace eager_test {
using AbstractAutogradMeta = paddle::AbstractAutogradMeta;
class AutogradMetaTest : public AbstractAutogradMeta {
public:
explicit AutogradMetaTest(int val) : val_(val) {}
int val_ = 0;
};
} // namespace eager_test
TEST(Tensor, Constructor) {
paddle::Tensor et1 = paddle::Tensor();
paddle::Tensor et2 = paddle::Tensor("et2");
PADDLE_ENFORCE_EQ(et1.defined(),
false,
common::errors::InvalidArgument("Tensor et1 should be "
"undefined."));
PADDLE_ENFORCE_EQ(et2.name(),
"et2",
common::errors::InvalidArgument("Tensor name should be "
"'et2'."));
phi::DenseTensorMeta meta =
phi::DenseTensorMeta(phi::DataType::FLOAT32, common::make_ddim({1, 2}));
std::shared_ptr<phi::DenseTensor> dt = std::make_shared<phi::DenseTensor>(
std::make_unique<paddle::experimental::DefaultAllocator>(phi::CPUPlace())
.get(),
meta);
auto* dt_ptr = dt->mutable_data<float>(phi::CPUPlace());
dt_ptr[0] = 5.0f;
dt_ptr[1] = 10.0f;
paddle::Tensor et3 = paddle::Tensor(dt);
auto* et3_ptr =
std::dynamic_pointer_cast<phi::DenseTensor>(et3.impl())->data<float>();
PADDLE_ENFORCE_EQ(et3_ptr[0],
5.0f,
common::errors::InvalidArgument("First element should be "
"5.0f."));
PADDLE_ENFORCE_EQ(et3_ptr[1],
10.0f,
common::errors::InvalidArgument("Second element should be "
"10.0f."));
// copy constructor
paddle::Tensor et4(et3);
auto* et4_ptr =
std::dynamic_pointer_cast<phi::DenseTensor>(et4.impl())->data<float>();
PADDLE_ENFORCE_EQ(et4_ptr[0],
5.0f,
common::errors::InvalidArgument("First element should be "
"5.0f."));
PADDLE_ENFORCE_EQ(et4_ptr[1],
10.0f,
common::errors::InvalidArgument("Second element should be "
"10.0f."));
paddle::Tensor et5(std::move(et4));
auto* et5_ptr =
std::dynamic_pointer_cast<phi::DenseTensor>(et5.impl())->data<float>();
PADDLE_ENFORCE_EQ(et5_ptr[0],
5.0f,
common::errors::InvalidArgument("First element should be "
"5.0f."));
PADDLE_ENFORCE_EQ(et5_ptr[1],
10.0f,
common::errors::InvalidArgument("Second element should be "
"10.0f."));
}
TEST(Tensor, MemberFunction) {
paddle::Tensor et3;
phi::DenseTensorMeta meta =
phi::DenseTensorMeta(phi::DataType::FLOAT32, common::make_ddim({1, 2}));
std::shared_ptr<phi::DenseTensor> dt = std::make_shared<phi::DenseTensor>(
std::make_unique<paddle::experimental::DefaultAllocator>(phi::CPUPlace())
.get(),
meta);
auto* dt_ptr = dt->mutable_data<float>(phi::CPUPlace());
dt_ptr[0] = 5.0f;
dt_ptr[1] = 10.0f;
VLOG(6) << "Make Dense Tensor";
et3.set_name("et3");
VLOG(6) << "Set Name";
PADDLE_ENFORCE_EQ(et3.name(),
"et3",
common::errors::InvalidArgument("Tensor name should be "
"'et3'."));
PADDLE_ENFORCE_EQ(et3.defined(),
false,
common::errors::InvalidArgument("Tensor et3 should be "
"undefined."));
et3.set_impl(dt);
VLOG(6) << "Set impl";
PADDLE_ENFORCE_EQ(et3.initialized(),
true,
common::errors::InvalidArgument("Tensor et3 should be "
"initialized."));
PADDLE_ENFORCE_EQ(et3.is_cpu(),
true,
common::errors::InvalidArgument("Tensor et3 should be "
"on CPU."));
PADDLE_ENFORCE_EQ(et3.is_gpu(),
false,
common::errors::InvalidArgument("Tensor et3 should not be "
"on GPU."));
PADDLE_ENFORCE_EQ(et3.numel(),
2,
common::errors::InvalidArgument("Tensor et3 should have "
"2 elements."));
auto expected_dim = common::make_ddim({1, 2});
PADDLE_ENFORCE_EQ(
et3.dims(),
expected_dim,
common::errors::InvalidArgument("Tensor dimensions should be "
"{1, 2}."));
PADDLE_ENFORCE_EQ(et3.type(),
phi::DataType::FLOAT32,
common::errors::InvalidArgument("Tensor data type should "
"be FLOAT32."));
PADDLE_ENFORCE_EQ(et3.layout(),
phi::DataLayout::NCHW,
common::errors::InvalidArgument("Tensor layout should be "
"NCHW."));
CHECK(phi::is_cpu_place(et3.place()));
VLOG(6) << "Get impl";
auto* dt3_ptr =
std::dynamic_pointer_cast<phi::DenseTensor>(et3.impl())->data<float>();
PADDLE_ENFORCE_EQ(dt3_ptr[0],
5.0f,
common::errors::InvalidArgument("First element should be "
"5.0f."));
PADDLE_ENFORCE_EQ(dt3_ptr[1],
10.0f,
common::errors::InvalidArgument("Second element should be "
"10.0f."));
paddle::Tensor et4 = et3;
VLOG(6) << "copy =";
PADDLE_ENFORCE_EQ(et4.initialized(),
true,
common::errors::InvalidArgument("Tensor et4 should be "
"initialized."));
auto* dt4_ptr =
std::dynamic_pointer_cast<phi::DenseTensor>(et4.impl())->data<float>();
PADDLE_ENFORCE_EQ(dt4_ptr[0],
5.0f,
common::errors::InvalidArgument("First element should be "
"5.0f."));
PADDLE_ENFORCE_EQ(dt4_ptr[1],
10.0f,
common::errors::InvalidArgument("Second element should be "
"10.0f."));
VLOG(6) << "move =";
paddle::Tensor et5 = std::move(et4);
auto* dt5_ptr =
std::dynamic_pointer_cast<phi::DenseTensor>(et5.impl())->data<float>();
PADDLE_ENFORCE_EQ(dt5_ptr[0],
5.0f,
common::errors::InvalidArgument("First element should be "
"5.0f."));
PADDLE_ENFORCE_EQ(dt5_ptr[1],
10.0f,
common::errors::InvalidArgument("Second element should be "
"10.0f."));
VLOG(6) << "AutogradMeta";
auto autograd_meta_test = std::make_shared<eager_test::AutogradMetaTest>(2);
et3.set_autograd_meta(autograd_meta_test);
auto* tmp_autograd_meta_test =
static_cast<eager_test::AutogradMetaTest*>(et3.get_autograd_meta());
PADDLE_ENFORCE_EQ(tmp_autograd_meta_test->val_,
2,
common::errors::InvalidArgument("AutogradMetaTest value "
"should be 2."));
}
TEST(EagerVariable, Constructor) {
paddle::Tensor t3;
phi::DenseTensorMeta meta =
phi::DenseTensorMeta(phi::DataType::FLOAT32, common::make_ddim({1, 2}));
std::shared_ptr<phi::DenseTensor> dt = std::make_shared<phi::DenseTensor>(
std::make_unique<paddle::experimental::DefaultAllocator>(phi::CPUPlace())
.get(),
meta);
auto* dt_ptr = dt->mutable_data<float>(phi::CPUPlace());
dt_ptr[0] = 5.0f;
dt_ptr[1] = 10.0f;
VLOG(6) << "Make Dense Tensor";
t3.set_name("t3");
VLOG(6) << "Set Name";
PADDLE_ENFORCE_EQ(t3.name(),
"t3",
common::errors::InvalidArgument("Tensor name should be "
"'t3'."));
PADDLE_ENFORCE_EQ(
t3.defined(),
false,
common::errors::InvalidArgument(
"Tensor t3 should be undefined but got %d.", t3.defined()));
t3.set_impl(dt);
egr::EagerVariable et3 = egr::EagerVariable(t3);
VLOG(6) << "SyncToVar";
PADDLE_ENFORCE_EQ(et3.Var().Get<phi::DenseTensor>().data<float>()[0],
5.0f,
common::errors::InvalidArgument("First element should be "
"5.0f."));
PADDLE_ENFORCE_EQ(et3.Var().Get<phi::DenseTensor>().data<float>()[1],
10.0f,
common::errors::InvalidArgument("Second element should be "
"10.0f."));
VLOG(6) << "SyncToTensor";
paddle::Tensor t4;
t4.set_impl(et3.GetTensorBase());
PADDLE_ENFORCE_EQ(
t4.initialized(),
true,
common::errors::InvalidArgument(
"Tensor t4 should be initialized but got %d.", t4.initialized()));
VLOG(6) << "Check Tensor";
auto* dt3_tmp_ptr =
std::dynamic_pointer_cast<phi::DenseTensor>(t4.impl())->data<float>();
PADDLE_ENFORCE_EQ(dt3_tmp_ptr[0],
5.0f,
common::errors::InvalidArgument("First element should be "
"5.0f."));
PADDLE_ENFORCE_EQ(dt3_tmp_ptr[1],
10.0f,
common::errors::InvalidArgument("Second element should be "
"10.0f."));
t4.reset();
PADDLE_ENFORCE_EQ(
t4.defined(),
false,
common::errors::InvalidArgument(
"Tensor t4 should be undefined but got %d.", t4.defined()));
VLOG(6) << "Check Tensor Copy_";
std::vector<int64_t> rows = {1, 2};
std::vector<int64_t> dims = {2};
paddle::Tensor t7(std::make_shared<phi::SelectedRows>(rows, 2));
std::dynamic_pointer_cast<phi::SelectedRows>(t7.impl())
->mutable_value()
->Resize(common::make_ddim(dims));
auto* dt7_tmp_ptr = std::dynamic_pointer_cast<phi::SelectedRows>(t7.impl())
->mutable_value()
->mutable_data<float>(phi::CPUPlace());
dt7_tmp_ptr[0] = 6.0f;
dt7_tmp_ptr[1] = 11.0f;
paddle::Tensor t8;
paddle::Tensor t5;
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
paddle::Tensor t6;
paddle::Tensor t9;
VLOG(6) << "Check Tensor Copy_ Selected Rows";
t8.copy_(t7, phi::GPUPlace(0), false);
t9.copy_(t8, phi::CPUPlace(), false);
auto* dt9_tmp_ptr = std::dynamic_pointer_cast<phi::SelectedRows>(t9.impl())
->value()
.data<float>();
PADDLE_ENFORCE_EQ(dt9_tmp_ptr[0],
6.0f,
common::errors::InvalidArgument("First element should be "
"6.0f."));
PADDLE_ENFORCE_EQ(dt9_tmp_ptr[1],
11.0f,
common::errors::InvalidArgument("Second element should be "
"11.0f."));
PADDLE_ENFORCE_EQ(
std::dynamic_pointer_cast<phi::SelectedRows>(t9.impl())->height(),
2,
common::errors::InvalidArgument("SelectedRows height should "
"be 2."));
VLOG(6) << "Check Tensor Copy_ Dense Tensor";
t5.copy_(t3, phi::GPUPlace(0), false);
t6.copy_(t5, phi::CPUPlace(), false);
auto* dt6_tmp_ptr =
std::dynamic_pointer_cast<phi::DenseTensor>(t6.impl())->data<float>();
PADDLE_ENFORCE_EQ(dt6_tmp_ptr[0],
5.0f,
common::errors::InvalidArgument("First element should be "
"5.0f."));
PADDLE_ENFORCE_EQ(dt6_tmp_ptr[1],
10.0f,
common::errors::InvalidArgument("Second element should be "
"10.0f."));
#else
t5.copy_(t3, phi::CPUPlace(), false);
auto* dt5_tmp_ptr =
std::dynamic_pointer_cast<phi::DenseTensor>(t5.impl())->data<float>();
PADDLE_ENFORCE_EQ(dt5_tmp_ptr[0],
5.0f,
common::errors::InvalidArgument("First element should be "
"5.0f."));
PADDLE_ENFORCE_EQ(dt5_tmp_ptr[1],
10.0f,
common::errors::InvalidArgument("Second element should be "
"10.0f."));
#endif
VLOG(6) << "Finish";
}
TEST(EagerVariable, DataLayout) {
paddle::Tensor tensor;
phi::DenseTensorMeta meta =
phi::DenseTensorMeta(phi::DataType::FLOAT32,
common::make_ddim({1, 1, 1, 1}),
phi::DataLayout::UNDEFINED);
std::shared_ptr<phi::DenseTensor> dt = std::make_shared<phi::DenseTensor>(
std::make_unique<paddle::experimental::DefaultAllocator>(phi::CPUPlace())
.get(),
meta);
auto* dt_ptr = dt->mutable_data<float>(phi::CPUPlace());
dt_ptr[0] = 5.0f;
dt_ptr[1] = 5.0f;
dt_ptr[2] = 5.0f;
dt_ptr[3] = 5.0f;
tensor.set_impl(dt);
auto eager_var = std::make_shared<egr::EagerVariable>(tensor);
auto layout = paddle::imperative::GetDataLayout(eager_var);
PADDLE_ENFORCE_EQ(layout,
phi::DataLayout::UNDEFINED,
common::errors::InvalidArgument("Data layout should be "
"UNDEFINED."));
paddle::imperative::SetDataLayout(eager_var, phi::DataLayout::NCHW);
layout = paddle::imperative::GetDataLayout(eager_var);
PADDLE_ENFORCE_EQ(layout,
phi::DataLayout::NCHW,
common::errors::InvalidArgument("Data layout should be "
"NCHW."));
}
TEST(VariableCompatTensor, MemberFunction) {
egr::VariableCompatTensor var_tensor;
// test GetMutable and Get
var_tensor.GetMutable<phi::Vocab>();
auto& vocab = var_tensor.Get<phi::Vocab>();
EXPECT_EQ(vocab.size(), 0UL);
bool caught_exception = false;
try {
var_tensor.GetMutable<phi::Strings>();
} catch (paddle::platform::EnforceNotMet& error) {
caught_exception = true;
std::string ex_msg = error.what();
EXPECT_TRUE(ex_msg.find("The Variable type must be") != std::string::npos);
}
EXPECT_TRUE(caught_exception);
// test Type and IsType
EXPECT_TRUE(var_tensor.IsType<phi::Vocab>());
EXPECT_EQ(var_tensor.Type(),
static_cast<int>(paddle::framework::proto::VarType::VOCAB));
// test valid and initialized
EXPECT_TRUE(var_tensor.IsInitialized());
EXPECT_TRUE(var_tensor.valid());
EXPECT_TRUE(var_tensor.initialized());
// test name
EXPECT_EQ(var_tensor.name(), "VariableCompatTensor");
// test other throw error methods
caught_exception = false;
try {
var_tensor.numel();
} catch (paddle::platform::EnforceNotMet& error) {
caught_exception = true;
std::string ex_msg = error.what();
EXPECT_TRUE(ex_msg.find("numel") != std::string::npos);
}
EXPECT_TRUE(caught_exception);
caught_exception = false;
try {
var_tensor.dims();
} catch (paddle::platform::EnforceNotMet& error) {
caught_exception = true;
std::string ex_msg = error.what();
EXPECT_TRUE(ex_msg.find("dims") != std::string::npos);
}
EXPECT_TRUE(caught_exception);
caught_exception = false;
try {
var_tensor.dtype();
} catch (paddle::platform::EnforceNotMet& error) {
caught_exception = true;
std::string ex_msg = error.what();
EXPECT_TRUE(ex_msg.find("dtype") != std::string::npos);
}
EXPECT_TRUE(caught_exception);
caught_exception = false;
try {
var_tensor.layout();
} catch (paddle::platform::EnforceNotMet& error) {
caught_exception = true;
std::string ex_msg = error.what();
EXPECT_TRUE(ex_msg.find("layout") != std::string::npos);
}
EXPECT_TRUE(caught_exception);
caught_exception = false;
try {
var_tensor.place();
} catch (paddle::platform::EnforceNotMet& error) {
caught_exception = true;
std::string ex_msg = error.what();
EXPECT_TRUE(ex_msg.find("place") != std::string::npos);
}
EXPECT_TRUE(caught_exception);
caught_exception = false;
try {
var_tensor.AllocateFrom(nullptr, phi::DataType::UNDEFINED);
} catch (paddle::platform::EnforceNotMet& error) {
caught_exception = true;
std::string ex_msg = error.what();
EXPECT_TRUE(ex_msg.find("AllocateFrom") != std::string::npos);
}
EXPECT_TRUE(caught_exception);
// test Clear
var_tensor.Clear();
EXPECT_FALSE(var_tensor.IsInitialized());
}
@@ -0,0 +1,257 @@
// 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.
#include "paddle/fluid/eager/grad_node_info.h"
#include "glog/logging.h"
#include "gtest/gtest.h"
#include "paddle/fluid/eager/autograd_meta.h"
#include "paddle/fluid/eager/eager_tensor.h"
#include "paddle/fluid/eager/hooks.h"
#include "paddle/phi/api/lib/utils/allocator.h"
#include "paddle/phi/core/enforce.h"
#include "test/cpp/eager/data_structure_tests/grad_node_test.h"
TEST(GradNodeInfo, GradSlotMeta) {
auto grad_slot = egr::GradSlotMeta();
VLOG(6) << "Set SetStopGradient";
grad_slot.SetStopGradient();
PADDLE_ENFORCE_EQ(
grad_slot.IsStopGradient(),
true,
common::errors::Fatal("`grad_slot.IsStopGradient()` should be "
"true, please check related function"));
}
void TestGradNodeBase(bool is_remove_gradient_hook) {
VLOG(6) << "Construct Grad Node";
auto grad_test_node0 = std::make_shared<eager_test::GradTestNode>(
/* val */ 5.0, /* in_num */ 2, /* out_num */ 2);
auto grad_test_node1 = std::make_shared<eager_test::GradTestNode>();
paddle::small_vector<std::vector<paddle::Tensor>, egr::kSlotSmallVectorSize>
grads;
phi::DenseTensorMeta meta =
phi::DenseTensorMeta(phi::DataType::FLOAT32, common::make_ddim({1, 1}));
std::shared_ptr<phi::DenseTensor> dt = std::make_shared<phi::DenseTensor>(
std::make_unique<paddle::experimental::DefaultAllocator>(phi::CPUPlace())
.get(),
meta);
auto* dt_ptr = dt->mutable_data<float>(phi::CPUPlace());
dt_ptr[0] = 5.0f;
paddle::Tensor et1(dt);
grads = {{et1}};
std::vector<int64_t> mesh_shape = {2, 2};
std::vector<int64_t> process_ids = {0, 1, 2, 3};
std::vector<std::string> dim_names = {"dp", "mp"};
phi::distributed::ProcessMesh process_mesh(
mesh_shape, process_ids, dim_names);
std::vector<int64_t> dim_mapping = {-1, 1};
phi::distributed::TensorDistAttr dist_attr =
phi::distributed::TensorDistAttr();
dist_attr.set_process_mesh(process_mesh);
dist_attr.set_dims_mapping(dim_mapping);
dist_attr.set_dynamic_dims(std::vector<bool>(mesh_shape.size(), false));
std::shared_ptr<phi::distributed::DistTensor> dist_dt1 =
std::make_shared<phi::distributed::DistTensor>(
phi::distributed::DistTensor(dt, dist_attr));
paddle::Tensor dist_et1(dist_dt1);
VLOG(6) << "Test Grad Node Call";
auto res = (*grad_test_node0)(grads);
PADDLE_ENFORCE_EQ(
std::dynamic_pointer_cast<phi::DenseTensor>(res[0][0].impl())
->data<float>()[0],
6.0f,
common::errors::InvalidArgument("Data of grads mismatch. Expected 6.0."));
egr::Edge tmp_edge1(grad_test_node1, 3, 4);
auto auto_grad1 = std::make_shared<egr::AutogradMeta>(tmp_edge1);
et1.set_autograd_meta(auto_grad1);
VLOG(6) << "Test Set Meta and Get Meta";
auto_grad1->SetStopGradient(true);
grad_test_node0->SetGradInMeta(et1, 0);
grad_test_node0->SetGradInMeta({et1}, 1);
grad_test_node0->SetGradOutMeta(et1, 0);
grad_test_node0->SetGradOutMeta({et1}, 1);
grad_test_node0->SetGradOutMeta(dist_et1, 0, dist_attr, dist_et1.dims());
PADDLE_ENFORCE_EQ(
grad_test_node0->InputMeta()[0].size(),
1UL,
common::errors::InvalidArgument("Size of input mismatch. Expected 1."));
PADDLE_ENFORCE_EQ(
grad_test_node0->InputMeta()[1].size(),
1UL,
common::errors::InvalidArgument("Size of input mismatch. Expected 1."));
PADDLE_ENFORCE_EQ(
grad_test_node0->InputMeta()[0][0].GetTensorMeta().dtype,
meta.dtype,
common::errors::InvalidArgument("Dtype of input tensor mismatch."));
PADDLE_ENFORCE_EQ(
grad_test_node0->InputMeta()[1][0].GetTensorMeta().dtype,
meta.dtype,
common::errors::InvalidArgument("Dtype of input tensor mismatch."));
PADDLE_ENFORCE_EQ(grad_test_node0->OutputMeta()[0][0].IsStopGradient(),
true,
common::errors::Fatal(
"`grad_test_node0->OutputMeta()[0][0].IsStopGradient()"
"` should be true, please related function"));
PADDLE_ENFORCE_EQ(grad_test_node0->OutputMeta()[1][0].IsStopGradient(),
true,
common::errors::Fatal(
"`grad_test_node0->OutputMeta()[1][0].IsStopGradient()"
"` should be true, please related function"));
PADDLE_ENFORCE_EQ(
grad_test_node0->OutputMeta()[0][0].GetTensorMeta().dtype,
meta.dtype,
common::errors::InvalidArgument("Dtype of output tensor mismatch."));
PADDLE_ENFORCE_EQ(
grad_test_node0->OutputMeta()[1][0].GetTensorMeta().dtype,
meta.dtype,
common::errors::InvalidArgument("Dtype of output tensor mismatch."));
PADDLE_ENFORCE_EQ(
grad_test_node0->OutputMeta()[0][0].DistAttr(),
dist_attr,
common::errors::InvalidArgument("DistAttr of output tensor mismatch."));
PADDLE_ENFORCE_EQ(
grad_test_node0->OutputMeta()[0][0].DistTensorGlobalDims(),
dist_et1.dims(),
common::errors::InvalidArgument("DDims of output tensor mismatch."));
VLOG(6) << "Test Default Set Meta and Get Meta";
auto grad_test_node2 = std::make_shared<eager_test::GradTestNode>(
/* val */ 5.0, /* in_num */ 1, /* out_num */ 1);
grad_test_node2->SetDefaultGradInOutMeta();
PADDLE_ENFORCE_GT(
grad_test_node2->OutputMeta()[0].size(),
0UL,
common::errors::InvalidArgument("Size of output not greater than 0."));
CHECK(grad_test_node2->OutputMeta()[0][0].IsStopGradient() == false);
PADDLE_ENFORCE_EQ(
grad_test_node2->OutputMeta()[0].size(),
1UL,
common::errors::InvalidArgument("Size of output mismatch. Expected 1."));
VLOG(6) << "Test Gradient Hook";
auto gradient_hook = [](const paddle::Tensor& et) -> paddle::Tensor {
paddle::Tensor res;
phi::DenseTensorMeta meta =
phi::DenseTensorMeta(phi::DataType::FLOAT32, common::make_ddim({1, 1}));
std::shared_ptr<phi::DenseTensor> dt = std::make_shared<phi::DenseTensor>(
std::make_unique<paddle::experimental::DefaultAllocator>(
phi::CPUPlace())
.get(),
meta);
auto* dt_ptr = dt->mutable_data<float>(phi::CPUPlace());
dt_ptr[0] = 6.0f;
auto* et_ptr =
std::dynamic_pointer_cast<phi::DenseTensor>(et.impl())->data<float>();
dt_ptr[0] += et_ptr[0];
res.set_impl(dt);
VLOG(6) << "Running Gradient Hook";
return res;
};
int64_t hook_id = grad_test_node0->RegisterGradientHook(
0, 0, std::make_shared<egr::CppTensorHook>(gradient_hook));
if (is_remove_gradient_hook) {
// Remove GradientHook
grad_test_node0->RemoveGradientHook(hook_id);
}
// Check results
auto grad_hook_res = grad_test_node0->ApplyGradientHooks(grads);
PADDLE_ENFORCE_EQ(
std::dynamic_pointer_cast<phi::DenseTensor>(grad_hook_res[0][0].impl())
->data<float>()[0],
is_remove_gradient_hook ? 5.0 : 11.0,
common::errors::InvalidArgument(
"Data of grad hook res mismatch. Expected 5.0 or 11.0."));
}
TEST(GradNodeInfo, GradNodeBase) {
TestGradNodeBase(true);
TestGradNodeBase(false);
}
TEST(GradNodeInfo, Edge) {
phi::DenseTensorMeta meta =
phi::DenseTensorMeta(phi::DataType::FLOAT32, common::make_ddim({1, 1}));
std::shared_ptr<phi::DenseTensor> dt = std::make_shared<phi::DenseTensor>(
std::make_unique<paddle::experimental::DefaultAllocator>(phi::CPUPlace())
.get(),
meta);
paddle::Tensor et1(dt);
auto grad_test_node0 = std::make_shared<eager_test::GradTestNode>(5, 2, 2);
auto auto_grad1 = std::make_shared<egr::AutogradMeta>();
VLOG(6) << "Test Construct Edge";
egr::Edge edge0 = egr::Edge();
PADDLE_ENFORCE_EQ(
edge0.IsInitialized(),
false,
common::errors::Fatal("`edge0.IsInitialized()` should be "
"false, please check related function"));
egr::Edge edge1 = egr::Edge(grad_test_node0, size_t(0), size_t(0));
PADDLE_ENFORCE_EQ(
edge1.IsInitialized(),
true,
common::errors::Fatal("`edge1.IsInitialized()` should be "
"true, please check related function"));
egr::Edge edge2 =
egr::Edge(grad_test_node0, std::make_pair(size_t(1), size_t(0)));
VLOG(6) << "Test Set Edge's Grad Node";
auto* grad_node = edge1.GetGradNode();
et1.set_autograd_meta(auto_grad1);
grad_node->SetGradInMeta(et1, 0);
PADDLE_ENFORCE_EQ(
grad_node->InputMeta().size(),
2UL,
common::errors::InvalidArgument("Size of input mismatch. Expected 2."));
std::vector<egr::AutogradMeta*> metas = {auto_grad1.get()};
PADDLE_ENFORCE_EQ(
grad_node->InputMeta()[0][0].IsStopGradient(),
true,
common::errors::Fatal("`grad_node->InputMeta()[0][0].IsStopGradient()` "
"should be true, please check related function"));
VLOG(6) << "Test Get/Set Edge Rank Info";
PADDLE_ENFORCE_EQ(
edge2.GetEdgeRankInfo().first,
1UL,
common::errors::InvalidArgument("Edge rank info mismatch. Expected 1."));
PADDLE_ENFORCE_EQ(
edge2.GetEdgeRankInfo().second,
0UL,
common::errors::InvalidArgument("Edge rank info mismatch. Expected 0."));
edge2.SetEdgeRankInfo(2, 3);
PADDLE_ENFORCE_EQ(
edge2.GetEdgeRankInfo().first,
2UL,
common::errors::InvalidArgument("Edge rank info mismatch. Expected 2."));
PADDLE_ENFORCE_EQ(
edge2.GetEdgeRankInfo().second,
3UL,
common::errors::InvalidArgument("Edge rank info mismatch. Expected 3."));
edge2.SetEdgeRankInfo(std::make_pair(size_t(4), size_t(5)));
PADDLE_ENFORCE_EQ(
edge2.GetEdgeRankInfo().first,
4UL,
common::errors::InvalidArgument("Edge rank info mismatch. Expected 4."));
PADDLE_ENFORCE_EQ(
edge2.GetEdgeRankInfo().second,
5UL,
common::errors::InvalidArgument("Edge rank info mismatch. Expected 5."));
}
@@ -0,0 +1,65 @@
// 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
#include "glog/logging.h"
#include "gtest/gtest.h"
#include "paddle/fluid/eager/autograd_meta.h"
#include "paddle/fluid/eager/eager_tensor.h"
#include "paddle/fluid/eager/grad_node_info.h"
#include "paddle/phi/api/lib/utils/allocator.h"
namespace egr {
class TensorWrapper;
}
namespace eager_test {
class GradTestNode : public egr::GradNodeBase {
public:
~GradTestNode() override = default;
GradTestNode(float val, int in_num, int out_num)
: GradNodeBase(in_num, out_num), val_(val) {}
GradTestNode() : GradNodeBase() { val_ = 1.0; }
std::string name() override { return "GradTestNode"; }
paddle::small_vector<std::vector<paddle::Tensor>, egr::kSlotSmallVectorSize>
operator()(paddle::small_vector<std::vector<paddle::Tensor>,
egr::kSlotSmallVectorSize>& grads, // NOLINT
bool create_graph = false,
bool is_new_grad = false) override {
val_ = std::dynamic_pointer_cast<phi::DenseTensor>(grads[0][0].impl())
->data<float>()[0];
phi::DenseTensorMeta meta =
phi::DenseTensorMeta(phi::DataType::FLOAT32, common::make_ddim({1, 1}));
std::shared_ptr<phi::DenseTensor> dt = std::make_shared<phi::DenseTensor>(
std::make_unique<paddle::experimental::DefaultAllocator>(
phi::CPUPlace())
.get(),
meta);
auto* dt_ptr = dt->mutable_data<float>(phi::CPUPlace());
dt_ptr[0] = 6.0f;
paddle::Tensor et1(dt);
paddle::small_vector<std::vector<paddle::Tensor>, egr::kSlotSmallVectorSize>
res = {{et1}};
return res;
}
void ClearTensorWrappers() override { VLOG(6) << "Do nothing here now"; }
std::shared_ptr<GradNodeBase> Copy() const override {
{
auto copied_node = std::shared_ptr<GradTestNode>(new GradTestNode(*this));
return copied_node;
}
}
float val_;
};
} // namespace eager_test
@@ -0,0 +1,206 @@
// 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.
#include "paddle/fluid/eager/grad_tensor_holder.h"
#include <sstream>
#include "gtest/gtest.h"
#include "paddle/fluid/eager/eager_tensor.h"
#include "paddle/fluid/eager/grad_node_info.h"
#include "paddle/fluid/eager/utils.h"
#include "paddle/phi/api/lib/utils/allocator.h"
#include "paddle/phi/core/kernel_registry.h"
#include "paddle/phi/core/selected_rows.h"
PD_DECLARE_KERNEL(full_like, CPU, ALL_LAYOUT);
PD_DECLARE_KERNEL(add, CPU, ALL_LAYOUT);
// TODO(jiabin): remove nolint here!!!
using namespace egr; // NOLINT
TEST(GradTensorHolder, Constructor) {
std::vector<GradSlotMeta> slot_meta(1);
GradTensorHolder grad_tensor_holder = GradTensorHolder({slot_meta});
GradTensorHolder grad_tensor_holder2 = GradTensorHolder(grad_tensor_holder);
// Construct Eager Tensor
phi::DenseTensorMeta meta =
phi::DenseTensorMeta(phi::DataType::FLOAT32, common::make_ddim({2, 2}));
std::shared_ptr<phi::DenseTensor> dt = std::make_shared<phi::DenseTensor>(
std::make_unique<paddle::experimental::DefaultAllocator>(phi::CPUPlace())
.get(),
meta);
paddle::Tensor et = paddle::Tensor(dt);
paddle::small_vector<std::vector<paddle::Tensor>, kSlotSmallVectorSize>
inputs;
inputs.push_back({et});
grad_tensor_holder2.SetBuffers(std::move(inputs));
}
TEST(GradTensorHolder, Interfaces) {
// Construct Eager Tensor
phi::DenseTensorMeta meta =
phi::DenseTensorMeta(phi::DataType::FLOAT32, common::make_ddim({1, 1}));
std::shared_ptr<phi::DenseTensor> dt0 = std::make_shared<phi::DenseTensor>(
std::make_unique<paddle::experimental::DefaultAllocator>(phi::CPUPlace())
.get(),
meta);
dt0->mutable_data<float>(phi::CPUPlace())[0] = 10.0;
paddle::Tensor et0 = paddle::Tensor(dt0);
std::shared_ptr<phi::DenseTensor> dt1 = std::make_shared<phi::DenseTensor>(
std::make_unique<paddle::experimental::DefaultAllocator>(phi::CPUPlace())
.get(),
meta);
dt1->mutable_data<float>(phi::CPUPlace())[0] = 20.0;
paddle::Tensor et1 = paddle::Tensor(dt1);
// Constructor empty GradTensorHolder
std::vector<GradSlotMeta> slot_meta(1);
GradTensorHolder grad_tensor_holder =
GradTensorHolder({slot_meta, slot_meta});
egr::EagerUtils::autograd_meta(&et0);
// add():
// fill one
grad_tensor_holder.CopyValueFromTensor(0, 0, et0, true);
// accumulation
grad_tensor_holder.add(1, 0, et0);
grad_tensor_holder.add(1, 0, et1);
// Buffers()
const auto& buffers = grad_tensor_holder.Buffers();
PADDLE_ENFORCE_EQ(static_cast<int>(buffers.size()),
2,
common::errors::InvalidArgument(
"The size of buffers should be 2, but received %d.",
static_cast<int>(buffers.size())));
PADDLE_ENFORCE_EQ(
static_cast<int>(buffers[0].size()),
1,
common::errors::InvalidArgument(
"The size of the first buffer should be 1, but received %d.",
static_cast<int>(buffers[0].size())));
PADDLE_ENFORCE_EQ(
static_cast<int>(buffers[1].size()),
1,
common::errors::InvalidArgument(
"The size of the second buffer should be 1, but received %d.",
static_cast<int>(buffers[1].size())));
// operator[]
const auto& holder_et0 = grad_tensor_holder[0][0];
const auto& holder_et1 = grad_tensor_holder[1][0];
auto* holder_et0_ptr =
std::dynamic_pointer_cast<phi::DenseTensor>(holder_et0.impl())
->data<float>();
auto* holder_et1_ptr =
std::dynamic_pointer_cast<phi::DenseTensor>(holder_et1.impl())
->data<float>();
PADDLE_ENFORCE_EQ(
holder_et0_ptr[0],
1.0f,
common::errors::InvalidArgument(
"The value of holder_et0_ptr[0] should be 1.0f, but received %f.",
holder_et0_ptr[0]));
PADDLE_ENFORCE_EQ(
holder_et1_ptr[0],
30.0f,
common::errors::InvalidArgument(
"The value of holder_et1_ptr[0] should be 30.0f, but received %f.",
holder_et1_ptr[0]));
}
TEST(GradTensorHolder, SelectedRowsMergeAdd) {
phi::CPUPlace cpu;
std::vector<int64_t> rows{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
int64_t table_size = 10;
int64_t embedding_width = 10;
auto sr1 = std::make_shared<phi::SelectedRows>(rows, table_size);
auto sr2 = std::make_shared<phi::SelectedRows>(rows, table_size);
// initialize a sparse table 1
sr1->mutable_value()->Resize(
common::make_ddim({table_size, embedding_width}));
auto* data_sr1 = sr1->mutable_value()->mutable_data<float>(cpu);
for (int64_t i = 0; i < table_size; ++i) {
for (int64_t j = 0; j < embedding_width; ++j) {
data_sr1[i * embedding_width + j] = static_cast<float>(i);
}
}
// initialize a sparse table 2
sr2->mutable_value()->Resize(
common::make_ddim({table_size, embedding_width}));
auto* data_sr2 = sr2->mutable_value()->mutable_data<float>(cpu);
for (int64_t i = 0; i < table_size; ++i) {
for (int64_t j = 0; j < embedding_width; ++j) {
data_sr2[i * embedding_width + j] = static_cast<float>(i);
}
}
// new 2 phi::Tensor
paddle::Tensor t1(sr1);
paddle::Tensor t2(sr2);
// Constructor empty GradTensorHolder
std::vector<GradSlotMeta> slot_meta(1);
GradTensorHolder grad_tensor_holder =
GradTensorHolder({slot_meta, slot_meta});
// accumulation
grad_tensor_holder.add(0, 0, t1);
grad_tensor_holder.add(0, 0, t2);
// Buffers()
const auto& buffers = grad_tensor_holder.Buffers();
PADDLE_ENFORCE_EQ(static_cast<int>(buffers.size()),
2,
common::errors::InvalidArgument(
"The size of buffers should be 2, but received %d.",
static_cast<int>(buffers.size())));
PADDLE_ENFORCE_EQ(
static_cast<int>(buffers[0].size()),
1,
common::errors::InvalidArgument(
"The size of the first buffer should be 1, but received %d.",
static_cast<int>(buffers[0].size())));
PADDLE_ENFORCE_EQ(
static_cast<int>(buffers[1].size()),
1,
common::errors::InvalidArgument(
"The size of the second buffer should be 1, but received %d.",
static_cast<int>(buffers[1].size())));
// operator[]
const auto& holder_et0 = grad_tensor_holder[0][0];
auto* tmp_buffer_tensor =
static_cast<phi::SelectedRows*>(holder_et0.impl().get());
auto* tmp_buffer_data_sr =
tmp_buffer_tensor->mutable_value()->mutable_data<float>(cpu);
// verify the MergeAdd result (accumulation result)
for (int64_t i = 0; i < table_size; ++i) {
for (int64_t j = 0; j < embedding_width; ++j) {
EXPECT_EQ(tmp_buffer_data_sr[i * embedding_width + j],
(static_cast<float>(i) + static_cast<float>(i)));
}
}
}
@@ -0,0 +1,108 @@
// 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.
#include "paddle/fluid/eager/tensor_wrapper.h"
#include "glog/logging.h"
#include "gtest/gtest.h"
#include "paddle/fluid/eager/utils.h"
#include "test/cpp/eager/data_structure_tests/grad_node_test.h"
TEST(TensorWrapper, Basic) {
VLOG(6) << "Test Full reserved";
paddle::Tensor et1;
phi::DenseTensorMeta meta =
phi::DenseTensorMeta(phi::DataType::FLOAT32, common::make_ddim({1, 2}));
std::shared_ptr<phi::DenseTensor> dt = std::make_shared<phi::DenseTensor>(
std::make_unique<paddle::experimental::DefaultAllocator>(phi::CPUPlace())
.get(),
meta);
auto* dt_ptr = dt->mutable_data<float>(phi::CPUPlace());
dt_ptr[0] = 5.0f;
dt_ptr[1] = 10.0f;
et1.set_impl(dt);
// Create grad node;
auto grad_test_node0 = std::make_shared<eager_test::GradTestNode>(
/* val */ 5.0, /* in_num */ 2, /* out_num */ 2);
egr::Edge edge0(grad_test_node0, 1, 2);
auto auto_grad0 = std::make_shared<egr::AutogradMeta>(edge0);
et1.set_autograd_meta(auto_grad0);
et1.set_name("et1");
auto tw0 = egr::TensorWrapper(et1);
auto recover_et1 = tw0.recover();
if (VLOG_IS_ON(7)) {
PADDLE_ENFORCE_EQ(
recover_et1.name(),
std::string("et1@saved"),
common::errors::InvalidArgument(
"Recovered tensor name should be 'et1@saved', but received %s.",
recover_et1.name().c_str()));
}
PADDLE_ENFORCE_EQ(egr::EagerUtils::OutRankInfo(recover_et1).first,
egr::EagerUtils::OutRankInfo(et1).first,
common::errors::InvalidArgument(
"The OutRankInfo first element of the recovered tensor "
"does not match the original tensor."));
PADDLE_ENFORCE_EQ(egr::EagerUtils::OutRankInfo(recover_et1).second,
egr::EagerUtils::OutRankInfo(et1).second,
common::errors::InvalidArgument(
"The OutRankInfo second element of the recovered "
"tensor does not match the original tensor."));
VLOG(6) << "Test reconstruct";
paddle::Tensor et2;
phi::DenseTensorMeta meta2 =
phi::DenseTensorMeta(phi::DataType::FLOAT32, common::make_ddim({1, 2}));
std::shared_ptr<phi::DenseTensor> dt2 = std::make_shared<phi::DenseTensor>(
std::make_unique<paddle::experimental::DefaultAllocator>(phi::CPUPlace())
.get(),
meta2);
auto* dt_ptr2 = dt->mutable_data<float>(phi::CPUPlace());
dt_ptr2[0] = 6.0f;
dt_ptr2[1] = 11.0f;
et2.set_impl(dt2);
et2.set_name("et2");
auto grad_test_node1 =
std::make_shared<eager_test::GradTestNode>(/* val */ 5.0, 2, 2);
egr::Edge edge1(grad_test_node1, 1, 2);
auto auto_grad1 = std::make_shared<egr::AutogradMeta>(edge1);
et2.set_autograd_meta(auto_grad1);
auto tw1 = egr::TensorWrapper(et2, false);
auto recover_et2 = tw1.recover();
if (VLOG_IS_ON(7)) {
PADDLE_ENFORCE_EQ(
recover_et2.name(),
std::string("et2@Saved"),
common::errors::InvalidArgument(
"Recovered tensor name should be 'et2@Saved', but received %s.",
recover_et2.name().c_str()));
}
PADDLE_ENFORCE_EQ(egr::EagerUtils::OutRankInfo(recover_et2).first,
egr::EagerUtils::OutRankInfo(et2).first,
common::errors::InvalidArgument(
"The OutRankInfo first element of the recovered tensor "
"does not match the original tensor."));
PADDLE_ENFORCE_EQ(egr::EagerUtils::OutRankInfo(recover_et2).second,
egr::EagerUtils::OutRankInfo(et2).second,
common::errors::InvalidArgument(
"The OutRankInfo second element of the recovered "
"tensor does not match the original tensor."));
// Test Raw recover
paddle::Tensor et3;
auto tw2 = egr::TensorWrapper(et3);
PADDLE_ENFORCE_EQ(
tw2.recover().initialized(),
false,
common::errors::Fatal(
"Variable `tw2` should not be initialized after recover"));
}
@@ -0,0 +1,35 @@
if(NOT (NOT WITH_PYTHON AND ON_INFER))
if(WITH_CINN)
set(eager_deps ${eager_deps} python)
endif()
cc_library(performance_benchmark_utils SRCS benchmark_utils.cc)
add_dependencies(
performance_benchmark_utils
${eager_deps}
${fluid_deps}
${generated_deps}
eager_scale
scale_node
generated_op
generated_static_op
dygraph_function
eager_prim_api)
paddle_test(test_egr_performance_benchmark_eager_cpu SRCS
benchmark_eager_cpu.cc DEPS performance_benchmark_utils)
paddle_test(test_egr_performance_benchmark_fluid_cpu SRCS
benchmark_fluid_cpu.cc DEPS performance_benchmark_utils)
if(WITH_GPU)
paddle_test(test_egr_performance_benchmark_eager_cuda SRCS
benchmark_eager_cuda.cc DEPS performance_benchmark_utils)
paddle_test(test_egr_performance_benchmark_fluid_cuda SRCS
benchmark_fluid_cuda.cc DEPS performance_benchmark_utils)
endif()
if(WITH_ONNXRUNTIME AND WIN32)
# Copy onnxruntime for some c++ test in Windows, since the test will
# be build only in CI, so suppose the generator in Windows is Ninja.
copy_onnx(performance_benchmark_utils)
endif()
endif()
@@ -0,0 +1,242 @@
// 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.
// Eager Dygraph
#include <paddle/fluid/framework/op_registry.h>
#include <chrono>
#include "gtest/gtest.h"
#include "paddle/common/flags.h"
#include "paddle/fluid/eager/api/all.h"
#include "paddle/fluid/eager/autograd_meta.h"
#include "paddle/fluid/eager/backward.h"
#include "paddle/fluid/imperative/tracer.h"
#include "test/cpp/eager/performance_tests/benchmark_utils.h"
#include "test/cpp/eager/test_utils.h"
#ifdef WITH_GPERFTOOLS
#include "gperftools/profiler.h"
#endif
#include "paddle/phi/core/kernel_registry.h"
using namespace egr; // NOLINT
using namespace egr_utils_api; // NOLINT
TEST(Benchmark, EagerScaleCPU) {
// Prepare Device Contexts
eager_test::InitEnv(phi::CPUPlace());
for (const std::string mode : {"Accuracy", "Performance"}) {
phi::DDim ddim = common::make_ddim({2, 4, 4, 4});
paddle::Tensor tensor =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
5.0,
true);
RetainGradForTensor(tensor);
if (mode == "Accuracy") {
benchmark_eager_scale(tensor, true /* accuracy_check*/);
} else if (mode == "Performance") {
auto t_start = std::chrono::high_resolution_clock::now();
#ifdef WITH_GPERFTOOLS
ProfilerStart("eager_scale_cpu.out");
#endif
benchmark_eager_scale(tensor);
#ifdef WITH_GPERFTOOLS
ProfilerStop();
#endif
auto t_end = std::chrono::high_resolution_clock::now();
double elapsed_time_ms =
std::chrono::duration<double, std::milli>(t_end - t_start).count();
std::cout << "Duration: " << elapsed_time_ms << " ms" << std::endl;
} else {
PADDLE_THROW(common::errors::Fatal("Unknown benchmark mode"));
}
}
}
TEST(Benchmark, EagerMatmulCPU) {
// Prepare Device Contexts
eager_test::InitEnv(phi::CPUPlace());
for (const std::string mode : {"Accuracy", "Performance"}) {
phi::DDim ddimX = common::make_ddim({2, 2});
paddle::Tensor X = eager_test::CreateTensorWithValue(ddimX,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
1.0,
true);
RetainGradForTensor(X);
phi::DDim ddimY = common::make_ddim({2, 2});
paddle::Tensor Y = eager_test::CreateTensorWithValue(ddimY,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
2.0,
true);
RetainGradForTensor(Y);
if (mode == "Accuracy") {
benchmark_eager_matmul(X, Y, true /* accuracy_check */);
} else if (mode == "Performance") {
auto t_start = std::chrono::high_resolution_clock::now();
#ifdef WITH_GPERFTOOLS
ProfilerStart("eager_matmul_cpu.out");
#endif
benchmark_eager_matmul(X, Y);
#ifdef WITH_GPERFTOOLS
ProfilerStop();
#endif
auto t_end = std::chrono::high_resolution_clock::now();
double elapsed_time_ms =
std::chrono::duration<double, std::milli>(t_end - t_start).count();
std::cout << "Duration: " << elapsed_time_ms << " ms" << std::endl;
} else {
PADDLE_THROW(common::errors::Fatal("Unknown benchmark mode"));
}
}
}
TEST(Benchmark, EagerIntermediateMatmulCPU) {
// Prepare Device Contexts
eager_test::InitEnv(phi::CPUPlace());
auto tracer = std::make_shared<paddle::imperative::Tracer>();
paddle::imperative::SetCurrentTracer(tracer);
for (const std::string mode : {"Accuracy", "Performance"}) {
phi::DDim ddimX = common::make_ddim({2, 2});
paddle::Tensor X = eager_test::CreateTensorWithValue(ddimX,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
1.0,
true);
RetainGradForTensor(X);
phi::DDim ddimY = common::make_ddim({2, 2});
paddle::Tensor Y = eager_test::CreateTensorWithValue(ddimY,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
2.0,
true);
RetainGradForTensor(Y);
if (mode == "Accuracy") {
benchmark_eager_intermediate_matmul(X, Y, true /* accuracy_check */);
} else if (mode == "Performance") {
auto t_start = std::chrono::high_resolution_clock::now();
#ifdef WITH_GPERFTOOLS
ProfilerStart("eager_intermediate_matmul_cpu.out");
#endif
benchmark_eager_intermediate_matmul(X, Y);
#ifdef WITH_GPERFTOOLS
ProfilerStop();
#endif
auto t_end = std::chrono::high_resolution_clock::now();
double elapsed_time_ms =
std::chrono::duration<double, std::milli>(t_end - t_start).count();
std::cout << "Duration: " << elapsed_time_ms << " ms" << std::endl;
} else {
PADDLE_THROW(common::errors::Fatal("Unknown benchmark mode"));
}
}
}
TEST(Benchmark, EagerIntermediateMLPCPU) {
// Prepare Device Contexts
eager_test::InitEnv(phi::CPUPlace());
auto tracer = std::make_shared<paddle::imperative::Tracer>();
paddle::imperative::SetCurrentTracer(tracer);
for (const std::string mode : {"Accuracy", "Performance"}) {
phi::DDim ddimX = common::make_ddim({MLP_M, MLP_N});
paddle::Tensor X = eager_test::CreateTensorWithValue(ddimX,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
MLP_X_VAL,
true);
RetainGradForTensor(X);
std::vector<paddle::Tensor> Ws;
std::vector<paddle::Tensor> Bs;
for (size_t i = 0; i < MLP_NUM_LINEAR; i++) {
phi::DDim ddimW = common::make_ddim({MLP_N, MLP_K});
paddle::Tensor W =
eager_test::CreateTensorWithValue(ddimW,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
MLP_W_VAL,
true);
RetainGradForTensor(W);
phi::DDim ddimB = common::make_ddim({MLP_K});
paddle::Tensor B =
eager_test::CreateTensorWithValue(ddimB,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
MLP_B_VAL,
true);
RetainGradForTensor(B);
Ws.emplace_back(std::move(W));
Bs.emplace_back(std::move(B));
}
if (mode == "Accuracy") {
benchmark_eager_intermediate_mlp(X, Ws, Bs, true /* accuracy_check */);
} else if (mode == "Performance") {
auto t_start = std::chrono::high_resolution_clock::now();
#ifdef WITH_GPERFTOOLS
ProfilerStart("eager_intermediate_mlp_cpu.out");
#endif
benchmark_eager_intermediate_mlp(X, Ws, Bs);
#ifdef WITH_GPERFTOOLS
ProfilerStop();
#endif
auto t_end = std::chrono::high_resolution_clock::now();
double elapsed_time_ms =
std::chrono::duration<double, std::milli>(t_end - t_start).count();
std::cout << "Duration: " << elapsed_time_ms << " ms" << std::endl;
} else {
PADDLE_THROW(common::errors::Fatal("Unknown benchmark mode"));
}
}
}
@@ -0,0 +1,257 @@
// 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.
// Eager Dygraph
#include <paddle/fluid/framework/op_registry.h>
#include <chrono>
#include "gtest/gtest.h"
#include "paddle/common/flags.h"
#include "paddle/fluid/eager/api/all.h"
#include "paddle/fluid/eager/autograd_meta.h"
#include "paddle/fluid/eager/backward.h"
#include "paddle/fluid/imperative/tracer.h"
#include "test/cpp/eager/performance_tests/benchmark_utils.h"
#include "test/cpp/eager/test_utils.h"
#ifdef WITH_GPERFTOOLS
#include "gperftools/profiler.h"
#endif
#include "paddle/phi/core/kernel_registry.h"
using namespace egr; // NOLINT
using namespace egr_utils_api; // NOLINT
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
TEST(Benchmark, EagerScaleCUDA) {
eager_test::InitEnv(phi::GPUPlace());
for (const std::string mode : {"Accuracy", "WarmUp", "Performance"}) {
phi::DDim ddim = common::make_ddim({2, 4, 4, 4});
paddle::Tensor tensor =
eager_test::CreateTensorWithValue(ddim,
phi::GPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
5.0 /*value*/,
true /*is_leaf*/);
RetainGradForTensor(tensor);
if (mode == "Accuracy") {
benchmark_eager_scale(tensor, true /* accuracy_check */);
} else if (mode == "WarmUp") {
benchmark_eager_scale(tensor);
} else if (mode == "Performance") {
auto t_start = std::chrono::high_resolution_clock::now();
#ifdef WITH_GPERFTOOLS
ProfilerStart("eager_scale_cuda.out");
#endif
benchmark_eager_scale(tensor);
#ifdef WITH_GPERFTOOLS
ProfilerStop();
#endif
auto t_end = std::chrono::high_resolution_clock::now();
double elapsed_time_ms =
std::chrono::duration<double, std::milli>(t_end - t_start).count();
std::cout << "Duration: " << elapsed_time_ms << " ms" << std::endl;
} else {
PADDLE_THROW(common::errors::Fatal("Unknown benchmark mode"));
}
}
}
TEST(Benchmark, EagerMatmulCUDA) {
phi::GPUPlace place;
eager_test::InitEnv(place);
for (const std::string mode : {"Accuracy", "WarmUp", "Performance"}) {
phi::DDim ddimX = common::make_ddim({2, 2});
paddle::Tensor X = eager_test::CreateTensorWithValue(ddimX,
phi::GPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
1.0,
true);
RetainGradForTensor(X);
phi::DDim ddimY = common::make_ddim({2, 2});
paddle::Tensor Y = eager_test::CreateTensorWithValue(ddimY,
phi::GPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
2.0,
true);
RetainGradForTensor(Y);
if (mode == "Accuracy") {
benchmark_eager_matmul(X, Y, true /* accuracy_check */);
} else if (mode == "WarmUp") {
benchmark_eager_matmul(X, Y);
} else if (mode == "Performance") {
auto t_start = std::chrono::high_resolution_clock::now();
#ifdef WITH_GPERFTOOLS
ProfilerStart("eager_matmul_cuda.out");
#endif
benchmark_eager_matmul(X, Y);
#ifdef WITH_GPERFTOOLS
ProfilerStop();
#endif
auto t_end = std::chrono::high_resolution_clock::now();
double elapsed_time_ms =
std::chrono::duration<double, std::milli>(t_end - t_start).count();
std::cout << "Duration: " << elapsed_time_ms << " ms" << std::endl;
} else {
PADDLE_THROW(common::errors::Fatal("Unknown benchmark mode"));
}
}
}
TEST(Benchmark, EagerIntermediateMatmulCUDA) {
phi::GPUPlace place;
eager_test::InitEnv(place);
auto tracer = std::make_shared<paddle::imperative::Tracer>();
tracer->SetExpectedPlace(place);
paddle::imperative::SetCurrentTracer(tracer);
for (const std::string mode : {"Accuracy", "WarmUp", "Performance"}) {
phi::DDim ddimX = common::make_ddim({2, 2});
paddle::Tensor X = eager_test::CreateTensorWithValue(ddimX,
phi::GPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
1.0,
true);
RetainGradForTensor(X);
phi::DDim ddimY = common::make_ddim({2, 2});
paddle::Tensor Y = eager_test::CreateTensorWithValue(ddimY,
phi::GPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
2.0,
true);
RetainGradForTensor(Y);
if (mode == "Accuracy") {
benchmark_eager_intermediate_matmul(X, Y, true /* accuracy_check */);
} else if (mode == "WarmUp") {
benchmark_eager_intermediate_matmul(X, Y);
} else if (mode == "Performance") {
auto t_start = std::chrono::high_resolution_clock::now();
#ifdef WITH_GPERFTOOLS
ProfilerStart("eager_intermediate_matmul_cuda.out");
#endif
benchmark_eager_intermediate_matmul(X, Y);
#ifdef WITH_GPERFTOOLS
ProfilerStop();
#endif
auto t_end = std::chrono::high_resolution_clock::now();
double elapsed_time_ms =
std::chrono::duration<double, std::milli>(t_end - t_start).count();
std::cout << "Duration: " << elapsed_time_ms << " ms" << std::endl;
} else {
PADDLE_THROW(common::errors::Fatal("Unknown benchmark mode"));
}
}
}
TEST(Benchmark, EagerIntermediateMLPCUDA) {
phi::GPUPlace place;
eager_test::InitEnv(place);
auto tracer = std::make_shared<paddle::imperative::Tracer>();
tracer->SetExpectedPlace(place);
paddle::imperative::SetCurrentTracer(tracer);
for (const std::string mode : {"Accuracy", "WarmUp", "Performance"}) {
phi::DDim ddimX = common::make_ddim({MLP_M, MLP_N});
paddle::Tensor X = eager_test::CreateTensorWithValue(ddimX,
phi::GPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
MLP_X_VAL,
true);
RetainGradForTensor(X);
std::vector<paddle::Tensor> Ws;
std::vector<paddle::Tensor> Bs;
for (size_t i = 0; i < MLP_NUM_LINEAR; i++) {
phi::DDim ddimW = common::make_ddim({MLP_N, MLP_K});
paddle::Tensor W =
eager_test::CreateTensorWithValue(ddimW,
phi::GPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
MLP_W_VAL,
true);
RetainGradForTensor(W);
phi::DDim ddimB = common::make_ddim({MLP_K});
paddle::Tensor B =
eager_test::CreateTensorWithValue(ddimB,
phi::GPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
MLP_B_VAL,
true);
RetainGradForTensor(B);
Ws.emplace_back(std::move(W));
Bs.emplace_back(std::move(B));
}
if (mode == "Accuracy") {
benchmark_eager_intermediate_mlp(X, Ws, Bs, true /* accuracy_check */);
} else if (mode == "WarmUp") {
benchmark_eager_intermediate_mlp(X, Ws, Bs);
} else if (mode == "Performance") {
auto t_start = std::chrono::high_resolution_clock::now();
#ifdef WITH_GPERFTOOLS
ProfilerStart("eager_intermediate_mlp_cuda.out");
#endif
benchmark_eager_intermediate_mlp(X, Ws, Bs);
#ifdef WITH_GPERFTOOLS
ProfilerStop();
#endif
auto t_end = std::chrono::high_resolution_clock::now();
double elapsed_time_ms =
std::chrono::duration<double, std::milli>(t_end - t_start).count();
std::cout << "Duration: " << elapsed_time_ms << " ms" << std::endl;
} else {
PADDLE_THROW(common::errors::Fatal("Unknown benchmark mode"));
}
}
}
#endif // PADDLE_WITH_CUDA || PADDLE_WITH_HIP
@@ -0,0 +1,230 @@
// 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.
#include <paddle/fluid/framework/op_registry.h>
#include <chrono>
#include <iostream>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include "glog/logging.h"
#include "gtest/gtest.h"
#include "paddle/fluid/imperative/basic_engine.h"
#include "paddle/fluid/imperative/tracer.h"
#include "paddle/phi/core/memory/memcpy.h"
#include "test/cpp/eager/performance_tests/benchmark_utils.h"
#include "test/cpp/eager/test_utils.h"
#ifdef WITH_GPERFTOOLS
#include "gperftools/profiler.h"
#endif
#include "paddle/phi/core/kernel_registry.h"
namespace paddle {
namespace imperative {
TEST(Benchmark, FluidScaleCPU) {
// Prepare Device Contexts
phi::CPUPlace place;
eager_test::InitEnv(place);
for (const std::string mode : {"Accuracy", "Performance"}) {
std::shared_ptr<imperative::VarBase> X(new imperative::VarBase(true, "X"));
X->SetOverriddenStopGradient(false);
std::vector<float> src_data(128, 5.0);
std::vector<int64_t> dims = {2, 4, 4, 4};
auto* x_tensor = X->MutableVar()->GetMutable<phi::DenseTensor>();
x_tensor->Resize(common::make_ddim(dims));
auto* mutable_x = x_tensor->mutable_data<float>(place);
paddle::memory::Copy(place,
mutable_x,
place,
src_data.data(),
sizeof(float) * src_data.size());
if (mode == "Accuracy") {
benchmark_fluid_scale(X, phi::Place(place), true /* accuracy_check */);
} else if (mode == "Performance") {
auto t_start = std::chrono::high_resolution_clock::now();
#ifdef WITH_GPERFTOOLS
ProfilerStart("fluid_scale_cpu.out");
#endif
benchmark_fluid_scale(X, phi::Place(place));
#ifdef WITH_GPERFTOOLS
ProfilerStop();
#endif
auto t_end = std::chrono::high_resolution_clock::now();
double elapsed_time_ms =
std::chrono::duration<double, std::milli>(t_end - t_start).count();
std::cout << "Duration: " << elapsed_time_ms << " ms" << std::endl;
} else {
PADDLE_THROW(common::errors::Fatal("Unknown benchmark mode"));
}
}
}
TEST(Benchmark, FluidMatmulCPU) {
// Prepare Device Contexts
phi::CPUPlace place;
eager_test::InitEnv(place);
for (const std::string mode : {"Accuracy", "Performance"}) {
std::shared_ptr<imperative::VarBase> X(new imperative::VarBase(true, "X"));
X->SetOverriddenStopGradient(false);
std::shared_ptr<imperative::VarBase> Y(new imperative::VarBase(true, "Y"));
Y->SetOverriddenStopGradient(false);
std::vector<float> x_src_data(4, 1.0);
std::vector<float> y_src_data(4, 2.0);
std::vector<int64_t> dims = {2, 2};
auto* x_tensor = X->MutableVar()->GetMutable<phi::DenseTensor>();
x_tensor->Resize(common::make_ddim(dims));
auto* mutable_x = x_tensor->mutable_data<float>(place);
paddle::memory::Copy(place,
mutable_x,
place,
x_src_data.data(),
sizeof(float) * x_src_data.size());
auto* y_tensor = Y->MutableVar()->GetMutable<phi::DenseTensor>();
y_tensor->Resize(common::make_ddim(dims));
auto* mutable_y = y_tensor->mutable_data<float>(place);
paddle::memory::Copy(place,
mutable_y,
place,
y_src_data.data(),
sizeof(float) * y_src_data.size());
if (mode == "Accuracy") {
benchmark_fluid_matmul(
X, Y, phi::Place(place), true /* accuracy_check */);
} else if (mode == "Performance") {
auto t_start = std::chrono::high_resolution_clock::now();
#ifdef WITH_GPERFTOOLS
ProfilerStart("fluid_matmul_cpu.out");
#endif
benchmark_fluid_matmul(X, Y, phi::Place(place));
#ifdef WITH_GPERFTOOLS
ProfilerStop();
#endif
auto t_end = std::chrono::high_resolution_clock::now();
double elapsed_time_ms =
std::chrono::duration<double, std::milli>(t_end - t_start).count();
std::cout << "Duration: " << elapsed_time_ms << " ms" << std::endl;
} else {
PADDLE_THROW(common::errors::Fatal("Unknown benchmark mode"));
}
}
}
TEST(Benchmark, FluidMLPCPU) {
// Prepare Device Contexts
phi::CPUPlace place;
eager_test::InitEnv(place);
for (const std::string mode : {"Accuracy", "Performance"}) {
std::vector<float> x_src_data(MLP_M * MLP_N, MLP_X_VAL);
std::vector<float> w_src_data(MLP_N * MLP_K, MLP_W_VAL);
std::vector<float> b_src_data(MLP_K, MLP_B_VAL);
std::vector<int64_t> x_dims = {MLP_M, MLP_N};
std::vector<int64_t> w_dims = {MLP_N, MLP_K};
std::vector<int64_t> b_dims = {MLP_K};
std::shared_ptr<imperative::VarBase> X(new imperative::VarBase(true, "X"));
X->SetOverriddenStopGradient(false);
auto* x_tensor = X->MutableVar()->GetMutable<phi::DenseTensor>();
x_tensor->Resize(common::make_ddim(x_dims));
auto* mutable_x = x_tensor->mutable_data<float>(place);
paddle::memory::Copy(place,
mutable_x,
place,
x_src_data.data(),
sizeof(float) * x_src_data.size());
std::vector<std::shared_ptr<imperative::VarBase>> Ws;
std::vector<std::shared_ptr<imperative::VarBase>> Bs;
for (size_t i = 0; i < MLP_NUM_LINEAR; i++) {
std::shared_ptr<imperative::VarBase> W(
new imperative::VarBase(true, "W"));
W->SetOverriddenStopGradient(false);
std::shared_ptr<imperative::VarBase> B(
new imperative::VarBase(true, "B"));
B->SetOverriddenStopGradient(false);
auto* w_tensor = W->MutableVar()->GetMutable<phi::DenseTensor>();
w_tensor->Resize(common::make_ddim(w_dims));
auto* mutable_w = w_tensor->mutable_data<float>(place);
paddle::memory::Copy(place,
mutable_w,
place,
w_src_data.data(),
sizeof(float) * w_src_data.size());
auto* b_tensor = B->MutableVar()->GetMutable<phi::DenseTensor>();
b_tensor->Resize(common::make_ddim(b_dims));
auto* mutable_b = b_tensor->mutable_data<float>(place);
paddle::memory::Copy(place,
mutable_b,
place,
b_src_data.data(),
sizeof(float) * b_src_data.size());
Ws.emplace_back(std::move(W));
Bs.emplace_back(std::move(B));
}
if (mode == "Accuracy") {
benchmark_fluid_mlp(
X, Ws, Bs, phi::Place(place), true /* accuracy_check */);
} else if (mode == "Performance") {
auto t_start = std::chrono::high_resolution_clock::now();
#ifdef WITH_GPERFTOOLS
ProfilerStart("fluid_mlp_cpu.out");
#endif
benchmark_fluid_mlp(X, Ws, Bs, phi::Place(place));
#ifdef WITH_GPERFTOOLS
ProfilerStop();
#endif
auto t_end = std::chrono::high_resolution_clock::now();
double elapsed_time_ms =
std::chrono::duration<double, std::milli>(t_end - t_start).count();
std::cout << "Duration: " << elapsed_time_ms << " ms" << std::endl;
} else {
PADDLE_THROW(common::errors::Fatal("Unknown benchmark mode"));
}
}
}
} // namespace imperative
} // namespace paddle
@@ -0,0 +1,258 @@
// 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.
#include <paddle/fluid/framework/op_registry.h>
#include <chrono>
#include <iostream>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include "glog/logging.h"
#include "gtest/gtest.h"
#include "paddle/fluid/imperative/basic_engine.h"
#include "paddle/fluid/imperative/tracer.h"
#include "paddle/phi/core/memory/memcpy.h"
#include "test/cpp/eager/performance_tests/benchmark_utils.h"
#include "test/cpp/eager/test_utils.h"
#ifdef WITH_GPERFTOOLS
#include "gperftools/profiler.h"
#endif
#include "paddle/phi/core/kernel_registry.h"
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
namespace paddle {
namespace imperative {
TEST(Benchmark, FluidScaleCUDA) {
// Prepare Device Contexts
phi::GPUPlace place;
eager_test::InitEnv(place);
for (const std::string mode : {"Accuracy", "WarmUp", "Performance"}) {
std::shared_ptr<imperative::VarBase> X(new imperative::VarBase(true, "X"));
X->SetOverriddenStopGradient(false);
std::vector<float> src_data(128, 5.0);
std::vector<int64_t> dims = {2, 4, 4, 4};
auto* x_tensor = X->MutableVar()->GetMutable<phi::DenseTensor>();
x_tensor->Resize(common::make_ddim(dims));
auto* mutable_x = x_tensor->mutable_data<float>(place);
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
auto* dev_ctx = dynamic_cast<phi::GPUContext*>(pool.Get(place));
auto stream = dev_ctx->stream();
paddle::memory::Copy(place,
mutable_x,
phi::CPUPlace(),
src_data.data(),
sizeof(float) * src_data.size(),
stream);
if (mode == "Accuracy") {
benchmark_fluid_scale(X, phi::Place(place), true /* accuracy_check */);
} else if (mode == "WarmUp") {
benchmark_fluid_scale(X, phi::Place(place));
} else if (mode == "Performance") {
auto t_start = std::chrono::high_resolution_clock::now();
#ifdef WITH_GPERFTOOLS
ProfilerStart("fluid_scale_cuda.out");
#endif
benchmark_fluid_scale(X, phi::Place(place));
#ifdef WITH_GPERFTOOLS
ProfilerStop();
#endif
auto t_end = std::chrono::high_resolution_clock::now();
double elapsed_time_ms =
std::chrono::duration<double, std::milli>(t_end - t_start).count();
std::cout << "Duration: " << elapsed_time_ms << " ms" << std::endl;
} else {
PADDLE_THROW(common::errors::Fatal("Unknown benchmark mode"));
}
}
}
TEST(Benchmark, FluidMatmulCUDA) {
// Prepare Device Contexts
phi::GPUPlace place;
eager_test::InitEnv(place);
for (const std::string mode : {"Accuracy", "WarmUp", "Performance"}) {
std::shared_ptr<imperative::VarBase> X(new imperative::VarBase(true, "X"));
X->SetOverriddenStopGradient(false);
std::shared_ptr<imperative::VarBase> Y(new imperative::VarBase(true, "Y"));
Y->SetOverriddenStopGradient(false);
std::vector<float> x_src_data(4, 1.0);
std::vector<float> y_src_data(4, 2.0);
std::vector<int64_t> dims = {2, 2};
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
auto* dev_ctx = dynamic_cast<phi::GPUContext*>(pool.Get(place));
auto stream = dev_ctx->stream();
auto* x_tensor = X->MutableVar()->GetMutable<phi::DenseTensor>();
x_tensor->Resize(common::make_ddim(dims));
auto* mutable_x = x_tensor->mutable_data<float>(place);
paddle::memory::Copy(place,
mutable_x,
phi::CPUPlace(),
x_src_data.data(),
sizeof(float) * x_src_data.size(),
stream);
auto* y_tensor = Y->MutableVar()->GetMutable<phi::DenseTensor>();
y_tensor->Resize(common::make_ddim(dims));
auto* mutable_y = y_tensor->mutable_data<float>(place);
paddle::memory::Copy(place,
mutable_y,
phi::CPUPlace(),
y_src_data.data(),
sizeof(float) * y_src_data.size(),
stream);
if (mode == "Accuracy") {
benchmark_fluid_matmul(
X, Y, phi::Place(place), true /* accuracy_check */);
} else if (mode == "WarmUp") {
benchmark_fluid_matmul(X, Y, phi::Place(place));
} else if (mode == "Performance") {
auto t_start = std::chrono::high_resolution_clock::now();
#ifdef WITH_GPERFTOOLS
ProfilerStart("fluid_matmul_cuda.out");
#endif
benchmark_fluid_matmul(X, Y, phi::Place(place));
#ifdef WITH_GPERFTOOLS
ProfilerStop();
#endif
auto t_end = std::chrono::high_resolution_clock::now();
double elapsed_time_ms =
std::chrono::duration<double, std::milli>(t_end - t_start).count();
std::cout << "Duration: " << elapsed_time_ms << " ms" << std::endl;
} else {
PADDLE_THROW(common::errors::Fatal("Unknown benchmark mode"));
}
}
}
TEST(Benchmark, FluidMLPCUDA) {
// Prepare Device Contexts
phi::GPUPlace place;
eager_test::InitEnv(place);
for (const std::string mode : {"Accuracy", "WarmUp", "Performance"}) {
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
auto* dev_ctx = dynamic_cast<phi::GPUContext*>(pool.Get(place));
auto stream = dev_ctx->stream();
std::vector<float> x_src_data(MLP_M * MLP_N, MLP_X_VAL);
std::vector<float> w_src_data(MLP_N * MLP_K, MLP_W_VAL);
std::vector<float> b_src_data(MLP_K, MLP_B_VAL);
std::vector<int64_t> x_dims = {MLP_M, MLP_N};
std::vector<int64_t> w_dims = {MLP_N, MLP_K};
std::vector<int64_t> b_dims = {MLP_K};
std::shared_ptr<imperative::VarBase> X(new imperative::VarBase(true, "X"));
X->SetOverriddenStopGradient(false);
auto* x_tensor = X->MutableVar()->GetMutable<phi::DenseTensor>();
x_tensor->Resize(common::make_ddim(x_dims));
auto* mutable_x = x_tensor->mutable_data<float>(place);
paddle::memory::Copy(place,
mutable_x,
phi::CPUPlace(),
x_src_data.data(),
sizeof(float) * x_src_data.size(),
stream);
std::vector<std::shared_ptr<imperative::VarBase>> Ws;
std::vector<std::shared_ptr<imperative::VarBase>> Bs;
for (size_t i = 0; i < MLP_NUM_LINEAR; i++) {
std::shared_ptr<imperative::VarBase> W(
new imperative::VarBase(true, "W"));
W->SetOverriddenStopGradient(false);
std::shared_ptr<imperative::VarBase> B(
new imperative::VarBase(true, "B"));
B->SetOverriddenStopGradient(false);
auto* w_tensor = W->MutableVar()->GetMutable<phi::DenseTensor>();
w_tensor->Resize(common::make_ddim(w_dims));
auto* mutable_w = w_tensor->mutable_data<float>(place);
paddle::memory::Copy(place,
mutable_w,
phi::CPUPlace(),
w_src_data.data(),
sizeof(float) * w_src_data.size(),
stream);
auto* b_tensor = B->MutableVar()->GetMutable<phi::DenseTensor>();
b_tensor->Resize(common::make_ddim(b_dims));
auto* mutable_b = b_tensor->mutable_data<float>(place);
paddle::memory::Copy(place,
mutable_b,
phi::CPUPlace(),
b_src_data.data(),
sizeof(float) * b_src_data.size(),
stream);
Ws.emplace_back(std::move(W));
Bs.emplace_back(std::move(B));
}
if (mode == "Accuracy") {
benchmark_fluid_mlp(
X, Ws, Bs, phi::Place(place), true /* accuracy_check */);
} else if (mode == "WarmUp") {
benchmark_fluid_mlp(X, Ws, Bs, phi::Place(place));
} else if (mode == "Performance") {
auto t_start = std::chrono::high_resolution_clock::now();
#ifdef WITH_GPERFTOOLS
ProfilerStart("fluid_mlp_cuda.out");
#endif
benchmark_fluid_mlp(X, Ws, Bs, phi::Place(place));
#ifdef WITH_GPERFTOOLS
ProfilerStop();
#endif
auto t_end = std::chrono::high_resolution_clock::now();
double elapsed_time_ms =
std::chrono::duration<double, std::milli>(t_end - t_start).count();
std::cout << "Duration: " << elapsed_time_ms << " ms" << std::endl;
} else {
PADDLE_THROW(common::errors::Fatal("Unknown benchmark mode"));
}
}
}
} // namespace imperative
} // namespace paddle
#endif // PADDLE_WITH_CUDA || PADDLE_WITH_HIP
@@ -0,0 +1,348 @@
// 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.
#include "test/cpp/eager/performance_tests/benchmark_utils.h"
#include <iostream>
#include <memory>
#include <set>
#include <string>
#include <vector>
// Eager
#include "paddle/fluid/eager/api/all.h"
#include "paddle/fluid/eager/autograd_meta.h"
#include "paddle/fluid/eager/backward.h"
#include "paddle/fluid/eager/utils.h"
#include "test/cpp/eager/test_utils.h"
// Eager Generated
#include "paddle/fluid/eager/api/generated/eager_generated/forwards/dygraph_functions.h"
#include "paddle/fluid/eager/api/generated/fluid_generated/dygraph_forward_api.h"
// Fluid
#include "paddle/fluid/framework/op_registry.h"
#include "paddle/fluid/imperative/basic_engine.h"
#include "paddle/fluid/imperative/tracer.h"
#include "paddle/phi/core/memory/memcpy.h"
static size_t max_num_benchmark_runs = 4000;
namespace egr {
/* --------------------- */
/* ---- Eager Scale ---- */
/* --------------------- */
void benchmark_eager_scale(const paddle::Tensor& tensor, bool accuracy_check) {
paddle::Tensor input_tensor = tensor;
float scale = 2.0;
float bias = 3.0;
size_t max_num_runs = accuracy_check ? 10 : max_num_benchmark_runs;
for (size_t i = 0; i < max_num_runs; i++) {
input_tensor = egr::scale(input_tensor,
scale,
bias,
true /*bias_after_scale*/,
true /*trace_backward*/);
}
std::vector<paddle::Tensor> target_tensors = {input_tensor};
Backward(target_tensors, {});
if (accuracy_check) {
// Examine Forward Grad (w.r.t max_num_runs = 10)
eager_test::CompareTensorWithValue<float>(input_tensor, 8189.0);
// Examine Backward Grad (w.r.t max_num_runs = 10)
eager_test::CompareGradTensorWithValue<float>(tensor, 1024.0);
}
}
void benchmark_eager_matmul(const paddle::Tensor& X,
const paddle::Tensor& Y,
bool accuracy_check) {
paddle::Tensor input_tensor0 = X;
size_t max_num_runs = accuracy_check ? 2 : max_num_benchmark_runs;
for (size_t i = 0; i < max_num_runs; i++) {
input_tensor0 = matmul_ad_func(input_tensor0, Y, false, false);
}
std::vector<paddle::Tensor> target_tensors = {input_tensor0};
Backward(target_tensors, {});
if (accuracy_check) {
// Examine Forward Grad (w.r.t max_num_runs = 2)
eager_test::CompareTensorWithValue<float>(input_tensor0, 16);
// Examine Backward Grad (w.r.t max_num_runs = 2)
eager_test::CompareGradTensorWithValue<float>(X, 16);
eager_test::CompareGradTensorWithValue<float>(Y, 16);
}
}
/* ----------------------------------- */
/* ---- Eager Intermediate Matmul ---- */
/* ----------------------------------- */
void benchmark_eager_intermediate_matmul(const paddle::Tensor& X,
const paddle::Tensor& Y,
bool accuracy_check) {
paddle::Tensor input_tensor0 = X;
size_t max_num_runs = accuracy_check ? 2 : max_num_benchmark_runs;
for (size_t i = 0; i < max_num_runs; i++) {
input_tensor0 = matmul_v2_dygraph_function(
input_tensor0, Y, {{"trans_x", false}, {"trans_y", false}});
}
std::vector<paddle::Tensor> target_tensors = {input_tensor0};
Backward(target_tensors, {});
if (accuracy_check) {
// Examine Forward Grad (w.r.t max_num_runs = 2)
eager_test::CompareTensorWithValue<float>(input_tensor0, 16);
// Examine Backward Grad (w.r.t max_num_runs = 2)
eager_test::CompareGradTensorWithValue<float>(X, 16);
eager_test::CompareGradTensorWithValue<float>(Y, 16);
}
}
/* -------------------------------- */
/* ---- Eager Intermediate MLP ---- */
/* -------------------------------- */
void benchmark_eager_intermediate_mlp(const paddle::Tensor& X,
const std::vector<paddle::Tensor>& Ws,
const std::vector<paddle::Tensor>& Bs,
bool accuracy_check) {
paddle::Tensor input0 = X;
for (size_t i = 0; i < MLP_NUM_LINEAR; i++) {
paddle::Tensor Out = matmul_v2_dygraph_function(
input0, Ws[i], {{"trans_x", false}, {"trans_y", false}});
input0 = elementwise_add_dygraph_function(Out, Bs[i], {});
}
paddle::Tensor Out =
reduce_sum_dygraph_function(input0, {{"reduce_all", true}});
std::vector<paddle::Tensor> target_tensors = {Out};
Backward(target_tensors, {});
if (accuracy_check) {
std::unordered_map<std::string, float> result =
compute_mlp_expected_results();
// Examine Forward Grad (w.r.t max_num_runs = 2)
eager_test::CompareTensorWithValue<float>(Out, result["Out"]);
// Examine Backward Grad (w.r.t max_num_runs = 2)
eager_test::CompareGradTensorWithValue<float>(X, result["GradX"]);
eager_test::CompareGradTensorWithValue<float>(Ws[0], result["GradW"]);
}
}
} // namespace egr
namespace paddle {
namespace imperative {
static void FluidCheckTensorValue(const std::shared_ptr<imperative::VarBase>& X,
const phi::Place& place,
float value) {
auto* tensor = X->MutableVar()->GetMutable<phi::DenseTensor>();
float* t_ptr = tensor->mutable_data<float>(place);
std::vector<float> host_data(tensor->numel());
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
if (place == phi::GPUPlace()) {
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
auto* dev_ctx = dynamic_cast<phi::GPUContext*>(pool.Get(place));
auto stream = dev_ctx->stream();
paddle::memory::Copy(phi::CPUPlace(),
host_data.data(),
phi::GPUPlace(),
t_ptr,
sizeof(float) * tensor->numel(),
stream);
t_ptr = host_data.data();
}
#endif
VLOG(6) << "Tensor Value: " << t_ptr[0] << ", Expected Value: " << value;
PADDLE_ENFORCE(
t_ptr[0] == value,
common::errors::Fatal(
"Detected numerical Error, Expected %f but got %f", value, t_ptr[0]));
}
static void FluidCheckGradTensorValue(
const std::shared_ptr<imperative::VarBase>& X,
const phi::Place& place,
float value) {
auto* grad_tensor = X->MutableGradVar()->GetMutable<phi::DenseTensor>();
float* g_ptr = grad_tensor->mutable_data<float>(place);
std::vector<float> g_host_data(grad_tensor->numel());
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
if (place == phi::GPUPlace()) {
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
auto* dev_ctx = dynamic_cast<phi::GPUContext*>(pool.Get(place));
auto stream = dev_ctx->stream();
paddle::memory::Copy(phi::CPUPlace(),
g_host_data.data(),
phi::GPUPlace(),
g_ptr,
sizeof(float) * grad_tensor->numel(),
stream);
g_ptr = g_host_data.data();
}
#endif
VLOG(6) << "Tensor Value: " << g_ptr[0] << ", Expected Value: " << value;
PADDLE_ENFORCE(
g_ptr[0] == value,
common::errors::Fatal(
"Detected numerical Error, Expected %f but got %f", value, g_ptr[0]));
}
/* --------------------- */
/* ---- Fluid Scale ---- */
/* --------------------- */
// TODO(jiabin): Change this and remove nolint
void benchmark_fluid_scale(const std::shared_ptr<imperative::VarBase>& X,
const phi::Place& place,
bool accuracy_check) {
imperative::Tracer tracer;
framework::AttributeMap attrs;
attrs["use_onednn"] = false;
attrs["scale"] = 2;
attrs["bias"] = 3;
attrs["bias_after_scale"] = true;
std::shared_ptr<imperative::VarBase> tmp_out = X;
size_t max_num_runs = accuracy_check ? 10 : max_num_benchmark_runs;
for (size_t i = 0; i < max_num_runs; i++) {
imperative::NameVarBaseMap ins = {{"X", {tmp_out}}};
imperative::NameVarBaseMap outs = {
{"Out", {std::make_shared<imperative::VarBase>(true, "Out")}}};
tracer.TraceOp<VarBase>("scale", ins, outs, attrs, place, true);
tmp_out = outs["Out"][0];
}
auto* engine = tracer.GetEngine();
std::vector<std::shared_ptr<imperative::VarBase>> grad_tensors{nullptr};
engine->Init({tmp_out}, grad_tensors, false /*retain_graph*/);
engine->Execute();
if (accuracy_check) {
FluidCheckTensorValue(tmp_out, place, 8189.0);
FluidCheckGradTensorValue(X, place, 1024.0);
}
}
/* ---------------------- */
/* ---- Fluid Matmul ---- */
/* ---------------------- */
void benchmark_fluid_matmul(const std::shared_ptr<imperative::VarBase>& X,
const std::shared_ptr<imperative::VarBase>& Y,
const phi::Place& place,
bool accuracy_check) {
imperative::Tracer tracer;
std::shared_ptr<imperative::VarBase> tmp_out = X;
size_t max_num_runs = accuracy_check ? 2 : max_num_benchmark_runs;
for (size_t i = 0; i < max_num_runs; i++) {
framework::AttributeMap attrs;
imperative::NameVarBaseMap ins = {{"X", {tmp_out}}, {"Y", {Y}}};
imperative::NameVarBaseMap outs = {
{"Out", {std::make_shared<imperative::VarBase>(true, "Out")}}};
tracer.TraceOp<VarBase>("matmul_v2", ins, outs, attrs, place, true);
tmp_out = outs["Out"][0];
}
auto* engine = tracer.GetEngine();
std::vector<std::shared_ptr<imperative::VarBase>> grad_tensors{nullptr};
engine->Init({tmp_out}, grad_tensors, false /*retain_graph*/);
engine->Execute();
if (accuracy_check) {
FluidCheckTensorValue(tmp_out, place, 16);
FluidCheckGradTensorValue(X, place, 16);
FluidCheckGradTensorValue(Y, place, 16);
}
}
/* ------------------- */
/* ---- Fluid MLP ---- */
/* ------------------- */
void benchmark_fluid_mlp(
const std::shared_ptr<imperative::VarBase>& X,
const std::vector<std::shared_ptr<imperative::VarBase>>& Ws,
const std::vector<std::shared_ptr<imperative::VarBase>>& Bs,
const phi::Place& place,
bool accuracy_check) {
imperative::Tracer tracer;
imperative::NameVarBaseMap ins;
imperative::NameVarBaseMap outs;
framework::AttributeMap attrs;
std::shared_ptr<imperative::VarBase> input0 = X;
for (size_t i = 0; i < MLP_NUM_LINEAR; i++) {
// Matmul0
ins = {{"X", {input0}}, {"Y", {Ws[0]}}};
outs = {{"Out", {std::make_shared<imperative::VarBase>(true, "Out")}}};
tracer.TraceOp<VarBase>("matmul_v2", ins, outs, attrs, place, true);
// EW-Add0
ins = {{"X", outs["Out"]}, {"Y", {Bs[i]}}};
outs = {{"Out", {std::make_shared<imperative::VarBase>(true, "Out")}}};
tracer.TraceOp<VarBase>("elementwise_add", ins, outs, attrs, place, true);
input0 = outs["Out"][0];
}
// ReduceSum
ins = {{"X", {input0}}};
outs = {{"Out", {std::make_shared<imperative::VarBase>(true, "Out")}}};
attrs = {{"reduce_all", true}};
tracer.TraceOp<VarBase>("reduce_sum", ins, outs, attrs, place, true);
auto* engine = tracer.GetEngine();
std::vector<std::shared_ptr<imperative::VarBase>> grad_tensors{nullptr};
engine->Init(outs["Out"], grad_tensors, false /*retain_graph*/);
engine->Execute();
if (accuracy_check) {
std::unordered_map<std::string, float> result =
egr::compute_mlp_expected_results();
FluidCheckTensorValue(outs["Out"][0], place, result["Out"]);
FluidCheckGradTensorValue(X, place, result["GradX"]);
FluidCheckGradTensorValue(Ws[0], place, result["GradW"]);
}
}
} // namespace imperative
} // namespace paddle
@@ -0,0 +1,95 @@
// 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
#include <math.h>
#include "paddle/fluid/eager/eager_tensor.h"
#include "paddle/fluid/imperative/layer.h"
#include "paddle/phi/api/all.h"
/* MLP Configurations */
// Out1 = X[M, N] x W[N, K] + B[K]
// ... x MLP_NUM_LINEAR
// Out = ReduceSum(OutN)
#define MLP_M 4
#define MLP_N 16
#define MLP_K MLP_N
#define MLP_X_VAL 1.0
#define MLP_W_VAL 2.0
#define MLP_B_VAL 3.0
#define MLP_NUM_LINEAR 1000
namespace egr {
inline std::unordered_map<std::string, float> compute_mlp_expected_results() {
float Out = MLP_X_VAL;
for (size_t i = 0; i < MLP_NUM_LINEAR; i++) {
Out = Out * MLP_W_VAL * MLP_N + MLP_B_VAL;
}
Out = Out * MLP_M * MLP_N;
float GradX = 1.0 * pow((MLP_W_VAL * MLP_N), MLP_NUM_LINEAR);
float GradW0 =
1.0 * pow((MLP_W_VAL * MLP_N), (MLP_NUM_LINEAR - 1)) * MLP_X_VAL * MLP_M;
return {{"Out", Out}, {"GradX", GradX}, {"GradW", GradW0}};
}
/* ---- Eager Scale ---- */
void benchmark_eager_scale(const paddle::Tensor& tensor,
bool accuracy_check = false);
/* ---- Eager MatMul ---- */
void benchmark_eager_matmul(const paddle::Tensor& X,
const paddle::Tensor& Y,
bool accuracy_check = false);
void benchmark_eager_intermediate_matmul(const paddle::Tensor& X,
const paddle::Tensor& Y,
bool accuracy_check = false);
void benchmark_eager_intermediate_mlp(const paddle::Tensor& X,
const std::vector<paddle::Tensor>& Ws,
const std::vector<paddle::Tensor>& Bs,
bool accuracy_check = false);
} // namespace egr
namespace paddle {
namespace imperative {
/* ---- Fluid Scale ---- */
// TODO(jiabin): Change this and remove nolint
void benchmark_fluid_scale(
const std::shared_ptr<imperative::VarBase>& X, // NOLINT
const phi::Place& place,
bool accuracy_check = false);
/* ---- Fluid MatMul ---- */
void benchmark_fluid_matmul(
const std::shared_ptr<imperative::VarBase>& X,
const std::shared_ptr<imperative::VarBase>& Y, // NOLINT
const phi::Place& place,
bool accuracy_check = false);
/* ---- Fluid MLP ---- */
void benchmark_fluid_mlp(
const std::shared_ptr<imperative::VarBase>& X,
const std::vector<std::shared_ptr<imperative::VarBase>>& Ws,
const std::vector<std::shared_ptr<imperative::VarBase>>& Bs,
const phi::Place& place,
bool accuracy_check = false);
} // namespace imperative
} // namespace paddle
+20
View File
@@ -0,0 +1,20 @@
paddle_test(test_egr_task_nan_inf_utils SRCS nan_inf_utils_test.cc DEPS common)
if(NOT ((NOT WITH_PYTHON) AND ON_INFER))
paddle_test(test_egr_task_hook SRCS hook_test.cc)
paddle_test(test_egr_task_backward SRCS backward_test.cc)
paddle_test(test_egr_task_grad SRCS grad_test.cc)
paddle_test(test_egr_task_fwd_bwd_joint SRCS fwd_bwd_joint_test.cc DEPS phi)
paddle_test(test_egr_task_cross_batch SRCS cross_batch_accumulation_test.cc)
paddle_test(test_egr_task_hook_intermediate SRCS hook_test_intermediate.cc)
paddle_test(test_egr_task_autocodegen SRCS generated_test.cc)
paddle_test(test_egr_task_tensor_utils SRCS tensor_utils_test.cc)
paddle_test(test_egr_task_eager_utils SRCS eager_utils_test.cc)
paddle_test(test_egr_task_forward_autograd SRCS forward_autograd_test.cc)
endif()
if(WITH_ONNXRUNTIME AND WIN32)
# Copy onnxruntime for some c++ test in Windows, since the test will
# be build only in CI, so suppose the generator in Windows is Ninja.
copy_onnx(test_egr_task_nan_inf_utils)
endif()
+345
View File
@@ -0,0 +1,345 @@
// 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.
#include "paddle/fluid/eager/backward.h"
#include <sstream>
#include "glog/logging.h"
#include "gtest/gtest.h"
#include "paddle/fluid/eager/accumulation/accumulation_node.h"
#include "paddle/fluid/eager/api/all.h"
#include "paddle/fluid/eager/api/generated/eager_generated/backwards/scale_node.h"
#include "paddle/fluid/eager/autograd_meta.h"
#include "paddle/fluid/eager/grad_node_info.h"
#include "paddle/phi/core/dense_tensor.h"
#include "paddle/phi/core/kernel_registry.h"
#include "paddle/phi/core/tensor_meta.h"
#include "test/cpp/eager/test_utils.h"
PD_DECLARE_KERNEL(full, CPU, ALL_LAYOUT);
PD_DECLARE_KERNEL(add, CPU, ALL_LAYOUT);
namespace egr {
TEST(Backward, SingleNodeEmptyGrad) {
// Prepare Device Contexts
eager_test::InitEnv(phi::CPUPlace());
// Prepare Inputs
phi::DDim ddim = common::make_ddim({4, 16, 16, 32});
// Create Target Tensor
paddle::Tensor target_tensor =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
1.0 /*value*/,
false /*is_leaf*/);
paddle::Tensor leaf_tensor;
{
// Create Scale Node
auto node0_ptr = std::make_shared<GradNodeScale>(1, 1);
node0_ptr->SetAttributes_scale(5.0 /*scale*/);
// Set grad in/out meta
node0_ptr->SetDefaultGradInOutMeta();
AutogradMeta* auto_grad_meta = EagerUtils::autograd_meta(&target_tensor);
auto_grad_meta->SetGradNode(
std::dynamic_pointer_cast<GradNodeBase>(node0_ptr));
auto_grad_meta->SetSingleOutRankWithSlot(0, 0);
auto_grad_meta->SetStopGradient(false);
AutogradMeta* auto_grad_meta1 = EagerUtils::autograd_meta(&leaf_tensor);
// Connect Tensor and AccumulationNode via AutoGradMeta
auto acc_node_ptr =
std::make_shared<egr::GradNodeAccumulation>(leaf_tensor);
auto_grad_meta1->SetGradNode(
std::dynamic_pointer_cast<GradNodeBase>(acc_node_ptr));
auto_grad_meta1->SetSingleOutRankWithSlot(0, 0);
auto_grad_meta1->SetStopGradient(false);
node0_ptr->SetGradOutMeta({leaf_tensor}, 0);
}
std::vector<paddle::Tensor> outs = {target_tensor};
// Run Backward
Backward(outs, {});
// Check Output Value
eager_test::CompareGradTensorWithValue<float>(leaf_tensor, 5.0);
}
TEST(Backward, SingleNodeCustomGrad) {
// Prepare Device Contexts
eager_test::InitEnv(phi::CPUPlace());
// Prepare Inputs
std::vector<paddle::Tensor> target_tensors;
phi::DDim ddim = common::make_ddim({4, 16, 16, 32});
// Create Target Tensor
paddle::Tensor tensor =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
1.0 /*value*/,
false /*is_leaf*/);
target_tensors.emplace_back(std::move(tensor));
std::vector<paddle::Tensor> grad_tensors;
// Create Grad Tensor
paddle::Tensor grad_tensor =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
10.0 /*value*/,
false /*is_leaf*/);
grad_tensors.emplace_back(std::move(grad_tensor));
paddle::Tensor leaf_tensor;
{
// Create Scale Node
auto node0_ptr = std::make_shared<GradNodeScale>(1, 1);
node0_ptr->SetAttributes_scale(5.0 /*scale*/);
// Set grad in/out meta
node0_ptr->SetDefaultGradInOutMeta();
// Connect Tensor and Node via AutoGradMeta
AutogradMeta* auto_grad_meta =
EagerUtils::autograd_meta(&(target_tensors[0]));
auto_grad_meta->SetGradNode(
std::dynamic_pointer_cast<GradNodeBase>(node0_ptr));
auto_grad_meta->SetSingleOutRankWithSlot(0, 0);
auto_grad_meta->SetStopGradient(false);
AutogradMeta* auto_grad_meta1 = EagerUtils::autograd_meta(&leaf_tensor);
// Connect Tensor and AccumulationNode via AutoGradMeta
auto acc_node_ptr =
std::make_shared<egr::GradNodeAccumulation>(leaf_tensor);
auto_grad_meta1->SetGradNode(
std::dynamic_pointer_cast<GradNodeBase>(acc_node_ptr));
auto_grad_meta1->SetSingleOutRankWithSlot(0, 0);
auto_grad_meta1->SetStopGradient(false);
node0_ptr->SetGradOutMeta({leaf_tensor}, 0);
}
// Run Backward
Backward(target_tensors, grad_tensors);
// Check Output Value
eager_test::CompareGradTensorWithValue<float>(leaf_tensor, 50.0);
}
/*
Node1
|
Node0
|
inp0
*/
TEST(Backward, LinearNodes) {
// Prepare Device Contexts
eager_test::InitEnv(phi::CPUPlace());
// Prepare Inputs
std::vector<paddle::Tensor> target_tensors;
phi::DDim ddim = common::make_ddim({4, 16, 16, 32});
// Create Target Tensor
paddle::Tensor tensor =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
1.0 /*value*/,
false /*is_leaf*/);
target_tensors.emplace_back(std::move(tensor));
paddle::Tensor leaf_tensor;
{
// Create Node0
auto node0_ptr = std::make_shared<GradNodeScale>(1, 1);
node0_ptr->SetAttributes_scale(5.0 /*scale*/);
// Set grad in/out meta for node0
node0_ptr->SetDefaultGradInOutMeta();
// Create Node1
auto node1_ptr = std::make_shared<GradNodeScale>(1, 1);
node1_ptr->SetAttributes_scale(10.0 /*scale*/);
// Set grad in/out meta for node1
node1_ptr->SetDefaultGradInOutMeta();
// Connect Input Tensor and Node0 via AutoGradMeta
AutogradMeta* auto_grad_meta =
EagerUtils::autograd_meta(&(target_tensors[0]));
auto_grad_meta->SetGradNode(
std::dynamic_pointer_cast<GradNodeBase>(node0_ptr));
auto_grad_meta->SetSingleOutRankWithSlot(0, 0);
auto_grad_meta->SetStopGradient(false);
// Connect Node0 -> Node1 via Edge
auto tmp_tensor = paddle::Tensor();
auto* meta0 = EagerUtils::autograd_meta(&tmp_tensor);
meta0->SetStopGradient(false);
meta0->SetSingleOutRankWithSlot(0, 0);
meta0->SetGradNode(node1_ptr);
node0_ptr->SetGradOutMeta(tmp_tensor, 0);
AutogradMeta* auto_grad_meta1 = EagerUtils::autograd_meta(&leaf_tensor);
// Connect Tensor and AccumulationNode via AutoGradMeta
auto acc_node_ptr =
std::make_shared<egr::GradNodeAccumulation>(leaf_tensor);
auto_grad_meta1->SetGradNode(
std::dynamic_pointer_cast<GradNodeBase>(acc_node_ptr));
auto_grad_meta1->SetSingleOutRankWithSlot(0, 0);
auto_grad_meta1->SetStopGradient(false);
node1_ptr->SetGradOutMeta(leaf_tensor, 0);
}
// Use Empty Grad Tensor
Backward(target_tensors, {});
// Check Output Value
eager_test::CompareGradTensorWithValue<float>(leaf_tensor, 50.0);
}
/*
Node2
| |
Node0 Node1
| |
inp0 inp1
*/
TEST(Backward, WithAccumulation) {
// Prepare Device Contexts
eager_test::InitEnv(phi::CPUPlace());
// Prepare Inputs
phi::DDim ddim = common::make_ddim({4, 16, 16, 32});
// Create Target Tensor
std::vector<paddle::Tensor> target_tensors;
paddle::Tensor tensor0 =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
1.0 /*value*/,
false /*is_leaf*/);
paddle::Tensor tensor1 =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
1.0 /*value*/,
false /*is_leaf*/);
target_tensors.emplace_back(std::move(tensor0));
target_tensors.emplace_back(std::move(tensor1));
// Create Grad Tensor
std::vector<paddle::Tensor> grad_tensors;
paddle::Tensor grad_tensor0 =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
5.0 /*value*/,
false /*is_leaf*/);
paddle::Tensor grad_tensor1 =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
10.0 /*value*/,
false /*is_leaf*/);
grad_tensors.emplace_back(std::move(grad_tensor0));
grad_tensors.emplace_back(std::move(grad_tensor1));
paddle::Tensor leaf_tensor;
{
// Create Node0
auto node0_ptr = std::make_shared<GradNodeScale>(1, 1);
node0_ptr->SetAttributes_scale(5.0 /*scale*/);
node0_ptr->SetDefaultGradInOutMeta();
// Create Node1
auto node1_ptr = std::make_shared<GradNodeScale>(1, 1);
node1_ptr->SetAttributes_scale(10.0 /*scale*/);
node1_ptr->SetDefaultGradInOutMeta();
// Create Node2
auto node2_ptr = std::make_shared<GradNodeScale>(1, 1);
node2_ptr->SetAttributes_scale(20.0 /*scale*/);
node2_ptr->SetDefaultGradInOutMeta();
// Connect Inp0 and Node0 via AutoGradMeta
AutogradMeta* auto_grad_meta0 =
EagerUtils::autograd_meta(&(target_tensors[0]));
auto_grad_meta0->SetGradNode(
std::dynamic_pointer_cast<GradNodeBase>(node0_ptr));
auto_grad_meta0->SetSingleOutRankWithSlot(0, 0);
auto_grad_meta0->SetStopGradient(false);
// Connect Inp1 and Node1 via AutoGradMeta
AutogradMeta* auto_grad_meta1 =
EagerUtils::autograd_meta(&(target_tensors[1]));
auto_grad_meta1->SetGradNode(
std::dynamic_pointer_cast<GradNodeBase>(node1_ptr));
auto_grad_meta1->SetSingleOutRankWithSlot(0, 0);
auto_grad_meta1->SetStopGradient(false);
// Connect Node0 -> Node2 via Edge
auto tmp_tensor0 = paddle::Tensor();
auto* meta0 = EagerUtils::autograd_meta(&tmp_tensor0);
meta0->SetStopGradient(false);
meta0->SetSingleOutRankWithSlot(0, 0);
meta0->SetGradNode(node2_ptr);
node0_ptr->SetGradOutMeta(tmp_tensor0, 0);
// Connect Node1 -> Node2 via Edge
auto tmp_tensor1 = paddle::Tensor();
auto* meta1 = EagerUtils::autograd_meta(&tmp_tensor1);
meta1->SetStopGradient(false);
meta1->SetSingleOutRankWithSlot(0, 0);
meta1->SetGradNode(node2_ptr);
node1_ptr->SetGradOutMeta(tmp_tensor1, 0);
AutogradMeta* auto_grad_meta2 = EagerUtils::autograd_meta(&leaf_tensor);
// Connect Tensor and AccumulationNode via AutoGradMeta
auto acc_node_ptr =
std::make_shared<egr::GradNodeAccumulation>(leaf_tensor);
auto_grad_meta2->SetGradNode(
std::dynamic_pointer_cast<GradNodeBase>(acc_node_ptr));
auto_grad_meta2->SetSingleOutRankWithSlot(0, 0);
auto_grad_meta2->SetStopGradient(false);
std::vector<egr::AutogradMeta*> res2 = {auto_grad_meta2};
node2_ptr->SetGradOutMeta(leaf_tensor, 0);
}
Backward(target_tensors, grad_tensors);
eager_test::CompareGradTensorWithValue<float>(leaf_tensor, 2500.0);
}
} // namespace egr
@@ -0,0 +1,83 @@
// 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.
#include <sstream>
#include "glog/logging.h"
#include "gtest/gtest.h"
#include "paddle/fluid/eager/accumulation/accumulation_node.h"
#include "paddle/fluid/eager/api/all.h"
#include "paddle/fluid/eager/api/generated/eager_generated/backwards/scale_node.h"
#include "paddle/fluid/eager/autograd_meta.h"
#include "paddle/fluid/eager/backward.h"
#include "paddle/fluid/eager/grad_node_info.h"
#include "paddle/phi/core/dense_tensor.h"
#include "paddle/phi/core/kernel_registry.h"
#include "paddle/phi/core/tensor_meta.h"
#include "test/cpp/eager/test_utils.h"
PD_DECLARE_KERNEL(full, CPU, ALL_LAYOUT);
namespace egr {
TEST(CrossBatchAccumulation, SingleScaleNode) {
eager_test::InitEnv(phi::CPUPlace());
std::vector<paddle::Tensor> target_tensors;
phi::DDim ddim = common::make_ddim({4, 16, 16, 32});
paddle::Tensor tensor =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
1.0 /*value*/,
false /*is_leaf*/);
target_tensors.emplace_back(std::move(tensor));
paddle::Tensor& target_tensor = target_tensors[0];
paddle::Tensor leaf_tensor = paddle::Tensor();
auto scale_node_ptr = std::make_shared<GradNodeScale>(1, 1);
scale_node_ptr->SetAttributes_scale(5.0 /*scale*/);
scale_node_ptr->SetDefaultGradInOutMeta();
AutogradMeta* auto_grad_meta = EagerUtils::autograd_meta(&target_tensor);
auto_grad_meta->SetGradNode(
std::dynamic_pointer_cast<GradNodeBase>(scale_node_ptr));
auto_grad_meta->SetSingleOutRankWithSlot(0, 0);
auto_grad_meta->SetStopGradient(false);
egr_utils_api::RetainGradForTensor(target_tensor); // result: 1.0
AutogradMeta* meta = EagerUtils::autograd_meta(&leaf_tensor);
auto acc_node_ptr = std::make_shared<GradNodeAccumulation>(leaf_tensor);
meta->SetStopGradient(false);
meta->SetSingleOutRankWithSlot(0, 0);
meta->SetGradNode(acc_node_ptr);
std::vector<egr::AutogradMeta*> res = {meta};
scale_node_ptr->SetGradOutMeta(leaf_tensor, 0);
Backward(target_tensors, {});
eager_test::CompareGradTensorWithValue<float>(target_tensor, 1.0);
eager_test::CompareGradTensorWithValue<float>(leaf_tensor, 5.0);
Backward(target_tensors, {});
eager_test::CompareGradTensorWithValue<float>(target_tensor, 1.0);
eager_test::CompareGradTensorWithValue<float>(leaf_tensor, 10.0);
}
} // namespace egr
@@ -0,0 +1,567 @@
// 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.
#include <sstream>
#include "gtest/gtest.h"
#include "paddle/common/flags.h"
#include "paddle/fluid/eager/accumulation/accumulation_node.h"
#include "paddle/fluid/eager/eager_tensor.h"
#include "paddle/fluid/eager/grad_node_info.h"
#include "paddle/fluid/eager/utils.h"
#include "paddle/phi/api/lib/utils/allocator.h"
#include "paddle/phi/core/enforce.h"
#include "paddle/phi/core/kernel_registry.h"
#include "test/cpp/eager/data_structure_tests/grad_node_test.h"
#include "test/cpp/eager/test_utils.h"
COMMON_DECLARE_bool(tensor_md5_checksum_use_binary_format);
PD_DECLARE_KERNEL(full, CPU, ALL_LAYOUT);
namespace egr {
TEST(EagerUtils, AutoGradMeta) {
// Construct Eager Tensor
phi::DenseTensorMeta meta =
phi::DenseTensorMeta(phi::DataType::FLOAT32, common::make_ddim({1, 1}));
std::shared_ptr<phi::DenseTensor> dt0 = std::make_shared<phi::DenseTensor>(
std::make_unique<paddle::experimental::DefaultAllocator>(phi::CPUPlace())
.get(),
meta);
dt0->mutable_data<float>(phi::CPUPlace())[0] = 10.0;
paddle::Tensor et0 = paddle::Tensor(dt0);
std::shared_ptr<phi::DenseTensor> dt1 = std::make_shared<phi::DenseTensor>(
std::make_unique<paddle::experimental::DefaultAllocator>(phi::CPUPlace())
.get(),
meta);
dt1->mutable_data<float>(phi::CPUPlace())[0] = 20.0;
paddle::Tensor et1 = paddle::Tensor(dt1);
// unsafe_autograd_meta()
// autograd_meta()
AutogradMeta* autograd_meta0 = EagerUtils::autograd_meta(&et0);
AutogradMeta* autograd_meta1 = EagerUtils::autograd_meta(&et1);
AutogradMeta* unsafe_autograd_meta_after =
EagerUtils::unsafe_autograd_meta(et0);
PADDLE_ENFORCE_NOT_NULL(
unsafe_autograd_meta_after,
common::errors::PreconditionNotMet(
"Unsafe autograd meta after should not be null."));
// NOTE: Since autograd_meta will be copied make sure it's not null
std::vector<paddle::Tensor> ets = {et0, et1};
auto test_node = std::make_shared<eager_test::GradTestNode>();
std::vector<AutogradMeta*> autograd_metas = EagerUtils::autograd_meta(&ets);
std::vector<AutogradMeta*> unsafe_autograd_metas =
EagerUtils::unsafe_autograd_meta(ets);
PADDLE_ENFORCE_NOT_NULL(unsafe_autograd_metas[0],
common::errors::PreconditionNotMet(
"Unsafe autograd metas should not be null."));
PADDLE_ENFORCE_NOT_NULL(unsafe_autograd_metas[1],
common::errors::PreconditionNotMet(
"Unsafe autograd metas should not be null."));
// Set Autograd Meta
autograd_meta0->SetSingleOutRankWithSlot(0, 1);
autograd_meta0->SetGradNode(test_node);
// OutRankInfo()
std::pair<size_t, size_t> out_rank_info0 = EagerUtils::OutRankInfo(et0);
PADDLE_ENFORCE_EQ(
static_cast<int>(out_rank_info0.first),
0UL,
common::errors::InvalidArgument("The first element of out rank info "
"mismatch. Expected 0 but received %d.",
static_cast<int>(out_rank_info0.first)));
PADDLE_ENFORCE_EQ(
static_cast<int>(out_rank_info0.second),
1UL,
common::errors::InvalidArgument("The second element of out rank info "
"mismatch. Expected 1 but received %d.",
static_cast<int>(out_rank_info0.second)));
// grad_node()
std::shared_ptr<GradNodeBase> grad_node0 = EagerUtils::grad_node(et0);
PADDLE_ENFORCE_NOT_NULL(
grad_node0.get(),
common::errors::PreconditionNotMet("Grad of node should not be null."));
EagerUtils::SetHistory(autograd_meta1, test_node);
EagerUtils::SetHistory(autograd_meta1, test_node);
std::shared_ptr<GradNodeBase> grad_node1 = EagerUtils::grad_node(et1);
PADDLE_ENFORCE_NOT_NULL(
grad_node1.get(),
common::errors::PreconditionNotMet("Grad of node should not be null."));
// SetOutRankWithSlot()
EagerUtils::SetOutRankWithSlot(autograd_meta1, 0);
std::pair<size_t, size_t> out_rank_info1 = EagerUtils::OutRankInfo(et1);
PADDLE_ENFORCE_EQ(
static_cast<int>(out_rank_info1.first),
0UL,
common::errors::InvalidArgument("The first element of out rank info "
"mismatch. Expected 0 but received %d.",
static_cast<int>(out_rank_info1.first)));
PADDLE_ENFORCE_EQ(
static_cast<int>(out_rank_info1.second),
0UL,
common::errors::InvalidArgument("The second element of out rank info "
"mismatch. Expected 0 but received %d.",
static_cast<int>(out_rank_info1.second)));
EagerUtils::SetOutRankWithSlot(&autograd_metas, 0);
std::pair<size_t, size_t> out_rank_info2 = EagerUtils::OutRankInfo(et0);
PADDLE_ENFORCE_EQ(
static_cast<int>(out_rank_info2.first),
0UL,
common::errors::InvalidArgument("The first element of out rank info "
"mismatch. Expected 0 but received %d.",
static_cast<int>(out_rank_info2.first)));
PADDLE_ENFORCE_EQ(
static_cast<int>(out_rank_info2.second),
0UL,
common::errors::InvalidArgument("The second element of out rank info "
"mismatch. Expected 0 but received %d.",
static_cast<int>(out_rank_info2.second)));
std::pair<size_t, size_t> out_rank_info3 = EagerUtils::OutRankInfo(et1);
PADDLE_ENFORCE_EQ(
static_cast<int>(out_rank_info3.first),
0UL,
common::errors::InvalidArgument("The first element of out rank info "
"mismatch. Expected 0 but received %d.",
static_cast<int>(out_rank_info3.first)));
PADDLE_ENFORCE_EQ(
static_cast<int>(out_rank_info3.second),
1UL,
common::errors::InvalidArgument("The second element of out rank info "
"mismatch. Expected 1 but received %d.",
static_cast<int>(out_rank_info3.second)));
}
template <typename T>
paddle::Tensor CreateTestCPUTensor(T val, const phi::DDim& ddim) {
phi::DenseTensorMeta meta =
phi::DenseTensorMeta(phi::DataType::FLOAT32, ddim);
paddle::Tensor tensor;
std::shared_ptr<phi::DenseTensor> dt = std::make_shared<phi::DenseTensor>(
std::make_unique<paddle::experimental::DefaultAllocator>(phi::CPUPlace())
.get(),
meta);
auto* dt_ptr = dt->mutable_data<T>(phi::CPUPlace());
for (int64_t i = 0; i < dt->numel(); i++) {
dt_ptr[i] = val;
}
tensor.set_impl(dt);
return tensor;
}
TEST(EagerUtils, ComputeRequireGrad) {
auto auto_grad0 = std::make_shared<egr::AutogradMeta>();
auto auto_grad1 = std::make_shared<egr::AutogradMeta>();
auto auto_grad2 = std::make_shared<egr::AutogradMeta>();
auto auto_grad3 = std::make_shared<egr::AutogradMeta>();
PADDLE_ENFORCE_EQ(
auto_grad0->NumericStopGradient(),
-1,
common::errors::InvalidArgument("The NumericStopGradient of auto grad "
"mismatch. Expected -1 but received %d.",
auto_grad0->NumericStopGradient()));
VLOG(6) << "Single Test ComputeRequireGrad";
auto_grad0->SetStopGradient(true);
PADDLE_ENFORCE_EQ(egr::EagerUtils::ComputeRequireGrad(true, auto_grad0.get()),
false,
::common::errors::InvalidArgument(
"Expected ComputeRequireGrad(true, auto_grad0) to be "
"false, but it is true."));
PADDLE_ENFORCE_EQ(
egr::EagerUtils::ComputeRequireGrad(false, auto_grad0.get()),
false,
::common::errors::InvalidArgument(
"Expected ComputeRequireGrad(false, auto_grad0) to be false, but it "
"is true."));
auto_grad0->SetStopGradient(false);
PADDLE_ENFORCE_EQ(
egr::EagerUtils::ComputeRequireGrad(false, auto_grad0.get()),
false,
::common::errors::InvalidArgument(
"Expected ComputeRequireGrad(false, auto_grad0) to be false, but it "
"is true."));
PADDLE_ENFORCE_EQ(egr::EagerUtils::ComputeRequireGrad(true, auto_grad0.get()),
true,
::common::errors::InvalidArgument(
"Expected ComputeRequireGrad(true, auto_grad0) to be "
"true, but it is false."));
VLOG(6) << "Multi Test ComputeRequireGrad";
auto_grad0->SetStopGradient(false);
auto_grad1->SetStopGradient(true);
PADDLE_ENFORCE_EQ(egr::EagerUtils::ComputeRequireGrad(
true, auto_grad0.get(), auto_grad1.get()),
true,
::common::errors::InvalidArgument(
"Expected ComputeRequireGrad(true, auto_grad0, "
"auto_grad1) to be true, but it is false."));
PADDLE_ENFORCE_EQ(egr::EagerUtils::ComputeRequireGrad(
false, auto_grad0.get(), auto_grad1.get()),
false,
::common::errors::InvalidArgument(
"Expected ComputeRequireGrad(false, auto_grad0, "
"auto_grad1) to be false, but it is true."));
auto_grad0->SetStopGradient(true);
PADDLE_ENFORCE_EQ(egr::EagerUtils::ComputeRequireGrad(
true, auto_grad0.get(), auto_grad1.get()),
false,
::common::errors::InvalidArgument(
"Expected ComputeRequireGrad(true, auto_grad0, "
"auto_grad1) to be false, but it is true."));
PADDLE_ENFORCE_EQ(egr::EagerUtils::ComputeRequireGrad(
false, auto_grad0.get(), auto_grad1.get()),
false,
::common::errors::InvalidArgument(
"Expected ComputeRequireGrad(false, auto_grad0, "
"auto_grad1) to be false, but it is true."));
}
TEST(EagerUtils, PassStopGradient) {
auto auto_grad0 = std::make_shared<egr::AutogradMeta>();
auto auto_grad1 = std::make_shared<egr::AutogradMeta>();
auto auto_grad2 = std::make_shared<egr::AutogradMeta>();
auto auto_grad3 = std::make_shared<egr::AutogradMeta>();
PADDLE_ENFORCE_EQ(
auto_grad0->NumericStopGradient(),
-1,
common::errors::InvalidArgument("The NumericStopGradient of auto grad "
"mismatch. Expected -1 but received %d.",
auto_grad0->NumericStopGradient()));
VLOG(6) << "Test PassStopGradient";
egr::EagerUtils::PassStopGradient(false, auto_grad0.get());
PADDLE_ENFORCE_EQ(
auto_grad0->StopGradient(),
false,
::common::errors::InvalidArgument(
"Expected auto_grad0->StopGradient() to be false, but received %d.",
auto_grad0->StopGradient()));
egr::EagerUtils::PassStopGradient(true,
auto_grad0.get(),
auto_grad1.get(),
auto_grad2.get(),
auto_grad3.get());
PADDLE_ENFORCE_EQ(
auto_grad0->StopGradient(),
true,
::common::errors::InvalidArgument(
"Expected auto_grad0->StopGradient() to be true, but received %d.",
auto_grad0->StopGradient()));
PADDLE_ENFORCE_EQ(
auto_grad1->StopGradient(),
true,
::common::errors::InvalidArgument(
"Expected auto_grad1->StopGradient() to be true, but received %d.",
auto_grad1->StopGradient()));
PADDLE_ENFORCE_EQ(
auto_grad2->StopGradient(),
true,
::common::errors::InvalidArgument(
"Expected auto_grad2->StopGradient() to be true, but received %d.",
auto_grad2->StopGradient()));
PADDLE_ENFORCE_EQ(
auto_grad3->StopGradient(),
true,
::common::errors::InvalidArgument(
"Expected auto_grad3->StopGradient() to be true, but received %d.",
auto_grad3->StopGradient()));
}
TEST(EagerUtils, TrySyncToVar) {
phi::DDim ddim = common::make_ddim({2, 4, 4, 4});
auto tensor = CreateTestCPUTensor(5.0f, ddim);
std::vector<std::shared_ptr<egr::EagerVariable>> var_bases = {
egr::EagerUtils::TrySyncToVar(tensor)};
paddle::framework::Variable* var = var_bases[0]->MutableVar();
const auto& framework_tensor = var->Get<phi::DenseTensor>();
const float* ptr = framework_tensor.data<float>();
VLOG(6) << "Check Value for SyncToVarsSingle";
PADDLE_ENFORCE_EQ(framework_tensor.numel(),
tensor.numel(),
common::errors::InvalidArgument(
"The numel of framework tensor and numel of "
"tensor should be the same, but received %d and %d.",
framework_tensor.numel(),
tensor.numel()));
for (int i = 0; i < framework_tensor.numel(); i++) {
PADDLE_ENFORCE_EQ(ptr[i],
5.0f,
common::errors::InvalidArgument(
"The numel of framework tensor mismatch. "
"Expected 5.0 but received %f.",
ptr[i]));
}
}
TEST(EagerUtils, TrySyncToVars) {
phi::DDim ddim = common::make_ddim({2, 4, 4, 4});
std::vector<paddle::Tensor> tensors = {CreateTestCPUTensor(1.0f, ddim),
CreateTestCPUTensor(2.0f, ddim)};
std::vector<std::shared_ptr<egr::EagerVariable>> var_bases =
egr::EagerUtils::TrySyncToVars(tensors);
{
paddle::framework::Variable* var = var_bases[0]->MutableVar();
const auto& framework_tensor = var->Get<phi::DenseTensor>();
const float* ptr = framework_tensor.data<float>();
PADDLE_ENFORCE_EQ(
framework_tensor.numel(),
tensors[0].numel(),
common::errors::InvalidArgument(
"The numel of framework tensor and numel "
"of tensor should be the same, but received %d and %d.",
framework_tensor.numel(),
tensors[0].numel()));
for (int i = 0; i < framework_tensor.numel(); i++) {
PADDLE_ENFORCE_EQ(ptr[i],
1.0,
common::errors::InvalidArgument(
"The numel of framework tensor mismatch. Expected "
"1.0 but received %f.",
ptr[i]));
}
}
{
paddle::framework::Variable* var = var_bases[1]->MutableVar();
const auto& framework_tensor = var->Get<phi::DenseTensor>();
const float* ptr = framework_tensor.data<float>();
VLOG(6) << "Check Value for SyncToVarsMultiple";
PADDLE_ENFORCE_EQ(
framework_tensor.numel(),
tensors[0].numel(),
common::errors::InvalidArgument(
"The numel of framework tensor and numel "
"of tensor should be the same, but received %d and %d.",
framework_tensor.numel(),
tensors[0].numel()));
for (int i = 0; i < framework_tensor.numel(); i++) {
PADDLE_ENFORCE_EQ(ptr[i],
2.0,
common::errors::InvalidArgument(
"The numel of framework tensor mismatch. Expected "
"2.0 but received %f.",
ptr[i]));
}
}
}
TEST(EagerUtils, CreateVars) {
VLOG(6) << "Check CreateVars";
std::vector<std::shared_ptr<egr::EagerVariable>> outs =
egr::EagerUtils::CreateVars(2);
PADDLE_ENFORCE_EQ(
outs.size(),
2UL,
common::errors::InvalidArgument(
"Size of outs mismatch. Expected 2 but received %d.", outs.size()));
PADDLE_ENFORCE_EQ(
outs[0]->Var().IsInitialized(),
false,
::common::errors::AlreadyExists("Expected the first variable to be "
"uninitialized, but already exists."));
}
TEST(EagerUtils, GetGradAccumulationNode) {
VLOG(6) << "Check GetGradAccumulationNode";
paddle::Tensor t0("test_tensor");
ASSERT_EQ(egr::EagerUtils::GetGradAccumulationNode(t0), nullptr);
auto autograd_ptr0 = egr::EagerUtils::autograd_meta(&t0);
autograd_ptr0->SetStopGradient(true);
ASSERT_EQ(egr::EagerUtils::GetGradAccumulationNode(t0), nullptr);
autograd_ptr0->SetStopGradient(false);
auto res = std::dynamic_pointer_cast<egr::GradNodeAccumulation>(
egr::EagerUtils::GetGradAccumulationNode(t0));
ASSERT_TRUE(res != nullptr);
auto res2 = egr::EagerUtils::GetGradAccumulationNode(t0);
ASSERT_EQ(res2.get(), res.get());
autograd_ptr0->SetStopGradient(true);
auto res3 = egr::EagerUtils::GetGradAccumulationNode(t0);
ASSERT_EQ(res3, nullptr);
autograd_ptr0->SetStopGradient(false);
autograd_ptr0->SetGradNode(
std::make_shared<eager_test::GradTestNode>(1, 2.0, 3));
ASSERT_ANY_THROW(egr::EagerUtils::GetGradAccumulationNode(t0));
}
TEST(EagerUtils, FillZeroForEmptyOptionalGradInput) {
paddle::small_vector<std::vector<paddle::Tensor>, egr::kSlotSmallVectorSize>
grads = {std::vector<paddle::Tensor>(1)};
paddle::small_vector<std::vector<GradSlotMeta>, egr::kSlotSmallVectorSize>
slot_metas = {std::vector<GradSlotMeta>(1)};
phi::DenseTensorMeta tensor_meta;
tensor_meta.dtype = phi::DataType::FLOAT32;
tensor_meta.dims = {2, 4};
slot_metas[0][0].SetTensorMeta(tensor_meta);
slot_metas[0][0].SetPlace(phi::CPUPlace());
EagerUtils::FillZeroForEmptyOptionalGradInput(&grads[0], slot_metas[0]);
eager_test::CompareTensorWithValue<float>(grads[0][0], 0.0);
}
TEST(EagerUtils, SetTensorName) {
std::string unique_api_name = "Test";
std::string var_name = "out";
phi::DDim ddim = common::make_ddim({2, 4, 4, 4});
std::vector<paddle::Tensor> tensors = {CreateTestCPUTensor(1.0f, ddim),
CreateTestCPUTensor(2.0f, ddim)};
paddle::optional<paddle::Tensor> optional_t;
optional_t = tensors[0];
paddle::Tensor* t = &(optional_t.get());
auto generate_tensor_name = [](const std::string& unique_api_name,
const std::string& var_name,
const paddle::Tensor* t) {
std::ostringstream oss;
oss << unique_api_name << "_" << var_name << "_" << t->dtype() << "_";
for (int i = 0; i < t->dims().size(); ++i) {
if (i != 0) {
oss << "x";
}
oss << t->dims()[i];
}
return oss.str();
};
// Gen refer name
std::string refer_name = generate_tensor_name(unique_api_name, var_name, t);
// test paddle::optional<paddle::Tensor>* tensor
egr::SetTensorName(unique_api_name, var_name, &optional_t);
ASSERT_TRUE(t->name() == refer_name);
refer_name = generate_tensor_name(
unique_api_name, var_name + "_" + std::to_string(0), t);
// test std::vector<paddle::Tensor>* tensors
egr::SetTensorName(unique_api_name, var_name, &tensors);
ASSERT_TRUE(tensors[0].name() == refer_name);
// test paddle::optional<std::vector<paddle::Tensor>>* tensors
paddle::optional<std::vector<paddle::Tensor>> opt_tensors = tensors;
egr::SetTensorName(unique_api_name, var_name, &opt_tensors);
ASSERT_TRUE(tensors[0].name() == refer_name);
}
TEST(EagerUtils, SetGradTensorName) {
phi::DDim ddim = common::make_ddim({2, 4});
std::vector<paddle::Tensor> tensors = {CreateTestCPUTensor(1.0f, ddim)};
paddle::small_vector<std::vector<GradSlotMeta>, egr::kSlotSmallVectorSize>
slot_metas = {std::vector<GradSlotMeta>(1)};
phi::DenseTensorMeta tensor_meta;
tensor_meta.dtype = phi::DataType::FLOAT32;
tensor_meta.dims = {2, 4};
slot_metas[0][0].SetTensorMeta(tensor_meta);
slot_metas[0][0].SetPlace(phi::CPUPlace());
egr::SetGradTensorName(&tensors, 0, slot_metas);
std::string refer_name = "@Grad";
ASSERT_TRUE(tensors[0].name() == refer_name);
}
TEST(EagerUtils, SaveTensorMD5CheckSumToFile) {
#define EXPECT_SAVE_TENSOR_MD5_CHECKSUM_FAILURE(t) \
try { \
egr::SaveTensorMD5CheckSumToFile("", t); \
FAIL() << "Expected std::exception"; \
} catch (const std::exception& e) { \
std::string error_str = e.what(); \
EXPECT_NE(error_str.find("Cannot open file for writing."), \
std::string::npos); \
} catch (...) { \
FAIL() << "Unexpected error"; \
}
#define EXPECT_SAVE_TENSOR_MD5_CHECKSUM_SUCCESS(t) \
try { \
egr::SaveTensorMD5CheckSumToFile("test_md5_checksum.txt", t); \
} catch (const std::exception& e) { \
FAIL() << "Unexpected error: " << e.what(); \
} catch (...) { \
FAIL() << "Unexpected error"; \
}
// Test the invalid file name
phi::DDim ddim = common::make_ddim({20, 40});
paddle::Tensor t = CreateTestCPUTensor(1.0f, ddim);
EXPECT_SAVE_TENSOR_MD5_CHECKSUM_FAILURE(t)
paddle::optional<paddle::Tensor> optional_t;
optional_t = CreateTestCPUTensor<double>(1.0, ddim);
EXPECT_SAVE_TENSOR_MD5_CHECKSUM_FAILURE(optional_t)
// Test the vector input
std::vector<paddle::Tensor> tensors = {CreateTestCPUTensor<int64_t>(1, ddim),
CreateTestCPUTensor<int64_t>(1, ddim)};
EXPECT_SAVE_TENSOR_MD5_CHECKSUM_FAILURE(tensors)
paddle::optional<std::vector<paddle::Tensor>> opt_tensors =
std::vector<paddle::Tensor>{CreateTestCPUTensor<bool>(true, ddim),
CreateTestCPUTensor<bool>(false, ddim)};
EXPECT_SAVE_TENSOR_MD5_CHECKSUM_FAILURE(opt_tensors)
// test the different data type
EXPECT_SAVE_TENSOR_MD5_CHECKSUM_FAILURE(CreateTestCPUTensor<int>(1, ddim))
EXPECT_SAVE_TENSOR_MD5_CHECKSUM_FAILURE(
CreateTestCPUTensor<phi::float16>(static_cast<phi::float16>(1), ddim))
EXPECT_SAVE_TENSOR_MD5_CHECKSUM_FAILURE(
CreateTestCPUTensor<int32_t>(static_cast<int32_t>(1), ddim))
paddle::Tensor complex64_t =
CreateTestCPUTensor(phi::complex64(1.0f, 2.0f), ddim);
paddle::Tensor complex128_t =
CreateTestCPUTensor(phi::complex128(1.0f, 2.0f), ddim);
#if defined(PADDLE_WITH_CUDA)
EXPECT_SAVE_TENSOR_MD5_CHECKSUM_FAILURE(
CreateTestCPUTensor<phi::bfloat16>(static_cast<phi::bfloat16>(1), ddim))
EXPECT_SAVE_TENSOR_MD5_CHECKSUM_FAILURE(
CreateTestCPUTensor<phi::float8_e4m3fn>(
static_cast<phi::float8_e4m3fn>(1), ddim))
EXPECT_SAVE_TENSOR_MD5_CHECKSUM_FAILURE(CreateTestCPUTensor<phi::float8_e5m2>(
static_cast<phi::float8_e5m2>(1), ddim))
#endif
#ifndef _WIN32
// test save to file
EXPECT_SAVE_TENSOR_MD5_CHECKSUM_SUCCESS(t)
EXPECT_SAVE_TENSOR_MD5_CHECKSUM_SUCCESS(optional_t)
EXPECT_SAVE_TENSOR_MD5_CHECKSUM_SUCCESS(tensors)
EXPECT_SAVE_TENSOR_MD5_CHECKSUM_SUCCESS(opt_tensors)
EXPECT_SAVE_TENSOR_MD5_CHECKSUM_SUCCESS(complex64_t)
EXPECT_SAVE_TENSOR_MD5_CHECKSUM_SUCCESS(complex128_t)
// test using binary format
FLAGS_tensor_md5_checksum_use_binary_format = true;
EXPECT_SAVE_TENSOR_MD5_CHECKSUM_SUCCESS(t)
EXPECT_SAVE_TENSOR_MD5_CHECKSUM_SUCCESS(optional_t)
EXPECT_SAVE_TENSOR_MD5_CHECKSUM_SUCCESS(tensors)
EXPECT_SAVE_TENSOR_MD5_CHECKSUM_SUCCESS(opt_tensors)
EXPECT_SAVE_TENSOR_MD5_CHECKSUM_SUCCESS(complex64_t)
EXPECT_SAVE_TENSOR_MD5_CHECKSUM_SUCCESS(complex128_t)
// test Fake dist tensor
t.set_impl(std::make_shared<phi::distributed::DistTensor>());
EXPECT_SAVE_TENSOR_MD5_CHECKSUM_SUCCESS(t)
#endif
}
} // namespace egr
@@ -0,0 +1,362 @@
// 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.
#include <sstream>
#include "glog/logging.h"
#include "gtest/gtest.h"
#include "paddle/fluid/eager/api/all.h"
#include "paddle/fluid/eager/api/generated/eager_generated/backwards/scale_node.h"
#include "paddle/fluid/eager/autograd_meta.h"
#include "paddle/fluid/eager/grad_node_info.h"
#include "paddle/phi/core/dense_tensor.h"
#include "paddle/phi/core/kernel_registry.h"
#include "paddle/phi/core/tensor_meta.h"
#include "test/cpp/eager/test_utils.h"
PD_DECLARE_KERNEL(full, CPU, ALL_LAYOUT);
namespace egr {
TEST(Forward, SingleNode) {
// Prepare Device Contexts
eager_test::InitEnv(phi::CPUPlace());
// Prepare Inputs
std::vector<paddle::Tensor> target_tensors;
phi::DDim ddim = common::make_ddim({4, 16, 16, 32});
// Create Target Tensor
paddle::Tensor t = eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
5.0 /*value*/,
false /*is_leaf*/);
target_tensors.emplace_back(std::move(t));
paddle::Tensor& tensor = target_tensors[0];
EagerUtils::autograd_meta(&tensor)->SetStopGradient(false);
// Run Forward
float scale = 2.0;
float bias = 3.0;
paddle::Tensor out = egr::scale(
tensor, scale, bias, true /*bias_after_scale*/, true /*trace_backward*/);
// Examine Forward Output
eager_test::CompareTensorWithValue<float>(out, 13.0);
// Examine GradNode
{
// 1. GradNode
AutogradMeta* meta = EagerUtils::autograd_meta(&out);
GradNodeBase* grad_node = meta->GradNode();
GradNodeScale* scale_node = dynamic_cast<GradNodeScale*>(grad_node);
CHECK_NOTNULL(scale_node);
PADDLE_ENFORCE_EQ(
static_cast<int>(meta->OutRankInfo().first),
0,
common::errors::InvalidArgument(
"static_cast<int>(meta->OutRankInfo().first) is not 0"));
PADDLE_ENFORCE_EQ(
static_cast<int>(meta->OutRankInfo().second),
0,
common::errors::InvalidArgument(
"static_cast<int>(meta->OutRankInfo().second) is not 0"));
}
}
/*
inp
|
Node0
|
Node1
|
out
*/
TEST(Forward, LinearNodes) {
eager_test::InitEnv(phi::CPUPlace());
// Prepare Inputs
std::vector<paddle::Tensor> target_tensors;
phi::DDim ddim = common::make_ddim({4, 16, 16, 32});
// Create Target Tensor
paddle::Tensor t = eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
5.0 /*value*/,
false /*is_leaf*/);
target_tensors.emplace_back(std::move(t));
paddle::Tensor& tensor = target_tensors[0];
EagerUtils::autograd_meta(&tensor)->SetStopGradient(false);
// Run Forward Node 0
float scale0 = 2.0;
float bias0 = 3.0;
paddle::Tensor out0 = egr::scale(tensor,
scale0,
bias0,
true /*bias_after_scale*/,
true /*trace_backward*/);
// Run Forward Node 1
float scale1 = 5.0;
float bias1 = 10.0;
paddle::Tensor out1 = egr::scale(
out0, scale1, bias1, true /*bias_after_scale*/, true /*trace_backward*/);
// Examine Forward Output 0
eager_test::CompareTensorWithValue<float>(out0, 13.0);
// Examine Forward Output 1
eager_test::CompareTensorWithValue<float>(out1, 75.0);
// Examine GradNode
{
// 1. GradNode
// Node 0
AutogradMeta* meta0 = EagerUtils::autograd_meta(&out0);
GradNodeBase* grad_node0 = meta0->GradNode();
GradNodeScale* scale_node0 = dynamic_cast<GradNodeScale*>(grad_node0);
CHECK_NOTNULL(scale_node0);
PADDLE_ENFORCE_EQ(
static_cast<int>(meta0->OutRankInfo().first),
0,
common::errors::InvalidArgument(
"static_cast<int>(meta0->OutRankInfo().first) is not 0"));
PADDLE_ENFORCE_EQ(
static_cast<int>(meta0->OutRankInfo().second),
0,
common::errors::InvalidArgument(
"static_cast<int>(meta0->OutRankInfo().second) is not 0"));
// Node 1
AutogradMeta* meta1 = EagerUtils::autograd_meta(&out1);
GradNodeBase* grad_node1 = meta1->GradNode();
GradNodeScale* scale_node1 = dynamic_cast<GradNodeScale*>(grad_node1);
CHECK_NOTNULL(scale_node1);
PADDLE_ENFORCE_EQ(
static_cast<int>(meta1->OutRankInfo().first),
0,
common::errors::InvalidArgument(
"static_cast<int>(meta1->OutRankInfo().first) is not 0"));
PADDLE_ENFORCE_EQ(
static_cast<int>(meta1->OutRankInfo().second),
0,
common::errors::InvalidArgument(
"static_cast<int>(meta1->OutRankInfo().second) is not 0"));
// 2. TensorWrapper: No TensorWrapper for ScaleNode
// 3. NextEdges: Node 1 -> Node 0
const paddle::small_vector<std::vector<GradSlotMeta>,
egr::kSlotSmallVectorSize>& node1_metas =
grad_node1->OutputMeta();
const auto& node1_meta = node1_metas[0];
PADDLE_ENFORCE_EQ(
static_cast<int>(node1_meta[0].GetEdge().GetEdgeRankInfo().first),
0,
common::errors::InvalidArgument(
"static_cast<int>(node1_meta[0].GetEdge().GetEdgeRankInfo().first)"
"is not 0"));
PADDLE_ENFORCE_EQ(
static_cast<int>(node1_meta[0].GetEdge().GetEdgeRankInfo().second),
0,
common::errors::InvalidArgument(
"static_cast<int>(node1_meta[0].GetEdge().GetEdgeRankInfo().second)"
"is not 0"));
PADDLE_ENFORCE_EQ(node1_meta[0].GetEdge().GetGradNode(),
grad_node0,
common::errors::InvalidArgument(
"node1_meta[0].GetEdge().GetGradNode() "
"is not equal with grad_node0, "
"the value of grad_node0 is %d "
"and node1_meta[0].GetEdge().GetGradNode() is %d",
grad_node0,
node1_meta[0].GetEdge().GetGradNode()));
}
}
/*
inp
|
Node0
____|____
| |
Node1 Node2
| |
out1 out2
*/
TEST(Forward, BranchedNodes) {
eager_test::InitEnv(phi::CPUPlace());
// Prepare Inputs
std::vector<paddle::Tensor> target_tensors;
phi::DDim ddim = common::make_ddim({4, 16, 16, 32});
// Create Target Tensor
paddle::Tensor t = eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
5.0 /*value*/,
false /*is_leaf*/);
target_tensors.emplace_back(std::move(t));
paddle::Tensor& tensor = target_tensors[0];
EagerUtils::autograd_meta(&tensor)->SetStopGradient(false);
// Run Forward Node 0
float scale0 = 2.0;
float bias0 = 3.0;
paddle::Tensor out0 = egr::scale(tensor,
scale0,
bias0,
true /*bias_after_scale*/,
true /*trace_backward*/);
// Run Forward Node 1
float scale1 = 5.0;
float bias1 = 10.0;
paddle::Tensor out1 = egr::scale(
out0, scale1, bias1, true /*bias_after_scale*/, true /*trace_backward*/);
// Run Forward Node 2
float scale2 = 10.0;
float bias2 = 20.0;
paddle::Tensor out2 = egr::scale(
out0, scale2, bias2, true /*bias_after_scale*/, true /*trace_backward*/);
// Examine Forward Output 0
eager_test::CompareTensorWithValue<float>(out0, 13.0);
// Examine Forward Output 1
eager_test::CompareTensorWithValue<float>(out1, 75.0);
// Examine Forward Output 2
eager_test::CompareTensorWithValue<float>(out2, 150.0);
// Examine GradNode
{
// 1. GradNode
// Node 0
AutogradMeta* meta0 = EagerUtils::autograd_meta(&out0);
GradNodeBase* grad_node0 = meta0->GradNode();
GradNodeScale* scale_node0 = dynamic_cast<GradNodeScale*>(grad_node0);
CHECK_NOTNULL(scale_node0);
PADDLE_ENFORCE_EQ(
static_cast<int>(meta0->OutRankInfo().first),
0,
common::errors::InvalidArgument(
"static_cast<int>(meta0->OutRankInfo().first) is not 0"));
PADDLE_ENFORCE_EQ(
static_cast<int>(meta0->OutRankInfo().second),
0,
common::errors::InvalidArgument(
"static_cast<int>(meta0->OutRankInfo().second) is not 0"));
// Node 1
AutogradMeta* meta1 = EagerUtils::autograd_meta(&out1);
GradNodeBase* grad_node1 = meta1->GradNode();
GradNodeScale* scale_node1 = dynamic_cast<GradNodeScale*>(grad_node1);
CHECK_NOTNULL(scale_node1);
PADDLE_ENFORCE_EQ(
static_cast<int>(meta1->OutRankInfo().first),
0,
common::errors::InvalidArgument(
"static_cast<int>(meta1->OutRankInfo().first) is not 0"));
PADDLE_ENFORCE_EQ(
static_cast<int>(meta1->OutRankInfo().second),
0,
common::errors::InvalidArgument(
"static_cast<int>(meta1->OutRankInfo().second) is not 0"));
// Node 2
AutogradMeta* meta2 = EagerUtils::autograd_meta(&out2);
GradNodeBase* grad_node2 = meta2->GradNode();
GradNodeScale* scale_node2 = dynamic_cast<GradNodeScale*>(grad_node2);
CHECK_NOTNULL(scale_node2);
PADDLE_ENFORCE_EQ(
static_cast<int>(meta2->OutRankInfo().first),
0,
common::errors::InvalidArgument(
"static_cast<int>(meta2->OutRankInfo().first) is not 0"));
PADDLE_ENFORCE_EQ(
static_cast<int>(meta2->OutRankInfo().second),
0,
common::errors::InvalidArgument(
"static_cast<int>(meta2->OutRankInfo().second) is not 0"));
// 2. TensorWrapper: No TensorWrapper for ScaleNode
// 3. NextEdges
// Node 1 -> Node 0
const paddle::small_vector<std::vector<GradSlotMeta>, kSlotSmallVectorSize>&
node1_metas = grad_node1->OutputMeta();
const Edge& node1_edge = node1_metas[0][0].GetEdge();
PADDLE_ENFORCE_EQ(
static_cast<int>(node1_edge.GetEdgeRankInfo().first),
0,
common::errors::InvalidArgument(
"static_cast<int>(node1_edge.GetEdgeRankInfo().first) is not 0"));
PADDLE_ENFORCE_EQ(
static_cast<int>(node1_edge.GetEdgeRankInfo().second),
0,
common::errors::InvalidArgument(
"static_cast<int>(node1_edge.GetEdgeRankInfo().second) is not 0"));
PADDLE_ENFORCE_EQ(
node1_edge.GetGradNode(),
grad_node0,
common::errors::InvalidArgument(
"node1_edge.GetGradNode() is not equal with grad_node0"
"the value of node1_edge.GetGradNode() is %d and grad_node0 is %d",
node1_edge.GetGradNode(),
grad_node0));
// Node 2 -> Node 0
const paddle::small_vector<std::vector<egr::GradSlotMeta>,
egr::kSlotSmallVectorSize>& node2_metas =
grad_node2->OutputMeta();
const Edge& node2_edge = node2_metas[0][0].GetEdge();
PADDLE_ENFORCE_EQ(
static_cast<int>(node2_edge.GetEdgeRankInfo().first),
0,
common::errors::InvalidArgument(
"static_cast<int>(node2_edge.GetEdgeRankInfo().first) is not 0"));
PADDLE_ENFORCE_EQ(
static_cast<int>(node2_edge.GetEdgeRankInfo().second),
0,
common::errors::InvalidArgument(
"static_cast<int>(node2_edge.GetEdgeRankInfo().second) is not 0"));
PADDLE_ENFORCE_EQ(
node2_edge.GetGradNode(),
grad_node0,
common::errors::InvalidArgument(
"node2_edge.GetGradNode() is not equal with grad_node0"
"the value of node2_edge.GetGradNode() is %d and grad_node0 is %d",
node2_edge.GetGradNode(),
grad_node0));
}
}
} // namespace egr
@@ -0,0 +1,457 @@
// 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.
#include <sstream>
#include "glog/logging.h"
#include "gtest/gtest.h"
#include "paddle/fluid/eager/accumulation/accumulation_node.h"
#include "paddle/fluid/eager/api/all.h"
#include "paddle/fluid/eager/api/generated/eager_generated/backwards/scale_node.h"
#include "paddle/fluid/eager/autograd_meta.h"
#include "paddle/fluid/eager/backward.h"
#include "paddle/fluid/eager/grad_node_info.h"
#include "paddle/fluid/eager/hooks.h"
#include "paddle/phi/core/dense_tensor.h"
#include "paddle/phi/core/kernel_registry.h"
#include "paddle/phi/core/tensor_meta.h"
#include "test/cpp/eager/test_utils.h"
PD_DECLARE_KERNEL(full, CPU, ALL_LAYOUT);
PD_DECLARE_KERNEL(add, CPU, ALL_LAYOUT);
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
PD_DECLARE_KERNEL(full, GPU, ALL_LAYOUT);
PD_DECLARE_KERNEL(add, KPS, ALL_LAYOUT);
#endif
namespace egr {
paddle::Tensor hook_function(const paddle::Tensor& t) {
auto t_dense = std::dynamic_pointer_cast<phi::DenseTensor>(t.impl());
auto ret_meta = phi::DenseTensorMeta(
t_dense->dtype(), t_dense->dims(), t_dense->layout());
auto place = t_dense->place();
size_t bytes_size =
common::product(t_dense->dims()) * SizeOf(t_dense->dtype());
auto ret_dense = std::make_shared<phi::DenseTensor>(
paddle::memory::Alloc(place, bytes_size), std::move(ret_meta));
float* t_ptr = t_dense->mutable_data<float>(place);
float* ret_ptr = ret_dense->mutable_data<float>(place);
for (int i = 0; i < ret_dense->numel(); i++) {
ret_ptr[i] = t_ptr[i] + 5.0f;
}
auto ret_impl = std::dynamic_pointer_cast<phi::TensorBase>(ret_dense);
paddle::Tensor ret = paddle::Tensor();
ret.set_impl(ret_impl);
return ret;
}
TEST(FwdBwdJoint, SingleNode) {
eager_test::InitEnv(phi::CPUPlace());
// 1. Prepare Input
phi::DDim ddim = common::make_ddim({4, 16, 16, 32});
paddle::Tensor tensor =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
5.0 /*value*/,
true /*is_leaf*/);
egr_utils_api::RetainGradForTensor(tensor);
// 3. Run Forward
float scale = 2.0;
float bias = 3.0;
paddle::Tensor out = egr::scale(
tensor, scale, bias, true /*bias_after_scale*/, true /*trace_backward*/);
// Examine Forward Output
eager_test::CompareTensorWithValue<float>(out, 13.0);
std::vector<paddle::Tensor> outs = {out};
// 4. Run Backward
Backward(outs, {});
VLOG(7) << "Target Grad is: "
<< std::static_pointer_cast<phi::DenseTensor>(
EagerUtils::unsafe_autograd_meta(tensor)->Grad().impl())
->data<float>()[0];
// Examine Backward Grad
eager_test::CompareGradTensorWithValue<float>(tensor, 2.0);
}
/*
inp
|
Node0
|
Node1
|
out
*/
TEST(FwdBwdJoint, LinearNodes) {
eager_test::InitEnv(phi::CPUPlace());
// 1. Prepare Input
phi::DDim ddim = common::make_ddim({4, 16, 16, 32});
paddle::Tensor tensor =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
5.0 /*value*/,
true /*is_leaf*/);
egr_utils_api::RetainGradForTensor(tensor);
// 3. Run Forward
// Run Forward Node 0
float scale0 = 2.0;
float bias0 = 3.0;
paddle::Tensor out0 = egr::scale(tensor,
scale0,
bias0,
true /*bias_after_scale*/,
true /*trace_backward*/);
// Run Forward Node 1
float scale1 = 5.0;
float bias1 = 10.0;
paddle::Tensor out1 = egr::scale(
out0, scale1, bias1, true /*bias_after_scale*/, true /*trace_backward*/);
// Examine Forward Output 0
eager_test::CompareTensorWithValue<float>(out0, 13.0);
// Examine Forward Output 1
eager_test::CompareTensorWithValue<float>(out1, 75.0);
std::vector<paddle::Tensor> outs = {out1};
// 4. Run Backward
Backward(outs, {});
// Examine Backward Grad
eager_test::CompareGradTensorWithValue<float>(tensor, 10.0);
}
/*
inp
|
Node0
____|____
| |
Node1 Node2
| |
out1 out2
*/
TEST(FwdBwdJoint, BranchedNodes) {
eager_test::InitEnv(phi::CPUPlace());
// 1. Prepare Input
phi::DDim ddim = common::make_ddim({4, 16, 16, 32});
paddle::Tensor tensor =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
5.0 /*value*/,
true /*is_leaf*/);
egr_utils_api::RetainGradForTensor(tensor);
// 3. Run Forward
// Run Forward Node 0
float scale0 = 2.0;
float bias0 = 3.0;
paddle::Tensor out0 = egr::scale(tensor,
scale0,
bias0,
true /*bias_after_scale*/,
true /*trace_backward*/);
// Run Forward Node 1
float scale1 = 5.0;
float bias1 = 10.0;
paddle::Tensor out1 = egr::scale(
out0, scale1, bias1, true /*bias_after_scale*/, true /*trace_backward*/);
// Run Forward Node 2
float scale2 = 10.0;
float bias2 = 20.0;
paddle::Tensor out2 = egr::scale(
out0, scale2, bias2, true /*bias_after_scale*/, true /*trace_backward*/);
// Examine Forward Output 0
eager_test::CompareTensorWithValue<float>(out0, 13.0);
// Examine Forward Output 1
eager_test::CompareTensorWithValue<float>(out1, 75.0);
// Examine Forward Output 2
{
auto dense_out = std::dynamic_pointer_cast<phi::DenseTensor>(out2.impl());
float* ptr = dense_out->mutable_data<float>(phi::CPUPlace());
for (int i = 0; i < 20; i++) {
PADDLE_ENFORCE(ptr[i] == 150.0,
common::errors::Fatal(
"Detected numerical Error, Expected %f but got %f",
150.0,
ptr[i]));
}
}
// 4. Run Backward
std::vector<paddle::Tensor> outs = {out1, out2};
Backward(outs, {});
// Examine Backward Grad
eager_test::CompareGradTensorWithValue<float>(tensor, 30.0);
}
/*
inp
|
Node0
____|____
| |
Node1 Node2
| |
out1 out2
*/
TEST(FwdBwdJoint, GradientHook) {
eager_test::InitEnv(phi::CPUPlace());
// 1. Prepare Input
phi::DDim ddim = common::make_ddim({4, 16, 16, 32});
paddle::Tensor tensor =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
5.0 /*value*/,
true /*is_leaf*/);
egr_utils_api::RetainGradForTensor(tensor);
// 3. Run Forward
// Run Forward Node 0
float scale0 = 2.0;
float bias0 = 3.0;
paddle::Tensor out0 = egr::scale(tensor,
scale0,
bias0,
true /*bias_after_scale*/,
true /*trace_backward*/);
egr_utils_api::RetainGradForTensor(out0); // hook: +5
egr_utils_api::RegisterGradientHookForTensor(out0,
hook_function); // hook: +5
// Run Forward Node 1
float scale1 = 5.0;
float bias1 = 10.0;
paddle::Tensor out1 = egr::scale(
out0, scale1, bias1, true /*bias_after_scale*/, true /*trace_backward*/);
egr_utils_api::RetainGradForTensor(out1); // hook: +5
egr_utils_api::RegisterGradientHookForTensor(out1,
hook_function); // hook: +5
// Run Forward Node 2
float scale2 = 10.0;
float bias2 = 20.0;
paddle::Tensor out2 = egr::scale(
out0, scale2, bias2, true /*bias_after_scale*/, true /*trace_backward*/);
egr_utils_api::RetainGradForTensor(out2); // hook: +5
egr_utils_api::RegisterGradientHookForTensor(out2,
hook_function); // hook: +5
// 4. Run Backward
std::vector<paddle::Tensor> outs = {out1, out2};
Backward(outs, {});
// Examine Backward Grad
// leaf grad
eager_test::CompareGradTensorWithValue<float>(tensor, 190.0);
// out0 grad
eager_test::CompareGradTensorWithValue<float>(out0, 90.0);
// out1 grad
eager_test::CompareGradTensorWithValue<float>(out1, 1.0);
// out2 grad
eager_test::CompareGradTensorWithValue<float>(out2, 1.0);
}
/*
inp
|
Node0
____|____
| |
Node1 Node2
| |
out1 out2
*/
TEST(FwdBwdJoint, CrossBatchAccumulation) {
eager_test::InitEnv(phi::CPUPlace());
// 1. Prepare Input
phi::DDim ddim = common::make_ddim({4, 16, 16, 32});
paddle::Tensor tensor =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
5.0 /*value*/,
true /*is_leaf*/);
egr_utils_api::RetainGradForTensor(tensor);
// 3. Run Forward
// Run Forward Node 0
float scale0 = 2.0;
float bias0 = 3.0;
paddle::Tensor out0 = egr::scale(tensor,
scale0,
bias0,
true /*bias_after_scale*/,
true /*trace_backward*/);
// Run Forward Node 1
float scale1 = 5.0;
float bias1 = 10.0;
paddle::Tensor out1 = egr::scale(
out0, scale1, bias1, true /*bias_after_scale*/, true /*trace_backward*/);
// Run Forward Node 2
float scale2 = 10.0;
float bias2 = 20.0;
paddle::Tensor out2 = egr::scale(
out0, scale2, bias2, true /*bias_after_scale*/, true /*trace_backward*/);
// 4. Run Backward
std::vector<paddle::Tensor> outs = {out1, out2};
Backward(outs, {});
// Examine Backward Grad
eager_test::CompareGradTensorWithValue<float>(tensor, 30.0);
// Cross Batch Accumulation
Backward(outs, {});
// Examine Backward Grad
eager_test::CompareGradTensorWithValue<float>(tensor, 60.0);
}
/* ---------------------------------------------------- */
/* ---------------------- CUDA Tests ------------------ */
/* ---------------------------------------------------- */
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
TEST(FwdBwdJoint, SingleNodeCUDA) {
eager_test::InitEnv(phi::GPUPlace());
// 1. Prepare Input
phi::DDim ddim = common::make_ddim({4, 16, 16, 32});
paddle::Tensor tensor =
eager_test::CreateTensorWithValue(ddim,
phi::GPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
5.0 /*value*/,
true /*is_leaf*/);
egr_utils_api::RetainGradForTensor(tensor);
// 3. Run Forward
float scale = 2.0;
float bias = 3.0;
paddle::Tensor out = egr::scale(
tensor, scale, bias, true /*bias_after_scale*/, true /*trace_backward*/);
// Examine Forward Output
eager_test::CompareTensorWithValue<float>(out, 13.0);
std::vector<paddle::Tensor> outs = {out};
// 4. Run Backward
Backward(outs, {});
// Examine Backward Grad
eager_test::CompareGradTensorWithValue<float>(tensor, 2.0);
}
/*
inp
|
Node0
____|____
| |
Node1 Node2
| |
out1 out2
*/
TEST(FwdBwdJoint, BranchedNodesCUDA) {
eager_test::InitEnv(phi::GPUPlace());
// 1. Prepare Input
phi::DDim ddim = common::make_ddim({4, 16, 16, 32});
paddle::Tensor tensor =
eager_test::CreateTensorWithValue(ddim,
phi::GPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
5.0 /*value*/,
true /*is_leaf*/);
egr_utils_api::RetainGradForTensor(tensor);
// 3. Run Forward
// Run Forward Node 0
float scale0 = 2.0;
float bias0 = 3.0;
paddle::Tensor out0 = egr::scale(tensor,
scale0,
bias0,
true /*bias_after_scale*/,
true /*trace_backward*/);
// Run Forward Node 1
float scale1 = 5.0;
float bias1 = 10.0;
paddle::Tensor out1 = egr::scale(
out0, scale1, bias1, true /*bias_after_scale*/, true /*trace_backward*/);
// Run Forward Node 2
float scale2 = 10.0;
float bias2 = 20.0;
paddle::Tensor out2 = egr::scale(
out0, scale2, bias2, true /*bias_after_scale*/, true /*trace_backward*/);
// Examine Forward Output 0
eager_test::CompareTensorWithValue<float>(out0, 13.0);
// Examine Forward Output 1
eager_test::CompareTensorWithValue<float>(out1, 75.0);
// Examine Forward Output 2
eager_test::CompareTensorWithValue<float>(out2, 150.0);
// TODO(jiabin): fix this with add functor
// 4. Run Backward
std::vector<paddle::Tensor> outs = {out1, out2};
Backward(outs, {});
// Examine Backward Grad
eager_test::CompareGradTensorWithValue<float>(tensor, 30.0);
}
#endif
} // namespace egr
+141
View File
@@ -0,0 +1,141 @@
// 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.
// Eager Dygraph
#include <chrono>
#include "gtest/gtest.h"
#include "paddle/fluid/eager/api/all.h"
#include "paddle/fluid/eager/api/generated/fluid_generated/dygraph_forward_api.h"
#include "paddle/fluid/eager/autograd_meta.h"
#include "paddle/fluid/eager/backward.h"
#include "paddle/fluid/eager/utils.h"
#include "paddle/fluid/imperative/tracer.h"
#include "paddle/phi/core/kernel_registry.h"
#include "test/cpp/eager/test_utils.h"
PD_DECLARE_KERNEL(full, CPU, ALL_LAYOUT);
PD_DECLARE_KERNEL(matmul, CPU, ALL_LAYOUT);
PD_DECLARE_KERNEL(matmul_grad, CPU, ALL_LAYOUT);
PD_DECLARE_KERNEL(add, CPU, ALL_LAYOUT);
PD_DECLARE_KERNEL(add_grad, CPU, ALL_LAYOUT);
namespace egr {
TEST(Generated, Sigmoid) {
// Prepare Device Contexts
eager_test::InitEnv(phi::CPUPlace());
VLOG(6) << "Init Env";
// 1. Prepare Input
phi::DDim ddim = common::make_ddim({2, 4, 4, 4});
VLOG(6) << "Make Dim";
paddle::Tensor tensor =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
0.0,
true);
VLOG(6) << "Make paddle::Tensor";
egr_utils_api::RetainGradForTensor(tensor);
VLOG(6) << "Retain Grad for Tensor";
auto output_tensor = sigmoid_dygraph_function(tensor, {});
VLOG(6) << "Run Backward";
eager_test::CompareTensorWithValue<float>(output_tensor, 0.5);
std::vector<paddle::Tensor> target_tensors = {output_tensor};
VLOG(6) << "Running Backward";
Backward(target_tensors, {});
VLOG(6) << "Finish Backward";
eager_test::CompareGradTensorWithValue<float>(tensor, 0.25);
}
TEST(Generated, Matmul_v2) {
// Prepare Device Contexts
eager_test::InitEnv(phi::CPUPlace());
auto tracer = std::make_shared<paddle::imperative::Tracer>();
paddle::imperative::SetCurrentTracer(tracer);
// 1. Prepare Input
phi::DDim ddimX = common::make_ddim({4, 16});
paddle::Tensor X = eager_test::CreateTensorWithValue(ddimX,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
3.0,
true);
egr_utils_api::RetainGradForTensor(X);
phi::DDim ddimY = common::make_ddim({16, 20});
paddle::Tensor Y = eager_test::CreateTensorWithValue(ddimY,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
2.0,
true);
egr_utils_api::RetainGradForTensor(Y);
auto output_tensor = matmul_v2_dygraph_function(
X, Y, {{"trans_x", false}, {"trans_y", false}});
eager_test::CompareTensorWithValue<float>(output_tensor, 96);
std::vector<paddle::Tensor> target_tensors = {output_tensor};
Backward(target_tensors, {});
eager_test::CompareGradTensorWithValue<float>(X, 2.0 * 20);
eager_test::CompareGradTensorWithValue<float>(Y, 3.0 * 4);
}
TEST(Generated, ElementwiseAdd) {
// Prepare Device Contexts
eager_test::InitEnv(phi::CPUPlace());
auto tracer = std::make_shared<paddle::imperative::Tracer>();
paddle::imperative::SetCurrentTracer(tracer);
// 1. Prepare Input
phi::DDim ddimX = common::make_ddim({4, 16});
paddle::Tensor X = eager_test::CreateTensorWithValue(ddimX,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
3.0,
true);
egr_utils_api::RetainGradForTensor(X);
phi::DDim ddimY = common::make_ddim({4, 16});
paddle::Tensor Y = eager_test::CreateTensorWithValue(ddimY,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
2.0,
true);
egr_utils_api::RetainGradForTensor(Y);
auto output_tensor = elementwise_add_dygraph_function(X, Y, {});
eager_test::CompareTensorWithValue<float>(output_tensor, 5);
std::vector<paddle::Tensor> target_tensors = {output_tensor};
Backward(target_tensors, {});
eager_test::CompareGradTensorWithValue<float>(X, 1.0);
eager_test::CompareGradTensorWithValue<float>(Y, 1.0);
}
} // namespace egr
+371
View File
@@ -0,0 +1,371 @@
// 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.
#include <sstream>
#include "glog/logging.h"
#include "gtest/gtest.h"
#include "paddle/fluid/eager/accumulation/accumulation_node.h"
#include "paddle/fluid/eager/api/all.h"
#include "paddle/fluid/eager/api/generated/eager_generated/backwards/scale_node.h"
#include "paddle/fluid/eager/autograd_meta.h"
#include "paddle/fluid/eager/backward.h"
#include "paddle/fluid/eager/grad_node_info.h"
#include "paddle/phi/core/dense_tensor.h"
#include "paddle/phi/core/kernel_registry.h"
#include "paddle/phi/core/tensor_meta.h"
#include "test/cpp/eager/test_utils.h"
PD_DECLARE_KERNEL(full, CPU, ALL_LAYOUT);
PD_DECLARE_KERNEL(add, CPU, ALL_LAYOUT);
namespace egr {
TEST(Grad, SingleNodeEmptyGrad) {
// Prepare Device Contexts
eager_test::InitEnv(phi::CPUPlace());
// Prepare Inputs
phi::DDim ddim = common::make_ddim({4, 16, 16, 32});
// Create Target Tensor (output)
paddle::Tensor output_tensor =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
1.0 /*value*/,
false /*is_leaf*/);
// Create input tensor
const paddle::Tensor leaf_tensor =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
1.0 /*value*/,
true /*is_leaf*/);
{
// Create Scale Node
auto node0_ptr = std::make_shared<GradNodeScale>(1, 1);
node0_ptr->SetAttributes_scale(5.0 /*scale*/);
// Set grad in/out meta
node0_ptr->SetDefaultGradInOutMeta();
// Output_tensor set GradNode、OutRank、StopGradient properties
AutogradMeta* auto_grad_meta = EagerUtils::autograd_meta(&output_tensor);
auto_grad_meta->SetGradNode(
std::dynamic_pointer_cast<GradNodeBase>(node0_ptr));
auto_grad_meta->SetSingleOutRankWithSlot(0, 0);
auto_grad_meta->SetStopGradient(false);
// Get autograd_meta from input tensor
AutogradMeta* auto_grad_meta1 =
EagerUtils::unsafe_autograd_meta(leaf_tensor);
// Connect Tensor and AccumulationNode via AutoGradMeta
auto acc_node_ptr =
std::make_shared<egr::GradNodeAccumulation>(leaf_tensor);
// input tensor set GradNode、OutRank、StopGradient properties
auto_grad_meta1->SetGradNode(
std::dynamic_pointer_cast<GradNodeBase>(acc_node_ptr));
auto_grad_meta1->SetSingleOutRankWithSlot(0, 0);
auto_grad_meta1->SetStopGradient(false);
// grad_node Add Edges
std::vector<egr::AutogradMeta*> res = {auto_grad_meta1};
node0_ptr->SetGradOutMeta(leaf_tensor, 0);
}
std::vector<paddle::Tensor> outs = {output_tensor};
// Run Grad
auto result = Grad(outs, {leaf_tensor}, {});
// Check Output Value
eager_test::CompareTensorWithValue<float>(result[0], 5.0);
}
TEST(Grad, SingleNodeCustomGrad) {
// Prepare Device Contexts
eager_test::InitEnv(phi::CPUPlace());
// Prepare Inputs
std::vector<paddle::Tensor> target_tensors;
phi::DDim ddim = common::make_ddim({4, 16, 16, 32});
// Create Target Tensor
paddle::Tensor tensor =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
1.0 /*value*/,
false /*is_leaf*/);
target_tensors.emplace_back(std::move(tensor));
std::vector<paddle::Tensor> grad_tensors;
// Create Grad Tensor
paddle::Tensor grad_tensor =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
10.0 /*value*/,
false /*is_leaf*/);
grad_tensors.emplace_back(std::move(grad_tensor));
paddle::Tensor leaf_tensor =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
1.0 /*value*/,
true /*is_leaf*/);
{
// Create Scale Node
auto node0_ptr = std::make_shared<GradNodeScale>(1, 1);
node0_ptr->SetAttributes_scale(5.0 /*scale*/);
// Set grad in/out meta
node0_ptr->SetDefaultGradInOutMeta();
// Connect Tensor and Node via AutoGradMeta
AutogradMeta* auto_grad_meta =
EagerUtils::autograd_meta(&(target_tensors[0]));
auto_grad_meta->SetGradNode(
std::dynamic_pointer_cast<GradNodeBase>(node0_ptr));
auto_grad_meta->SetSingleOutRankWithSlot(0, 0);
auto_grad_meta->SetStopGradient(false);
AutogradMeta* auto_grad_meta1 = EagerUtils::autograd_meta(&leaf_tensor);
// Connect Tensor and AccumulationNode via AutoGradMeta
auto acc_node_ptr =
std::make_shared<egr::GradNodeAccumulation>(leaf_tensor);
auto_grad_meta1->SetGradNode(
std::dynamic_pointer_cast<GradNodeBase>(acc_node_ptr));
auto_grad_meta1->SetSingleOutRankWithSlot(0, 0);
auto_grad_meta1->SetStopGradient(false);
std::vector<egr::AutogradMeta*> res = {auto_grad_meta1};
node0_ptr->SetGradOutMeta(leaf_tensor, 0);
}
auto result = Grad(target_tensors, {leaf_tensor}, grad_tensors);
// Check Output Value
eager_test::CompareTensorWithValue<float>(result[0], 50.0);
}
/*
Node1
|
Node0
|
{ } // empty grad tensor
*/
TEST(Grad, LinearNodes) {
// Prepare Device Contexts
eager_test::InitEnv(phi::CPUPlace());
// Prepare Target Tensor
std::vector<paddle::Tensor> target_tensors;
phi::DDim ddim = common::make_ddim({4, 16, 16, 32});
// Create Target Tensor
paddle::Tensor tensor =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
1.0 /*value*/,
false /*is_leaf*/);
target_tensors.emplace_back(std::move(tensor));
paddle::Tensor leaf_tensor =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
1.0 /*value*/,
true /*is_leaf*/);
{
// Create Node0
auto node0_ptr = std::make_shared<GradNodeScale>(1, 1);
node0_ptr->SetAttributes_scale(5.0 /*scale*/);
// Set grad in/out meta for node0
node0_ptr->SetDefaultGradInOutMeta();
// Create Node1
auto node1_ptr = std::make_shared<GradNodeScale>(1, 1);
node1_ptr->SetAttributes_scale(10.0 /*scale*/);
// Set grad in/out meta for node1
node1_ptr->SetDefaultGradInOutMeta();
// Connect Input Tensor and Node0 via AutoGradMeta
AutogradMeta* auto_grad_meta =
EagerUtils::autograd_meta(&(target_tensors[0]));
auto_grad_meta->SetGradNode(
std::dynamic_pointer_cast<GradNodeBase>(node0_ptr));
auto_grad_meta->SetSingleOutRankWithSlot(0, 0);
auto_grad_meta->SetStopGradient(false);
// Connect Node0 -> Node1 via Edge
auto tmp_tensor = paddle::Tensor();
auto* meta0 = EagerUtils::autograd_meta(&tmp_tensor);
meta0->SetStopGradient(false);
meta0->SetSingleOutRankWithSlot(0, 0);
meta0->SetGradNode(node1_ptr);
node0_ptr->SetGradOutMeta(tmp_tensor, 0);
AutogradMeta* auto_grad_meta1 = EagerUtils::autograd_meta(&leaf_tensor);
// Connect Tensor and AccumulationNode via AutoGradMeta
auto acc_node_ptr =
std::make_shared<egr::GradNodeAccumulation>(leaf_tensor);
auto_grad_meta1->SetGradNode(
std::dynamic_pointer_cast<GradNodeBase>(acc_node_ptr));
auto_grad_meta1->SetSingleOutRankWithSlot(0, 0);
auto_grad_meta1->SetStopGradient(false);
node1_ptr->SetGradOutMeta(leaf_tensor, 0);
}
// Use Empty Grad Tensor
auto result = Grad(target_tensors, {leaf_tensor}, {});
// Check Output Value
eager_test::CompareTensorWithValue<float>(result[0], 50.0);
}
/*
Node2
| |
Node0 Node1
| |
in0 in1
*/
TEST(Grad, WithAccumulation) {
// Prepare Device Contexts
eager_test::InitEnv(phi::CPUPlace());
// Prepare Inputs
phi::DDim ddim = common::make_ddim({4, 16, 16, 32});
// Create Target Tensor
std::vector<paddle::Tensor> target_tensors;
paddle::Tensor tensor0 =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
1.0 /*value*/,
false /*is_leaf*/);
paddle::Tensor tensor1 =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
1.0 /*value*/,
false /*is_leaf*/);
target_tensors.emplace_back(std::move(tensor0));
target_tensors.emplace_back(std::move(tensor1));
// Create Grad Tensor
std::vector<paddle::Tensor> grad_tensors;
paddle::Tensor grad_tensor0 =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
5.0 /*value*/,
false /*is_leaf*/);
paddle::Tensor grad_tensor1 =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
10.0 /*value*/,
false /*is_leaf*/);
grad_tensors.emplace_back(std::move(grad_tensor0));
grad_tensors.emplace_back(std::move(grad_tensor1));
paddle::Tensor leaf_tensor;
{
// Create Node0
auto node0_ptr = std::make_shared<GradNodeScale>(1, 1);
node0_ptr->SetAttributes_scale(5.0 /*scale*/);
node0_ptr->SetDefaultGradInOutMeta();
// Create Node1
auto node1_ptr = std::make_shared<GradNodeScale>(1, 1);
node1_ptr->SetAttributes_scale(10.0 /*scale*/);
node1_ptr->SetDefaultGradInOutMeta();
// Create Node2
auto node2_ptr = std::make_shared<GradNodeScale>(1, 1);
node2_ptr->SetAttributes_scale(20.0 /*scale*/);
node2_ptr->SetDefaultGradInOutMeta();
// Connect Inp0 and Node0 via AutoGradMeta
AutogradMeta* auto_grad_meta0 =
EagerUtils::autograd_meta(&(target_tensors[0]));
auto_grad_meta0->SetGradNode(
std::dynamic_pointer_cast<GradNodeBase>(node0_ptr));
auto_grad_meta0->SetSingleOutRankWithSlot(0, 0);
auto_grad_meta0->SetStopGradient(false);
// Connect Inp1 and Node1 via AutoGradMeta
AutogradMeta* auto_grad_meta1 =
EagerUtils::autograd_meta(&(target_tensors[1]));
auto_grad_meta1->SetGradNode(
std::dynamic_pointer_cast<GradNodeBase>(node1_ptr));
auto_grad_meta1->SetSingleOutRankWithSlot(0, 0);
auto_grad_meta1->SetStopGradient(false);
// Connect Node0 -> Node2 via Edge
auto tmp_tensor0 = paddle::Tensor();
auto* meta0 = EagerUtils::autograd_meta(&tmp_tensor0);
meta0->SetStopGradient(false);
meta0->SetSingleOutRankWithSlot(0, 0);
meta0->SetGradNode(node2_ptr);
node0_ptr->SetGradOutMeta(tmp_tensor0, 0);
// Connect Node1 -> Node2 via Edge
auto tmp_tensor1 = paddle::Tensor();
auto meta1 = EagerUtils::autograd_meta(&tmp_tensor1);
meta1->SetStopGradient(false);
meta1->SetSingleOutRankWithSlot(0, 0);
meta1->SetGradNode(node2_ptr);
node1_ptr->SetGradOutMeta(tmp_tensor1, 0);
AutogradMeta* auto_grad_meta2 = EagerUtils::autograd_meta(&leaf_tensor);
// Connect Tensor and AccumulationNode via AutoGradMeta
auto acc_node_ptr =
std::make_shared<egr::GradNodeAccumulation>(leaf_tensor);
auto_grad_meta2->SetGradNode(
std::dynamic_pointer_cast<GradNodeBase>(acc_node_ptr));
auto_grad_meta2->SetSingleOutRankWithSlot(0, 0);
auto_grad_meta2->SetStopGradient(false);
node2_ptr->SetGradOutMeta(leaf_tensor, 0);
}
auto result = Grad(target_tensors, {leaf_tensor}, grad_tensors);
eager_test::CompareTensorWithValue<float>(result[0], 2500.0);
}
} // namespace egr
+200
View File
@@ -0,0 +1,200 @@
// 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.
#include <sstream>
#include "glog/logging.h"
#include "gtest/gtest.h"
#include "paddle/fluid/eager/accumulation/accumulation_node.h"
#include "paddle/fluid/eager/api/all.h"
#include "paddle/fluid/eager/api/generated/eager_generated/backwards/scale_node.h"
#include "paddle/fluid/eager/autograd_meta.h"
#include "paddle/fluid/eager/backward.h"
#include "paddle/fluid/eager/grad_node_info.h"
#include "paddle/fluid/eager/hooks.h"
#include "paddle/phi/core/dense_tensor.h"
#include "paddle/phi/core/kernel_registry.h"
#include "paddle/phi/core/tensor_meta.h"
#include "test/cpp/eager/test_utils.h"
PD_DECLARE_KERNEL(full, CPU, ALL_LAYOUT);
namespace egr {
paddle::Tensor hook_function(const paddle::Tensor& t) {
auto t_dense = std::dynamic_pointer_cast<phi::DenseTensor>(t.impl());
auto ret_meta = phi::DenseTensorMeta(
t_dense->dtype(), t_dense->dims(), t_dense->layout());
auto place = t_dense->place();
size_t bytes_size =
common::product(t_dense->dims()) * SizeOf(t_dense->dtype());
auto ret_dense = std::make_shared<phi::DenseTensor>(
paddle::memory::Alloc(place, bytes_size), std::move(ret_meta));
float* t_ptr = t_dense->mutable_data<float>(place);
float* ret_ptr = ret_dense->mutable_data<float>(place);
for (int i = 0; i < ret_dense->numel(); i++) {
ret_ptr[i] = t_ptr[i] + 3.0f;
}
auto ret_impl = std::dynamic_pointer_cast<phi::TensorBase>(ret_dense);
paddle::Tensor ret = paddle::Tensor();
ret.set_impl(ret_impl);
return ret;
}
TEST(RetainGrad, HookBeforeRetainGrad) {
eager_test::InitEnv(phi::CPUPlace());
// Prepare Inputs
std::vector<paddle::Tensor> target_tensors;
phi::DDim ddim = common::make_ddim({4, 16, 16, 32});
// Create Target Tensor
paddle::Tensor tensor =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
1.0 /*value*/,
false /*is_leaf*/);
target_tensors.emplace_back(std::move(tensor));
paddle::Tensor& target_tensor = target_tensors[0];
// Create ScaleNode
auto scale_node_ptr = std::make_shared<GradNodeScale>(1, 1);
scale_node_ptr->SetAttributes_scale(5.0 /*scale*/);
// Set grad in/out meta for node0
scale_node_ptr->SetDefaultGradInOutMeta();
// Connect Input Tensor and ScaleNode via AutoGradMeta
// Apply RetainGrad
{
// ScaleNode Hook: +3
auto auto_grad_meta = std::make_shared<AutogradMeta>();
auto_grad_meta->SetGradNode(
std::dynamic_pointer_cast<GradNodeBase>(scale_node_ptr));
auto_grad_meta->SetSingleOutRankWithSlot(0, 0);
auto_grad_meta->SetStopGradient(false);
target_tensor.set_autograd_meta(
std::dynamic_pointer_cast<paddle::AbstractAutogradMeta>(
auto_grad_meta));
egr_utils_api::RegisterGradientHookForTensor(target_tensor, hook_function);
egr_utils_api::RetainGradForTensor(
target_tensor); // result: 1.0 + 3.0 = 4.0
egr_utils_api::RetainGradForTensor(
target_tensor); // result: 1.0 + 3.0 = 4.0
}
// Retain Grad for leaf tensor1
paddle::Tensor leaf_tensor = paddle::Tensor();
{
// AccumulationNode Hook: +3
auto tmp_tensor0 = paddle::Tensor();
auto auto_grad_meta = EagerUtils::autograd_meta(&tmp_tensor0);
auto acc_node_ptr = std::make_shared<GradNodeAccumulation>(tmp_tensor0);
auto_grad_meta->SetStopGradient(false);
auto_grad_meta->SetGradNode(acc_node_ptr);
auto_grad_meta->SetSingleOutRankWithSlot(0, 0);
std::vector<egr::AutogradMeta*> res = {auto_grad_meta};
scale_node_ptr->SetGradOutMeta(tmp_tensor0, 0);
leaf_tensor.set_autograd_meta(
std::dynamic_pointer_cast<paddle::AbstractAutogradMeta>(
tmp_tensor0.mutable_autograd_meta()));
egr_utils_api::RegisterGradientHookForTensor(leaf_tensor, hook_function);
egr_utils_api::RetainGradForTensor(
leaf_tensor); // result: 4.0*5.0 + 3.0 = 23.0
}
Backward(target_tensors, {});
eager_test::CompareGradTensorWithValue<float>(target_tensor, 4.0);
eager_test::CompareGradTensorWithValue<float>(leaf_tensor, 23.0);
}
TEST(RetainGrad, HookAfterRetainGrad) {
eager_test::InitEnv(phi::CPUPlace());
// Prepare Inputs
std::vector<paddle::Tensor> target_tensors;
phi::DDim ddim = common::make_ddim({4, 16, 16, 32});
// Create Target Tensor
paddle::Tensor tensor =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
1.0 /*value*/,
false /*is_leaf*/);
target_tensors.emplace_back(std::move(tensor));
paddle::Tensor& target_tensor = target_tensors[0];
// Create ScaleNode
auto scale_node_ptr = std::make_shared<GradNodeScale>(1, 1);
scale_node_ptr->SetAttributes_scale(5.0 /*scale*/);
// Set grad in/out meta for node0
scale_node_ptr->SetDefaultGradInOutMeta();
// Connect Input Tensor and ScaleNode via AutoGradMeta
// Apply RetainGrad
{
// ScaleNode Hook: +3
auto auto_grad_meta = std::make_shared<AutogradMeta>();
auto_grad_meta->SetGradNode(
std::dynamic_pointer_cast<GradNodeBase>(scale_node_ptr));
auto_grad_meta->SetSingleOutRankWithSlot(0, 0);
auto_grad_meta->SetStopGradient(false);
target_tensor.set_autograd_meta(
std::dynamic_pointer_cast<paddle::AbstractAutogradMeta>(
auto_grad_meta));
egr_utils_api::RetainGradForTensor(target_tensor); // result: 1.0
egr_utils_api::RegisterGradientHookForTensor(target_tensor, hook_function);
}
// Retain Grad for leaf tensor1
paddle::Tensor leaf_tensor = paddle::Tensor();
{
// AccumulationNode Hook: +3
auto tmp_tensor0 = paddle::Tensor();
auto auto_grad_meta = EagerUtils::autograd_meta(&tmp_tensor0);
auto acc_node_ptr = std::make_shared<GradNodeAccumulation>(tmp_tensor0);
auto_grad_meta->SetGradNode(acc_node_ptr);
auto_grad_meta->SetStopGradient(false);
scale_node_ptr->SetGradOutMeta(tmp_tensor0, 0);
auto_grad_meta->SetSingleOutRankWithSlot(0, 0);
leaf_tensor.set_autograd_meta(
std::dynamic_pointer_cast<paddle::AbstractAutogradMeta>(
tmp_tensor0.mutable_autograd_meta()));
egr_utils_api::RegisterGradientHookForTensor(leaf_tensor, hook_function);
}
Backward(target_tensors, {});
eager_test::CompareGradTensorWithValue<float>(target_tensor, 1.0);
eager_test::CompareGradTensorWithValue<float>(leaf_tensor, 23.0);
}
} // namespace egr
@@ -0,0 +1,327 @@
// 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 <sstream>
#include "gtest/gtest.h"
#include "paddle/fluid/eager/api/all.h"
#include "paddle/fluid/eager/api/generated/fluid_generated/dygraph_forward_api.h"
#include "paddle/fluid/eager/backward.h"
#include "paddle/fluid/eager/grad_node_info.h"
#include "paddle/fluid/eager/hooks.h"
#include "paddle/fluid/imperative/tracer.h"
#include "paddle/phi/core/dense_tensor.h"
#include "paddle/phi/core/kernel_registry.h"
#include "test/cpp/eager/test_utils.h"
PD_DECLARE_KERNEL(full, CPU, ALL_LAYOUT);
PD_DECLARE_KERNEL(matmul, CPU, ALL_LAYOUT);
PD_DECLARE_KERNEL(matmul_grad, CPU, ALL_LAYOUT);
PD_DECLARE_KERNEL(add, CPU, ALL_LAYOUT);
PD_DECLARE_KERNEL(add_grad, CPU, ALL_LAYOUT);
PD_DECLARE_KERNEL(sigmoid, CPU, ALL_LAYOUT);
PD_DECLARE_KERNEL(sigmoid_grad, CPU, ALL_LAYOUT);
namespace egr {
paddle::Tensor hook_function(const paddle::Tensor& t) {
auto t_dense = std::dynamic_pointer_cast<phi::DenseTensor>(t.impl());
auto ret_meta = phi::DenseTensorMeta(
t_dense->dtype(), t_dense->dims(), t_dense->layout());
auto place = t_dense->place();
size_t bytes_size =
common::product(t_dense->dims()) * SizeOf(t_dense->dtype());
auto ret_dense = std::make_shared<phi::DenseTensor>(
paddle::memory::Alloc(place, bytes_size), std::move(ret_meta));
float* t_ptr = t_dense->mutable_data<float>(place);
float* ret_ptr = ret_dense->mutable_data<float>(place);
for (int i = 0; i < ret_dense->numel(); i++) {
ret_ptr[i] = t_ptr[i] + 3.0f;
}
auto ret_impl = std::dynamic_pointer_cast<phi::TensorBase>(ret_dense);
paddle::Tensor ret = paddle::Tensor();
ret.set_impl(ret_impl);
return ret;
}
void test_sigmoid(bool is_remove_gradient_hook) {
// Prepare Device Contexts
VLOG(6) << "Init Env";
eager_test::InitEnv(phi::CPUPlace());
VLOG(6) << "Make Dim";
phi::DDim ddim = common::make_ddim({2, 4, 4, 4});
VLOG(6) << "Make paddle::Tensor";
paddle::Tensor tensor =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
0.0,
true);
VLOG(6) << "Make ReduceHook function";
auto reduce_hook = [&]() -> void {
auto* t_ptr = std::dynamic_pointer_cast<phi::DenseTensor>(tensor.impl())
->data<float>();
for (int i = 0; i < tensor.numel(); i++) {
t_ptr[i] = 100.0; // set to 100.0
}
};
VLOG(6) << "Retain Grad for Tensor";
egr_utils_api::RetainGradForTensor(tensor);
VLOG(6) << "Register GradientHook for Tensor";
int64_t hook_id =
egr_utils_api::RegisterGradientHookForTensor(tensor, hook_function);
VLOG(6) << "Register ReduceHook for Tensor";
egr_utils_api::RegisterReduceHookForTensor(tensor, reduce_hook);
VLOG(6) << "Running Forward";
auto output_tensor = sigmoid_dygraph_function(tensor, {});
VLOG(6) << "Finish Forward";
eager_test::CompareTensorWithValue<float>(output_tensor, 0.5);
std::vector<paddle::Tensor> target_tensors = {output_tensor};
if (is_remove_gradient_hook) {
std::shared_ptr<GradNodeBase> grad_node_tmp = EagerUtils::grad_node(tensor);
grad_node_tmp->RemoveGradientHook(hook_id);
}
VLOG(6) << "Running Backward";
Backward(target_tensors, {});
VLOG(6) << "Finish Backward";
eager_test::CompareGradTensorWithValue<float>(
tensor, is_remove_gradient_hook ? 0.25 : 0.25 + 3.0);
VLOG(6) << "Checking ReduceHook results";
for (int i = 0; i < tensor.numel(); i++) {
PADDLE_ENFORCE_EQ(
std::dynamic_pointer_cast<phi::DenseTensor>(tensor.impl())
->data<float>()[i],
static_cast<float>(100.0f),
common::errors::InvalidArgument(
"Required tensor.impl()->data[%d] should be equal to 100.0 . ", i));
}
VLOG(6) << "After Tests";
}
void test_elementwiseAdd(bool is_remove_gradient_hook) {
// Prepare Device Contexts
eager_test::InitEnv(phi::CPUPlace());
auto tracer = std::make_shared<paddle::imperative::Tracer>();
paddle::imperative::SetCurrentTracer(tracer);
// 1. Prepare Input
phi::DDim ddimX = common::make_ddim({4, 16});
paddle::Tensor X = eager_test::CreateTensorWithValue(ddimX,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
3.0,
true);
egr_utils_api::RetainGradForTensor(X);
phi::DDim ddimY = common::make_ddim({4, 16});
paddle::Tensor Y = eager_test::CreateTensorWithValue(ddimY,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
2.0,
true);
auto reduce_hook = [&]() -> void {
auto* t_ptr =
std::dynamic_pointer_cast<phi::DenseTensor>(Y.impl())->data<float>();
for (int i = 0; i < Y.numel(); i++) {
t_ptr[i] = 100.0; // set to 100.0
}
};
egr_utils_api::RetainGradForTensor(Y);
int64_t hook_id =
egr_utils_api::RegisterGradientHookForTensor(Y, hook_function);
egr_utils_api::RegisterReduceHookForTensor(Y, reduce_hook);
auto output_tensor = elementwise_add_dygraph_function(X, Y, {});
eager_test::CompareTensorWithValue<float>(output_tensor, 5);
std::vector<paddle::Tensor> target_tensors = {output_tensor};
if (is_remove_gradient_hook) {
std::shared_ptr<GradNodeBase> grad_node_tmp = EagerUtils::grad_node(Y);
grad_node_tmp->RemoveGradientHook(hook_id);
}
Backward(target_tensors, {});
eager_test::CompareGradTensorWithValue<float>(X, 1.0);
eager_test::CompareGradTensorWithValue<float>(
Y, is_remove_gradient_hook ? 1.0 : 1.0 + 3.0);
// Checking ReduceHook results
for (int i = 0; i < Y.numel(); i++) {
PADDLE_ENFORCE_EQ(
std::dynamic_pointer_cast<phi::DenseTensor>(Y.impl())->data<float>()[i],
static_cast<float>(100.0f),
common::errors::InvalidArgument(
"Required Y.impl()->data[%d] should be equal to 100.0 . ", i));
}
}
void test_matmul(bool is_remove_gradient_hook) {
// Prepare Device Contexts
eager_test::InitEnv(phi::CPUPlace());
auto tracer = std::make_shared<paddle::imperative::Tracer>();
paddle::imperative::SetCurrentTracer(tracer);
// 1. Prepare Input
phi::DDim ddimX = common::make_ddim({4, 16});
paddle::Tensor X = eager_test::CreateTensorWithValue(ddimX,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
3.0,
true);
egr_utils_api::RetainGradForTensor(X);
phi::DDim ddimY = common::make_ddim({16, 20});
paddle::Tensor Y = eager_test::CreateTensorWithValue(ddimY,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
2.0,
true);
auto reduce_hook = [&]() -> void {
auto* t_ptr =
std::dynamic_pointer_cast<phi::DenseTensor>(Y.impl())->data<float>();
for (int i = 0; i < Y.numel(); i++) {
t_ptr[i] = 100.0; // set to 100.0
}
};
egr_utils_api::RetainGradForTensor(Y);
int64_t hook_id =
egr_utils_api::RegisterGradientHookForTensor(Y, hook_function);
egr_utils_api::RegisterReduceHookForTensor(Y, reduce_hook);
auto output_tensor = matmul_v2_dygraph_function(
X, Y, {{"trans_x", false}, {"trans_y", false}});
eager_test::CompareTensorWithValue<float>(output_tensor, 96);
std::vector<paddle::Tensor> target_tensors = {output_tensor};
if (is_remove_gradient_hook) {
std::shared_ptr<GradNodeBase> grad_node_tmp = EagerUtils::grad_node(Y);
grad_node_tmp->RemoveGradientHook(hook_id);
}
Backward(target_tensors, {});
eager_test::CompareGradTensorWithValue<float>(X, 2.0 * 20);
eager_test::CompareGradTensorWithValue<float>(
Y, is_remove_gradient_hook ? 3.0 * 4 : 3.0 * 4 + 3);
// Checking ReduceHook results
for (int i = 0; i < Y.numel(); i++) {
PADDLE_ENFORCE_EQ(
std::dynamic_pointer_cast<phi::DenseTensor>(Y.impl())->data<float>()[i],
static_cast<float>(100.0f),
common::errors::InvalidArgument(
"Required Y.impl()->data[%d] should be equal to 100.0 . ", i));
}
}
void test_backward_final_hooks() {
// Prepare Device Contexts
VLOG(6) << "Init Env";
eager_test::InitEnv(phi::CPUPlace());
VLOG(6) << "Make paddle::Tensor";
phi::DDim ddimX = common::make_ddim({4, 16});
paddle::Tensor X = eager_test::CreateTensorWithValue(ddimX,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
3.0,
true);
phi::DDim ddimY = common::make_ddim({16, 20});
egr_utils_api::RetainGradForTensor(X);
paddle::Tensor Y = eager_test::CreateTensorWithValue(ddimY,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
2.0,
true);
VLOG(6) << "Make ReduceHook function";
auto backward_final_hook = [&]() -> void {
auto* t_ptr =
std::dynamic_pointer_cast<phi::DenseTensor>(X.impl())->data<float>();
VLOG(6) << "Run Target Backward Hook";
for (int i = 0; i < X.numel(); i++) {
t_ptr[i] = 100.0; // set to 100.0
}
};
VLOG(6) << "Register Backward Final Hook";
egr_utils_api::RegisterBackwardFinalHook(backward_final_hook);
VLOG(6) << "Running Forward";
auto output_tensor = matmul_v2_dygraph_function(
X, Y, {{"trans_x", false}, {"trans_y", false}});
auto res = sigmoid_dygraph_function(output_tensor, {});
VLOG(6) << "Finish Forward";
eager_test::CompareTensorWithValue<float>(X, 3.0);
std::vector<paddle::Tensor> target_tensors = {output_tensor};
VLOG(6) << "Running Backward";
Backward(target_tensors, {});
VLOG(6) << "Finish Backward";
eager_test::CompareTensorWithValue<float>(X, 100.0);
}
TEST(Hook_intermediate, Sigmoid) {
// True or false represents whether to call RemoveGradientHook
test_sigmoid(true);
test_sigmoid(false);
}
TEST(Hook_intermediate, ElementwiseAdd) {
test_elementwiseAdd(true);
test_elementwiseAdd(false);
}
TEST(Hook_intermediate, Matmul_v2) {
test_matmul(true);
test_matmul(false);
}
TEST(Hook_intermediate, BackwardFinal) { test_backward_final_hooks(); }
} // namespace egr
@@ -0,0 +1,169 @@
// 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/fluid/eager/nan_inf_utils.h"
#include <iostream>
#include <limits>
#include <ostream>
#include <string>
#include <tuple>
#include "gtest/gtest.h"
#include "paddle/common/flags.h"
#include "paddle/fluid/framework/tensor_util.h"
#include "paddle/fluid/platform/enforce.h"
#include "paddle/phi/api/include/api.h"
#include "paddle/phi/api/include/strings_api.h"
#include "paddle/phi/core/kernel_registry.h"
PD_DECLARE_KERNEL(full, CPU, ALL_LAYOUT);
PD_DECLARE_KERNEL(strings_empty, CPU, ALL_LAYOUT);
COMMON_DECLARE_string(check_nan_inf_blacklist);
namespace egr {
using paddle_flags::FLAGS_check_nan_inf_blacklist;
#define CHECK_NAN_INF(tensors) \
{ \
bool caught_exception = false; \
try { \
CheckTensorHasNanOrInf("nan_inf_test", tensors); \
} catch (paddle::platform::EnforceNotMet & error) { \
caught_exception = true; \
std::string ex_msg = error.what(); \
EXPECT_TRUE(ex_msg.find("There are NAN or INF") != std::string::npos); \
} \
EXPECT_TRUE(caught_exception); \
}
#define CHECK_NO_NAN_INF(tensors) \
{ \
bool caught_exception = false; \
try { \
CheckTensorHasNanOrInf("nan_inf_test", tensors); \
} catch (paddle::platform::EnforceNotMet & error) { \
caught_exception = true; \
std::string ex_msg = error.what(); \
EXPECT_TRUE(ex_msg.find("There are NAN or INF") != std::string::npos); \
} \
EXPECT_FALSE(caught_exception); \
}
#define CHECK_APINAME_SKIP(api_name, tensor) \
{ \
bool caught_exception = false; \
try { \
CheckTensorHasNanOrInf(api_name, tensor); \
} catch (paddle::platform::EnforceNotMet & error) { \
caught_exception = true; \
} \
EXPECT_FALSE(caught_exception); \
}
#define CHECK_APINAME_NO_SKIP(api_name, tensor) \
{ \
bool caught_exception = false; \
try { \
CheckTensorHasNanOrInf(api_name, tensor); \
} catch (paddle::platform::EnforceNotMet & error) { \
caught_exception = true; \
} \
EXPECT_TRUE(caught_exception); \
}
TEST(NanInfUtils, BlacklistSkipCheck) {
auto nan_tensor = paddle::experimental::full(
{3, 4}, std::numeric_limits<double>::quiet_NaN(), phi::DataType::FLOAT64);
FLAGS_check_nan_inf_blacklist = "";
CHECK_APINAME_SKIP("empty", nan_tensor);
// Test that "empty_like" always skips regardless of blacklist
FLAGS_check_nan_inf_blacklist = "";
CHECK_APINAME_SKIP("empty_like", nan_tensor);
// Test with empty blacklist (default behavior)
FLAGS_check_nan_inf_blacklist = "";
CHECK_APINAME_NO_SKIP("some_op", nan_tensor);
// Test with single op in blacklist
FLAGS_check_nan_inf_blacklist = "single_op";
CHECK_APINAME_SKIP("single_op", nan_tensor);
CHECK_APINAME_NO_SKIP("other_op", nan_tensor);
// Even when blacklist is set, these should still skip
CHECK_APINAME_SKIP("empty", nan_tensor);
CHECK_APINAME_SKIP("empty_like", nan_tensor);
// blacklist="op1,op2,op3" and op is in blacklist
FLAGS_check_nan_inf_blacklist = "op1,op2,op3";
CHECK_APINAME_SKIP("op1", nan_tensor);
CHECK_APINAME_SKIP("op2", nan_tensor);
CHECK_APINAME_SKIP("op3", nan_tensor);
// not in blacklist, should perform nan_or_inf check
CHECK_APINAME_NO_SKIP("op4", nan_tensor);
FLAGS_check_nan_inf_blacklist = "";
}
TEST(NanInfUtils, Functions) {
// test all methods
auto tensor = paddle::experimental::full(
{3, 4}, std::numeric_limits<double>::quiet_NaN(), phi::DataType::FLOAT64);
CHECK_NAN_INF(tensor);
auto tensor1 = paddle::experimental::full(
{3, 4}, std::numeric_limits<double>::quiet_NaN(), phi::DataType::FLOAT64);
auto two_tensors = std::make_tuple(tensor, tensor1);
CHECK_NAN_INF(two_tensors);
auto tensor2 = paddle::experimental::full(
{3, 4}, std::numeric_limits<double>::quiet_NaN(), phi::DataType::FLOAT64);
auto three_tensors = std::make_tuple(tensor, tensor1, tensor2);
CHECK_NAN_INF(three_tensors);
auto tensor3 = paddle::experimental::full(
{3, 4}, std::numeric_limits<double>::quiet_NaN(), phi::DataType::FLOAT64);
auto four_tensors = std::make_tuple(tensor, tensor1, tensor2, tensor3);
CHECK_NAN_INF(four_tensors);
auto tensor4 = paddle::experimental::full(
{3, 4}, std::numeric_limits<double>::quiet_NaN(), phi::DataType::FLOAT64);
auto five_tensors =
std::make_tuple(tensor, tensor1, tensor2, tensor3, tensor4);
CHECK_NAN_INF(five_tensors);
auto tensor5 = paddle::experimental::full(
{3, 4}, std::numeric_limits<double>::quiet_NaN(), phi::DataType::FLOAT64);
auto six_tensors =
std::make_tuple(tensor, tensor1, tensor2, tensor3, tensor4, tensor5);
CHECK_NAN_INF(six_tensors);
std::vector<paddle::Tensor> tensor_vec;
tensor_vec.emplace_back(tensor);
tensor_vec.emplace_back(tensor1);
CHECK_NAN_INF(tensor_vec);
paddle::small_vector<std::vector<paddle::Tensor>, egr::kSlotSmallVectorSize>
small_vec;
small_vec.emplace_back(tensor_vec);
CHECK_NAN_INF(small_vec);
// test selected_rows
paddle::Tensor tensor_sr;
auto sr = std::make_shared<phi::SelectedRows>();
*sr->mutable_value() =
*(static_cast<const phi::DenseTensor*>(tensor.impl().get()));
tensor_sr.set_impl(sr);
CHECK_NAN_INF(tensor_sr);
// test other tensor
auto tensor_str = paddle::experimental::strings::empty({3, 4});
CHECK_NO_NAN_INF(tensor_str);
}
} // namespace egr
@@ -0,0 +1,67 @@
// 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.
#include <sstream>
#include "gtest/gtest.h"
#include "paddle/fluid/eager/eager_tensor.h"
#include "paddle/fluid/eager/grad_node_info.h"
#include "paddle/fluid/eager/grad_tensor_holder.h"
#include "paddle/phi/api/lib/utils/allocator.h"
#include "paddle/phi/core/kernel_registry.h"
#include "test/cpp/eager/test_utils.h"
PD_DECLARE_KERNEL(full, CPU, ALL_LAYOUT);
namespace egr {
TEST(TensorUtils, Test) {
// Prepare Device Contexts
eager_test::InitEnv(phi::CPUPlace());
// Prepare Inputs
std::vector<paddle::Tensor> target_tensors;
phi::DDim ddim = common::make_ddim({4, 16, 16, 32});
// Create Target Tensor
paddle::Tensor t = eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
5.0 /*value*/,
true /*is_leaf*/);
paddle::Tensor t_grad =
eager_test::CreateTensorWithValue(ddim,
phi::CPUPlace(),
phi::DataType::FLOAT32,
phi::DataLayout::NCHW,
1.0 /*value*/,
false /*is_leaf*/);
PADDLE_ENFORCE_EQ(
EagerUtils::IsLeafTensor(t),
true,
common::errors::InvalidArgument("The tensor t is not a leaf tensor."));
// Test Utils
eager_test::CompareTensorWithValue<float>(t, 5.0);
egr::AutogradMeta* meta = egr::EagerUtils::autograd_meta(&t);
*meta->MutableGrad() = t_grad;
eager_test::CompareGradTensorWithValue<float>(t, 1.0);
}
} // namespace egr
+136
View File
@@ -0,0 +1,136 @@
// 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
#include "paddle/fluid/eager/accumulation/accumulation_node.h"
#include "paddle/fluid/eager/api/utils/global_utils.h"
#include "paddle/fluid/eager/autograd_meta.h"
#include "paddle/fluid/eager/eager_tensor.h"
#include "paddle/fluid/eager/utils.h"
#include "paddle/fluid/platform/init.h"
#include "paddle/phi/api/all.h"
#include "paddle/phi/core/dense_tensor.h"
#include "paddle/phi/core/memory/memcpy.h"
#include "paddle/phi/core/platform/device_context.h"
#include "paddle/phi/core/tensor_meta.h"
namespace eager_test {
inline paddle::Tensor CreateTensorWithValue(const phi::DDim& ddim,
const phi::Place& place,
const phi::DataType& dtype,
const phi::DataLayout& layout,
float value,
bool is_leaf = true) {
paddle::Tensor out =
paddle::experimental::full(common::vectorize(ddim),
paddle::experimental::Scalar(value),
dtype,
place);
auto meta = egr::EagerUtils::autograd_meta(&out);
if (is_leaf) {
auto accumulation_node = std::make_shared<egr::GradNodeAccumulation>(out);
meta->SetGradNode(accumulation_node);
meta->SetStopGradient(false);
}
return out;
}
template <typename T>
bool CompareGradTensorWithValue(const paddle::Tensor& target, T value) {
egr::AutogradMeta* meta = egr::EagerUtils::unsafe_autograd_meta(target);
auto grad_dense =
std::dynamic_pointer_cast<phi::DenseTensor>(meta->Grad().impl());
T* ptr = grad_dense->data<T>();
std::vector<T> host_data(grad_dense->numel());
if (phi::is_gpu_place(grad_dense->place())) {
#ifdef PADDLE_WITH_CUDA
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
auto* dev_ctx = dynamic_cast<phi::GPUContext*>(pool.Get(phi::GPUPlace()));
auto stream = dev_ctx->stream();
paddle::memory::Copy(phi::CPUPlace(),
host_data.data(),
phi::GPUPlace(),
ptr,
sizeof(T) * grad_dense->numel(),
stream);
ptr = host_data.data();
#endif
}
VLOG(6) << "CompareGradTensorWithValue";
for (int i = 0; i < grad_dense->numel(); i++) {
PADDLE_ENFORCE(value == ptr[i],
common::errors::PreconditionNotMet(
"Numerical Error in Compare Grad Variable With Value of "
"%d, we expected got value: %f, but got: %f instead. "
"Please check it later.",
i,
value,
ptr[i]));
}
return true;
}
template <typename T>
bool CompareTensorWithValue(const paddle::Tensor& target, T value) {
// TODO(jiabin): Support Selected Rows later
auto dense_t = std::dynamic_pointer_cast<phi::DenseTensor>(target.impl());
T* ptr = dense_t->data<T>();
std::vector<T> host_data(dense_t->numel());
if (phi::is_gpu_place(dense_t->place())) {
#ifdef PADDLE_WITH_CUDA
phi::DeviceContextPool& pool = phi::DeviceContextPool::Instance();
auto* dev_ctx = dynamic_cast<phi::GPUContext*>(pool.Get(phi::GPUPlace()));
auto stream = dev_ctx->stream();
paddle::memory::Copy(phi::CPUPlace(),
host_data.data(),
phi::GPUPlace(),
ptr,
sizeof(T) * dense_t->numel(),
stream);
ptr = host_data.data();
#endif
}
VLOG(6) << "CompareTensorWithValue";
for (int i = 0; i < dense_t->numel(); i++) {
PADDLE_ENFORCE(value == ptr[i],
common::errors::PreconditionNotMet(
"Numerical Error in Compare Grad Variable With Value of "
"%d, we expected got value: %f, but got: %f instead. "
"Please check it later.",
i,
value,
ptr[i]));
}
return true;
}
inline void InitEnv(phi::Place place) {
// Prepare Device Contexts
// Init DeviceContextPool
paddle::framework::InitDevices();
// Init Tracer Place
egr::Controller::Instance().SetExpectedPlace(place);
}
} // namespace eager_test