Transformers documentation

Các chiến lược sinh

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

Các chiến lược sinh

Chiến lược giải mã quyết định cách một mô hình chọn token tiếp theo để tạo ra. Có nhiều loại chiến lược giải mã khác nhau, và việc lựa chọn chiến lược phù hợp có tác động đáng kể đến chất lượng của văn bản được tạo ra.

Hướng dẫn này sẽ giúp bạn hiểu các chiến lược giải mã khác nhau có sẵn trong Transformers cũng như cách và thời điểm sử dụng chúng.

Các phương pháp giải mã cơ bản

Đây là các phương pháp giải mã đã được thiết lập vững chắc và nên là điểm khởi đầu của bạn cho các tác vụ tạo văn bản.

Tìm kiếm tham lam

Tìm kiếm tham lam là chiến lược giải mã mặc định. Chiến lược này chọn token có khả năng cao nhất ở mỗi bước. Trừ khi được chỉ định trong GenerationConfig, chiến lược này sẽ tạo ra tối đa 20 token mới.

Greedy search hoạt động tốt cho các tác vụ có đầu ra tương đối ngắn, nơi tính sáng tạo không phải là ưu tiên. Tuy nhiên, phương pháp này gặp sự cố khi tạo ra các chuỗi dài hơn vì nó bắt đầu lặp lại chính mình.

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from accelerate import Accelerator

device = Accelerator().device

tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt").to(device)

model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf", dtype=torch.float16).to(device)
# explicitly set to default length because Llama2 generation length is 4096
outputs = model.generate(**inputs, max_new_tokens=20)
tokenizer.batch_decode(outputs, skip_special_tokens=True)
'Hugging Face is an open-source company that provides a suite of tools and services for building, deploying, and maintaining natural language processing'

Mẫu

Sampling, hay còn gọi là lấy mẫu đa thức (multinomial sampling), chọn ngẫu nhiên một token dựa trên phân phối xác suất trên toàn bộ từ vựng của mô hình (khác với token có khả năng cao nhất, như trong tìm kiếm tham lam). Điều này có nghĩa là mọi token có xác suất khác không đều có cơ hội được chọn. Các chiến lược sampling giúp giảm sự lặp lại và có thể tạo ra các đầu ra sáng tạo và đa dạng hơn.

Bật lấy mẫu đa thức với do_sample=True và num_beams=1.

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from accelerate import Accelerator

device = Accelerator().device

tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt").to(device)

model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf", dtype=torch.float16).to(device)
# explicitly set to 100 because Llama2 generation length is 4096
outputs = model.generate(**inputs, max_new_tokens=50, do_sample=True, num_beams=1)
tokenizer.batch_decode(outputs, skip_special_tokens=True)
'Hugging Face is an open-source company 🤗\nWe are open-source and believe that open-source is the best way to build technology. Our mission is to make AI accessible to everyone, and we believe that open-source is the best way to achieve that.'

Tìm kiếm chùm

Beam search theo dõi một số chuỗi được tạo ra (các beam) tại mỗi bước thời gian. Sau một số bước nhất định, nó chọn chuỗi có xác suất tổng thể cao nhất. Khác với tìm kiếm tham lam, chiến lược này có thể “nhìn trước” và chọn một chuỗi có xác suất tổng thể cao hơn ngay cả khi các token ban đầu có xác suất thấp hơn. Phương pháp này phù hợp nhất cho các tác vụ dựa trên đầu vào, như mô tả một hình ảnh hoặc nhận dạng giọng nói. Bạn cũng có thể sử dụng do_sample=True cùng với beam search để lấy mẫu tại mỗi bước, nhưng beam search vẫn sẽ cắt bỏ các chuỗi có xác suất thấp giữa các bước theo cách tham lam.

Hãy xem trình trực quan hóa beam search để tìm hiểu cách beam search hoạt động.

Bật beam search bằng tham số num_beams (phải lớn hơn 1, nếu không sẽ tương đương với tìm kiếm tham lam).

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from accelerate import Accelerator

device = Accelerator().device

tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-2-7b-hf")
inputs = tokenizer("Hugging Face is an open-source company", return_tensors="pt").to(device)

model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf", dtype=torch.float16).to(device)
# explicitly set to 100 because Llama2 generation length is 4096
outputs = model.generate(**inputs, max_new_tokens=50, num_beams=2)
tokenizer.batch_decode(outputs, skip_special_tokens=True)
"['Hugging Face is an open-source company that develops and maintains the Hugging Face platform, which is a collection of tools and libraries for building and deploying natural language processing (NLP) models. Hugging Face was founded in 2018 by Thomas Wolf']"

Các phương pháp sinh tùy chỉnh

Các phương pháp sinh tùy chỉnh cho phép các hành vi chuyên biệt như:

  • cho phép mô hình tiếp tục suy nghĩ nếu nó không chắc chắn;
  • hoàn tác quá trình tạo nếu mô hình bị mắc kẹt;
  • xử lý các token đặc biệt bằng logic tùy chỉnh;
  • sử dụng bộ nhớ đệm KV chuyên dụng;

Chúng tôi cho phép các phương pháp sinh tùy chỉnh thông qua các kho lưu trữ mô hình, với giả định về một thẻ mô hình cụ thể và cấu trúc tệp (xem tiểu mục bên dưới). Tính năng này là sự mở rộng của mã mô hình tùy chỉnh và, tương tự như vậy, yêu cầu thiết lập trust_remote_code=True.

Nếu một kho lưu trữ mô hình chứa phương pháp sinh tùy chỉnh, cách dễ nhất để thử nghiệm là tải mô hình và sinh bằng nó:

from transformers import AutoModelForCausalLM, AutoTokenizer

# `transformers-community/custom_generate_example` holds a copy of `Qwen/Qwen2.5-0.5B-Instruct`, but
# with custom generation code -> calling `generate` uses the custom generation method!
tokenizer = AutoTokenizer.from_pretrained("transformers-community/custom_generate_example")
model = AutoModelForCausalLM.from_pretrained(
    "transformers-community/custom_generate_example", device_map="auto", trust_remote_code=True
)

inputs = tokenizer(["The quick brown"], return_tensors="pt").to(model.device)
# The custom generation method is a minimal greedy decoding implementation. It also prints a custom message at run time.
gen_out = model.generate(**inputs)
# you should now see its custom message, "✨ using a custom generation method ✨"
print(tokenizer.batch_decode(gen_out, skip_special_tokens=True))
'The quick brown fox jumps over a lazy dog, and the dog is a type of animal. Is'

Các kho lưu trữ model có phương pháp sinh tùy chỉnh có một thuộc tính đặc biệt: phương pháp sinh của chúng có thể được nạp từ bất kỳ model nào thông qua đối số custom_generate của generate(). Điều này có nghĩa là bất kỳ ai cũng có thể tạo và chia sẻ phương pháp sinh tùy chỉnh của mình để có thể hoạt động với bất kỳ model Transformers nào, mà không yêu cầu người dùng cài đặt các gói Python bổ sung.

from transformers import AutoModelForCausalLM, AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen2.5-0.5B-Instruct")
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2.5-0.5B-Instruct", device_map="auto")

inputs = tokenizer(["The quick brown"], return_tensors="pt").to(model.device)
# `custom_generate` replaces the original `generate` by the custom generation method defined in
# `transformers-community/custom_generate_example`
gen_out = model.generate(**inputs, custom_generate="transformers-community/custom_generate_example", trust_remote_code=True)
print(tokenizer.batch_decode(gen_out, skip_special_tokens=True)[0])
'The quick brown fox jumps over a lazy dog, and the dog is a type of animal. Is'

Bạn nên đọc tệp README.md của kho chứa chiến lược sinh tùy chỉnh để xem các đối số mới và sự khác biệt về kiểu đầu ra là gì, nếu có. Nếu không, bạn có thể giả định rằng nó hoạt động giống như phương thức generate() cơ bản.

Bạn có thể tìm tất cả các phương pháp sinh tùy chỉnh bằng cách tìm kiếm thẻ tùy chỉnh của chúng., custom_generate.

Hãy xem kho Hub transformers-community/custom_generate_example làm ví dụ. README.md nêu rõ rằng nó có một đối số đầu vào bổ sung, left_padding, thêm một số token đệm trước prompt.

gen_out = model.generate(
    **inputs, custom_generate="transformers-community/custom_generate_example", trust_remote_code=True, left_padding=5
)
print(tokenizer.batch_decode(gen_out)[0])
'<|endoftext|><|endoftext|><|endoftext|><|endoftext|><|endoftext|>The quick brown fox jumps over the lazy dog.\n\nThe sentence "The quick'

Nếu phương pháp tùy chỉnh có các yêu cầu Python cố định mà môi trường của bạn không đáp ứng, bạn sẽ nhận được ngoại lệ về các yêu cầu bị thiếu. Ví dụ, transformers-community/custom_generate_bad_requirements có một tập hợp các yêu cầu không thể thực hiện được, được định nghĩa trong tệp custom_generate/requirements.txt của nó, và bạn sẽ thấy thông báo lỗi bên dưới nếu cố gắng chạy nó.

ImportError: Missing requirements in your local environment for `transformers-community/custom_generate_bad_requirements`:
foo (installed: None)
bar==0.0.0 (installed: None)
torch>=99.0 (installed: 2.6.0)

Việc cập nhật các yêu cầu Python của bạn cho phù hợp sẽ loại bỏ thông báo lỗi này.

Tạo phương pháp sinh tùy chỉnh

Để tạo một phương pháp sinh mới, bạn cần tạo một kho Model mới và đẩy một vài tệp vào đó.

  1. Mô hình mà bạn đã thiết kế phương pháp sinh của mình dựa trên.
  2. custom_generate/generate.py, chứa toàn bộ logic cho phương pháp sinh tùy chỉnh của bạn.
  3. custom_generate/requirements.txt, được dùng để tùy chọn thêm các yêu cầu Python mới và/hoặc khóa các phiên bản cụ thể để sử dụng đúng phương pháp của bạn.
  4. README.md, nơi bạn nên thêm thẻ custom_generate và tài liệu hóa các đối số mới hoặc sự khác biệt về kiểu đầu ra của phương pháp tùy chỉnh của bạn tại đây.

Sau khi bạn đã thêm tất cả các tệp bắt buộc, kho lưu trữ của bạn nên trông như sau

your_repo/
├── README.md          # include the 'custom_generate' tag
├── config.json
├── ...
└── custom_generate/
    ├── generate.py
    └── requirements.txt

Thêm mô hình cơ sở

Điểm khởi đầu cho phương pháp sinh tùy chỉnh của bạn là một kho lưu trữ mô hình giống như bất kỳ kho nào khác. Mô hình cần thêm vào kho này phải là mô hình mà bạn đã thiết kế phương pháp của mình dựa trên, và nó được dự định là một phần của cặp mô hình-sinh tự chứa và hoạt động được. Khi mô hình trong kho này được nạp, phương pháp sinh tùy chỉnh của bạn sẽ ghi đè lên generate. Đừng lo — phương pháp sinh của bạn vẫn có thể được nạp với bất kỳ mô hình Transformers nào khác, như đã giải thích trong phần ở trên.

Nếu bạn chỉ muốn sao chép một mô hình hiện có, bạn có thể

from transformers import AutoModelForCausalLM, AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("source/model_repo")
model = AutoModelForCausalLM.from_pretrained("source/model_repo")
tokenizer.save_pretrained("your/generation_method", push_to_hub=True)
model.save_pretrained("your/generation_method", push_to_hub=True)

generate.py

Đây là phần cốt lõi của phương pháp sinh của bạn. Nó phải chứa một phương pháp có tên là generate, và phương pháp này phải chứa đối số model làm đối số đầu tiên. model là instance của model, điều này có nghĩa là bạn có quyền truy cập vào tất cả các thuộc tính và phương pháp trong model, bao gồm cả những cái được định nghĩa trong GenerationMixin (như phương pháp generate cơ bản).

generate.py phải được đặt trong một thư mục có tên là custom_generate, không được đặt ở cấp gốc của kho. Các đường dẫn tệp cho tính năng này được hardcode.

Bên trong, khi phương thức generate() cơ bản được gọi với đối số custom_generate, nó trước tiên kiểm tra các yêu cầu Python (nếu có), sau đó tìm phương thức generate tùy chỉnh trong generate.py, và cuối cùng gọi generate tùy chỉnh. Tất cả các đối số nhận được và model được chuyển tiếp đến phương thức generate tùy chỉnh của bạn, ngoại trừ các đối số được dùng để kích hoạt sinh tùy chỉnh (trust_remote_code và custom_generate).

Điều này có nghĩa là generate của bạn có thể chứa một hỗn hợp các đối số gốc và tùy chỉnh (cũng như một kiểu đầu ra khác) như được minh họa bên dưới.

import torch

def generate(model, input_ids, generation_config=None, left_padding=None, **kwargs):
    generation_config = generation_config or model.generation_config  # default to the model generation config
    cur_length = input_ids.shape[1]
    max_length = generation_config.max_length or cur_length + generation_config.max_new_tokens

    # Example of custom argument: add `left_padding` (integer) pad tokens before the prompt
    if left_padding is not None:
        if not isinstance(left_padding, int) or left_padding < 0:
            raise ValueError(f"left_padding must be an integer larger than 0, but is {left_padding}")

        pad_token = kwargs.pop("pad_token", None) or generation_config.pad_token_id or model.config.pad_token_id
        if pad_token is None:
            raise ValueError("pad_token is not defined")
        batch_size = input_ids.shape[0]
        pad_tensor = torch.full(size=(batch_size, left_padding), fill_value=pad_token).to(input_ids.device)
        input_ids = torch.cat((pad_tensor, input_ids), dim=1)
        cur_length = input_ids.shape[1]

    # Simple greedy decoding loop
    while cur_length < max_length:
        logits = model(input_ids).logits
        next_token_logits = logits[:, -1, :]
        next_tokens = torch.argmax(next_token_logits, dim=-1)
        input_ids = torch.cat((input_ids, next_tokens[:, None]), dim=-1)
        cur_length += 1

    return input_ids

Tuân theo các thực hành được khuyến nghị bên dưới để đảm bảo phương pháp tạo tùy chỉnh của bạn hoạt động như mong đợi.

  • Hãy tự do tái sử dụng logic cho việc xác thực và chuẩn bị đầu vào trong generate() gốc.
  • Hãy cố định phiên bản transformers trong yêu cầu nếu bạn sử dụng bất kỳ phương thức/thuộc tính riêng tư nào trong model.
  • Hãy cân nhắc thêm xác thực mô hình, xác thực đầu vào, hoặc thậm chí một tệp kiểm thử riêng để giúp người dùng kiểm tra tính hợp lý của mã của bạn trong môi trường của họ.

Phương thức generate tùy chỉnh của bạn có thể import tương đối mã từ thư mục custom_generate. Ví dụ, nếu bạn có tệp utils.py, bạn có thể import nó như sau:

from .utils import some_function

Chỉ hỗ trợ import tương đối từ thư mục custom_generate cùng cấp. Import từ thư mục cha/anh chị em không hợp lệ. Tham số custom_generate cũng hoạt động cục bộ với bất kỳ thư mục nào chứa cấu trúc custom_generate, đây là quy trình làm việc được khuyến nghị để phát triển phương pháp sinh tùy chỉnh của bạn.

gen_out = model.generate(**inputs, custom_generate="path/to/local/dir", trust_remote_code=True)

Việc tải một thư mục cục bộ vẫn thực thi custom_generate/generate.py của nó, do đó cần trust_remote_code=True giống như một kho Hub. Chỉ truyền trust_remote_code=True cho mã do bạn viết hoặc đã xem xét.

requirements.txt

Bạn có thể tùy chọn chỉ định các yêu cầu Python bổ sung trong tệp requirements.txt bên trong thư mục custom_generate. Các yêu cầu này được kiểm tra khi chạy và một ngoại lệ sẽ được ném ra nếu chúng bị thiếu, nhắc người dùng cập nhật môi trường của họ cho phù hợp.

README.md

File README.md ở cấp độ gốc trong kho lưu trữ mô hình thường mô tả mô hình bên trong đó. Tuy nhiên, vì trọng tâm của kho lưu trữ là phương pháp sinh tùy chỉnh, chúng tôi rất khuyến nghị chuyển trọng tâm sang việc mô tả phương pháp sinh tùy chỉnh. Ngoài phần mô tả phương pháp, chúng tôi khuyến nghị tài liệu hóa mọi khác biệt về đầu vào và/hoặc đầu so với generate() gốc. Bằng cách này, người dùng có thể tập trung vào những gì mới và dựa vào tài liệu của Transformers cho các chi tiết triển khai chung.

Để tăng khả năng tìm kiếm, chúng tôi rất khuyến khích bạn thêm thẻ custom_generate vào kho lưu trữ của mình. Để làm điều này, phần đầu tệp README.md của bạn nên giống như ví dụ bên dưới. Sau khi bạn đẩy tệp lên, bạn sẽ thấy thẻ trong kho lưu trữ của mình!

---
library_name: transformers
tags:
  - custom_generate
---

(your markdown content here)

Các thực hành được khuyến nghị:

  • Tài liệu hóa các khác biệt về đầu vào và đầu ra trong generate().
  • Thêm các ví dụ tự chứa để cho phép thử nghiệm nhanh chóng.
  • Mô tả các yêu cầu mềm, chẳng hạn như phương pháp chỉ hoạt động tốt với một họ mô hình nhất định.

Tái sử dụng việc chuẩn bị đầu vào của generate

Nếu bạn đang thêm một vòng lặp giải mã mới, bạn có thể muốn giữ lại các bước chuẩn bị đầu vào có sẵn trong generate (mở rộng batch, attention masks, logits processors, tiêu chí dừng, v.v.). Bạn cũng có thể truyền một callable vào custom_generate để tái sử dụng toàn bộ pipeline chuẩn bị của generate() trong khi chỉ ghi đè lên vòng lặp giải mã.

def custom_loop(model, input_ids, attention_mask, logits_processor, stopping_criteria, generation_config, **model_kwargs):
    next_tokens = input_ids
    while input_ids.shape[1] < stopping_criteria[0].max_length:
        logits = model(next_tokens, attention_mask=attention_mask, **model_kwargs).logits
        next_token_logits = logits_processor(input_ids, logits[:, -1, :])
        next_tokens = torch.argmax(next_token_logits, dim=-1)[:, None]
        input_ids = torch.cat((input_ids, next_tokens), dim=-1)
        attention_mask = torch.cat((attention_mask, torch.ones_like(next_tokens)), dim=-1)
    return input_ids

output = model.generate(
    **inputs,
    custom_generate=custom_loop,
    max_new_tokens=10,
)

Nếu bạn phát hành một kho lưu trữ custom_generate, phần triển khai generate của bạn có thể tự định nghĩa một hàm callable và truyền nó vào model.generate(). Điều này cho phép bạn tùy chỉnh vòng lặp giải mã trong khi vẫn tận dụng được logic chuẩn bị đầu vào có sẵn của Transformers.

Tìm các phương pháp sinh tùy chỉnh

Bạn có thể tìm tất cả các phương thức sinh tùy chỉnh bằng cách tìm kiếm thẻ tùy chỉnh của chúng., custom_generate. Ngoài thẻ, chúng tôi tuyển chọn hai bộ sưu tập các phương thức custom_generate:

Tài nguyên

Đọc bài đăng trên blog Cách tạo văn bản: sử dụng các phương pháp giải mã khác nhau cho việc tạo ngôn ngữ với Transformers để tìm hiểu cách các chiến lược giải mã phổ biến hoạt động.

Update on GitHub