Sign in

    weopqrst/tally/vocab does not have a README file

    VocabError

    pub suberror VocabError {
    InvalidBase64(Char)
    MalformedLine(Int, String)
    DuplicateToken(Int, Int)
    EmptyToken(Int)
    MissingByteToken(Int)
    SpecialOutOfRange(Int, Int)
    UnknownSection(String)
    TrainSizeTooSmall(Int, Int)
    } derive(
    Debug
    )

    Merge

    pub(all) struct Merge {
    rank : Int
    merged : Bytes
    left : Bytes
    right : Bytes
    }

    一次合并:把 left 与 right 拼成 merged,占据 rank 位。

    TrainResult

    pub(all) struct TrainResult {
    vocab : Vocab
    merges : Array[Merge]
    corpus_bytes : Int
    corpus_words : Int
    vocab_size : Int
    min_frequency : Int
    }

    一次训练的完整产物。

    除了词表本身,还把输入与参数一并带上:只有词表无法回答 "这是拿什么语料、什么参数训出来的",而"可复现"要求这个问题有答案。

    TrainResult::to_text

    fn TrainResult::to_text(self : TrainResult) -> String

    导出为 tally-train v1。

    与 to_text 同源的理由:绝不依赖 Map 的迭代顺序, specials 按 id 升序、merges 按 rank 升序,行尾一律 \n。

    Vocab

    pub(all) struct Vocab {
    tokens : Array[Bytes]
    ranks : Map[Bytes, Int]
    ids : Map[Bytes, Int]
    rank_short : Map[Int64, Int]
    id_short : Map[Int64, Int]
    specials : Array[(String, Int)]
    byte_ids : Array[Int]
    }

    词表。tokens[id] 是该 id 的字节序列;ranks 是合并优先级; ids 提供"字节序列 -> id"的反查;specials 是特殊 token 字面量。

    Vocab::byte_id

    fn Vocab::byte_id(self : Vocab, b : Int) -> Int

    单字节 token 的 id。

    Vocab::count

    fn Vocab::count(self : Vocab, text : String) -> Int64

    文本的 token 数。同样不分配 id 数组。

    Vocab::count_bytes

    fn Vocab::count_bytes(self : Vocab, bytes : Bytes) -> Int64

    字节序列的 token 数(Int64:所有累计量都用 64 位,避免 32 位静默溢出)。

    走"只计数"路径,不分配 id 数组;结果与 encode_bytes(bytes).length() 相同。

    Vocab::decode_ids

    fn Vocab::decode_ids(self : Vocab, ids : Array[Int]) -> Bytes

    token id 序列 -> 原始字节。

    Vocab::encode_bytes

    fn Vocab::encode_bytes(self : Vocab, bytes : Bytes) -> Array[Int]

    编码任意字节序列(含特殊 token 切分)。

    Vocab::encode_ordinary_bytes

    fn Vocab::encode_ordinary_bytes(self : Vocab, bytes : Bytes) -> Array[Int]

    不做特殊 token 切分的编码(把它们当普通文本)。

    Vocab::encode_string

    fn Vocab::encode_string(self : Vocab, text : String) -> Array[Int]

    编码一段文本。先整体 UTF-8 编码,再按字节编码。

    String 的编码结果必然是合法 UTF-8,于是 @bpe.encode 里那条 「严格解码成功 -> Unicode 语义」的路径正好生效,与参考实现 encode(str) 对齐。 不需要另一个入口。

    Vocab::id_of

    fn Vocab::id_of(self : Vocab, bytes : Bytes) -> Int?

    字节序列对应的 token id。

    Vocab::piece_counts

    fn Vocab::piece_counts(self : Vocab, bytes : Bytes) -> Array[(String, Int64)]

    逐片明细:(片文本, 该片的 token 数)。

    Vocab::rank_of

    fn Vocab::rank_of(self : Vocab, bytes : Bytes) -> Int?

    字节序列的合并优先级(越小越先合并)。

    Vocab::special_id

    fn Vocab::special_id(self : Vocab, name : String) -> Int?

    特殊 token 名字对应的 id。

    Vocab::special_literals

    fn Vocab::special_literals(self : Vocab) -> Array[String]

    已登记的特殊 token 字面量列表(按最长优先排序)。

    Vocab::to_text

    fn Vocab::to_text(self : Vocab) -> String

    导出为自有规范文本格式(tally-vocab v1)。

    不变量 V10:load(root_export(v)) 与 v 内容等价, 且同样的 v 导出结果逐字节稳定。

    Vocab::token_count

    fn Vocab::token_count(self : Vocab) -> Int

    token 总数。

    Vocab::view

    转成 bpe 包认识的视图。specials 已是"按长度降序"的顺序。

    b64_decode

    fn b64_decode(text : StringView) -> Bytes raise VocabError

    标准 base64 解码。= 及其后的内容被忽略;非法字符报错。

    b64_encode

    fn b64_encode(bytes : Bytes) -> String

    标准 base64 编码(带 = 补位,规范形式)。

    build_vocab

    fn build_vocab(tokens : Array[Bytes], ranks : Map[Bytes, Int], specials : Array[(String, Int)]) -> Vocab raise VocabError

    由三块数据构造一个经过校验的 Vocab。

    specials 的每一项是 (字面量, id);id 必须落在 tokens 的范围内。

    format_header

    let format_header : String

    自有格式的版本标识行。

    load

    fn load(text : String) -> Vocab raise VocabError

    加载自有规范文本格式。

    load_tiktoken

    fn load_tiktoken(text : String, specials : Array[(String, Int)]) -> Vocab raise VocabError

    加载 .tiktoken 风格的词表:每行 <base64> <rank>,rank 即 id。

    specials 由调用方传入(字面量, id),因为该格式不携带特殊 token 定义。

    load_train

    fn load_train(text : String) -> TrainResult raise VocabError

    回读 tally-train v1,重建 TrainResult(词表一并重建)。

    校验的都是"重建会不会错"的要害:合并 rank 稠密升序、merged == left + right、 特殊 token 的 id 接在合并产物之后、# tokens 与重建结果相符。

    train

    fn train(corpus : Array[Bytes], vocab_size : Int, min_frequency : Int, specials : Array[String]) -> TrainResult raise VocabError

    从语料训练一个词表。

    • vocab_size —— 目标总数,含 256 个单字节与 specials。 语料不够(或频次不够)就提前停下,不补零、不灌水。
    • min_frequency —— pair 频次低于它就停止合并(GPT-2 传统取 2)。 取 0 或负数表示"只看 vocab_size,不设频次下限"。
    • specials —— 特殊 token 字面量,按给定顺序追加在合并产物之后。

    返回的 TrainResult 同时带出合并序列与本次的参数,便于冻结与 diff。

    train_format_header

    let train_format_header : String

    训练产物的版本标识行。