Files
paddlepaddle--paddle/test/cpp/eager/task_tests/hook_test_intermediate.cc
T
2026-07-13 12:40:42 +08:00

328 lines
12 KiB
C++

// 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