Release Notes v0.2.3
This release introduces SentencePiece Lite, a zero-dependency C++20 runtime, new vocabulary-selection algorithms for training (Auto-character Coverage and Sparse L1 Unigram pruning), a Bazel (Bzlmod) build, a large number of security and robustness fixes found by OSS-Fuzz and community reports, and a cleanup of long-deprecated APIs and flags.
1. SentencePiece Lite (New Zero-Dependency Runtime)
- New
lite/runtime: A compact (~45 KB stripped, < 2k LOC) C++20 tokenizer engine that runs directly on memory-mapped FlatBuffers model binaries (.spm.fb) with no runtime dependency on Protobuf or Abseil (#1330, Commita2cb4d8). See lite/README.md.
2. Training: New Vocabulary Selection Algorithms
- Auto-character Coverage (
--auto_character_coverage): NewTrainerSpec.auto_character_coverageoption for both BPE and Unigram that globally optimizes the allocation between single characters and multi-character subwords within the vocabulary budget, while keeping lossless round-trip via byte fallback (Commitse23ece8,df18339,d34a6ce). See doc/auto_character_coverage.md. - Sparse L1 Unigram pruning (
--use_sparse_pruning): Optional L1-regularized EM vocabulary selection with Post-Lasso debiased refit for the Unigram model, replacing the discrete heuristic pruning (#1295, Commitfd53b5c). Required when--auto_character_coverageis used with Unigram. See doc/sparse_l1_unigram.md. PruneUnreachableSentencePieces: Remove pieces that can never appear in a Viterbi path during Unigram training, and fix the discrete pruning loop order (Commitsb292ce5,59c3b80).- Custom pretokenizer callback: Trainer now accepts a
std::function<std::vector<std::string>(absl::string_view)>pretokenizer, exposed to Python via thepretokenizer=training argument;pretokenization_delimiterand callback are mutually exclusive (#1287, Commitd1b6696). unk_id = -1withbyte_fallback: Training with--unk_id=-1is now allowed when--byte_fallback=true; null-byte pieces are treated as UNUSED when byte fallback is enabled (fixes #1308, Commitc2fbf86).spm_evalmetrics: Added Bytes/Tok, Model PPL, Empirical PPL, and Coverage metrics (Commit01305c9).
3. Python Wrapper
- Pickling:
SentencePieceProcessornow preserves encode options and the full instance dict (including subclasses) when pickled (#1349, Commits4e66c53,52b1a47). - Normalizer fixes:
- Decode / Encode edge cases:
- Buffer protocol & integer inputs: Accept 8/16/32/64-bit signed/unsigned integer buffers with saturation clamping and zero-copy lifetime safety; accept general sequences (including tuples) in decode APIs (Commit
b3717da). - Free-threaded Python: Fix a pretokenizer callback race on free-threaded builds (
cp314t) and GIL-safety issues in_TrainFromMap(Commitsca0f388,ee1d3dd). Free-threaded wheels are now tested on 3.14t / 3.15t. - Python version support: Requires Python >= 3.10; added Python 3.15 classifier and
cibuildwheel4.3.1 (Commitsfa40c16,ab49d75). - AIX: Fixed the Python build on AIX (#1359).
4. Performance Optimizations
- BPE training: Replaced the per-symbol position
btree_setwith a vector and parallelized initial indexing; removed the 65,535-character sentence length limit by replacing 16-bit packed positions with aPositionstruct (Commitsa44ce92,b3717da). - Sentence preprocessing: Parallelized
TrainerInterface::LoadSentencesandSplitSentencesByWhitespace, withRunBatch-based dynamic load balancing for normalization (Commitsa44ce92,d1b6696). - Decode: Avoid intermediate allocations and skip redundant
StrReplaceAllinDecode()(Commita44ce92). - Unigram: Avoid unnecessary allocations in
Lattice::NBest/Lattice::Sample, heap-free score precomputation inBoundedPriorityQueue::Gc, and deduplicated corpus byte counting (Commitee1d3dd). - ParallelEncode / Normalizer: Skip unused
SentencePieceTextallocations inParallelEncodeoverloads and skip alignment bookkeeping when not requested (Commitee1d3dd).
5. Security & Hardening
- OSS-Fuzz findings: Bounded hypothesis allocations, agenda shrink rounds, and periodic timeout checks in
unigram::Lattice::NBestto fix timeouts/OOM; added piece-ID bounds checks inIdToPiece,GetScore,IsControl,IsUnknown,IsUnused,IsByte(fixes #1342, #1344, #1347, Commit2e432ca). - Lattice bounds: Reject invalid positions/lengths in
Lattice::Insert, verify EOS/begin nodes before Viterbi backtrace, and guard against nullprevpointers and cycles (Commitfa40c16). - Empty-piece guards: Guard empty pieces in
PrefixMatcher::PrefixMatchand UnigramPieceToId(#1326, #1325). - Charsmap validation: Validate leaf node offsets and safely slice values in
DecompileCharsMap; fixBuilder::BuildNFC_CFMapand regeneratenfc_cf.tsv(#1329, #1327). - Trainer guards:
RET_CHECKon zero character/word counts, clamp thread pool size to 1024, fix swap-and-pop bug when removing empty normalized sentences, and fix NaN in Gumbel sampling / thread-local RNG re-seeding (Commitsb3717da,70ed5fc,a44ce92). - Lite hardening: Alignment and bounds checks on FlatBuffers models, direct-mapping validation, and endian-swap overflow protection (Commit
b3717da). - General input validation: Additional edge-case hardening across C++, Lite, and Python (Commit
5d21631).
6. Normalization
nmt_nfkc: Normalize U+061C (ARABIC LETTER MARK) to space (#1331).
7. Deprecations & Removals
- Removed deprecated C++ / Python APIs (#1286, Commit
442a7d7):*AsSerializedProto/*AsImmutableProtovariants,ImmutableSentencePieceText,ImmutableNBestSentencePieceText.SampleEncodeAndScore*,CalculateEntropy.SetVocabulary/ResetVocabulary/LoadVocabulary.- Python:
OverrideNormalizerSpec,__getstate_for_pickle__.
- Deprecated
TrainerSpecfields (now marked[deprecated = true]and removed fromspm_trainCLI flags):accept_language,self_test_sample_size,mining_sentence_size,training_sentence_size,train_extremely_large_corpus,enable_differential_privacy,differential_privacy_noise_level,differential_privacy_clipping_threshold(Commitsd29cf00,470b7d5). - Removed
SelfTestDatafromsentencepiece_model.proto(Commit470b7d5). - Removed
contrib/nlcodecfast BPE trainer and other dead code / unused build dependencies (Commitsb6910fd,c91fbef).
8. Build System & Packaging
- Bazel (Bzlmod) support: New
MODULE.bazel/BUILD.bazelcovering the runtime, trainer, CLI binaries, shared libraries, and test suites;darts-clone,libsais, andabseil-cppare taken from the Bazel Central Registry (#1310, #1311, #1312, #1313, closes #1280). - C++20 baseline: Raised the required C++ standard to C++20 across CMake, Bazel, and the Python extension, including MSVC (#1316, Commit
c0232a9). - Dependency upgrades: Protobuf v36.2, Abseil 20260817.0, FlatBuffers 25.12.19, GoogleTest 1.18.0, Google Benchmark 1.10.0; removed legacy
protobuf-liteandbuiltin_pb(#1296, Commit443fedc). - GoogleTest migration: Replaced the custom
testharnesswith GoogleTest / GoogleMock via CMakeFetchContent(Commits87ab362,c5ae4a9). - CMake modernization: Modernized configuration and target export,
protoccross-compilation support (CMAKE_CROSSCOMPILING_EMULATOR), and self-contained sdist (Commits6bcf11d,e9e7600,16e057b,4e5215e).
9. Documentation
- GitHub Pages site: Added an MkDocs Material documentation site with integrated navigation (Commits
a24b577,a705d0a). - New guides:
doc/auto_character_coverage.md,doc/sparse_l1_unigram.md,doc/bazel.md, andlite/README.md. - Updated references: Reorganized
options.md,special_symbols.md, C++ / normalization / CMake docs, and the tokenizer comparison cheat sheet for 0.2.3; README examples now usereturn_type(Commitsee1d3dd,70ed5fc,cc5aab4).