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...

相关推荐
WZTTMoon7 分钟前
Spring Boot 4.0 迁移核心注意点总结
java·spring boot·后端
寻kiki7 分钟前
scala 函数类?
后端
疯狂的程序猴18 分钟前
iOS App 混淆的真实世界指南,从构建到成品 IPA 的安全链路重塑
后端
bcbnb29 分钟前
iOS 性能测试的工程化方法,构建从底层诊断到真机监控的多工具测试体系
后端
开心就好202532 分钟前
iOS 上架 TestFlight 的真实流程复盘 从构建、上传到审核的团队协作方式
后端
小周在成长41 分钟前
Java 泛型支持的类型
后端
aiopencode41 分钟前
Charles 抓不到包怎么办?HTTPS 抓包失败、TCP 数据流异常与底层补抓方案全解析
后端
大模型教程43 分钟前
开源大模型不求人!一文带你全面入门《开源大模型食用指南》
程序员·llm·agent
稚辉君.MCA_P8_Java1 小时前
Gemini永久会员 C++返回最长有效子串长度
开发语言·数据结构·c++·后端·算法
大模型教程1 小时前
从 0 到 1,微调一个自己专属的大模型
程序员·llm·agent