The OOM That Revealed a Misunderstanding: When Expert Parallelism Doesn't Mean What You Think

In the high-stakes world of deploying large language models on multi-GPU hardware, every configuration choice is a gamble. Message [msg 2311] captures a pivotal moment in an extended optimization session: the assistant attempts to launch the MiniMax-M2.5 model (a 230-billion-parameter, FP8-quantized Mixture-of-Experts architecture) using a combination of Tensor Parallelism (TP) and Expert Parallelism (EP) across 8 NVIDIA RTX PRO 6000 Blackwell GPUs. The attempt fails with a stark, familiar error: CUDA out of memory. But the real story lies not in the OOM itself, but in the chain of reasoning that led to this configuration—and the incorrect assumption about vLLM's parallelism model that made it fail.

The Context: A Quest for Throughput

To understand this message, we must step back into the broader narrative. The session had been an exhaustive tour of 1-trillion-parameter model deployment on 8 Blackwell GPUs. Earlier, the team had pivoted from the NVFP4 Kimi-K2.5 (which was bottlenecked by PCIe allreduce across 8 GPUs for its 61-layer MLA architecture) to MiniMax-M2.5, a 230B-parameter FP8 model with a Grouped-Query Attention (GQA) architecture and only 10 billion active parameters per token thanks to its Mixture-of-Experts design. The results were spectacular: with TP=4 (tensor parallelism across 4 GPUs), MiniMax achieved 84 tok/s single-stream and over 2,500 tok/s at high concurrency, far outperforming the Kimi models on this hardware.

But the user wanted more. In message [msg 2303], they asked a simple question: "can we do tp/ep or tp6?"—essentially asking whether the model could leverage all 8 GPUs through either TP=6 or a combination of tensor parallelism and expert parallelism. This question set off a chain of analysis that culminated in the failed launch of message [msg 2311].

The Reasoning Behind the Configuration

The assistant's response in [msg 2309] is a masterclass in distributed inference arithmetic. It systematically enumerated the constraints:

  1. FP8 block quantization alignment: The model uses FP8 quantization with a block size of [128, 128]. When tensor parallelism shards the expert intermediate dimension (size 1536), the sharded size must be divisible by 128. TP=8 gives 1536/8=192, which fails. TP=4 gives 384, which works. TP=6 gives 256, which works for this constraint—but fails on KV head divisibility.
  2. KV head divisibility: With 8 key-value heads, TP=6 would require 8/6=1.33 heads per GPU—not an integer. TP=6 was ruled out.
  3. The EP hypothesis: Expert parallelism distributes entire experts across GPUs rather than sharding their weights. This means the FP8 alignment constraint on intermediate_size/TP doesn't apply to expert weights when EP is active—experts are not tensor-sharded. The attention layers still use TP, but the MoE layers use EP. The assistant concluded that TP=2, EP=4 was the most promising configuration: tensor parallelism across 2 GPUs for attention layers, expert parallelism across 4 groups for the MoE layers, using all 8 GPUs. This would minimize allreduce overhead for attention while spreading the 256 experts across GPUs for maximum memory efficiency.

The Launch and the Failure

Message [msg 2310] shows the actual launch command. The assistant carefully cleans up shared memory artifacts (/dev/shm/psm_*, /dev/shm/sem.mp-*, /dev/shm/*vllm*, /dev/shm/*nccl*) to avoid stale state, then launches the server with:

--tensor-parallel-size 2 --enable-expert-parallel

along with the full suite of model-specific flags: --tool-call-parser minimax_m2, --reasoning-parser minimax_m2, --enable-auto-tool-choice, and --trust-remote-code.

Then comes message [msg 2311]: the wait loop. The assistant polls the health endpoint every 15 seconds, checking if the process is still alive. After two polling cycles (approximately 30 seconds), the process dies. The error message is truncated but unmistakable:

(Worker_TP1_EP1 pid=232741) ERROR 02-21 00:55:57 [gpu_model_runner.py:4223] 
Failed to load model - not enough GPU memory. Try lowering --gpu-memory-utilization 
to free memory for weights, increasing --tensor-parallel-size, or using --quantization. 
... (original error: CUDA out of memory. Tried to allocate 1.12 GiB. GPU 1 has a total 
capacity of 94.97 GiB of whic...

The Hidden Assumption: vLLM's EP Model

The OOM error is a symptom, not the root cause. The real issue is revealed in the worker identifier: Worker_TP1_EP1. The process only launched two workers (TP rank 0 and TP rank 1, EP rank 0 and EP rank 1). The assistant had assumed that --tensor-parallel-size 2 --enable-expert-parallel would use 8 GPUs with TP=2 and EP=4, but vLLM's implementation ties EP size to TP size. When EP is enabled, the EP group equals the TP group. With TP=2, the world size is 2—only two GPUs are used.

This is a critical misunderstanding. The assistant's mental model was that TP and EP are independently configurable dimensions, like a 2×4 grid. But vLLM (at least in this version) treats EP as a mode that operates within the TP group: all GPUs in the TP group also participate in EP, and the number of EP groups equals the number of TP groups. To get 8 GPUs with EP, you'd need TP=8—but TP=8 is impossible due to the FP8 alignment constraint.

The 230GB model, split across only 2 GPUs, requires approximately 115GB per GPU. Each GPU has 97.8GB of total capacity (as shown in earlier memory checks like [msg 2285]). The model simply doesn't fit. The OOM is inevitable.

What This Message Reveals About the Thinking Process

The assistant's reasoning chain in [msg 2309] was mathematically sound but architecturally incomplete. It correctly identified all the divisibility constraints, enumerated the viable options, and selected the most promising configuration. But it made an implicit assumption about vLLM's parallelism model that turned out to be wrong.

This is a classic systems debugging pattern: a failure at one level of abstraction (OOM) that can only be understood by reasoning at a different level (distributed runtime architecture). The error message itself is misleading—it suggests lowering --gpu-memory-utilization or increasing --tensor-parallel-size, but neither would help. Lowering memory utilization would make the problem worse (less available memory for weights), and increasing TP size would hit the FP8 alignment wall.

The subsequent messages ([msg 2312] through [msg 2314]) show the assistant debugging this failure. It checks the logs and discovers world_size=2, confirming that only 2 GPUs were used. It then searches the vLLM codebase for EP configuration options, finding no separate --expert-parallel-size flag. The realization dawns: "In vLLM, EP size = TP size when EP is enabled."

The Broader Lesson

This message is a microcosm of the challenges in deploying large models on cutting-edge hardware. Every layer of the stack imposes constraints: GPU memory capacity, quantization block alignment, attention head divisibility, distributed runtime architecture, and PCIe bandwidth. The optimal configuration is the intersection of all these constraints, and finding it requires not just mathematical reasoning but deep knowledge of the software implementation.

The assistant's mistake was reasonable—the concept of "expert parallelism" intuitively suggests an independent parallelism dimension. Many distributed training frameworks (like DeepSpeed and Megatron-LM) do support independent TP and EP dimensions. But vLLM's inference engine, at least in this version, couples them. This is a design choice that prioritizes simplicity and performance (all GPUs in the TP group can participate in the same allreduce for attention layers) at the cost of flexibility.

The message also demonstrates the value of rapid iteration. The wait loop checks every 15 seconds, and the entire cycle—from hypothesis to launch to failure to diagnosis—takes only a few minutes. In a production deployment scenario, this kind of fast feedback is essential. The assistant doesn't dwell on the failure; it immediately pivots to diagnosis, checking the logs, searching the codebase, and formulating a new understanding.

Conclusion

Message [msg 2311] is a failure, but a productive one. It reveals an incorrect assumption about vLLM's parallelism architecture, forcing the assistant to dive into the source code and understand the actual implementation. The OOM error is not the end of the story but a signal that guides the investigation toward a deeper understanding. In the broader arc of the session, this failure leads to the discovery that TP=4 (the original configuration) was actually optimal for this model on this hardware—a conclusion that could only be reached by systematically testing and falsifying the alternatives.

The message stands as a testament to the iterative nature of systems engineering: every failed hypothesis, properly diagnosed, yields knowledge that no amount of theoretical reasoning could provide.