|
|
|
|
| import pytest |
| import torch |
| from transformers.configuration_utils import PretrainedConfig |
|
|
| from fla.utils import assert_close, device, is_intel_alchemist, is_nvidia_hopper |
|
|
| from .test_modeling_utils import ( |
| GENERATION_UNSUPPORTED, |
| HOPPER_EXCLUSIVE, |
| MODELING_UNSUPPORTED_VARLEN, |
| NOT_READY_FOR_TESTING, |
| create_model_and_config, |
| ) |
|
|
|
|
| |
| |
| |
| @pytest.mark.skipif( |
| is_intel_alchemist, |
| reason="Skipping test on Intel Alchemist due to known issues with SRAM.", |
| ) |
| def run_test_model_forward_backward( |
| L: int, |
| B: int, |
| T: int, |
| H: int, |
| D: int, |
| config_class: type, |
| use_l2warp: bool, |
| dtype: torch.dtype, |
| ): |
| """ |
| A foundational test for the forward and backward passes of a model. |
| """ |
| if not is_nvidia_hopper and D == 128: |
| pytest.skip("D=128 is only tested on Hopper GPUs to save CI time.") |
| if not is_nvidia_hopper and config_class.__name__ in HOPPER_EXCLUSIVE: |
| pytest.skip(f"{config_class.__name__} requires Hopper-specific features.") |
| if config_class.__name__ in NOT_READY_FOR_TESTING: |
| pytest.skip(f"{config_class.__name__} is not yet ready for testing.") |
|
|
| model, config = create_model_and_config(config_class, L, H, D, use_l2warp=use_l2warp, dtype=dtype) |
| input_ids = torch.randint(low=0, high=config.vocab_size, size=(B, T), device=device) |
| output_fixed = model(input_ids, output_hidden_states=True).hidden_states[-1] |
| assert output_fixed.shape == (B, T, config.hidden_size) |
|
|
| if config_class.__name__ in MODELING_UNSUPPORTED_VARLEN: |
| pytest.skip(f"Variable length not supported for {config_class.__name__}.") |
|
|
| cu_seqlens = torch.arange(0, B * T + 1, T, dtype=torch.int32, device=device) |
| output_var = model( |
| input_ids.view(1, B * T), output_hidden_states=True, cu_seqlens=cu_seqlens, |
| ).hidden_states[-1] |
| assert output_var.shape == (1, B * T, config.hidden_size) |
| assert_close("output", output_fixed.view(1, B * T, -1), output_var, 1e-3) |
| output_var.backward(torch.randn_like(output_var)) |
|
|
|
|
| |
| |
| |
| def run_test_generation( |
| L: int, |
| B: int, |
| T: int, |
| H: int, |
| D: int, |
| config_class: type, |
| dtype: torch.dtype, |
| use_l2warp: bool = False, |
| model: torch.nn.Module | None = None, |
| config: PretrainedConfig | None = None, |
| tol: float = 2e-3, |
| ): |
| """ |
| A foundational test for K/V cache-based generation. |
| """ |
| torch.manual_seed(42) |
| if config_class.__name__ in GENERATION_UNSUPPORTED: |
| pytest.skip(f"Generation test not supported for {config_class.__name__}.") |
| if config_class.__name__ in NOT_READY_FOR_TESTING: |
| pytest.skip(f"{config_class.__name__} is not yet ready for testing.") |
|
|
| if model is None: |
| model, config = create_model_and_config(config_class, L, H, D, use_l2warp=use_l2warp, dtype=dtype) |
| model.eval() |
| model = model.to(dtype).to(device) |
|
|
| num_chunks = 4 |
| chunk_size = T // num_chunks |
| input_ids = torch.randint(low=0, high=config.vocab_size, size=(B, T)).to(device) |
| attention_mask = torch.ones((B, T), dtype=torch.bool).to(device) |
| seq_start = torch.randint(low=1, high=chunk_size - 1, size=(B,)) |
| attention_mask[torch.arange(T) < seq_start[:, None]] = False |
| ref = torch.cat([ |
| model(input_ids=input_ids[i:i+1, start:], use_cache=False).logits |
| for i, start in enumerate(seq_start) |
| ], dim=1) |
|
|
| logits = [] |
| out = model( |
| input_ids=input_ids[:, :chunk_size], |
| attention_mask=attention_mask[:, :chunk_size], |
| use_cache=True, |
| past_key_values=None, |
| ) |
| logits, past_key_values = [out.logits], out.past_key_values |
| for i in range(1, num_chunks): |
| start, end = i * chunk_size, (i + 1) * chunk_size |
| for j in range(start, end): |
| out = model( |
| input_ids=input_ids[:, j:j+1], |
| attention_mask=attention_mask[:, :j+1], |
| use_cache=True, |
| past_key_values=past_key_values, |
| ) |
| logits.append(out.logits) |
| past_key_values = out.past_key_values |
| gen = torch.cat(logits, 1) |
| gen = torch.cat([gen[i:i+1, start:] for i, start in enumerate(seq_start)], 1) |
| assert_close('logits', ref, gen, tol) |
|
|