Adapt tokenization_interns1.py to transformers>=5.0.0
#7
by lvhan - opened
- tokenization_interns1.py +146 -29
tokenization_interns1.py
CHANGED
|
@@ -25,24 +25,27 @@ import regex as re
|
|
| 25 |
import sentencepiece as spm
|
| 26 |
from collections import OrderedDict
|
| 27 |
|
| 28 |
-
from transformers.tokenization_utils import PreTrainedTokenizer
|
| 29 |
from transformers.tokenization_utils_base import AddedToken, TextInput
|
| 30 |
-
from transformers.models.qwen2.tokenization_qwen2 import Qwen2Tokenizer
|
| 31 |
from transformers.utils import logging
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
|
| 33 |
|
| 34 |
logger = logging.get_logger(__name__)
|
| 35 |
|
| 36 |
try:
|
| 37 |
-
from rdkit import Chem
|
| 38 |
-
from rdkit import RDLogger
|
| 39 |
|
| 40 |
RDLogger.DisableLog("rdApp.error")
|
| 41 |
RDLogger.DisableLog("rdApp.*")
|
| 42 |
RDKIT_AVAILABLE = True
|
| 43 |
except ImportError:
|
| 44 |
logger.warning_once(
|
| 45 |
-
|
| 46 |
)
|
| 47 |
RDKIT_AVAILABLE = False
|
| 48 |
|
|
@@ -60,7 +63,6 @@ PRETOKENIZE_REGEX = r"""(?i:'s|'t|'re|'ve|'m|'ll|'d)|[^\r\n\p{L}\p{N}]?\p{L}+|\p
|
|
| 60 |
class InternS1CheckModuleMixin(ABC):
|
| 61 |
"""
|
| 62 |
Basic auto-detection module.
|
| 63 |
-
|
| 64 |
Note that short strings are ignored by this module.
|
| 65 |
"""
|
| 66 |
def __init__(self, *, min_length: int):
|
|
@@ -122,7 +124,6 @@ class InternS1CheckModuleMixin(ABC):
|
|
| 122 |
class FastaCheckModule(InternS1CheckModuleMixin):
|
| 123 |
"""
|
| 124 |
Protein sequence auto-detection module.
|
| 125 |
-
|
| 126 |
Automatically detects protein sequence using regex patterns.
|
| 127 |
"""
|
| 128 |
def __init__(self, *, min_length: int = 27):
|
|
@@ -160,7 +161,6 @@ elements = [
|
|
| 160 |
class SmilesCheckModule(InternS1CheckModuleMixin):
|
| 161 |
"""
|
| 162 |
SMILES molecular sequence auto-detection module.
|
| 163 |
-
|
| 164 |
Automatically detects and validates SMILES strings in text using regex patterns
|
| 165 |
or chemical syntax rules. Uses RDKit for precise validation when available,
|
| 166 |
otherwise falls back to rule-based validation.
|
|
@@ -343,28 +343,61 @@ class SmilesCheckModule(InternS1CheckModuleMixin):
|
|
| 343 |
return self.check_brackets(text)
|
| 344 |
|
| 345 |
|
| 346 |
-
|
|
|
|
|
|
|
| 347 |
"""
|
| 348 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 349 |
|
|
|
|
|
|
|
|
|
|
| 350 |
Same with GPT2Tokenizer, this tokenizer has been trained to treat spaces like parts of the tokens so a word will
|
| 351 |
be encoded differently whether it is at the beginning of the sentence (without space) or not:
|
| 352 |
-
|
| 353 |
```python
|
| 354 |
>>> from transformers import AutoTokenizer
|
| 355 |
-
|
| 356 |
>>> tokenizer = AutoTokenizer.from_pretrained("InternS1Tokenizer", trust_remote_code=True)
|
| 357 |
>>> tokenizer("Hello world")["input_ids"]
|
| 358 |
[9707, 1879]
|
| 359 |
-
|
| 360 |
>>> tokenizer(" Hello world")["input_ids"]
|
| 361 |
[21927, 1879]
|
| 362 |
```
|
| 363 |
This is expected.
|
| 364 |
-
|
| 365 |
Include custom extension to support better domain-specific text tokenization, leveraging a separately trained tokenizer model.
|
| 366 |
Users should refer to this superclass [`PreTrainedTokenizer`] for more information regarding those overloaded methods
|
| 367 |
-
|
| 368 |
Args:
|
| 369 |
vocab_file (`str`):
|
| 370 |
Path to the vocabulary file.
|
|
@@ -408,6 +441,54 @@ class InternS1Tokenizer(Qwen2Tokenizer):
|
|
| 408 |
split_special_tokens=False,
|
| 409 |
**kwargs,
|
| 410 |
):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 411 |
self.extra_tokenizer_start_mapping = {}
|
| 412 |
self.extra_tokenizer_end_mapping = {}
|
| 413 |
self._extra_special_tokens = []
|
|
@@ -460,6 +541,7 @@ class InternS1Tokenizer(Qwen2Tokenizer):
|
|
| 460 |
pad_token=pad_token,
|
| 461 |
clean_up_tokenization_spaces=clean_up_tokenization_spaces,
|
| 462 |
split_special_tokens=split_special_tokens,
|
|
|
|
| 463 |
**kwargs,
|
| 464 |
)
|
| 465 |
|
|
@@ -497,6 +579,10 @@ class InternS1Tokenizer(Qwen2Tokenizer):
|
|
| 497 |
"""Overload method"""
|
| 498 |
return self.vocab_size
|
| 499 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 500 |
@property
|
| 501 |
def logical_auto_tokens(self):
|
| 502 |
"""Tokens that won't be decoded and only for switching tokenizer"""
|
|
@@ -623,9 +709,7 @@ class InternS1Tokenizer(Qwen2Tokenizer):
|
|
| 623 |
def tokenize(self, text: TextInput, **kwargs) -> List[str]:
|
| 624 |
"""
|
| 625 |
Converts a string into a sequence of tokens, using the tokenizer.
|
| 626 |
-
|
| 627 |
It will switch to domain-specific tokenizer once encountering extra/logical sp tokens.
|
| 628 |
-
|
| 629 |
Args:
|
| 630 |
text: TextInput
|
| 631 |
"""
|
|
@@ -633,9 +717,6 @@ class InternS1Tokenizer(Qwen2Tokenizer):
|
|
| 633 |
|
| 634 |
text, kwargs = self.prepare_for_tokenization(text, **kwargs)
|
| 635 |
|
| 636 |
-
if kwargs:
|
| 637 |
-
logger.warning(f"Keyword arguments {kwargs} not recognized.")
|
| 638 |
-
|
| 639 |
if hasattr(self, "do_lower_case") and self.do_lower_case:
|
| 640 |
# convert non-special tokens to lowercase. Might be super slow as well?
|
| 641 |
escaped_special_toks = [re.escape(s_tok) for s_tok in (self.all_special_tokens)]
|
|
@@ -738,7 +819,6 @@ class InternS1Tokenizer(Qwen2Tokenizer):
|
|
| 738 |
def _add_tokens(self, new_tokens: Union[List[str], List[AddedToken]], special_tokens: bool = False) -> int:
|
| 739 |
"""
|
| 740 |
Modified from `transformers.tokenization_utils._add_tokens`.
|
| 741 |
-
|
| 742 |
This adaptation supports dynamic tokenizer length due to supplementary tokenizers (e.g., domain-specific or scientific text tokenizers).
|
| 743 |
"""
|
| 744 |
added_tokens = 0
|
|
@@ -785,6 +865,7 @@ class InternS1Tokenizer(Qwen2Tokenizer):
|
|
| 785 |
self._added_tokens_encoder[token.content] = token_index
|
| 786 |
if self.verbose:
|
| 787 |
logger.info(f"Adding {token} to the vocabulary")
|
|
|
|
| 788 |
self._update_trie()
|
| 789 |
self._update_total_vocab_size()
|
| 790 |
|
|
@@ -797,7 +878,6 @@ class InternS1Tokenizer(Qwen2Tokenizer):
|
|
| 797 |
def _tokenize(self, text, **kwargs):
|
| 798 |
"""
|
| 799 |
Modified from `transformers.models.gpt2.tokenization_gpt2.GPT2Tokenizer._tokenize`.
|
| 800 |
-
|
| 801 |
This adaptation supports domain-specific tokenizers.
|
| 802 |
"""
|
| 803 |
extra_tokenizer_stack = kwargs.pop("extra_tokenizer_stack", False)
|
|
@@ -814,6 +894,49 @@ class InternS1Tokenizer(Qwen2Tokenizer):
|
|
| 814 |
else:
|
| 815 |
return self._bpe_tokenize(text)
|
| 816 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 817 |
def _bpe_tokenize(self, text, **kwargs):
|
| 818 |
text = text.replace(
|
| 819 |
"▁", " "
|
|
@@ -829,15 +952,11 @@ class InternS1Tokenizer(Qwen2Tokenizer):
|
|
| 829 |
def convert_tokens_to_ids(self, tokens: Union[str, List[str]]) -> Union[int, List[int]]:
|
| 830 |
"""
|
| 831 |
Modified from `transformers.tokenization_utils.PreTrainedTokenzier.convert_tokens_to_ids`.
|
| 832 |
-
|
| 833 |
Converts a token string (or a sequence of tokens) in a single integer id (or a sequence of ids), using the
|
| 834 |
vocabulary.
|
| 835 |
-
|
| 836 |
This adaptation supports domain-specific tokenizers.
|
| 837 |
-
|
| 838 |
Args:
|
| 839 |
tokens (`str` or `List[str]`): One or several token(s) to convert to token id(s).
|
| 840 |
-
|
| 841 |
Returns:
|
| 842 |
`int` or `List[int]`: The token id or list of token ids.
|
| 843 |
"""
|
|
@@ -865,7 +984,6 @@ class InternS1Tokenizer(Qwen2Tokenizer):
|
|
| 865 |
def _convert_token_to_id_with_added_voc(self, token, **kwargs):
|
| 866 |
"""
|
| 867 |
Modified from `transformers.tokenization_utils.PreTrainedTokenzier._convert_token_to_id_with_added_voc`.
|
| 868 |
-
|
| 869 |
This adaptation supports domain-specific tokenizers.
|
| 870 |
"""
|
| 871 |
if token is None:
|
|
@@ -878,9 +996,7 @@ class InternS1Tokenizer(Qwen2Tokenizer):
|
|
| 878 |
def _convert_token_to_id(self, token, **kwargs):
|
| 879 |
"""
|
| 880 |
Modified from `transformers.tokenization_utils.PreTrainedTokenzier._convert_token_to_id`.
|
| 881 |
-
|
| 882 |
Converts a token (str) in an id using the vocab.
|
| 883 |
-
|
| 884 |
Fall back to original tokenizer once OOV.
|
| 885 |
"""
|
| 886 |
extra_tokenizer_stack = kwargs.pop("extra_tokenizer_stack", False)
|
|
@@ -978,3 +1094,4 @@ class InternS1Tokenizer(Qwen2Tokenizer):
|
|
| 978 |
|
| 979 |
|
| 980 |
__all__ = ["InternS1Tokenizer"]
|
|
|
|
|
|
| 25 |
import sentencepiece as spm
|
| 26 |
from collections import OrderedDict
|
| 27 |
|
|
|
|
| 28 |
from transformers.tokenization_utils_base import AddedToken, TextInput
|
|
|
|
| 29 |
from transformers.utils import logging
|
| 30 |
+
import transformers
|
| 31 |
+
from packaging import version
|
| 32 |
+
if version.parse(transformers.__version__) >= version.parse("5.0.0"):
|
| 33 |
+
from transformers.tokenization_python import PreTrainedTokenizer
|
| 34 |
+
else:
|
| 35 |
+
from transformers.tokenization_utils import PreTrainedTokenizer
|
| 36 |
|
| 37 |
|
| 38 |
logger = logging.get_logger(__name__)
|
| 39 |
|
| 40 |
try:
|
| 41 |
+
from rdkit import Chem, RDLogger
|
|
|
|
| 42 |
|
| 43 |
RDLogger.DisableLog("rdApp.error")
|
| 44 |
RDLogger.DisableLog("rdApp.*")
|
| 45 |
RDKIT_AVAILABLE = True
|
| 46 |
except ImportError:
|
| 47 |
logger.warning_once(
|
| 48 |
+
"If tokenization with SMILES formula is of necessity, please 'pip install RDKit' for better tokenization quality."
|
| 49 |
)
|
| 50 |
RDKIT_AVAILABLE = False
|
| 51 |
|
|
|
|
| 63 |
class InternS1CheckModuleMixin(ABC):
|
| 64 |
"""
|
| 65 |
Basic auto-detection module.
|
|
|
|
| 66 |
Note that short strings are ignored by this module.
|
| 67 |
"""
|
| 68 |
def __init__(self, *, min_length: int):
|
|
|
|
| 124 |
class FastaCheckModule(InternS1CheckModuleMixin):
|
| 125 |
"""
|
| 126 |
Protein sequence auto-detection module.
|
|
|
|
| 127 |
Automatically detects protein sequence using regex patterns.
|
| 128 |
"""
|
| 129 |
def __init__(self, *, min_length: int = 27):
|
|
|
|
| 161 |
class SmilesCheckModule(InternS1CheckModuleMixin):
|
| 162 |
"""
|
| 163 |
SMILES molecular sequence auto-detection module.
|
|
|
|
| 164 |
Automatically detects and validates SMILES strings in text using regex patterns
|
| 165 |
or chemical syntax rules. Uses RDKit for precise validation when available,
|
| 166 |
otherwise falls back to rule-based validation.
|
|
|
|
| 343 |
return self.check_brackets(text)
|
| 344 |
|
| 345 |
|
| 346 |
+
@lru_cache
|
| 347 |
+
# Copied from transformers.models.gpt2.tokenization_gpt2.bytes_to_unicode
|
| 348 |
+
def bytes_to_unicode():
|
| 349 |
"""
|
| 350 |
+
Returns list of utf-8 byte and a mapping to unicode strings. We specifically avoids mapping to whitespace/control
|
| 351 |
+
characters the bpe code barfs on.
|
| 352 |
+
The reversible bpe codes work on unicode strings. This means you need a large # of unicode characters in your vocab
|
| 353 |
+
if you want to avoid UNKs. When you're at something like a 10B token dataset you end up needing around 5K for
|
| 354 |
+
decent coverage. This is a significant percentage of your normal, say, 32K bpe vocab. To avoid that, we want lookup
|
| 355 |
+
tables between utf-8 bytes and unicode strings.
|
| 356 |
+
"""
|
| 357 |
+
bs = (
|
| 358 |
+
list(range(ord("!"), ord("~") + 1)) + list(range(ord("¡"), ord("¬") + 1)) + list(range(ord("®"), ord("ÿ") + 1))
|
| 359 |
+
)
|
| 360 |
+
cs = bs[:]
|
| 361 |
+
n = 0
|
| 362 |
+
for b in range(2**8):
|
| 363 |
+
if b not in bs:
|
| 364 |
+
bs.append(b)
|
| 365 |
+
cs.append(2**8 + n)
|
| 366 |
+
n += 1
|
| 367 |
+
cs = [chr(n) for n in cs]
|
| 368 |
+
return dict(zip(bs, cs))
|
| 369 |
+
|
| 370 |
+
|
| 371 |
+
# Copied from transformers.models.gpt2.tokenization_gpt2.get_pairs
|
| 372 |
+
def get_pairs(word):
|
| 373 |
+
"""
|
| 374 |
+
Return set of symbol pairs in a word.
|
| 375 |
+
Word is represented as tuple of symbols (symbols being variable-length strings).
|
| 376 |
+
"""
|
| 377 |
+
pairs = set()
|
| 378 |
+
prev_char = word[0]
|
| 379 |
+
for char in word[1:]:
|
| 380 |
+
pairs.add((prev_char, char))
|
| 381 |
+
prev_char = char
|
| 382 |
+
return pairs
|
| 383 |
+
|
| 384 |
|
| 385 |
+
class InternS1Tokenizer(PreTrainedTokenizer):
|
| 386 |
+
"""
|
| 387 |
+
Construct an InternS1 tokenizer. Based on byte-level Byte-Pair-Encoding.
|
| 388 |
Same with GPT2Tokenizer, this tokenizer has been trained to treat spaces like parts of the tokens so a word will
|
| 389 |
be encoded differently whether it is at the beginning of the sentence (without space) or not:
|
|
|
|
| 390 |
```python
|
| 391 |
>>> from transformers import AutoTokenizer
|
|
|
|
| 392 |
>>> tokenizer = AutoTokenizer.from_pretrained("InternS1Tokenizer", trust_remote_code=True)
|
| 393 |
>>> tokenizer("Hello world")["input_ids"]
|
| 394 |
[9707, 1879]
|
|
|
|
| 395 |
>>> tokenizer(" Hello world")["input_ids"]
|
| 396 |
[21927, 1879]
|
| 397 |
```
|
| 398 |
This is expected.
|
|
|
|
| 399 |
Include custom extension to support better domain-specific text tokenization, leveraging a separately trained tokenizer model.
|
| 400 |
Users should refer to this superclass [`PreTrainedTokenizer`] for more information regarding those overloaded methods
|
|
|
|
| 401 |
Args:
|
| 402 |
vocab_file (`str`):
|
| 403 |
Path to the vocabulary file.
|
|
|
|
| 441 |
split_special_tokens=False,
|
| 442 |
**kwargs,
|
| 443 |
):
|
| 444 |
+
bos_token = (
|
| 445 |
+
AddedToken(bos_token, lstrip=False, rstrip=False, special=True, normalized=False)
|
| 446 |
+
if isinstance(bos_token, str)
|
| 447 |
+
else bos_token
|
| 448 |
+
)
|
| 449 |
+
eos_token = (
|
| 450 |
+
AddedToken(eos_token, lstrip=False, rstrip=False, special=True, normalized=False)
|
| 451 |
+
if isinstance(eos_token, str)
|
| 452 |
+
else eos_token
|
| 453 |
+
)
|
| 454 |
+
unk_token = (
|
| 455 |
+
AddedToken(unk_token, lstrip=False, rstrip=False, special=True, normalized=False)
|
| 456 |
+
if isinstance(unk_token, str)
|
| 457 |
+
else unk_token
|
| 458 |
+
)
|
| 459 |
+
pad_token = (
|
| 460 |
+
AddedToken(pad_token, lstrip=False, rstrip=False, special=True, normalized=False)
|
| 461 |
+
if isinstance(pad_token, str)
|
| 462 |
+
else pad_token
|
| 463 |
+
)
|
| 464 |
+
|
| 465 |
+
with open(vocab_file, encoding="utf-8") as vocab_handle:
|
| 466 |
+
self.encoder = json.load(vocab_handle)
|
| 467 |
+
self.decoder = {v: k for k, v in self.encoder.items()}
|
| 468 |
+
self.errors = errors # how to handle errors in decoding
|
| 469 |
+
self.byte_encoder = bytes_to_unicode()
|
| 470 |
+
self.byte_decoder = {v: k for k, v in self.byte_encoder.items()}
|
| 471 |
+
bpe_merges = []
|
| 472 |
+
with open(merges_file, encoding="utf-8") as merges_handle:
|
| 473 |
+
for i, line in enumerate(merges_handle):
|
| 474 |
+
line = line.strip()
|
| 475 |
+
if (i == 0 and line.startswith("#version:")) or not line:
|
| 476 |
+
continue
|
| 477 |
+
bpe_merges.append(tuple(line.split()))
|
| 478 |
+
self.bpe_ranks = dict(zip(bpe_merges, range(len(bpe_merges))))
|
| 479 |
+
# NOTE: the cache can grow without bound and will get really large for long running processes
|
| 480 |
+
# (esp. for texts of language that do not use space between word, e.g. Chinese); technically
|
| 481 |
+
# not a memory leak but appears as one.
|
| 482 |
+
# GPT2Tokenizer has the same problem, so let's be consistent.
|
| 483 |
+
self.cache = {}
|
| 484 |
+
|
| 485 |
+
self.pat = re.compile(PRETOKENIZE_REGEX)
|
| 486 |
+
|
| 487 |
+
if kwargs.get("add_prefix_space", False):
|
| 488 |
+
logger.warning_once(
|
| 489 |
+
f"{self.__class__.__name} does not support `add_prefix_space`, setting it to True has no effect."
|
| 490 |
+
)
|
| 491 |
+
|
| 492 |
self.extra_tokenizer_start_mapping = {}
|
| 493 |
self.extra_tokenizer_end_mapping = {}
|
| 494 |
self._extra_special_tokens = []
|
|
|
|
| 541 |
pad_token=pad_token,
|
| 542 |
clean_up_tokenization_spaces=clean_up_tokenization_spaces,
|
| 543 |
split_special_tokens=split_special_tokens,
|
| 544 |
+
special_tokens_pattern="none",
|
| 545 |
**kwargs,
|
| 546 |
)
|
| 547 |
|
|
|
|
| 579 |
"""Overload method"""
|
| 580 |
return self.vocab_size
|
| 581 |
|
| 582 |
+
# Copied from transformers.models.gpt2.tokenization_gpt2.GPT2Tokenizer.get_vocab
|
| 583 |
+
def get_vocab(self):
|
| 584 |
+
return dict(self.encoder, **self.added_tokens_encoder)
|
| 585 |
+
|
| 586 |
@property
|
| 587 |
def logical_auto_tokens(self):
|
| 588 |
"""Tokens that won't be decoded and only for switching tokenizer"""
|
|
|
|
| 709 |
def tokenize(self, text: TextInput, **kwargs) -> List[str]:
|
| 710 |
"""
|
| 711 |
Converts a string into a sequence of tokens, using the tokenizer.
|
|
|
|
| 712 |
It will switch to domain-specific tokenizer once encountering extra/logical sp tokens.
|
|
|
|
| 713 |
Args:
|
| 714 |
text: TextInput
|
| 715 |
"""
|
|
|
|
| 717 |
|
| 718 |
text, kwargs = self.prepare_for_tokenization(text, **kwargs)
|
| 719 |
|
|
|
|
|
|
|
|
|
|
| 720 |
if hasattr(self, "do_lower_case") and self.do_lower_case:
|
| 721 |
# convert non-special tokens to lowercase. Might be super slow as well?
|
| 722 |
escaped_special_toks = [re.escape(s_tok) for s_tok in (self.all_special_tokens)]
|
|
|
|
| 819 |
def _add_tokens(self, new_tokens: Union[List[str], List[AddedToken]], special_tokens: bool = False) -> int:
|
| 820 |
"""
|
| 821 |
Modified from `transformers.tokenization_utils._add_tokens`.
|
|
|
|
| 822 |
This adaptation supports dynamic tokenizer length due to supplementary tokenizers (e.g., domain-specific or scientific text tokenizers).
|
| 823 |
"""
|
| 824 |
added_tokens = 0
|
|
|
|
| 865 |
self._added_tokens_encoder[token.content] = token_index
|
| 866 |
if self.verbose:
|
| 867 |
logger.info(f"Adding {token} to the vocabulary")
|
| 868 |
+
|
| 869 |
self._update_trie()
|
| 870 |
self._update_total_vocab_size()
|
| 871 |
|
|
|
|
| 878 |
def _tokenize(self, text, **kwargs):
|
| 879 |
"""
|
| 880 |
Modified from `transformers.models.gpt2.tokenization_gpt2.GPT2Tokenizer._tokenize`.
|
|
|
|
| 881 |
This adaptation supports domain-specific tokenizers.
|
| 882 |
"""
|
| 883 |
extra_tokenizer_stack = kwargs.pop("extra_tokenizer_stack", False)
|
|
|
|
| 894 |
else:
|
| 895 |
return self._bpe_tokenize(text)
|
| 896 |
|
| 897 |
+
# Copied from transformers.models.gpt2.tokenization_gpt2.GPT2Tokenizer.bpe
|
| 898 |
+
def bpe(self, token):
|
| 899 |
+
if token in self.cache:
|
| 900 |
+
return self.cache[token]
|
| 901 |
+
word = tuple(token)
|
| 902 |
+
pairs = get_pairs(word)
|
| 903 |
+
|
| 904 |
+
if not pairs:
|
| 905 |
+
return token
|
| 906 |
+
|
| 907 |
+
while True:
|
| 908 |
+
bigram = min(pairs, key=lambda pair: self.bpe_ranks.get(pair, float("inf")))
|
| 909 |
+
if bigram not in self.bpe_ranks:
|
| 910 |
+
break
|
| 911 |
+
first, second = bigram
|
| 912 |
+
new_word = []
|
| 913 |
+
i = 0
|
| 914 |
+
while i < len(word):
|
| 915 |
+
try:
|
| 916 |
+
j = word.index(first, i)
|
| 917 |
+
except ValueError:
|
| 918 |
+
new_word.extend(word[i:])
|
| 919 |
+
break
|
| 920 |
+
else:
|
| 921 |
+
new_word.extend(word[i:j])
|
| 922 |
+
i = j
|
| 923 |
+
|
| 924 |
+
if word[i] == first and i < len(word) - 1 and word[i + 1] == second:
|
| 925 |
+
new_word.append(first + second)
|
| 926 |
+
i += 2
|
| 927 |
+
else:
|
| 928 |
+
new_word.append(word[i])
|
| 929 |
+
i += 1
|
| 930 |
+
new_word = tuple(new_word)
|
| 931 |
+
word = new_word
|
| 932 |
+
if len(word) == 1:
|
| 933 |
+
break
|
| 934 |
+
else:
|
| 935 |
+
pairs = get_pairs(word)
|
| 936 |
+
word = " ".join(word)
|
| 937 |
+
self.cache[token] = word
|
| 938 |
+
return word
|
| 939 |
+
|
| 940 |
def _bpe_tokenize(self, text, **kwargs):
|
| 941 |
text = text.replace(
|
| 942 |
"▁", " "
|
|
|
|
| 952 |
def convert_tokens_to_ids(self, tokens: Union[str, List[str]]) -> Union[int, List[int]]:
|
| 953 |
"""
|
| 954 |
Modified from `transformers.tokenization_utils.PreTrainedTokenzier.convert_tokens_to_ids`.
|
|
|
|
| 955 |
Converts a token string (or a sequence of tokens) in a single integer id (or a sequence of ids), using the
|
| 956 |
vocabulary.
|
|
|
|
| 957 |
This adaptation supports domain-specific tokenizers.
|
|
|
|
| 958 |
Args:
|
| 959 |
tokens (`str` or `List[str]`): One or several token(s) to convert to token id(s).
|
|
|
|
| 960 |
Returns:
|
| 961 |
`int` or `List[int]`: The token id or list of token ids.
|
| 962 |
"""
|
|
|
|
| 984 |
def _convert_token_to_id_with_added_voc(self, token, **kwargs):
|
| 985 |
"""
|
| 986 |
Modified from `transformers.tokenization_utils.PreTrainedTokenzier._convert_token_to_id_with_added_voc`.
|
|
|
|
| 987 |
This adaptation supports domain-specific tokenizers.
|
| 988 |
"""
|
| 989 |
if token is None:
|
|
|
|
| 996 |
def _convert_token_to_id(self, token, **kwargs):
|
| 997 |
"""
|
| 998 |
Modified from `transformers.tokenization_utils.PreTrainedTokenzier._convert_token_to_id`.
|
|
|
|
| 999 |
Converts a token (str) in an id using the vocab.
|
|
|
|
| 1000 |
Fall back to original tokenizer once OOV.
|
| 1001 |
"""
|
| 1002 |
extra_tokenizer_stack = kwargs.pop("extra_tokenizer_stack", False)
|
|
|
|
| 1094 |
|
| 1095 |
|
| 1096 |
__all__ = ["InternS1Tokenizer"]
|
| 1097 |
+
|