Transformers documentation

Đóng góp

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

and get access to the augmented documentation experience

to get started

Đóng góp

Transformers hỗ trợ nhiều phương pháp lượng tử hóa như QLoRA, GPTQ, LLM.int8 và AWQ. Tuy nhiên, vẫn còn nhiều cách tiếp cận lượng tử hóa khác chưa được tích hợp. Để việc thêm và sử dụng các phương pháp lượng tử hóa này với Transformers trở nên dễ dàng hơn, hãy sử dụng lớp HfQuantizer. HfQuantizer được thiết kế như một lớp trợ giúp nội bộ để thêm một phương pháp lượng tử hóa, thay vì là thứ được áp dụng cho mọi module PyTorch.

Hướng dẫn này sẽ cho bạn thấy cách tích hợp một phương pháp lượng tử hóa mới với HfQuantizer.

Yêu cầu

Trước khi tích hợp một phương pháp lượng tử hóa mới vào Transformers, hãy đảm bảo phương pháp đó đáp ứng các yêu cầu sau. Chỉ các phương pháp lượng tử hóa có thể chạy với các module PyTorch mới được hỗ trợ.

  • Phương pháp lượng tử hóa có sẵn thông qua một gói Python có thể cài đặt bằng pip (việc chỉ có thể cài đặt gói từ mã nguồn cũng hoàn toàn ổn). Về lý tưởng, các kernel đã biên dịch sẵn được bao gồm trong gói pip.

  • Phương pháp này có thể chạy trên phần cứng phổ biến (CPU, GPU, v.v.).

  • Phương thức được bọc trong một nn.Module (~bitsandbytes.nn.Linear8bitLt, ~bitsandbytes.nn.Linear4bit), và lớp tuyến tính đã lượng tử hóa nên có định nghĩa như sau.

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

    Nhờ đó, các mô hình Transformers có thể được lượng tử hóa một cách dễ dàng bằng cách thay thế các thể hiện của nn.Linear bằng một lớp đích.

  • Phương pháp lượng tử hóa phải có thể được phân chuỗi. Bạn có thể lưu các trọng số đã lượng tử hóa cục bộ hoặc đẩy chúng lên Hub.

  • Hãy đảm bảo rằng gói chứa các kernel/primitive lượng tử hóa ổn định (không có thay đổi gây lỗi thường xuyên).

Một số phương pháp lượng tử hóa có thể yêu cầu “tiền lượng tử hóa” mô hình thông qua hiệu chuẩn dữ liệu (AWQ). Trong trường hợp này, chúng tôi ưu tiên chỉ hỗ trợ suy luận trong Transformers và để thư viện bên thứ ba do cộng đồng ML duy trì tự xử lý việc lượng tử hóa mô hình.

Tạo lớp HFQuantizer mới

  1. Điểm khởi đầu tốt nhất là xem xét một phương pháp lượng tử hóa khác, chẳng hạn như Finegrained Fp8. Bạn sẽ phải cập nhật hoặc tạo tổng cộng ba tệp: tệp cấu hình, tệp tích hợp và tệp bộ lượng tử hóa.

  2. Tạo một lớp cấu hình lượng tử hóa mới bên trong src/transformers/utils/quantization_config.py. Thêm cấu hình lượng tử hóa mới vào _import_structure bên trong tệp src/transformers/__init__.py của Transformers.

  3. Tạo một tệp mới bên trong src/transformers/quantizers/ có tên là quantizer_your_method.py, và cho nó kế thừa từ [`~quantizers.HfQuantizer`]. Hãy đảm bảo thêm quantizer mới và cấu hình lượng tử hóa vào bản ánh xạ tự động cho lượng tử hóa trong src/transformers/quantizers/auto.py.

  4. Định nghĩa các thuộc tính lớp và phương thức thuộc tính sau cho phương pháp lượng tử hóa của bạn:

    • requires_calibration: Xác định xem phương pháp lượng tử hóa có yêu cầu quy trình hiệu chuẩn dữ liệu hay không. Nếu đặt thành True, bạn chỉ có thể hỗ trợ suy luận (với trọng số đã lượng tử hóa) mà không thể thực hiện cả suy luận lẫn lượng tử hóa.
    • is_serializable: Một phương thức thuộc tính để xác định xem phương thức có thể được phân chuỗi (serializable) hay không.
    • is_trainable: Một phương thức thuộc tính để xác định xem bạn có thể tinh chỉnh (fine-tune) các mô hình trên phương pháp lượng tử hóa (có hoặc không có các phương pháp PEFT) hay không.
  5. Viết các phương thức validate_environment và update_dtype. Các phương thức này được gọi trước khi tạo mô hình lượng tử hóa để đảm bảo người dùng sử dụng cấu hình đúng. Tham khảo các bộ lượng tử hóa khác để xem cách chúng được triển khai.

  6. Viết phương thức _process_model_before_weight_loading. Trong Transformers, các mô hình lượng tử hóa được khởi tạo trước trên thiết bị "meta" trước khi tải trọng số. Điều này có nghĩa là phương thức _process_model_before_weight_loading chịu trách nhiệm thao tác trên khung mô hình để thay thế một số module (nn.Linear) bằng các module đích (các module lượng tử hóa).

Bạn có thể định nghĩa logic thay thế module hoặc bất kỳ phương tiện tiện ích nào khác bằng cách tạo một tệp mới trong transformers/src/integrations/ và phơi bày các phương thức liên quan trong tệp __init__.py của thư mục đó.

  1. Thêm phương thức get_quantize_ops vào lớp quantizer nếu phép lượng tử hóa hỗ trợ lượng tử hóa trực tiếp. Trong transformers, chúng ta vật chất hóa từng tensor và áp dụng một chuỗi các thao tác khác nhau lên nó. Trong trường hợp của chúng ta, thao tác lượng tử hóa diễn ra ở cuối. Bạn cần tạo một XXXQuantize, một lớp con của ConversionOps, và thêm một phương thức convert. Trong phương thức convert, bạn cần lượng tử hóa các trọng số và trả về một từ điển chứa các tham số đã được lượng tử hóa.

  2. Thêm phương thức get_weight_conversions vào lớp quantizer nếu quá trình lượng tử hóa hỗ trợ nạp trọng số đã được lượng tử hóa trước. Trong transformers, chúng ta có thể thu thập nhiều tensor và áp dụng các thao tác lên chúng. Điều này đặc biệt hữu ích khi chúng ta có các tensor trong checkpoint cần được nhóm lại để tái tạo các tensor đã lượng tử hóa.

  3. Viết phương thức _process_model_after_weight_loading nếu cần. Phương thức này cho phép triển khai các tính năng bổ sung yêu cầu thao tác trên mô hình sau khi tải trọng số.

  4. Tài liệu hóa mọi thứ! Đảm bảo phương pháp lượng tử hóa của bạn được tài liệu hóa bằng cách thêm một tệp mới dưới docs/source/en/quantization.

  5. Bạn nên thêm các bài kiểm thử bằng cách thêm gói vào Dockerfile chạy hàng đêm của chúng tôi trong docker/transformers-quantization-latest-gpu và sau đó thêm một tệp kiểm thử mới trong tests/quantization/xxx. Bạn có thể xem các phương pháp lượng tử hóa hiện có để biết cách triển khai.

Tổng quan về các tệp

FileMục đích
utils/quantization_config.pyĐịnh nghĩa YourMethodConfig kế thừa từ QuantizationConfigMixin
quantizers/quantizer_your_method.pyThực hiện YourMethodHfQuantizer kế thừa từ HfQuantizer
integrations/your_method.pyThực hiện các lớp con của ConversionOps và các hàm hỗ trợ
quantizers/auto.pyĐăng ký quantizer và config trong AUTO_QUANTIZER_MAPPING và AUTO_QUANTIZATION_CONFIG_MAPPING
docs/source/en/quantization/your_method.mdTài liệu sử dụng cho người dùng
tests/quantization/your_method/Thêm các bài kiểm thử tích hợp

Hiểu về get_quantize_ops so với get_weight_conversions

Hai phương pháp này xử lý các kịch bản khác nhau khi nạp trọng số. Việc hiểu rõ khi nào nên sử dụng từng phương pháp là điều cần thiết.

get_quantize_ops — Lượng tử hóa theo thời gian thực

Sử dụng điều này khi tải một checkpoint không lượng tử hóa (ví dụ: trọng số float16/bfloat16) và lượng tử hóa trong quá trình tải.

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

Phương thức convert nhận một tensor mỗi lần, lượng tử hóa nó và có thể trả về một từ điển các tham số đã lượng tử hóa, ví dụ:

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 — Nạp các checkpoint đã lượng tử hóa trước

Sử dụng tùy chọn này khi nạp một checkpoint đã lượng tử hóa trước, trong đó các trọng số đã lượng tử hóa được lưu dưới dạng nhiều thành phần riêng biệt (chẳng hạn như data, scale và zero point), và các thành phần này cần được kết hợp thành một tensor duy nhất trong quá trình nạp. Không phải phương pháp lượng tử hóa nào cũng yêu cầu bước tái tạo này: ví dụ, một số phương pháp như FP8 chỉ đơn giản nạp trọng số và scale như chúng được lưu, mà không cần kết hợp chúng. Ngược lại, các phương pháp khác, chẳng hạn như torchao, lại yêu cầu lắp ráp lại tensor đã lượng tử hóa từ nhiều thành phần đã được lưu.

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 thu thập các tensor liên quan dựa trên source_patterns, sau đó truyền chúng đến phương thức convert của bạn:

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