1. 添加特殊 Tokens

根据模型架构和任务需求,会在序列的开头、结尾或特定位置添加特殊 tokens:

  • [CLS] (Classification Token):用于分类任务的聚合表示(如 BERT)
  • [SEP] (Separator Token):分隔句子对(如问答、自然语言推理)
  • [BOS] (Beginning of Sequence):序列开始标记
  • [EOS] (End of Sequence):序列结束标记
  • [PAD]:填充 token(稍后添加)

示例:

原始 tokens: ["我", "喜欢", "机器学习"]
添加特殊 tokens 后: ["[CLS]", "我", "喜欢", "机器学习", "[SEP]"]

2. 填充 (Padding) 或截断 (Truncation)

为了批量处理,需要将所有序列统一到相同长度:

  • Padding:较短的序列用 [PAD] token 填充到最大长度
  • Truncation:较长的序列被截断到最大长度限制
# 示例:批量序列填充
序列1: [101, 2054, 2003, 1037, 666, 102]  # 长度6
序列2: [101, 1045, 2293, 102]              # 长度4
填充后 (max_length=8):
序列1: [101, 2054, 2003, 1037, 666, 102, 0, 0]
序列2: [101, 1045, 2293, 102, 0, 0, 0, 0]

3. 创建注意力掩码 (Attention Mask)

告诉模型哪些位置是真实 tokens,哪些是填充 tokens:

  • 1 表示真实 token(需要被注意力机制关注)
  • 0 表示填充 token(应该被忽略)
# 对应上面的填充示例
注意力掩码1: [1, 1, 1, 1, 1, 1, 0, 0]
注意力掩码2: [1, 1, 1, 1, 0, 0, 0, 0]

4. 创建 Token 类型 ID (Segment IDs)

对于处理句子对的任务(如问答、自然语言推理),需要区分两个句子:

  • 0 表示属于第一个句子
  • 1 表示属于第二个句子
# 句子对: [CLS] 句子A [SEP] 句子B [SEP]
input_ids:   [101, 2054, 2003, 102, 1045, 2293, 102]
token_type_ids: [0,   0,    0,   0,   1,    1,   1]

5. 位置编码 (Positional Encoding)

由于 Transformer 的自注意力机制本身没有位置信息,需要注入位置信息:

  • 绝对位置编码:为每个位置生成固定的编码向量
  • 相对位置编码:编码 token 之间的相对距离关系
  • 学习的位置嵌入:将位置索引也作为可学习的嵌入
# 位置索引: [0, 1, 2, 3, 4, 5] (对应序列长度)
位置编码 = 位置嵌入矩阵[位置索引]

6. 转换为模型输入张量

将所有组件组合成最终的输入字典或张量元组:

{
    'input_ids': tensor([[101, 2054, 2003, 102, 0, 0]]),      # Token IDs
    'attention_mask': tensor([[1, 1, 1, 1, 0, 0]]),          # 注意力掩码
    'token_type_ids': tensor([[0, 0, 0, 0, 0, 0]]),          # Token 类型 ID
    'position_ids': tensor([[0, 1, 2, 3, 4, 5]])             # 位置 IDs(某些模型)
}

完整的数据预处理流程示例

# 假设使用 Hugging Face Transformers 库
from transformers import AutoTokenizer

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

# 原始文本
text = "Hello, how are you?"

# 1. Tokenization
tokens = tokenizer.tokenize(text)  # ["hello", ",", "how", "are", "you", "?"]

# 2. 转换为 IDs 并添加特殊 tokens
input_ids = tokenizer.encode(text)  # [101, 7592, 1010, 2129, 2024, 2017, 1029, 102]

# 3. 批量处理时:填充和创建掩码
batch_texts = ["Hello!", "How are you doing today?"]
inputs = tokenizer(
    batch_texts,
    padding=True,        # 填充到批次中最长序列
    truncation=True,     # 截断到模型最大长度
    return_tensors="pt"  # 返回 PyTorch 张量
)

print(inputs)
# {
#     'input_ids': tensor([[101, 7592, 999, 102, 0, 0], [101, 2129, 2024, 2017, 2513, 102]]),
#     'attention_mask': tensor([[1, 1, 1, 1, 0, 0], [1, 1, 1, 1, 1, 1]]),
#     'token_type_ids': tensor([[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]])
# }

总结

Tokenizer 之后的操作形成了一个完整的数据预处理流水线:

文本 → Tokenization → 添加特殊Tokens → 填充/截断 → 创建注意力掩码 → 创建Segment IDs → 位置编码 → 输入张量

这些步骤确保了不同长度、不同任务的文本都能被规范化为模型可以处理的统一格式,是 Transformer 模型能够有效工作的关键前提。

Logo

更多推荐