# Tạo văn bản

Tạo văn bản là ứng dụng phổ biến nhất của các mô hình ngôn ngữ lớn (LLM). Một LLM được huấn luyện để tạo ra từ (token) tiếp theo dựa trên một số văn bản ban đầu (prompt) cùng với các đầu ra do chính nó tạo ra cho đến khi đạt độ dài định trước hoặc khi nó chạm đến token kết thúc chuỗi (`EOS`).

Trong Transformers, API [generate()](/docs/transformers/main/vi/main_classes/text_generation#transformers.GenerationMixin.generate) xử lý việc tạo văn bản và có sẵn cho tất cả các mô hình có khả năng sinh. Hướng dẫn này sẽ cho bạn thấy các cơ bản về tạo văn bản với [generate()](/docs/transformers/main/vi/main_classes/text_generation#transformers.GenerationMixin.generate) và một số bẫy phổ biến cần tránh.

> [!TIP]
> Đối với các lệnh sau, hãy đảm bảo rằng [`transformers serve` đang chạy](./serve-cli/serving).
>
> ```shell
> transformers chat Qwen/Qwen2.5-0.5B-Instruct
> ```

## Mặc định generate

Trước khi bắt đầu, việc cài đặt [bitsandbytes](https://hf.co/docs/bitsandbytes/index) sẽ giúp ích để lượng tử hóa các mô hình rất lớn nhằm giảm mức sử dụng bộ nhớ của chúng.

```bash
!pip install -U transformers bitsandbytes
```

Bitsandbytes hỗ trợ nhiều backend khác ngoài GPU dựa trên CUDA. Tham khảo [hướng dẫn](https://huggingface.co/docs/bitsandbytes/main/en/installation#multi-backend) cài đặt đa backend để biết thêm.

Tải một LLM bằng [from_pretrained()](/docs/transformers/main/vi/main_classes/model#transformers.PreTrainedModel.from_pretrained) và thêm hai tham số sau để giảm yêu cầu về bộ nhớ.

- `device_map="auto"` kích hoạt tính năng [Big Model Inference](./models#big-model-inference) của Accelerate để tự động khởi tạo khung mô hình và nạp, phân phối trọng số mô hình trên tất cả các thiết bị khả dụng, bắt đầu từ thiết bị nhanh nhất (GPU).
- `quantization_config` là một đối tượng cấu hình xác định các cài đặt lượng tử hóa. Ví dụ này sử dụng bitsandbytes làm backend lượng tử hóa (xem phần [Lượng tử hóa](./quantization/overview) để biết thêm các backend khả dụng) và tải mô hình ở [4-bit](./quantization/bitsandbytes).

```py
from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig

quantization_config = BitsAndBytesConfig(load_in_4bit=True)
model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1", device_map="auto", quantization_config=quantization_config)
```

Thực hiện tokenize đầu vào của bạn và đặt tham số `padding_side()` thành `"left"` vì LLM không được huấn luyện để tiếp tục sinh từ các token padding. Tokenizer sẽ trả về các input ids và attention mask.

> [!TIP]
> Xử lý nhiều hơn một prompt cùng lúc bằng cách truyền một danh sách các chuỗi vào tokenizer. Gom các đầu vào thành batch để cải thiện thông lượng với chi phí nhỏ về độ trễ và bộ nhớ.

```py
tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1", padding_side="left")
model_inputs = tokenizer(["A list of colors: red, blue"], return_tensors="pt").to(model.device)
```

Truyền các đầu vào vào [generate()](/docs/transformers/main/vi/main_classes/text_generation#transformers.GenerationMixin.generate) để tạo ra các token, sau đó dùng [batch_decode()](/docs/transformers/main/vi/internal/tokenization_utils#transformers.PreTrainedTokenizerBase.batch_decode) để chuyển các token đã tạo thành văn bản.

```py
generated_ids = model.generate(**model_inputs)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
"A list of colors: red, blue, green, yellow, orange, purple, pink,"
```

## Cấu hình tạo

Tất cả các cài đặt sinh đều được chứa trong [GenerationConfig](/docs/transformers/main/vi/main_classes/text_generation#transformers.GenerationConfig). Trong ví dụ trên, các cài đặt sinh được suy ra từ tệp `generation_config.json` của [mistralai/Mistral-7B-v0.1](https://huggingface.co/mistralai/Mistral-7B-v0.1). Một chiến lược giải mã mặc định sẽ được sử dụng khi không có cấu hình nào được lưu cùng với mô hình.

Kiểm tra cấu hình thông qua thuộc tính `generation_config`. Nó chỉ hiển thị các giá trị khác với cấu hình mặc định, trong trường hợp này là `bos_token_id` và `eos_token_id`.

```py
from transformers import AutoModelForCausalLM

model = AutoModelForCausalLM.from_pretrained("mistralai/Mistral-7B-v0.1", device_map="auto")
model.generation_config
GenerationConfig {
  "bos_token_id": 1,
  "eos_token_id": 2
}
```

Bạn có thể tùy chỉnh [generate()](/docs/transformers/main/vi/main_classes/text_generation#transformers.GenerationMixin.generate) bằng cách ghi đè các tham số và giá trị trong [GenerationConfig](/docs/transformers/main/vi/main_classes/text_generation#transformers.GenerationConfig). Xem [mục này bên dưới](#common-options) để biết các tham số thường được điều chỉnh.

```py
# enable beam search sampling strategy
model.generate(**inputs, num_beams=4, do_sample=True)
```

[generate()](/docs/transformers/main/vi/main_classes/text_generation#transformers.GenerationMixin.generate) cũng có thể được mở rộng bằng các thư viện bên ngoài hoặc mã tùy chỉnh:

1. tham số `logits_processor` chấp nhận các instance [LogitsProcessor](/docs/transformers/main/vi/internal/generation_utils#transformers.LogitsProcessor) tùy chỉnh để thao tác trên phân phối xác suất của token tiếp theo;
2. tham số `stopping_criteria` hỗ trợ [StoppingCriteria](/docs/transformers/main/vi/internal/generation_utils#transformers.StoppingCriteria) tùy chỉnh để dừng tạo văn bản;
3. các phương pháp sinh tùy chỉnh khác có thể được tải thông qua cờ `custom_generate` ([tài liệu](./generation_strategies#custom-generation-methods)).

Tham khảo hướng dẫn [Các chiến lược sinh](./generation_strategies) để tìm hiểu thêm về các chiến lược tìm kiếm, lấy mẫu và giải mã.

### Lưu

Tạo một instance của [GenerationConfig](/docs/transformers/main/vi/main_classes/text_generation#transformers.GenerationConfig) và chỉ định các tham số giải mã mà bạn muốn.

```py
from transformers import AutoModelForCausalLM, GenerationConfig

model = AutoModelForCausalLM.from_pretrained("my_account/my_model")
generation_config = GenerationConfig(
    max_new_tokens=50, do_sample=True, top_k=50, eos_token_id=model.config.eos_token_id
)
```

Sử dụng [save_pretrained()](/docs/transformers/main/vi/main_classes/text_generation#transformers.GenerationConfig.save_pretrained) để lưu một cấu hình sinh cụ thể và đặt tham số `push_to_hub` thành `True` để tải nó lên Hub.

```py
generation_config.save_pretrained("my_account/my_model", push_to_hub=True)
```

Để trống tham số `config_file_name`. Tham số này nên được sử dụng khi lưu trữ nhiều cấu hình sinh trong một thư mục duy nhất. Nó cho phép bạn chỉ định cấu hình sinh nào cần tải. Bạn có thể tạo các cấu hình khác nhau cho các tác vụ sinh khác nhau (sinh văn bản sáng tạo với sampling, tóm tắt với beam search) để sử dụng với một mô hình duy nhất.

```py
from transformers import AutoModelForSeq2SeqLM, AutoTokenizer, GenerationConfig

tokenizer = AutoTokenizer.from_pretrained("google-t5/t5-small")
model = AutoModelForSeq2SeqLM.from_pretrained("google-t5/t5-small")

translation_generation_config = GenerationConfig(
    num_beams=4,
    early_stopping=True,
    decoder_start_token_id=0,
    eos_token_id=model.config.eos_token_id,
    pad_token=model.config.pad_token_id,
)

translation_generation_config.save_pretrained("/tmp", config_file_name="translation_generation_config.json", push_to_hub=True)

generation_config = GenerationConfig.from_pretrained("/tmp", config_file_name="translation_generation_config.json")
inputs = tokenizer("translate English to French: Configuration files are easy to use!", return_tensors="pt")
outputs = model.generate(**inputs, generation_config=generation_config)
print(tokenizer.batch_decode(outputs, skip_special_tokens=True))
```

## Các tùy chọn phổ biến

[generate()](/docs/transformers/main/vi/main_classes/text_generation#transformers.GenerationMixin.generate) là một công cụ mạnh mẽ, có thể tùy chỉnh sâu. Điều này có thể gây khó khăn cho người dùng mới. Phần này chứa danh sách các tùy chọn sinh phổ biến mà bạn có thể định nghĩa trong hầu hết các công cụ sinh văn bản trong Transformers: [generate()](/docs/transformers/main/vi/main_classes/text_generation#transformers.GenerationMixin.generate), [GenerationConfig](/docs/transformers/main/vi/main_classes/text_generation#transformers.GenerationConfig), `pipelines`, CLI `chat`, ...

| Tên tùy chọn | Loại | Mô tả đơn giản |
|---|---|---|
| `max_new_tokens` | `int` | Kiểm soát độ dài tối đa của quá trình sinh. Hãy đảm bảo định nghĩa tham số này, vì mặc định nó thường có giá trị nhỏ. |
| `do_sample` | `bool` | Xác định xem quá trình sinh sẽ lấy mẫu token tiếp theo (`True`) hay thay vào đó là tham lam (`False`). Hầu hết các trường hợp sử dụng nên đặt cờ này thành `True`. Xem [hướng dẫn này](./generation_strategies) để biết thêm thông tin. |
| `temperature` | `float` | Mức độ khó dự đoán của token tiếp theo được chọn. Giá trị cao (`>0.8`) phù hợp cho các tác vụ sáng tạo, giá trị thấp (ví dụ `<0.4`) cho các tác vụ đòi hỏi "suy nghĩ". Yêu cầu `do_sample=True`. |
| `num_beams` | `int` | Khi được đặt thành `>1`, thuật toán beam search sẽ được kích hoạt. Beam search hoạt động tốt với các tác vụ dựa trên đầu vào. Xem [hướng dẫn này](./generation_strategies) để biết thêm thông tin. |
| `repetition_penalty` | `float` | Đặt giá trị này lớn hơn `>1.0` nếu bạn thấy mô hình lặp lại nội dung thường xuyên. Giá trị lớn hơn sẽ áp dụng mức phạt lớn hơn. |
| `eos_token_id` | `list[int]` | Token (các token) sẽ khiến quá trình sinh kết thúc. Giá trị mặc định thường là tốt, nhưng bạn có thể chỉ định một token khác. |

## Những bẫy

Phần bên dưới đề cập đến một số vấn đề phổ biến mà bạn có thể gặp phải trong quá trình tạo văn bản và cách giải quyết chúng.

### Độ dài đầu ra

[generate()](/docs/transformers/main/vi/main_classes/text_generation#transformers.GenerationMixin.generate) mặc định trả về tối đa 20 token trừ khi được chỉ định khác trong [GenerationConfig](/docs/transformers/main/vi/main_classes/text_generation#transformers.GenerationConfig) của model. Rất khuyến nghị đặt thủ công số lượng token được tạo bằng tham số `max_new_tokens` để kiểm soát độ dài đầu ra. Các model [Decoder-only](https://hf.co/learn/nlp-course/chapter1/6?fw=pt) trả về prompt ban đầu cùng với các token được tạo.

```py
model_inputs = tokenizer(["A sequence of numbers: 1, 2"], return_tensors="pt").to(model.device)
```

```py
generated_ids = model.generate(**model_inputs)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
'A sequence of numbers: 1, 2, 3, 4, 5'
```

```py
generated_ids = model.generate(**model_inputs, max_new_tokens=50)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
'A sequence of numbers: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,'
```

### Chiến lược giải mã

Chiến lược giải mã mặc định trong [generate()](/docs/transformers/main/vi/main_classes/text_generation#transformers.GenerationMixin.generate) là *greedy search*, chọn token có xác suất cao nhất tiếp theo, trừ khi được chỉ định khác trong [GenerationConfig](/docs/transformers/main/vi/main_classes/text_generation#transformers.GenerationConfig) của mô hình. Mặc dù chiến lược giải mã này hoạt động tốt cho các tác vụ dựa trên đầu vào (chuyển văn bản thành giọng nói, dịch thuật), nhưng nó không tối ưu cho các trường hợp sử dụng sáng tạo hơn (viết truyện, ứng dụng trò chuyện).

Ví dụ, hãy bật chiến lược [multinomial sampling](./generation_strategies#sampling) để tạo ra các đầu ra đa dạng hơn. Tham khảo hướng dẫn [Generation strategy](./generation_strategies) để biết thêm về các chiến lược giải mã.

```py
model_inputs = tokenizer(["I am a cat."], return_tensors="pt").to(model.device)
```

```py
generated_ids = model.generate(**model_inputs)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
```

```py
generated_ids = model.generate(**model_inputs, do_sample=True)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
```

### Bên đệm

Các đầu vào cần được đệm (padding) nếu chúng không có cùng độ dài. Tuy nhiên, các LLM không được huấn luyện để tiếp tục sinh nội dung từ các token đệm, điều này có nghĩa là tham số `padding_side()` cần được đặt ở phía bên trái của đầu vào. Việc đệm bên phải gây bất lợi hơn cho các mô hình không gian trạng thái và mô hình lai, vì trạng thái đệ quy của chúng liên tục cập nhật trên các token đệm ở cuối, khiến bộ nhớ đệm (cache) không còn khớp với phần cuối của prompt.

```py
model_inputs = tokenizer(
    ["1, 2, 3", "A, B, C, D, E"], padding=True, return_tensors="pt"
).to(model.device)
generated_ids = model.generate(**model_inputs)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
'1, 2, 33333333333'
```

```py
tokenizer = AutoTokenizer.from_pretrained("mistralai/Mistral-7B-v0.1", padding_side="left")
tokenizer.pad_token = tokenizer.eos_token
model_inputs = tokenizer(
    ["1, 2, 3", "A, B, C, D, E"], padding=True, return_tensors="pt"
).to(model.device)
generated_ids = model.generate(**model_inputs)
tokenizer.batch_decode(generated_ids, skip_special_tokens=True)[0]
'1, 2, 3, 4, 5, 6,'
```

### Định dạng prompt

Một số mô hình và tác vụ yêu cầu một định dạng prompt đầu vào nhất định, và nếu định dạng không chính xác, mô hình sẽ trả về kết quả đầu ra không tối ưu. Bạn có thể tìm hiểu thêm về việc tạo prompt trong hướng dẫn [kỹ thuật prompt](./tasks/prompting).

Ví dụ, một mô hình chat kỳ vọng đầu vào dưới dạng [mẫu chat](./chat_templating). Prompt của bạn nên bao gồm `role` và `content` để chỉ rõ ai đang tham gia cuộc trò chuyện. Nếu bạn cố gắng truyền prompt dưới dạng một chuỗi duy nhất, mô hình không phải lúc nào cũng trả về đầu ra như mong đợi.

```py
from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig

tokenizer = AutoTokenizer.from_pretrained("HuggingFaceH4/zephyr-7b-alpha")
model = AutoModelForCausalLM.from_pretrained(
    "HuggingFaceH4/zephyr-7b-alpha", device_map="auto", quantization_config=BitsAndBytesConfig(load_in_4bit=True)
)
```

```py
prompt = """How many cats does it take to change a light bulb? Reply as a pirate."""
model_inputs = tokenizer([prompt], return_tensors="pt").to(model.device)
input_length = model_inputs.input_ids.shape[1]
generated_ids = model.generate(**model_inputs, max_new_tokens=50)
print(tokenizer.batch_decode(generated_ids[:, input_length:], skip_special_tokens=True)[0])
"Aye, matey! 'Tis a simple task for a cat with a keen eye and nimble paws. First, the cat will climb up the ladder, carefully avoiding the rickety rungs. Then, with"
```

```py
messages = [
    {
        "role": "system",
        "content": "You are a friendly chatbot who always responds in the style of a pirate",
    },
    {"role": "user", "content": "How many cats does it take to change a light bulb?"},
]
model_inputs = tokenizer.apply_chat_template(messages, add_generation_prompt=True, return_tensors="pt").to(model.device)
input_length = model_inputs["input_ids"].shape[1]
generated_ids = model.generate(**model_inputs, do_sample=True, max_new_tokens=50)
print(tokenizer.batch_decode(generated_ids[:, input_length:], skip_special_tokens=True)[0])
"Arr, matey! According to me beliefs, 'twas always one cat to hold the ladder and another to climb up it an’ change the light bulb, but if yer looking to save some catnip, maybe yer can
```

## Tài nguyên

Xem bên dưới để tìm hiểu thêm về một số thư viện tạo văn bản cụ thể và chuyên biệt hơn.

- [Optimum](https://github.com/huggingface/optimum): một phần mở rộng của Transformers tập trung vào việc tối ưu hóa huấn luyện và suy luận trên các thiết bị phần cứng cụ thể
- [Outlines](https://github.com/dottxt-ai/outlines): một thư viện cho việc tạo văn bản có ràng buộc (ví dụ: tạo các tệp JSON).
- [SynCode](https://github.com/uiuc-focal-lab/syncode): một thư viện cho việc tạo sinh có hướng dẫn bằng ngữ pháp không ngữ cảnh (JSON, SQL, Python).
- [Text Generation Inference](https://github.com/huggingface/text-generation-inference): một máy chủ sẵn sàng cho môi trường sản xuất dành cho LLM.
- [Giao diện web tạo văn bản](https://github.com/oobabooga/text-generation-webui): một giao diện web Gradio để tạo văn bản.
- [logits-processor-zoo](https://github.com/NVIDIA/logits-processor-zoo): các logits processor bổ sung để kiểm soát việc tạo văn bản.

