【问题标题】:BertWordPieceTokenizer vs BertTokenizer from HuggingFaceHuggingFace 的 BertWordPieceTokenizer 与 BertTokenizer
【发布时间】:2020-10-05 20:44:58
【问题描述】:

我有以下代码片段,并试图了解 BertWordPieceTokenizer 和 BertTokenizer 之间的区别。

BertWordPieceTokenizer(基于 Rust)

from tokenizers import BertWordPieceTokenizer

sequence = "Hello, y'all! How are you Tokenizer ???? ?"
tokenizer = BertWordPieceTokenizer("bert-base-uncased-vocab.txt")
tokenized_sequence = tokenizer.encode(sequence)
print(tokenized_sequence)
>>>Encoding(num_tokens=15, attributes=[ids, type_ids, tokens, offsets, attention_mask, special_tokens_mask, overflowing])

print(tokenized_sequence.tokens)
>>>['[CLS]', 'hello', ',', 'y', "'", 'all', '!', 'how', 'are', 'you', 'token', '##izer', '[UNK]', '?', '[SEP]']

BertTokenizer

from transformers import BertTokenizer
tokenizer = BertTokenizer("bert-base-cased-vocab.txt")
tokenized_sequence = tokenizer.encode(sequence)
print(tokenized_sequence)
#Output: [19082, 117, 194, 112, 1155, 106, 1293, 1132, 1128, 22559, 17260, 100, 136]
  1. 为什么编码在两者中的工作方式不同?在 BertWordPieceTokenizer 中,它提供 Encoding 对象,而在 BertTokenizer 中,它提供 vocab 的 id。
  2. BertWordPieceTokenizer 和 BertTokenizer 从根本上来说有什么区别,因为据我了解,BertTokenizer 也在后台使用 WordPiece。

谢谢

【问题讨论】:

    标签: nlp huggingface-transformers bert-language-model huggingface-tokenizers


    【解决方案1】:

    当您使用相同的词汇表时,它们应该产生相同的输出(在您的示例中,您使用了 bert-base-uncased-vocab.txt 和 bert-base-cased-vocab.txt)。主要区别在于 tokenizers 包中的标记器比 transformers 中的标记器更快,因为它们是在 Rust 中实现的。

    当您修改示例时,您会看到它们产生了相同的 ids 和其他属性(编码对象),而转换器标记器仅产生了 ids 的列表:

    from tokenizers import BertWordPieceTokenizer
    
    sequence = "Hello, y'all! How are you Tokenizer ? ?"
    tokenizerBW = BertWordPieceTokenizer("/content/bert-base-uncased-vocab.txt")
    tokenized_sequenceBW = tokenizerBW.encode(sequence)
    print(tokenized_sequenceBW)
    print(type(tokenized_sequenceBW))
    print(tokenized_sequenceBW.ids)
    

    输出:

    Encoding(num_tokens=15, attributes=[ids, type_ids, tokens, offsets, attention_mask, special_tokens_mask, overflowing])
    <class 'Encoding'>
    [101, 7592, 1010, 1061, 1005, 2035, 999, 2129, 2024, 2017, 19204, 17629, 100, 1029, 102]
    
    from transformers import BertTokenizer
    
    tokenizerBT = BertTokenizer("/content/bert-base-uncased-vocab.txt")
    tokenized_sequenceBT = tokenizerBT.encode(sequence)
    print(tokenized_sequenceBT)
    print(type(tokenized_sequenceBT))
    

    输出:

    [101, 7592, 1010, 1061, 1005, 2035, 999, 2129, 2024, 2017, 19204, 17629, 100, 1029, 102]
    <class 'list'>
    

    您在 cmets 中提到您的问题更多是关于为什么产生的输出不同。据我所知,这是开发人员做出的设计决定,没有具体原因。 tokenizers 的 BertWordPieceTokenizer 也不是 transformers 的 BertTokenizer 的就地替代品。他们仍然使用包装器使其与transformers tokenizer API 兼容。有一个 BertTokenizerFast 类具有“清理”方法 _convert_encoding 以使 BertWordPieceTokenizer 完全兼容。因此,您必须将上面的 BertTokenizer 示例与以下内容进行比较:

    from transformers import BertTokenizerFast
    
    sequence = "Hello, y'all! How are you Tokenizer ? ?"
    tokenizerBW = BertTokenizerFast.from_pretrained("bert-base-uncased")
    tokenized_sequenceBW = tokenizerBW.encode(sequence)
    print(tokenized_sequenceBW)
    print(type(tokenized_sequenceBW))
    

    输出:

    [101, 7592, 1010, 1061, 1005, 2035, 999, 2129, 2024, 2017, 19204, 17629, 100, 1029, 102]
    <class 'list'>
    

    在我看来,他们已经独立于 transformers 库构建了 tokenizers 库,目标是快速和有用。

    【讨论】:

    • 这很好地抓住了我的一个错误。但是,参考您的代码,我的问题更多是关于为什么 tokenizerBT.encode(sequence) 在 BT 的情况下给出令牌,而在 BWPT 的情况下我们必须做 tokenizerBW.encode(sequence).ids 来获取令牌。是否只是不同实现的一种情况...肯定会混淆一个 tokenizerBT.encode 直接给出令牌,但在 BWPT 的情况下它不会这样做
    • 抱歉,我一开始没有把它读出来。我已经扩展了我的答案来解决这个问题。
    猜你喜欢
    • 2020-11-18
    • 1970-01-01
    • 2021-07-03
    • 2021-11-02
    • 2021-07-16
    • 1970-01-01
    • 2021-12-17
    • 1970-01-01
    • 2021-10-27
    相关资源
    最近更新 更多