|
|
| import pytest |
| import torch |
| import torch.nn as nn |
| import torch.nn.functional as F |
|
|
| from fla.modules import FusedCrossEntropyLoss, FusedLinearCrossEntropyLoss |
| from fla.utils import assert_close, device, device_platform |
|
|
|
|
| @pytest.mark.parametrize("B", [2]) |
| @pytest.mark.parametrize("T", [512, 1024]) |
| @pytest.mark.parametrize("D", [1024, 2048]) |
| @pytest.mark.parametrize("V", [32000, 100000]) |
| @pytest.mark.parametrize("reduction", ['mean']) |
| @pytest.mark.parametrize("dtype", [torch.bfloat16]) |
| @pytest.mark.skipif( |
| device_platform == 'intel', |
| reason="Intel Triton Failure", |
| ) |
| def test_fused_cross_entropy(B: int, T: int, D: int, V: int, reduction: str, dtype: torch.dtype): |
| torch.manual_seed(42) |
| logits = torch.randn(B * T, V).to(device).to(dtype=dtype).requires_grad_() |
| target = torch.randint(0, V, (B, T)).to(device) |
| target = torch.cat((target[..., 1:], torch.full_like(target[..., :1], -100)), -1) |
| target = target.flatten() |
|
|
| ref = nn.CrossEntropyLoss(reduction=reduction)(logits, target).to(dtype=dtype) |
| do = torch.randn_like(ref).to(device).to(dtype=dtype) |
|
|
| ref.backward(do) |
| ref_d, logits.grad = logits.grad.clone(), None |
|
|
| tri = FusedCrossEntropyLoss(reduction=reduction)(logits, target).to(dtype=dtype) |
| tri.backward(do) |
| tri_d, logits.grad = logits.grad.clone(), None |
|
|
| assert_close(" o", ref, tri, ratio=1e-2) |
| assert_close("dl", ref_d, tri_d, ratio=1e-2) |
|
|
|
|
| @pytest.mark.parametrize("B", [2]) |
| @pytest.mark.parametrize("T", [512, 1024]) |
| @pytest.mark.parametrize("D", [1024, 2048]) |
| @pytest.mark.parametrize("V", [32000, 100000]) |
| @pytest.mark.parametrize("scale", [1., 0.5]) |
| @pytest.mark.parametrize("reduction", ['mean']) |
| @pytest.mark.parametrize("dtype", [torch.bfloat16]) |
| @pytest.mark.skipif( |
| device_platform == 'intel', |
| reason="Intel Triton Failure", |
| ) |
| def test_fused_linear_cross_entropy(B: int, T: int, D: int, V: int, scale: float, reduction: str, dtype: torch.dtype): |
| torch.manual_seed(42) |
|
|
| x = torch.randn(B * T, D).to(device).to(dtype=dtype).requires_grad_() |
| target = torch.randint(0, V, (B, T)).to(device) |
| target = torch.cat((target[..., 1:], torch.full_like(target[..., :1], -100)), -1) |
| target = target.flatten() |
| weight = torch.randn(V, D).to(device).to(dtype=dtype).requires_grad_() |
| bias = torch.randn(V).to(device).to(dtype=dtype).requires_grad_() |
|
|
| logits = F.linear(x, weight, bias) |
| ref = FusedCrossEntropyLoss(logit_scale=scale, reduction=reduction)(logits, target) |
| do = torch.randn_like(ref).to(device).to(dtype=dtype) |
|
|
| ref.backward(do) |
| ref_dx, x.grad = x.grad.clone(), None |
| ref_dw, weight.grad = weight.grad.clone(), None |
| ref_db, bias.grad = bias.grad.clone(), None |
|
|
| tri = FusedLinearCrossEntropyLoss(logit_scale=scale, reduction=reduction)(x, target, weight, bias) |
| tri.backward(do) |
| tri_dx, x.grad = x.grad.clone(), None |
| tri_dw, weight.grad = weight.grad.clone(), None |
| tri_db, bias.grad = bias.grad.clone(), None |
|
|
| assert_close(" o", ref, tri, ratio=1e-2) |
| assert_close("dx", ref_dx, tri_dx, ratio=1e-2) |
| assert_close("dw", ref_dw, tri_dw, ratio=1e-2) |
| assert_close("db", ref_db, tri_db, ratio=1e-2) |
|
|