ggml 소개
ggml은 C와 C++로 작성된 저수준 머신러닝(ML) 라이브러리로, 트랜스포머 추론을 위해 특별히 설계되었습니다. llama.cpp, whisper.cpp, ollama, Jan, LM Studio, GPT4All 등 인기 있는 온-디바이스 LLM 프로젝트의 기반 엔진으로 사용됩니다.
ggml의 핵심 장점
ggml은 최소주의와 효율성을 목표로 설계되어 자원 제한이 있는 하드웨어에 배포하기에 이상적입니다. 주요 장점은 다음과 같습니다:
- 최소 발자국: 핵심 라이브러리는 5개 미만의 파일로 자체 포함되어 있으며, 컴파일된 바이너리 크기는 1MB 이하입니다.
- 단순화된 컴파일: GPU 지원 없이 기본 컴파일을 위해 GCC 또는 Clang만 필요하므로 복잡한 빌드 도구를 피할 수 있습니다.
- 넓은 하드웨어 호환성: x86_64, ARM, Apple Silicon, CUDA 등 다양한 하드웨어 아키텍처를 지원합니다.
- 메모리 효율성: 라이브러리는 텐서 저장 및 연산에 대한 오버헤드를 최소화하고, 양자화 텐서를 지원하여 메모리 사용량을 줄이고 성능을 향상시킬 수 있습니다.
기술적 트레이드오프
활발히 개발 중인 저수준 라이브러리인 ggml은 다음과 같은 제한 사항을 가지고 있습니다:
- 백엔드 차이: 모든 텐서 연산이 모든 백엔드에서 지원되는 것은 아니며(예: CPU에서는 동작하지만 CUDA에서는 동작하지 않을 수 있음),
- 개발 복잡성: ggml을 사용하려면 저수준 프로그래밍에 대한 깊은 지식이 필요합니다.
- 안정성: 활발히 개발 중이므로 파괴적인 변경이 발생할 수 있습니다.
핵심 용어 및 개념
ggml을 이해하려면 성능을 세밀하게 제어할 수 있는 여러 저수준 추상화에 익숙해져야 합니다:
ggml_context: 텐서, 그래프 및 선택적 데이터를 담는 컨테이너.ggml_cgraph: 백엔드가 실행할 연산 순서를 나타내는 계산 그래프.ggml_backend: 계산 그래프를 실행하기 위한 인터페이스이며, CPU(기본), CUDA, Metal, Vulkan, RPC 등에 대한 구현을 제공합니다.ggml_backend_buffer_type: 특정 백엔드에 연결된 메모리 할당자(예: GPU 메모리 할당).ggml_backend_buffer:buffer_type에 의해 할당된 버퍼로, 여러 텐서의 데이터를 저장할 수 있습니다.ggml_gallocr: 계산 그래프 내 텐서를 효율적으로 관리하기 위한 그래프 메모리 할당자.ggml_backend_sched: 여러 백엔드에 연산을 분배하는 스케줄러(예: CPU와 GPU 간 작업 분할)이며, 지원되지 않는 연산은 자동으로 CPU에 할당합니다.
구현 워크플로우
기본 연산
행렬 곱셈과 같은 간단한 연산의 경우 ggml 워크플로우는 다음과 같습니다:
- 텐서 데이터를 위한
ggml_context할당. - 텐서를 생성하고 데이터를 할당.
- 연산을 위한
ggml_cgraph정의(예:ggml_mul_mat). ggml_graph_compute_with_ctx를 사용해 연산 실행.- 결과를 가져오고 메모리를 해제.
백엔드 기반 연산
CUDA와 같은 특정 하드웨어 백엔드를 사용할 때는 장치 메모리 관리를 효율적으로 하기 위해 절차가 더 상세합니다:
ggml_backend초기화.- 텐서 메타데이터 전용
ggml_context할당. - 텐서 메타데이터(형태와 타입) 생성.
- 디바이스에 텐서를 저장하기 위한
ggml_backend_buffer할당. - RAM에서 백엔드 버퍼로 텐서 데이터 복사.
- 그래프 할당을 위한
ggml_cgraph와ggml_gallocr생성. ggml_backend_graph_compute를 사용해 연산 실행.- 디바이스 버퍼에서 RAM으로 결과 텐서 복사.
계산 그래프 디버깅
개발자는 ggml_cgraph를 검사하여 연산 순서를 확인할 수 있습니다. 라이브러리는 그래프를 콘솔에 출력하는 ggml_graph_print와 Graphviz dot 형식으로 그래프를 내보내 시각화할 수 있는 ggml_graph_dump_dot를 제공합니다.
Sources
- OriginalIntroduction to ggml