How to Inference Big LLM? - Using Accelerate Library

논문 정보

  • Date: 2024-05-07
  • Reviewer: 준원 장
  • Property: LLM, Inference

A100-80GB에서 BIG LLM (e.g.,70B)을 Inference하는 방법

  • Llama2-70B Model을 Full Precision으로 올리기 위해서 필요한 VRAM
# Constants
parameters = 70_000_000_000  # 70 billion parameters
bytes_per_parameter = 4  # float32

# Total size in bytes
total_bytes = parameters * bytes_per_parameter

# Convert bytes to gigabytes
bytes_per_gb = 2**30
total_gb = total_bytes / bytes_per_gb

total_gb = 260.77 GB

⇒ 조금 더 효과적으로 가지고 있는 자원을 활용해 Inference할 수 있는 방법이 없을까?

Huggingface accelerate 필요 (Transformer 호환 검토 필요!!)

pip install accelerate
  • 일반적으로 Model을 load하는 방법은 다음과 같음
import torch

my_model = ModelClass(...)
state_dict = torch.load(checkpoint_file)
my_model.load_state_dict(state_dict)

→ state_dict란

‘’’In PyTorch, the learnable parameters (i.e. weights and biases) of a **torch.nn.Module** model are contained in the model’s parameters (accessed with **model.parameters()**). A **state_dict** is simply a Python dictionary object that maps each layer to its parameter tensor.’’’

→ ModelClass가 가지고 있는 device(mps 또는 cuda)가 요구하는것보다 더 많은 메모리를 요구하는 경우, OOM이 발생할 수 있음

  • RAM(VRAM X)을 많이 차치하지 않은 empty skeleton model을 먼저 load한다.
from accelerate import init_empty_weights
with init_empty_weights():
    my_model = ModelClass(...)
  • Instantiate한 Model이 ‘Parameterless’하기 때문에  load_checkpoint_and_dispatch()라는 함수를 통해서 checkpoint를 empty model에 load하고, 모든 device(GPU/MPS 및 CPU RAM)에 걸쳐 weight를 보낸다.

[device_map="auto" 로 설정하면 GPU → CPU → RAM → DISK 순서로 자동적으로 weight를 보냄]

from accelerate import load_checkpoint_and_dispatch

model = load_checkpoint_and_dispatch(
    model, checkpoint=checkpoint_file, device_map="auto"
)

→ ‘no_split_module_classes’ argument로 분리되면 안되는 layer를 지정해줘야하는데 (e.g, no_split_module_classes=['Block']) 모델별 달라서 사용전에 필히 확인!

→ Conceptual 영상에 따르면 이후 Garbage Collecter가 Checkpoint 메모리에서 회수해간다고 함

  • Inference는 아래와 같은 과정으로 진행
  1. 각 Weight에 hook이 추가됨 (이건 weight를 VRAM에서 On/OFF loading하는 역할을 진행)
  1. Input이 첫번째 layer에 도달하면 hook이 trigger되면 첫번째 layer가 CPU RAM → GPU VRAM으로 이동해서 Forwarding이 진행됨
  1. 2번째 layer에 도달하면 hook이 trigger되고 1번째 layer는 GPU VRAM → CPU RAM으로 이동 & 2번째 layers는 CPU RAM → GPU VRAM으로 이동한 후 Forwarding이 진행됨
  • 예시
# Create a model and initialize it with empty weights
weights_location = hf_hub_download(model_name, "model.safetensors.index.json")
with init_empty_weights():
    model = AutoModelForCausalLM.from_pretrained(model_name)
# Load the checkpoint and dispatch it to the right devices
model = load_checkpoint_and_dispatch(
        model, checkpoint=weights_location, device_map="auto", no_split_module_classes=["LlamaDecoderLayer"], dtype=torch.float16)
model.eval()

# input forwarding
 model.generate(input_ids=input_ids['input_ids'].cuda(), attention_mask=input_ids['attention_mask'].cuda())

→ “”model.safetensors.index.json””

[index.json: It maps these configurations to the actual files stored in the repository, guiding users or automated systems on how to correctly load the model.]

{
  "metadata": {
    "total_size": 137953316864
  },
  "weight_map": {
    "lm_head.weight": "model-00015-of-00015.safetensors",
    "model.embed_tokens.weight": "model-00001-of-00015.safetensors",
    "model.layers.0.input_layernorm.weight": "model-00001-of-00015.safetensors",
    "model.layers.0.mlp.down_proj.weight": "model-00001-of-00015.safetensors",
    "model.layers.0.mlp.gate_proj.weight": "model-00001-of-00015.safetensors",
    "model.layers.0.mlp.up_proj.weight": "model-00001-of-00015.safetensors",
    "model.layers.0.post_attention_layernorm.weight": "model-00001-of-00015.safetensors",
    "model.layers.0.self_attn.k_proj.weight": "model-00001-of-00015.safetensors",
  • Reference