본문으로 건너뛰기

[llm-compressor] Group Size Validation: 그룹 크기 호환성 검사

들어가며

W4A16이나 W2A16 같은 그룹 단위 양자화는 출력 채널을 group_size(주로 128) 단위로 쪼개서 각 그룹마다 독립적인 스케일을 계산한다. 이때 레이어의 입력 채널 수가 group_size로 나누어 떨어져야 한다. MLP의 up_proj 같은 레이어는 대부분 128로 나누어 떨어지지만, 일부 모델은 그렇지 않다(예: Llama의 intermediate_size=11008은 128로 나눠떨어지지만 32000 같은 vocab 크기는 그렇지 않다). 이 호환성을 사전에 검증하는 것이 src/llmcompressor/modifiers/quantization/group_size_validation.pyvalidate_group_size 함수다.

핵심 구조/코드 분석

validate_group_size 함수

def validate_group_size(
    model: torch.nn.Module,              # 검증 대상 모델
    targets: list[str],                  # 양자화 대상 모듈 패턴
    ignore: list[str],                   # 건너뛸 모듈
    group_size: int,                     # 그룹 크기 (예: 128)
) -> list[str]:
    """
    Check that all target Linear layers have in_features divisible by group_size.
    Returns a list of offending module names (empty if all OK).
    """
    failing = []

    for name, module in match_named_modules(model, targets, ignore):
        if not isinstance(module, torch.nn.Linear):
            continue

        in_features = module.in_features
        if in_features % group_size != 0:
            failing.append(
                f"{name} (in_features={in_features}, group_size={group_size})"
            )

    return failing
  • 1단계: match_named_modules로 양자화 대상 모듈을 모두 찾는다. 이는 compressed-tensors가 제공하는 유틸리티로, 정규식 기반 패턴 매칭을 수행한다.
  • 2단계: Linear만 검사. Conv 같은 다른 레이어 타입은 건너뛴다.
  • 3단계: in_features % group_size != 0인 레이어를 리스트에 수집.
  • 4단계: 실패 리스트 반환. 빈 리스트면 검증 통과.

호출 지점과 에러 메시지

이 함수는 QuantizationModifier.on_initialize 또는 GPTQModifier.on_initialize에서 호출된다.

failing = validate_group_size(model, targets, ignore, group_size=128)
if failing:
    raise ValueError(
        "The following modules have in_features not divisible by group_size=128:\n  "
        + "\n  ".join(failing)
        + "\n\nConsider using a smaller group_size or adding these modules to `ignore`."
    )

에러 메시지가 실행 가능한 조언을 포함한다. 사용자는 어느 모듈이 문제인지 정확히 알 수 있고, 해결 방법(작은 group_size, 또는 ignore 목록 추가) 힌트를 받는다.

대표적인 실패 케이스

모델 레이어 in_features 128로 나눠짐?
Llama q_proj 4096
Llama up_proj 11008
Llama lm_head 4096
Gemma lm_head 256000 (vocab) ✓ (256000 / 128 = 2000)
어떤 모델 some_proj 4097 ✗ 실패

실제로 대부분의 LLM은 hidden size와 intermediate size를 128의 배수로 설계한다. NVIDIA Tensor Core의 효율성 때문이다. 하지만 커스텀 모델이나 비표준 아키텍처에서는 검증 실패가 발생할 수 있다.

Group size vs Strategy

group_sizeQuantizationStrategy.GROUP 전략에서만 의미가 있다. 다른 전략을 쓰는 경우는 검증이 필요 없다.

Strategy 검증 필요 설명
TENSOR 텐서 단위 하나의 스케일. 어떤 shape도 OK
CHANNEL 채널 단위 스케일. 각 채널이 독립적
GROUP 그룹 단위 스케일. in_features % group_size == 0 필수
TENSOR_GROUP Group + tensor-level global scale
TOKEN 토큰 단위 (주로 activation)

따라서 validate_group_sizestrategy in (GROUP, TENSOR_GROUP)일 때만 호출된다.

왜 이 설계인가

1. Fail-fast 철학. 검증이 없으면 양자화 코드가 한참 돌다가 중간에 shape mismatch 에러가 난다. 사전 검증은 "캘리브레이션 루프 시작 전 1초 안에 실패"를 보장한다. 특히 대형 모델에서 중요하다.

2. 실행 가능한 에러 메시지. 단순히 "group_size mismatch"가 아니라 "이 모듈에서, 이 값이, 이렇게 하면 해결"이라는 구체적 가이드를 준다. 사용자 경험 면에서 큰 차이.

3. 리스트 반환 설계. boolean이 아닌 "실패한 모듈 이름 리스트"를 반환한다. 여러 모듈이 동시에 실패해도 한 번에 보고되므로, 사용자가 여러 번 실패하며 반복할 필요가 없다.

4. Linear 한정 검증. Conv, Embedding 같은 레이어는 양자화 전략이 다르므로 제외한다. 이 필터가 없으면 "무관한" 모듈에 대한 경고가 발생해 실제 문제를 가린다.

5. Ignore 패턴 지원. 검증 대상도 targetsignore 패턴을 따르므로, 사용자가 특정 레이어를 이미 무시 처리했다면 그 레이어는 검증하지 않는다. 필요한 검사만 한다.

마무리

Group Size Validation은 60줄 안의 작은 함수지만, 사용자 경험에 큰 영향을 주는 guard다. 다음 글부터는 본격적으로 개별 양자화 알고리즘(GPTQ 논문 구현)을 파고든다.

참고 자료

댓글

관련 포스트

llm-compressor 의 다른글