【大模型】Transformers基础组件 - Tokenizer

Hugging Face 的 Transformers 库是目前最流行和功能最强大的自然语言处理(NLP)库之一,提供了对大量预训练模型的访问和支持。这些模型涵盖了文本生成、文本分类、命名实体识别、机器翻译等多种任务。Hugging Face 的 Transformers 库提供了 Tokenizer(分词器)、Model(模型)、Pipeline(流水线)等模块,便于灵活使用。

本篇博客我们主要介绍基于Hugging Face 的 Transformers 库进行Tokenizer的基本使用Tokenizer的训练

1. Tokenizer的基本使用

本部分内容主要参考博客: 【Transformers基础入门篇3】基础组件之Tokenizer

HuggingFace的Transformers库中提供了许多经典大模型(如BERT、GPT、Llama等)的Tokenizer,可以基于 AutoTokenizer 来自动适配并使用。

# 先从transformers 导入 AutoTokenizer 
from transformers import AutoTokenizer
input = 'What is machine learning?'

1.1 Tokenizer的加载及保存

  • 从HuggingFace加载,输入模型名称或者路径,即可加载对应的分词器
model_path = '../model/Meta-Llama-3-8B'
tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
  • 将tokenizer 保存到本地
tokenizer.save_pretrained("./llama_tokenizer")
  • 从本地加载tokenizer
tokenizer = AutoTokenizer.from_pretrained("./llama_tokenizer/")
  • 查看词典
print(tokenizer.vocab)  # 查看词典

输出的部分词典如下:

'Äıte': 122957, 'į°ìĿ´': 47318, 'Ġpropia': 98429, 'Ġobscene': 84109, 'Ġstehen': 65957, 'Ġexpansions': 78588, 'ĠpÅĻÃŃ': 100578, 'nite': 62664, 'Emp': 29831, 'ui': 2005, 'g': 70, 'ĠPlatform': 17916, 'ĠHanson': 76313, '-suite': 92674, 'Term': 17695, 'ιÏĥÏĦο': 122974, 'Ġgord': 94913,

其中,Ġ是拉丁文表示,代表分词中的空格。

  • 查看词典大小
print(tokenizer.vocab_size)  # 查看词典的大小

输出如下:

128000

1.2 分词

tokenizer.tokenize() 将输入文本拆分为 token 列表。它只负责将文本分词为子词单元(subword),而不进行其他处理(如添加特殊标记符、转换为 token ID 等)

input = 'What is machine learning?'
tokens = tokenizer.tokenize(input)
print('tokens:', tokens)

输出如下:

tokens: ['What', 'Ġis', 'Ġmachine', 'Ġlearning', '?']

1.3 索引转换

(1)基于tokenizer.encode函数

在 tranformers 库中,我们可以直接基于 tokenizer.encode函数将词序列转换为token的id序列。

ids = tokenizer.encode(input)
print('ids:', ids)

输出如下:

ids: [3923, 374, 5780, 6975, 30]

(2)基于 tokenizer.convert_ 系列函数

如果我们想详细的看到整个转换的过程,可以基于 tokenizer.convert_ 系列函数进行处理,如下所示:

tokens = tokenizer.tokenize(input)

# 将词序列转换为id序列
ids_1 = tokenizer.convert_tokens_to_ids(tokens)
print('ids_1:', ids_1)

# 将id序列转换为token序列
tokens_1 = tokenizer.convert_ids_to_tokens(ids_1)
print('tokens_1:', tokens_1)

# 将token序列转换为string
str_sen = tokenizer.convert_tokens_to_string(tokens_1)
print('str_sen:', str_sen)

输出如下:

ids_1: [3923, 374, 5780, 6975, 30]
tokens_1: ['What', 'Ġis', 'Ġmachine', 'Ġlearning', '?']
str_sen: What is machine learning?

2. Tokenizer的训练

2.1 BPE分词

本文主要以 Byte-Pair Encoding(BPE) 为基础分词算法来介绍Tokenizer的训练。这里,先简单介绍下BPE算法:

  • 训练方法:从字符级的小词表出发,训练产生合并规则以及一个词表
  • 编码方法:将文本切分成字符,再应用训练阶段获得的合并规则
  • 经典模型:GPT, GPT-2, RoBERTa, BART, LLaMA, ChatGLM等

BPE分词算法的详细介绍可以参考我之前的博客:NLP中常见的分词算法(BPE、WordPiece、Unigram、SentencePiece)

2.2 分词器训练

本部分内容主要参考博客:MiniDeepSeek分词器训练流程

针对我们自己有一份语料数据,想从头开始训练自己的大模型的情况,我们可以基于Transformers库训练自己的分词器。

在训练环节,目标是给定语料,通过训练算法,生成合并规则和词表。 BPE算法是从一个字符级别的词表为基础,合并pair并添加到词表中,逐步形成大词表。合并规则为选择相邻pair词频最大的进行合并。具体步骤如下:

  • Step 1.导入必要的库
import random
from tqdm import tqdm
from transformers import AutoTokenizer
import json
from datasets import load_dataset
from tokenizers import (
    decoders,
    models,
    normalizers,
    pre_tokenizers,
    processors,
    trainers,
    Tokenizer,
)
import os
  • Step 2.读取 tokenizer_train.jsonl 文件
def read_texts_from_jsonl(file_path):
    with open(file_path, 'r', encoding='utf-8') as f:
        for line in f:
            data = json.loads(line)
            yield data['text']

# 测试读取数据
data_path = './dataset/tokenizer_train.jsonl'
texts = read_texts_from_jsonl(data_path)

# 打印前几行文本
for i, text in enumerate(texts):
    if i < 5:
        print(text)
    else:
        break
  • Step 3.初始化分词器

首先,通过 models.BPE() 创建了一个基于 Byte-Pair Encoding (BPE) 模型的分词器。

# 初始化tokenizer
tokenizer = Tokenizer(models.BPE())
tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=False)

# 定义特殊token
special_tokens = ["<unk>", "<s>", "</s>"]

# 设置训练器并添加特殊token
trainer = trainers.BpeTrainer(
    vocab_size=6400,
    special_tokens=special_tokens,  # 确保这三个token被包含
    show_progress=True,
    initial_alphabet=pre_tokenizers.ByteLevel.alphabet()
)

print("分词器初始化成功,准备训练。")
  • Step 4.训练分词器
# 读取文本数据
texts = read_texts_from_jsonl(data_path)

# 训练tokenizer
tokenizer.train_from_iterator(texts, trainer=trainer)

print("分词器训练完成!")
  • Step 5.保存分词器
    在训练完毕之后,还需要设置解码器 (tokenizer.decoder = decoders.ByteLevel()) ,这是为了在生成文本时正确地将分词器产生的 token 序列还原回原始文本。
# 设置解码器
tokenizer.decoder = decoders.ByteLevel()

# 保存tokenizer
tokenizer_dir = "./model/miniDeepSeek_tokenizer"
os.makedirs(tokenizer_dir, exist_ok=True)
tokenizer.save(os.path.join(tokenizer_dir, "tokenizer.json"))
tokenizer.model.save("./model/miniDeepSeek_tokenizer")

# 手动创建配置文件
config = {
    "add_bos_token": False,
    "add_eos_token": False,
    "add_prefix_space": True,
    "added_tokens_decoder": {
        "0": {
            "content": "<unk>",
            "lstrip": False,
            "normalized": False,
            "rstrip": False,
            "single_word": False,
            "special": True
            },
        "1": {
            "content": "<s>",
            "lstrip": False,
            "normalized": False,
            "rstrip": False,
            "single_word": False,
            "special": True
            },
        "2": {
            "content": "</s>",
            "lstrip": False,
            "normalized": False,
            "rstrip": False,
            "single_word": False,
            "special": True
            }
    },
    "bos_token": "<s>",
    "clean_up_tokenization_spaces": False,
    "eos_token": "</s>",
    "legacy": True,
    "model_max_length": 1000000000000000019884624838656,
    "pad_token": None,
    "sp_model_kwargs": {},
    "spaces_between_special_tokens": False,
    "tokenizer_class": "PreTrainedTokenizerFast",
    "unk_token": "<unk>",
    "use_default_system_prompt": False,
    "chat_template": "{% if messages[0]['role'] == 'system' %}{% set system_message = messages[0]['content'] %}{% endif %}{% if system_message is defined %}{{ system_message }}{% endif %}{% for message in messages %}{% set content = message['content'] %}{% if message['role'] == 'user' %}{{ '<s>user\\n' + content + '</s>\\n<s>assistant\\n' }}{% elif message['role'] == 'assistant' %}{{ content + '</s>' + '\\n' }}{% endif %}{% endfor %}"
}

# 保存配置文件
with open(os.path.join(tokenizer_dir, "tokenizer_config.json"), "w", encoding="utf-8") as config_file:
    json.dump(config, config_file, ensure_ascii=False, indent=4)

print("Tokenizer 保存成功!")

保存完成的分词器相关文件如下所示:
在这里插入图片描述

参考资料

### 解决方案 在处理 `transformers-stream-generator` 报错问题时,可以从以下几个方面入手: #### 1. 路径错误修正 如果模型路径设置不正确,可能会导致安装失败或其他运行时错误。确保指定的路径有效并指向正确的文件夹或存储位置[^1]。 ```bash pip install einops transformers_stream_generator ``` 上述命令用于安装必要的依赖库 `einops` 和 `transformers_stream_generator`。如果遇到路径相关的问题,请确认本地环境变量配置无误,并验证网络连接是否正常。 --- #### 2. macOS 下安装 Tokenizer 的兼容性问题 对于 macOS 用户,在安装 Hugging Face 的 `transformers` 或其相关组件(如 `tokenizers`)时,可能出现编译错误。具体表现为以下提示信息: ``` ERROR: Could not build wheels for tokenizers which use PEP 517 ... ``` 此问题是由于某些 C++ 扩展无法通过 Python 编译器构建所致。以下是两种常见解决方法[^2]: - **升级工具链版本** 确保 Xcode 命令行工具已更新至最新版本: ```bash xcode-select --install ``` - **手动安装预编译二进制包** 如果仍存在问题,可尝试直接下载官方提供的轮子文件 (wheel),并通过以下方式完成安装: ```bash pip install tokenizers --no-use-pep517 ``` --- #### 3. 流式返回机制优化 部分情况下,API 请求未即时响应可能是由客户端工具(如 Postman)的行为引起。尽管服务端已经支持流式传输数据,Postman 可能会阻塞直到整个请求结束才显示结果。这一现象已在较新的 Postman 版本中修复[^3]。 建议采取以下措施以改善体验: - 更新到最新的 Postman 应用程序; - 使用其他 HTTP 客户端测试接口性能,例如 cURL 或 Python 的 requests 库。 示例代码如下所示: ```python import requests url = 'http://example.com/api/stream' response = requests.get(url, stream=True) for line in response.iter_lines(): if line: print(line.decode('utf-8')) ``` --- ### 总结 综合以上分析可知,针对 `transformers-stream-generator` 报错的情况需分别排查路径设定、操作系统特定依赖以及前端交互逻辑等方面因素。逐一排除潜在隐患后即可恢复正常功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值