Files
2026-07-13 12:40:42 +08:00

222 lines
6.1 KiB
Python

# 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.
import os
import tempfile
import unittest
import numpy as np
from dygraph_to_static_utils import (
Dy2StTestBase,
test_ast_only,
)
import paddle
class GradLayer(paddle.nn.Layer):
def __init__(self):
super().__init__()
def forward(self, x):
x.stop_gradient = False
y = x * x
dx = paddle.grad(outputs=[y], inputs=[x])[0]
return dx
class GradLinearLayer(paddle.nn.Layer):
def __init__(self):
super().__init__()
self.linear = paddle.nn.Linear(5, 5, bias_attr=False)
def forward(self, x):
x.stop_gradient = False
tmp = x + x
for i in range(10):
tmp = self.linear(tmp)
out = tmp
dx = paddle.grad(
[out], [x], None, create_graph=True, allow_unused=False
)[0]
return dx
class NoGradLinearLayer(paddle.nn.Layer):
def __init__(self):
super().__init__()
self.linear = paddle.nn.Linear(5, 5, bias_attr=False)
def forward(self, x):
x.stop_gradient = False
with paddle.no_grad():
y = self.linear(x)
out = y + x
return out
class TestGrad(Dy2StTestBase):
def setUp(self):
self.func = GradLayer()
self.x = paddle.ones(shape=[10, 2, 5], dtype='float32')
self.x.stop_gradient = False
def test_forward(self):
dygraph_res = self.func(self.x).numpy()
static_res = paddle.jit.to_static(self.func)(self.x).numpy()
np.testing.assert_allclose(static_res, dygraph_res, rtol=1e-05)
class TestGradLinear(TestGrad):
def setUp(self):
self.func = GradLinearLayer()
self.x = paddle.ones(shape=[10, 2, 5], dtype='float32')
self.x.stop_gradient = False
self.temp_dir = tempfile.TemporaryDirectory()
self.infer_model_path = os.path.join(
self.temp_dir.name, 'double_grad_infer_model'
)
self.train_model_path = os.path.join(
self.temp_dir.name, 'double_grad_train_model'
)
def tearDown(self):
self.temp_dir.cleanup()
def test_save_infer_program(self):
static_fn = paddle.jit.to_static(self.func)
input_spec = [
paddle.static.InputSpec(shape=[10, 2, 5], dtype='float32')
]
paddle.jit.save(static_fn, self.infer_model_path, input_spec=input_spec)
load_func = paddle.jit.load(self.infer_model_path)
origin_res = static_fn(self.x).numpy()
load_res = load_func(self.x).numpy()
np.testing.assert_allclose(origin_res, load_res, rtol=1e-05)
def test_save_train_program(self):
static_fn = paddle.jit.to_static(self.func)
grad_clip = paddle.nn.ClipGradByGlobalNorm(2.0)
optimizer = paddle.optimizer.SGD(
learning_rate=0.01,
grad_clip=grad_clip,
parameters=static_fn.parameters(),
)
for i in range(10):
out = static_fn(self.x)
avg_loss = paddle.mean(paddle.abs(out - 1))
avg_loss.backward()
optimizer.minimize(avg_loss)
static_fn.clear_gradients()
paddle.jit.save(static_fn, self.train_model_path)
load_func = paddle.jit.load(self.train_model_path)
origin_res = static_fn(self.x).numpy()
load_res = load_func(self.x).numpy()
np.testing.assert_allclose(origin_res, load_res, rtol=1e-05)
class TestNoGradLinear(TestGradLinear):
def setUp(self):
self.func = NoGradLinearLayer()
self.x = paddle.ones(shape=[10, 2, 5], dtype='float32')
self.x.stop_gradient = False
self.temp_dir = tempfile.TemporaryDirectory()
self.infer_model_path = os.path.join(
self.temp_dir.name, 'no_grad_infer_model'
)
self.train_model_path = os.path.join(
self.temp_dir.name, 'no_grad_train_model'
)
def tearDown(self):
self.temp_dir.cleanup()
class UnuseGradVarLayer(paddle.nn.Layer):
def __init__(self):
super().__init__()
def forward(self, var_0, var_1):
var_1 = var_1 + 1
return var_0, var_1
class TestUnuseGradVar(Dy2StTestBase):
def test_run(self):
layer = UnuseGradVarLayer()
layer = paddle.jit.to_static(layer)
x = paddle.to_tensor([1.0])
y = paddle.to_tensor([2.0])
x.stop_gradient = False
y.stop_gradient = False
out1, out2 = layer(x, y)
out = out1 + out2
out.backward()
np.testing.assert_array_equal(out.numpy(), [4])
np.testing.assert_array_equal(x.grad.numpy(), [1])
class NoGradNet(paddle.nn.Layer):
def __init__(self):
super().__init__()
self.linear = paddle.nn.Linear(3, 4)
def forward(self, x):
with paddle.no_grad():
out = self.linear(x)
return out
class TestNoGrad(Dy2StTestBase):
def test_run(self):
net = NoGradNet()
net = paddle.jit.to_static(net)
x = paddle.rand([2, 3], 'float32')
x.stop_gradient = False
out = net(x)
np.testing.assert_array_equal(out.stop_gradient, True)
def grad_with_if_case(x):
y = paddle.tanh(x)
if x.numel() > 0:
return paddle.grad([y], [x])[0]
return paddle.ones_like(x, dtype='float32')
class TestGradWithIf(Dy2StTestBase):
@test_ast_only
def test_grad_with_if(self):
fn = grad_with_if_case
static_fn = paddle.jit.to_static(fn)
x = paddle.randn([2, 2])
x.stop_gradient = False
dx = fn(x)
dx_st = static_fn(x)
np.testing.assert_allclose(dx, dx_st)
if __name__ == '__main__':
unittest.main()