You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
BPE byte-level mapping: byte 0xAD mapped to identity instead of U+0143 (GPT-2 bytes_to_unicode) — CJK chars containing 0xAD tokenize to <unk> #806
BPETokenizer::init_byte_mappings (cactus-engine/src/bpe.cpp) maps bytes 161..255 to identity code points. GPT-2 byte-level BPE (bytes_to_unicode()) excludes byte 173 (U+00AD, soft hyphen) from that range and assigns it the next free code point after the other non-printables (U+0143). Any UTF-8 sequence containing byte 0xAD therefore tokenizes differently from the reference tokenizer and decodes to U+FFFD.
Repro (LiquidAI/LFM2.5-230M bundle, cactus_tokenize / Cactus.tokenize in the RN bridge)
input
cactus 2.1.0
HF reference
歯 (E6 AD AF)
[672, 0, 617] (byte, unk, byte)
[33687]
歯医者
[672, 0, 617, 8773, 4046]
[33687, 8773, 4046]
明日の朝9時に歯医者に電話することを思い出させて
17 tokens, 1 unknown
15 tokens
Only characters containing byte 0xAD are affected — everything else in the sentence tokenizes identically to HF. Decode side of the same table: cactus run on the stock lfm2.5-230m-cq4 bundle echoes 歯医者 as �丈医者. Observed end-to-end in a React Native app: a tool-call argument 歯医者に電話する came back as �Reception医者に電話する.
Root cause
for (int i = 161; i <= 255; ++i) bytes.push_back(i); // includes 173
...
} elseif (byte >= 161 && byte <= 255) { // identity branch also catches 173
GPT-2: identity ranges are 33..126, 161..172, 174..255; all other bytes (0..32, 127..160, 173) get 256+n in increasing byte order → 173 → U+0143.
Fix
Exclude 173 from both the identity list and the identity branch condition (the branch is selected by byte value, so moving the byte between lists alone is a no-op), and append 173 to remaining_bytes after 160. PR: #805. Verified: the resulting 256-entry mapping equals HF GPT2Tokenizer.bytes_to_unicode() byte-for-byte; cactus_tokenize("歯") → [33687] after the change.
Related: #803 (Python-binding ensure_ascii escaping — a separate, input-path bug; both were found while running a multilingual tool-calling model on cactus).
Activity