153 lines
5.8 KiB
Python
153 lines
5.8 KiB
Python
# Copyright (c) 2023 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 op_test import get_device_place, is_custom_device
|
|
from simple_nets import simple_fc_net_with_inputs
|
|
|
|
import paddle
|
|
from paddle.base.dygraph.base import switch_to_static_graph
|
|
from paddle.device.cuda.graphs import CUDAGraph
|
|
|
|
|
|
def can_use_cuda_graph():
|
|
return (
|
|
paddle.is_compiled_with_cuda() or is_custom_device()
|
|
) and not paddle.is_compiled_with_rocm()
|
|
|
|
|
|
def build_program(main, startup, batch_size, class_num):
|
|
image_shape = [batch_size, 784]
|
|
label_shape = [batch_size, 1]
|
|
with paddle.static.program_guard(main, startup):
|
|
image = paddle.static.data(
|
|
name="image", shape=image_shape, dtype='float32'
|
|
)
|
|
label = paddle.static.data(
|
|
name="label", shape=label_shape, dtype='int64'
|
|
)
|
|
image.persistable = True
|
|
label.persistable = True
|
|
loss = simple_fc_net_with_inputs(image, label, class_num)
|
|
loss.persistable = True
|
|
lr = paddle.optimizer.lr.PiecewiseDecay(
|
|
boundaries=[2, 3, 4], values=[0.01, 0.02, 0.03, 0.04]
|
|
)
|
|
optimizer = paddle.optimizer.SGD(learning_rate=lr)
|
|
optimizer.minimize(loss)
|
|
return image, label, loss, lr
|
|
|
|
|
|
@unittest.skipIf(
|
|
not (paddle.is_compiled_with_cuda() or is_custom_device())
|
|
or float(paddle.version.cuda()) < 11.0,
|
|
"only support cuda >= 11.0",
|
|
)
|
|
class TestCUDAGraphInStaticMode(unittest.TestCase):
|
|
def setUp(self):
|
|
if can_use_cuda_graph():
|
|
# The behavior of `FLAGS_use_stream_safe_cuda_allocator` in static
|
|
# mode is inconsistent with that in dygraph mode.
|
|
# In static mode, FLAGS_use_stream_safe_cuda_allocator must be True.
|
|
# In dygraph mode, FLAGS_use_stream_safe_cuda_allocator must be False.
|
|
# These two types of unittests need to be written separately, because
|
|
# the allocator may only be initialized once, and the flag
|
|
# `FLAGS_use_stream_safe_cuda_allocator` only takes effect during
|
|
# initialization.
|
|
paddle.set_flags(
|
|
{
|
|
'FLAGS_allocator_strategy': 'auto_growth',
|
|
'FLAGS_sync_nccl_allreduce': False,
|
|
'FLAGS_cudnn_deterministic': True,
|
|
'FLAGS_use_stream_safe_cuda_allocator': True,
|
|
}
|
|
)
|
|
|
|
@switch_to_static_graph
|
|
def test_cuda_graph_static_graph(self):
|
|
if not can_use_cuda_graph():
|
|
return
|
|
|
|
seed = 100
|
|
loss_cuda_graph = self.cuda_graph_static_graph_main(
|
|
seed, use_cuda_graph=True
|
|
)
|
|
loss_no_cuda_graph = self.cuda_graph_static_graph_main(
|
|
seed, use_cuda_graph=False
|
|
)
|
|
self.assertEqual(loss_cuda_graph, loss_no_cuda_graph)
|
|
|
|
def cuda_graph_static_graph_main(self, seed, use_cuda_graph):
|
|
with paddle.pir_utils.OldIrGuard():
|
|
batch_size = 1
|
|
class_num = 10
|
|
image_shape = [batch_size, 784]
|
|
label_shape = [batch_size, 1]
|
|
|
|
paddle.seed(seed)
|
|
np.random.seed(seed)
|
|
startup = paddle.static.Program()
|
|
main = paddle.static.Program()
|
|
|
|
image, label, loss, lr = build_program(
|
|
main, startup, batch_size, class_num
|
|
)
|
|
|
|
place = get_device_place()
|
|
exe = paddle.static.Executor(place)
|
|
scope = paddle.static.Scope()
|
|
with paddle.static.scope_guard(scope):
|
|
exe.run(startup)
|
|
build_strategy = paddle.static.BuildStrategy()
|
|
build_strategy.allow_cuda_graph_capture = True
|
|
build_strategy.fuse_all_optimizer_ops = True
|
|
compiled_program = paddle.static.CompiledProgram(
|
|
main, build_strategy=build_strategy
|
|
)
|
|
image_t = scope.var(image.name).get_tensor()
|
|
label_t = scope.var(label.name).get_tensor()
|
|
loss_t = scope.var(loss.name).get_tensor()
|
|
lr_var = main.global_block().var(lr._var_name)
|
|
self.assertTrue(lr_var.persistable)
|
|
lr_t = scope.var(lr_var.name).get_tensor()
|
|
cuda_graph = None
|
|
for batch_id in range(20):
|
|
image_np = np.random.rand(*image_shape).astype('float32')
|
|
label_np = np.random.randint(
|
|
low=0, high=class_num, size=label_shape, dtype='int64'
|
|
)
|
|
image_t.set(image_np, place)
|
|
label_t.set(label_np, place)
|
|
|
|
if batch_id == 1 and use_cuda_graph:
|
|
cuda_graph = CUDAGraph(place, mode="global")
|
|
cuda_graph.capture_begin()
|
|
exe.run(compiled_program)
|
|
cuda_graph.capture_end()
|
|
|
|
if cuda_graph:
|
|
lr_t.set(np.array([lr()], dtype='float32'), place)
|
|
cuda_graph.replay()
|
|
else:
|
|
exe.run(compiled_program)
|
|
lr.step()
|
|
if cuda_graph:
|
|
cuda_graph.reset()
|
|
return np.array(loss_t)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|