Files
paddlepaddle--paddle/test/dygraph_to_static/test_jit_recompute.py
T
2026-07-13 12:40:42 +08:00

133 lines
3.8 KiB
Python

# Copyright (c) 2026 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.
import unittest
import numpy as np
from dygraph_to_static_utils import (
Dy2StTestBase,
)
import paddle
from paddle.distributed.fleet.utils import recompute
class ManualPyLayerRecompute(paddle.autograd.PyLayer):
@staticmethod
def forward(ctx, fn, x, y):
ctx.fn = fn
ctx.save_for_backward(x, y)
with paddle.no_grad():
out = fn(x, y)
return out
@staticmethod
def backward(ctx, grad_out):
x, y = ctx.saved_tensor()
with paddle.enable_grad():
x.stop_gradient = False
y.stop_gradient = False
out = ctx.fn(x, y)
grad_inputs = paddle.autograd.grad(out, [x, y], grad_out)
return (*grad_inputs,)
class TestManualPyLayerRecompute(Dy2StTestBase):
def test_recompute(self):
@paddle.jit.to_static()
def fn(x, y):
return x * y + paddle.sin(x)
x = paddle.randn([3, 3])
x.stop_gradient = False
y = paddle.randn([3, 3])
y.stop_gradient = False
out = ManualPyLayerRecompute.apply(fn, x, y)
out.backward()
grad_x1 = x.grad.numpy()
grad_y1 = y.grad.numpy()
x.clear_gradient()
y.clear_gradient()
out2 = fn(x, y)
out2.backward()
grad_x2 = x.grad.numpy()
grad_y2 = y.grad.numpy()
x.clear_gradient()
y.clear_gradient()
np.testing.assert_allclose(grad_x1, grad_x2, rtol=1e-05)
np.testing.assert_allclose(grad_y1, grad_y2, rtol=1e-05)
class SimpleRecomputeNetToStatic(paddle.nn.Layer):
def __init__(self, input_size=10):
super().__init__()
self.block = paddle.nn.Sequential(
paddle.nn.Linear(input_size, input_size, bias_attr=False),
paddle.nn.ReLU(),
)
self.block = paddle.jit.to_static(self.block)
def forward(self, inputs):
return recompute(self.block, inputs)
class SimpleRecomputeNet(paddle.nn.Layer):
def __init__(self, input_size=10):
super().__init__()
self.block = paddle.nn.Sequential(
paddle.nn.Linear(input_size, input_size, bias_attr=False),
paddle.nn.ReLU(),
)
def forward(self, inputs):
return self.block(inputs)
class TestDistributedPyLayerRecompute(Dy2StTestBase):
def test_recompute(self):
input_size = 10
inp = np.random.rand(2, input_size).astype("float32")
x = paddle.to_tensor(inp)
x.stop_gradient = False
y = paddle.to_tensor(inp)
y.stop_gradient = False
weight = np.random.rand(input_size, input_size).astype("float32")
model_x = SimpleRecomputeNet(input_size)
model_y = SimpleRecomputeNetToStatic(input_size)
with paddle.no_grad():
model_x.block[0].weight.set_value(weight)
model_y.block[0].weight.set_value(weight)
out_x = model_x(x)
loss_x = out_x.mean()
loss_x.backward()
out_y = model_y(y)
loss_y = out_y.mean()
loss_y.backward()
np.testing.assert_allclose(out_x.numpy(), out_y.numpy(), rtol=1e-05)
np.testing.assert_allclose(x.grad.numpy(), y.grad.numpy(), rtol=1e-05)
if __name__ == '__main__':
unittest.main()