diff --git a/docs/basic_usage/deepseek_v32.md b/docs/basic_usage/deepseek_v32.md index 24aeaa49f..ca38db221 100644 --- a/docs/basic_usage/deepseek_v32.md +++ b/docs/basic_usage/deepseek_v32.md @@ -125,6 +125,14 @@ python3 -m sglang.launch_server \ --reasoning-parser deepseek-v3 ``` +## NVFP4 Checkpoint + +To launch deepseek v3.2 [NVFP4 checkpoint](https://huggingface.co/nvidia/DeepSeek-V3.2-NVFP4) on Blackwell devices, the user needs to specify the quantization method as `modelopt_fp4`, and moe runner backend as one of `flashinfer_trtllm`(recommended), `flashinfer_cutlass` and `flashinfer_cutedsl`. Any other usage (parallelism, reasoning parser, ...) is the same as FP8 checkpoint. + +An example launching command can be: +```bash +python -m sglang.launch_server --model nvidia/DeepSeek-V3.2-NVFP4 --tp 4 --quantization modelopt_fp4 --moe-runner-backend flashinfer_trtllm --tool-call-parser deepseekv32 --reasoning-parser deepseek-v3 +``` ## PD Disaggregation diff --git a/test/srt/run_suite.py b/test/srt/run_suite.py index ce724a04c..f7b291cfd 100644 --- a/test/srt/run_suite.py +++ b/test/srt/run_suite.py @@ -36,6 +36,7 @@ suites = { TestFile("test_fp8_blockwise_gemm.py", 280), TestFile("test_gpt_oss_4gpu.py", 300), TestFile("test_nvfp4_gemm.py", 360), + TestFile("test_deepseek_v32_fp4_4gpu.py", 600), ], # "per-commit-8-gpu-b200": [ # TestFile("test_mistral_large3_basic.py", 275), # Moved to nightly - large model diff --git a/test/srt/test_deepseek_v32_fp4_4gpu.py b/test/srt/test_deepseek_v32_fp4_4gpu.py new file mode 100644 index 000000000..8b140e7c5 --- /dev/null +++ b/test/srt/test_deepseek_v32_fp4_4gpu.py @@ -0,0 +1,79 @@ +import unittest +from types import SimpleNamespace + +from sglang.srt.utils import kill_process_tree +from sglang.test.few_shot_gsm8k import run_eval as run_eval_few_shot_gsm8k +from sglang.test.test_utils import ( + DEFAULT_URL_FOR_TEST, + CustomTestCase, + is_in_ci, + popen_launch_server, + write_github_step_summary, +) + +FULL_DEEPSEEK_V3_FP4_MODEL_PATH = "nvidia/DeepSeek-V3.2-NVFP4" +SERVER_LAUNCH_TIMEOUT = 1200 + + +class TestDeepseekV32FP4(CustomTestCase): + @classmethod + def setUpClass(cls): + cls.model = FULL_DEEPSEEK_V3_FP4_MODEL_PATH + cls.base_url = DEFAULT_URL_FOR_TEST + other_args = [ + "--tp", + "4", + "--dp", + "4", + "--enable-dp-attention", + "--attention-backend", + "nsa", + "--moe-runner-backend", + "flashinfer_trtllm", + "--quantization", + "modelopt_fp4", + "--kv-cache-dtype", + "fp8_e4m3", + "--tool-call-parser", + "deepseekv32", + "--reasoning-parser", + "deepseek-v3", + "--model-loader-extra-config", + '{"enable_multithread_load": true,"num_threads": 64}', + ] + cls.process = popen_launch_server( + cls.model, + cls.base_url, + timeout=SERVER_LAUNCH_TIMEOUT, + other_args=other_args, + ) + + @classmethod + def tearDownClass(cls): + kill_process_tree(cls.process.pid) + + def test_a_gsm8k( + self, + ): # Append an "a" to make this test run first (alphabetically) to warm up the server + args = SimpleNamespace( + num_shots=20, + data_path=None, + num_questions=1319, + parallel=1319, + max_new_tokens=512, + host="http://127.0.0.1", + port=int(self.base_url.split(":")[-1]), + ) + metrics = run_eval_few_shot_gsm8k(args) + print(f"{metrics=}") + + if is_in_ci(): + write_github_step_summary( + f"### test_gsm8k (deepseek-v3-fp4)\n" f'{metrics["accuracy"]=:.3f}\n' + ) + + self.assertGreater(metrics["accuracy"], 0.935) + + +if __name__ == "__main__": + unittest.main()