stanrom/internlm-xcomposer2-7b-4bit
037
1# Copyright (c) InternLM. All rights reserved.2#3# This code is based on EleutherAI's GPT-NeoX library and the GPT-NeoX4# and OPT implementations in this library. It has been modified from its5# original forms to accommodate minor architectural differences compared6# to GPT-NeoX and OPT used by the Meta AI team that trained the model.7#8# Licensed under the Apache License, Version 2.0 (the "License");9# you may not use this file except in compliance with the License.10# You may obtain a copy of the License at11#12# http://www.apache.org/licenses/LICENSE-2.013#14# Unless required by applicable law or agreed to in writing, software15# distributed under the License is distributed on an "AS IS" BASIS,16# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.17# See the License for the specific language governing permissions and18# limitations under the License.19"""Tokenization classes for IntermLM."""20import os21from shutil import copyfile22from typing import Any, Dict, List, Optional, Tuple23 24import sentencepiece as spm25from transformers.tokenization_utils import PreTrainedTokenizer26from transformers.utils import logging27 28logger = logging.get_logger(__name__)29 30VOCAB_FILES_NAMES = {'vocab_file': './tokenizer.model'}31 32PRETRAINED_VOCAB_FILES_MAP = {}33 34 35class InternLMXComposer2Tokenizer(PreTrainedTokenizer):36 """Construct a InternLM tokenizer. Based on byte-level Byte-Pair-Encoding.37 38 Args:39 vocab_file (`str`):40 Path to the vocabulary file.41 """42 43 vocab_files_names = VOCAB_FILES_NAMES44 pretrained_vocab_files_map = PRETRAINED_VOCAB_FILES_MAP45 model_input_names = ['input_ids', 'attention_mask']46 _auto_class = 'AutoTokenizer'47 48 def __init__(49 self,50 vocab_file,51 unk_token='<unk>',52 bos_token='<s>',53 eos_token='</s>',54 pad_token='</s>',55 sp_model_kwargs: Optional[Dict[str, Any]] = None,56 add_bos_token=True,57 add_eos_token=False,58 decode_with_prefix_space=False,59 clean_up_tokenization_spaces=False,60 **kwargs,61 ):62 self.sp_model_kwargs = {} if sp_model_kwargs is None else sp_model_kwargs63 self.vocab_file = vocab_file64 self.add_bos_token = add_bos_token65 self.add_eos_token = add_eos_token66 self.decode_with_prefix_space = decode_with_prefix_space67 self.sp_model = spm.SentencePieceProcessor(**self.sp_model_kwargs)68 self.sp_model.Load(vocab_file)69 self._no_prefix_space_tokens = None70 super().__init__(71 bos_token=bos_token,72 eos_token=eos_token,73 unk_token=unk_token,74 pad_token=pad_token,75 clean_up_tokenization_spaces=clean_up_tokenization_spaces,76 **kwargs,77 )78 """ Initialization"""79 80 @property81 def no_prefix_space_tokens(self):82 if self._no_prefix_space_tokens is None:83 vocab = self.convert_ids_to_tokens(list(range(self.vocab_size)))84 self._no_prefix_space_tokens = {85 i86 for i, tok in enumerate(vocab) if not tok.startswith('▁')87 }88 return self._no_prefix_space_tokens89 90 @property91 def vocab_size(self):92 """Returns vocab size."""93 return self.sp_model.get_piece_size()94 95 @property96 def bos_token_id(self) -> Optional[int]:97 return self.sp_model.bos_id()98 99 @property100 def eos_token_id(self) -> Optional[int]:101 return self.sp_model.eos_id()102 103 def get_vocab(self):104 """Returns vocab as a dict."""105 vocab = {106 self.convert_ids_to_tokens(i): i107 for i in range(self.vocab_size)108 }109 vocab.update(self.added_tokens_encoder)110 return vocab111 112 def _tokenize(self, text):113 """Returns a tokenized string."""114 return self.sp_model.encode(text, out_type=str)115 116 def _convert_token_to_id(self, token):117 """Converts a token (str) in an id using the vocab."""118 return self.sp_model.piece_to_id(token)119 120 def _convert_id_to_token(self, index):121 """Converts an index (integer) in a token (str) using the vocab."""122 token = self.sp_model.IdToPiece(index)123 return token124 125 def _maybe_add_prefix_space(self, tokens, decoded):126 if tokens and tokens[0] not in self.no_prefix_space_tokens:127 return ' ' + decoded128 else:129 return decoded130 131 def convert_tokens_to_string(self, tokens):132 """Converts a sequence of tokens (string) in a single string."""133 current_sub_tokens = []134 out_string = ''135 prev_is_special = False136 for token in tokens:137 # make sure that special tokens are not decoded using sentencepiece model138 if token in self.all_special_tokens:139 if not prev_is_special:140 out_string += ' '141 out_string += self.sp_model.decode(current_sub_tokens) + token142 prev_is_special = True143 current_sub_tokens = []144 else:145 current_sub_tokens.append(token)146 prev_is_special = False147 out_string += self.sp_model.decode(current_sub_tokens)148 out_string = self.clean_up_tokenization(out_string)149 out_string = self._maybe_add_prefix_space(150 tokens=tokens, decoded=out_string)151 return out_string[1:]152 153 def save_vocabulary(self,154 save_directory,155 filename_prefix: Optional[str] = None) -> Tuple[str]:156 """Save the vocabulary and special tokens file to a directory.157 158 Args:159 save_directory (`str`):160 The directory in which to save the vocabulary.161 162 Returns:163 `Tuple(str)`: Paths to the files saved.164 """165 if not os.path.isdir(save_directory):166 logger.error(167 f'Vocabulary path ({save_directory}) should be a directory')168 return169 out_vocab_file = os.path.join(170 save_directory,171 (filename_prefix + '-' if filename_prefix else '') +172 VOCAB_FILES_NAMES['vocab_file'])173 174 if os.path.abspath(self.vocab_file) != os.path.abspath(175 out_vocab_file) and os.path.isfile(self.vocab_file):176 copyfile(self.vocab_file, out_vocab_file)177 elif not os.path.isfile(self.vocab_file):178 with open(out_vocab_file, 'wb') as fi:179 content_spiece_model = self.sp_model.serialized_model_proto()180 fi.write(content_spiece_model)181 182 return (out_vocab_file, )183 184 def build_inputs_with_special_tokens(self, token_ids_0, token_ids_1=None):185 if self.add_bos_token:186 bos_token_ids = [self.bos_token_id]187 else:188 bos_token_ids = []189 190 output = bos_token_ids + token_ids_0191 192 if token_ids_1 is not None:193 output = output + token_ids_1194 195 if self.add_eos_token:196 output = output + [self.eos_token_id]197 198 return output199 200 def get_special_tokens_mask(201 self,202 token_ids_0: List[int],203 token_ids_1: Optional[List[int]] = None,204 already_has_special_tokens: bool = False) -> List[int]:205 """Retrieve sequence ids from a token list that has no special tokens206 added. This method is called when adding special tokens using the207 tokenizer `prepare_for_model` method.208 209 Args:210 token_ids_0 (`List[int]`):211 List of IDs.212 token_ids_1 (`List[int]`, *optional*):213 Optional second list of IDs for sequence pairs.214 already_has_special_tokens (`bool`, *optional*, defaults to `False`):215 Whether or not the token list is already formatted with special tokens for the model.216 217 Returns:218 `List[int]`: A list of integers in the range [0, 1]: 1 for a special token, 0 for a sequence token.219 """220 if already_has_special_tokens:221 return super().get_special_tokens_mask(222 token_ids_0=token_ids_0,223 token_ids_1=token_ids_1,224 already_has_special_tokens=True)225 226 if token_ids_1 is None:227 return [1] + ([0] * len(token_ids_0)) + [1]228 return [1] + ([0] * len(token_ids_0)) + [1, 1] + (229 [0] * len(token_ids_1)) + [1]230 231 def create_token_type_ids_from_sequences(232 self,233 token_ids_0: List[int],234 token_ids_1: Optional[List[int]] = None) -> List[int]:235 """Create a mask from the two sequences passed to be used in a236 sequence-pair classification task. T5 does not make use of token type237 ids, therefore a list of zeros is returned.238 239 Args:240 token_ids_0 (`List[int]`):241 List of IDs.242 token_ids_1 (`List[int]`, *optional*):243 Optional second list of IDs for sequence pairs.244 245 Returns:246 `List[int]`: List of zeros.247 """248 eos = [self.eos_token_id]249 250 if token_ids_1 is None:251 return len(token_ids_0 + eos) * [0]252 return len(token_ids_0 + eos + token_ids_1 + eos) * [0]253 