본문 바로가기
NLP

LLM Quantization - by llama.cpp

by ㅣlㅣl 2024. 3. 11.

최종 프로젝트를 위해 LLM Quantization을 진행하여 Chat agent backbone model의 성능을 테스트해보고자 한다.

눈물의 troubleshooting..


개요

우리의 목표는 다음과 같다!

  1. LLM을 gguf 파일 형식으로 변환
  2. LLM quantize
  3. Langchain으로 inference를 쉽게 뽑을 수 있게 하기

 

gguf convert, quantization 모두 llama.cpp를 활용해 쉽게 할 수 있다.

https://github.com/ggerganov/llama.cpp

 

GitHub - ggerganov/llama.cpp: LLM inference in C/C++

LLM inference in C/C++. Contribute to ggerganov/llama.cpp development by creating an account on GitHub.

github.com

 

쉽게? ... 아닌듯

레포를 차근차근 따라가보자.

 

참고로 내 개발 환경은 데스크탑 - Windows 11 (WSL2) / 노트북 - Macbook Air (M1)

우선적으로 WSL2 부터 시도해 주었으나... 결론부터 말하자면 Mac에서만 quantization에 성공했다.

따라서 Mac 환경에서의 llama.cpp 적용에 초점이 맞춰져있다.

 

또한 레포에서 코드 수정 & 추가 & 삭제가 매우 활발하게 일어나기 때문에, 진행 전 항상 git pull을 해주는 습관을 들이자.

 

Install

git clone https://github.com/ggerganov/llama.cpp.git
cd llama.cpp
git pull -p
pip install -r requirements.txt

 

Build

cuBLAS build부터 해줘야 model quantization을 진행할 수 있다.

nvidia-cuda-toolkit이 깔려있는 것을 전제로 아래 과정이 수행된다.

 

in WSL2 (Ubuntu-20.04)

공식 레포에는 다음과 같이 적혀있다.

On Windows:
1. Download the latest fortran version of w64devkit.
2. Extract w64devkit on your pc.
3. Run w64devkit.exe.
4. Use the cd command to reach the llama.cpp folder.
5. From here you can run: `make`

그러나 5번 'make' 명령어 실행에서 에러가 발생했다.

Makefile:613: *** I ERROR: For CUDA versions < 11.7 a target CUDA architecture must be explicitly provided via CUDA_DOCKER_ARCH. Stop. /usr/bin/ld: BFD (GNU Binutils for Ubuntu) 2.38 assertion fail ../../bfd/reloc.c:8580 console.o:console.cpp:(.xdata+0x5c): dangerous relocation: collect2: fatal error: ld terminated with signal 11 [Segmentation fault] compilation terminated. make: *** [Makefile:682: main] Error 1

Segmentation fault... 심지어 cuda 버전이 12.1이었음에도 저런 에러가 뜬 이유는 찾을 수가 없었다.

 

따라서 cmake로 선회했는데,

mkdir build
cd build
cmake .. -DLLAMA_CUBLAS=ON
cmake --build . --config Release
ERROR : undefined reference to `cudaGetDeviceProperties_v2'

cudaGetDeviceProperties_v2는 cuda 12.2 이상 버전부터 지원한다.

내가 가지고 있는 RTX 4070 ti에 CUDA 12.2 이상을 깔 수는 있지만, 로컬에서 돌리고 있는 기타 프로젝트의 호환성 이슈 & 시간적 여유가 없기에 우선은 보류하였다.

본인의 GPU architecture가 CUDA 12.2 이상을 지원할 경우 WSL2 -> cmake로 시도해보는 것도 나쁘지 않겠다.

 

in Mac

그러나 Mac에서의 세팅이 훨씬 간편했기 때문에 우선적으로 시도해보았다.

Mac에서는 무려...

make LLAMA_CUBLAS=1

 

이거 한 줄이면 된다.. ㅋㅋ 참....

 

 

Convert model to gguf

이제 gguf 형식으로 모델을 변환해줄 시간이다.

여기서 잠깐, gguf는 대체 무엇일까?

 

GGUF & GGML

한 줄 요약하자면, GPT같은 모델 양자화해서 저장하는 파일 형식이다!

  • GGML : GPT-Generated Model Language
  • GGUF : GPT-Generated Unified Format

GGML이 발전된 것이 GGUF format이라고 볼 수 있다. 자세한 건 상단의 llama.cpp 레포와 아래 컬럼에 잘 나와있다.

https://medium.com/@phillipgimmi/what-is-gguf-and-ggml-e364834d241c

 

What is GGUF and GGML?

GGUF and GGML are file formats used for storing models for inference, especially in the context of language models like GPT (Generative…

medium.com

 

 

그럼 이제 본격적으로 모델을 변환해보자.

 

1. 변환한 모델의 snapshot을 Huggingface에서 다운로드

다양한 모델이 있을텐데, 이번 예시로는 upstage/SOLAR-10.7B-v1.0를 backbone으로 하여 한국어 말뭉치를 추가 학습한 beomi/OPEN-SOLAR-KO-10.7B 를 변환해보겠다.

# download.py
from huggingface_hub import snapshot_download
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--model_id')
parser.add_argument('--local_dir', default="./orion")
args = parser.parse_args()

def main(args):
    snapshot_download(repo_id=args.model_id, local_dir=args.local_dir,
                    local_dir_use_symlinks=False, revision="main")


if __name__ == '__main__':
    main(args)
python3 download.py --model_id=beomi/OPEN-SOLAR-KO-10.7B --local_dir=./OPEN-SOLAR-KO-10.7B/

 

이렇게 하면 지정된 local_dir 안에 huggingface snapshot이 다운로드 받아질 것이다.

처음에는 convert-hf-to-gguf.py로 변환을 시도해보았으나

NotImplementedError: Architecture "LlamaForCausalLM" not supported!

가 발생했고, 따라서 convert.py로 변환을 시도했을 때 문제 없이 잘 돌아갔다.

(관련 이슈 : https://github.com/ggerganov/llama.cpp/issues/4964)

# python3 llama.cpp/convert.py {스냅샷 저장한 폴더 위치} --outfile {내보낼 gguf 모델 위치}.gguf
python3 llama.cpp/convert.py ./OPEN-SOLAR-KO-10.7B --outfile OPEN-SOLAR-KO-10.7B/OPEN-SOLAR-KO-10.7B.gguf

 

2. Model quantization

여러 가지 양자화 방식을 지원해준다. [각주:1]

  • q2_k: Uses Q4_K for the attention.vw and feed_forward.w2 tensors, Q2_K for the other tensors.
  • q3_k_l: Uses Q5_K for the attention.wv, attention.wo, and feed_forward.w2 tensors, else Q3_K
  • q3_k_m: Uses Q4_K for the attention.wv, attention.wo, and feed_forward.w2 tensors, else Q3_K
  • q3_k_s: Uses Q3_K for all tensors
  • q4_0: Original quant method, 4-bit.
  • q4_1: Higher accuracy than q4_0 but not as high as q5_0. However has quicker inference than q5 models.
  • q4_k_m: Uses Q6_K for half of the attention.wv and feed_forward.w2 tensors, else Q4_K
  • q4_k_s: Uses Q4_K for all tensors
  • q5_0: Higher accuracy, higher resource usage and slower inference.
  • q5_1: Even higher accuracy, resource usage and slower inference.
  • q5_k_m: Uses Q6_K for half of the attention.wv and feed_forward.w2 tensors, else Q5_K
  • q5_k_s: Uses Q5_K for all tensors
  • q6_k: Uses Q8_K for all tensors
  • q8_0: Almost indistinguishable from float16. High resource use and slow. Not recommended for most users.

 

이 중 q5_k_s 방식을 사용해서 양자화를 진행할 것이다.

# ./llama.cpp/quantize {GGUF 파일 위치} {양자화된 GGUF 파일 위치} {양자화 방식}
./llama.cpp/quantize ./OPEN-SOLAR-KO-10.7B/OPEN-SOLAR-KO-10.7B.gguf ./OPEN-SOLAR-KO-10_7B.Q5_K_S.gguf q5_k_s

만약 커맨드 실행 시 'quantize is a directory' 와 같은 에러가 발생한다면 build가 제대로 수행되지 않은 것이니 build부터 다시 해야 한다.

 

3. Upload to Huggingface

팀원들과 공유 & 데스크탑에서의 사용을 위해 huggingface에 upload까지 진행해보겠다.

코드를 실행하기 전, huggingface-cli login으로 access token 발급까지 진행해주자.

# upload.py
from huggingface_hub import HfApi
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--model_id')
args = parser.parse_args()

def main(args):
    api = HfApi()

    model_id = "ywhwang/" + args.model_id
    api.create_repo(model_id, exist_ok=True, repo_type="model")
    api.upload_file(
        path_or_fileobj=args.model_id,
        path_in_repo=args.model_id,
        repo_id=model_id,
    )

if __name__ == '__main__':
    main(args)
python3 upload.py --model_name=OPEN-SOLAR-KO-10.7B --file_path=OPEN-SOLAR-KO-10_7B.Q5_K_S.gguf

 

깔끔하게 업로드가 진행된 것을 볼 수 있다!

 

 

다음 번에는 변환한 gguf 모델 파일을 어떻게 inference 할 수 있는지, G-EVAL을 어떻게 진행하면 좋은지 포스팅해보도록 하겠다.

 


참고자료

https://velog.io/@iloveonsen/llama.cpp-%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%B4-huggingface-%EB%AA%A8%EB%8D%B8%EC%9D%84-GGUF-%ED%98%95%ED%83%9C%EB%A1%9C-%EB%B3%80%ED%99%98%ED%95%98%EA%B8%B0

 

llama.cpp 를 이용해 huggingface 모델을 GGUF 형태로 변환하기

LM Studio 는 LLM 챗봇 모델들을 로컬 머신에서 inference 할수 있게 해주는 유용한 프로그램으로, 원하는 모델을 다운 받아 ChatGPT 와 비슷한 형태로 채팅을 할수 있도록 하는 프로그램이다...

velog.io

 

 

https://www.substratus.ai/blog/converting-hf-model-gguf-model/

 

Converting HuggingFace Models to GGUF/GGML | Substratus.AI

Llama.cpp is a great way to run LLMs efficiently on CPUs and GPUs. The downside however is that you need to convert models to a format that's supported by Llama.cpp, which is now the GGUF file format. In this blog post you will learn how to convert a Huggi

www.substratus.ai