Inference with vLLM on Aurora¶
vLLM is an open-source library designed to optimize the inference and serving. Originally developed at UC Berkeley's Sky Computing Lab, it has evolved into a community-driven project. The library is built around the innovative PagedAttention algorithm, which significantly improves memory management by reducing waste in Key-Value (KV) cache memory.
Provided Installation¶
vLLM is installed and available as part of the frameworks module. Please use the following commands to load the installation and query the version info:
Then, you can import vllm as follows
Known Issue on Aurora¶
CCL_PROCESS_LAUNCHER is set to pmix through the frameworks module, which leads to a warning |CCL_WARN| PMIx_Init failed: PMIX_ERR_UNREACH, but it appears that vllm recovers, and performance is not affected. Cleanest is to set this variable either to none or torchrun. Based on our tests, we have found setting this to be optional.
Tip
Do not forget to set the proxies on the compute node if you download directly from the job.
Access Model Weights¶
Model weights for commonly used open-weight models are downloaded and available in the following directory on Aurora.
To ensure your workflows utilize the preloaded model weights and datasets, update the following environment variables in your session. Some models hosted on Hugging Face (HF) may be gated, requiring additional authentication. To access these gated models, you will need a Hugging Face authentication token.
Set the following environment variables to avoid hitting the Hugging Face Hub API, if a model is already cached.
Serving Small Models on a Single Tile¶
For small models that fit within the memory of a single PVC tile (64 GB), no additional configuration is required to serve the model. Simply use the default tensor parallelism size (TP) of 1 when serving the model. This ensures the model is run on a single tile without the need for distributed setup. Models with fewer than 20 billion parameters typically fit within a single tile when using half precision (e.g., bfloat16).
For example, the following command serves meta-llama/Llama-3.1-8B-Instruct on a single tile of a single node:
After the server output says Application startup complete., it is ready to accept prompt requests, for example with the following simple Python code (can background the server process)
Serving Medium Models on Multiple Tiles (Single Node)¶
To serve larger models which require multiple tiles (TP>1) but still only a single node, a more advanced setup is necessary. This involves setting the VLLM_HOST_IP and the TP size. By default, vLLM uses the mp backend, which is sufficient for single node model serving. Models with a few hundred billion parameters can usually fit within a single node utilizing half precision.
The following commands demonstrate how to serve the meta-llama/Llama-3.3-70B-Instruct on 8 tiles on a single node.
Serving Large Models on Multiple Tiles and Nodes¶
To serve models across multiple nodes, vLLM uses Ray to launch processes across nodes. We suggest users take advantage of the provided setup_ray_cluster.sh script to setup a Ray cluster across nodes before running vllm serve.
Setup script
| setup_ray_cluster.sh | |
|---|---|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | |
The following example serves meta-llama/Llama-3.1-405B-Instruct model using 2 nodes. It sets tensor parallelism TP=8 for intra-node communications and pipeline parallelism PP=2 for inter-node communication, for a total of 16 shards.
Additional Notes on Ray
- By default,
setup_ray_cluster.shlaunches a ray cluster with 8 raylets per node by specifingONEAPI_DEVICE_SELECTOR="opencl:gpu;level_zero:0,1,2,3,4,5,6,7"and--num-gpus=8. This matches thevllm servecommand withTP=8. This is the recommended setup, however if users want to change the TP size, remember to also change the number of GPUs in the Ray setup script.
Guidelines for vLLM Model Serving¶
Estimating the memory requirements¶
When serving a model, the GPU memory has to hold the model weights, the KV cache and any additional runtime overhead. The memory for the model weights and the KV cache is managed by vLLM. During initialization, vLLM first loads the weights into memory, then profiles the forward pass and pre-allocates the remaining available memory for the KV cache. This memory can be controlled with a number of parameters which can be passed to vllm serve. Some of the main ones to consider are:
--gpu-memory-utilization: The fraction of GPU memory to be used for the model executor, ranges from 0 to 1.--kv-cache-memory-bytes: Size of KV Cache per GPU in bytes. This parameter overridesgpu-memory-utilizationand when not set vLLM automatically infers the KV cache size based ongpu-memory-utilization.--max-model-len: Model context length (prompt and output).--max-num-seqs: Maximum number of sequences to be processed in a single iteration.--dtype: Data type for model weights and activations.--kv-cache-dtype: Data type for KV cache storage.
The main knob to control how much memory vLLM uses is --gpu-memory-utilization. In most cases, a value of 0.9 (i.e., 90% of the total GPU memory) is sufficient to leave enough spare memory for the runtime and other overhead (usually only a few GB).
The memory used by the weights can be estimated simply by multiplying the number of parameters of the model by the number of bytes used by the data type selected. For bfloat16, which is the recommended data type on Aurora, the memory used by the weights in GB is estimated as
The memory used by the KV cache is estimated by first measuring the amount of memory needed per token. A simple formula which depends on the model details and the data type is
where \(\text{num layers}\), \(\text{num kv heads}\) and \(\text{head_dim}\) are properties of the model, and \(\text{bytes per element}\) is determined by setting --dtype or --kv-cache-dtype to control the KV cache data type specifically.
Then, the total KV cache memory needed for a full sequence is
where the sequence length is controlled with --max-model-len. The memory left for the KV cache is whatever remains of the GPU memory budget once the weights are loaded and the forward pass is profiled (a few GB for activations),
so the number of concurrent sequences that fit in the KV cache is
With kv_memory_per_seq is computed using the maximum context length of the model, this gives a worst-case estimate since it assumes every request fills the entire context window. In practice, vLLM allocates KV cache blocks on demand as sequences grow, so many more short requests can be served concurrently. Concurrency can be capped by --max-num-seqs regardless of how much KV cache memory is free.
If your workflow does not need the model's full context window, it is recommended to set --max-model-len to a smaller value to increase the concurrency of requests that can be served.
Supported data types on Intel Max 1550 GPU
Note that fp8 is not supported on Aurora's Intel GPU, so bfloat16 is the recommended setting for the data type and --kv-cache-dtype cannot be used to easily reduce the size of the KV cache. Use the memory parameters --gpu-memory-utilization and --kv-cache-memory-bytes to directly limit the KV cache size or use --max-model-len to reduce the context window.
Applicability to MoE and MLA models
While the weight memory estimate holds for all model types, the KV cache estimates above assume a dense model using standard multi-head or grouped-query attention (MHA/GQA) or a Mixture of Experts (MoE) model. For Multi-head Latent Attention (MLA) models or those with interleved local-global attention, the KV cache formula does not apply and will overestimate the memory required.
Determining the number of GPUs¶
To help support the significant memory requirements of LLMs, the models can be parallelized across multiple GPUs and nodes along two main dimensions:
- Tensor parallelism (TP) is the first dimension to consider, and it is sized to evenly divide the number of attention heads of the model. The KV cache is also sharded across GPUs in a TP group. To avoid duplicating the KV heads across GPUs, it is best to ensure that the TP size also divides the KV heads equally. For example, the
Llama-3.1-70B-Instructmodel has 64 attention heads and 8 KV heads, so valid TP values are 1, 2, 4, 8. On Aurora, using all 12 PVC tiles per node is not the preferred approach since it usually does not evenly divide the number of attention heads; \(\text{TP}=2,4,8\) are preferred instead. - Pipeline parallelism (PP) is the second dimension, and it is sized to divide the number of layers in the model. The KV cache is partitioned in this case too. For load balance, even division with the number of layers in the model is preferred. Usually, PP is set to the number of nodes used to serve the model.
- The product \(\text{TP} \times \text{PP}\) is the total number of GPUs used to serve the model.
- For performance, it is recommended to scale TP groups within a node to take advantage of faster intra-node collectives. If a model requires more than 8 PVC tiles, scale the model on 2 (or more nodes) with PP>1.
To configure vLLM assuming the maximum context window is desired, we recommend the following steps using the Llama-3.1-405B-Instruct model as an example.
- Obtain the model information from the Hugging Face config file.
- Number of parameters: 406B
- Maximum context length: 131072
- Number of hidden layers: 126
- Number of attention heads: 128
- Number of KV heads: 8
- Head dimension (if not explicitly set, derive as \(\text{hidden size} / \text{num. attention heads}\)): 128
- Tensor type: BF16
- Estimate the memory requirements using bfloat16 precision.
- \(\text{weights memory} = 406 \times 2 = 812\) GB
- \(\text{kv memory per seq} = 126 \times (2 \times 8 \times 128 \times 2) x 131072 \times 10^{-9} = 67.6\) GB`
- The minimum memory required to serve the model with full context length is \(812 + 68 = 880\) GB
- Obtain the number of GPUs needed to serve the model.
- On Aurora, we recommend the use of tile-as-device, meaning each PVC tile with 68.7 GB (64 GiB) of memory is considered a GPU.
- Set
--gpu-memory-utilizationto 0.9 to leave enough overhead for the runtime. - The number of PVC tiles needed is: \(ceil( \frac{880}{0.9 \times 68.7}) = 15\)
- A minimum of 15 PVC tiles are needed to serve the Llama 3.1 405B model with full context length.
- Determining the appropriate TP and PP sizes.
- Since 15 PVC tiles are needed, we set TP and PP values to the next valid product. On Aurora, this results in \(\text{TP}=8\) and \(\text{PP}=2\) for a total of 16 tiles.
- At 16 tiles, roughly 177 GB remains for the KV cache after the weights, enough for about 2 concurrent full-context requests.
- For increased concurrency, you can increase TP and/or PP beyond the minimum number required. In this case, using 24 tiles with \(\text{PP}=3\).
Scaling vLLM Workflows¶
To scale vLLM workflows on ALCF system there are a few recommended approaches depending on the user's needs and setup. These approaches are described in detail in the GettingStarted repository along with example scripts for each.