Files
wehub-resource-sync 59a0a3844c
PR Test AMD / cancel-on-close (push) Has been skipped
PR Test NVIDIA ARM / scan (push) Has been skipped
PR Test NVIDIA / cancel-on-close (push) Has been skipped
PR Test AMD / scan (push) Has been skipped
PR Test NVIDIA ARM / cancel-on-close (push) Has been skipped
PR Test NVIDIA / scan (push) Has been skipped
Release Docker Images / build (cu129-torch-2.11.0) (push) Has been skipped
Release Docker Images / build (cu130-torch-2.11.0) (push) Has been skipped
Release PyPI / publish (push) Has been skipped
Scheduler Python Test / test (push) Successful in 27m19s
Docs / build (push) Successful in 28m8s
Scheduler C++ Test / test (push) Successful in 28m19s
Scheduler C++ Test / test-flat (push) Successful in 28m18s
Docs / deploy (push) Has been cancelled
PR Test AMD / finish (push) Has been cancelled
PR Test NVIDIA / finish (push) Has been cancelled
PR Test NVIDIA ARM / finish (push) Has been cancelled
PR Test NVIDIA ARM / ${{ matrix.name }} (${{ matrix.runner }}) (push) Has been cancelled
PR Test AMD / ${{ matrix.name }} (${{ matrix.runner }}) (push) Has been cancelled
PR Test NVIDIA / ${{ matrix.name }} (${{ matrix.runner }}) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:32:31 +08:00

165 lines
5.3 KiB
Python

"""Cheap LongCat-Flash model wiring tests."""
import unittest
from types import SimpleNamespace
from unittest import mock
import torch
from tokenspeed.runtime.layers.moe.topk import StandardTopKOutput
from tokenspeed.runtime.models.longcat_flash import (
LongcatFlashForCausalLM,
_ensure_longcat_config,
_get_longcat_moe_quant_config,
_RuntimeLongcatMoE,
)
class TestLongcatFlashRegistry(unittest.TestCase):
def test_registered(self):
from tokenspeed.runtime.models.registry import ModelRegistry
cls, arch = ModelRegistry.resolve_model_cls(["LongcatFlashForCausalLM"])
self.assertIs(cls, LongcatFlashForCausalLM)
self.assertEqual(arch, "LongcatFlashForCausalLM")
def test_mla_and_double_attention_metadata_registered(self):
from tokenspeed.runtime.configs import model_config
self.assertIn("LongcatFlashForCausalLM", model_config._MLA_ARCHITECTURES)
self.assertIn(
"LongcatFlashForCausalLM",
model_config._DOUBLE_ATTENTION_LAYER_ARCHITECTURES,
)
class TestLongcatFlashConfig(unittest.TestCase):
def test_config_aliases_are_normalized(self):
config = SimpleNamespace(
num_layers=28,
ffn_hidden_size=14336,
expert_ffn_hidden_size=2048,
moe_topk=8,
hidden_size=6144,
n_routed_experts=512,
)
_ensure_longcat_config(config)
self.assertEqual(config.num_hidden_layers, 28)
self.assertEqual(config.intermediate_size, 14336)
self.assertEqual(config.moe_intermediate_size, 2048)
self.assertEqual(config.num_experts_per_tok, 8)
self.assertEqual(config.hidden_act, "silu")
self.assertEqual(config.zero_expert_num, 0)
self.assertFalse(config.router_bias)
class TestLongcatMixedFp8Config(unittest.TestCase):
def test_moe_layer_uses_unquantized_backend_when_all_experts_are_ignored(self):
config = SimpleNamespace(n_routed_experts=2)
quant_config = SimpleNamespace(
ignored_layers=[
f"model.layers.0.mlp.experts.{expert_id}.{proj_name}"
for expert_id in range(2)
for proj_name in ("gate_proj", "up_proj", "down_proj")
]
)
self.assertIsNone(
_get_longcat_moe_quant_config(
config,
quant_config,
"model.layers.0.mlp",
)
)
def test_moe_layer_keeps_quantization_when_no_experts_are_ignored(self):
config = SimpleNamespace(n_routed_experts=2)
quant_config = SimpleNamespace(ignored_layers=[])
self.assertIs(
_get_longcat_moe_quant_config(
config,
quant_config,
"model.layers.0.mlp",
),
quant_config,
)
def test_moe_layer_rejects_partially_ignored_experts(self):
config = SimpleNamespace(n_routed_experts=2)
quant_config = SimpleNamespace(
ignored_layers=[
"model.layers.0.mlp.experts.0.gate_proj",
]
)
with self.assertRaisesRegex(ValueError, "partially ignored"):
_get_longcat_moe_quant_config(
config,
quant_config,
"model.layers.0.mlp",
)
class TestLongcatZeroExpert(unittest.TestCase):
def test_identity_zero_expert_masks_and_adds_hidden_state(self):
moe = object.__new__(_RuntimeLongcatMoE)
moe.zero_expert_num = 1
moe.n_routed_experts = 3
moe.zero_expert_type = "identity"
hidden_states = torch.tensor(
[[2.0, 4.0], [6.0, 8.0]],
dtype=torch.float32,
)
topk_output = StandardTopKOutput(
topk_weights=torch.tensor([[0.25, 0.75], [0.5, 0.5]]),
topk_ids=torch.tensor([[0, -1], [3, 1]]),
router_logits=torch.zeros(2, 4),
)
zero_output = _RuntimeLongcatMoE._apply_zero_experts(
moe,
hidden_states,
topk_output,
)
torch.testing.assert_close(
zero_output,
torch.tensor([[1.5, 3.0], [3.0, 4.0]]),
)
torch.testing.assert_close(
topk_output.topk_weights,
torch.tensor([[0.25, 0.0], [0.0, 0.5]]),
)
torch.testing.assert_close(
topk_output.topk_ids,
torch.tensor([[0, 0], [0, 1]]),
)
class TestLongcatCheckpointLoading(unittest.TestCase):
def test_missing_kv_scale_params_are_silent(self):
model = object.__new__(LongcatFlashForCausalLM)
with mock.patch(
"tokenspeed.runtime.models.longcat_flash._longcat_logger.warning"
) as warning:
self.assertIsNone(model.get_param({}, "model.layers.0.self_attn.0.k_scale"))
self.assertIsNone(model.get_param({}, "model.layers.0.self_attn.1.v_scale"))
warning.assert_not_called()
def test_missing_mtp_params_are_silent(self):
model = object.__new__(LongcatFlashForCausalLM)
with mock.patch(
"tokenspeed.runtime.models.longcat_flash._longcat_logger.warning"
) as warning:
self.assertIsNone(
model.get_param({}, "model.mtp.layers.0.self_attn.q_proj.weight")
)
warning.assert_not_called()
if __name__ == "__main__":
unittest.main()