CPU에서 BERT 추론 확장하기 (Part 1)

Hugging Face는 현대적인 CPU에서 BERT와 같은 모델의 추론을 확장하는 방법론을 상세히 설명하며, 특정 물리적 CPU 코어에 바인딩된 여러 개의 독립적인 모델 인스턴스를 배포함으로써 최대 처리량을 달성할 수 있음을 보여줍니다. 이 접근 방식은 Simultaneous Multi-Threading (SMT) 및 소켓 간 통신 오버헤드를 피하여 처리량에서 거의 선형적인 확장성을 제공합니다.

기본 프레임워크 성능

AWS c5.metal 인스턴스(Intel Xeon Platinum 8275 CPU, 48 cores/96 threads)에서 수행된 초기 벤치마크 결과, 다양한 구성에서 PyTorch (1.8.1)가 Google TensorFlow (2.4.1)보다 BERT 추론 성능이 일반적으로 더 뛰어난 것으로 나타났습니다. 이러한 성능 차이는 기반이 되는 실행 기술의 차이에서 기인합니다. PyTorch는 OpenMP와 Intel MKL (oneDNN)을 활용하는 반면, TensorFlow는 Eigen과 자체 스레딩 구현에 의존합니다.

CPU 아키텍처 및 스레드 친화성

주로 일반 행렬 곱셈(GEMMs)으로 구성되는 BERT 추론과 같은 CPU 집약적 작업을 최적화하려면 특정 하드웨어 고려 사항이 필요합니다.

Simultaneous Multi-Threading (SMT)

SMT(또는 Hyper-Threading)는 두 개의 소프트웨어 스레드가 단일 물리적 코어를 공유하도록 합니다. 그러나 BERT 추론은 CPU 집약적이기 때문에 논리적 코어가 동일한 실행 리소스를 두고 경쟁하게 됩니다. 즉, SMT는 성능 이점을 제공하지 않으며, 물리적 코어만 사용하는 것이 권장됩니다.

NUMA 및 소켓 관리

현대적인 멀티 소켓 서버는 각 CPU 소켓이 자체 메모리 서브셋을 관리하는 Non-Uniform Memory Access (NUMA) 방식을 사용합니다. 소켓 간 통신 오버헤드로 인한 성능 저하를 방지하려면 numactl과 같은 도구를 사용하여 프로세스를 특정 코어 및 메모리 풀에 바인딩해야 합니다.

핵심 구성 전략:

  • 스레드 친화성 (Thread Affinity): 프로세스를 특정 물리적 코어 세트에 바인딩합니다 (예: numactl -C -47).
  • 메모리 할당: 계산을 수행하는 코어와 가장 가까운 소켓에 메모리가 할당되도록 합니다 (예: numactl -m 0,1).

코어 수 확장 vs. 멀티 스트림 추론

추론을 위해 리소스를 확장하는 데는 두 가지 주요 방법이 있으며, 각각 지연 시간(latency)과 처리량(throughput)에에 미치는 영향이 다릅니다.

코어 수 확장 (Strong Scaling)

이는 지연 시간을 줄이기 위해 단일 작업에 할당된 코어 수를 늘리는 것을 포함합니다. 이 방식의 효과는 문제의 크기에 따라 달라집니다:

  • 작은 규모에서 중간 규모의 문제: 단일 소켓을 사용하는 것이 종종 가장 좋은 성능을 제공합니다.
  • 큰 규모의 문제: 소켓 간 통신 오버헤드가 계산 비용에 의해 상쇄되므로, 두 소켓 모두의 사용 가능한 모든 코어를 사용하는 것이 유익합니다.

멀티 스트림 추론 (Instance Parallelism)

하나의 인스턴스에 더 많은 코어를 할당하는 대신, 이 방법은 중복되지 않는 물리적 코어의 서브셋에 각각 바인딩된 여러 개의 독립적인 모델 인스턴스를 할당합니다.

예를 들어, 24개의 코어를 가진 단일 인스턴스보다 각각 12개의 코어를 사용하는 4개의 독립적인 인스턴스를 실행하면 개별 지연 시간은 약간 증가할 수 있지만, 전체 처리량은 4배 증가합니다. 이를 통해 서로 다른 시퀀스 길이에 맞춰 조정된 특정 인스턴스로 요청을을 routing 할 수 있는 "스마트 디스패칭(smart dispatching)"이 가능해집니다 (예: 짧은 시퀀스에는 8개 코어, 긴 시퀀스에는 24개 코어).

배치 사이즈 확장 및 처리량

배치 사이즈 확장은 글로벌 배치 $B$를 $N$개의 인스턴스에 나누는 것을 포함하며, 여기서 각 인스턴스는 $C/N$개의 코어에서 $B/N$의 서브 배치를 처리합니다.

지연 시간 및 처리량 트레이드오프

  • 지연 시간 (Latency): 배치의 전체 지연 시간은 풀(pool) 내에서 가장 느린 인스턴스에 의해 결정됩니다. 지연 시간을 최소화하기 위한 최적의 인스턴스 수는 문제의 크기에 따라 달라집니다. 배치 크기 8, 시퀀스 길이 128인 경우, 4개의 인스턴스(각각 배치 2, 12개 코어)가 가장 좋은 결과를 제공했습니다.
  • 처리량 (Throughput): 인스턴스당 작업량이 비례적으로 감소한다면, 인스턴스가 추가될수록 처리량은 거의 선형적으로 확장됩니다. 이는 최적의 하드웨어 활용도를 나타냅니다.

하드웨어 최적화 영향 요약

스레드 친화성 및 인스턴스 할당을 올적으로게 조정함으로써, 조직은 인프라 비용을 크게 줄일 수 있습니다. Hugging Face는 특정 워크로드의 경우, 문제의 크기가 최적의 지연 시간을 위해 추가 코어를 필요로 하지 않는다면, 48코어 머신($4.848/h)에서 8코어 인스턴스($0.808/h)를 사용하는 것으로 전환함으로써 6배의 비용 절감 효과를를 수 있습니다 있습니다.

Sources