EXL2 양자화 변환 (convert.py)

EXL2 양자화 변환 (convert.py)

EXL2 포맷으로 모델을 양자화하려면 저장소의 convert.py를 쓰면 돼요. 이 스크립트는 두 번의 패스로 동작해요: 먼저 양자화가 모델의 각 모듈에 미치는 영향을 측정(measurement)하고, 그 결과를 바탕으로 전체 평균 비트율을 맞추면서 각 레이어의 양자화 오차를 최소화하는 파라미터를 골라 실제 양자화를 수행해요. 오차 계산·파라미터 선택이 자동이라서, 목표 비트율만 정해 주면 되는 구조예요.

아래는 공식 문서의 옵션·주의점·예시를 정리한 거예요.

convert.py 인자

  • -i / --in_dir directory: (재개가 아니라면 필수) 변환할 원본 모델(HF 형식, FP16). 디렉토리에 최소한 config.json, tokenizer.model, 가중치 .safetensors 파일이 있어야 해요. 가중치 파일이 여러 개여도(sharded 모델) 전부 인덱싱해서 필요한 텐서를 찾아줘요.
  • -o / --out_dir directory: (필수) 변환기가 임시 파일을 저장하고 최종 산출물을 놓을 작업 디렉토리. -cf를 함께 주지 않으면 여기에 결과가 저장돼요. 변환 시작 시 이 디렉토리가 비어 있지 않으면, 그곳에서 하던 작업을 재개(resume) 하려고 시도해요. 즉 작업이 중단돼도 같은 인자로 다시 실행하면 이어서 진행돼요. 다만 파라미터는 이 디렉토리의 job.json에서 읽으므로, 재개 시 새 파라미터를 주려면 그 파일을 직접 수정해야 해요. 변경 사항 중 일부는 잡을 비정상 상태로 만들 수 있으니 주의가 필요해요.
  • -nr / --no_resume: 이 플래그를 주면 작업 디렉토리가 비어 있지 않아도 재개하지 않아요. 비어 있지 않으면 그 안의 파일을 전부 삭제하고 새 잡을 시작해요.
  • -cf / --compile_full directory: 결과 .safetensors는 기본적으로 작업 디렉토리에 저장돼요. 여기에 디렉토리를 지정하면 양자화된 가중치를 그쪽에 저장하고, 모델(입력) 디렉토리의 모든 파일(원본 .safetensors 제외)을 그 디렉토리로 복사해요. 결과적으로 ExLlamaV2가 바로 추론에 쓸 수 있는 완전한 모델 디렉토리가 만들어져요.
  • -om / --output_measurement file: 첫 번째(측정) 패스가 끝나면 measurement.json이 작업 디렉토리(-o)에 생성돼요. -om으로 경로를 지정하면 그 경로에 측정 결과를 저장하고 측정 패스 직후 스크립트가 바로 종료돼요.
  • -m / --measurement file: 측정 패스를 건너뛰고 주어진 파일의 결과를 사용해요. 같은 모델을 여러 비트율로 양자화할 때 특히 유용한데, 측정 패스는 오래 걸리거든요.
  • -c / --cal_dataset file: (선택) Parquet 형식의 보정(calibration) 데이터셋. 양자화기는 이 파일의 데이터를 하나의 긴 문자열로 이어붙이고, 처음 r × l 개 토큰을 보정에 써요. 지정하지 않으면 다양한 데이터를 폭넓게 섞은 내장 기본 보정 데이터셋을 써요. 이 기본셋은 모델이 특정 모드·언어·스타일에 과적합하지 않도록 설계됐고, 특히 낮은 비트율에서 더 견고하고 믿을 만한 출력을 만들어 줘요.
  • -l / --length int: 보정 각 행의 길이(토큰). 기본 2048.
  • -r / --dataset_rows int: 보정 배치의 행 수. 기본 100.
  • -ml / --measurement_length int: 측정 패스에 쓰는 보정 각 행의 길이(토큰). 기본 2048.
  • -mr / --measurement_rows int: 측정 패스 보정 배치의 행 수. 기본 16.
  • -b / --bits float: 목표 평균 비트/가중치(비트율).
  • -hb / --bits int: 모델의 lm_head(출력) 레이어의 비트 수. 기본 6인데, 실제로는 약 6.3비트의 혼합 정밀도 결과를 줘요. 선택지는 2, 3, 4, 5, 6, 8 (실용적으로는 6과 8만 쓸 만해요).
  • -ss / --shard_size float: 출력 shard 크기(MB). 기본 8192. 0으로 두면 샤딩을 끄는 거예요. 아주 큰 .safetensors 파일을 쓰려면 시스템 RAM이 많이 필요할 수 있어요.
  • -ra / --rope_alpha float: 보정에 적용할 RoPE(NTK) alpha.
  • -rs / --rope_scale float: 보정에 적용할 RoPE 스케일 계수. 이 설정은 모델 config에서 자동으로 읽지 않으므로, 모델이 학습/파인튜닝될 때 쓴 설정을 직접 확인하는 게 강력히 권장돼요. 예를 들어 deepseek-coder는 스케일 계수 4를 쓰니, -rs 4 없이 변환하면 잘못 보정돼요.

두 번의 패스와 측정 파일의 중요성

첫 번째(측정) 패스는 모델 전체를 사실상 약 12번 양자화해서 실행하기 때문에 느려요(보정 데이터셋의 덜 포괄적인 샘플로 하지만). 그래서 measurement.json을 꼭 저장해 두면, 같은 모델을 다시 양자화할 때 그 패스를 건너뛸 수 있어요. 같은 모델을 여러 비트율로 돌릴 땐 특히 이 파일 하나가 시간을 크게 아껴요.

사용 예시

모델을 변환하면서 양자화 버전과 원본 파일들을 모두 담은 디렉토리 만들기:

python convert.py \
    -i /mnt/models/llama2-7b-fp16/ \
    -o /mnt/temp/exl2/ \
    -cf /mnt/models/llama2-7b-exl2/3.0bpw/ \
    -b 3.0

작업 디렉토리를 비우고 모델의 측정 패스만 실행해 measurement.json 만들기:

python convert.py \
    -i /mnt/models/llama2-7b-fp16/ \
    -o /mnt/temp/exl2/ \
    -nr \
    -om /mnt/models/llama2-7b-exl2/measurement.json

그 측정 결과를 재사용해 같은 모델을 두 비트율로 양자화하기:

python convert.py \
    -i /mnt/models/llama2-7b-fp16/ \
    -o /mnt/temp/exl2/ \
    -nr \
    -m /mnt/models/llama2-7b-exl2/measurement.json \
    -cf /mnt/models/llama2-7b-exl2/4.0bpw/ \
    -b 4.0

python convert.py \
    -i /mnt/models/llama2-7b-fp16/ \
    -o /mnt/temp/exl2/ \
    -nr \
    -m /mnt/models/llama2-7b-exl2/measurement.json \
    -cf /mnt/models/llama2-7b-exl2/4.5bpw/ \
    -b 4.5

작업 -o 디렉토리가 비어 있지 않고 -nr을 안 줬다면 기존 잡이 재개돼요. 다른 인자 없이도 재개할 수 있어요:

python convert.py -o /mnt/temp/exl2/

주의점

  • 변환 스크립트가 "Solving..." 단계에서 멈춘 것처럼 보이면 잠시 기다려 보세요. 비트 예산 안에서 각 레이어의 측정 오차 곱을 최소화하는 파라미터 조합을 찾는 중인데, 그 구현이 아주 효율적이진 않아요.
  • MoE 모델의 측정·변환 중 !! Warning: w2.7 has less than 10% calibration for 77/115 rows 같은 메시지가 보일 수 있어요. 참조 포워드 패스에서 특정 전문가(expert)가 충분히 트리거되지 않아 보정 데이터가 적다는 뜻인데, 변환 실패를 일으키진 않고 아예 무시해도 되는 경우가 많아요. 다만 MoE의 GPTQ식 양자화는 아주 최신이라 실제로 영향이 있는지는 아직 불확실하다고 문서는 말해요.
  • 변환 후 "calibration perplexity (quant)" 값은, 만들어진 양자화 모델이 보정 데이터의 작은 샘플을 처리한 퍼플렉서티예요. 이 값이 30 이상으로 높게 나오면 양자화가 잘 안 된 신호이고, 수천 단위로 비정상적으로 높다면 양자화가 치명적으로 실패한 거예요.

하드웨어 요구사항

대략 70B 모델을 변환하려면 RAM 약 64GB, VRAM 약 24GB가 필요하고, 7B는 RAM 약 16GB, VRAM 약 8GB 정도면 돼요.

메모리 요구를 결정하는 건 모델의 깊이보다 폭(width) 이에요. 그래서 70B와 hidden size가 같은 120B 모델은 하드웨어 요구가 같아요. Mixtral 8x7B는 feed-forward 레이어가 훨씬 넓어서 VRAM이 약 20GB 필요해요.

더 알아보기

  • ExLlamaV2 개요 — EXL2 포맷 개념과 양자화 배경
  • 다이내믹 제너레이터 — 양자화한 모델로 실제 추론을 돌리는 법
  • 평가 스크립트 — 양자화 결과물을 HumanEval·MMLU로 측정하기
  • 원본: Conversion 문서