Lazy loaded image6.1 GPU Usage Analysis

🚗 LLM, officially called Large Language Models, have seen their parameter counts grow massively from 0.5B, 1B, 400B, to even 600B. To handle the training and inference of models with such enormous parameter sizes, some works have made optimizations and improvements in this area.

6.1 GPU Usage Analysis

6.1.1 Model GPU Usage

When training or inferencing a model, GPU memory allocation is partly used by the AI framework and partly reserved for the system. The total GPU memory usage can be checked via commands. For example, on NVIDIA GPUs, you can use the nvidia-smi command to display the memory usage of each process:
📌
The GPU memory usage includes: Model parameters (parameter), Optimizer states (optimizer_state), Activations (activation), Gradients (gradient), Input data (input), Temporary variables (temporary), Autograd information (autograd_detail), and Unknown data (unknown). From the user's perspective, these can be categorized into:
  • Estimatable Data: Model parameters (parameter), Optimizer states (optimizer_state), Activations (activation), Gradients (gradient), Input data (input)
  • Unamed Data: Temporary variables (temporary), Unknown data (unknown)
  • Other (Framework-specific): Autograd information (autograd_detail)
🤔
Why is there sometimes a large gap between the estimated GPU memory usage and the actual measured usage?
One possible reason is that the amount of unknown data is large. In other words, the proportion of estimatable data in GPU memory is relatively small, while the proportion of unestimatable data is large. This can cause a significant difference between the estimated and actual values (with errors can exceed 30%).
For example, you might estimate GPU memory usage to be 50 GB, but actual measurements show it reaching 75 GB, where the exceeded amount might include, for example, certain temporary buffers, intermediate results, and internally allocated data by underlying frameworks (such as CUDA or cuDNN). These are usually dynamic and can vary, making their size difficult to estimate in advance.
<ins/>

6.1.2 GPU Usage During Training

📌
Memory Consumption During Training (Estimatable Portion) mainly includes: Model parameters + Optimizer status + Gradient values + Activation values
Based on the value changes, memory consumption can be classified into static and dynamic allocations. During training, GPU memory for model parameters and optimizer status generally remain unchanged and are categorized as static; the allocation for activation values and gradient values changes during training, so they are categorized as dynamic.
Static Allocation Analysis
  • Model Memory
    • The GPU memory occupied by a model mainly depends on the number of parameters and the data type. Common data types include fp32, fp16/bf16, as well as int8, fp8, etc.
      The memory usage can be calculated as ModelMem = TypeSize * Params based on different data types, using the formulas below (unit: GB):
    • fp32 = 4 * params / (1024 * 1024 * 1024)
    • fp16/bf16 = 2 * params / (1024 * 1024 * 1024)
    • fp8/int8 = 1 * params / (1024 * 1024 * 1024)
    • Regarding model checkpoint size calculation :
      When saving a checkpoint, only the parameters are stored, not the optimizer states (if we don’t want to retrain or fine-tune the model). For example, with a 1B (1 billion) parameter model using fp32 storage, the disk size would be:
      Memory = 4 * 1 * 10⁹ / (1024 * 1024 * 1024) ≈ 3.725GB
      Since 1TB typically equals 3.725GB of storage space, for easier estimation we often consider 1B ≈ 4GB, which can simplify storage planning. For instance, Llama-13B requires around 52GB of storage. The DeepSeek-R1 has 671B parameters, but its file size on the Huggingface is around 688 GB, which is because it’s stored in fp8.
      Note: If mixed precision training is used, the saved checkpoint is still stored as fp32 unless otherwise specified.
  • Optimizer States
    • In LLM training, a common optimizer is Adam. Each parameter typically needs a Momentum and a Variance (Second moment) state. In mixed-precision training, Adam also maintains a model parameter copy.
      The Adam optimizer state memory can be calculated as (unit: GB):
      OptMem = (4 + 4 + 4) * Params / (1024 * 1024 * 1024)
      Here, (4 + 4 + 4) refers to:
    • Model copy: 4 Bytes
    • Momentum: 4 Bytes
    • Variance: 4 Bytes
    • If 8-bit optimization is applied, the calculation changes to:
      8BitOptMem = (4 + 1 + 1) * Params / (1024 * 1024 * 1024)
      Where:
    • Model copy: 4 Bytes
    • Momentum: 1 Byte
    • Variance: 1 Byte
Dynamic Allocation Analysis
  • Activation Memory
    • The size of activation memory is related to model parameters, recomputation, and parallelism strategies. Here we refer to the formula provided by Megatron to explain the calculation of activation memory usage (case w/o parallelism).
      Activation memory consumption (Unit: GB):
      where:
    • s: sequence length, the number of tokens
    • b: microbatch size
    • h: hidden dimension size
    • a: number of attention heads
    • L: number of transformer layers
    • γ: scaling factor, for unit of GB, γ = 1 / (1024 * 1024 * 1024)
  • Gradient Memory
    • The memory required for gradients is consistent with the model parameters, depending on the data type used. The calculation formulas are as follows (unit: GB):
    • For fp32 model parameters:
      • fp32 = 4 * params / (1024 * 1024 * 1024)
    • For fp16 or bf16 models:
      • fp16/bf16 = 2 * params / (1024 * 1024 * 1024)
<ins/>

6.1.3 GPU Usage During Inference

💡
The memory composition for inference is simpler compared to training. There is a straightforward estimation formula for total memory usage:
When is the 1.2× estimate inaccurate?
  • When the sequence length is very long (e.g., long-context inference with tens of thousands of tokens), the KV cache grows significantly and memory usage can far exceed 1.2×.
  • When the batch size is large, the increase in intermediate activations can cause inference memory to expand.
  • When techniques like offloading (to cpu) are enabled during inference, memory usage can also vary.

6.1.4 Memory Optimization

🧸
Due to the exponential growth in model parameters, which far exceeds the physical memory capacity of a single GPU, LLM training inevitably requires memory optimization. Memory optimization focuses on reducing the computational overhead of the model or expanding the physical memory. But because the physical memory is hard to expand, the main ways to obtain extra memory are:
  • Time-for-space tradeoff: e.g., recomputation
  • Data shifting: e.g., multi-device parallelism, offload
Among them, time-for-space usually incurs computation overhead and latency; data shifting mainly incurs I/O overhead and may cause delays, possibly affecting throughput.
🌲
The memory optimization process generally starts from the model algorithm layer down to the system layer. A suggested optimization path could be:
Multi-device parallelism -> Operator/Data type -> Framework optimization -> Memory management -> Low-level API
  1. Multi-device parallelism:
    1. At this stage, this one is most frequently used and generally does not affect computational accuracy. Techniques like TP/PP/DP/Zero and recomputation can be used to lower memory consumption.
      Drawback: these methods may increase bandwidth overhead.
  1. Operator optimization:
    1. Select operators that consume less memory but with the same precision.
      Drawback: developing new operators is time-consuming.
  1. Data type optimization:
    1. Use lower precision to replace higher precision, such as replacing fp32 with fp16, or even using int8/int4.
      Drawback: this usually affects training convergence speed/stability/performance.
  1. Framework optimization:
    1. Within frameworks (like PyTorch), some data are intermediate results produced by the framework. These can be cleaned up to save memory.
      Drawback: relatively high development cost.
  1. Memory management:
    1. Reduce memory fragments introduced by frameworks’ memory management
      Drawback: currently few available methods.
  1. Low-level API:
    1. In GPU driver libs or CUDA ops libs, the way APIs consume memory differs. By using better low-level APIs that consume less memory, memory consumption can be reduced, such as FlashAttention. Some default operations will introduce additional system memory consumption; you may have to pay attention to if there is a higher version of the API that’s been improved.
Prev
5.5 Enterprise-level RAG Practice (II)
Next
6.2 Latency Analysis for Inference
Loading...
Article List
LLM Learning Roadmap
✨ Awesome-Anything
🖼️ Digital Image Processing
🍃 LLM Components
🌱 LLM Pre-training
☘️ LLM Post-Training
🍀 LLM Popular Models
🪴 LLM Applications
🌿 LLM Optimization
🌾 LLM Compression
🌵 LLM Hands-on Practice
🌴 LLM Must-read Papers
🌳 LLM Q&A
🐝 VLM Image Encoders
📝 MISC.