| """ |
| 端到端正确性 + 误差分析:优化后的 CUDA infer_step 必须与普通 TTT layer 的 |
| forward 输出一致。 |
| |
| 对比链(同一份权重、同一份输入、真实 vision-expert 形状): |
| REF = 普通 TTT layer forward(全前缀因果 op, chunk=256) <- 黄金参考 |
| TORCH = 增量 torch (infer_build_state + infer_step, 无 CUDA) |
| CUDA = 增量 CUDA fused kernel (infer_step + use_cuda_kernel) |
| |
| 报告每条路径 vs REF 的: |
| - 绝对误差 max |a-b| |
| - 相对误差 max|a-b| / max|REF| |
| - 相对误差 (逐元素) mean |a-b|/(|REF|+eps) |
| fp32(查数学正确性) 和 bf16(查部署精度) 都测。 |
| |
| 判据: |
| fp32 CUDA vs REF 相对误差 < 1e-3 (matmul 形状不同导致的 cuBLAS rounding 量级) |
| bf16 CUDA vs REF 相对误差 < torch vs REF 的 1.5x (CUDA 不得比 torch 更不准) |
| |
| Run on any GPU (正确性对共享卡稳健): |
| TORCHDYNAMO_DISABLE=1 PYTHONPATH="$PWD" CUDA_VISIBLE_DEVICES=<x> \ |
| /mnt/afs-h200/yuyangcheng/venvs/fla_triton32/bin/python -m src.models.test_infer_correctness |
| """ |
| import sys |
| import torch |
| from src.models.ttt import FastWeightGluMLPMultihead |
|
|
| dev = "cuda" |
| HIDDEN, HEADS, L, TCTX = 768, 12, 256, 16 |
|
|
|
|
| def errs(ref, x): |
| ref = ref.float(); x = x.float() |
| d = (ref - x).abs() |
| abs_max = d.max().item() |
| denom = ref.abs().max().item() + 1e-12 |
| rel_max = abs_max / denom |
| rel_mean = (d / (ref.abs() + 1e-6)).mean().item() |
| return abs_max, rel_max, rel_mean |
|
|
|
|
| def build_pair(dtype): |
| torch.manual_seed(0) |
| ref = FastWeightGluMLPMultihead(dim=HIDDEN, head_dim=HIDDEN // HEADS, causal=True, |
| chunk_size=256, vlm_hidden_size=HIDDEN, |
| use_cuda_kernel=False).to(dev, dtype).eval() |
| cuda = FastWeightGluMLPMultihead(dim=HIDDEN, head_dim=HIDDEN // HEADS, causal=True, |
| chunk_size=256, vlm_hidden_size=HIDDEN, |
| use_cuda_kernel=True).to(dev, dtype).eval() |
| cuda.load_state_dict(ref.state_dict()) |
| return ref, cuda |
|
|
|
|
| def main(): |
| if not torch.cuda.is_available(): |
| print("SKIP: no CUDA"); return 0 |
| from src.models import ttt_cuda |
| ext = ttt_cuda._load_extension() |
| has_cuda = ext is not None and hasattr(ext, "infer_step") |
| print(f"CUDA infer_step kernel available: {has_cuda}\n") |
|
|
| results = [] |
| for dtype in (torch.float32, torch.bfloat16): |
| ref_layer, cuda_layer = build_pair(dtype) |
| g = torch.Generator(device=dev).manual_seed(7) |
| x = torch.randn(1, L, HIDDEN, generator=g, device=dev, dtype=dtype) |
| ctx = torch.randn(1, TCTX, HIDDEN, generator=g, device=dev, dtype=dtype) |
|
|
| with torch.no_grad(): |
| |
| ref_out, _ = ref_layer(x, {}, ctx) |
| |
| st_t = ref_layer.infer_build_state(ctx) |
| torch_out = torch.cat([ref_layer.infer_step(x[:, t:t+1], st_t) for t in range(L)], 1) |
| |
| st_c = cuda_layer.infer_build_state(ctx) |
| cuda_out = torch.cat([cuda_layer.infer_step(x[:, t:t+1], st_c) for t in range(L)], 1) |
|
|
| print(f"===== dtype = {dtype} =====") |
| a_t, rmax_t, rmean_t = errs(ref_out, torch_out) |
| a_c, rmax_c, rmean_c = errs(ref_out, cuda_out) |
| print(f" TORCH-incr vs REF : abs={a_t:.3e} rel_max={rmax_t:.3e} rel_mean={rmean_t:.3e}") |
| print(f" CUDA-incr vs REF : abs={a_c:.3e} rel_max={rmax_c:.3e} rel_mean={rmean_c:.3e}") |
| |
| a_ct, rmax_ct, rmean_ct = errs(torch_out, cuda_out) |
| print(f" CUDA vs TORCH : abs={a_ct:.3e} rel_max={rmax_ct:.3e} rel_mean={rmean_ct:.3e}") |
|
|
| if dtype == torch.float32: |
| ok = rmax_c < 1e-3 |
| print(f" -> fp32 criterion CUDA-vs-REF rel_max < 1e-3 : {'PASS' if ok else 'FAIL'}") |
| else: |
| |
| |
| |
| ref32, cuda32 = build_pair(torch.float32) |
| x32, ctx32 = x.float(), ctx.float() |
| with torch.no_grad(): |
| truth, _ = ref32(x32, {}, ctx32) |
| st_tt = ref32.infer_build_state(ctx32) |
| torch_t32 = torch.cat([ref32.infer_step(x32[:, t:t+1], st_tt) for t in range(L)], 1) |
| st_cc = cuda32.infer_build_state(ctx32) |
| cuda_t32 = torch.cat([cuda32.infer_step(x32[:, t:t+1], st_cc) for t in range(L)], 1) |
| _, rmax_truth_t, _ = errs(truth, torch_out) |
| _, rmax_truth_c, _ = errs(truth, cuda_out) |
| print(f" vs fp32-TRUTH: torch-bf16 rel_max={rmax_truth_t:.3e} cuda-bf16 rel_max={rmax_truth_c:.3e}") |
| ok = rmax_truth_c <= rmax_truth_t * 1.5 + 1e-6 |
| print(f" -> bf16 criterion cuda-bf16 closer-or-equal to truth vs torch : {'PASS' if ok else 'FAIL'}") |
| results.append(ok) |
| print() |
|
|
| allok = all(results) |
| print("=== CORRECTNESS", "PASS ===" if allok else "FAIL ===") |
| return 0 if allok else 1 |
|
|
|
|
| if __name__ == "__main__": |
| sys.exit(main()) |
|
|