transformers源码1】AutoTokenizer 详解

概述

最近研究了一下 transformers 的源码,通过 debug 的方式一步步调试代码,了解了transformers 加载模型的完整流程。本文将根据自己的调试过程详细介绍 transformers 加载模型的原理,接下来我将分成下面几个部分介绍 transformers 源码:

  • AutoTokenizer 详解
  • AutoModelForCausalLM 详解
  • Trainer 详解

本文是transformers源码的第一篇 -- AutoTokenizer 详解, 通过本文的学习,你将有如下收获:

  • 了解 AutoTokenizer 如何自动加载 tokenizer
  • 了解 tokenizer 如何进行编码(encode)
  • 了解 tokenizer 如何进行解码(decode)
  • 了解 tokenizer 如何使用对话模板(chat_template)
  • 了解如何自定义 tokenizer 并集成到 transformers 中

在介绍具体内容之前,先说明一下本文的讲解思路,我将以 Qwen/Qwen-7B 进行讲解,为什么选择 Qwen-7B,因为其在模型文件目录中自定义了 tokenization_qwen.pymodeling_qwen.py 文件,也就是说它没有将 tokenizer 和 model 的加载集成到 transformers 框架中,这样的话可以帮助我们理解如何自定义 tokenizer 和 model,当我们了解了 tokenizer 的自定义加载过程,也就很容易实现将自定义的加载过程集成到 transformers 框架中。

本文将从 huggingface 中的 Qwen/Qwen-7B 的快速使用代码为入口进行调试讲解,快速开始的代码示例如下:

python 复制代码
from transformers import AutoModelForCausalLM, AutoTokenizer
from transformers.generation import GenerationConfig

# Note: The default behavior now has injection attack prevention off.
tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen-7B", trust_remote_code=True)

# use bf16
# model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen-7B", device_map="auto", trust_remote_code=True, bf16=True).eval()
# use fp16
# model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen-7B", device_map="auto", trust_remote_code=True, fp16=True).eval()
# use cpu only
# model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen-7B", device_map="cpu", trust_remote_code=True).eval()
# use auto mode, automatically select precision based on the device.
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen-7B", device_map="auto", trust_remote_code=True).eval()

# Specify hyperparameters for generation. But if you use transformers>=4.32.0, there is no need to do this.
# model.generation_config = GenerationConfig.from_pretrained("Qwen/Qwen-7B", trust_remote_code=True)

inputs = tokenizer('蒙古国的首都是乌兰巴托(Ulaanbaatar)\n冰岛的首都是雷克雅未克(Reykjavik)\n埃塞俄比亚的首都是', return_tensors='pt')
inputs = inputs.to(model.device)
pred = model.generate(**inputs)
print(tokenizer.decode(pred.cpu()[0], skip_special_tokens=True))
# 蒙古国的首都是乌兰巴托(Ulaanbaatar)\n冰岛的首都是雷克雅未克(Reykjavik)\n埃塞俄比亚的首都是亚的斯亚贝巴(Addis Ababa)...

transformers 懒加载原理

首先将 Qwen-7B 下载到本地,由于在国内访问 huggingface 比较慢,可以通过 modelscope下载对应的模型,这里我已经将模型下载到了本地,然后通过下面的代码进行调试:

python 复制代码
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("/Users/xiniao/models/Qwen/Qwen-7B", trust_remote_code=True)

当执行 from transformers import AutoTokenizer 这行代码时,导入包的顺序如下:

  1. Python 首先会解析 transformers 这个模块的路径,找到对应的模块文件。如果我们通过 pip install transformers 安装,所以会在python安装目录下的 site-packages包中找到 transformers 包;如果下载 transformers 源码,然后通过 pip install -e .安装,则会从本地的 transformers 路径中找到 transformers 包(可以通 sys.path 查看包路径)。

  2. 然后 Python 会执行 transformers 模块的代码,这包括执行该包下的__init__.py文件初始化操作、执行一些代码,以及定义相关的类和函数。

  3. 最后 Python 会从 transformers 模块中导入 AutoTokenizer 对象,并将其添加到当前模块的命名空间中,使得在当前模块中可以直接使用 AutoTokenizer

Python 基础知识

在Python中当导入一个包时,会执行该包下的__init__.py文件。这是因为在Python中,目录下如果包含了__init__.py文件,Python就会将这个目录视为一个包,而不仅仅是一个普通的目录。

init.py文件的主要作用有以下几个方面:

  1. 定义包的初始化内容:init.py中可以包含一些初始化的代码,比如定义包的公共变量、常量、函数等,确保在导入包的时候能够进行一些初始化操作。

  2. 控制包的导入行为:init.py文件可以用来控制包的导入行为,可以在其中定义__all__变量来控制在使用import *时导入的内容,也可以在其中进行一些导入时的特殊处理。

  3. 作为包的标识:init.py文件的存在表示该目录是一个包,有助于Python解释器正确识别和处理包的导入。

所以,当导入一个包时,Python会首先执行该包下的__init__.py文件,以便进行一些初始化操作,并标识该目录为一个包。

查看 transformers 源码,在 __init__.py 文件中,有如下代码:

python 基础知识

当使用 import 语句导入模块时,Python会按照以下步骤检查 sys.modules 中是否已经存在对应的模块:

  1. 首先,Python会根据 import 语句中指定的模块名在 sys.modules 中查找对应的键。如果该模块名已经存在于 sys.modules 中,说明该模块已经被导入过了。

  2. 如果找到了对应的模块名,Python会直接使用 sys.modules 中已经缓存的模块对象,而不会重新导入模块。

  3. 如果未找到对应的模块名,Python会继续执行模块的实际导入操作,并在导入完成后将模块对象添加到 sys.modules 中,以便后续的导入操作可以直接使用缓存的模块对象。

总之,当使用 import 语句导入模块时,Python会先在 sys.modules 中检查是否已经存在对应的模块名,如果存在则直接使用缓存的模块对象,否则才会进行模块的实际导入操作。这个机制可以提高模块导入的效率,并避免重复导入相同的模块。

因为在__init__.py文件中设置了 sys.modules,所以会从 _LazyModule 中导入对应的模块,接下来看一下_LazyModule是如何根据名称导入模块的,核心代码如下:

python 基础知识

在Python中,调用 getattr() 函数不会直接触发 __getattr__ 方法的调用,因为这两者是不同的概念。getattr() 函数用于获取对象的属性值,而 __getattr__ 方法用于处理对象属性的访问行为。

然而,在一些情况下,通过 getattr() 获取对象的属性时,如果该属性不存在,会间接触发 __getattr__ 方法的调用。具体来说,当使用 getattr() 获取对象的属性时,如果该属性不存在,Python 会尝试从对象的 __getattr__ 方法中查找该属性。

下面是一个示例说明了这种情况:

python 复制代码
class Example:

def __getattr__(self, name):

print(f'Attribute {name} is not found')

obj = Example()

getattr(obj, 'attribute1') # 调用getattr()获取对象属性,会触发__getattr__方法的调用

在上面的示例中,由于attribute1属性不存在,getattr(obj, 'attribute1') 会触发Example类中的 __getattr__ 方法,并输出 Attribute attribute1 is not found

因此,尽管 getattr() 函数本身并不直接触发 __getattr__ 方法的调用,但在获取对象的属性时,如果该属性不存在,Python 会尝试从对象的 __getattr__ 方法中查找该属性,从而间接触发 __getattr__ 方法的调用。

我们看一下 auto 包中的__init__.py文件做了什么,如下图所示:

在 auto 包中的 init .py 文件中定义了一个 _import_structure 字典,该字典的key对应 auto 包下面的 python 文件名(模块名),字典的 value 对应 python 文件中定义的变量名、函数名、类名,这个字典是用来实现 python 的懒加载的,也就是在python运行过程中可以根据名称导入对应的模块,在后面将详细介绍如何实现的。

通过前面的介绍,总结一下 from transformers import AutoTokenizer 是如何通过懒加载的方式导入 AutoTokenizer。当从 transformers 模块中导入AutoTokenizer的时候,会从 sys.modules字典中找 key 为 transformers 的模块,因为在 transformers 包的 __init__.py 文件中设置了 sys.modules['transformers'] = _LazyModule并且将懒加载的字典 _import_structure 作为参数传入给_LazyModule中,所以导入AutoTokenizer时会调用 _LazyModule__getattr__(name)方法,传入的name ='AutoTokenizer', 执行__getattr__(name)方法会从 import_structure 字典配置中找到 AutoTokenizer对应的模块名 models.auto,然后通过 importlib.import_module("." + module_name, self.__name__) 方式导入 transformers.models.auto 模块,在使用importlib.import_module导入模块时会执行 transformers.models.auto 模块中的 __init__.py 代码,和 transformers 模块中的 __init__.py 类似,会将 transformers.models.auto 模块设置到 sys.modules 中,导入模块后会调用 getattr(module, name) 获取 transformers.models.auto 的属性 AutoTokenizer,如果获取不到,则会继续调用 __getattr__(name) 方法从 transformers.models.auto模块的 __init__.py 文件中配置的 _import_structure字典中找到 AutoTokenizer对应的模块 tokenization_auto,再次通过importlib.import_module("." + module_name, self.__name__)导入transformers.models.auto模块中 tokenization_auto模块,再次调用 getattr(module, name)获取tokenization_auto模块中 AutoTokenizer类,这次可以获取到了,则将 AutoTokenizer类通过 setattr(self, name, value)方法设置到 transformersAutoTokenizer属性中,最后返回从 transfomers.auto.models.tokenization_auto中导入的 AutoTokenizer类。

用一个简单的流程图描述一下上面的过程:

也许你看完上面描述的这个流程有点绕,建议通过debug的方式,在 _LazyModule类的 __getattr__(self, name: str)方法中打上断点进行调试验证,如下图所示:

通过前面的介绍,我们可以知道从 tranformers 模块中导入其他模块对象都是一样的加载流程。

一句话总结 transformers 的懒加载机制:在各个模块的__init__.py文件中定义要导入的类、方法、变量的名称和模块名称的映射,然后将映射字典设置到_LazyModel中,最后将模块名称和_LazyModel设置到sys.modules字典中,导入包的时候会在_LazyModel中通过importlib.import_module方法递归导入,直到找到对应的模块或者找不到对应的模块而报错。

如何自动加载 tokenizer

前面介绍了如何从 from transformers import AutoTokenizer导入 AutoTokenizer,接下来介绍使用 AutoTokenizer.from_pretrained方法加载 tokenizer。

ini 复制代码
from transformers import AutoTokenizer

if __name__ == '__main__':

    model_path = '/Users/xiniao/models/Qwen/Qwen-7B'
    tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
    print(tokenizer)

AutoTokenizer.from_pretrained方法的内容比较多,这里只介绍核心流程:

get_tokenizer_config方法的内容如下:

在 transformers 框架中定义的 Slow tokenizers 和 Fast tokenizers 配置文件的名称如下,在调用 save_pretrained()保存 tokenizer 时,会保存下面的配置文件,后面会介绍 Slow tokenizers 和 Fast tokenizers的区别

我们可以查看 qwen-7b 中的 tokenizer_config.json文件的内容如下:

通过前面源码截图的粗略介绍,接下来总结一下 transformers 使用 AutoTokenizer.from_pretrained加载tokenizer的原理。

AutoTokenizer 首先会读取指定模型目录下的 tokenizer_config.json 文件内容,然后从读取的字典中获取 tokenizer_class 的值,如果 tokenizer_class 不存在,则会从 config.json 文件中读取 tokenizer_class 的值。

然后从tokenizer_config.json配置的字典中读取 auto_map 中的 AutoTokenizer 的值,如果这个值存在,则表示模型自定义了 tokenizer,也就是说需要从模型目录中查找对应的python文件执行文件的代码,这个存在安全问题,所以transformers中强制在加载自定义内容时必须 trust_remote_code=True否则会报错。

接下来程序会解析自定义的AutoTokenizer对应的字符串值:tokenization_qwen.QWenTokenizer通过 . 切分字符串,前面的 tokenization_qwen是python文件的名称(模块名称),后面的 QWenTokenizertokenization_qwen文件中的类名。在解析自定义 tokenizer 的时候,会做如下操作:

  • 将模型目录下的 tokenization_qwen.py 文件复制到 ~/.cache/huggingface/modules/transformers_modules/Qwen-7B文件夹中。复制本地文件以避免在 sys.path 中放置太多文件夹,当文件是新的或自上次复制以来已更改时,会进行此复制。为什么将 tokenization_qwen.py复制到 ~/.cache/huggingface/modules/transformers_modules/Qwen-7B文件夹中任然能够正确的导入模块,因为在执行复制操作之前,程序执行了 init_hf_modules()方法,该方法会将 ~/.cache/huggingface/modules添加到 sys.path 中,所以能够正确导入对应的模块。

自定义的 QWenTokenizer实际上是在 get_class_in_module()方法中导入的,如下所示:

自定义的 QWenTokenizer类在哪里实例化的呢?查看源码我们知道自定义的 QWenTokenizer类继承自 PreTrainedTokenizer类,PreTrainedTokenizer类继承自 PreTrainedTokenizerBase类,如果 QWenTokenizer没有重写 from_pretrained()类方法,那么调用 QWenTokenizer.from_pretrained类方法,则会调用父类 PreTrainedTokenizerBase中的from_pretrained类方法,实际上实例化 tokenizer 的代码如下所示:

在实例化 tokenizer 的时候,如何找到词表文件的,实际上是在自定义的 tokenizer 的 vocab_files_names属性中指定的,如下图所示:

在自定义的 QWenTokenizer的类属性中指定了 vocab_files_names 的值,所以才能正确加载词表:

经过上面的步骤,终于来到了自定义 tokenizer 的实例化方法中,前面的一系列操作都是为了获取 tokenizer 的配置内容(也就是 tokenizer_config.json 文件中的内容)和词表文件的路径,接下来进行初始化操作,在初始化过程中,主要完成如下内容:

  1. 调用父类 PreTrainedTokenizer__init__() 方法,在其构造方法中主要实现了将tokenizer自定义配置内容中的 added_tokens_decoder添加到 _added_tokens_decoder 实例属性中。实现了以统一的方式在所有的tokenizer中添加token,因此我们不必特殊处理各种基础词典结构(BPE、sentencepiece...)的特定词汇扩充方法。

模型 gemma-2b 中的 tokenizer_config.json 的配置如下:

  1. 调用父类PreTrainedTokenizer的父类 PreTrainedTokenizerBase__init__() 方法,在其构造方法中主要实现了将tokenizer自定义的配置内容设置成它的属性值,如果没有配置的内容,则设置默认值。
  1. PreTrainedTokenizerBase中会调用其父类 SpecialTokensMixin__init__() 方法,在SpecialTokensMixin__init__() 方法中会将tokenizer_config.json配置字典的值设置到specail_token 中,如下图所示:
  1. 在自定义的 QWenTokenizer 构造方法中加载词表文件对应的 tokenizer,以及设置其他自定义的特殊token。

到这里已经介绍完了创建自定义的 QWenTokenizer 实例的基本流程,因为是通过文字和截图的方式描述的,整个过程可能还是有点不清晰,建议自己通过debug的方式过一遍,这样对整个流程就会更加清晰一点,如果后续有时间,我将录制一个视频简单讲解一下。

默认情况下,AutoTokenizer 类首先加载 Fast tokenizer

Fast tokenizer 和 Slow tokenizer 的区别

Fast tokenizer 和 Slow tokenizer 的区别:

Slow tokenizer 是在 Transformer 库中用Python编写的。

Fast tokenizer 是在 Tokenizers 库中用Rust编写的。

Fast tokenizer 和 Slow tokenizer 分别对 Drug Review Dataset 的分词速度比较如下:

当标记一个句子时,Fast tokenizer 和 Slow tokenizer 分词速度差异不明显,事实上 Fast tokenizer 可能更慢!只有当同时并行标记大量文本时,你才能清楚地看到差异。

tokenizer 如何进行编码

前面粗略地介绍了使用 AutoTokenizer.from_pretrained()加载自定义 tokenizer 实例的过程,接下来介绍一下 tokenizer 如何进行编码的。

python 复制代码
from transformers import AutoTokenizer, TensorType

if __name__ == '__main__':

    model_path = '/Users/xiniao/models/Qwen/Qwen-7B'
    tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
    print(tokenizer)
    inputs = tokenizer('蒙古国的首都是乌兰巴托(Ulaanbaatar)\n冰岛的首都是雷克雅未克(Reykjavik)\n埃塞俄比亚的首都是', return_tensors=TensorType.PYTORCH)
    print(inputs)
    prompt = tokenizer.decode(inputs['input_ids'][0])
    print(prompt)

当调用 tokenizer('prompt') 时,实际的调用方法栈如下图:

调用 tokenizer(['prompt1', 'prompt2']) 时,实际的调用方法栈如下图:

接下来我们重点看一下tokenizer是怎样对输入文本进行编码的,主要实现是在 _encode_plus()_batch_encode_plus() 方法中,在它们的方法中定义了一个函数 get_input_ids(),在 get_input_ids()方法中调用了 tokenize()convert_tokens_to_ids()方法分别进行分词和将分词后的 token 转换为字典表对应的 id,这两个方法通常可以在自定义的 tokenizer 中实现。

因为 tokenize()convert_tokens_to_ids()方法在 PreTrainedTokenizer 中本质上调用的是 _tokenize()_convert_tokens_to_ids()方法,并且这两个方法在PreTrainedTokenizer 中都没有实现,所以在自定义的 tokenizer 中需要实现_tokenize()_convert_tokens_to_ids()方法。

可以看到 QWenTokenizer 中实现了 _tokenize()_convert_tokens_to_ids()方法,并且重写了tokenize()convert_tokens_to_ids()方法:

总结:通过前面的介绍我们简单总结一下 tokenizer 如何进行编码的,主要是在自定义的 tokenizer 中实现了 tokenize()convert_tokens_to_ids()或者 _tokenize()_convert_tokens_to_ids()方法 ,这两个方法是用来对输入的文本分词和转换为字典表的 id ,然后返回对应的 id 列表。在获取到输入文本对应的 id 列表后,在prepare_for_model()方法中需要对这个 id 列表进行截断(truncate)和 填充(pad),最后构造为模型推理和训练需要的字典参数返回。

关于tokenizer 编码过程中截断(truncate)和 填充(pad)这里不再详细介绍,详细的内容可以查看huggingface 对应的文档 Padding and truncation

tokenizer 如何进行解码

前面简单介绍了 tokenizer 如何对输入文本进行编码,接下来介绍一下如何使用 tokenizer.decode() 对输入的 token_id 列表进行解码,还原为原来的文本内容:

python 复制代码
from transformers import AutoTokenizer, TensorType

if __name__ == '__main__':
    prompts = ['蒙古国的首都是乌兰巴托(Ulaanbaatar)', '冰岛的首都是雷克雅未克(Reykjavik)', '埃塞俄比亚的首都是']
    model_path = '/Users/xiniao/models/Qwen/Qwen-7B'
    tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
    print(tokenizer)
    inputs = tokenizer(prompts, return_tensors=TensorType.PYTORCH, padding=True)
    print(inputs)
    prompt = tokenizer.decode(inputs['input_ids'][0])
    print(prompt)

通过debug的方式查看源码如下,实际调用 PreTrainedTokenizerBase类的 decode()

QWenTokenizer 中实现了 _decode() 方法,所以对于 QWenTokenizer来说,会调用自定义的_decode() 方法完成解码。

对于没有实现 _decode() 方法的 tokenizer 来说,会按照如下的调用过程完成解码:

  1. 调用 PreTrainedTokenizer类的 _decode()方法
  2. 调用 convert_ids_to_tokens()方法,如果子类重写了该方法,则调用子类重写的该方法
  3. 调用 _convert_id_to_token()方法(在convert_ids_to_tokens()内部),如果子类重写了该方法,则调用子类重写的该方法
  4. 调用 convert_tokens_to_string() 方法,如果子类重写了该方法,则调用子类重写的该方法

LlamaTokenizer中重写了 _convert_id_to_token()convert_tokens_to_string() 来完成自定义的解码。

如果我们需要自定义解码逻辑,重写下面介绍的几个方法即可:

  • _decode():将 token_id 列表还原为字符串

  • convert_ids_to_tokens():将 token_id 列表还原为 token 列表

  • _convert_id_to_token():在 在convert_ids_to_tokens()内部调用

  • convert_tokens_to_string():将 token 列表还原为字符串列表

tokenizer 如何使用对话模板

tokenizer 对话模板详细使用可以查看 huggingface 官方文档:Templates for Chat Models

大语言模型最常用的功能是聊天,我们在使用模型进行chat的时候,需要使用对话模版,不同的模型有不同的对话模板,推理时的对话模型需要和模型训练的对话模板保持一致。

在引入chat_template之前,聊天模板的处理是在模型类级别进行硬编码的,通过手动的方式拼接不同模型的对话模版,为了解决手动拼接对话模版的问题,transformers 的 PreTrainedTokenizerBase 类引入了一个chat_template属性,该属性配置 jinja模版,通过该模版可以自动将具有" role "和" content "键的 Conversation 对象或字典列表转换为对话模版字符串。

为了向后兼容,如果模型没有设置chat_template,但其模型类有default_chat_template属性,则调用tokenizer.apply_chat_template()将使用类default_chat_template配置的模板,可以通过tokenizer.default_chat_template属性来查看tokenizer的默认模板是什么。

下面使用一个例子来说明如何使用 tokenizer 的对话模板:

python 复制代码
from transformers import AutoTokenizer, TensorType

if __name__ == '__main__':
    model_path = '/Users/xiniao/models/Qwen/Qwen-7B'
    
    tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)

    tokenizer.chat_template = "{% for message in messages %}{% if loop.first and messages[0]['role'] != 'system' %}{{ '<|im_start|>system\nYou are a helpful assistant<|im_end|>\n' }}{% endif %}{{'<|im_start|>' + message['role'] + '\n' + message['content']}}{% if (loop.last and add_generation_prompt) or not loop.last %}{{ '<|im_end|>' + '\n'}}{% endif %}{% endfor %}{% if add_generation_prompt and messages[-1]['role'] != 'assistant' %}{{ '<|im_start|>assistant\n' }}{% endif %}"
    chat = [
        {"role": "user", "content": "你好,你好吗?"},
        {"role": "assistant", "content": "我很好,需要什么帮助吗?"},
        {"role": "user", "content": "我想了解聊天模板的工作原理!"},
    ]
    chat_template = tokenizer.apply_chat_template(chat, tokenize=False)
    print(chat_template)

# 输出内容:
# <|im_start|>system
# You are a helpful assistant<|im_end|>
# <|im_start|>user
# 你好,你好吗?<|im_end|>
# <|im_start|>assistant
# 我很好,需要什么帮助吗?<|im_end|>
# <|im_start|>user
# 我想了解聊天模板的工作原理!

如上代码所示,通过给 tokenizer 设置 chat_template属性,然后调用 apply_chat_template()方法就可以自动生成对话模版字符串。接下来说明一下 apply_chat_template()方法的作用和各个参数的含义:

方法的作用:

将Conversation对象或带有"role"和"content"键的字典列表转换为token id列表或者对话模版字符串,该方法旨在与聊天模型一起使用,并将读取 tokenizer 的 chat_template 属性以确定在转换时要使用的格式和控制标记,当chat_templateNone 时,它将退回到类级别指定的 default_chat_template

方法的参数说明:

  • conversation (Union[List[Dict[str, str]], "Conversation"]): 表示对话的内容,可以是一个 Conversation 对象或者是一个包含了字典的列表,每个字典包含了 "role" 和 "content" 键来表示对话的历史。这个参数用于表示到目前为止的聊天记录。
  • chat_template (str, optional): 表示对话的模板,是一个字符串。如果不传入这个参数,将会使用模型的默认对话模板。
  • add_generation_prompt (bool, optional): 表示是否在提示(prompt)的末尾添加指示开始助手消息的标记(token)。这在你想要生成模型的回复时非常有用。注意,这个参数将被传递给对话模板,因此对话模板必须支持这个参数才能起作用。
  • tokenize (bool, defaults to True): 表示是否对输出进行分词(tokenization)。如果为 False,输出将是一个字符串。
  • padding (bool, defaults to False): 表示是否对序列进行填充(padding)到最大长度。如果 tokenizeFalse,则此参数无效。
  • truncation (bool, defaults to False): 表示是否对序列进行截断(truncation)到最大长度。如果 tokenizeFalse,则此参数无效。
  • max_length (int, optional): 表示填充或截断的最大长度(以标记数计算)。如果未指定,将使用分词器的 max_length 属性作为默认值。
  • return_tensors (str or TensorType, optional): 如果设置,将返回特定框架(framework)的张量。如果 tokenizeFalse,此参数无效。可接受的值包括:
    • 'tf': 返回 TensorFlow tf.Tensor 对象。
    • 'pt': 返回 PyTorch torch.Tensor 对象。
    • 'np': 返回 NumPy np.ndarray 对象。
    • 'jax': 返回 JAX jnp.ndarray 对象。
  • return_dict (bool, optional, defaults to False): 表示是否返回具有命名输出的字典。如果 tokenizeFalse,此参数无效。
  • **tokenizer_kwargs: 附加的关键字参数,用于传递给分词器。

设置tokenizer 的 chat_template的方式和优先级(从高到低)如下:

  1. apply_chat_template()方法的 chat_template参数中设置
  2. tokenizerchat_template属性中设置
  3. tokenizer_config.json 配置文件中 chat_template属性中设置
  4. tokenizerdefault_chat_template属性中设置

参考文章

深入理解 tokenizer

Tokenizers

github.com/huggingface...

相关推荐
凡人的AI工具箱2 小时前
15分钟学 Python 第38天 :Python 爬虫入门(四)
开发语言·人工智能·后端·爬虫·python
丶21362 小时前
【SQL】深入理解SQL:从基础概念到常用命令
数据库·后端·sql
木子02042 小时前
Nacos的应用
后端
哎呦没2 小时前
Spring Boot框架在医院管理中的应用
java·spring boot·后端
陈序缘3 小时前
Go语言实现长连接并发框架 - 消息
linux·服务器·开发语言·后端·golang
络73 小时前
Spring14——案例:利用AOP环绕通知计算业务层接口执行效率
java·后端·spring·mybatis·aop
2401_857600954 小时前
明星周边销售网站开发:SpringBoot技术全解析
spring boot·后端·php
AskHarries4 小时前
Spring Cloud 3.x 集成admin快速入门Demo
java·后端·spring cloud
程序员大金4 小时前
基于SpringBoot+Vue+MySQL的在线学习交流平台
java·vue.js·spring boot·后端·学习·mysql·intellij-idea
qq_2518364574 小时前
基于SpringBoot vue 医院病房信息管理系统设计与实现
vue.js·spring boot·后端