# Chuẩn hoá và tiền tokenize

<DocNotebookDropdown
  classNames="absolute z-10 right-0 top-0"
  options={[
    {label: "Google Colab", value: "https://colab.research.google.com/github/huggingface/notebooks/blob/master/course/vi/chapter6/section4.ipynb"},
    {label: "Aws Studio", value: "https://studiolab.sagemaker.aws/import/github/huggingface/notebooks/blob/master/course/vi/chapter6/section4.ipynb"},
]} />

Trước khi đi sâu hơn vào ba thuật toán tokenize từ phụ phổ biến nhất được sử dụng với các mô hình Transformer (Mã hóa theo cặp [BPE], WordPiece và Unigram), trước tiên chúng ta sẽ xem xét tiền xử lý mà mỗi trình tokenize áp dụng cho văn bản. Dưới đây là tổng quan cấp cao về các bước trong pipeline tokenize:

<div class="flex justify-center">
<img class="block dark:hidden" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter6/tokenization_pipeline.svg" alt="The tokenization pipeline.">
<img class="hidden dark:block" src="https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter6/tokenization_pipeline-dark.svg" alt="The tokenization pipeline.">
</div>

Trước khi tách một đoạn văn bản thành các token phụ (dựa theo mô hình)tokenizer sẽ thực hiện 2 bước: _normalization_ (chuẩn hoá) và _pre-tokenization_ (tiền tokenize).

## Chuẩn hoá

<Youtube id="4IIC2jI9CaU"/>

Bước chuẩn hóa bao gồm một số thao tác dọn dẹp, chẳng hạn như loại bỏ khoảng trắng không cần thiết, viết thường tất cả các chữ, và/hoặc xóa dấu. Nếu bạn đã quen với [chuẩn hóa Unicode](http://www.unicode.org/reports/tr15/) (chẳng hạn như NFC hoặc NFKC), thì đây cũng là điều mà tokenizer có thể áp dụng.

`tokenizer` của 🤗 Transformers có một thuộc tính gọi là `backend_tokenizer` cung cấp quyền truy cập vào tokenizer bên dưới từ thư viện 🤗 Tokenizers:

```py
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased")
print(type(tokenizer.backend_tokenizer))
```

```python out
<class 'tokenizers.Tokenizer'>
```

Thuộc tính `normalizer` của đối tượng `tokenizer` có phương thức `normalize_str()` mà ta có thể dùng để thấy cách bước chuẩn hoá được thực hiện:

```py
print(tokenizer.backend_tokenizer.normalizer.normalize_str("Héllò hôw are ü?"))
```

```python out
'hello how are u?'
```

Trong ví dụ này, vì chúng ta chọn checkpoint `bert-base-uncased`, bước chuẩn hoá sẽ thực hiện viết thường và loại bỏ các dấu.

<Tip>

✏️ **Try it out!** Tải tokenizer từ checkpoint `bert-base-cased` và truyền vào cùng một ví dụ vào.Sự khác biệt chính mà bạn có thể thấy giữa các phiên bản có dấu và không dấu của tokenizer là gì?

</Tip>

## Pre-tokenization

<Youtube id="grlLV8AIXug"/>

Như chúng ta sẽ thấy trong các phần tiếp theo, một tokenizer không thể được huấn luyện trên văn bản thô. Thay vào đó, trước tiên chúng ta cần chia các văn bản thành các thực thể nhỏ, như các từ. Đó là khi bước pre-tokenization bắt đầu. Như chúng ta đã thấy trong [Chương 2](/course/chapter2), trình tokenize dựa trên từ có thể chỉ cần tách một văn bản thô thành các từ dựa trên khoảng trắng và dấu câu. Những từ đó sẽ là ranh giới của các token con mà tokenizer có thể học được trong quá trình huấn luyện của nó.

Để xem cách một tokenizer nhanh thực hiện pre-tokenization, chúng ta có thể sử dụng phương thức `pre_tokenize_str()` của thuộc tính `pre_tokenizer` của đối tượng `tokenizer`:

```py
tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str("Hello, how are  you?")
```

```python out
[('Hello', (0, 5)), (',', (5, 6)), ('how', (7, 10)), ('are', (11, 14)), ('you', (16, 19)), ('?', (19, 20))]
```

Lưu ý cách tokenizer đã theo dõi các offset, đó là cách nó có thể cung cấp cho chúng ta ánh xạ offset mà ta đã sử dụng trong phần trước. Ở đây tokenizer bỏ qua hai khoảng trắng và thay thế chúng bằng chỉ một, nhưng các offset xen giữa `are` và `you` để giải thích điều đó.

Vì chúng ta đang sử dụng BERT tokenizer, pre-tokenization liên quan đến việc phân tách dựa trên khoảng trắng và dấu chấm câu. Các tokenizer khác có thể có các quy tắc khác nhau cho bước này. Ví dụ: nếu sử dụng GPT-2 tokenizer:

```py
tokenizer = AutoTokenizer.from_pretrained("gpt2")
tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str("Hello, how are  you?")
```

nó sẽ tách dựa trên dấu cách và dấu câu, nhưng sẽ giữa dấu cách và thay thế chúng bởi kí hiệu `Ġ`, cho phép nó khôi phục không gian ban đầu nếu chúng tôi giải mã các token:

```python out
[('Hello', (0, 5)), (',', (5, 6)), ('Ġhow', (6, 10)), ('Ġare', (10, 14)), ('Ġ', (14, 15)), ('Ġyou', (15, 19)),
 ('?', (19, 20))]
```

Cần lưu ý thêm rằng không như BERT tokenizer, tokenizer này bỏ qua dấu cách kép.

Ở ví dụ cuối, hãy cùng xem T5 tokenizer dựa trên thuật toán SentencePiece:

```py
tokenizer = AutoTokenizer.from_pretrained("t5-small")
tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str("Hello, how are  you?")
```

```python out
[('▁Hello,', (0, 6)), ('▁how', (7, 10)), ('▁are', (11, 14)), ('▁you?', (16, 20))]
```

Giống như GPT-2 tokenizer, phương pháp này giữ các dấu cách và thay thế chúng bởi một tí tự đặc biệt (`_`), nhưng T5 tokenizer chỉ tách dựa theo dấu cách, không dựa theo dấu câu. Một lưu ý nữa đó là nó cũng mặc định thêm dấu cách ở phía đầu câu (trước `Hello`) và bỏ qua những dấu cách kẹp ở giữa `are` và `you`.

Bây giờ chúng ta đã biết một chút về cách một số loại tokenizers khác nhau để xử lý văn bản, chúng ta có thể bắt đầu tự khám phá các thuật toán cơ bản. Chúng ta sẽ bắt đầu bằng một cái nhìn nhanh về SentencePiece được áp dụng rộng rãi; sau đó, trong ba phần tiếp theo, chúng ta sẽ xem xét cách thức hoạt động của ba thuật toán chính được sử dụng để mã hóa từ phụ.

## SentencePiece

[SentencePiece](https://github.com/google/sentencepiece) là một thuật toán tokenize để tiền xử lý văn bản mà bạn có thể sử dụng với bất kỳ mô hình nào chúng ta sẽ thấy trong ba phần tiếp theo. Nó coi văn bản là một chuỗi các ký tự Unicode và thay thế dấu cách bằng một ký tự đặc biệt, `▁`. Được sử dụng cùng với thuật toán Unigram (xem [phần 7](/course/chapter7/7)), nó thậm chí không yêu cầu bước pre-tokenization, rất hữu ích cho các ngôn ngữ không sử dụng dấu cách (như Trung Quốc hoặc Nhật Bản).

Tính năng chính khác của SentencePiece là *reversible tokenization* hay *tokenize có thể đảo ngược*: vì không có cách xử lý đặc biệt nào cho dấu cách, nên việc giải mã các token được thực hiện đơn giản bằng cách nối chúng và thay thế các dấu `_` bằng dấu cách - điều này giúp văn bản được chuẩn hóa. Như chúng ta đã thấy trước đó, BERT tokenizer loại bỏ các dấu cách lặp lại, vì vậy token của nó không thể đảo ngược.

## Tổng quan thuật toán

Trong các phần tiếp theo, chúng ta sẽ đi sâu vào ba thuật toán tokenize từ phụ tiêu biểu: BPE (được sử dụng bởi GPT-2 và các thuật toán khác), WordPiece (được sử dụng bởi BERT) và Unigram (được sử dụng bởi T5 và các thuật toán khác). Trước khi chúng ta bắt đầu, đây là tổng quan nhanh về cách hoạt động của từng loại. Đừng ngần ngại quay lại bảng này sau khi đọc từng phần tiếp theo nếu bạn chưa hiểu hết.

Mô hình | BPE | WordPiece | Unigram
:----:|:---:|:---------:|:------:
Huấn luyện | Bắt đầu với một bộ từ vựng nhỏ và học bộ quy tắc hợp nhất token |  Bắt đầu với một bộ từ vựng nhỏ và học bộ quy tắc hợp nhất token | Bắt đầu với một bộ từ vựng lớn và học bộ quy tắc để loại bỏ token
Bước huấn luyện | Gộp các token liên quan đến cặp phổ biến nhất | Gộp các token liên quan đến cặp có điểm cao nhất dựa trên tần suất của cặp, with the best score based on the frequency of the pair,  ưu tiên các cặp mà mỗi token cá nhân tần suất thấp hơn| Loại bỏ tất cả các token trong bộ từ điển giảm thiểu tối đa độ mất mát được tính trên toàn bộ kho ngữ liệu
Học | Gộp bộ quy tắc và bộ từ vựng | Chỉ bộ từ vựng  | Một bộ tự vựng với điểm cho mỗi token
Mã hoá | Chia từ thành các kí tự và áp dụng bước gộp từ quá trình huấn luyện | Tìm ra chuỗi từ phụ dài nhất bắt đầu từ phần bắt đầu có trong bộ từ vựng, sau đó làm tương tự với các phần còn lại của từ | Tìm từ có khả năng chia thành token cao nhất sử dụng điểm có được từ quá trình huấn luyện

Giờ chúng ta hãy đi sâu vào BPE thôi!
