[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.py의 validate_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_size는 QuantizationStrategy.GROUP 전략에서만 의미가 있다. 다른 전략을 쓰는 경우는 검증이 필요 없다.
| Strategy | 검증 필요 | 설명 |
|---|---|---|
| TENSOR | ✗ | 텐서 단위 하나의 스케일. 어떤 shape도 OK |
| CHANNEL | ✗ | 채널 단위 스케일. 각 채널이 독립적 |
| GROUP | ✓ | 그룹 단위 스케일. in_features % group_size == 0 필수 |
| TENSOR_GROUP | ✓ | Group + tensor-level global scale |
| TOKEN | ✗ | 토큰 단위 (주로 activation) |
따라서 validate_group_size는 strategy in (GROUP, TENSOR_GROUP)일 때만 호출된다.
왜 이 설계인가
1. Fail-fast 철학. 검증이 없으면 양자화 코드가 한참 돌다가 중간에 shape mismatch 에러가 난다. 사전 검증은 "캘리브레이션 루프 시작 전 1초 안에 실패"를 보장한다. 특히 대형 모델에서 중요하다.
2. 실행 가능한 에러 메시지. 단순히 "group_size mismatch"가 아니라 "이 모듈에서, 이 값이, 이렇게 하면 해결"이라는 구체적 가이드를 준다. 사용자 경험 면에서 큰 차이.
3. 리스트 반환 설계. boolean이 아닌 "실패한 모듈 이름 리스트"를 반환한다. 여러 모듈이 동시에 실패해도 한 번에 보고되므로, 사용자가 여러 번 실패하며 반복할 필요가 없다.
4. Linear 한정 검증. Conv, Embedding 같은 레이어는 양자화 전략이 다르므로 제외한다. 이 필터가 없으면 "무관한" 모듈에 대한 경고가 발생해 실제 문제를 가린다.
5. Ignore 패턴 지원. 검증 대상도 targets와 ignore 패턴을 따르므로, 사용자가 특정 레이어를 이미 무시 처리했다면 그 레이어는 검증하지 않는다. 필요한 검사만 한다.
마무리
Group Size Validation은 60줄 안의 작은 함수지만, 사용자 경험에 큰 영향을 주는 guard다. 다음 글부터는 본격적으로 개별 양자화 알고리즘(GPTQ 논문 구현)을 파고든다.
참고 자료
관련 포스트
llm-compressor 의 다른글
- 이전글 [llm-compressor] Quantization Calibration: update_weight_zp_scale와 observer 등록
- 현재글 : [llm-compressor] Group Size Validation: 그룹 크기 호환성 검사
- 다음글 [llm-compressor] GPTQ: 2차 정보 기반 후훈련 양자화 구현
댓글