#
Normalizare și pre-tokenizare

Înainte de a analiza în profunzime cei mai comuni trei algoritmi de subword tokenization utilizați cu modelele Transformer (Byte-Pair Encoding [BPE], WordPiece și Unigram), vom arunca mai întâi o privire la preprocesarea pe care fiecare tokenizer o aplică textului. Iată o prezentare generală a etapelor din pipelineul de tokenizare:

Înainte de a împărți un text în subtokens (în conformitate cu modelul său), tokenizerul efectuează doi pași: normalization__ și _pre-tokenization.

##
Normalization

Etapa de normalizare implică o curățare generală, cum ar fi eliminarea spațiilor inutile, a le face minuscule, și/sau ștergerea accentelor. Dacă sunteți familiarizat cu Unicode normalization (cum ar fi NFC sau NFKC), acest lucru poate fi aplicat și de tokenizer.

`Tokenizer`-ul 🤗 Transformers are un atribut numit `backend_tokenizer` care oferă acces la tokenizatorul de bază din biblioteca 🤗 Tokenizers:

    from transformers import AutoTokenizer

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

    <class 'tokenizers.Tokenizer'>

Atributul `normalizer` al obiectului `tokenizer` are o metodă `normalize_str()` pe care o putem folosi pentru a vedea cum se realizează normalizarea:

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

    'hello how are u?'

În acest exemplu, din moment ce am ales checkpointul `bert-base-uncased`, normalizarea a aplicat scrierea cu minusculă și a eliminat accentele.

> ✏️ Încercați! Încărcați un tokenizer din checkpointul `bert-base-cased` și treceți-i același exemplu. Care sunt principalele diferențe pe care le puteți observa între versiunile cased și uncased ale tokenizerului?

##
Pre-tokenization

După cum vom vedea în secțiunile următoare, un tokenizer nu poate fi antrenat doar pe text raw. În schimb, trebuie mai întâi să împărțim textele în entități mici, cum ar fi cuvintele. Aici intervine etapa de pre-tokenizare. După cum am văzut în Capitolul 2, un tokenizer bazat pe cuvinte poate împărți pur și simplu un text raw în cuvinte pe baza spațiului și a punctuației. Aceste cuvinte vor fi limitele subtokenurilor pe care tokenizerul le poate învăța în timpul instruirii sale.

Pentru a vedea cum un tokenizator rapid efectuează pre-tokenizarea, putem utiliza metoda `pre_tokenize_str()` a atributului `pre_tokenizer` al obiectului `tokenizer`:

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

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

Observați cum tokenizatorul ține deja evidența offseturilor, acesta fiind modul în care ne poate oferi mappingul offseturilor pe care l-am folosit în secțiunea anterioară. Aici, tokenizatorul ignoră cele două spații și le înlocuiește cu unul singur, dar offsetul sare între `are` și `you` pentru a ține cont de acest lucru.

Deoarece utilizăm un tokenizer BERT, pre-tokenizarea implică separarea spațiilor și a punctuației. Alți tokenizatori pot avea reguli diferite pentru acest pas. De exemplu, dacă folosim tokenizatorul GPT-2:

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

va despărți în spații și punctuație, dar va păstra spațiile și le va înlocui cu un simbol `Ġ`, permițându-i să recupereze spațiile originale dacă facem decode tokenilor:

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

De asemenea, rețineți că, spre deosebire de tokenizatorul BERT, acest tokenizator nu ignoră spațiul dublu.

Pentru un ultim exemplu, să aruncăm o privire la tokenizerul T5, care se bazează pe algoritmul SentencePiece:

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

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

Ca și tokenizatorul GPT-2, acesta păstrează spațiile și le înlocuiește cu un token specific (`_`), dar tokenizatorul T5 separă doar spațiile, nu și punctuația. De asemenea, observați că a adăugat un spațiu implicit la începutul propoziției (înainte de `Hello`) și a ignorat spațiul dublu dintre `are` și `you`.

Acum că am văzut puțin din modul în care diferite tokenizere procesează textul, putem începe să explorăm algoritmii care stau la baza acestora. Vom începe cu o privire rapidă asupra SentencePiece, care se aplică pe scară largă; apoi, în următoarele trei secțiuni, vom examina modul în care funcționează cei trei algoritmi principali utilizați pentru tokenizarea subcuvintelor.

##
SentencePiece

SentencePiece este un algoritm de tokenizare pentru preprocesarea textului pe care îl puteți utiliza cu oricare dintre modelele pe care le vom vedea în următoarele trei secțiuni. Acesta consideră textul ca o secvență de caractere Unicode și înlocuiește spațiile cu un caracter special, `▁`. Folosit împreună cu algoritmul Unigram (a se vedea secțiunea 7), nu necesită nici măcar o etapă de pre-tokenizare, ceea ce este foarte util pentru limbile în care nu se folosește caracterul spațiu (cum ar fi chineza sau japoneza).

Cealaltă caracteristică principală a SentencePiece este reversible tokenization: deoarece nu există un tratament special al spațiilor, decodarea tokenurilor se face pur și simplu prin concatenarea lor și înlocuirea `_` cu spații - acest lucru rezultă în textul normalizat. După cum am văzut mai devreme, tokenizatorul BERT elimină spațiile care se repetă, deci tokenizarea sa nu este reversibilă.

##
Prezentare generală a algoritmului

În următoarele secțiuni, vom analiza cei trei algoritmi principali de tokenizare a subcuvintelor: BPE (utilizat de GPT-2 și alții), WordPiece (utilizat de exemplu de BERT) și Unigram (utilizat de T5 și alții). Înainte de a începe, iată o scurtă prezentare generală a modului în care funcționează fiecare dintre acestea. Nu ezitați să reveniți la acest tabel după ce citiți fiecare dintre secțiunile următoare, dacă încă nu are sens pentru dumneavoastră.

Model | BPE | WordPiece | Unigram
--- | --- | --- | ---
Training | Pornește de la un vocabular restrâns și învață reguli de îmbinare a tokenilor | Pornește de la un vocabular restrâns și învață reguli de îmbinare a tokenilor | Pornește de la un vocabular mare și învață regulile de eliminare a tokenilor
Training step | Combină tokenii corespunzători celei mai comune perechi | Combină tokenii corespunzători perechii cu cel mai bun scor pe baza frecvenței perechii, privilegiind perechile în care fiecare token individual este mai puțin frecvent | Elimină toți tokenii din vocabular care vor minimiza pierderea calculată pe întregul corpus
Learns | Reguli de combinare și un vocabular | Doar un vocabular | Un vocabular cu un anumit scor pentru fiecare token
Encoding | Împarte un cuvânt în caractere și aplică îmbinările învățate în timpul antrenării | Găsește cel mai lung subcuvânt începând de la început care se află în vocabular, apoi face același lucru pentru restul cuvântului | Găsește cea mai probabilă împărțire în tokens, folosind scorurile învățate în timpul antrenării

Acum hai să trecem la BPE!

Update on GitHub