Skip to main content

LengthTokenizer Rust (DP 最少 token / 最低 TPC) Python extension

Project description

Length-MAX Tokenizer

说明(中文补充):本仓库同时提供

  • Rust 训练/统计实现(length_tokenizer
  • Rust 推理分词(DP 最少 token / 最低 TPC):Python 扩展 length_tokenizer_rs.DpTokenizer
  • HuggingFace remote code 导出(train_to_hf* 生成 tokenizer_out/ 目录)

1) Install

pip install length-tokenizer-rs

If your corpus is parquet (or you want streaming reads via pyarrow):

pip install pyarrow

1.1 GitHub Actions / CI install

  • Option A (recommended): publish via GitHub Actions (this repo) and install from PyPI.
    • In GitHub repo settings → Secrets and variablesActions, add:
      • PYPI_API_TOKEN: your PyPI token (project-scoped recommended).
    • Bump version in pyproject.toml / Cargo.toml, then create and push a tag like v0.1.10.
    • The workflow /.github/workflows/publish_pypi.yml will build wheels (Linux/macOS/Windows) + sdist and publish.
    • Then in any CI (or locally):
pip install length-tokenizer-rs==0.1.10
  • Option B: build-from-source install inside GitHub Actions (no PyPI needed).
    • This compiles the Rust extension during CI.
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
  with:
    python-version: "3.10"
- uses: PyO3/maturin-action@v1
  with:
    command: develop
    args: --release
- run: python -c "import length_tokenizer_rs; print(length_tokenizer_rs.__version__)"

2) Train a vocab from your corpus (export a local tokenizer directory)

After training you will get a directory (e.g. ./tokenizer_out/) containing: vocab.json / tokenizer_config.json / special_tokens_map.json / tokenization_length_tokenizer.py / README.md

2.1 Text corpus (one sentence per line)
from length_tokenizer_rs import train_to_hf

train_to_hf(
    corpus_file="corpus.txt",   # one sentence per line
    out_dir="./tokenizer_out",
    num_merges=50000,
    aim_token_num=20000,
    n_max=6,
    num_workers=8,
    multi_process=False,
    use_heap=False,  # 默认关闭:更省内存(推荐大语料/大 n_max)
)
2.2 Parquet corpus (streaming read via pyarrow)
from length_tokenizer_rs import train_to_hf_parquet

train_to_hf_parquet(
    parquet_path="/path/to/parquet_dir_or_file",
    out_dir="./tokenizer_out",
    text_column="text",
    max_docs=0,
    batch_size=8192,
    recursive=True,
    num_merges=50000,
    aim_token_num=20000,
    n_max=6,
    num_workers=8,
    multi_process=False,
    use_heap=False,  # 默认关闭:更省内存
    chunk_size=4096,
)
2.3 推荐最高效设置(大语料 + n_max=9 + 32k vocab)

当你要对齐主流 Llama 系列(vocab_size≈32k)并且 n-gram 上限较大(如 n_max=9)时,内存峰值通常是最大瓶颈。 本实现新增了 use_heap 开关(默认关闭),用于避免候选堆复制一份 n-gram key 导致的额外内存。

  • 推荐参数(经验值,适用于 2×GPU 训练前的 vocab 训练阶段):

    • aim_token_num=32000
    • num_merges=40000(上限,不等于最终词表大小)
    • n_max=9
    • num_workers=64(按 CPU 资源调整)
    • use_heap=False(默认,强烈建议保持)
    • multi_process=True推荐大语料:更稳定,也便于利用增量 apply 优化)
  • 默认高效行为(无需额外设置):当 multi_process=True 时,本实现会默认开启一组“高吞吐/低峰值”的策略:

    • 默认启用 增量模式(不再每步全量重算 stats)
    • 默认将 diff 临时文件优先写到 /dev/shm(Linux 内存盘;若不存在则回退到系统 temp 目录)
    • 默认给每个 worker 设置一个“不过量”的线程数(避免 64 个 worker 各自开满 128 线程导致抖动)
    • 默认使用较大的 MP_BUCKET_BATCH 以提升主进程合并桶文件的并行度
  • 仍可覆盖(仅在你需要 debug/保守模式时):

    • MP_FULL_RECOMPUTE=1MP_NO_INCREMENTAL=1:强制每步全量重算(更慢)
    • WORKER_THREADS=1:限制 worker 内部线程(更稳、但可能更慢)
    • MP_BUCKET_BATCH=64:降低主进程并行读桶批大小(降低峰值内存)
  • 日志重定向(很重要):训练日志默认写到 stderr,如果你用 tee 记日志,需要把 stderr 合并到 stdout:

... 2>&1 | tee run.log
  • CLI 示例(适合快速 bench / 复现实验):
cd tokenizers_rust

cargo run --release --bin length_tokenizer -- \
  --corpus /path/to/train.txt \
  --corpus-format txt \
  --output token_table_32k.json \
  --num-merges 40000 \
  --aim-token-num 32000 \
  --n-max 9 \
  --num-workers 64 \
  2>&1 | tee run_32k_n9.log

如你确实有充足内存并希望加速“找 best n-gram”,可以显式开启 heap:

--use-heap

3) Tokenize your corpus with the new vocab → write ids (data prep)

The examples below write ids.txt: one sample per line, space-separated token ids (high throughput: Rust DpTokenizer.encode_batch()).

3.1 Text corpus (one sentence per line) → ids.txt
import json
from pathlib import Path

from length_tokenizer_rs import DpTokenizer

TOKENIZER_DIR = Path("./tokenizer_out")
VOCAB = TOKENIZER_DIR / "vocab.json"
dp = DpTokenizer(str(VOCAB), "<unk>")

# Optional: add BOS/EOS (adjust to your training pipeline)
vocab = json.loads(VOCAB.read_text(encoding="utf-8"))
bos = vocab.get("<s>")
eos = vocab.get("</s>")

IN_TXT = Path("corpus.txt")
OUT_IDS = Path("corpus.ids.txt")

BATCH = 256
buf = []
with IN_TXT.open("r", encoding="utf-8", errors="ignore") as r, OUT_IDS.open("w", encoding="utf-8") as w:
    for line in r:
        s = line.strip()
        if not s:
            continue
        buf.append(s)
        if len(buf) >= BATCH:
            for ids in dp.encode_batch(buf):
                if bos is not None:
                    w.write(str(int(bos)) + " ")
                w.write(" ".join(str(int(x)) for x in ids))
                if eos is not None:
                    w.write(" " + str(int(eos)))
                w.write("\n")
            buf.clear()
    if buf:
        for ids in dp.encode_batch(buf):
            if bos is not None:
                w.write(str(int(bos)) + " ")
            w.write(" ".join(str(int(x)) for x in ids))
            if eos is not None:
                w.write(" " + str(int(eos)))
            w.write("\n")
3.2 Parquet corpus (streaming read) → ids.txt
import json
from pathlib import Path

import pyarrow.dataset as ds
from length_tokenizer_rs import DpTokenizer

PARQUET = "/path/to/parquet_dir_or_file"
TEXT_COL = "text"

TOKENIZER_DIR = Path("./tokenizer_out")
VOCAB = TOKENIZER_DIR / "vocab.json"
dp = DpTokenizer(str(VOCAB), "<unk>")

vocab = json.loads(VOCAB.read_text(encoding="utf-8"))
bos = vocab.get("<s>")
eos = vocab.get("</s>")

OUT_IDS = Path("parquet.ids.txt")
BATCH = 256
buf = []

dataset = ds.dataset(PARQUET, format="parquet")
scanner = dataset.scanner(columns=[TEXT_COL], batch_size=8192, use_threads=True)

with OUT_IDS.open("w", encoding="utf-8") as w:
    for batch in scanner.to_batches():
        col = batch.column(0)
        for s in col.to_pylist():
            if not s or not str(s).strip():
                continue
            buf.append(str(s))
            if len(buf) >= BATCH:
                for ids in dp.encode_batch(buf):
                    if bos is not None:
                        w.write(str(int(bos)) + " ")
                    w.write(" ".join(str(int(x)) for x in ids))
                    if eos is not None:
                        w.write(" " + str(int(eos)))
                    w.write("\n")
                buf.clear()
    if buf:
        for ids in dp.encode_batch(buf):
            if bos is not None:
                w.write(str(int(bos)) + " ")
            w.write(" ".join(str(int(x)) for x in ids))
            if eos is not None:
                w.write(" " + str(int(eos)))
            w.write("\n")

4) Load the tokenizer for training (local directory)

from transformers import AutoTokenizer

tok = AutoTokenizer.from_pretrained("./tokenizer_out", trust_remote_code=True)
assert getattr(tok, "_rust", None) is not None, "Rust extension not active"

5) 现代架构验证(Llama-style: RoPE + RMSNorm + SwiGLU)

审稿/对外说明时,“现代架构验证”通常指:在 非 GPT-2 的 decoder-only Transformer 上,从零训练(或至少跑通训练环节)并复现同方向的效率收益。

本仓库提供一个最小可复用脚本 validate_modern_arch_llama.py,用你导出的 Length-MAX tokenizer 直接训练一个小的 LlamaForCausalLM(RoPE + RMSNorm + SwiGLU)若干步,验证流程可跑通:

pip install -U torch transformers

python validate_modern_arch_llama.py \
  --tokenizer_dir ./tokenizer_out \
  --corpus_file corpus.txt \
  --seq_len 256 \
  --batch_size 8 \
  --steps 100

建议用于 rebuttal 的正式实验:保持同语料/同 vocab size/同超参,只替换 tokenizer(BPE vs Length-MAX),并在该现代架构上报告 steps-to-target loss、latency/throughput、以及下游任务指标。

5.1 2×GPU(例如 2×5060Ti 16GB)推荐跑法:torchrun DDP

脚本已支持 DDP。示例(两张卡):

torchrun --standalone --nproc_per_node 2 validate_modern_arch_llama.py \
  --tokenizer_dir ./tokenizer_out \
  --corpus_file corpus.txt \
  --max_lines 0 \
  --device cuda \
  --precision bf16 \
  --grad_checkpointing \
  --seq_len 1024 \
  --batch_size 32 \
  --grad_accum 4 \
  --steps 2000 \
  --lr 3e-4 \
  --weight_decay 0.1 \
  --print_every 50 \
  --hidden_size 768 \
  --num_layers 12 \
  --num_heads 12 \
  --num_kv_heads 12 \
  --intermediate_size 2048

说明:

  • --batch_sizeglobal batch size(DDP 下会按 world size 自动切分到每张卡)。
  • 显存不够时,优先开 --grad_checkpointing,然后减小 --seq_len--batch_size,用 --grad_accum 把全局 batch 拉回去。

6) Publish to PyPI(推荐用 GitHub Actions)

这个仓库原本就带了 GitHub Actions 发版流程:tokenizers_rust/.github/workflows/publish_pypi.yml

  • GitHub 发版(推荐,跨平台 wheel)
    • workflow 触发条件是 push tag,例如 v0.1.7
    • 会构建 Linux/macOS/Windows 的 wheels(py3.10/3.11/3.12),并用 PYPI_API_TOKEN 发布到 PyPI

示例(在你自己的 git repo 里执行):

git add tokenizers_rust
git commit -m "Release v0.1.7"
git tag v0.1.7
git push origin main --tags
  • 本地发布(不推荐,通常只会上传当前平台 wheel)

注意:maturin publish 不需要也不支持 --release(默认就是 release 构建)。

cd tokenizers_rust
maturin publish

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

length_tokenizer_rs-0.1.10.tar.gz (149.3 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

length_tokenizer_rs-0.1.10-cp312-cp312-win_amd64.whl (615.8 kB view details)

Uploaded CPython 3.12Windows x86-64

length_tokenizer_rs-0.1.10-cp312-cp312-macosx_11_0_arm64.whl (661.5 kB view details)

Uploaded CPython 3.12macOS 11.0+ ARM64

length_tokenizer_rs-0.1.10-cp312-cp312-macosx_10_12_x86_64.whl (697.7 kB view details)

Uploaded CPython 3.12macOS 10.12+ x86-64

length_tokenizer_rs-0.1.10-cp311-cp311-win_amd64.whl (614.8 kB view details)

Uploaded CPython 3.11Windows x86-64

length_tokenizer_rs-0.1.10-cp311-cp311-macosx_11_0_arm64.whl (662.2 kB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

length_tokenizer_rs-0.1.10-cp311-cp311-macosx_10_12_x86_64.whl (698.1 kB view details)

Uploaded CPython 3.11macOS 10.12+ x86-64

length_tokenizer_rs-0.1.10-cp310-cp310-win_amd64.whl (615.0 kB view details)

Uploaded CPython 3.10Windows x86-64

length_tokenizer_rs-0.1.10-cp310-cp310-macosx_11_0_arm64.whl (662.2 kB view details)

Uploaded CPython 3.10macOS 11.0+ ARM64

length_tokenizer_rs-0.1.10-cp310-cp310-macosx_10_12_x86_64.whl (698.2 kB view details)

Uploaded CPython 3.10macOS 10.12+ x86-64

length_tokenizer_rs-0.1.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (743.5 kB view details)

Uploaded CPython 3.8manylinux: glibc 2.17+ x86-64

File details

Details for the file length_tokenizer_rs-0.1.10.tar.gz.

File metadata

  • Download URL: length_tokenizer_rs-0.1.10.tar.gz
  • Upload date:
  • Size: 149.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for length_tokenizer_rs-0.1.10.tar.gz
Algorithm Hash digest
SHA256 33ce705974113845f6c49398fc4eb0ce39fadebad4feb45c1ba8493785855946
MD5 13501f95929948a63ee2f354e3e8a4b0
BLAKE2b-256 f25fb33f73fb1fa398504e20ee32a58ca9f0ff7dea64f6cde7eef98b3c7035d0

See more details on using hashes here.

File details

Details for the file length_tokenizer_rs-0.1.10-cp312-cp312-win_amd64.whl.

File metadata

File hashes

Hashes for length_tokenizer_rs-0.1.10-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 80f842eb0d2f7cd72d732b8ccff6f7e2a79e6b1249e854285b9c4ffe9693a0be
MD5 5339ec2033499cdc929ed7f2679fea6e
BLAKE2b-256 5f929edd5aa9d367496b3957541ce06f9d12e886983121f22764a2c8aaeec3d1

See more details on using hashes here.

File details

Details for the file length_tokenizer_rs-0.1.10-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for length_tokenizer_rs-0.1.10-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 c5a6ac6437205857fe4acfa6ea5d587b9f231117b18d9e18fa6a75b86f462d0e
MD5 18f15001c9cc188c3e662a715d6bfb47
BLAKE2b-256 848169779b2d0ae06530006c85afa826b8e20c6cd48057b7bd16c3752cd67715

See more details on using hashes here.

File details

Details for the file length_tokenizer_rs-0.1.10-cp312-cp312-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for length_tokenizer_rs-0.1.10-cp312-cp312-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 01c47e5bb39cb1eb7959e78105162ee46f05b464554242b6a37bd7c9f65bda97
MD5 0fb244e8515b29ceeced8ad527042988
BLAKE2b-256 137a0905c774a7e0c11aa9fe6b649b014613e7d6aa11805b611a0c0d211d29d2

See more details on using hashes here.

File details

Details for the file length_tokenizer_rs-0.1.10-cp311-cp311-win_amd64.whl.

File metadata

File hashes

Hashes for length_tokenizer_rs-0.1.10-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 7ba68f472d88d3ca64d3595f471ae1eccc6044bc964aa0e4de010004c83ff1a8
MD5 60c493d8d294f65041288530a17d56a7
BLAKE2b-256 cd4e5d211431915c768a1e544aaa64b659e8a172dcf0a23c4f898007f7f3645b

See more details on using hashes here.

File details

Details for the file length_tokenizer_rs-0.1.10-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for length_tokenizer_rs-0.1.10-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 c76ea3af83260884537c0d678dea7a2659de82a9b64b73ab97c64cd903122a38
MD5 0ded96523247703e3f9f7ffd8b413fc4
BLAKE2b-256 cd1012e05d7524c0d661b6692df943469e63cf81108a651d2e58e29bdd42dc68

See more details on using hashes here.

File details

Details for the file length_tokenizer_rs-0.1.10-cp311-cp311-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for length_tokenizer_rs-0.1.10-cp311-cp311-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 f7c623f273758338d6f0babec5b698d775866668bbff22dea72d5294606cb6dd
MD5 a731390f32e0a21e6a600f5f0d417572
BLAKE2b-256 c63409f70330262bece02fe36a0bb6f8b0352c4d146897d7aa80189e4c2eab97

See more details on using hashes here.

File details

Details for the file length_tokenizer_rs-0.1.10-cp310-cp310-win_amd64.whl.

File metadata

File hashes

Hashes for length_tokenizer_rs-0.1.10-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 4c4bf598745c8f6328acbc608a12044eb5cf074e8060a8e6aaab361f7b39c8d1
MD5 db1c97ce3b7cf322b77d60d5cef51f2a
BLAKE2b-256 eca609d05ced9a95a19394d32e0edebc41683975b3ddca19fc42f4a305555f27

See more details on using hashes here.

File details

Details for the file length_tokenizer_rs-0.1.10-cp310-cp310-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for length_tokenizer_rs-0.1.10-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 9f6b36a8f73851c97cb1e6c977821fa565395ba748936825d7b3f01fb1345419
MD5 63d946c0179b93edd1261bf0075a2c4b
BLAKE2b-256 cb2df71c47c8014eb21937a5109b3b2490c351c30ddaf9b6cd30bd3a9b0a0ee3

See more details on using hashes here.

File details

Details for the file length_tokenizer_rs-0.1.10-cp310-cp310-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for length_tokenizer_rs-0.1.10-cp310-cp310-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 8e3d5747fa6936d8d34497b29a4401a537f6adf72fdd824607ee19d1d0799b93
MD5 ab2319257599a832dbcbf9889f480e80
BLAKE2b-256 86d804d74cbcd4d55983f984e2cda5da1b327b9ad597dfcf81666cca253f7831

See more details on using hashes here.

File details

Details for the file length_tokenizer_rs-0.1.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for length_tokenizer_rs-0.1.10-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 d8e74a5c54f8346f4e6b0059884e67b91c51f05ae2c48742cb3d391b03958bbb
MD5 f0534541baa3513baeaeebe08833cb49
BLAKE2b-256 c4bb025eef8e49b26b899fee9441b22bd18cdbd96392fa3347b3b7f688bc55b6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page