# Tokenizer
## Week 29
----
## 說文解字
Byte 位元組
Character 字元
Word 單字、詞
Vocabulary 字典
----
## Byte
例如 `"Apple"` 可以表示成
`0x41/0x70/0x70/0x6C/0x65`
等 5 個位元組,每個英文字母佔 1 Byte
----
## Byte
若是中文的「蘋果」則為
`0xE8/0x98/0x8B/0xE6/0x9E/0x9C`
等 6 個位元組,每個中文字佔 3 Bytes
----
## Character
例如 `"Apple"` 可以分解成
`A/p/p/l/e` 等 5 個字元
而「蘋果」則是 2 個字元
----
## Word
例如 `"I have an apple"` 可以分解成
`I/have/an/apple` 等 4 個單字
----
## Chinese Word?
「我有一顆蘋果」可以分解成
`我有/一顆/蘋果`
`我/有/一/顆/蘋果`
不同定義下有不同的切法
這在中文也稱為
「斷詞 (Word Segmentation)」
----
## Token
Token 資訊歷史上最難翻譯的一個單字
比較理想的翻譯是「詞元」
若是當成 API Token 則會翻成「令牌」
但兩者的用法情境是不同的
----
## Token
Tokenize 動詞,指分詞這個動作
Tokenization 名詞,指分詞的過程
Tokenizer 名詞,分詞器、詞元分析器
----
## 什麼是 Token
介在 Byte 與 Word 之間的單位
例如 `Apple` 可能是 1 個獨立的 Token
而 `Pineapple` 則可能被分解成
`Pine` 跟 `##apple` 兩個 Tokens
----
## Too Many Tokens
UTF-8 編碼可以表示九萬多種中日韓字元
整個 Unicode 包含了約 14 萬個字元
更遑論這些字元可以合併成更多單字詞
對模型訓練而言,這樣會產生非常高的維度
使模型尺寸相當大,難以訓練
----
## Byte-Level Token
把 Token 的單位縮減到 Byte-Level
就能在 256 個 Tokens 內表達所有文字
但是「文本壓縮率」就會很低
「我有一顆蘋果」需要 18 個 Tokens 來表示
----
## Tokenizer Training
透過一些統計的技巧
在字典大小與文本壓縮率之間取得平衡
除此之外,還要能夠應對未知詞
Out-of-Vocabulary, OOV
---
# 訓練演算法
----
## 演算法種類
Character/Word-Level
Unigram
Word-Piece
Byte-Pair Encoding (BPE)
----
## Char/Word-Level
直接以字元/單字為單位
最單純的做法
不適合中日韓文字
----
## Unigram
統計單字詞之間的機率
介在 Char-Level 與 Word-Level 之間
比較能夠表達 OOV 文字
----
## Word-Piece
先將所有文本分析成 Words
再把每個 Word 拆解成 Pieces
例如已經有了 `photo, graphy` 兩字
則遇到 `photography` 可拆解成
`photo, ##graphy` 兩個 Tokens
----
## Byte-Pair Encoding
先把所有文本拆解成 Bytes
再把常常出現的 Byte-Pair 組合在一起
例如已經有了 `a, g, h, o, p, r, t, y` 等
`photo` 很常配在一起,合併成一個 Token
`graphy` 很常配在一起,合併成另一個 Token
---
# 訓練工具
----
## 開源套件
[Hugging Face - Tokenizers](https://github.com/huggingface/tokenizers) (HF Tokenizer)
[Google - SentencePiece](https://github.com/google/sentencepiece) (SPM)
----
## 準備文本
可以參考國科會 TAIDE 計畫的[訓練資料](https://taide.tw/public/trainData)
或者 Hugging Face Hub 上的[繁體中文維基](https://huggingface.co/datasets/bigscience-data/roots_zh-tw_wikipedia)
----
## Parquet 格式
[Apache Parquet](https://parquet.apache.org/) 是一種
**Column-Oriented** 的資料格式
具有不錯的壓縮率與讀寫速度
對機器學習相關任務相當友善
壓縮率 Gzip > Parquet >>> Raw
讀寫速度 Parquet > Raw >>> Gzip
----
## Parquet 使用方法
寫入檔案
```python=
import pandas as pd
dataset = [
dict(id=0, text="Hello"),
dict(id=1, text="Hi"),
]
dataset = pd.DataFrame(dataset)
dataset.to_parquet("dataset.parquet")
```
讀取檔案
```python=
import pandas as pd
dataset = pd.read_parquet("dataset.parquet")
print(dataset)
```
----
## 將資料存為純文字格式
```python=
import pandas as pd
data = pd.read_parquet("wiki.parquet")
with open("Raw.txt", "wt", encoding="UTF-8") as fp:
for text in data["text"][:1000]:
fp.write(text.strip())
fp.write("\n\n")
```
----
## 透過 HF Tokenizers 訓練
```python=
from tokenizers import Tokenizer, models, trainers
model = models.BPE(byte_fallback=True, unk_token="[UNK]")
trainer = trainers.BpeTrainer(special_tokens=["[UNK]"])
tokenizer = Tokenizer(model)
files = ["Raw.txt"]
tokenizer.train(files, trainer)
tokenizer.save("Tokenizer.json")
```
----
## 透過 SentencePiece 訓練
```bash=
spm_train --input=Raw.txt --model_prefix=spm-model/tk --model_type=bpe
```
----
## Tokenizer 生態系
SPM 可以被轉成 HF Tokenizer
HF Tokenizer 可以跟 Transformers 一起訓練
但 HF Tokenizer 比較難被轉回 SPM
{"title":"Week 29 - Tokenizer","description":"地獄貓旅行團第 41 週心得分享","contributors":"[{\"id\":\"c7cbb212-2c41-4dfa-8d85-f8e7fa769bf1\",\"add\":3644,\"del\":310}]","slideOptions":"{\"transition\":\"slide\"}"}