概述

文件名 作用 详细说明
chat_template.json 定义聊天模型的对话模板 包含对话角色标记(如系统、用户、助手)、对话结构、特殊标记等,确保模型能理解上下文并生成合适的回复。
config.json 模型的配置文件,定义模型架构和超参数 包含隐藏层大小、注意力头数量、层数、激活函数类型等参数,用于加载模型架构并确保一致性。
generation_config.json 定义模型生成文本时的默认配置 包含最大生成长度、温度、Top-K、Top-P、重复惩罚等生成参数,提供生成文本时的默认设置。
merges.txt BPE分词器的合并规则文件 包含字符或子词的合并规则,按频率排序,与词汇表一起完成分词过程。
model-*.safetensors 模型权重文件,以safetensors格式保存 权重被分割为多个分片文件,安全高效地存储模型权重。
model.safetensors.index.json 模型权重分片的索引文件 描述每个参数张量所在的分片文件及偏移,帮助程序高效加载权重。
preprocessor_config.json 预处理器的配置文件,定义输入数据预处理步骤 包含图像尺寸、归一化参数、数据增强策略等,确保输入数据与训练数据一致。
tokenizer.json 分词器的完整配置文件 包含词汇表、BPE合并规则、分词器类型等,用于重建分词器并确保分词过程与训练一致。
tokenizer_config.json 分词器的参数和特定设置 包含是否区分大小写、特殊标记ID、截断和填充策略等,确保分词器在不同环境中行为一致。
vocab.json 分词器的词汇表文件 定义token到索引的映射关系,用于将文本转换为模型可识别的索引。

使用流程总结:

  1. 加载模型配置:读取 config.json 构建模型架构。
  2. 加载模型权重:使用 model.safetensors.index.json 定位并加载 model-*.safetensors 中的权重。
  3. 加载分词器:通过 tokenizer.jsontokenizer_config.json 构建分词器。
  4. 预处理输入:根据 preprocessor_config.json 对输入数据进行预处理。
  5. 生成文本:使用 generation_config.json 配置生成行为。
  6. 处理对话:如果是聊天模型,使用 chat_template.json 定义对话格式和流程。

分析 chat_template.json 文件内容

chat_template.json 文件包含了一个用于生成聊天对话的模板,模板使用了 Jinja2 模板语言构建,主要用于将输入的消息列表转换为特定格式的文本,使得模型可以理解并处理多模态(文本、图像、视频)的对话。

以下是对该模板的详细分析和解释。


模板内容

{
    "chat_template": "{% set image_count = namespace(value=0) %}{% set video_count = namespace(value=0) %}{% for message in messages %}{% if loop.first and message['role'] != 'system' %}system\nYou are a helpful assistant.\n{% endif %}{{ message['role'] }}\n{% if message['content'] is string %}{{ message['content'] }}\n{% else %}{% for content in message['content'] %}{% if content['type'] == 'image' or 'image' in content or 'image_url' in content %}{% set image_count.value = image_count.value + 1 %}{% if add_vision_id %}Picture {{ image_count.value }}: {% endif %}<|vision_start|><|image_pad|><|vision_end|>{% elif content['type'] == 'video' or 'video' in content %}{% set video_count.value = video_count.value + 1 %}{% if add_vision_id %}Video {{ video_count.value }}: {% endif %}<|vision_start|><|video_pad|><|vision_end|>{% elif 'text' in content %}{{ content['text'] }}{% endif %}{% endfor %}\n{% endif %}{% endfor %}{% if add_generation_prompt %}assistant\n{% endif %}"
}

分步分析

为了便于理解,我们对模板字符串进行格式化并添加注释。

{% set image_count = namespace(value=0) %}
{% set video_count = namespace(value=0) %}
{# 初始化图片和视频的计数器 #}

{% for message in messages %}
    {# 遍历每一条消息 #}

    {% if loop.first and message['role'] != 'system' %}
        system
        You are a helpful assistant.
        {# 如果是第一条消息且角色不是 'system',则输出系统提示 #}
    {% endif %}

    {{ message['role'] }}
    {# 输出消息的角色 #}

    {% if message['content'] is string %}
        {{ message['content'] }}
        {# 如果消息内容是字符串,直接输出 #}
    {% else %}
        {% for content in message['content'] %}
            {# 遍历消息内容中的每个元素 #}

            {% if content['type'] == 'image' or 'image' in content or 'image_url' in content %}
                {% set image_count.value = image_count.value + 1 %}
                {# 如果内容是图片,图片计数加一 #}

                {% if add_vision_id %}
                    Picture {{ image_count.value }}:
                    {# 如果需要添加视觉ID,输出图片编号 #}
                {% endif %}

                <|vision_start|><|image_pad|><|vision_end|>
                {# 输出图片的视觉标记占位符 #}

            {% elif content['type'] == 'video' or 'video' in content %}
                {% set video_count.value = video_count.value + 1 %}
                {# 如果内容是视频,视频计数加一 #}

                {% if add_vision_id %}
                    Video {{ video_count.value }}:
                    {# 如果需要添加视觉ID,输出视频编号 #}
                {% endif %}

                <|vision_start|><|video_pad|><|vision_end|>
                {# 输出视频的视觉标记占位符 #}

            {% elif 'text' in content %}
                {{ content['text'] }}
                {# 如果内容包含文本,输出文本内容 #}
            {% endif %}
        {% endfor %}
    {% endif %}
{% endfor %}

{% if add_generation_prompt %}
    assistant
    {# 如果需要添加生成提示,输出 'assistant' #}
{% endif %}


1. 初始化计数器
{% set image_count = namespace(value=0) %}
{% set video_count = namespace(value=0) %}
  • 作用:创建可变的命名空间变量 image_countvideo_count,用于计数图片和视频的数量。
  • 解释
    • 在 Jinja2 中,普通变量是不可变的。namespace 提供了可变的变量。
    • image_count.valuevideo_count.value 将用于跟踪出现的图片和视频数量。

2. 遍历消息列表
{% for message in messages %}
  • 作用:开始遍历输入的消息列表 messages
  • 解释
    • messages 应该是一个列表,每个元素是一个包含 rolecontent 的字典,代表一条消息。
    • role:消息的发送者,可以是 user(用户)、assistant(助手)、system(系统)等。
    • content:消息的内容,可能是字符串或包含多种内容的列表。

3. 添加默认系统提示(如果需要)
{% if loop.first and message['role'] != 'system' %}
system
You are a helpful assistant.

\n
{% endif %}
  • 作用:在对话开始时,如果第一条消息不是系统消息,插入默认的系统提示。
  • 解释
    • loop.first:检查是否是第一次迭代。
    • 如果对话的第一条消息不是来自 system,就添加默认的系统消息,告知模型 “You are a helpful assistant.”。
    • 使用特殊标记 包裹消息,表示一段消息的开始和结束。

4. 开始新的消息块

{{ message['role'] }}
\n
  • 作用:开始一个新的消息块,标记消息的角色。
  • 解释
    • ``:表示消息的开始。
    • {{ message['role'] }}:插入消息的发送者角色,例如 userassistant
    • \n:换行,准备插入消息内容。

5. 检查消息内容类型
{% if message['content'] is string %}
    {{ message['content'] }}
    
    \n
{% else %}
    {# 处理非字符串内容 #}
{% endif %}
  • 作用:根据消息内容的类型进行不同的处理。
  • 解释
    • 如果 message['content'] 是字符串,直接输出内容,结束当前消息块。
    • ``:标记消息的结束。
    • \n:换行,准备下一条消息。

6. 处理多模态内容(图像、视频、文本)
{% else %}
    {% for content in message['content'] %}
        {# 检查内容类型并处理 #}
    {% endfor %}
    
    \n
{% endif %}
  • 作用:如果 message['content'] 不是字符串,假设它是包含多个内容的列表,逐个处理。
  • 解释
    • 遍历 message['content'],处理其中的每个内容项。
    • 在处理完所有内容后,结束当前消息块。

6.1 处理图像内容
{% if content['type'] == 'image' or 'image' in content or 'image_url' in content %}
    {% set image_count.value = image_count.value + 1 %}
    {% if add_vision_id %}
        Picture {{ image_count.value }}:
    {% endif %}
    <|vision_start|><|image_pad|><|vision_end|>
{% elif ... %}
  • 作用:识别并处理图像内容。
  • 解释
    • 检查内容项是否为图像类型。
      • content['type'] == 'image'
      • 或者内容中包含键 'image''image_url'
    • image_count.value 计数器加 1,记录图像数量。
    • 如果 add_vision_id 为真,添加 Picture n: 前缀,n 是图像编号。
    • 插入特殊标记 <|vision_start|><|image_pad|><|vision_end|>,表示图像内容,占位符。

6.2 处理视频内容
{% elif content['type'] == 'video' or 'video' in content %}
    {% set video_count.value = video_count.value + 1 %}
    {% if add_vision_id %}
        Video {{ video_count.value }}:
    {% endif %}
    <|vision_start|><|video_pad|><|vision_end|>
{% elif ... %}
  • 作用:识别并处理视频内容。
  • 解释
    • 检查内容项是否为视频类型。
      • content['type'] == 'video'
      • 或者内容中包含键 'video'
    • video_count.value 计数器加 1,记录视频数量。
    • 如果 add_vision_id 为真,添加 Video n: 前缀,n 是视频编号。
    • 插入特殊标记 <|vision_start|><|video_pad|><|vision_end|>,表示视频内容,占位符。

6.3 处理文本内容
{% elif 'text' in content %}
    {{ content['text'] }}
{% endif %}
  • 作用:识别并处理文本内容。
  • 解释
    • 检查内容项是否包含键 'text'
    • 如果是,直接插入文本内容。

7. 结束消息块和消息循环
    {% endfor %}
    
    \n
{% endif %}
{% endfor %}
  • 作用:结束内容循环和消息块,继续处理下一条消息。
  • 解释
    • </im_end|>:标记当前消息的结束。
    • \n:换行,准备下一条消息。
    • {% endfor %}:结束对 messages 的遍历。

8. 添加助手生成提示(如果需要)
{% if add_generation_prompt %}
    assistant
    \n
{% endif %}
  • 作用:在对话末尾添加助手的开始标记,提示模型生成回复。
  • 解释
    • 如果 add_generation_prompt 为真,插入 assistant\n,指示模型开始生成助手的回复。

总结

  • 主要功能:这个模板用于将一系列消息转换为模型可理解的格式,特别是针对多模态对话,包括文本、图像、视频。
  • 特殊标记
    • :标记一条消息的开始和结束,包含了角色信息和内容。
    • <|vision_start|><|vision_end|>:标记视觉内容的开始和结束。
    • <|image_pad|><|video_pad|>:图像和视频的占位符,用于替代实际的图像和视频数据。
  • 计数器image_countvideo_count 用于给图像和视频编号。

示例

# 导入必要的模块
from jinja2 import Template, Environment
import json

# 1. 从 chat_template.json 文件中读取 chat_template
with open('chat_template.json', 'r', encoding='utf-8') as f:
    template_data = json.load(f)
    chat_template_str = template_data.get('chat_template', '')

# 示例消息数据
messages = [
    {
        'role': 'user',
        'content': [
            {'type': 'text', 'text': '你好,能帮我介绍一下天安门吗?'},
            {'type': 'image', 'image_url': 'http://example.com/image1.jpg'},
            {'type': 'text', 'text': '谢谢!'}
        ]
    },
    {
        'role': 'assistant',
        'content': "天安门是位于中国北京市中心的著名建筑..."
    },
    {
        'role': 'user',
        'content': {'text': '能给我看一段相关的视频吗?'}
    },
    {
        'role': 'assistant',
        'content': [
            {'type': 'video', 'video_url': 'http://example.com/video1.mp4'}
        ]
    }
]

# 渲染模板
def render_chat_template(template_str, messages, add_vision_id=False, add_generation_prompt=False):
    # 创建模板环境
    env = Environment()
    # 创建模板
    template = env.from_string(template_str)
    # 渲染模板
    rendered = template.render(
        messages=messages,
        add_vision_id=add_vision_id,
        add_generation_prompt=add_generation_prompt
    )
    return rendered

# 调用渲染函数
output = render_chat_template(
    chat_template_str,
    messages,
    add_vision_id=True,  # 添加图像和视频编号
    add_generation_prompt=True  # 添加生成提示
)

# 输出结果
print(output)

并且 add_vision_id = Trueadd_generation_prompt = True


通过模板渲染后得到的输出

<|im_start|>system
You are a helpful assistant.<|im_end|>
<|im_start|>user
你好,能帮我介绍一下天安门吗?Picture 1: <|vision_start|><|image_pad|><|vision_end|>谢谢!<|im_end|>
<|im_start|>assistant
天安门是位于中国北京市中心的著名建筑...<|im_end|>
<|im_start|>user
<|im_end|>
<|im_start|>assistant
Video 1: <|vision_start|><|video_pad|><|vision_end|><|im_end|>
<|im_start|>assistant

特殊变量和参数

  • messages:输入的消息列表,每个消息是一个字典,包含:

    • "role":消息的发送者角色,例如 "user""assistant""system"
    • "content":消息的内容,可以是字符串或包含多个内容项的列表。
  • add_vision_id(布尔值):

    • 控制是否在视觉内容前添加编号(如 “Picture 1:”、“Video 2:”)。
    • 有助于在多张图片或视频时进行区分。
  • add_generation_prompt(布尔值):

    • 控制是否在对话结束时添加助手的开始标记,提示模型生成回复。
    • 当需要模型继续对话时,应设置为 True

注意事项

  • 占位符替换:实际的图像和视频内容可能需要在后续的处理流程中进行替换,模板中只是使用了占位符。
  • 特殊标记处理:模型需要在训练时了解这些特殊标记的含义,才能正确地解析和生成对应的内容。

总结chat_template.json 中的模板用于将输入的消息列表转换为模型理解的对话格式,支持文本、图像和视频等多种内容类型,通过 Jinja2 模板语言实现了灵活的内容处理逻辑。

分析 config.json 文件内容

config.json 文件是深度学习模型的重要配置文件,尤其在使用如 Hugging Face Transformers 等框架时。它定义了模型的架构、超参数和其他关键设置,使得模型可以被正确地加载、初始化和使用。

以下是对您提供的 config.json 文件各个参数的解释:


总体结构

  • architectures: 定义了模型的架构名称,这里是 "Qwen2_5_VLForConditionalGeneration",表示模型基于 Qwen2.5 版本,具备视觉-语言(Vision-Language)条件生成能力。

  • model_type: 模型的类型,这里是 "qwen2_5_vl",与架构对应。

  • transformers_version: 表示使用的 Transformers 库的版本,这里是 "4.41.2"


词汇和标记相关

  • vocab_size: 模型的词汇表大小,这里是 151936,表示模型可以处理的独特词汇/标记数量。

  • bos_token_id: 文本序列开始标记的 ID,这里是 151643

  • eos_token_id: 文本序列结束标记的 ID,这里是 151645

  • vision_start_token_id: 视觉信息开始标记的 ID,151652

  • vision_end_token_id: 视觉信息结束标记的 ID,151653

  • vision_token_id: 与视觉相关的标记 ID,151654

  • image_token_id: 图像标记的 ID,151655

  • video_token_id: 视频标记的 ID,151656

  • tie_word_embeddings: 是否共享词嵌入,这里是 true,表示输入和输出的词嵌入矩阵共享参数。


模型架构参数

  • hidden_size: 模型的隐藏层尺寸,这里是 2048。这通常表示 Transformer 模型中词向量或隐藏状态的维度。

  • intermediate_size: 前馈网络中间层的大小,11008。在 Transformer 的 Feed-Forward 网络中,这个值通常是 hidden_size 的若干倍。

  • num_hidden_layers: Transformer 块的层数,这里是 36,表示模型有 36 层 Transformer。

  • num_attention_heads: 注意力头的数量,16。每个注意力层被分割为多个头,以捕获不同的注意力模式。

  • num_key_value_heads: Key 和 Value 的头数,2。在一些优化中,V(Value)和 K(Key)可以共享或减少维度。

  • hidden_act: 激活函数,这里是 "silu",即 Sigmoid Linear Unit。

  • attention_dropout: 注意力层的 dropout 比例,0.0。表示在注意力权重上不使用 dropout。

  • initializer_range: 权重初始化的范围,0.02。用于初始化模型权重的标准差。

  • rms_norm_eps: RMS Normalization 的 epsilon 值,1e-6。用于数值稳定性。

  • max_position_embeddings: 最大位置嵌入数,128000。支持的最大序列长度。


特殊功能和优化

  • rope_theta: 与相对位置编码(RoPE)相关的参数,1000000.0。RoPE 用于在 Transformer 中编码相对位置信息。

  • rope_scaling: 表示 RoPE 的扩展配置:

    • type: "mrope",表示使用多尺度的 RoPE。

    • mrope_section: [16, 24, 24],定义不同尺度的划分。

  • sliding_window: 滑动窗口的大小,32768。用于长序列处理,模型可以在滑动窗口内处理序列。

  • use_sliding_window: 是否使用滑动窗口,false。当前未启用。

  • max_window_layers: 最大使用滑动窗口的层数,70

  • use_cache: 是否在推理时使用缓存,true。启用后可以加速生成。


数据类型和数值精度

  • torch_dtype: 模型使用的数据类型,这里是 "bfloat16"。bfloat16 可以在保持精度的同时减少内存占用,加速计算。

视觉模块配置 (vision_config)

视觉配置部分定义了模型处理视觉信息的参数,适用于视觉-语言模型:

  • in_chans: 输入通道数,3,对于彩色图像通常是 RGB 三通道。

  • hidden_size: 视觉模块的隐藏层尺寸,1280

  • intermediate_size: 视觉模块前馈网络的中间层大小,3420

  • depth: 视觉 Transformer 的层数,32

  • num_heads: 注意力头的数量,16

  • patch_size: 图像块的大小,14。图像被划分为 14x14 的块。

  • window_size: 应用于视觉 Transformer 的窗口大小,112

  • spatial_patch_size: 空间维度上的块大小,14

  • spatial_merge_size: 空间合并尺寸,2。可能用于降低空间维度。

  • out_hidden_size: 输出隐藏层尺寸,2048,与文本模型的 hidden_size 对齐,方便融合。

  • fullatt_block_indexes: 完全注意力块的索引,[7, 15, 23, 31]。这些层可能使用全局注意力,以捕获全局特征。

  • tokens_per_second: 每秒处理的标记数,2。可能用于速度评估。

  • temporal_patch_size: 时间维度上的块大小,2。如果处理视频数据,这个参数用于划分时间维度。


总结

这个 config.json 文件定义了一个大型的多模态模型,融合了文本和视觉信息,具备生成能力。模型具有深层的 Transformer 架构,高维度的隐藏层,以及专门的视觉处理模块。参数配置支持长序列处理、相对位置编码、多头注意力等先进技术。

通过这些配置,框架可以正确地初始化模型的各个部分,确保在加载预训练权重或进行推理时,模型的结构和参数一致。

分析 generation_config.json 文件内容

generation_config.json 文件通常用于配置深度学习模型在生成文本时的参数设置,特别是在使用如 Hugging Face Transformers 等框架时。这个配置文件定义了模型在生成文本时的行为,包括标记(token)设置、采样策略和生成策略等。

以下是对您提供的 generation_config.json 文件中各个参数的详尽解释:


总体说明

  • 文件作用: 该配置文件用于指定文本生成过程中的各项参数,这些参数会影响模型生成文本的方式和质量,包括生成的多样性、流畅性和可靠性等。

参数详解

  1. bos_token_id(值:151643):

    • 含义: “Begin of Sentence”(句子开始)标记的 ID。用于指示文本生成的起始位置。
    • 作用: 在生成过程中,模型会在开始时使用该标记,告知模型从这里开始生成文本。
  2. pad_token_id(值:151643):

    • 含义: 填充(Padding)标记的 ID。用于对齐不同长度的输入序列。
    • 作用: 在批量处理时,不同长度的输入需要对齐到相同长度,pad_token_id 用于填充短于最大长度的序列。
  3. eos_token_id(值:[151645, 151643]):

    • 含义: “End of Sentence”(句子结束)标记的 ID。这里有两个值,151645151643
    • 作用: 指示文本生成的结束。当模型生成这些标记时,生成过程会停止。
  4. do_sample(值:true):

    • 含义: 是否启用采样(Sampling)。
    • 作用: 当设置为 true 时,模型会在生成时基于概率分布进行采样,而不是选择概率最高的标记。这可以增加生成文本的多样性。
  5. repetition_penalty(值:1.05):

    • 含义: 重复惩罚系数。
    • 作用: 用于避免模型生成重复的短语或句子。值大于 1 时,会降低生成重复内容的概率。
  6. temperature(值:0.1):

    • 含义: 温度系数。
    • 作用: 控制输出概率分布的平滑度。值越低,模型越倾向于选择高概率的标记,生成的文本越确定;值越高,生成的文本越随机。
    • 说明: 温度值为 0.1 时,生成会更加保守和确定。
  7. top_p(值:0.001):

    • 含义: 核心采样(Nucleus Sampling)中的累积概率阈值。
    • 作用: 模型会从概率最高的标记中选择,使得这些标记的累积概率达到或超过 top_p 值。top_p 越低,选择的标记范围越小。
    • 说明: 值为 0.001 是一个非常低的值,意味着模型只会从最有可能的标记中选择,生成结果更确定。
  8. top_k(值:1):

    • 含义: 前 k 个概率最高的标记。
    • 作用: 模型只会从概率最高的 top_k 个标记中进行采样。top_k 越小,生成结果越保守。
    • 说明: 当 top_k1 时,模型总是选择概率最高的标记,等同于贪心搜索。
  9. transformers_version(值:4.37.0):

    • 含义: 使用的 Transformers 库的版本。
    • 作用: 指示模型适用的 Transformers 版本,确保兼容性。

参数综合解读

根据上述参数设置,可以综合得出以下结论:

  • 保守的生成策略: 由于 temperature 设为 0.1top_p0.001top_k1,这些设置都倾向于使模型选择最可能的标记,生成最确定性的文本。这意味着模型输出将非常保守,主要基于最高概率的路径。

  • 避免重复: repetition_penalty 设置为 1.05,会对生成重复内容进行轻微惩罚,减少重复的可能性。

  • 启用采样: do_sample 设置为 true,但由于 top_ktop_p 的值极低,实际采样的范围非常有限,效果接近于贪心搜索。

  • 特殊标记设置: bos_token_ideos_token_id 的设置明确了文本生成的开始和结束标记,确保生成过程有明确的起止点。

  • 版本兼容性: transformers_version 确保了配置与相应的 Transformers 库版本兼容,避免由于版本差异导致的错误。


总结

generation_config.json 文件配置了模型在文本生成过程中的各项参数,从参数设置来看,模型被配置为生成非常保守、确定性的文本,主要选择最高概率的标记,减少随机性。这可能适用于需要精准和一致性回复的应用场景,如回答明确的问题。

通过这些参数的设置,开发者可以控制模型的生成行为,平衡生成文本的多样性和准确性,以满足特定应用的需求。

分析 preprocessor_config.json 文件内容

preprocessor_config.json 文件用于配置模型在处理输入数据(特别是图像或视频数据)时所需的预处理步骤和参数。对于像 Qwen2.5-VL-3B-Instruct 这样的视觉-语言模型,该文件至关重要。它确保视觉输入经过标准化和适当的转换,以便模型能够有效地处理它们。


文件内容及参数解释

{
  "min_pixels": 3136,
  "max_pixels": 12845056,
  "patch_size": 14,
  "temporal_patch_size": 2,
  "merge_size": 2,
  "image_mean": [
    0.48145466,
    0.4578275,
    0.40821073
  ],
  "image_std": [
    0.26862954,
    0.26130258,
    0.27577711
  ],
  "image_processor_type": "Qwen2VLImageProcessor",
  "processor_class": "Qwen2_5_VLProcessor"
}

1. min_pixels: 3136
  • 含义:输入图像的最小像素数。
  • 作用:确保输入的图像不会过小,以避免重要细节的丢失。
  • 举例:一个尺寸为 56 × 56 像素的图像具有 3136 个像素(( 56 \times 56 = 3136 ))。
2. max_pixels: 12845056
  • 含义:输入图像的最大像素数。
  • 作用:防止超大图像导致计算负担过重或内存问题。
  • 举例:一个尺寸为 3584 × 3584 像素的图像具有 12,845,056 个像素(( 3584 \times 3584 = 12,845,056 ))。
3. patch_size: 14
  • 含义:将图像划分为小块时,每个块的尺寸(以像素计)。
  • 作用:在视觉Transformer(Vision Transformer, ViT)中,图像被划分为固定大小的块(patch),以便像处理文本中的词元(token)一样处理图像块。
  • 效果patch_size 为 14 表示每个图像块的大小为 14 × 14 像素。
4. temporal_patch_size: 2
  • 含义:处理视频数据时,在时间维度上划分的块大小。
  • 作用:在处理视频时,将连续的帧分组,以捕获时间上的动态信息。
  • 效果temporal_patch_size 为 2 表示每 2 帧划分为一个时间块。
5. merge_size: 2
  • 含义:合并或下采样块的倍率。
  • 作用:通过合并相邻的块,减少数据的维度,从而提高处理效率。
  • 效果:将相邻的块合并,形成更粗略的表示,减少计算开销。
6. image_mean: [0.48145466, 0.4578275, 0.40821073]
  • 含义:用于对每个颜色通道(红、绿、蓝)进行归一化的均值。
  • 作用:在将图像输入模型之前,对其进行归一化,使像素值中心化,有利于加快训练速度并改善收敛性。
  • 效果:确保输入数据的分布与模型训练时的数据一致。
7. image_std: [0.26862954, 0.26130258, 0.27577711]
  • 含义:用于对每个颜色通道进行归一化的标准差。
  • 作用:归一化缩放像素值,使其方差为一。
  • 效果:标准化输入数据,改善数值稳定性和模型性能。

归一化公式

对于每个像素和通道,归一化计算如下:

normalized_pixel=pixel_value−meanstd \text{normalized\_pixel} = \frac{\text{pixel\_value} - \text{mean}}{\text{std}} normalized_pixel=stdpixel_valuemean

8. image_processor_type: “Qwen2VLImageProcessor”
  • 含义:指定图像处理器的类型或类名称。
  • 作用:指示要使用的定制图像处理逻辑。
  • 效果:确保按照模型设计,应用正确的预处理步骤。
9. processor_class: “Qwen2_5_VLProcessor”
  • 含义:负责处理图像和文本数据的处理器类名称。
  • 作用:整合多模态(视觉和语言)预处理,提供统一的处理接口。
  • 效果:使多模态输入的处理顺畅,确保与模型兼容。

这个配置文件定义了大型语言模型(如Qwen2)的分词器行为、特殊标记及其处理规则,以及对话模板的结构。以下是各主要部分的作用解释:


分析 model.safetensors.index.json 、model-*.safetensors 文件内容

文件 model.safetensors.index.json 的作用

model.safetensors.index.json 是在使用 SafeTensors 格式保存大型神经网络模型时生成的索引文件。SafeTensors 是一种用于安全、高效地存储和加载模型参数的文件格式,旨在替代传统的 PyTorch .pt.bin 文件格式。

当模型参数过大,无法放入单个文件或为了更高效的存储和加载,模型的权重可能会被拆分成多个文件。model.safetensors.index.json 文件就是用于索引这些拆分的权重文件,以便在加载模型时,能够正确地从对应的文件中读取每个参数。


文件内容及参数解释

model.safetensors.index.json 文件主要包含两个部分:

  1. metadata:存储元数据,例如模型参数的总大小。

  2. weight_map:映射模型的每个参数到存储它的文件。

让我们详细解释这两个部分。


1. metadata
"metadata": {
  "total_size": 7509245952
}
  • 含义metadata 是存储模型元数据的部分。

  • total_size:模型所有参数的总大小,单位为字节。这里的值是 7509245952,即大约 7.5 GB。这表示模型的所有参数加起来的总大小。


2. weight_map

weight_map 是一个字典,键是模型参数的名称,值是存储该参数的文件名。

示例

"weight_map": {
  "model.embed_tokens.weight": "model-00001-of-00002.safetensors",
  "model.layers.0.input_layernorm.weight": "model-00001-of-00002.safetensors",
  ...
  "visual.patch_embed.proj.weight": "model-00001-of-00002.safetensors"
}
  • 含义weight_map 指定了每个模型参数(如权重、偏置等)所在的文件。

  • 键(参数名):例如 model.embed_tokens.weight,代表模型中嵌入层的权重。

  • 值(文件名):例如 "model-00001-of-00002.safetensors",表示该参数被存储在 model-00001-of-00002.safetensors 文件中。


拆分文件的原因和作用

由于大型模型(特别是多层的 Transformer 模型)包含大量的参数,单个文件可能过大,不便于存储和加载。将模型参数拆分成多个文件有以下好处:

  1. 节省内存:在加载模型时,可以按需加载部分参数,减少一次性内存占用。

  2. 提高加载速度:并行读取多个小文件可能比读取一个大文件更快。

  3. 兼容性:某些文件系统或传输方式对单个文件的大小有限制,拆分文件可以提高兼容性。

model.safetensors.index.json 文件通过提供参数到文件的映射,确保在加载模型时,程序知道从哪个文件中读取每个参数。


模型加载流程

在加载模型时,以下是简单的流程:

  1. 读取索引文件:程序首先读取 model.safetensors.index.json 文件,获取 metadataweight_map

  2. 初始化模型结构:根据模型定义,初始化模型的各层和参数(名称对应)。

  3. 加载参数:遍历 weight_map,对于每个参数:

    • 参数名称:如 model.layers.0.self_attn.q_proj.weight

    • 对应文件:如 model-00001-of-00002.safetensors

    • 从文件中读取参数:程序打开对应的文件,读取指定的参数。

  4. 组装模型:将读取的参数赋值到模型的对应位置,完成模型的加载。


文件拆分示例

weight_map 可以看到,模型的参数被拆分存储在两个文件中:

  • model-00001-of-00002.safetensors

  • model-00002-of-00002.safetensors

例如:

  • 参数 model.layers.0.mlp.down_proj.weight 被存储在 model-00001-of-00002.safetensors 中。

  • 参数 model.layers.13.mlp.down_proj.weight 被存储在 model-00002-of-00002.safetensors 中。

这表明模型的前半部分参数被存储在第一个文件,后半部分参数被存储在第二个文件。这种拆分可能是按照模型的层数或参数大小来进行的。


SafeTensors 格式的优势

  • 安全性:SafeTensors 格式避免了在加载不可信模型时可能出现的代码执行漏洞,因为它不使用 Python 的 pickle 序列化。

  • 高效性:文件格式简单轻量,支持更快的加载速度。

  • 零拷贝加载:支持内存映射(memory mapping),在可能的情况下,可以无需拷贝数据就直接使用,从而提高效率。


总结

  • model.safetensors.index.json 的作用:索引模型的参数文件,以便在加载模型时知道每个参数存储的位置。

  • metadata 部分:包含模型参数的总大小等元数据。

  • weight_map 部分:映射每个参数到其所在的文件。

  • 拆分文件的目的:解决大模型的存储和加载问题,提高效率和兼容性。

  • 模型加载过程:通过读取索引文件,逐个从对应的文件中加载参数,组装成完整的模型。

分析 tokenizer_config.json 文件内容

tokenizer_config.json 文件用于配置模型的 分词器(Tokenizer),这是深度学习模型,特别是自然语言处理(NLP)模型的重要组成部分。分词器负责将输入的文本转换为模型可以理解的 词元(Token) 序列,以及将模型生成的词元序列转换回人类可读的文本。

该配置文件定义了分词器的行为方式、特殊标记(Special Tokens)、最大序列长度等参数,确保分词器在编码和解码过程中正确地处理文本,使其与模型的预期行为一致。


文件内容及参数解释

以下是您提供的 tokenizer_config.json 文件的内容及每个参数的详细解释:

{
  "add_prefix_space": false,
  "added_tokens_decoder": {
    "151644": {
      "content": "",
      "lstrip": false,
      "normalized": false,
      "rstrip": false,
      "single_word": false,
      "special": true
    },
    "151645": {
      "content": "",
      "lstrip": false,
      "normalized": false,
      "rstrip": false,
      "single_word": false,
      "special": true
    },
    "151646": {
      "content": "<|object_ref_start|>",
      "lstrip": false,
      "normalized": false,
      "rstrip": false,
      "single_word": false,
      "special": true
    },
    "151647": {
      "content": "<|object_ref_end|>",
      "lstrip": false,
      "normalized": false,
      "rstrip": false,
      "single_word": false,
      "special": true
    },
    "151648": {
      "content": "<|box_start|>",
      "lstrip": false,
      "normalized": false,
      "rstrip": false,
      "single_word": false,
      "special": true
    },
    "151649": {
      "content": "<|box_end|>",
      "lstrip": false,
      "normalized": false,
      "rstrip": false,
      "single_word": false,
      "special": true
    },
    "151650": {
      "content": "<|quad_start|>",
      "lstrip": false,
      "normalized": false,
      "rstrip": false,
      "single_word": false,
      "special": true
    },
    "151651": {
      "content": "<|quad_end|>",
      "lstrip": false,
      "normalized": false,
      "rstrip": false,
      "single_word": false,
      "special": true
    },
    "151652": {
      "content": "<|vision_start|>",
      "lstrip": false,
      "normalized": false,
      "rstrip": false,
      "single_word": false,
      "special": true
    },
    "151653": {
      "content": "<|vision_end|>",
      "lstrip": false,
      "normalized": false,
      "rstrip": false,
      "single_word": false,
      "special": true
    },
    "151654": {
      "content": "<|vision_pad|>",
      "lstrip": false,
      "normalized": false,
      "rstrip": false,
      "single_word": false,
      "special": true
    },
    "151655": {
      "content": "<|image_pad|>",
      "lstrip": false,
      "normalized": false,
      "rstrip": false,
      "single_word": false,
      "special": true
    },
    "151656": {
      "content": "<|video_pad|>",
      "lstrip": false,
      "normalized": false,
      "rstrip": false,
      "single_word": false,
      "special": true
    },
    "151657": {
      "content": "<tool_call>",
      "lstrip": false,
      "normalized": false,
      "rstrip": false,
      "single_word": false,
      "special": false
    },
    "151658": {
      "content": "</tool_call>",
      "lstrip": false,
      "normalized": false,
      "rstrip": false,
      "single_word": false,
      "special": false
    },
    "151659": {
      "content": "",
      "lstrip": false,
      "normalized": false,
      "rstrip": false,
      "single_word": false,
      "special": false
    },
    "151660": {
      "content": "",
      "lstrip": false,
      "normalized": false,
      "rstrip": false,
      "single_word": false,
      "special": false
    },
    "151661": {
      "content": "<|fim_suffix|>",
      "lstrip": false,
      "normalized": false,
      "rstrip": false,
      "single_word": false,
      "special": false
    },
    "151662": {
      "content": "<|fim_pad|>",
      "lstrip": false,
      "normalized": false,
      "rstrip": false,
      "single_word": false,
      "special": false
    },
    "151663": {
      "content": "<|repo_name|>",
      "lstrip": false,
      "normalized": false,
      "rstrip": false,
      "single_word": false,
      "special": false
    },
    "151664": {
      "content": "<|file_sep|>",
      "lstrip": false,
      "normalized": false,
      "rstrip": false,
      "single_word": false,
      "special": false
    }
  },
  "additional_special_tokens": [
    "",
    "",
    "<|object_ref_start|>",
    "<|object_ref_end|>",
    "<|box_start|>",
    "<|box_end|>",
    "<|quad_start|>",
    "<|quad_end|>",
    "<|vision_start|>",
    "<|vision_end|>",
    "<|vision_pad|>",
    "<|image_pad|>",
    "<|video_pad|>"
  ],
  "bos_token": null,
  "chat_template": "{...}",
  "clean_up_tokenization_spaces": false,
  "eos_token": "",
  "errors": "replace",
  "model_max_length": 131072,
  "split_special_tokens": false,
  "tokenizer_class": "Qwen2Tokenizer",
  "unk_token": null,
  "add_bos_token": false
}
1. "add_prefix_space": false
  • 含义:指定在分词时,是否在词元前添加空格。
  • 作用:当设置为 true 时,在处理词与词之间的空格时,会在某些情况下在词元前添加一个空格,防止某些情况下的词元合并错误。false 表示不添加前缀空格。
2. "added_tokens_decoder": { ... }
  • 含义:定义了分词器中新增的特殊词元及其属性,映射词元 ID 到其对应的内容。

  • 作用:告知分词器如何将特殊的词元 ID 解码回对应的文本内容。

  • 详细内容

    • 示例

      • "151644":对应特殊标记 ``,通常用于表示一段文本的开始。

        • 属性解释

          • "lstrip":在分词时是否去除该标记前的空格,false 表示不去除。
          • "normalized":该标记是否已标准化,false
          • "rstrip":在分词时是否去除该标记后的空格,false
          • "single_word":是否仅匹配单个词,false
          • "special":是否为特殊标记,true 表示是特殊标记。
      • "151645":对应特殊标记 ``,表示一段文本的结束。

      • 其他词元 ID 与内容:

        • "151646"<|object_ref_start|>,对象引用的开始。
        • "151647"<|object_ref_end|>,对象引用的结束。
        • "151648"<|box_start|>,框的开始。
        • "151649"<|box_end|>,框的结束。
        • "151650"<|quad_start|>,四边形的开始。
        • "151651"<|quad_end|>,四边形的结束。
        • "151652"<|vision_start|>,视觉内容的开始。
        • "151653"<|vision_end|>,视觉内容的结束。
        • "151654"<|vision_pad|>,视觉内容的填充标记。
        • "151655"<|image_pad|>,图像填充标记。
        • "151656"<|video_pad|>,视频填充标记。
        • "151657"<tool_call>,工具调用的开始。
        • "151658"</tool_call>,工具调用的结束。
        • "151659":``,可能用于代码填充前缀。
        • "151660":``,代码填充中间部分。
        • "151661"<|fim_suffix|>,代码填充后缀。
        • "151662"<|fim_pad|>,代码填充的填充标记。
        • "151663"<|repo_name|>,代码仓库名称。
        • "151664"<|file_sep|>,文件分隔符。
3. "additional_special_tokens": [ ... ]
  • 含义:额外的特殊标记列表,包含需要在分词器中额外处理的特殊词元。

  • 作用:确保这些特殊标记在分词和解码过程中被正确识别和处理,不被拆分或忽略。

  • 列出的特殊标记

    • , , <|object_ref_start|>, <|object_ref_end|>, <|box_start|>, <|box_end|>, <|quad_start|>, <|quad_end|>, <|vision_start|>, <|vision_end|>, <|vision_pad|>, <|image_pad|>, <|video_pad|>
4. "bos_token": null
  • 含义:序列开始标记(Begin of Sequence Token)。
  • 作用:如果设置了 bos_token,在文本编码或生成时,序列开始会添加该标记。
  • 当前设置为 null,表示不使用特殊的序列开始标记。
5. "chat_template": "{...}"
  • 含义:对话模板,用于格式化多轮对话的结构。

  • 作用:定义了不同角色(如用户、系统、助手)之间消息的组织方式,以及如何在生成回复时提供上下文。

  • 内容说明

    • 该模板使用了 Jinja2 模板语言,包含了条件判断和循环等模板指令。
    • 模板中定义了如何将 toolsmessagestool_calls 等信息组织成模型可以理解的输入格式。
    • 使用特殊标记(如 )来区分不同角色和消息的边界。
  • 示例

    • 系统消息的格式:

      system
      系统消息内容
      
      
    • 用户消息的格式:

      user
      用户消息内容
      
      
    • 助手消息的格式(可能包含工具调用):

      assistant
      助手回复内容
      <tool_call>
      {"name": "工具名称", "arguments": {"参数": "值"}}
      </tool_call>
      
      
6. "clean_up_tokenization_spaces": false
  • 含义:在解码过程中是否清理多余的空格。
  • 作用false 表示保留原始的空格,true 则会清理多余的空格,以获得更干净的输出。
7. "eos_token": "<|im_end|>"
  • 含义:序列结束标记(End of Sequence Token)。
  • 作用:指示文本序列的结束,模型在生成文本时遇到该标记会停止生成。
8. "errors": "replace"
  • 含义:在解码字节为字符串时处理错误的方式。
  • 作用"replace" 表示当遇到无法解码的字节时,用替代字符(通常是 )替换。
9. "model_max_length": 131072
  • 含义:模型支持的最大序列长度。
  • 作用:限制输入序列的最大长度,超过该长度的序列可能会被截断或引发错误。
10. "split_special_tokens": false
  • 含义:是否拆分特殊标记中的词元。
  • 作用false 表示特殊标记作为一个整体处理,不被拆分。true 则可能将特殊标记拆分为更小的词元。
11. "tokenizer_class": "Qwen2Tokenizer"
  • 含义:分词器的类名。
  • 作用:指定使用的分词器类型,这里是 Qwen2Tokenizer,表示模型使用特定的自定义分词器。
12. "unk_token": null
  • 含义:未知词元标记(Unknown Token)。

  • 作用:当输入的词无法在词汇表中找到时,用于替代的标记。

  • 当前设置为 null,可能表示以下情况:

    • 不使用特殊的未知词元标记。
    • 分词器可能使用其他方式处理未知词元,如基于子词或字节对编码(BPE)。
13. "add_bos_token": false
  • 含义:是否在编码时添加开始标记 bos_token
  • 作用false 表示不自动在序列开头添加 bos_token

总结

tokenizer_config.json 文件为模型的分词器提供了详细的配置,确保特殊标记和词元在编码和解码过程中被正确处理。

  • 特殊标记:定义了许多用于表示特殊含义的标记,如对话开始和结束、视觉内容的边界、对象引用、工具调用等。这些标记对于多模态模型(处理文本和视觉信息的模型)以及需要复杂上下文管理的模型非常重要。

  • 分词器行为:通过参数如 add_prefix_spaceclean_up_tokenization_spacessplit_special_tokens 等,控制分词器在处理空格、标点、特殊标记时的行为。

  • 模型兼容性:指定了分词器类名 Qwen2Tokenizer,保证了分词器与模型的架构和需求相匹配。

  • 序列长度model_max_length 设置了模型支持的最大序列长度,确保在处理长文本时不会超出模型的能力范围。

  • 对话模板chat_template 提供了一个灵活的模板,用于构建与模型交互的输入格式,适用于多轮对话和工具调用等复杂场景。


注意:当在实际使用模型时,分词器的配置必须与模型的训练方式和预期输入格式一致。使用不正确的分词器配置可能导致模型性能下降或产生错误的结果。

分析 tokenizer.json 文件内容

tokenizer.json 文件是用于配置模型的 分词器(Tokenizer) 的核心文件。分词器是自然语言处理模型中关键的组件,负责将输入的文本 编码(Encode) 为模型可以理解的 词元(Token) 序列,以及将模型生成的词元序列 解码(Decode) 回可读的文本。

该文件详细定义了分词器的所有必要信息,包括:

  • 词汇表(vocab):词元与其唯一 ID(索引)之间的映射。
  • 合并规则(merges):用于构建词元的字节对编码(Byte-Pair Encoding,BPE)合并规则。
  • 预处理和后处理逻辑:包括正则化(Normalizer)、预分词器(PreTokenizer)、后处理器(PostProcessor)和解码器(Decoder)。

文件结构及参数解释

以下是 tokenizer.json 文件的主要结构及其组成部分的详细解释:

{
  "version": "1.0",
  "truncation": null,
  "padding": null,
  "added_tokens": [ ... ],
  "normalizer": { ... },
  "pre_tokenizer": { ... },
  "post_processor": { ... },
  "decoder": { ... },
  "model": {
    "type": "BPE",
    "vocab": { ... },
    "merges": [ ... ],
    ...
  }
}

1. "version": "1.0"
  • 含义:分词器配置文件的版本号。
  • 作用:用于确保分词器的配置与分词器库或模型版本兼容。

2. "truncation""padding"
  • 含义:关于 截断填充 策略的配置。
  • 当前值null,表示没有全局指定截断和填充策略,通常在使用分词器时可以动态指定。

3. "added_tokens": [ ... ]
  • 含义:定义了分词器中添加的特殊词元及其属性。

  • 作用:确保在编码和解码过程中,这些特殊词元被正确处理,不被拆分或忽略。

  • 示例

    {
      "id": 151644,
      "content": "",
      "single_word": false,
      "lstrip": false,
      "rstrip": false,
      "normalized": false,
      "special": true
    }
    
    • 解释

      • "id":词元的唯一标识符。
      • "content":词元的文本表示。
      • "special"true 表示这是一个特殊的词元。
      • 其他参数(如 "lstrip""rstrip")指定了在分词时是否去除前后空格等。
  • 常见的特殊词元

    • """":用于标记消息或段落的开始和结束,尤其在对话模型中。
    • "<|vision_start|>""<|vision_end|>":用于标记视觉内容的开始和结束,适用于多模态模型。
    • 其他的特殊标记如 "<|object_ref_start|>""<|box_start|>" 等,也用于特殊的标记功能。

4. "normalizer": { ... }
  • 含义:定义文本正则化的策略。

  • 示例

    {
      "type": "NFC"
    }
    
    • 解释:使用 Unicode 正规化形式 C(Normalization Form C,NFC)对文本进行标准化,确保文本的一致性。

5. "pre_tokenizer": { ... }
  • 含义:定义预分词器,用于在正式分词前对文本进行初步拆分。

  • 示例

    {
      "type": "Sequence",
      "pretokenizers": [
        {
          "type": "Split",
          "pattern": {
            "Regex": "(正则表达式)"
          },
          "behavior": "Isolated",
          "invert": false
        },
        {
          "type": "ByteLevel",
          "add_prefix_space": false,
          "trim_offsets": false,
          "use_regex": false
        }
      ]
    }
    
    • 解释

      • 第一个预分词器

        • "type": "Split":使用拆分策略。
        • "pattern":指定了用于拆分的正则表达式。这允许根据特定的模式将文本拆分为更小的片段。
        • "behavior": "Isolated":每个匹配项作为一个独立的段。
      • 第二个预分词器

        • "type": "ByteLevel":使用字节级别的预分词器。
        • 作用:将文本转换为字节序列,为后续的 BPE 分词器做准备。

6. "post_processor": { ... }"decoder": { ... }
  • 含义

    • 后处理器(PostProcessor):在分词后对词元序列进行处理,例如添加特殊的起始和结束标记。
    • 解码器(Decoder):将词元序列转换回可读文本。
  • 示例

    {
      "type": "ByteLevel",
      "add_prefix_space": false,
      "trim_offsets": false,
      "use_regex": false
    }
    
    • 解释:使用字节级别的策略处理,确保在编码和解码过程中字符和字节的一致性。

7. "model": { ... }
  • 含义:定义了分词器的核心模型和参数,特别是词汇表和合并规则。

  • 主要参数

    • "type": "BPE":使用 字节对编码(Byte-Pair Encoding, BPE) 的分词算法。

    • 词汇表(“vocab”)

      • 作用:映射词元(通常是字符串)到唯一的索引(整数 ID)。

      • 内容:包括所有可能的词元,如常见的单词、子词、标点符号、特殊符号等。

      • 示例

        "vocab": {
          "!": 0,
          "\"": 1,
          "#": 2,
          "$": 3,
          "%": 4,
          "&": 5,
          "'": 6,
          "(": 7,
          ")": 8,
          "*": 9,
          "+": 10,
          ...
          "âį¨": 151640,
          "âºŁ": 151641,
          "â½Ĺ": 151642
        }
        
        • 解释

          • 开头部分是一些常见的标点符号和数字字符,映射到对应的索引。

          • 后面的词元,如 "âį¨""âºŁ""â½Ĺ",看起来像“乱码”。

            • 原因

              • 这是由于 BPE 分词器的算法特点,可能会生成一些看似无意义的字符组合。
              • 在训练分词器时,为了覆盖所有可能的输入字符和字符序列,BPE 会将罕见的或未知的字符组合也作为词元。
              • 如果文本中存在非 ASCII 字符,或者在编码和解码过程中出现了字符编码问题(如 UTF-8 与其他编码之间的转换错误),就可能出现看似“乱码”的字符。
    • 合并规则(“merges”)

      • 作用:定义了 BPE 分词器如何将字符或子词逐步合并为更大的词元。

      • 内容:按照频率或概率排序的字符或子词对。

      • 示例

        "merges": [
          "Ġ Ġ",
          "ĠĠ ĠĠ",
          "i n",
          ...
          "âį ¨",
          "⺠Ł",
          "â½ Ĺ"
        ]
        
        • 解释

          • "Ġ Ġ""ĠĠ ĠĠ":这些可能是分词器用于处理空格或特殊标记的合并规则。

          • "i n":表示将字符 'i''n' 合并为子词 'in'

          • 乱码字符

            • "âį ¨""⺠Ł""â½ Ĺ",同样由于字符编码问题或 BPE 产生的罕见合并规则而出现。
            • 这些合并规则可能用于处理非拉丁字符集、特殊符号或在训练数据中出现的稀有字符组合。

tokenizer.json、tokenizer_config.json代码示例

步骤概述

  1. 加载 tokenizer.json 构建分词器。
  2. tokenizer_config.json 中读取特殊标记和配置并应用到分词器。
  3. 使用分词器对文本进行编码和解码。

所需库

我们将使用 transformerstokenizers 库。

请确保已安装如下库:

pip install transformers==4.31.0 tokenizers==0.13.3

代码示例

from transformers import PreTrainedTokenizerFast
import json

# 1. 加载 tokenizer.json 构建分词器
tokenizer = PreTrainedTokenizerFast(
    tokenizer_file='tokenizer.json'  # 确保该文件在当前目录下
)

# 2. 从 tokenizer_config.json 中读取配置
with open('tokenizer_config.json', 'r', encoding='utf-8') as f:
    tokenizer_config = json.load(f)

# 应用特殊标记和其他配置
special_tokens = {}

if 'bos_token' in tokenizer_config and tokenizer_config['bos_token']:
    special_tokens['bos_token'] = tokenizer_config['bos_token']

if 'eos_token' in tokenizer_config and tokenizer_config['eos_token']:
    special_tokens['eos_token'] = tokenizer_config['eos_token']

if 'unk_token' in tokenizer_config and tokenizer_config['unk_token']:
    special_tokens['unk_token'] = tokenizer_config['unk_token']

if 'pad_token' in tokenizer_config and tokenizer_config['pad_token']:
    special_tokens['pad_token'] = tokenizer_config['pad_token']

if 'additional_special_tokens' in tokenizer_config:
    special_tokens['additional_special_tokens'] = tokenizer_config['additional_special_tokens']

# 添加特殊标记到分词器
tokenizer.add_special_tokens(special_tokens)

# 3. 使用分词器对文本进行编码和解码
text = "你好,世界!This is a test."

# 编码:将文本转换为模型可识别的 token ID 列表
encoded = tokenizer.encode(text)
print("编码后的 token ID:", encoded)

# 解码:将 token ID 列表转换回可读文本
decoded = tokenizer.decode(encoded)
print("解码后的文本:", decoded)

代码解释

  • 加载分词器

    • 使用 PreTrainedTokenizerFast 并指定 tokenizer_file 参数加载 tokenizer.json 文件,该文件包含了分词器的所有必要信息。
  • 读取并应用配置

    • 打开 tokenizer_config.json 文件,读取其中的特殊标记和其他配置参数。
    • 使用 add_special_tokens 方法将特殊标记添加到分词器中,确保分词器能够正确处理这些标记。
  • 编码和解码

    • 使用 tokenizer.encode(text) 方法将输入文本转换为模型可识别的 token ID 列表。
    • 使用 tokenizer.decode(encoded) 方法将 token ID 列表转换回可读文本。
编码后的 token ID: [108386, 3837, 99489, 6313, 1986, 374, 264, 1273, 13]
解码后的文本: 你好,世界!This is a test.

分析 merges.txt 、vocab.json 文件内容

如果需要直接使用 vocab.jsonmerges.txt 来构建分词器,可以使用以下代码:

from tokenizers import Tokenizer
from tokenizers.models import BPE
from tokenizers.decoders import ByteLevel as ByteLevelDecoder
from tokenizers.normalizers import Sequence, NFD, Lowercase, StripAccents
from tokenizers.pre_tokenizers import ByteLevel as ByteLevelPreTokenizer
from transformers import PreTrainedTokenizerFast

import json

# 1. 加载 vocab.json 和 merges.txt
with open('vocab.json', 'r', encoding='utf-8') as f:
    vocab = json.load(f)

with open('merges.txt', 'r', encoding='utf-8') as f:
    merges = f.read().split('\n')
    merges = [tuple(merge.split()) for merge in merges if merge and not merge.startswith('#')]

# 2. 构建 BPE 分词器
tokenizer_model = BPE(vocab=vocab, merges=merges)

# 3. 初始化 Tokenizer
tokenizer = Tokenizer(tokenizer_model)

# 4. 设置预处理器、解码器等
tokenizer.normalizer = Sequence([NFD(), Lowercase(), StripAccents()])
tokenizer.pre_tokenizer = ByteLevelPreTokenizer()
tokenizer.decoder = ByteLevelDecoder()

# 5. 包装为 PreTrainedTokenizerFast
wrapper = PreTrainedTokenizerFast(tokenizer_object=tokenizer)

# 6. 从 tokenizer_config.json 中读取配置并应用
with open('tokenizer_config.json', 'r', encoding='utf-8') as f:
    tokenizer_config = json.load(f)

special_tokens = {}

if 'bos_token' in tokenizer_config and tokenizer_config['bos_token']:
    special_tokens['bos_token'] = tokenizer_config['bos_token']

if 'eos_token' in tokenizer_config and tokenizer_config['eos_token']:
    special_tokens['eos_token'] = tokenizer_config['eos_token']

if 'unk_token' in tokenizer_config and tokenizer_config['unk_token']:
    special_tokens['unk_token'] = tokenizer_config['unk_token']

if 'pad_token' in tokenizer_config and tokenizer_config['pad_token']:
    special_tokens['pad_token'] = tokenizer_config['pad_token']

if 'additional_special_tokens' in tokenizer_config:
    special_tokens['additional_special_tokens'] = tokenizer_config['additional_special_tokens']

# 添加特殊标记到分词器
wrapper.add_special_tokens(special_tokens)

# 7. 使用分词器对文本进行编码和解码
text = "你好,世界!This is a test."

encoded = wrapper.encode(text)
print("编码后的 token ID:", encoded)

decoded = wrapper.decode(encoded)
print("解码后的文本:", decoded)

代码解释

  • 加载词汇表和合并规则

    • 读取 vocab.jsonmerges.txt 文件,分别获得词汇表和 BPE 合并规则。
  • 构建分词器模型

    • 使用 tokenizers 库的 BPE 模型,传入词汇表和合并规则,构建分词器模型。
  • 设置正则化、预分词器和解码器

    • 设置正则化器(normalizer),例如将文本统一为小写、去除重音符号等。
    • 设置预分词器(pre_tokenizer),使用字节级预分词器 ByteLevelPreTokenizer
    • 设置解码器(decoder),使用字节级解码器 ByteLevelDecoder
  • 包装为 PreTrainedTokenizerFast

    • 将构建的分词器模型包装为 PreTrainedTokenizerFast 实例,便于与 transformers 库兼容。
  • 应用特殊标记和配置

    • 与之前的步骤类似,从 tokenizer_config.json 中读取特殊标记并应用到分词器中。
  • 编码和解码

    • 使用分词器对文本进行编码和解码。
编码后的 token ID: [108386, 3837, 99489, 6313, 574, 374, 264, 1273, 13]
解码后的文本: 你好,世界!this is a test.

在之前的示例中,我们通过两种方式构建了分词器:

  1. 使用 tokenizer.json:这个文件包含了分词器的完整配置,包括词汇表(vocab)、BPE 合并规则(merges)、正则化器、预分词器、后处理器等所有必要信息。

  2. 使用 vocab.jsonmerges.txt:分别加载词汇表和 BPE 合并规则,然后手动构建分词器,并设置正则化器、预分词器和解码器。

这两种方式最终 实现了相同的功能,即构建了一个分词器,可以将文本编码为模型可理解的 Token ID 序列,并将其解码回可读文本。


tokenizer.jsonvocab.json + merges.txt 的关系

  • tokenizer.json

    • 综合性:这是一个综合的分词器配置文件,包含了分词器运行所需的所有信息。
    • 内容
      • 词汇表(vocab):与 vocab.json 相同的词元到索引的映射。
      • BPE 合并规则(merges):与 merges.txt 相同的 BPE 合并规则列表。
      • 其他配置:包括正则化器、预分词器、后处理器、解码器等,以及特殊标记和其他参数。
  • vocab.jsonmerges.txt

    • 独立性:这两个文件分别包含词汇表和 BPE 合并规则。
    • 内容
      • vocab.json:词元到索引的映射。
      • merges.txt:BPE 合并规则列表,按照频率排序。
    • 用途:需要手动构建分词器,并设置其他必要的组件(正则化器、预分词器等)。

因此,tokenizer.json 实际上包含了 vocab.jsonmerges.txt 的内容,以及更多的配置。


Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐