181 lines
6.2 KiB
Python
181 lines
6.2 KiB
Python
# Copyright (c) 2025 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
|
|
|
|
import paddle
|
|
from paddle.distributed.fleet.meta_parallel import zero_bubble_utils
|
|
|
|
|
|
class TestZuroBubble(unittest.TestCase):
|
|
def setUp(self):
|
|
paddle.seed(42)
|
|
|
|
def test_weight_grad_store(self):
|
|
def fake_func():
|
|
return
|
|
|
|
zero_bubble_utils.WeightGradStore.put(fake_func)
|
|
np.testing.assert_equal(
|
|
zero_bubble_utils.WeightGradStore.funcs_queue.empty(), True
|
|
)
|
|
zero_bubble_utils.WeightGradStore.flush()
|
|
np.testing.assert_equal(
|
|
zero_bubble_utils.WeightGradStore.funcs_queue.empty(), False
|
|
)
|
|
zero_bubble_utils.WeightGradStore.pop()
|
|
np.testing.assert_equal(
|
|
zero_bubble_utils.WeightGradStore.funcs_queue.empty(), True
|
|
)
|
|
|
|
def test_zero_bubble_utils(self):
|
|
zero_bubble_utils.WeightGradStore.enabled = False
|
|
|
|
paddle.seed(42)
|
|
input = paddle.randn([2, 4096, 2048])
|
|
input.stop_gradient = False
|
|
splitbw_linear = zero_bubble_utils.SplitBWLinear(
|
|
2048, 2048, bias_attr=True
|
|
)
|
|
o = splitbw_linear(input)
|
|
o.mean().backward()
|
|
|
|
paddle.seed(42)
|
|
ref_input = paddle.randn([2, 4096, 2048])
|
|
ref_input.stop_gradient = False
|
|
ref_linear = paddle.nn.Linear(2048, 2048, bias_attr=True)
|
|
o_ref = ref_linear(ref_input)
|
|
o_ref.mean().backward()
|
|
|
|
np.testing.assert_equal(o._md5sum(), o_ref._md5sum())
|
|
np.testing.assert_equal(input.grad._md5sum(), ref_input.grad._md5sum())
|
|
np.testing.assert_equal(
|
|
splitbw_linear.weight.grad._md5sum(),
|
|
ref_linear.weight.grad._md5sum(),
|
|
)
|
|
np.testing.assert_equal(
|
|
splitbw_linear.bias.grad._md5sum(), ref_linear.bias.grad._md5sum()
|
|
)
|
|
|
|
zero_bubble_utils.WeightGradStore.enabled = True
|
|
|
|
paddle.seed(42)
|
|
input = paddle.randn([2, 4096, 2048])
|
|
input.stop_gradient = False
|
|
splitbw_linear = zero_bubble_utils.SplitBWLinear(
|
|
2048, 2048, bias_attr=True
|
|
)
|
|
o = splitbw_linear(input)
|
|
o.mean().backward()
|
|
np.testing.assert_equal(splitbw_linear.weight.grad, None)
|
|
zero_bubble_utils.WeightGradStore.flush()
|
|
zero_bubble_utils.WeightGradStore.pop()
|
|
np.testing.assert_equal(
|
|
splitbw_linear.weight.grad._md5sum(),
|
|
ref_linear.weight.grad._md5sum(),
|
|
)
|
|
|
|
def test_zero_bubble_utils_no_bias(self):
|
|
zero_bubble_utils.WeightGradStore.enabled = True
|
|
|
|
paddle.seed(42)
|
|
ref_input = paddle.randn([2, 4096, 2048])
|
|
ref_input.stop_gradient = False
|
|
ref_linear = paddle.nn.Linear(2048, 2048, bias_attr=False)
|
|
o_ref = ref_linear(ref_input)
|
|
o_ref.mean().backward()
|
|
|
|
paddle.seed(42)
|
|
input = paddle.randn([2, 4096, 2048])
|
|
input.stop_gradient = False
|
|
splitbw_linear = zero_bubble_utils.SplitBWLinear(
|
|
2048, 2048, bias_attr=False
|
|
)
|
|
o = splitbw_linear(input)
|
|
o.mean().backward()
|
|
|
|
np.testing.assert_equal(splitbw_linear.weight.grad, None)
|
|
|
|
zero_bubble_utils.WeightGradStore.flush()
|
|
zero_bubble_utils.WeightGradStore.pop()
|
|
|
|
np.testing.assert_equal(o._md5sum(), o_ref._md5sum())
|
|
np.testing.assert_equal(input.grad._md5sum(), ref_input.grad._md5sum())
|
|
np.testing.assert_equal(
|
|
splitbw_linear.weight.grad._md5sum(),
|
|
ref_linear.weight.grad._md5sum(),
|
|
)
|
|
|
|
def test_zero_bubble_with_main_grad(self):
|
|
def _update_main_grad_hook(param):
|
|
@paddle.autograd.no_grad()
|
|
def param_hook(tmp_grad):
|
|
if tmp_grad is not None and tmp_grad._is_initialized():
|
|
if param.main_grad is None:
|
|
param.main_grad = (
|
|
paddle.base.framework.core.eager.Tensor(
|
|
value=tmp_grad.cast(paddle.float32).value(),
|
|
place=tmp_grad.place,
|
|
name="main_grad@" + param.name,
|
|
)
|
|
)
|
|
else:
|
|
# 梯度累加
|
|
param.main_grad.add_(tmp_grad)
|
|
|
|
tmp_grad._clear_data()
|
|
|
|
return param_hook
|
|
|
|
zero_bubble_utils.WeightGradStore.enabled = False
|
|
|
|
paddle.seed(42)
|
|
ref_input = paddle.randn([2, 4096, 2048])
|
|
ref_input.stop_gradient = False
|
|
ref_linear = paddle.nn.Linear(2048, 2048, bias_attr=False)
|
|
|
|
paddle.seed(42)
|
|
input = paddle.randn([2, 4096, 2048])
|
|
input.stop_gradient = False
|
|
splitbw_linear = zero_bubble_utils.SplitBWLinear(
|
|
2048, 2048, bias_attr=False
|
|
)
|
|
|
|
for param in splitbw_linear.parameters():
|
|
if not hasattr(param, "main_grad"):
|
|
param.main_grad = None
|
|
param._register_grad_hook(_update_main_grad_hook(param))
|
|
for param in ref_linear.parameters():
|
|
if not hasattr(param, "main_grad"):
|
|
param.main_grad = None
|
|
param._register_grad_hook(_update_main_grad_hook(param))
|
|
|
|
o_ref = ref_linear(ref_input)
|
|
o_ref.mean().backward()
|
|
o = splitbw_linear(input)
|
|
o.mean().backward()
|
|
|
|
np.testing.assert_equal(o._md5sum(), o_ref._md5sum())
|
|
np.testing.assert_equal(input.grad._md5sum(), ref_input.grad._md5sum())
|
|
np.testing.assert_equal(
|
|
splitbw_linear.weight.main_grad._md5sum(),
|
|
ref_linear.weight.main_grad._md5sum(),
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|