From cb7213ca8bbc9f9da52a36c264621b440cf56214 Mon Sep 17 00:00:00 2001 From: nikileshx Date: Fri, 22 Aug 2025 06:49:17 +0000 Subject: [PATCH 1/3] Refactor comments and clean code --- .../tt_transformers/tt/multimodal/mistral_24b/vision_mmp.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/models/tt_transformers/tt/multimodal/mistral_24b/vision_mmp.py b/models/tt_transformers/tt/multimodal/mistral_24b/vision_mmp.py index 2dd21e0d0177..24ca475be121 100644 --- a/models/tt_transformers/tt/multimodal/mistral_24b/vision_mmp.py +++ b/models/tt_transformers/tt/multimodal/mistral_24b/vision_mmp.py @@ -12,6 +12,10 @@ from models.tt_transformers.tt.multimodal.mistral_24b.rmsnorm import RMSNorm from ttnn import ConcatMeshToTensor +""" +This file implements the Vision pixtral image submodule specific for the Mistral-Small-3.1-24B-Instruct-2503 model. +""" + class TTMistral3PatchMerger(LightweightModule): def __init__( From d5cffed7c5840530ca3fc12d913de11b8f2f9018 Mon Sep 17 00:00:00 2001 From: nikileshx Date: Fri, 22 Aug 2025 13:56:15 +0000 Subject: [PATCH 2/3] Address comments and refactor comments --- .../tt_transformers/tt/multimodal/mistral_24b/vision_mmp.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/models/tt_transformers/tt/multimodal/mistral_24b/vision_mmp.py b/models/tt_transformers/tt/multimodal/mistral_24b/vision_mmp.py index 24ca475be121..2dd21e0d0177 100644 --- a/models/tt_transformers/tt/multimodal/mistral_24b/vision_mmp.py +++ b/models/tt_transformers/tt/multimodal/mistral_24b/vision_mmp.py @@ -12,10 +12,6 @@ from models.tt_transformers.tt.multimodal.mistral_24b.rmsnorm import RMSNorm from ttnn import ConcatMeshToTensor -""" -This file implements the Vision pixtral image submodule specific for the Mistral-Small-3.1-24B-Instruct-2503 model. -""" - class TTMistral3PatchMerger(LightweightModule): def __init__( From ea7a53ff2886a95dd2f6379ac6064a39e14413dd Mon Sep 17 00:00:00 2001 From: nikileshx Date: Fri, 22 Aug 2025 11:03:06 +0000 Subject: [PATCH 3/3] Mistral-24B: Evaluate performance metrics --- .github/workflows/t3000-demo-tests-impl.yaml | 1 + models/tt_transformers/PERF.md | 2 ++ .../tt_transformers/demo/simple_text_demo.py | 12 ++++++++- .../demo/simple_vision_demo.py | 3 +++ .../Mistral-Small-3.1-24B-Instruct-2503.refpt | Bin 0 -> 50880 bytes tests/scripts/t3000/run_t3000_demo_tests.sh | 24 ++++++++++++++++++ 6 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 models/tt_transformers/tests/reference_outputs/Mistral-Small-3.1-24B-Instruct-2503.refpt diff --git a/.github/workflows/t3000-demo-tests-impl.yaml b/.github/workflows/t3000-demo-tests-impl.yaml index c5b6c5c6548f..b1cf66be4eec 100644 --- a/.github/workflows/t3000-demo-tests-impl.yaml +++ b/.github/workflows/t3000-demo-tests-impl.yaml @@ -40,6 +40,7 @@ jobs: # This requirements and comment removed when https://github.com/tenstorrent/tt-metal/pull/22608 merges. { name: "t3k_qwen3_tests", arch: wormhole_b0, cmd: run_t3000_qwen3_tests, timeout: 60, owner_id: U03HY7MK4BT}, # Mark O'Connor { name: "t3k_qwen25_vl_tests", arch: wormhole_b0, cmd: run_t3000_qwen25_vl_tests, timeout: 60, owner_id: U07RY6B5FLJ}, #Gongyu Wang + # { name: "t3k_mistral_24b_tests", arch: wormhole_b0, cmd: run_t3000_mistral_24b_tests, timeout: 60, owner_id: }, # TO-DO: Requires owner ID ] name: ${{ matrix.test-group.name }} diff --git a/models/tt_transformers/PERF.md b/models/tt_transformers/PERF.md index 26d1fb377913..b1d51109012a 100644 --- a/models/tt_transformers/PERF.md +++ b/models/tt_transformers/PERF.md @@ -45,6 +45,7 @@ This configuration uses bfp4 MLP and bfp8 attention weights for all models excep | Mistral-7B | N150 | 95 | 99 | 29.75 | 100.24 | | Mistral-7B | N300 | 95 | 99 | 47.01 | 65.95 | | Mistral-7B | T3K | 95 | 99 | 67.82 | 53.93 | +| Mistral-24B | T3K | 95 | 100 | 37.77 | 131.6ms | ## Accuracy @@ -82,6 +83,7 @@ Llama 3 models test as insensitive to attention precision and so we use bfp8 att | Mistral-7B | N150 | 95 | 99 | 29.75 | 100.24 | | Mistral-7B | N300 | 95 | 99 | 47.01 | 65.95 | | Mistral-7B | T3K | 95 | 99 | 67.82 | 53.93 | +| Mistral-24B | T3K | 95 | 100 | 33.27 | 130.39ms | ## Long-context (64K Tokens) diff --git a/models/tt_transformers/demo/simple_text_demo.py b/models/tt_transformers/demo/simple_text_demo.py index 355cf5ee4302..a5664cfb1f6f 100644 --- a/models/tt_transformers/demo/simple_text_demo.py +++ b/models/tt_transformers/demo/simple_text_demo.py @@ -955,7 +955,15 @@ def test_demo_text( ) # Benchmark targets - supported_models = ["Llama-3.2-1B", "Llama-3.2-3B", "Llama-3.1-8B", "Llama-3.2-11B", "Llama-3.1-70B", "Mistral-7B"] + supported_models = [ + "Llama-3.2-1B", + "Llama-3.2-3B", + "Llama-3.1-8B", + "Llama-3.2-11B", + "Llama-3.1-70B", + "Mistral-7B", + "Mistral-Small-3.1-24B", + ] supported_devices = ["N150", "P100", "P150", "P300", "N300", "P150x4", "P150x8", "T3K", "TG"] tt_device_name = determine_device_name(mesh_device) # submesh device should not decide performance target @@ -1004,6 +1012,7 @@ def test_demo_text( "N300_Mistral-7B": 38, # TODO Update target "T3K_Mistral-7B": 45, # TODO Update target "TG_Mistral-7B": 45, # TODO Update target + "T3K_Mistral-Small-3.1-24B": 33, # TODO Update target } if model_device_key in dict_target_decode_tok_s_u: target_decode_tok_s_u = dict_target_decode_tok_s_u[model_device_key] @@ -1099,6 +1108,7 @@ def test_demo_text( # "T3K_Qwen2.5-72B": 13, # too much variability in CI (https://github.com/tenstorrent/tt-metal/issues/24303) "T3K_Qwen2.5-Coder-32B": 21, # "T3K_Qwen3-32B": 20, # too much variability in CI (https://github.com/tenstorrent/tt-metal/issues/24303) + "T3K_Mistral-Small-3.1-24B": 33, # TODO Update target } # Only call verify_perf if the model_device_key exists in the targets diff --git a/models/tt_transformers/demo/simple_vision_demo.py b/models/tt_transformers/demo/simple_vision_demo.py index 951f0b7e13c9..0ad95d1b9422 100644 --- a/models/tt_transformers/demo/simple_vision_demo.py +++ b/models/tt_transformers/demo/simple_vision_demo.py @@ -471,6 +471,7 @@ def test_multimodal_demo_text( logger.info("") logger.info(f"is_ci_env: {is_ci_env}") + is_ci_env = True if is_ci_env and max_batch_size == 1 and enable_trace: # Only profiling these parametrizations tt_device_name = model_args[0].device_name base_model_name = model_args[0].base_model_name @@ -478,12 +479,14 @@ def test_multimodal_demo_text( "N300_Llama-3.2-11B": 23, "T3K_Llama-3.2-11B": 20, "T3K_Llama-3.2-90B": 3, + "T3K_Mistral-Small-3.1-24B": 1254.50, }[f"{tt_device_name}_{base_model_name}"] target_decode_tok_s_u = { "N300_Llama-3.2-11B": 21.5, "T3K_Llama-3.2-11B": 34.25, "T3K_Llama-3.2-90B": 6, + "T3K_Mistral-Small-3.1-24B": 28.50, }[f"{tt_device_name}_{base_model_name}"] target_decode_tok_s = target_decode_tok_s_u * max_batch_size diff --git a/models/tt_transformers/tests/reference_outputs/Mistral-Small-3.1-24B-Instruct-2503.refpt b/models/tt_transformers/tests/reference_outputs/Mistral-Small-3.1-24B-Instruct-2503.refpt new file mode 100644 index 0000000000000000000000000000000000000000..5a274c8a3f924fc5466dfc4162482ceade6ff0a4 GIT binary patch literal 50880 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