mwauranjorogekelvin commited on
Commit
8c4821f
·
verified ·
1 Parent(s): ca30ffe

Create utils/tokenizer_base.py

Browse files
Files changed (1) hide show
  1. utils/tokenizer_base.py +113 -0
utils/tokenizer_base.py ADDED
@@ -0,0 +1,113 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from abc import ABC, abstractmethod
2
+ from itertools import groupby
3
+ from typing import List, Optional, Tuple
4
+
5
+ import torch
6
+ from torch import Tensor
7
+ from torch.nn.utils.rnn import pad_sequence
8
+
9
+
10
+ class CharsetAdapter:
11
+ def __init__(self, target_charset) -> None:
12
+ super().__init__()
13
+ self.charset = target_charset
14
+ self.lowercase_only = target_charset == target_charset.lower()
15
+ self.uppercase_only = target_charset == target_charset.upper()
16
+
17
+ def __call__(self, label):
18
+ if self.lowercase_only:
19
+ label = label.lower()
20
+ elif self.uppercase_only:
21
+ label = label.upper()
22
+ return label
23
+
24
+
25
+ class BaseTokenizer(ABC):
26
+ def __init__(self, charset: str, specials_first: tuple = (), specials_last: tuple = ()) -> None:
27
+ self._itos = specials_first + tuple(charset + "[UNK]") + specials_last
28
+ self._stoi = {s: i for i, s in enumerate(self._itos)}
29
+
30
+ def __len__(self):
31
+ return len(self._itos)
32
+
33
+ def _tok2ids(self, tokens: str) -> List[int]:
34
+ return [self._stoi[s] for s in tokens]
35
+
36
+ def _ids2tok(self, token_ids: List[int], join: bool = True) -> str:
37
+ tokens = [self._itos[i] for i in token_ids]
38
+ return "".join(tokens) if join else tokens
39
+
40
+ @abstractmethod
41
+ def encode(self, labels: List[str], device: Optional[torch.device] = None) -> Tensor:
42
+ raise NotImplementedError
43
+
44
+ @abstractmethod
45
+ def _filter(self, probs: Tensor, ids: Tensor) -> Tuple[Tensor, List[int]]:
46
+ raise NotImplementedError
47
+
48
+ def decode(self, token_dists: Tensor, raw: bool = False) -> Tuple[List[str], List[Tensor]]:
49
+ batch_tokens = []
50
+ batch_probs = []
51
+ for dist in token_dists:
52
+ probs, ids = dist.max(-1)
53
+ if not raw:
54
+ probs, ids = self._filter(probs, ids)
55
+ tokens = self._ids2tok(ids, not raw)
56
+ batch_tokens.append(tokens)
57
+ batch_probs.append(probs)
58
+ return batch_tokens, batch_probs
59
+
60
+
61
+ class Tokenizer(BaseTokenizer):
62
+ BOS = "[B]"
63
+ EOS = "[E]"
64
+ PAD = "[P]"
65
+
66
+ def __init__(self, charset: str) -> None:
67
+ specials_first = (self.EOS,)
68
+ specials_last = (self.BOS, self.PAD)
69
+ super().__init__(charset, specials_first, specials_last)
70
+ self.eos_id, self.bos_id, self.pad_id = [
71
+ self._stoi[s] for s in specials_first + specials_last
72
+ ]
73
+
74
+ def encode(self, labels: List[str], device: Optional[torch.device] = None) -> Tensor:
75
+ batch = [
76
+ torch.as_tensor(
77
+ [self.bos_id] + self._tok2ids(y) + [self.eos_id],
78
+ dtype=torch.long,
79
+ device=device,
80
+ )
81
+ for y in labels
82
+ ]
83
+ return pad_sequence(batch, batch_first=True, padding_value=self.pad_id)
84
+
85
+ def _filter(self, probs: Tensor, ids: Tensor) -> Tuple[Tensor, List[int]]:
86
+ ids = ids.tolist()
87
+ try:
88
+ eos_idx = ids.index(self.eos_id)
89
+ except ValueError:
90
+ eos_idx = len(ids)
91
+ ids = ids[:eos_idx]
92
+ probs = probs[:eos_idx + 1]
93
+ return probs, ids
94
+
95
+
96
+ class CTCTokenizer(BaseTokenizer):
97
+ BLANK = "[B]"
98
+
99
+ def __init__(self, charset: str) -> None:
100
+ super().__init__(charset, specials_first=(self.BLANK,))
101
+ self.blank_id = self._stoi[self.BLANK]
102
+
103
+ def encode(self, labels: List[str], device: Optional[torch.device] = None) -> Tensor:
104
+ batch = [
105
+ torch.as_tensor(self._tok2ids(y), dtype=torch.long, device=device)
106
+ for y in labels
107
+ ]
108
+ return pad_sequence(batch, batch_first=True, padding_value=self.blank_id)
109
+
110
+ def _filter(self, probs: Tensor, ids: Tensor) -> Tuple[Tensor, List[int]]:
111
+ ids = list(zip(*groupby(ids.tolist())))[0]
112
+ ids = [x for x in ids if x != self.blank_id]
113
+ return probs, ids