90 lines
3.8 KiB
Python
90 lines
3.8 KiB
Python
# Copyright (c) Microsoft Corporation.
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
# DeepSpeed Team
|
|
|
|
import functools
|
|
|
|
import pytest
|
|
import torch
|
|
import deepspeed.runtime.zero.linear as zero_linear
|
|
from deepspeed.runtime.zero.linear import LinearModuleForZeroStage3
|
|
from deepspeed.accelerator import get_accelerator
|
|
from deepspeed.utils.torch import required_torch_version
|
|
from unit.common import DistributedTest
|
|
|
|
|
|
@pytest.mark.parametrize('half_op', [False, True])
|
|
class TestAutoCastDisable(DistributedTest):
|
|
|
|
def test_missing_amp_autocast(self, half_op):
|
|
hidden_dim = 4
|
|
if half_op:
|
|
input = torch.randn(hidden_dim).to(get_accelerator().device_name()).half()
|
|
ds_linear = LinearModuleForZeroStage3(hidden_dim, hidden_dim).to(get_accelerator().device_name()).half()
|
|
else:
|
|
input = torch.randn(hidden_dim).to(get_accelerator().device_name())
|
|
ds_linear = LinearModuleForZeroStage3(hidden_dim, hidden_dim).to(get_accelerator().device_name())
|
|
|
|
output = ds_linear(input)
|
|
assert output.dtype == ds_linear.weight.dtype
|
|
|
|
def test_disable_autocast_linear(self, half_op):
|
|
hidden_dim = 4
|
|
if half_op:
|
|
input = torch.randn(hidden_dim).to(get_accelerator().device_name()).half()
|
|
ds_linear = LinearModuleForZeroStage3(hidden_dim, hidden_dim).to(get_accelerator().device_name()).half()
|
|
else:
|
|
input = torch.randn(hidden_dim).to(get_accelerator().device_name())
|
|
ds_linear = LinearModuleForZeroStage3(hidden_dim, hidden_dim).to(get_accelerator().device_name())
|
|
|
|
with torch.amp.autocast(device_type=get_accelerator().device_name(), enabled=False):
|
|
output = ds_linear(input)
|
|
assert output.dtype == ds_linear.weight.dtype
|
|
|
|
|
|
@pytest.mark.parametrize('half_input, half_weight', [(False, False), (False, True), (True, False), (True, True)])
|
|
class TestAutoCastEnable(DistributedTest):
|
|
|
|
def test_autocast_linear(self, tmpdir, half_input, half_weight):
|
|
hidden_dim = 4
|
|
input = torch.randn(hidden_dim).to(get_accelerator().device_name())
|
|
ds_linear = LinearModuleForZeroStage3(hidden_dim, hidden_dim).to(get_accelerator().device_name())
|
|
|
|
if half_input:
|
|
input = input.half()
|
|
|
|
if half_weight:
|
|
ds_linear = ds_linear.half()
|
|
|
|
with torch.amp.autocast(device_type=get_accelerator().device_name()):
|
|
output = ds_linear(input)
|
|
assert output.dtype == torch.half or output.dtype == torch.bfloat16
|
|
|
|
|
|
def test_get_autocast_decorators_use_torch_amp_on_torch_2_4_or_newer():
|
|
if not required_torch_version(min_version=2.4):
|
|
pytest.skip('torch.amp.custom_fwd/custom_bwd are only available on torch >= 2.4')
|
|
|
|
device_type = get_accelerator().device_name()
|
|
|
|
assert isinstance(zero_linear.autocast_custom_fwd, functools.partial)
|
|
assert isinstance(zero_linear.autocast_custom_bwd, functools.partial)
|
|
assert zero_linear.autocast_custom_fwd.func is torch.amp.custom_fwd
|
|
assert zero_linear.autocast_custom_bwd.func is torch.amp.custom_bwd
|
|
assert zero_linear.autocast_custom_fwd.keywords == {'device_type': device_type}
|
|
assert zero_linear.autocast_custom_bwd.keywords == {'device_type': device_type}
|
|
|
|
|
|
def test_get_autocast_decorators_use_legacy_amp_or_noop_before_torch_2_4():
|
|
if required_torch_version(min_version=2.4):
|
|
pytest.skip('legacy AMP fallback only applies on torch < 2.4')
|
|
|
|
device_type = get_accelerator().device_name()
|
|
legacy_amp = getattr(getattr(torch, device_type, None), 'amp', None)
|
|
expected_custom_fwd = getattr(legacy_amp, 'custom_fwd', zero_linear.noop_decorator)
|
|
expected_custom_bwd = getattr(legacy_amp, 'custom_bwd', zero_linear.noop_decorator)
|
|
|
|
assert zero_linear.autocast_custom_fwd is expected_custom_fwd
|
|
assert zero_linear.autocast_custom_bwd is expected_custom_bwd
|