|
from typing import Dict, Iterator, List, Optional, Tuple, Union |
|
|
|
from .. import AddedToken, Tokenizer, decoders, pre_tokenizers, trainers |
|
from ..models import BPE |
|
from ..normalizers import BertNormalizer, Lowercase, Sequence, unicode_normalizer_from_str |
|
from .base_tokenizer import BaseTokenizer |
|
|
|
|
|
class CharBPETokenizer(BaseTokenizer): |
|
"""Original BPE Tokenizer |
|
|
|
Represents the BPE algorithm, as introduced by Rico Sennrich |
|
(https://arxiv.org/abs/1508.07909) |
|
|
|
The defaults settings corresponds to OpenAI GPT BPE tokenizers and differs from the original |
|
Sennrich subword-nmt implementation by the following options that you can deactivate: |
|
- adding a normalizer to clean up the text (deactivate with `bert_normalizer=False`) by: |
|
* removing any control characters and replacing all whitespaces by the classic one. |
|
* handle chinese chars by putting spaces around them. |
|
* strip all accents. |
|
- spitting on punctuation in addition to whitespaces (deactivate it with |
|
`split_on_whitespace_only=True`) |
|
""" |
|
|
|
def __init__( |
|
self, |
|
vocab: Optional[Union[str, Dict[str, int]]] = None, |
|
merges: Optional[Union[str, Dict[Tuple[int, int], Tuple[int, int]]]] = None, |
|
unk_token: Union[str, AddedToken] = "<unk>", |
|
suffix: str = "</w>", |
|
dropout: Optional[float] = None, |
|
lowercase: bool = False, |
|
unicode_normalizer: Optional[str] = None, |
|
bert_normalizer: bool = True, |
|
split_on_whitespace_only: bool = False, |
|
): |
|
if vocab is not None and merges is not None: |
|
tokenizer = Tokenizer( |
|
BPE( |
|
vocab, |
|
merges, |
|
dropout=dropout, |
|
unk_token=str(unk_token), |
|
end_of_word_suffix=suffix, |
|
) |
|
) |
|
else: |
|
tokenizer = Tokenizer(BPE(unk_token=str(unk_token), dropout=dropout, end_of_word_suffix=suffix)) |
|
|
|
if tokenizer.token_to_id(str(unk_token)) is not None: |
|
tokenizer.add_special_tokens([str(unk_token)]) |
|
|
|
|
|
normalizers = [] |
|
|
|
if unicode_normalizer: |
|
normalizers += [unicode_normalizer_from_str(unicode_normalizer)] |
|
|
|
if bert_normalizer: |
|
normalizers += [BertNormalizer(lowercase=False)] |
|
|
|
if lowercase: |
|
normalizers += [Lowercase()] |
|
|
|
|
|
if len(normalizers) > 0: |
|
if len(normalizers) > 1: |
|
tokenizer.normalizer = Sequence(normalizers) |
|
else: |
|
tokenizer.normalizer = normalizers[0] |
|
|
|
if split_on_whitespace_only: |
|
tokenizer.pre_tokenizer = pre_tokenizers.WhitespaceSplit() |
|
else: |
|
tokenizer.pre_tokenizer = pre_tokenizers.BertPreTokenizer() |
|
|
|
tokenizer.decoder = decoders.BPEDecoder(suffix=suffix) |
|
|
|
parameters = { |
|
"model": "BPE", |
|
"unk_token": unk_token, |
|
"suffix": suffix, |
|
"dropout": dropout, |
|
"lowercase": lowercase, |
|
"unicode_normalizer": unicode_normalizer, |
|
"bert_normalizer": bert_normalizer, |
|
"split_on_whitespace_only": split_on_whitespace_only, |
|
} |
|
|
|
super().__init__(tokenizer, parameters) |
|
|
|
@staticmethod |
|
def from_file(vocab_filename: str, merges_filename: str, **kwargs): |
|
vocab, merges = BPE.read_file(vocab_filename, merges_filename) |
|
return CharBPETokenizer(vocab, merges, **kwargs) |
|
|
|
def train( |
|
self, |
|
files: Union[str, List[str]], |
|
vocab_size: int = 30000, |
|
min_frequency: int = 2, |
|
special_tokens: List[Union[str, AddedToken]] = ["<unk>"], |
|
limit_alphabet: int = 1000, |
|
initial_alphabet: List[str] = [], |
|
suffix: Optional[str] = "</w>", |
|
show_progress: bool = True, |
|
): |
|
"""Train the model using the given files""" |
|
|
|
trainer = trainers.BpeTrainer( |
|
vocab_size=vocab_size, |
|
min_frequency=min_frequency, |
|
special_tokens=special_tokens, |
|
limit_alphabet=limit_alphabet, |
|
initial_alphabet=initial_alphabet, |
|
end_of_word_suffix=suffix, |
|
show_progress=show_progress, |
|
) |
|
if isinstance(files, str): |
|
files = [files] |
|
self._tokenizer.train(files, trainer=trainer) |
|
|
|
def train_from_iterator( |
|
self, |
|
iterator: Union[Iterator[str], Iterator[Iterator[str]]], |
|
vocab_size: int = 30000, |
|
min_frequency: int = 2, |
|
special_tokens: List[Union[str, AddedToken]] = ["<unk>"], |
|
limit_alphabet: int = 1000, |
|
initial_alphabet: List[str] = [], |
|
suffix: Optional[str] = "</w>", |
|
show_progress: bool = True, |
|
length: Optional[int] = None, |
|
): |
|
"""Train the model using the given iterator""" |
|
|
|
trainer = trainers.BpeTrainer( |
|
vocab_size=vocab_size, |
|
min_frequency=min_frequency, |
|
special_tokens=special_tokens, |
|
limit_alphabet=limit_alphabet, |
|
initial_alphabet=initial_alphabet, |
|
end_of_word_suffix=suffix, |
|
show_progress=show_progress, |
|
) |
|
self._tokenizer.train_from_iterator( |
|
iterator, |
|
trainer=trainer, |
|
length=length, |
|
) |
|
|