[RNE Rewrite] feat: add tokenizer pipeline (#1248)#1274
Conversation
c5817d8 to
f426882
Compare
f426882 to
66dfb9d
Compare
66dfb9d to
d394a7e
Compare
d394a7e to
81d7ab1
Compare
barhanc
left a comment
There was a problem hiding this comment.
I only went over the library implementation. Tomorrow I will take a look at the example app and test it.
5fddd90 to
cec7c37
Compare
barhanc
left a comment
There was a problem hiding this comment.
Tested and works good! One more thing I noticed (that isn't blocking on this PR because it will probably become clearer when we add some downstream tasks that use tokenizer) is the serialization cost of number[] returned by the async encode. I worry it might be quite large for long texts. I guess it's not a problem for tasks like embeddings or privacy-filter since there we would use the tokenizer.ts directly and tokens array would never pass the thread boundary since the tokens would then get consumed by some other model and the final returned object might be much lighter. Worth keeping in mind though. For now since the hook is mostly to test the tokenizer implementation it's fine.
- install loadTokenizer under the nlp JSI submodule (rnexecutorchJsi.nlp) - move ops/tokenizer.ts to nlp/tokenizer.ts; standard-template JSDoc, drop low/high-level coupling and Model/Tensor mention - default skipSpecialTokens and empty-input handling in C++ decode - minimal tokenization task (no worklet wrappers; sync lightweight lookups); inline single-field config to a path string - readable tokenizer error strings; drop unnecessary build-config comments
cec7c37 to
b0548f1
Compare
I'll add this point to the |
|
I guess returning TypedArray instead of |
|
@barhanc last question, do you want to keep this demo app? I build it mainly for testing purpose. It is not interactive at all, so maybe we shouldn't keep it at all? |
|
For now it's fine. When we have some other screens like embeddings we can remove it. |
Description
Adds the tokenizer pipeline (issue #1248) using the new worklet-based architecture, with functional parity to the current
TokenizerModule.A new
nlpextension exposes aloadTokenizerJSI primitive (top-level on__rnexecutorch_jsi__, likeloadModel) returning aTokenizerhost object backed bytokenizers::HFTokenizer. On top of it sits acreateTokenizer(config, runtime?)async factory (async +*Workletvariants +dispose) and auseTokenizerhook. Methods:encode,decode,getVocabSize,idToToken,tokenToId— same semantics as today (special tokens follow thetokenizer.jsonpost_processor). The*Workletvariants let an upcoming text-embeddings task tokenize → build tensors → run forward within a single worklet.cpp/extensions/nlp/{tokenizer,install}.{h,cpp}, wired intoRnExecutorch.cpp.src/extensions/nlp/{ops,tasks}/tokenizer.ts,src/hooks/useTokenizer.ts, exports inindex.ts, examplemodels.tokenizer.ALL_MINILM_L6_V2.android/CMakeLists.txtand the podspec —pytorch/tokenizers/includeplus the bundled libs its public headers pull in (nlohmann/json,re2, and re2'sabseildep). Symbols link from the prebuiltlibexecutorch. Documented inthird-party/README.md.apps/nlpexample app with a Tokenizer screen that drives the full pipeline on device.Introduces a breaking change?
Type of change
Tested on
Testing instructions
CI is TypeScript-only here (native isn't compiled in CI);
yarn typecheck, rootyarn lint, andyarn prepare(bob build) all pass.To exercise the native tokenizer end-to-end via the demo app:
third-partyartifacts intopackages/react-native-executorch/third-party/(seethird-party/README.md). The existing PoC bundle already ships the llm/tokenizers extension (headers + symbols), so no rebuild is needed.yarn && cd apps/nlp && yarn ios— the iOS simulator works since the tokenizer is pure CPU (no GPU/Metal).all-MiniLM-L6-v2and auto-runsencode/decode/getVocabSize/idToToken/tokenToId, asserting:encode("Hello world")=[7592, 2088],decoderound-trips to"hello world",getVocabSize()=30522, andtokenToId(idToToken(id))is the identity. All three assertions should read PASS (also logged as[TokenizerTest]).The screen genuinely drives the new code —
useTokenizer→createTokenizer→ theloadTokenizerJSI primitive → the nativeTokenizerHostObject/HFTokenizer— so a green run validates the whole pipeline, not just the types. Verified locally on iOS (iPhone 16 Pro Max, Xcode 26.5): all assertions pass.The
apps/nlpapp is intentionally minimal and exists only to prove this pipeline; it can be dropped after approval if you'd prefer not to keep a demo app in-tree.Screenshots
Related issues
#1248, part of #1208
Checklist
Additional notes
The C++ mirrors the current
TokenizerModule, which is backed bypytorch/tokenizers(tokenizers::HFTokenizer) from the ExecuTorch llm/tokenizers extension. This PR consumes the same headers (the third-party bundle underextension/llm/tokenizers) and prebuilt symbols (fromlibexecutorch); it does not use thetokenizers-cppsubmodule. Tokenizer download currently uses the temporaryreact-native-fs-baseduseResourceDownloadintroduced in #1264 (to be replaced by the ResourceFetcher in #1253).