Download code/models/tt_transformers/tests/test_model_prefill.py from raahemnabeel/qwen3-coder-next: direct link, hf CLI and curl.
- Browser
- Download file 13.2 kB
-
https://huggingface.co/raahemnabeel/qwen3-coder-next/resolve/main/code/models/tt_transformers/tests/test_model_prefill.py
- Command line
-
hf download hf://raahemnabeel/qwen3-coder-next/code/models/tt_transformers/tests/test_model_prefill.py
-
curl -L -o test_model_prefill.py https://huggingface.co/raahemnabeel/qwen3-coder-next/resolve/main/code/models/tt_transformers/tests/test_model_prefill.py
13.2 kB
| # SPDX-FileCopyrightText: © 2024 Tenstorrent USA, Inc. | |
| # SPDX-License-Identifier: Apache-2.0 | |
| import bz2 | |
| import os | |
| import pytest | |
| import torch | |
| from loguru import logger | |
| import ttnn | |
| from models.common.utility_functions import comp_pcc | |
| from models.tt_transformers.tt.common import PagedAttentionConfig, create_tt_model | |
| from models.tt_transformers.tt.generator import Generator | |
| from models.tt_transformers.tt.model_config import DecodersPrecision | |
| # Model and attention prefill tests should run both with and without paged attention to debug any issues that may occur with default attention | |
| def test_model_inference( | |
| paged_attention, | |
| page_params, | |
| optimizations, | |
| seq_len, | |
| max_seq_len, | |
| num_layers, | |
| mesh_device, | |
| reset_seeds, | |
| ensure_gc, | |
| is_ci_env, | |
| request, | |
| use_prefetcher, | |
| ): | |
| test_id = request.node.callspec.id | |
| use_hf_rope = request.config.getoption("--use_hf_rope") | |
| if is_ci_env: | |
| if "accuracy" in test_id: | |
| pytest.skip("CI test only runs performance mode to reduce CI pipeline load") | |
| # TODO: Save ref outputs to avoid running reference model for large seq_len | |
| if seq_len > 8192: | |
| pytest.skip("CI test only runs up to 8192 seq_len to avoid out of ram issues for ref model") | |
| if use_hf_rope: | |
| if num_layers != 1 and seq_len != 256: | |
| pytest.skip("When HF rope is used CI only runs full model for 256 seq len to reduce CI pipeline load") | |
| elif num_layers != 1 and seq_len != 4096: | |
| pytest.skip("CI only runs full model for 4k seq len to reduce CI pipeline load") | |
| hf_model_env = os.getenv("HF_MODEL", "") | |
| if ("Llama" in hf_model_env) and ("Vision" in hf_model_env) and (num_layers is None): | |
| pytest.skip("Skipping Llama Vision full model test: no CrossAttention functionality in this test.") | |
| run_ref_pt = True # Flag to run reference PyTorch model and compare PCC | |
| dtype = ttnn.bfloat8_b | |
| batch_size = 1 # For prefill we only support batch_size = 1 | |
| # Use instruct weights instead of general weights | |
| instruct = True | |
| paged_attention_config = ( | |
| PagedAttentionConfig( | |
| block_size=page_params["page_block_size"], | |
| max_num_blocks=page_params["page_max_num_blocks"], | |
| ) | |
| if paged_attention | |
| else None | |
| ) | |
| # Load TTNN model | |
| logger.info(f"Loading TT model...") | |
| model_args, tt_model, tt_kv_cache, state_dict = create_tt_model( | |
| mesh_device, | |
| instruct=instruct, | |
| max_batch_size=batch_size, | |
| optimizations=optimizations, | |
| max_seq_len=max_seq_len, | |
| paged_attention_config=paged_attention_config, | |
| dtype=dtype, | |
| num_layers=num_layers, | |
| use_prefetcher=use_prefetcher, | |
| use_hf_rope=use_hf_rope, | |
| ) | |
| if ( | |
| model_args.base_model_name.startswith("Mistral-") | |
| or model_args.base_model_name.startswith("Qwen3-") | |
| or model_args.base_model_name.startswith("Phi-3-mini-") | |
| or model_args.base_model_name.startswith("phi-4") | |
| ): | |
| # TODO: Per layer KV cache fetching is not implemented for all models | |
| # See issue https://github.com/tenstorrent/tt-metal/issues/19806" | |
| cache_pcc = False | |
| else: | |
| cache_pcc = True | |
| # This sets the minimum PCC for each iteration based on optimization mode | |
| # TODO: See issue https://github.com/tenstorrent/tt-metal/issues/19806 | |
| perf_out_pcc_map = {"Mistral-7B-Instruct-v0.3": 0.73} | |
| acc_out_pcc_map = { | |
| "Mistral-7B-Instruct-v0.3": 0.75, | |
| "Phi-3-mini-128k-instruct": 0.89, | |
| } | |
| kv_cache_pcc_map = {"Mistral-7B-Instruct-v0.3": 0.75} | |
| if num_layers == 1: | |
| expec_out_pcc = 0.97 | |
| expec_kv_cache_pcc = 0.99 | |
| else: | |
| if "accuracy" in test_id: | |
| default_expec_out_pcc = 0.91 # TODO Look on improving PCC | |
| expec_out_pcc = acc_out_pcc_map.get(model_args.model_name, default_expec_out_pcc) | |
| else: # performance mode | |
| assert "performance" in test_id | |
| default_expec_out_pcc = 0.869 # TODO Look on improving PCC | |
| expec_out_pcc = perf_out_pcc_map.get(model_args.model_name, default_expec_out_pcc) | |
| default_expec_kv_cache_pcc = 0.88 | |
| expec_kv_cache_pcc = kv_cache_pcc_map.get(model_args.model_name, default_expec_kv_cache_pcc) | |
| processor = model_args.processor | |
| tokenizer = model_args.tokenizer | |
| generator = Generator([tt_model], [model_args], mesh_device, processor=processor, tokenizer=tokenizer) | |
| logger.info("Finished loading TT model.") | |
| # Create page table if paged attention is enabled | |
| if paged_attention: | |
| # Implied shuffling of blocks | |
| permutation = torch.randperm(paged_attention_config.max_num_blocks) | |
| # Page table which maps virtual blocks to physical | |
| reverse_permutation = torch.argsort(permutation) | |
| page_table = reverse_permutation.reshape( | |
| model_args.max_batch_size, paged_attention_config.max_num_blocks // model_args.max_batch_size | |
| ) | |
| else: | |
| page_table = None | |
| # Load prompt | |
| current_file_path = os.path.abspath(__file__) | |
| current_file_dir = os.path.dirname(current_file_path) | |
| prompt_file = os.path.join(current_file_dir, "tale-of-two-cities.txt.bz2") | |
| with bz2.open(prompt_file, "rt", encoding="utf-8") as f: | |
| prompt = f.read() | |
| encoded_prompt = model_args.encode_prompt(prompt, instruct=instruct)[:seq_len] | |
| logger.info(f"Prompt length: {len(encoded_prompt)} tokens") | |
| # Load reference model | |
| if run_ref_pt: | |
| logger.info("Loading reference model...") | |
| # On a warm ttnn cache, create_tt_model defers the HF load and returns a dataless | |
| # placeholder state_dict. The host reference embedding below still needs the REAL weights, | |
| # so reload them here when the state_dict is a warm-cache placeholder (either flavor) or | |
| # genuinely empty. Branch on is_placeholder, NOT truthiness: tt_transformers' | |
| # _PlaceholderStateDict is falsy but the shared CachedStateDict is truthy, so `if not | |
| # state_dict` alone would silently stop reloading -- and build this torch reference from | |
| # torch.empty garbage -- if the loaders are ever collapsed onto the shared class. (#45400) | |
| if getattr(state_dict, "is_placeholder", False) or not state_dict: | |
| state_dict = model_args.load_state_dict() | |
| state_dict_prefix = model_args.get_state_dict_prefix("", None) | |
| reference_model = model_args.reference_transformer(load_checkpoint=True) | |
| # Embedding on host | |
| embd = model_args.reference_embedding() | |
| if model_args.is_llama_vision(): | |
| weight = torch.cat( | |
| [ | |
| state_dict[f"{state_dict_prefix}tok_embeddings.weight"], | |
| state_dict[f"{state_dict_prefix}learnable_embedding.weight"], | |
| ], | |
| dim=0, | |
| ) | |
| else: | |
| weight = state_dict[f"{state_dict_prefix}tok_embeddings.weight"] | |
| embd.load_state_dict({"emb.weight": weight}) | |
| logger.info("Finished loading reference model.") | |
| # Select the first token from the prompt for initial decoding | |
| encoded_prompt_tensor = torch.tensor(encoded_prompt) # [:,0] | |
| tt_prefill_input = encoded_prompt_tensor.unsqueeze(0) | |
| prompt_lens = [seq_len] | |
| start_pos = 0 | |
| # Run TT model | |
| logger.info(f"Running TT model...") | |
| tt_output_torch = generator.prefill_forward_text( | |
| tt_prefill_input, | |
| page_table=page_table, | |
| kv_cache=[tt_kv_cache], | |
| prompt_lens=prompt_lens, | |
| ) | |
| logger.info(f"Finished running TT model.") | |
| if run_ref_pt: | |
| # Run reference model | |
| logger.info(f"Running reference model...") | |
| pt_prefill_input = embd(encoded_prompt_tensor).view(batch_size, seq_len, -1) | |
| ref_output = reference_model(pt_prefill_input, start_pos) | |
| ref_output = ref_output[:, -1:, :] # Get last token since TT model only returns the last token | |
| logger.info(f"Finished running reference model.") | |
| # Measure PCC if also running reference model | |
| all_tests_pass = True | |
| # Check output pcc | |
| passing, pcc_message = comp_pcc(ref_output, tt_output_torch, expec_out_pcc) | |
| logger.info(f"Output PCC: {pcc_message}") | |
| if not passing: | |
| all_tests_pass = False | |
| logger.warning(f"Output PCC {pcc_message} is lower than {expec_out_pcc}") | |
| # Compare KV caches | |
| if cache_pcc: | |
| for i in range(model_args.n_layers): | |
| pytorch_layer_present = [ | |
| reference_model.cache_k[i].clone().permute(0, 2, 1, 3), # [batch_size, n_kv_heads, seq, head_dim] | |
| reference_model.cache_v[i].clone().permute(0, 2, 1, 3), # [batch_size, n_kv_heads, seq, head_dim] | |
| ] | |
| tt_layer_present = [] | |
| if paged_attention: | |
| for layer_past in tt_model.layers[i].attention.layer_past: | |
| tt_layer_present.append( | |
| ttnn.to_torch( | |
| layer_past, | |
| mesh_composer=ttnn.ConcatMesh2dToTensor( | |
| mesh_device, | |
| dims=(1, 3) if model_args.is_galaxy else (0, 1), | |
| mesh_shape=model_args.cluster_shape, | |
| ), | |
| )[reverse_permutation][:, : model_args.n_kv_heads, :, : model_args.head_dim] | |
| .reshape( | |
| model_args.max_batch_size, | |
| paged_attention_config.max_num_blocks // model_args.max_batch_size, | |
| model_args.n_kv_heads, | |
| paged_attention_config.block_size, | |
| model_args.head_dim, | |
| ) | |
| .transpose(1, 2) | |
| .reshape(model_args.max_batch_size, model_args.n_kv_heads, -1, model_args.head_dim)[ | |
| :batch_size, ... | |
| ] | |
| ) | |
| else: | |
| for layer_past in tt_model.layers[i].attention.layer_past_list[0]: | |
| tt_layer_present.append( | |
| ttnn.to_torch( | |
| layer_past, | |
| mesh_composer=ttnn.ConcatMesh2dToTensor( | |
| mesh_device, | |
| dims=(1, 0) if model_args.is_galaxy else (0, 1), | |
| mesh_shape=model_args.cluster_shape, | |
| ), | |
| ) | |
| ) | |
| for j, (cache_pt, cache_tt) in enumerate(zip(pytorch_layer_present, tt_layer_present)): | |
| cache_length_to_check = seq_len | |
| cache_pt = cache_pt[:, :, 0:cache_length_to_check, :] | |
| cache_tt = cache_tt[:, :, 0:cache_length_to_check, :] | |
| pcc_passed, output_pcc = comp_pcc(cache_pt, cache_tt, expec_kv_cache_pcc) | |
| kv_str = "K" if j == 0 else "V" | |
| logger.info(f"[layer={i+1}] {kv_str} cache PCC: {output_pcc}") | |
| if not pcc_passed: | |
| all_tests_pass = False | |
| logger.warning(f"[layer={i+1}] {kv_str} PCC {output_pcc} is lower than {expec_kv_cache_pcc}") | |
| if all_tests_pass: | |
| logger.info("All PCC checks passed!") | |
| else: | |
| assert all_tests_pass, f"PCC is lower than expected for some of the outputs. Check warnings!" | |