Hugging Face Transformers 源码学习指南

Hugging Face Transformers 源码学习指南

一、学习前准备

1.1 环境配置

# 安装依赖
pip install -e ".[dev]"
pip install torch accelerate

# 验证安装
python -c "from transformers import BertModel; print('OK')"

1.2 必读论文

按顺序阅读:

  1. Attention Is All You Need (2017) - Transformer 架构基础

  2. BERT: Pre-training of Deep Bidirectional Transformers (2018)


二、项目结构概览

2.1 Transformers 框架与模型的关系

Transformers 定义了统一的标准接口,各大模型厂商按照这个标准来实现自己的模型:

┌─────────────────────────────────────────────────────────┐
│              Transformers 框架(定义标准)                │
│  ┌─────────────────┐  ┌─────────────────┐              │
│  │ PreTrainedModel │  │ PretrainedConfig│  ...         │
│  │  - forward()    │  │  - from_dict()  │              │
│  │  - from_pretrained() │              │              │
│  └────────┬────────┘  └────────────────┘              │
└───────────┼───────────────────────────────────────────┘
            │ 继承 & 实现
            ▼
┌───────────────────────────────────────────────────────┐
│                    各厂商模型实现                        │
│  ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐     │
│  │  BERT   │ │  LLaMA  │ │  Qwen   │ │DeepSeek │ ... │
│  │ (Google)│ │ (Meta)  │ │(阿里云) │ │(深度求索)│     │
│  └─────────┘ └─────────┘ └─────────┘ └─────────┘     │
└───────────────────────────────────────────────────────┘

这样做的好处:

  • 用户侧:学会一个 API,就能用所有模型
  • 厂商侧:按标准实现,立刻获得整个生态的支持

Transformers 就像 AI 模型界的 "Android SDK",各厂商主动适配是因为:

"如果你的模型不在 Transformers 里,用户用起来就很麻烦"

2.2 目录结构

transformers/
├── src/transformers/
│   ├── models/                    # 各模型实现(重点)
│   │   ├── bert/                  # BERT 模型
│   │   ├── gpt2/                  # GPT-2 模型
│   │   ├── llama/                 # LLaMA 模型
│   │   └── ...
│   ├── configuration_utils.py     # 配置基类
│   ├── modeling_utils.py          # 模型基类 PreTrainedModel
│   ├── tokenization_utils_base.py # Tokenizer 基类
│   ├── trainer.py                 # 训练器
│   └── pipelines/                 # 推理管道
├── tests/                         # 测试代码
└── docs/                          # 文档

三、核心代码学习路径(以 BERT 为例)

3.1 学习顺序

第1步: configuration_bert.py    → 理解模型配置参数
第2步: modeling_bert.py         → 理解模型架构实现
第3步: tokenization_bert.py     → 理解文本分词
第4步: 动手调试                  → 加深理解

3.2 BERT 模型架构(对应论文)

modeling_bert.py 中的类层次:

BertModel (完整模型)
├── BertEmbeddings          # 输入嵌入层
│   ├── word_embeddings     # 词嵌入 (vocab_size × hidden_size)
│   ├── position_embeddings # 位置嵌入 (max_position × hidden_size)
│   ├── token_type_embeddings # 段落嵌入 (type_vocab_size × hidden_size)
│   ├── LayerNorm
│   └── Dropout
│
├── BertEncoder             # Transformer 编码器
│   └── BertLayer × 12      # 12 层 Transformer
│       ├── BertAttention   # 注意力模块
│       │   ├── BertSelfAttention  # 自注意力(核心!)
│       │   └── BertSelfOutput     # 输出投影 + 残差 + LayerNorm
│       ├── BertIntermediate       # FFN 第一层 (hidden → intermediate)
│       └── BertOutput             # FFN 第二层 + 残差 + LayerNorm
│
└── BertPooler              # 池化层(取 [CLS] token)

3.3 关键代码解读

3.3.1 配置类 (configuration_bert.py)

class BertConfig(PreTrainedConfig):
    def __init__(
        self,
        vocab_size=30522,           # 词表大小
        hidden_size=768,            # 隐藏层维度 (论文中的 d_model)
        num_hidden_layers=12,       # Transformer 层数
        num_attention_heads=12,     # 注意力头数
        intermediate_size=3072,     # FFN 中间层维度 (通常是 4 × hidden_size)
        hidden_act="gelu",          # 激活函数
        hidden_dropout_prob=0.1,    # Dropout 概率
        attention_probs_dropout_prob=0.1,
        max_position_embeddings=512, # 最大序列长度
        ...
    ):

3.3.2 嵌入层 (BertEmbeddings)

# 对应论文:Input Embedding = Token Embedding + Position Embedding + Segment Embedding
def forward(self, input_ids, token_type_ids, position_ids, ...):
    # 词嵌入
    inputs_embeds = self.word_embeddings(input_ids)
    # 段落嵌入(区分句子A和句子B)
    token_type_embeddings = self.token_type_embeddings(token_type_ids)
    # 位置嵌入
    position_embeddings = self.position_embeddings(position_ids)
    
    # 三者相加
    embeddings = inputs_embeds + token_type_embeddings + position_embeddings
    embeddings = self.LayerNorm(embeddings)
    embeddings = self.dropout(embeddings)
    return embeddings

3.3.3 自注意力机制 (BertSelfAttention) - 核心!

# 对应论文公式: Attention(Q,K,V) = softmax(QK^T / √d_k) V

def __init__(self, config):
    # Q、K、V 投影矩阵
    self.query = nn.Linear(config.hidden_size, self.all_head_size)
    self.key = nn.Linear(config.hidden_size, self.all_head_size)
    self.value = nn.Linear(config.hidden_size, self.all_head_size)
    
    # 缩放因子 √d_k
    self.scaling = self.attention_head_size ** -0.5

def forward(self, hidden_states, attention_mask, ...):
    # 1. 线性投影得到 Q、K、V
    query_layer = self.query(hidden_states)  # [batch, seq_len, hidden]
    key_layer = self.key(hidden_states)
    value_layer = self.value(hidden_states)
    
    # 2. 重塑为多头形式 [batch, num_heads, seq_len, head_dim]
    query_layer = query_layer.view(*hidden_shape).transpose(1, 2)
    key_layer = key_layer.view(*hidden_shape).transpose(1, 2)
    value_layer = value_layer.view(*hidden_shape).transpose(1, 2)
    
    # 3. 计算注意力分数 (对应 QK^T / √d_k)
    attn_weights = torch.matmul(query, key.transpose(-2, -1)) * self.scaling
    
    # 4. 应用 mask(padding 位置设为 -inf)
    attn_weights = attn_weights + attention_mask
    
    # 5. Softmax 归一化
    attn_weights = nn.functional.softmax(attn_weights, dim=-1)
    
    # 6. 加权求和得到输出
    attn_output = torch.matmul(attn_weights, value)
    
    return attn_output

3.3.4 前馈网络 (BertIntermediate + BertOutput)

# 对应论文: FFN(x) = GELU(xW1 + b1)W2 + b2

class BertIntermediate(nn.Module):
    def forward(self, hidden_states):
        hidden_states = self.dense(hidden_states)      # hidden_size → intermediate_size
        hidden_states = self.intermediate_act_fn(hidden_states)  # GELU 激活
        return hidden_states

class BertOutput(nn.Module):
    def forward(self, hidden_states, input_tensor):
        hidden_states = self.dense(hidden_states)      # intermediate_size → hidden_size
        hidden_states = self.dropout(hidden_states)
        hidden_states = self.LayerNorm(hidden_states + input_tensor)  # 残差连接
        return hidden_states

四、调试学习方法

4.1 基础调试脚本

在项目根目录创建 debug_bert.py

from transformers import BertModel, BertTokenizer
import torch

# 加载预训练模型和分词器
tokenizer = BertTokenizer.from_pretrained("bert-base-uncased")
model = BertModel.from_pretrained("bert-base-uncased")

# 准备输入
text = "Hello, how are you?"
inputs = tokenizer(text, return_tensors="pt")

print("=== 输入信息 ===")
print(f"input_ids shape: {inputs['input_ids'].shape}")
print(f"input_ids: {inputs['input_ids']}")
print(f"tokens: {tokenizer.convert_ids_to_tokens(inputs['input_ids'][0])}")

# 前向传播(在这里打断点)
outputs = model(**inputs)

print("\n=== 输出信息 ===")
print(f"last_hidden_state shape: {outputs.last_hidden_state.shape}")
print(f"pooler_output shape: {outputs.pooler_output.shape}")

4.2 PyCharm 调试步骤

  1. debug_bert.pyoutputs = model(**inputs) 行打断点
  2. 右键 → Debug 'debug_bert'
  3. 使用 "Step Into" (F7) 进入 BertModel.forward()
  4. 继续 Step Into 进入各个子模块

4.3 重点调试位置

在以下位置打断点,观察张量变化:

文件 位置 观察内容
modeling_bert.py BertEmbeddings.forward() 嵌入向量如何生成
modeling_bert.py BertSelfAttention.forward() Q/K/V 计算、注意力分数
modeling_bert.py eager_attention_forward() 注意力计算细节
modeling_bert.py BertLayer.forward() 单层 Transformer 流程

4.4 可视化注意力权重

from transformers import BertModel, BertTokenizer
import torch
import matplotlib.pyplot as plt

tokenizer = BertTokenizer.from_pretrained("bert-base-uncased")
model = BertModel.from_pretrained("bert-base-uncased", output_attentions=True)

text = "The cat sat on the mat"
inputs = tokenizer(text, return_tensors="pt")
outputs = model(**inputs)

# 获取注意力权重
attentions = outputs.attentions  # tuple of (batch, heads, seq, seq)

# 可视化第一层第一个头的注意力
tokens = tokenizer.convert_ids_to_tokens(inputs['input_ids'][0])
attn = attentions[0][0, 0].detach().numpy()  # 第1层,第1个头

plt.figure(figsize=(8, 8))
plt.imshow(attn, cmap='viridis')
plt.xticks(range(len(tokens)), tokens, rotation=45)
plt.yticks(range(len(tokens)), tokens)
plt.colorbar()
plt.title("Attention Weights (Layer 1, Head 1)")
plt.tight_layout()
plt.savefig("attention_visualization.png")
plt.show()

五、进阶学习路径

5.1 学完 BERT 后的下一步

模型 特点 对应文件
GPT-2 单向解码器、因果注意力 models/gpt2/modeling_gpt2.py
T5 编码器-解码器架构 models/t5/modeling_t5.py
LLaMA RoPE 位置编码、RMSNorm models/llama/modeling_llama.py
Qwen2 现代 LLM 架构 models/qwen2/modeling_qwen2.py

5.2 关键概念对比

概念 BERT GPT 区别
注意力类型 双向 单向(因果) GPT 只能看到前面的 token
位置编码 绝对位置嵌入 绝对/RoPE 现代模型多用 RoPE
预训练任务 MLM + NSP 下一个词预测 不同的训练目标

5.3 重要基类学习

src/transformers/
├── configuration_utils.py    # PreTrainedConfig - 所有配置的基类
├── modeling_utils.py         # PreTrainedModel - 所有模型的基类
├── tokenization_utils_base.py # PreTrainedTokenizerBase - 分词器基类
└── trainer.py                # Trainer - 训练器

六、学习资源

6.1 官方资源

6.2 推荐阅读顺序

  1. 先跑通 debug_bert.py,熟悉基本流程
  2. 精读 BertSelfAttention,对照论文公式
  3. 理解 BertLayer 的完整流程
  4. 学习 BertModel.forward() 的整体架构
  5. 扩展到其他模型(GPT-2、LLaMA)

6.3 学习建议

  • 边读代码边画架构图
  • 用调试器观察张量 shape 变化
  • 对照论文公式理解每一步计算
  • 先忽略缓存、量化等优化代码,专注核心逻辑
  • 遇到不懂的先跳过,建立整体认知后再回头

七、常见问题

Q1: 代码太多,从哪里开始?

BertSelfAttention.forward() 开始,这是 Transformer 的核心。

Q2: 论文公式和代码对不上?

代码中有很多工程优化(如多头并行计算),但数学本质相同。关注 eager_attention_forward() 函数。

Q3: 什么是 attention_mask

用于屏蔽 padding token,防止模型关注无意义的位置。值为 0 的位置会被 mask 掉。

Q4: hidden_states 的 shape 是什么?

通常是 [batch_size, sequence_length, hidden_size],例如 [1, 7, 768]


八、BertModel 模型加载深度解析

8.1 Tokenizer vs Model 对比

tokenizer = BertTokenizer.from_pretrained("bert-base-uncased")  # 加载分词器
model = BertModel.from_pretrained("bert-base-uncased")          # 加载模型
对象 作用 下载的文件 大小
tokenizer 文本 → 数字 ID vocab.txt, tokenizer.json ~1MB
model 神经网络计算 pytorch_model.bin / model.safetensors ~440MB

简单类比:

tokenizer = 翻译官(把人话翻译成机器能懂的数字)
model = 大脑(用神经网络处理这些数字,理解语义)

from_pretrained = 下载一个已经"学过很多知识"的大脑
                  而不是用一个空白的大脑从头学习

8.2 BertModel 的结构

class BertModel(BertPreTrainedModel):
    def __init__(self, config, add_pooling_layer=True):
        super().__init__(config)
        
        # 三大核心组件
        self.embeddings = BertEmbeddings(config)   # 嵌入层
        self.encoder = BertEncoder(config)         # 12层 Transformer
        self.pooler = BertPooler(config)           # 池化层

对应的架构:

输入: input_ids [1, 8]  (batch=1, seq_len=8)
         │
         ▼
┌─────────────────────┐
│   BertEmbeddings    │  词嵌入 + 位置嵌入 + 段落嵌入
│   输出: [1, 8, 768] │
└─────────────────────┘
         │
         ▼
┌─────────────────────┐
│    BertEncoder      │  12 层 Transformer
│    (BertLayer × 12) │  每层: Self-Attention + FFN
│   输出: [1, 8, 768] │
└─────────────────────┘
         │
         ▼
┌─────────────────────┐
│     BertPooler      │  取 [CLS] token,过一个全连接层
│   输出: [1, 768]    │
└─────────────────────┘

8.3 from_pretrained 完整流程

BertModel.from_pretrained("bert-base-uncased")
        │
        ▼
┌───────────────────────────────────────────────────────────┐
│  第一步:下载配置文件 config.json                           │
│  包含: vocab_size=30522, hidden_size=768,                 │
│        num_hidden_layers=12, num_attention_heads=12, ...  │
└───────────────────────────────────────────────────────────┘
        │
        ▼
┌───────────────────────────────────────────────────────────┐
│  第二步:根据配置创建模型结构                                │
│  model = BertModel(config)                                │
│  此时权重是随机初始化的                                     │
└───────────────────────────────────────────────────────────┘
        │
        ▼
┌───────────────────────────────────────────────────────────┐
│  第三步:下载预训练权重文件                                  │
│  model.safetensors 或 pytorch_model.bin (~440MB)          │
│  包含 1.1 亿个参数的具体数值                                │
└───────────────────────────────────────────────────────────┘
        │
        ▼
┌───────────────────────────────────────────────────────────┐
│  第四步:加载权重到模型                                     │
│  model.load_state_dict(weights)                           │
│  随机权重被替换为预训练好的权重                              │
└───────────────────────────────────────────────────────────┘
        │
        ▼
    返回加载好权重的 model 实例

8.4 预训练权重包含什么?

# 查看模型参数
for name, param in model.named_parameters():
    print(f"{name}: {param.shape}")

# 输出示例:
# embeddings.word_embeddings.weight: [30522, 768]  ← 词嵌入矩阵
# embeddings.position_embeddings.weight: [512, 768] ← 位置嵌入
# encoder.layer.0.attention.self.query.weight: [768, 768] ← Q 矩阵
# encoder.layer.0.attention.self.key.weight: [768, 768]   ← K 矩阵
# encoder.layer.0.attention.self.value.weight: [768, 768] ← V 矩阵
# ... (共 12 层)
# pooler.dense.weight: [768, 768]

这些权重是 Google 用大量文本(Wikipedia + BookCorpus)预训练得到的,包含了语言知识。

8.5 源码 vs 权重:理解"开源大模型"

核心概念:

文件 是什么 在哪里 开源?
modeling_bert.py 模型源码(网络结构) transformers 仓库 ✅ 开源
model.safetensors 权重文件(训练好的参数) Hugging Face Hub ✅ 开源

文件位置:

模型源码位置(本地 transformers 仓库):
src/transformers/models/bert/
├── modeling_bert.py          # 模型代码 ← 定义网络结构
├── configuration_bert.py     # 配置类
├── tokenization_bert.py      # 分词器
└── ...

权重文件位置(Hugging Face Hub 云端):
https://huggingface.co/bert-base-uncased/
├── model.safetensors         # 权重文件 ← 训练好的参数
├── config.json               # 配置
├── vocab.txt                 # 词表
└── ...

开源大模型 = 开源的源码 + 开源的权重:

modeling_bert.py (源码)     +    model.safetensors (权重)
      ↓                              ↓
  定义网络长什么样               训练好的具体数值
  (骨架)                        (血肉)
      ↓                              ↓
      └──────────── 合并 ────────────┘
                    ↓
              完整可用的模型

这就是为什么两行代码就能跑起大模型:

from transformers import BertModel  # 导入源码(骨架)
model = BertModel.from_pretrained("bert-base-uncased")  # 下载权重(血肉)

不同厂商的开源程度:

┌────────────────────────────────────────────────────────────┐
│                      开源程度对比                           │
├──────────────┬─────────┬─────────┬─────────┬──────────────┤
│              │  权重   │  代码   │训练代码 │  训练数据     │
├──────────────┼─────────┼─────────┼─────────┼──────────────┤
│ LLaMA (Meta) │   ✅    │   ✅    │   ❌    │    ❌        │
│ Qwen (阿里)  │   ✅    │   ✅    │   ❌    │    ❌        │
│ DeepSeek     │   ✅    │   ✅    │   ✅    │    ❌        │
│ GPT-4 (OpenAI)│  ❌    │   ❌    │   ❌    │    ❌        │
│ BERT (Google)│   ✅    │   ✅    │   ✅    │    ✅        │
└──────────────┴─────────┴─────────┴─────────┴──────────────┘

为什么权重文件最有价值?

  • 训练权重需要:TB 级数据 + 数百万美元算力 + 数周时间
  • 有了开源权重:几分钟下载,直接使用或微调

九、Tokenizer 分词器深度解析

8.1 from_pretrained 完整流程

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

这一行代码背后发生了很多事情:

BertTokenizer.from_pretrained("bert-base-uncased")
        │
        ▼
┌───────────────────────────────────────────────────────────┐
│  第一步:解析参数                                           │
│  "bert-base-uncased" 是 Hugging Face Hub 上的模型 ID       │
└───────────────────────────────────────────────────────────┘
        │
        ▼
┌───────────────────────────────────────────────────────────┐
│  第二步:下载/缓存文件                                       │
│  从 Hub 下载这些文件到本地缓存:                             │
│  - vocab.txt (词表文件)                                    │
│  - tokenizer.json (快速分词器配置)                          │
│  - tokenizer_config.json (分词器参数配置)                   │
│  - special_tokens_map.json (特殊 token 映射)               │
└───────────────────────────────────────────────────────────┘
        │
        ▼
┌───────────────────────────────────────────────────────────┐
│  第三步:初始化 BertTokenizer                               │
│  - 加载词表 (30522 个词)                                   │
│  - 配置特殊 token: [CLS], [SEP], [PAD], [UNK], [MASK]      │
│  - 初始化 WordPiece 分词算法                                │
│  - 设置 normalizer, pre_tokenizer, post_processor          │
└───────────────────────────────────────────────────────────┘
        │
        ▼
    返回 tokenizer 实例

8.2 类继承关系

BertTokenizer
    └── TokenizersBackend              # 快速分词器后端 (Rust)
            └── PreTrainedTokenizerBase    # 所有分词器的基类
                    └── PushToHubMixin         # 上传到 Hub 的功能

注意:在旧版本中有独立的 SpecialTokensMixin,但在 V5 版本中已合并到 PreTrainedTokenizerBase

8.3 Rust 后端证明

BertTokenizer 底层调用 Rust 代码,证据如下:

# tokenization_bert.py 中的导入
from tokenizers import Tokenizer, decoders, normalizers, pre_tokenizers, processors
from tokenizers.models import WordPiece

tokenizers 库是 HuggingFace 的独立项目,用 Rust 编写,通过 PyO3 绑定到 Python。

验证方法:

import tokenizers
import os

# 查看 tokenizers 安装位置
print(tokenizers.__file__)
# 输出: C:\Users\xxx\...\tokenizers\__init__.py

# 在该目录下会发现 .pyd 文件(Windows)或 .so 文件(Linux)
# 这些是编译后的 Rust 二进制文件
dir_path = os.path.dirname(tokenizers.__file__)
print([f for f in os.listdir(dir_path) if f.endswith('.pyd') or f.endswith('.so')])
# 输出: ['tokenizers.pyd']

8.4 分词器初始化核心代码

# BertTokenizer.__init__() 中的关键代码:

# 1. 创建 WordPiece 分词模型(Rust 实现)
self._tokenizer = Tokenizer(WordPiece(vocab, unk_token="[UNK]"))

# 2. 设置文本规范化器 (normalizer)
self._tokenizer.normalizer = normalizers.BertNormalizer(
    clean_text=True,              # 清理控制字符
    handle_chinese_chars=True,    # 处理中文字符
    strip_accents=None,           # 去除重音
    lowercase=do_lower_case       # 转小写
)

# 3. 设置预分词器 (pre_tokenizer)
self._tokenizer.pre_tokenizer = pre_tokenizers.BertPreTokenizer()

# 4. 设置后处理器 (post_processor) - 添加 [CLS] 和 [SEP]
self._tokenizer.post_processor = processors.TemplateProcessing(
    single="[CLS]:0 $A:0 [SEP]:0",  # 单句模板
    pair="[CLS]:0 $A:0 [SEP]:0 $B:1 [SEP]:1",  # 句对模板
    special_tokens=[("[CLS]", 101), ("[SEP]", 102)]
)

8.5 不同模型的分词器对比

每个模型需要适配自己的分词器,但复用了底层算法:

模型 分词算法 特殊 token 词表文件
BERT WordPiece [CLS], [SEP], [MASK] vocab.txt
LLaMA BPE <s>, </s> tokenizer.model
GPT-2 BPE <|endoftext|> vocab.json + merges.txt
Qwen2 BPE <|endoftext|> vocab.json + merges.txt

代码对比:

# BERT 用 WordPiece
self._tokenizer = Tokenizer(WordPiece(vocab, unk_token="[UNK]"))
self._tokenizer.normalizer = normalizers.BertNormalizer(...)

# LLaMA 用 BPE + 字节回退
self._tokenizer = Tokenizer(BPE(vocab, merges, byte_fallback=True))

# Qwen2 用 BPE + 特殊预分词正则
self._tokenizer = Tokenizer(BPE(vocab, merges, ...))
self._tokenizer.pre_tokenizer = pre_tokenizers.Split(Regex(PRETOKENIZE_REGEX), ...)

8.6 分词器架构图

                    TokenizersBackend (基类)
                           │
                           │ 提供统一接口
                           │
        ┌──────────────────┼──────────────────┐
        │                  │                  │
        ▼                  ▼                  ▼
  BertTokenizer      LlamaTokenizer     Qwen2Tokenizer
        │                  │                  │
        │ 配置             │ 配置             │ 配置
        ▼                  ▼                  ▼
    WordPiece            BPE               BPE
   + BertNormalizer   + ByteFallback   + 特殊正则
   + [CLS][SEP]       + <s></s>        + <|endoftext|>
        │                  │                  │
        └──────────────────┼──────────────────┘
                           │
                           ▼
                    Rust 编译的二进制
                    (tokenizers.pyd)

8.7 WordPiece 分词算法示例

# 输入: "unhappiness"
# 分词过程:
# 1. 查找 "unhappiness" → 不在词表中
# 2. 查找 "unhappines" → 不在词表中
# 3. ...
# 4. 查找 "un" → 在词表中! 保留
# 5. 对剩余 "happiness" 继续,加 ## 前缀
# 6. 查找 "##happiness" → 不在词表中
# 7. ...
# 8. 查找 "##happi" → 在词表中! 保留
# 9. 对剩余 "ness" 继续
# 10. 查找 "##ness" → 在词表中! 保留

# 最终结果: ["un", "##happi", "##ness"]

8.8 vocab.txt 词表结构

[PAD]      # ID: 0
[UNK]      # ID: 1  
[CLS]      # ID: 101
[SEP]      # ID: 102
[MASK]     # ID: 103
...
hello      # ID: 7592
world      # ID: 2088
##ing      # ID: 2075  ← WordPiece 子词,## 表示非词首
##ed       # ID: 2098
...
# 共 30522 个词

8.9 总结

  • 底层算法(WordPiece、BPE)是 Rust 实现的,所有模型共用
  • 上层配置(词表、特殊 token、预处理)每个模型需要自己适配
  • 这就像:发动机是通用的,但每辆车的外壳、内饰、配置不同

祝学习顺利!🚀

posted @ 2026-01-23 14:35  Me无情  阅读(2)  评论(0)    收藏  举报