@@ -7292,6 +7292,272 @@ def test_nvfp4_8gpus_mtp_custom_op(self, monkeypatch):
72927292 extra_evaluator_kwargs = self .EXTRA_EVALUATOR_KWARGS )
72937293
72947294
7295+ class TestNemotronV3Ultra (LlmapiAccuracyTestHarness ):
7296+ MODEL_NAME = "nvidia/Nemotron-Ultra-V3"
7297+ # No thinking mode for now.
7298+ EXTRA_EVALUATOR_KWARGS = dict (chat_template_kwargs = dict (
7299+ enable_thinking = False ))
7300+
7301+ def _run_nvfp4_4gpus_eplb (self , moe_backend , eplb_config , model_path ):
7302+ kv_cache_config = KvCacheConfig (
7303+ enable_block_reuse = False ,
7304+ mamba_ssm_cache_dtype = "float16" ,
7305+ free_gpu_memory_fraction = 0.5 ,
7306+ )
7307+ max_batch_size = 32
7308+ cuda_graph_config = CudaGraphConfig (max_batch_size = max_batch_size ,
7309+ enable_padding = True )
7310+ moe_config = MoeConfig (backend = moe_backend , load_balancer = eplb_config )
7311+ pytorch_config = dict (cuda_graph_config = cuda_graph_config ,
7312+ moe_config = moe_config )
7313+ with LLM (
7314+ model_path ,
7315+ kv_cache_config = kv_cache_config ,
7316+ max_batch_size = max_batch_size ,
7317+ tensor_parallel_size = 4 ,
7318+ moe_expert_parallel_size = 4 ,
7319+ enable_attention_dp = True ,
7320+ ** pytorch_config ,
7321+ ) as llm :
7322+ task = MMLU (self .MODEL_NAME )
7323+ task .evaluate (llm ,
7324+ extra_evaluator_kwargs = self .EXTRA_EVALUATOR_KWARGS )
7325+ task = GSM8K (self .MODEL_NAME )
7326+ task .evaluate (llm ,
7327+ extra_evaluator_kwargs = self .EXTRA_EVALUATOR_KWARGS )
7328+
7329+ @skip_pre_blackwell
7330+ @pytest .mark .skip_less_mpi_world_size (4 )
7331+ @pytest .mark .skip_less_device_memory (80000 )
7332+ @parametrize_with_ids ("moe_backend" , ["TRTLLM" , "CUTLASS" , "CUTEDSL" ])
7333+ def test_nvfp4_4gpus_static_eplb (self , moe_backend ):
7334+ from transformers import AutoConfig
7335+ model_path = f"{ llm_models_root ()} /NVIDIA-Nemotron-3-Ultra-550B-A55B-NVFP4"
7336+ model_cfg = AutoConfig .from_pretrained (model_path ,
7337+ trust_remote_code = True )
7338+ num_experts = model_cfg .n_routed_experts
7339+ # num_slots should be larger than or equal to num_experts and should be divisible by parallel_size.
7340+ # Assign extra 16 expert slots per rank.
7341+ extra_num_slots = 16 * 4
7342+ num_slots = num_experts + extra_num_slots
7343+ hybrid_pattern = model_cfg .hybrid_override_pattern
7344+ moe_layer_indices = [
7345+ i for i , ch in enumerate (hybrid_pattern ) if ch == 'E'
7346+ ]
7347+ initial_global_assignments = {}
7348+ for i in moe_layer_indices :
7349+ initial_global_assignments [i ] = [(i + j ) % num_experts
7350+ for j in range (num_slots )]
7351+ eplb_config = MoeLoadBalancerConfig (
7352+ num_slots = num_slots ,
7353+ initial_global_assignments = initial_global_assignments ,
7354+ layer_updates_per_iter = 0 )
7355+ self ._run_nvfp4_4gpus_eplb (moe_backend , eplb_config , model_path )
7356+
7357+ @pytest .mark .skip_less_device (4 )
7358+ @pytest .mark .skip_device_not_contain (["GB200" ])
7359+ @parametrize_with_ids ("moe_backend" , ["TRTLLM" , "CUTLASS" , "CUTEDSL" ])
7360+ def test_nvfp4_4gpus_online_eplb (self , moe_backend ):
7361+ model_path = f"{ llm_models_root ()} /NVIDIA-Nemotron-3-Ultra-550B-A55B-NVFP4"
7362+ num_experts = 512 # 512 experts per token for Nemotron V3 Ultra.
7363+ # num_slots should be larger than or equal to num_experts and should be divisible by parallel_size.
7364+ # Assign extra 16 expert slots per rank.
7365+ extra_num_slots = 16 * 4
7366+ num_slots = num_experts + extra_num_slots
7367+ eplb_config = MoeLoadBalancerConfig (num_slots = num_slots ,
7368+ layer_updates_per_iter = 2 )
7369+ self ._run_nvfp4_4gpus_eplb (moe_backend , eplb_config , model_path )
7370+
7371+ @skip_pre_blackwell
7372+ @pytest .mark .skip_less_mpi_world_size (8 )
7373+ @pytest .mark .parametrize ("moe_backend" , ["TRTLLM" , "CUTLASS" , "CUTEDSL" ],
7374+ ids = ["trtllm" , "cutlass" , "cutedsl" ])
7375+ @pytest .mark .parametrize (
7376+ "attention_dp" ,
7377+ [
7378+ False ,
7379+ True ,
7380+ ],
7381+ ids = [
7382+ "attention_dp_off" ,
7383+ "attention_dp_on" ,
7384+ ],
7385+ )
7386+ def test_nvfp4_8gpus (self , attention_dp , moe_backend ):
7387+ max_batch_size = 4 if attention_dp else 32
7388+ with LLM (
7389+ f"{ llm_models_root ()} /NVIDIA-Nemotron-3-Ultra-550B-A55B-NVFP4" ,
7390+ kv_cache_config = KvCacheConfig (
7391+ enable_block_reuse = False ,
7392+ mamba_ssm_cache_dtype = "float16" ,
7393+ free_gpu_memory_fraction = 0.5 ,
7394+ ),
7395+ max_batch_size = max_batch_size ,
7396+ tensor_parallel_size = 8 ,
7397+ moe_expert_parallel_size = 8 ,
7398+ pipeline_parallel_size = 1 ,
7399+ enable_attention_dp = attention_dp ,
7400+ cuda_graph_config = CudaGraphConfig (max_batch_size = max_batch_size ,
7401+ enable_padding = True ),
7402+ disable_overlap_scheduler = False ,
7403+ moe_config = MoeConfig (backend = moe_backend ),
7404+ ) as llm :
7405+ task = MMLU (self .MODEL_NAME )
7406+ task .evaluate (llm ,
7407+ extra_evaluator_kwargs = self .EXTRA_EVALUATOR_KWARGS )
7408+ task = GSM8K (self .MODEL_NAME )
7409+ task .evaluate (llm ,
7410+ extra_evaluator_kwargs = self .EXTRA_EVALUATOR_KWARGS )
7411+
7412+ @skip_pre_blackwell
7413+ @pytest .mark .skip_less_mpi_world_size (4 )
7414+ @pytest .mark .parametrize (
7415+ "tp_size, ep_size, mamba_state_cache_interval, attention_dp, use_mtp" ,
7416+ [
7417+ (4 , 1 , 256 , False , True ),
7418+ (4 , 4 , 256 , False , False ),
7419+ (4 , 4 , 256 , True , False ),
7420+ (4 , 4 , 512 , True , True ),
7421+ ],
7422+ ids = ["TP4_MTP" , "TEP4" , "ADP4" , "ADP4_MTP" ],
7423+ )
7424+ def test_nvfp4_4gpus_block_reuse (self , tp_size , ep_size ,
7425+ mamba_state_cache_interval , attention_dp ,
7426+ use_mtp ):
7427+ mtp_config = MTPDecodingConfig (
7428+ num_nextn_predict_layers = 3 ,
7429+ mtp_eagle_one_model = True ,
7430+ )
7431+ max_batch_size = 4 if attention_dp else 32
7432+ with LLM (
7433+ f"{ llm_models_root ()} /NVIDIA-Nemotron-3-Ultra-550B-A55B-NVFP4" ,
7434+ kv_cache_config = KvCacheConfig (
7435+ enable_block_reuse = True ,
7436+ mamba_ssm_cache_dtype = "float16" ,
7437+ mamba_state_cache_interval = mamba_state_cache_interval ,
7438+ free_gpu_memory_fraction = 0.6 ,
7439+ ),
7440+ max_batch_size = max_batch_size ,
7441+ tensor_parallel_size = tp_size ,
7442+ moe_expert_parallel_size = ep_size ,
7443+ pipeline_parallel_size = 1 ,
7444+ enable_attention_dp = attention_dp ,
7445+ cuda_graph_config = CudaGraphConfig (max_batch_size = max_batch_size ,
7446+ enable_padding = True ),
7447+ disable_overlap_scheduler = False ,
7448+ moe_config = MoeConfig (backend = "TRTLLM" ),
7449+ speculative_config = mtp_config if use_mtp else None ,
7450+ ) as llm :
7451+ task = MMLU (self .MODEL_NAME )
7452+ task .evaluate (llm ,
7453+ extra_evaluator_kwargs = self .EXTRA_EVALUATOR_KWARGS )
7454+ task = GSM8K (self .MODEL_NAME )
7455+ task .evaluate (llm ,
7456+ extra_evaluator_kwargs = self .EXTRA_EVALUATOR_KWARGS )
7457+
7458+ @skip_pre_blackwell
7459+ @pytest .mark .skip_less_mpi_world_size (4 )
7460+ @pytest .mark .parametrize (
7461+ "tp_size, ep_size, pp_size, attention_dp" ,
7462+ [
7463+ (2 , 1 , 2 , False ),
7464+ (2 , 2 , 2 , False ),
7465+ (2 , 2 , 2 , True ),
7466+ ],
7467+ ids = ["TP2_PP2" , "TEP2_PP2" , "ADP2_PP2" ],
7468+ )
7469+ def test_nvfp4_parallelism (self , tp_size , ep_size , pp_size , attention_dp ):
7470+ max_batch_size = 8 if attention_dp else 32
7471+ with LLM (
7472+ f"{ llm_models_root ()} /NVIDIA-Nemotron-3-Ultra-550B-A55B-NVFP4" ,
7473+ kv_cache_config = KvCacheConfig (
7474+ enable_block_reuse = False ,
7475+ mamba_ssm_cache_dtype = "float16" ,
7476+ free_gpu_memory_fraction = 0.6 ,
7477+ ),
7478+ max_batch_size = max_batch_size ,
7479+ tensor_parallel_size = tp_size ,
7480+ moe_expert_parallel_size = ep_size ,
7481+ pipeline_parallel_size = pp_size ,
7482+ enable_attention_dp = attention_dp ,
7483+ cuda_graph_config = CudaGraphConfig (max_batch_size = max_batch_size ,
7484+ enable_padding = True ),
7485+ disable_overlap_scheduler = False ,
7486+ moe_config = MoeConfig (backend = "CUTEDSL" ),
7487+ ) as llm :
7488+ task = MMLU (self .MODEL_NAME )
7489+ task .evaluate (llm ,
7490+ extra_evaluator_kwargs = self .EXTRA_EVALUATOR_KWARGS )
7491+ task = GSM8K (self .MODEL_NAME )
7492+ task .evaluate (llm ,
7493+ extra_evaluator_kwargs = self .EXTRA_EVALUATOR_KWARGS )
7494+
7495+ @skip_pre_blackwell
7496+ @pytest .mark .skip_less_device (4 )
7497+ @pytest .mark .skip_less_device_memory (80000 )
7498+ def test_nvfp4_4gpu_mtp_ar (self ):
7499+ max_draft_len = 7
7500+ mtp_config = MTPDecodingConfig (
7501+ max_draft_len = max_draft_len ,
7502+ mtp_eagle_one_model = True ,
7503+ )
7504+ model_path = f"{ llm_models_root ()} /NVIDIA-Nemotron-3-Ultra-550B-A55B-NVFP4"
7505+
7506+ llm_common_config = dict (
7507+ model = model_path ,
7508+ tensor_parallel_size = 4 ,
7509+ moe_expert_parallel_size = 4 ,
7510+ kv_cache_config = KvCacheConfig (
7511+ enable_block_reuse = False ,
7512+ mamba_ssm_cache_dtype = "float16" ,
7513+ free_gpu_memory_fraction = 0.5 ,
7514+ ),
7515+ max_batch_size = 4 ,
7516+ enable_attention_dp = True ,
7517+ cuda_graph_config = CudaGraphConfig (max_batch_size = 4 ,
7518+ enable_padding = True ),
7519+ disable_overlap_scheduler = False ,
7520+ moe_config = MoeConfig (backend = "CUTLASS" ),
7521+ )
7522+
7523+ with LLM (** llm_common_config ,
7524+ speculative_config = mtp_config ) as llm_spec :
7525+ raw_prompts = [
7526+ "The capital of France is" ,
7527+ "The president of the United States is" ,
7528+ "The future of AI is" ,
7529+ ]
7530+ prompts = [
7531+ llm_spec .tokenizer .apply_chat_template (
7532+ [{
7533+ "role" : "user" ,
7534+ "content" : p
7535+ }],
7536+ tokenize = False ,
7537+ add_generation_prompt = True ,
7538+ ) for p in raw_prompts
7539+ ]
7540+ tok_ids = [llm_spec .tokenizer .encode (p ) for p in prompts ]
7541+
7542+ sampling_params = SamplingParams (max_tokens = 128 , temperature = 0 )
7543+
7544+ for i in range (len (tok_ids )):
7545+ num_tokens = 0
7546+ num_drafted = 0
7547+ num_accepted = 0
7548+ for output in llm_spec .generate_async (tok_ids [i ],
7549+ sampling_params ,
7550+ streaming = True ):
7551+ new_tokens = output .outputs [0 ].token_ids
7552+ num_drafted += max_draft_len
7553+ num_accepted += len (new_tokens ) - num_tokens - 1
7554+ num_tokens = len (new_tokens )
7555+
7556+ accept_rate = num_accepted / num_drafted
7557+ assert accept_rate > 0.2 , \
7558+ f"Acceptance rate too low for prompt { i } : { accept_rate :.2f} "
7559+
7560+
72957561@skip_pre_hopper
72967562class TestMiniMaxM2 (LlmapiAccuracyTestHarness ):
72977563 MODEL_NAME = "MiniMaxAI/MiniMax-M2"
0 commit comments