"...git@developer.sourcefind.cn:2222/OpenDAS/vllm_cscc.git" did not exist on "fa3ffb4365e2c2225af06b7935d08ee48d637c6a"
tokenizer.py 7.74 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# coding=utf-8
# Copyright (c) 2020, NVIDIA CORPORATION.  All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Megatron tokenizers."""

17
18
19
20
from abc import ABC, abstractmethod

from colossalai.legacy.context import ParallelMode
from colossalai.legacy.core import global_context as gpc
21
22
23
24
25
26
27

from .bert_tokenization import FullTokenizer as FullBertTokenizer


def build_tokenizer(vocab_file, tokenizer_type, vocab_extra_ids=0):
    """Initialize tokenizer."""
    if not gpc.is_initialized(ParallelMode.GLOBAL) or gpc.get_global_rank() == 0:
28
        print("> building {} tokenizer ...".format(tokenizer_type), flush=True)
29
30

    # Select and instantiate the tokenizer.
31
    if tokenizer_type == "BertWordPieceLowerCase":
32
        tokenizer = _BertWordPieceTokenizer(vocab_file=vocab_file, lower_case=True, vocab_extra_ids=vocab_extra_ids)
33
    elif tokenizer_type == "BertWordPieceCase":
34
        tokenizer = _BertWordPieceTokenizer(vocab_file=vocab_file, lower_case=False, vocab_extra_ids=vocab_extra_ids)
35
    else:
36
        raise NotImplementedError("{} tokenizer is not " "implemented.".format(tokenizer_type))
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

    # Add vocab size.
    padded_vocab_size = _vocab_size_with_padding(tokenizer.vocab_size)

    return tokenizer, padded_vocab_size


def _vocab_size_with_padding(orig_vocab_size, make_vocab_size_divisible_by=128):
    """Pad vocab size so it is divisible by model parallel size and
    still having GPU friendly size."""

    after = orig_vocab_size

    if gpc.is_initialized(ParallelMode.TENSOR):
        multiple = make_vocab_size_divisible_by * gpc.get_world_size(ParallelMode.TENSOR)
    else:
        multiple = make_vocab_size_divisible_by
    while (after % multiple) != 0:
        after += 1
    if not gpc.is_initialized(ParallelMode.GLOBAL) or gpc.get_global_rank() == 0:
57
58
59
60
61
        print(
            " > padded vocab (size: {}) with {} dummy tokens "
            "(new size: {})".format(orig_vocab_size, after - orig_vocab_size, after),
            flush=True,
        )
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
    return after


class AbstractTokenizer(ABC):
    """Abstract class for tokenizer."""

    def __init__(self, name):
        self.name = name
        super().__init__()

    @property
    @abstractmethod
    def vocab_size(self):
        pass

    @property
    @abstractmethod
    def vocab(self):
        """Dictionary from vocab text token to id token."""

    @property
    @abstractmethod
    def inv_vocab(self):
        """Dictionary from vocab id token to text token."""

    @abstractmethod
    def tokenize(self, text):
        pass

    def detokenize(self, token_ids):
92
        raise NotImplementedError("detokenizer is not implemented for {} " "tokenizer".format(self.name))
93
94
95

    @property
    def cls(self):
96
        raise NotImplementedError("CLS is not provided for {} " "tokenizer".format(self.name))
97
98
99

    @property
    def sep(self):
100
        raise NotImplementedError("SEP is not provided for {} " "tokenizer".format(self.name))
101
102
103

    @property
    def pad(self):
104
        raise NotImplementedError("PAD is not provided for {} " "tokenizer".format(self.name))
105
106
107

    @property
    def eod(self):
108
        raise NotImplementedError("EOD is not provided for {} " "tokenizer".format(self.name))
109
110
111

    @property
    def mask(self):
112
        raise NotImplementedError("MASK is not provided for {} " "tokenizer".format(self.name))
113
114
115
116
117
118
119


class _BertWordPieceTokenizer(AbstractTokenizer):
    """Original BERT wordpiece tokenizer."""

    def __init__(self, vocab_file, lower_case=True, vocab_extra_ids=0):
        if lower_case:
120
            name = "BERT Lower Case"
121
        else:
122
            name = "BERT Upper Case"
123
124
        super().__init__(name)
        self.tokenizer = FullBertTokenizer(vocab_file, do_lower_case=lower_case)
125
126
127
128
        self.cls_id = self.tokenizer.vocab["[CLS]"]
        self.sep_id = self.tokenizer.vocab["[SEP]"]
        self.pad_id = self.tokenizer.vocab["[PAD]"]
        self.mask_id = self.tokenizer.vocab["[MASK]"]
129
130
131
        self._additional_special_tokens = []

        # (dsachan) Add BOS and EOS tokens
132
133
        SPECIAL_TOKENS = {"eos_token": "[EOS]", "bos_token": "[BOS]"}
        self._bos_token = "[BOS]"
134
135
136
        self.add_token(self._bos_token)
        self._bos_token_id = self.vocab.get(self._bos_token)

137
        self._eos_token = "[EOS]"
138
139
140
141
142
143
        self.add_token(self._eos_token)
        self._eos_token_id = self.vocab.get(self._eos_token)

        # (dsachan) Add additional special tokens
        # These can be used as sentinel tokens in T5 model inputs
        additional_special_tokens = []
144
        additional_special_tokens.extend(["<extra_id_{}>".format(i) for i in range(vocab_extra_ids)])
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
        self.add_additional_special_tokens(additional_special_tokens)

    def add_token(self, token):
        if token not in self.vocab:
            self.inv_vocab[self.vocab_size] = token
            # self.vocab_size comes from len(vocab)
            # and it will increase as we add elements
            self.vocab[token] = self.vocab_size

    def add_additional_special_tokens(self, tokens_list):
        setattr(self, "additional_special_tokens", tokens_list)
        for value in tokens_list:
            self.add_token(value)

    @property
    def vocab_size(self):
        return self.tokenizer.vocab_size()

    @property
    def vocab(self):
        return self.tokenizer.vocab

    @property
    def inv_vocab(self):
        return self.tokenizer.inv_vocab

    def tokenize(self, text):
        text_tokens = self.tokenizer.tokenize(text)
        return self.tokenizer.convert_tokens_to_ids(text_tokens)

    def decode(self, ids):
        tokens = self.tokenizer.convert_ids_to_tokens(ids)
        return self.tokenizer.convert_tokens_to_string(tokens)

    def decode_token_ids(self, token_ids):
        tokens = self.tokenizer.convert_ids_to_tokens(token_ids)
181
        exclude_list = ["[PAD]", "[CLS]"]
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
        non_pads = [t for t in tokens if t not in exclude_list]

        result = ""
        for s in non_pads:
            if s.startswith("##"):
                result += s[2:]
            else:
                result += " " + s

        return result

    @property
    def cls(self):
        return self.cls_id

    @property
    def sep(self):
        return self.sep_id

    @property
    def pad(self):
        return self.pad_id

    @property
    def mask(self):
        return self.mask_id

    @property
    def bos_token(self):
211
        """Beginning of sentence token id"""
212
213
214
215
        return self._bos_token

    @property
    def eos_token(self):
216
        """End of sentence token id"""
217
218
219
220
        return self._eos_token

    @property
    def additional_special_tokens(self):
221
        """All the additional special tokens you may want to use (list of strings)."""
222
223
224
225
        return self._additional_special_tokens

    @property
    def bos_token_id(self):
226
        """Id of the beginning of sentence token in the vocabulary."""
227
228
229
230
        return self._bos_token_id

    @property
    def eos_token_id(self):
231
        """Id of the end of sentence token in the vocabulary."""
232
233
234
235
        return self._eos_token_id

    @property
    def additional_special_tokens_ids(self):
236
        """Ids of all the additional special tokens in the vocabulary (list of integers)."""
237
238
239
240
241
        return [self.vocab.get(token) for token in self._additional_special_tokens]

    @additional_special_tokens.setter
    def additional_special_tokens(self, value):
        self._additional_special_tokens = value