| """ | |
| GPU-Specific Execution & Hardware Validation Test Suite. | |
| Designed to validate real CUDA execution, multi-precision autocasting (FP16/BF16), | |
| peak memory tracking, DDP distribution, and numerical stability on GPU hardware. | |
| Run: pytest Codes/framework/tests/test_gpu_execution.py -v --timeout=300 | |
| """ | |
| import math | |
| import sys | |
| import os | |
| from typing import Dict, List | |
| import pytest | |
| import torch | |
| import torch.nn as nn | |
| sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../../..")) | |
| from framework.eval_all_models_datasets import ( | |
| build_model_instance, | |
| apply_module_to_model, | |
| get_dataset_batch, | |
| _filter_batch, | |
| _extract_logits_and_loss, | |
| ) | |
| from framework.core.registry import ATTENTION_REGISTRY, COMPRESSOR_REGISTRY | |
| CUDA_AVAILABLE = torch.cuda.is_available() | |
| MODEL_FAMILIES = ["bert", "roberta", "t5", "distilbert", "gpt2"] | |
| def make_gpu_batch(family: str, batch_size: int = 4, seq_len: int = 32, device: str = "cuda") -> Dict[str, torch.Tensor]: | |
| """Generates a test batch directly on target CUDA device.""" | |
| vocab_size = 50265 if family == "roberta" else (50257 if family == "gpt2" else 30522) | |
| dev = torch.device(device) | |
| b = { | |
| "input_ids": torch.randint(100, vocab_size - 100, (batch_size, seq_len), device=dev), | |
| "attention_mask": torch.ones(batch_size, seq_len, dtype=torch.long, device=dev), | |
| } | |
| if family not in {"t5", "gpt2"}: | |
| b["token_type_ids"] = torch.zeros(batch_size, seq_len, dtype=torch.long, device=dev) | |
| if family == "gpt2": | |
| b["labels"] = torch.randint(100, vocab_size - 100, (batch_size, seq_len), device=dev) | |
| elif family != "t5": | |
| b["labels"] = torch.zeros(batch_size, dtype=torch.long, device=dev) | |
| return b | |
| def test_model_moves_to_cuda(family: str): | |
| """Verifies that every model family moves onto CUDA and parameters reside on GPU memory.""" | |
| device = torch.device("cuda:0") | |
| model, cfg = build_model_instance( | |
| family, num_labels=2, hidden_size=64, num_heads=4, num_layers=1, device=device | |
| ) | |
| assert isinstance(model, nn.Module) | |
| first_param = next(model.parameters()) | |
| assert first_param.is_cuda is True, f"{family} parameters not placed on CUDA" | |
| assert first_param.device.type == "cuda" | |
| def test_forward_pass_on_cuda(family: str): | |
| """Executes a full forward pass on GPU memory asserting outputs reside on CUDA.""" | |
| device = torch.device("cuda:0") | |
| model, _ = build_model_instance( | |
| family, num_labels=2, hidden_size=64, num_heads=4, num_layers=1, device=device | |
| ) | |
| batch = make_gpu_batch(family, batch_size=4, seq_len=32, device="cuda:0") | |
| batch = _filter_batch(batch, family, model) | |
| model.eval() | |
| with torch.no_grad(): | |
| out = model(**batch) | |
| assert out is not None | |
| logits, loss = _extract_logits_and_loss(out, num_labels=2, labels=batch.get("labels")) | |
| if logits is not None: | |
| assert logits.is_cuda is True, "Output logits not on CUDA" | |
| elif loss is not None: | |
| assert loss.is_cuda is True, "Output loss not on CUDA" | |
| def test_mixed_precision_autocast(module_name: str, precision_dtype: torch.dtype): | |
| """Tests forward pass under AMP autocast (FP16/BF16) asserting zero NaN/Inf outputs.""" | |
| if precision_dtype == torch.bfloat16 and not torch.cuda.is_bf16_supported(): | |
| pytest.skip("BFloat16 not supported on this CUDA hardware") | |
| device = torch.device("cuda:0") | |
| model, _ = build_model_instance("bert", num_labels=2, hidden_size=64, num_heads=4, num_layers=1, device=device) | |
| model, _ = apply_module_to_model(model, module_name, "attention", rank=8, device=device) | |
| batch = make_gpu_batch("bert", batch_size=4, seq_len=32, device="cuda:0") | |
| batch = _filter_batch(batch, "bert", model) | |
| model.eval() | |
| with torch.no_grad(): | |
| with torch.autocast(device_type="cuda", dtype=precision_dtype): | |
| out = model(**batch) | |
| logits, loss = _extract_logits_and_loss(out, num_labels=2, labels=batch.get("labels")) | |
| target_tensor = logits if logits is not None else loss | |
| assert target_tensor is not None | |
| assert not torch.isnan(target_tensor).any(), f"NaN detected under {precision_dtype} in {module_name}" | |
| assert not torch.isinf(target_tensor).any(), f"Inf detected under {precision_dtype} in {module_name}" | |
| def test_peak_memory_tracking(): | |
| """Verifies that PyTorch CUDA memory tracking produces finite, non-zero allocations.""" | |
| device = torch.device("cuda:0") | |
| torch.cuda.reset_peak_memory_stats(device) | |
| model, _ = build_model_instance("bert", num_labels=2, hidden_size=128, num_heads=4, num_layers=2, device=device) | |
| batch = make_gpu_batch("bert", batch_size=8, seq_len=64, device="cuda:0") | |
| model.train() | |
| out = model(**batch) | |
| loss = out.loss if hasattr(out, "loss") and out.loss is not None else out[0].sum() | |
| loss.backward() | |
| peak_allocated = torch.cuda.max_memory_allocated(device) | |
| assert peak_allocated > 0, "Reported peak CUDA memory allocation was 0 bytes" | |
| assert not math.isnan(peak_allocated) and not math.isinf(peak_allocated) | |
| def test_multi_gpu_ddp_smoke(): | |
| """Validates DistributedDataParallel setup across multiple CUDA devices.""" | |
| assert torch.cuda.device_count() >= 2 | |
| def test_compression_engine_gpu_numerical_stability(comp_name: str): | |
| """Tests compression engines under FP16 autocasting ensuring covariance computation doesn't overflow.""" | |
| device = torch.device("cuda:0") | |
| model, _ = build_model_instance("bert", num_labels=2, hidden_size=64, num_heads=4, num_layers=1, device=device) | |
| # Apply compression on GPU | |
| compressed_model, ratio = apply_module_to_model(model, comp_name, "compressor", rank=8, device=device) | |
| batch = make_gpu_batch("bert", batch_size=4, seq_len=32, device="cuda:0") | |
| batch = _filter_batch(batch, "bert", compressed_model) | |
| compressed_model.eval() | |
| with torch.no_grad(): | |
| with torch.autocast(device_type="cuda", dtype=torch.float16): | |
| out = compressed_model(**batch) | |
| logits, loss = _extract_logits_and_loss(out, num_labels=2, labels=batch.get("labels")) | |
| target_tensor = logits if logits is not None else loss | |
| assert target_tensor is not None | |
| assert not torch.isnan(target_tensor).any(), f"NaN detected after {comp_name} compression on GPU" | |
| assert not torch.isinf(target_tensor).any(), f"Inf detected after {comp_name} compression on GPU" | |
Xet Storage Details
- Size:
- 7.29 kB
- Xet hash:
- 46b80f419df77d4bb5e75df7b2ed0a06434b8399df878591d8e5cbaebf7b401e
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.