通俗易懂理解Token分词(经验版)

一、参考资料

常识| 大模型收费计量单位之Token概念

二、Token相关介绍

1. Token简介

在 AI 领域,Token 是指模型处理的基本数据单位。它可以是单词、字符、短语甚至图像片段、声音片段等。例如,一句话会被分割成多个 Token,每个标点符号也会被视为单独的 Token。

Token 的划分方式会影响模型对数据的理解和处理。例如,中英文的 Token 划分方式就存在差异。对于中文,由于存在多音字和词组的情况,Token 的划分需要更加细致。

2. 分词策略

常见的分词策略,有按词切分 (Word-based)、按字符切分 (Character-based)、按子词切分 (Subword)三种方法。

中文示例:今天天气很好

英文示例:Let's do tokenization!

2.1 按词切分 (Word-based)

按词切分就是基于空格的 Token 化。

bash 复制代码
["今天", "天气", "很好"]
bash 复制代码
tokenized_text = "let's do tokenization".split()
print(tokenized_text)

2.2 按字符切分 (Character-based)

按字符切分就是基于字的 Token 化。

bash 复制代码
["今", "天", "天", "气", "候", "很", "好"]

2.3 按子词切分 (Subword)

3. 基于 BERT 的 Token 化

Bert会将不常用的词汇进行细分,比如fearless,经过分词输出 'fear','##less'。使用双#号表示连续词汇的分词。

在 BERT 的 Token 化结果中,[CLS][SEP] 是特殊的 Token,它们分别表示句子的开始和结束。

bash 复制代码
["今", "天", "天", "气", "候", "[CLS]", "很", "好", "[SEP]"]

4. Hugging Face分词器

Hugging Face 提供两种分词器:

  1. 慢速分词器:Transformers 库自带,使用 Python 编写。

  2. 快速分词器:Tokenizers 库提供,使用 Rust 编写。

快速分词器只有在并行处理大量文本时才能发挥出速度优势,在处理单个句子时甚至可能慢于慢速分词器。

5. Tokenizer 工具

具体的分词效果,可以通过 OpenAI 官方的 Tokenizer 工具查看:https://platform.openai.com/tokenizer

6. Tokenizer 文件

三、示例代码

Transformer中的Tokenizer分词器使用学习

1. 加载分词器

transformers.AutoTokenizer.from_pretrained

python 复制代码
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")

print("词典大小:",tokenizer.vocab_size)

输出结果

bash 复制代码
词典大小: 28996

2. 分词化

transformers.PreTrainedTokenizer.tokenize

python 复制代码
sequence = "hello world!I am Lisa."
tokens = tokenizer.tokenize(sequence)
print("分词结果:",tokens)

输出结果

bash 复制代码
分词结果: ['hello', 'world', '!', 'I', 'am', 'Lisa', '.']

3. 编码(Encode)

transformers.PreTrainedTokenizer.convert_tokens_to_ids

编码操作,实现了分词tokenize和词汇的编码convert_tokens_to_ids

python 复制代码
token_ids = tokenizer.convert_tokens_to_ids(tokens)
print(token_ids)

# 或者
token_ids = tokenizer.encode(sequence, add_special_tokens=True)

输出结果

bash 复制代码
[19082, 1362, 106, 146, 1821, 6516, 119]

4. 解码(Decode)

transformers.PreTrainedTokenizerBase.convert_tokens_to_string

transformers.PreTrainedTokenizer.convert_ids_to_tokens

解码操作,实现了词汇的解码 convert_ids_to_tokens 和转换 convert_tokens_to_string

python 复制代码
decode_result = tokenizer.convert_tokens_to_string(tokenizer.convert_ids_to_tokens(token_ids))
print("解码结果:", decode_result)

输出结果

bash 复制代码
解码结果: hello world! I am Lisa.

5. AutoTokenizer分词器

python 复制代码
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("bert-base-cased")
tokenizer.save_pretrained("./models/bert-base-cased/")

调用 Tokenizer.save_pretrained() 函数会创建以下4个文件:

bash 复制代码
(llama.cpp) root@notebook-1813389960667746306-scnlbe5oi5-79366:/public/home/scnlbe5oi5/Downloads# tree -L 1 ./models/bert-base-cased/
./models/bert-base-cased/
|-- special_tokens_map.json
|-- tokenizer.json
|-- tokenizer_config.json
`-- vocab.txt

special_tokens_map.json

映射文件,包含特殊字符的映射关系。

bash 复制代码
{
  "cls_token": "[CLS]",
  "mask_token": "[MASK]",
  "pad_token": "[PAD]",
  "sep_token": "[SEP]",
  "unk_token": "[UNK]"
}

tokenizer.json

vocab.txt 词表中的词按顺序生成索引表。模型根据索引表中的索引号编码生成one-hot向量,并与Bert中的 nn.embeding 训练权重矩阵相乘以获得该字符的随机词向量。

Bert与word2vec、glove等词嵌入向量获取方式不同,word2vec、glove属于静态查表法,输入一个单词就输出一个token向量,不考虑语义相似性。例如:"热狗"和"养条狗",虽然都有汉字"狗",但语义不同,Bert则需要输入完整语句后,结合上下文信息生成具有语义信息的狗字。

vocab.txt 词表示例:

对应的 tokenizer.json 索引表:

tokenizer_config.json

分词器配置文件,包含构建分词器需要的参数。

json 复制代码
{
  "added_tokens_decoder": {
    "0": {
      "content": "[PAD]",
      "lstrip": false,
      "normalized": false,
      "rstrip": false,
      "single_word": false,
      "special": true
    },
    "100": {
      "content": "[UNK]",
      "lstrip": false,
      "normalized": false,
      "rstrip": false,
      "single_word": false,
      "special": true
    },
    "101": {
      "content": "[CLS]",
      "lstrip": false,
      "normalized": false,
      "rstrip": false,
      "single_word": false,
      "special": true
    },
    "102": {
      "content": "[SEP]",
      "lstrip": false,
      "normalized": false,
      "rstrip": false,
      "single_word": false,
      "special": true
    },
    "103": {
      "content": "[MASK]",
      "lstrip": false,
      "normalized": false,
      "rstrip": false,
      "single_word": false,
      "special": true
    }
  },
  "clean_up_tokenization_spaces": true,
  "cls_token": "[CLS]",
  "do_lower_case": false,
  "mask_token": "[MASK]",
  "model_max_length": 512,
  "pad_token": "[PAD]",
  "sep_token": "[SEP]",
  "strip_accents": null,
  "tokenize_chinese_chars": true,
  "tokenizer_class": "BertTokenizer",
  "unk_token": "[UNK]"
}

vocab.txt

vocab.txt是词表文件,每一个 token 占一行,行号就是对应的 token ID(从 0 开始)。不同模型的词表文件会因为设置的规则不同导致内容不同,所以相同的文本序列调用不同模型的tokenizer会产生不同的整数索引。预训练模型与tokenizer必须使用相同的vocab文件和配置文件才能使输入文本序列满足模型的输入要求。

6. BertTokenizer分词器

python 复制代码
from transformers import BertTokenizer

tokenizer = BertTokenizer.from_pretrained("bert-base-cased")
tokenizer.save_pretrained("./models/bert-base-cased/")
相关推荐
长臂人猿18 天前
SpringSecurity构建登录模块
登录·token·springsecurity
@Crazy Snail1 个月前
C# 多线程异步--Token
开发语言·c#·token·task
Gungnirss1 个月前
前后端分离,后端拦截器无法获得前端请求的token
java·前端·token
卫龙~1 个月前
Django token 生成与验证
python·django·token
雪碧聊技术1 个月前
Redis6:短信登录
redis·token·拦截器·短信登录
NiNg_1_2341 个月前
Spring Boot 集成JWT实现Token验证详解
spring boot·后端·jwt·token
Hoper.J2 个月前
BPE vs WordPiece:理解 Tokenizer 的工作原理与子词分割方法
transformers·tokenizer·1024程序员节·bpe·wordpiece·子词分割方法
nameofworld2 个月前
前端面试题-token的登录流程、JWT
前端·面试·jwt·token·1024程序员节
华农第一蒟蒻3 个月前
Java中JWT(JSON Web Token)的运用
java·前端·spring boot·json·token
这孩子叫逆3 个月前
JWT(JSON Web Token)的介绍
java·token·拦截验证