|
|
| import pytest |
| import torch |
| import torch.nn as nn |
| import torch.nn.functional as F |
|
|
| from fla.modules import FusedLinearCrossEntropyLoss |
| from fla.modules.l2warp import l2_warp as standalone_l2_warp |
| from fla.utils import assert_close, device, is_intel_alchemist |
|
|
|
|
| @pytest.mark.parametrize("dtype", [torch.float32, torch.bfloat16]) |
| @pytest.mark.parametrize("B", [4, 8]) |
| @pytest.mark.parametrize("T", [1024]) |
| @pytest.mark.parametrize("H", [256]) |
| @pytest.mark.parametrize("V", [2000]) |
| @pytest.mark.parametrize("l2_penalty_factor", [1e-4, 1]) |
| @pytest.mark.skipif( |
| is_intel_alchemist is True, |
| reason="Intel Triton Failure", |
| ) |
| def test_fused_linear_cross_entropy_l2_warp( |
| B: int, |
| T: int, |
| H: int, |
| V: int, |
| l2_penalty_factor: float, |
| dtype: torch.dtype, |
| ): |
| torch.manual_seed(42) |
|
|
| lm_head = nn.Linear(H, V, bias=True, device=device, dtype=dtype) |
| x = torch.randn(B, T, H, device=device, dtype=dtype, requires_grad=True) |
| labels = torch.randint(0, V, (B, T), device=device) |
|
|
| ignore_index = -100 |
| shift_labels = torch.cat((labels[..., 1:], torch.full_like(labels[:, :1], ignore_index)), 1) |
|
|
| ref_criterion = nn.CrossEntropyLoss() |
|
|
| ref_logits = F.linear(x.view(-1, H), lm_head.weight, lm_head.bias) |
| ref_loss_ce = ref_criterion(ref_logits.view(B * T, V), shift_labels.view(-1)) |
| ref_loss = standalone_l2_warp(ref_loss_ce, ref_logits.view(B, T, V), l2_penalty_factor) |
|
|
| ref_loss.backward() |
| ref_x_grad = x.grad.clone() |
| ref_w_grad = lm_head.weight.grad.clone() |
| ref_b_grad = lm_head.bias.grad.clone() |
|
|
| x.grad = None |
| lm_head.zero_grad() |
|
|
| fused_criterion = FusedLinearCrossEntropyLoss( |
| l2_penalty_factor=l2_penalty_factor, |
| use_l2warp=True, |
| ) |
|
|
| fused_loss = fused_criterion(x, shift_labels, lm_head.weight, lm_head.bias) |
|
|
| fused_loss.backward() |
| fused_x_grad = x.grad.clone() |
| fused_w_grad = lm_head.weight.grad.clone() |
| fused_b_grad = lm_head.bias.grad.clone() |
|
|
| ratio = 4e-3 if dtype == torch.bfloat16 else 1e-3 |
|
|
| assert_close("Loss", ref_loss, fused_loss, ratio) |
| assert_close("dx", ref_x_grad, fused_x_grad, ratio) |
| assert_close("dw", ref_w_grad, fused_w_grad, ratio) |
| assert_close("db", ref_b_grad, fused_b_grad, ratio) |
|
|