qwen38-flash-next / code /models /tt_transformers /tests /mixtral /test_mixtral_decoder.py
DeAIafdeling's picture
Add files using upload-large-folder tool
2bedc3e verified
Raw History Blame Contribute Delete
6.57 kB
# SPDX-FileCopyrightText: © 2025 Tenstorrent USA, Inc.
# SPDX-License-Identifier: Apache-2.0
import pytest
import torch
from loguru import logger
from transformers.models.mixtral.modeling_mixtral import MixtralDecoderLayer, MixtralRotaryEmbedding
import ttnn
from models.common.utility_functions import comp_allclose, comp_pcc
from models.tt_transformers.tt.ccl import TT_CCL
from models.tt_transformers.tt.common import Mode
from models.tt_transformers.tt.decoder import TransformerBlock as TtTransformerBlock
from models.tt_transformers.tt.model_config import ModelArgs
from models.tt_transformers.tt.rope import RotarySetup
from .utils import fuse_mixtral_experts, load_hf_mixtral_config
# pytest models/tt_transformers/tests/mixtral/test_mixtral_decoder.py
def convert2ref(state_dict):
"""Convert state dict keys for compatibility with reference model naming."""
replacements = [
("attention.wq.weight", "self_attn.q_proj.weight"),
("attention.wk.weight", "self_attn.k_proj.weight"),
("attention.wv.weight", "self_attn.v_proj.weight"),
("attention.wo.weight", "self_attn.o_proj.weight"),
("attention_norm.weight", "input_layernorm.weight"),
("ffn_norm.weight", "post_attention_layernorm.weight"),
# transformers 5.x renamed MixtralDecoderLayer.block_sparse_moe -> mlp
("block_sparse_moe.gate.weight", "mlp.gate.weight"),
]
out = {}
for k, v in state_dict.items():
new_k = k
for old, new in replacements:
if k.startswith(old):
new_k = k.replace(old, new)
break
out[new_k] = v
return out
@pytest.mark.parametrize("layer_idx", [0])
@pytest.mark.parametrize(
"batch",
(32,),
)
@pytest.mark.parametrize("device_params", [{"fabric_config": True}], indirect=True)
@pytest.mark.parametrize("mesh_device", [(1, 8)], indirect=True)
def test_mixtral_decoder_inference(mesh_device, reset_seeds, batch, device_params, layer_idx):
"""
b: batch
s: sequence length
h: hidden size
"""
pcc = 0.98
dtype = ttnn.bfloat8_b
if batch == 32:
generation_start_pos = 15000
max_seq_len = 16384
elif batch in [4, 8, 16]:
generation_start_pos = 30000
max_seq_len = 32768
else:
raise ValueError(f"Batch size {batch} not supported")
hf_config = load_hf_mixtral_config()
model_args = ModelArgs(mesh_device, max_seq_len=max_seq_len, max_batch_size=batch)
model_args.use_qk_fused = False
state_dict = model_args.load_state_dict()
partial_state_dict = {k[9:]: v for k, v in state_dict.items() if (k.startswith(f"layers.{layer_idx}."))}
reference_model = MixtralDecoderLayer(hf_config, layer_idx)
# transformers 5.x: experts are fused into mlp.experts.{gate_up_proj,down_proj}
reference_model.load_state_dict(
fuse_mixtral_experts(
convert2ref(partial_state_dict), hf_config.num_local_experts, "block_sparse_moe.experts", "mlp.experts"
)
)
reference_rotary_emb = MixtralRotaryEmbedding(config=hf_config)
# Initialize TT model
rope_setup = RotarySetup(
mesh_device,
model_args.max_batch_size,
model_args.head_dim,
model_args.max_seq_len,
model_args.rope_theta,
model_args.rope_scaling,
)
tt_ccl = TT_CCL(mesh_device)
tt_model = TtTransformerBlock(
mesh_device=mesh_device,
state_dict=state_dict,
args=model_args,
layer_num=layer_idx,
dtype=dtype,
weight_cache_path=model_args.weight_cache_path(dtype),
transformation_mats=rope_setup.get_both_trans_mats(),
tt_ccl=tt_ccl,
)
generation_length = 10
all_tests_pass = True
seqlen = 1
for i in range(generation_length):
logger.info(f"[Decoder] Generating token {i}")
pt_decode_input_bsh = (torch.rand(batch, seqlen, model_args.dim) * 2) - 1
start_pos = generation_start_pos + i
start_pos_ids = torch.tensor([start_pos for _ in range(batch)])
current_pos_tensor = ttnn.from_torch(
start_pos_ids,
device=mesh_device,
dtype=ttnn.int32,
mesh_mapper=ttnn.ShardTensor2dMesh(
mesh_device,
dims=(None, None),
mesh_shape=model_args.cluster_shape,
),
)
tt_decode_input = pt_decode_input_bsh.clone()
decode_input = model_args.prepare_residual_tensor_decode(
tt_decode_input,
model_args.get_residual_mem_config(Mode.DECODE, None),
)
rot_mats = rope_setup.get_rot_mats(start_pos_ids)
# Run TT model
tt_out_b1sh = tt_model(
decode_input,
current_pos_tensor,
rot_mats_global=rot_mats,
mode=Mode.DECODE,
)
tt_out = (
ttnn.to_torch(
tt_out_b1sh,
mesh_composer=ttnn.ConcatMesh2dToTensor(mesh_device, dims=(1, 3), mesh_shape=model_args.cluster_shape),
)[0]
.squeeze(0)
.view(batch, 1, -1)
)
# Reference model
positions = torch.LongTensor([start_pos])
position_ids = positions.unsqueeze(0)
position_embeddings = reference_rotary_emb(pt_decode_input_bsh, position_ids)
# transformers 5.x MixtralDecoderLayer.forward returns a single tensor (older versions
# returned a tuple). `ref_output_bsh, *_ =` would unpack the tensor along the batch dim,
# so assign directly and take element 0 only when a tuple/list is returned.
ref_output_bsh = reference_model(
hidden_states=pt_decode_input_bsh,
position_ids=position_ids,
position_embeddings=position_embeddings,
)
if isinstance(ref_output_bsh, (tuple, list)):
ref_output_bsh = ref_output_bsh[0]
passing, pcc_message = comp_pcc(ref_output_bsh, tt_out, pcc)
logger.info(comp_allclose(ref_output_bsh, tt_out))
logger.info(pcc_message)
if passing:
logger.info("Mixtral Decoder Block Passed!")
else:
logger.warning("Mixtral Decoder Block Failed!")
all_tests_pass = False
if all_tests_pass:
logger.info(f"All {generation_length} Mixtral decode iterations Passed!")
else:
logger.warning("One or more iterations of Mixtral decode Failed!")
assert all_tests_pass, f"PCC value is lower than {pcc} for some of the outputs. Check Warnings!"