huggingface里的tokenizer封装的很麻烦,但是也可以理解,毕竟涉及到的预训练模型太多了。
随便截个图,在src文件夹里,有一堆tokenization开头的文件:
注意所有的tokenization_xx.py都继承了tokenization_utils.py,里面的PreTrainedTokenizer类是所有的tokenizer的基类,有关tokenizer的大部分方法都定义在了PreTrainedTokenizer中,然后再在各个子类中继承和重写。
对于新进来的一对句对,是通过encode_plus方法进行tokenize,然后转化为id,最后和特殊ID拼接成一句话的。这个方法里还包含了好几个方法:
def encode_plus(
self,
text: Union[TextInput, PreTokenizedInput, EncodedInput],
text_pair: Optional[Union[TextInput, PreTokenizedInput, EncodedInput]] = None,
add_special_tokens: bool = True,
max_length: Optional[int] = None,
**kwargs
) -> BatchEncoding:
def get_input_ids(text):
if isinstance(text, str):
# 注意tokenize的过程是在这里实现的,而且tokenize这个方法会被子类重写
# 所以不同预训练模型的tokenize过程是在这里实现的
tokens = self.tokenize(text, add_special_tokens=add_special_tokens, **kwargs)
return self.convert_tokens_to_ids(tokens)
elif isinstance(text, (list, tuple)) and len(text) > 0 and isinstance(text[0], str):
return self.convert_tokens_to_ids(text)
elif isinstance(text, (list, tuple)) and len(text) > 0 and isinstance(text[0], int):
return text
else:
raise ValueError(
"Input is not valid. Should be a string, a list/tuple of strings or a list/tuple of integers."
)
first_ids = get_input_ids(text)
second_ids = get_input_ids(text_pair) if text_pair is not None else None
return self.prepare_for_model(
first_ids,
pair_ids=second_ids,
max_length=max_length,
pad_to_max_length=pad_to_max_length,
add_special_tokens=add_special_tokens,
)
encode_plus 和 prepare_for_model这两个方法子类并不会重写,重写的是tokenize这个方法,因为不同模型的子词切分算法是不一样的。(但是prepare_for_model时拼接的特殊ID会根据模型的不同而不同。