Per addestrare un modello linguistico, dobbiamo scomporre il linguaggio in pezzi (i cosiddetti token) e inserirli nel modello in modo incrementale. La tokenizzazione può essere eseguita su più livelli.
- A livello di personaggio: Il testo viene percepito come una sequenza di singoli caratteri (compresi gli spazi bianchi). Questo approccio granulare consente di formare ogni possibile parola da una sequenza di caratteri. Tuttavia, è più difficile catturare le relazioni semantiche tra le parole.
- A livello di parola: Il testo è rappresentato come una sequenza di parole. Tuttavia, il vocabolario del modello è limitato dalle parole esistenti nei dati di addestramento.
- A livello di sottoparola: Il testo è suddiviso in unità di sottoparole, che sono più piccole delle parole ma più grandi dei caratteri.
Anche se ho iniziato con un tokenizzatore a livello di carattere, ho sentito che il tempo di addestramento era sprecato, imparando sequenze di caratteri di parole ripetitive, piuttosto che concentrarmi sulla relazione semantica tra le parole nella frase.
Per ragioni di semplicità concettuale, ho deciso di passare a un tokenizzatore a livello di parola, tenendo da parte le librerie disponibili per strategie di tokenizzazione più sofisticate.
from nltk.tokenize import RegexpTokenizerdef custom_tokenizer(txt: str, spec_tokens: List(str), pattern: str="|\d|\\w+|(^\\s)") -> List(str):
"""
Tokenize text into words or characters using NLTK's RegexpTokenizer, considerung
given special combinations as single tokens.
:param txt: The corpus as a single string element.
:param spec_tokens: A list of special tokens (e.g. ending, out-of-vocab).
:param pattern: By default the corpus is tokenized on a word level (split by spaces).
Numbers are considered single tokens.
>> note: The pattern for character level tokenization is '|.'
"""
pattern = "|".join(spec_tokens) + pattern
tokenizer = RegexpTokenizer(pattern)
tokens = tokenizer.tokenize(txt)
return tokens
("Alice:", "Hi", "how", "are", "you", "guys", "?", "<END>", "Tom:", ... )
Si è scoperto che i miei dati di allenamento hanno un vocabolario di circa 70.000 parole uniche. Tuttavia, poiché molte parole compaiono solo una o due volte, ho deciso di sostituire parole così rare con un “
from collections import Counterdef get_infrequent_tokens(tokens: Union(List(str), str), min_count: int) -> List(str):
"""
Identify tokens that appear less than a minimum count.
:param tokens: When it is the raw text in a string, frequencies are counted on character level.
When it is the tokenized corpus as list, frequencies are counted on token level.
:min_count: Threshold of occurence to flag a token.
:return: List of tokens that appear infrequently.
"""
counts = Counter(tokens)
infreq_tokens = set((k for k,v in counts.items() if v<=min_count))
return infreq_tokens
def mask_tokens(tokens: List(str), mask: Set(str)) -> List(str):
"""
Iterate through all tokens. Any token that is part of the set, is replaced by the unknown token.
:param tokens: The tokenized corpus.
:param mask: Set of tokens that shall be masked in the corpus.
:return: List of tokenized corpus after the masking operation.
"""
return (t.replace(t, unknown_token) if t in mask else t for t in tokens)
infreq_tokens = get_infrequent_tokens(tokens, min_count=2)
tokens = mask_tokens(tokens, infreq_tokens)
("Alice:", "Hi", "how", "are", "you", "<UNK>", "?", "<END>", "Tom:", ... )
Fonte: towardsdatascience.com