Skip to content

perf: optimize BNLP — 2-7.4x speedup with Rust-accelerated tokenizer#55

Open
Fatin-Ishraq wants to merge 1 commit into
sagorbrur:mainfrom
Fatin-Ishraq:main
Open

perf: optimize BNLP — 2-7.4x speedup with Rust-accelerated tokenizer#55
Fatin-Ishraq wants to merge 1 commit into
sagorbrur:mainfrom
Fatin-Ishraq:main

Conversation

@Fatin-Ishraq

Copy link
Copy Markdown

🚀 Performance Optimization PR

This PR delivers systematic performance improvements across the BNLP library, achieving 2–7.4× speedup depending on the operation, with an optional Rust extension for maximum performance.

📊 Benchmark Results

OperationBaselineOptimizedSpeedup
Tokenizer (medium)110.5 µs15.0 µs7.4×
Tokenizer (long)5.70 ms0.78 ms7.3×
Batch Tokenize 1K20.2 ms1.3 ms15.1×
Stopword Lookup (set)113.6 µs16.1 µs7.1×
Remove Punctuations (long)205.3 µs89.9 µs2.3×
Pipeline (long)29.6 ms15.0 ms2.0×
CleanText (medium)497.7 µs298.7 µs1.7×

🔧 What Changed

Rust Extension (Optional — bnlp_rust/)

  • New PyO3-based Rust module for hot paths: tokenizer, emoji detection, punctuation, Unicode normalization
  • Rust tokenizer eliminates Python-level per-character iteration and unicodedata.category() bridge overhead
  • Single-pass clean_text() function that does punctuation + emoji + digit removal in one Rust pass
  • Fully optional — if bnlp_rust is not installed, the optimized pure Python fallback is used automatically

Pure Python Optimizations

  • BasicTokenizer: Precomputed frozenset of Unicode punctuation codepoints (eliminated 5.2M unicodedata.category() calls), fast-path skip for tokens without punctuation
  • remove_punctuations(): Replaced per-character Python loop with precompiled regex — 2.3× faster
  • remove_emoji(): Fast-path detection using Rust has_emoji() — skips expensive emoji library for text without emoji
  • BengaliCorpus: Added stopwords_set for O(1) membership testing instead of O(n) list scan — 7.1× faster lookups
  • BatchProcessor: Fixed to use sequential processing for CPU-bound work — ThreadPool was 30% slower due to GIL
  • Lazy imports: BengaliSpellChecker and LanguageDetector now load on-demand via __getattr__ — avoids requiring symspellpy/fasttext at package install

CI / Publishing

  • Updated build_and_test.yml: Builds Rust extension before testing, adds pure Python fallback test job, uses pytest
  • Updated bnlp-publish-auto.yml: Uses maturin-action to build Rust wheels for Linux/macOS/Windows across Python 3.9–3.13, publishes both pure Python and Rust wheels to PyPI on release

🔒 Backward Compatibility

  • All 142 existing tests pass
  • Public API is unchanged — same class names, same method signatures, same return types
  • Rust is optional — library works perfectly without it (just with pure Python speedups)
  • For PyPI release: GitHub Actions builds pre-compiled wheels — users just pip install bnlp, no Rust toolchain needed

📁 Files Changed (22 files, +1,382 / -210 lines)

FileChange
bnlp_rust/ (new)Rust extension — Cargo.toml, lib.rs (355 lines of PyO3)
bnlp/_rust.py (new)Centralized Rust availability check with graceful fallback
bnlp/tokenizer/basic.pyPrecomputed frozenset, fast-path, Rust integration
bnlp/cleantext/clean.pyRegex punctuation, emoji fast-path, Rust has_emoji
bnlp/corpus/corpus.pyAdded stopwords_set for O(1) lookup
bnlp/core/batch.pySequential processing for CPU-bound work
bnlp/core/pipeline.pyIntegration fixes
bnlp/embedding/Optimization + error handling
bnlp/spellcheck/spellchecker.pyRefactored with proper OOP
bnlp/utils/registry.py (new)New registry module
bnlp/__init__.pyVersion bump, lazy imports
setup.pyVersion bump, extras for rust/all
.github/workflows/Cross-platform Rust wheel builds + pure Python tests

🧪 How to Test

# Pure Python (no Rust needed)
pip install -r requirements.txt
python -m pytest tests/ -q

With Rust acceleration

cd bnlp_rust && maturin develop --release && cd ..
python -m pytest tests/ -q

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant