Skip to content

分词与词表 — 代码走读

src/llama-vocab.cpp — 分词器实现

核心类结构

llama_vocab 类管理整个词表和分词逻辑:

cpp
struct llama_vocab {
    // 词表数据
    std::vector<llama_vocab_token> tokens;
    std::unordered_map<std::string, llama_token> token_to_id;

    // 分词类型
    enum llama_vocab_type type;

    // 特殊 token ID
    llama_token bos_token_id;
    llama_token eos_token_id;
    llama_token pad_token_id;

    // BPE 合并规则
    std::vector<std::pair<std::string, std::string>> merges;
};

分词入口

cpp
int32_t llama_tokenize(
    const struct llama_model * model,
    const char * text,
    llama_token * tokens,
    int32_t n_max_tokens,
    bool add_bos,
    bool special);

BPE 编码流程

cpp
// 1. 预处理:Unicode 规范化
text = unicode_normalize(text);

// 2. 预分词:按正则分割为词
auto words = pre_tokenize(text);

// 3. 对每个词执行 BPE
for (auto & word : words) {
    auto tokens = bpe_encode(word);
    result.insert(result.end(), tokens.begin(), tokens.end());
}

// 4. 添加特殊 token
if (add_bos) result.insert(result.begin(), vocab.bos_token_id);

BPE 合并

cpp
// BPE 核心:重复合并最高优先级的 token 对
while (true) {
    auto best = find_best_merge(tokens, merges);
    if (best.score == -INF) break;
    tokens = merge_pair(tokens, best.pair);
}

Detokenization

cpp
// 将 token ID 转回文本
int32_t llama_token_to_piece(
    const struct llama_model * model,
    llama_token token,
    char * buf,
    int32_t length,
    int32_t lstrip,
    bool special);

关键函数索引

函数说明
llama_tokenize文本 → token IDs
llama_token_to_piecetoken ID → 文本片段
llama_vocab_get_text获取 token 的文本表示
llama_vocab_get_type获取分词器类型
llm_load_vocab从 GGUF 加载词表