Transformers documentation

기여하기

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v5.22.2).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

기여하기

Transformers는 QLoRA, GPTQ, LLM.int8, AWQ 등 다양한 양자화 방법을 지원합니다. 그러나 아직 통합되지 않은 양자화 접근 방식이 여전히 많습니다. 이러한 양자화 방법을 Transformers에 추가하고 사용하는 것을 더 쉽게 하기 위해 HfQuantizer 클래스를 사용하세요. HfQuantizer는 모든 PyTorch 모듈에 적용되는 것이 아니라, 양자화 방법을 추가하기 위한 내부 헬퍼 클래스로 설계되었습니다.

이 가이드에서는 HfQuantizer에 새로운 양자화 방법을 통합하는 방법을 보여 드립니다.

요구 사항

Transformers에 새로운 양자화 방법을 통합하기 전에, 해당 방법이 다음 요구 사항을 충족하는지 확인하세요. PyTorch 모듈로 실행할 수 있는 양자화 방법만 지원됩니다.

  • 양자화 방법은 pip으로 설치할 수 있는 Python 패키지를 통해 사용할 수 있습니다(소스에서 패키지만 설치할 수 있는 경우에도 문제없습니다). 이상적으로는 pip 패키지에 사전 컴파일된 커널이 포함되어 있어야 합니다.

  • 이 메서드는 일반적으로 사용되는 하드웨어(CPU, GPU 등)에서 실행할 수 있습니다.

  • 해당 메서드는 nn.Module(~bitsandbytes.nn.Linear8bitLt, ~bitsandbytes.nn.Linear4bit)로 래핑되어 있으며, 양자화된 선형 레이어는 다음 정의가 있어야 합니다.

    class Linear4bit(nn.Module):
        def __init__(self, ...):
            ...
    
        def forward(self, x):
            return my_4bit_kernel(x, self.weight, self.bias)

    이 방식은 nn.Linear 인스턴스를 대상 클래스로 교체하여 Transformers 모델을 쉽게 양자화할 수 있게 합니다.

  • 양자화 방법은 직렬화 가능해야 합니다. 양자화된 가중치를 로컬에 저장하거나 Hub에 push할 수 있습니다.

  • 양자화 커널/프라이미티브를 포함하는 패키지가 안정적(빈번한 깨지는 변경 없음)인지 확인하세요.

일부 양자화 방법은 데이터 보정을 통해 모델을 “사전 양자화”해야 할 수 있습니다(AWQ). 이 경우, Transformers에서는 추론만 지원하고, 모델 양자화 자체는 ML 커뮤니티에서 유지 관리하는 서드파티 라이브러리에 맡기는 것을 권장합니다.

새로운 HFQuantizer 클래스 생성

  1. 가장 좋은 시작점은 Finegrained Fp8과 같은 다른 양자화 방법을 살펴보는 것입니다. 총 3개의 파일을 업데이트하거나 새로 만들어야 합니다: config 파일, integration 파일, quantizer 파일.

  2. src/transformers/utils/quantization_config.py 안에 새로운 quantization config 클래스를 생성합니다. Transformers의 src/transformers/__init__.py 파일 내부의 _import_structure에 새로운 quantization config를 추가합니다.

  3. quantizer_your_method.py이라는 이름의 새 파일을 src/transformers/quantizers/ 안에 생성하고, [`~quantizers.HfQuantizer`]를 상속하도록 하세요. src/transformers/quantizers/auto.py의 양자화 자동 매핑에 새 양자화기 및 양자화 구성을 추가했는지 확인하세요.

  4. quantization method에 대해 다음 클래스 속성과 프로퍼티 메서드를 정의하세요:

    • requires_calibration: 양자화 방식에 데이터 보정 과정이 필요한지 여부. True로 설정하면 양자화된 가중치를 사용한 추론만 지원되며, 추론과 양자화를 동시에 수행할 수 없습니다.
    • is_serializable: 해당 메서드가 직렬화 가능한지 여부를 결정하는 프로퍼티 메서드입니다.
    • is_trainable: 양자화 방식(PEFT 방식 사용 여부와 관계없이) 위에 모델을 fine-tune할 수 있는지 여부를 결정하는 property method입니다.
  5. validate_environment 및 update_dtype 메서드를 작성하세요. 이 메서드들은 양자화 모델 생성 전에 호출되어 사용자가 올바른 구성을 사용하는지 확인합니다. 구현 예시를 확인하려면 다른 양자화기를 참고하세요.

  6. _process_model_before_weight_loading 메서드를 작성합니다. Transformers에서는 가중치를 로드하기 전에 양자화된 모델이 먼저 "meta" 디바이스에서 초기화됩니다. 즉, _process_model_before_weight_loading 메서드는 모델 스켈레톤을 조작하여 일부 모듈(nn.Linear)을 대상 모듈(양자화 모듈)로 교체하는 역할을 담당합니다.

transformers/src/integrations/ 폴더에 새 파일을 생성하고 해당 폴더의 __init__.py 파일에서 관련 메서드를 노출하여 모듈 교체 로직이나 기타 유틸리티 메서드를 정의할 수 있습니다.

  1. 양자화가 온더플라이 양자화를 지원하는 경우, 양자화기 클래스에 get_quantize_ops 메서드를 추가합니다. Transformers에서는 각 텐서를 물리적으로 생성한 후 일련의 다양한 연산을 적용합니다. 이 경우 양자화 연산은 마지막에 수행됩니다. ConversionOps의 하위 클래스인 XXXQuantize를 생성하고 convert 메서드를 추가해야 합니다. convert 메서드에서는 가중치를 양자화하고 양자화된 매개변수의 딕셔너리를 반환해야 합니다.

  2. 양자화가 사전 양자화 가중치 로딩을 지원하는 경우, 양자화기 클래스에 get_weight_conversions 메서드를 추가합니다. transformers에서는 여러 텐서를 수집하고 그 위에 연산을 적용할 수 있습니다. 이는 체크포인트에 있는 텐서를 다시 그룹화하여 양자화 텐서를 재구성해야 하는 경우에 특히 유용합니다.

  3. 필요한 경우 _process_model_after_weight_loading 메서드를 작성하세요. 이 메서드는 가중치를 로드한 후 모델을 조작해야 하는 추가 기능을 구현할 수 있게 합니다.

  4. 모든 것을 문서화하세요! docs/source/en/quantization 아래에 새 파일을 추가하여 양자화 방법이 문서화되었는지 확인하세요.

  5. docker/transformers-quantization-latest-gpu 안의 nightly Dockerfile에 패키지를 추가하고, tests/quantization/xxx에 새로운 테스트 파일을 추가하여 테스트를 추가해야 합니다. 구현 방식을 확인하려면 기존 양자화 메서드를 참고해 보세요.

파일 개요

파일목적
utils/quantization_config.pyQuantizationConfigMixin을 상속받는 YourMethodConfig를 정의합니다
quantizers/quantizer_your_method.pyHfQuantizer를 상속받아 YourMethodHfQuantizer를 구현합니다
integrations/your_method.pyConversionOps 하위 클래스 및 헬퍼 함수 구현
quantizers/auto.pyAUTO_QUANTIZER_MAPPING과 AUTO_QUANTIZATION_CONFIG_MAPPING에 quantizer와 config를 등록합니다
docs/source/en/quantization/your_method.md사용자를 위한 문서 사용
tests/quantization/your_method/통합 테스트 추가

get_quantize_ops와 get_weight_conversions 이해하기

이 두 메서드는 가중치 로딩을 위한 서로 다른 시나리오를 처리합니다. 각각을 언제 사용해야 하는지 이해하는 것이 필수적입니다.

get_quantize_ops — 실시간 양자화

양자화되지 않은 체크포인트(예: float16/bfloat16 가중치)를 로드하면서 로드 중에 양자화를 수행할 때 이 방법을 사용합니다.

Checkpoint: model.safetensors (float16 weights for example)
     ↓
get_quantize_ops → YourQuantize.convert()
     ↓
Result: Quantized weights in memory

convert 메서드는 한 번에 하나의 텐서를 받아서 양자화하고, 양자화된 매개변수의 사전(dict)을 반환할 수 있습니다. 예를 들어:

class YourQuantize(ConversionOps):
    def convert(self, input_dict, model, full_layer_name, missing_keys, **kwargs):
        # input_dict = {"layer.weight": <float16 tensor>}
        value = list(input_dict.values())[0]
        module, tensor_name = get_module_from_name(model, full_layer_name)

        # Quantize and assign
        quantized, scale, zero_point = your_quantize_fn(value)
        return {full_layer_name: quantized, full_layer_name + ".scale": scale, full_layer_name + ".zero_point": zero_point}

get_weight_conversions — 사전 양자화된 체크포인트 로드

양자화된 가중치가 여러 개의 개별 구성 요소(예: data, scale, zero point)로 저장되어 있고, 로딩 시 이를 하나의 텐서로 결합해야 하는 사전 양자화 체크포인트를 로드할 때 이 기능을 사용합니다. 모든 양자화 방식이 이 재구성 단계를 요구하지는 않습니다. 예를 들어 FP8과 같은 일부 방식은 가중치와 스케일을 그대로 로드할 뿐 결합하지 않습니다. 반면 torchao와 같은 방식은 저장된 여러 구성 요소로부터 양자화 텐서를 다시 조립해야 합니다.

Checkpoint: model.safetensors (quantized components)
  - layer._weight_qdata
  - layer._weight_scale
  - layer._weight_zero_point
     ↓
get_weight_conversions → WeightConverter + YourDeserialize.convert()
     ↓
Result: Reconstructed quantized tensor → layer.weight

WeightConverter는 source_patterns에 따라 관련 텐서를 수집한 후, 이를 사용자의 convert 메서드로 전달합니다:

def get_weight_conversions(self):
    if self.pre_quantized:
        return [
            WeightConverter(
                source_patterns=["_weight_qdata", "_weight_scale", "_weight_zero_point"],
                target_patterns="weight",
                operations=[YourDeserialize(self)],
            ),
        ]
    return []


class YourDeserialize(ConversionOps):
    def convert(self, input_dict, model, full_layer_name, **kwargs):
        # input_dict contains all collected tensors
        # Reconstruct the quantized tensor from components
        reconstructed_tensor = reconstruct_from_components(input_dict)
        return {full_layer_name: reconstructed_tensor}
Update on GitHub