huggingface的tokenizer解读

发布时间:2024年01月01日


前言

目前很多大模型或NLP相关模型可使用huggingface实现,是一个非常好用的集成库,特别是transformer库。而Hugging Face的Tokenizer模块是该平台的重要组成部分,主要用于文本的处理和编码。Tokenizer模块提供了各种先进的文本处理工具,包括分词、编码、解码等功能。本文将以llama模型作为tokenizer列子,介绍tokenizer相关使用内容。


一、huggingface的tokenizer含义

1、含义

Tokenizers are one of the core components of the NLP pipeline. They serve one purpose: to translate text into data that can be processed by the model. Models can only process numbers, so tokenizers need to convert our text inputs to numerical data. In this section, we’ll explore exactly what happens in the tokenization pipeline.
However, models can only process numbers, so we need to find a way to convert the raw text to numbers. That’s what the tokenizers do, and there are a lot of ways to go about this. The goal is to find the most meaningful representation — that is, the one that makes the most sense to the model — and, if possible, the smallest representation.

翻译理解为:Hugging Face的tokenizer是用于将文本转换为模型可以理解的格式的工具。它可以将输入文本分解成ids,并根据模型的要求进行编码。这样可以确保模型能够正确地理解输入并进行处理。也就是说模型只能加工数字,toknizer就是处理文本到数字过程。不同模型有不同tokenizer表示。我将以小羊驼语言模型作为列子说明。

直白理解:处理文本能被模型处理的输入格式。

官网解释链接:https://huggingface.co/learn/nlp-course/chapter2/4?fw=pt

2、整体概括

其主要内容可以总结如下:

Tokenization(分词):Tokenizer模块支持多种语言的分词器,能够将输入的文本分割成单词、子词或字符,为后续的处理和编码做准备。这对于不同NLP任务来说非常重要,因为文本的分割方式直接影响到模型的输入表示。

编码和解码:Tokenizer能够将文本转换成模型可接受的输入编码,并能够将模型输出的编码解码成可读的文本。这对于使用预训练模型进行推理和生成任务非常关键。

特殊标记处理:Tokenizer能够处理特殊标记,如掩码标记(mask token)、分隔标记(separator token)等,这些标记在不同的NLP任务中扮演着重要的角色。

多种预训练模型支持:Tokenizer模块支持多种预训练模型,包括BERT、GPT、LLMA等,用户可以根据自己的需求选择合适的模型和相应的Tokenizer进行文本处理。

总之,Hugging Face的Tokenizer模块为用户提供了强大而灵活的文本处理工具,能够满足各种NLP任务对于文本处理的需求,并与Hugging Face平台上的其他模块无缝集成,为NLP研究和开发提供了便利。

二、加载lmsys/vicuna-7b-v1.5模型的tokenizer

huggingface最强大库的transformer,内有很多语言模型,也提供了很简单操作可实现tokenizer,你只需在官网下载对应模型库文件,然后使用对应包.from_pretrained(模型文件夹地址)

代码如下:

from transformers import LlamaTokenizer
def llama2_tokenizer(tokenizer_path, signal_type="base"):
    tokenizer = LlamaTokenizer.from_pretrained(tokenizer_path)
    # 向tokenizer中添加变量与值
    if tokenizer.pad_token_id is None:
        tokenizer.pad_token_id = 32000
    tokenizer.boi = "[IMG]"
    tokenizer.eoi = "[/IMG]"
    assert signal_type in ["base", "chat", "vqa", "chat_old"]
    tokenizer.signal_type = signal_type
    return tokenizer

以上实现基于llma模型的tokenizer方法调用,实际是文本转模型识别数字的一些包装。当然,你也可参考映射map方法博客点击这里

三、调用tokernizer方法

下载好对应文件权重如下格式:
在这里插入图片描述
在二中实现加载tokenizer方式,在使用如下代码给出tokenizer,如下:

    llama_path = '/home/lmsys/vicuna-7b-v1.5'
    tokenizer = llama2_tokenizer(llama_path)

四、字符串的tokens应用

1、tokenizer应用

直接使用tokenizer方法,可返回input_ids与attention_mask,这里attention_mask表示每个文本对应位置值,若有文本词则为1否则为0,后面我会进一步说明。

    text = 'It is a nice day'
    t=tokenizer(text)
    print(t)
    t = tokenizer(['It is a nice day', 'nice day'])
    print(t)

结果如下:

第一个输出值为一个文本:
{'input_ids': [1, 739, 338, 263, 7575, 2462], 'attention_mask': [1, 1, 1, 1, 1, 1]}
第二个输出值为文本列表:
{'input_ids': [[1, 739, 338, 263, 7575, 2462], [1, 7575, 2462]], 'attention_mask': [[1, 1, 1, 1, 1, 1], [1, 1, 1]]}

当然,不同模型的tokenizer会多一些值,如官网返回值:

{'input_ids': [101, 7993, 170, 11303, 1200, 2443, 1110, 3014, 102],
 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0],
 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]}

2、tokenizer进行token分词(tokenizer.tokenize)

使用tokenizer.tokenize可输出字符串列表或叫token,官网解释The output of this method is a list of strings, or tokens,其代码如下:

    text = 'It is a nice day'
    # tokenize,#仅用于分词
    tokens = tokenizer.tokenize(text)
    print("token分词结果:\n", tokens)

结果如下:

 ['▁It', '▁is', '▁a', '▁nice', '▁day']

实际是对文本text进行分词方法,完成了分词就能找到对应数字,也就是模型能识别的数字了。

3、tokens转模型识别ids(tokenizer.convert_tokens_to_ids)

使用tokenizer.convert_tokens_to_ids将token转成模型识别ids,官网解释The conversion to input IDs is handled by the convert_tokens_to_ids() tokenizer method:,其代码如下:

    # convert_tokens_to_ids,将token转化成ids,在分词之后,
    ids = tokenizer.convert_tokens_to_ids(tokens)
    print("tokens Ids:\n", ids)

结果如下:

 [739, 338, 263, 7575, 2462]

输出转为张量结构,模型可输入数字,实际是文本text分词后找映射数字。

注:映射数字id只对应分词,无开始和结束id

4、ids转token(tokenizer.convert_ids_to_token)

应用ids转回token,需要根据对应模型,有的模型提供可直接使用,若没有提供则不需要使用。恰好llama为提供该转换方法。

    # convert_ids_to_tokens,将id转化成token,通常用于模型预测出结果,查看时使用。
    tokens = tokenizer.convert_ids_to_token(ids)
    print("tokenize Id2token:\n", tokens)

五、tokenizer的decode应用(tokenizer.decode)

使用tokenizer.decode将token转成模型的ids,官网解释The conversion to input IDs is handled by the convert_tokens_to_ids() tokenizer method:,其代码如下:

    # ids映射回原来文本内容
    decoded_string = tokenizer.decode(ids)
    print('ids2text', decoded_string)

结果如下:

 [739, 338, 263, 7575, 2462]

实际是文本text分词后找映射数字。

注:映射数字id只对应分词,无开始和结束id

六、tokenizer的encode应用

1、tokenizer的tokenizer.encode

使用tokenizer.encode将文本转为对应ids,其代码如下:

    #  encode,进行分词和token转换,encode=tokenize+convert_tokens_to_ids
    encode_num = tokenizer.encode(text)
    print("text=",text)
    print('encode=', encode_num)
    decoded_string = tokenizer.decode(encode_num)
    print('decode=', decoded_string)

结果如下:

text= It is a nice day
encode= [1, 739, 338, 263, 7575, 2462]
decoded_string= <s> It is a nice day

可看出输出多了文字,这个应该是模型需要的,类似seq

2、tokenizer的tokenizer.encode_plus

将encode的输出变成input_ids变量,其值完全不变,且多出attention_mask变量,也会根据模型方法会多出其它变量,其代码如下:

    # encode_plus,在encode的基础之上生成input_ids、token_type_ids、attention_mask
    encode_plus_text = tokenizer.encode_plus(text)
    print("验证encode_plus编码\nencode_plus=", encode_plus_text)

结果如下:


encode_plus= {'input_ids': [1, 739, 338, 263, 7575, 2462], 'attention_mask': [1, 1, 1, 1, 1, 1]}

在encode基础上多了attention_mask内容,有的模型会提供一些其它多余输出结果(如:token_type_ids)。

3、tokenizer的tokenizer.batch_encode_plus

a、tokenizer.batch_encode_plus函数含义

tokenizer.batch_encode_plus函数用于批量对文本进行编码处理,它可以同时处理多个文本,并提供填充、截断、返回张量类型等选项。

texts: 待编码的文本列表
return_tensors: 指定返回的张量类型,如'tensor''pt'
padding: 是否对文本进行填充
truncation: 是否对文本进行截断
max_length: 最大长度限制
return_attention_mask: 是否返回注意力掩码张量

b、tokenizer.batch_encode_plus使用方法

    batch_encode_plus = tokenizer.batch_encode_plus(text_batch, max_length=10, padding='max_length', truncation='longest_first')  # 长的截,短的补
    print("验证batch_encode_plus编码\nbatch_encode_plus=", batch_encode_plus)

c、tokenizer.batch_encode_plus运行结果

batch_encode_plus= {'input_ids': [[1, 739, 338, 263, 7575, 2462, 0, 0, 0, 0], [1, 7575, 2462, 0, 0, 0, 0, 0, 0, 0]], 'attention_mask': [[1, 1, 1, 1, 1, 1, 0, 0, 0, 0], [1, 1, 1, 0, 0, 0, 0, 0, 0, 0]]}

七、完整代码

from transformers import LlamaTokenizer
def llama2_tokenizer(tokenizer_path, signal_type="base"):
    tokenizer = LlamaTokenizer.from_pretrained(tokenizer_path)
    # 向tokenizer中添加变量与值
    if tokenizer.pad_token_id is None:
        tokenizer.pad_token_id = 32000
    tokenizer.boi = "[IMG]"
    tokenizer.eoi = "[/IMG]"
    assert signal_type in ["base", "chat", "vqa", "chat_old"]
    tokenizer.signal_type = signal_type
    return tokenizer


def tokenizer_tutor():
    llama_path = '/extend_disk/tj/CogVLM-main/lmsys/vicuna-7b-v1.5'
    tokenizer = llama2_tokenizer(llama_path)
    text_batch = ['It is a nice day', 'nice day']
    text = 'It is a nice day'
    
    t=tokenizer(text)
    print(t)
    t = tokenizer(text_batch)
    print(t)

    # tokenize,#仅用于分词
    tokens = tokenizer.tokenize(text)
    print("token分词结果:\n", tokens)
    
    # convert_tokens_to_ids,将token转化成ids,在分词之后,
    ids = tokenizer.convert_tokens_to_ids(tokens)
    print("tokens Ids:\n", ids)

    # # convert_ids_to_tokens,将id转化成token,通常用于模型预测出结果,查看时使用。
    # tokens = tokenizer.convert_ids_to_token(ids)
    # print("tokenize Id2token:\n", tokens)

    # ids映射回原来文本内容
    decoded_string = tokenizer.decode(ids)
    print('decode=', decoded_string)

    #  encode,进行分词和token转换,encode=tokenize+convert_tokens_to_ids
    encode_num = tokenizer.encode(text)
    print("验证encode编码\ntext=",text)
    print('encode=', encode_num)
    decoded_string = tokenizer.decode(encode_num)
    print('decoded_string=', decoded_string)

    # encode_plus,在encode的基础之上生成input_ids、token_type_ids、attention_mask
    encode_plus_text = tokenizer.encode_plus(text)
    print("验证encode_plus编码\nencode_plus=", encode_plus_text)

    batch_encode_plus = tokenizer.batch_encode_plus(text_batch, max_length=10, padding='max_length', truncation='longest_first')  # 长的截,短的补
    print("验证batch_encode_plus编码\nbatch_encode_plus=", batch_encode_plus)

if __name__ == '__main__':
    tokenizer_tutor()

文章来源:https://blog.csdn.net/weixin_38252409/article/details/135286461
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。