Repository navigation
Unlimited-OCR-2 on native Metal: the publisher's BF16 release, page images to structured text - #2074
BobClawblaw wants to merge 24 commits into
Conversation
|
Thanks @BobClawblaw, this is a careful port. A new family that reads the release as published, with the reference
Three small things before it lands:
On your question: yes, we'd build the template in. Use the family's own when the checkpoint ships none, and keep Once these are in, we'll run the recipe's six cases on an M5 Ultra against your reference transcripts. |
10fe5c4 to
3fb5d5b
Compare
|
Thanks. All three are in, rebased on main
The template is built in as you suggested: when the checkpoint ships none and its On |
|
If CUDA is not in this PR's scope, I have a measured CUDA implementation of the same family (DASH tile/step, router, MoE, SAM/CLIP tower) and can stack the backend here once the Metal family lands. Is that a welcome follow-up, and would you prefer it as a separate PR against #2074's branch or against main after merge? |
|
Thanks @BobClawblaw. All three are in: @shuuul, thanks for the CUDA offer, and yes, it's welcome. Please make it its own PR against main once this has landed, with the gate agreed on #2073 first. CUDA is something we can run on our side. |
3fb5d5b to
86857ca
Compare
|
Thanks @ashhart. Rebased onto main On this head: One thing outside this PR: |
|
Thanks @BobClawblaw, and for keeping both lists' main entries in the rebase. This is ready on our side once our runs are in: your six cases on an M5 Ultra against your reference transcripts, and the tensor-units refusal on an M3 Ultra. One small thing we'll handle: the recipe's speed row was measured with another model on the GPU, so we'll put our M5 Ultra numbers there instead. Thanks also for tracking down the |
f6848b8 to
6f25825
Compare
|
Thanks @BobClawblaw. Main moved again: the branch now conflicts in |
SAM ViT-B, its neck and CLIP-L to the projector's rows, for the 1024 global view and 640 tiles (position tables resized as torch does, bit-identical). tf-uocr-vision gates each stage against float32 on a reference dump's pixels.
…ernel groups, their records)
…ery reply token fed back The server clamps a reply to the room the prompt leaves; the family refused that reply by one row, so any request without max_tokens failed once --max-tokens reached the context.
…ne-line comments, the records' duplicate test dropped
… none; --chat-template still overrides
…nd that it runs on M5 GPUs
…built-in template
… follows, with their licences modeling_unlimitedocr.py, deepencoder.py, dash_attention.py and modeling_deepseekv2.py (the release's MIT, Copyright (c) 2026 Baidu) and _sparse_base_impl.py (Apache-2.0, DeepSeek-AI and The HuggingFace Inc. team), at revision 0480966938291445591f69f08a13b041c073a96a.
6f25825 to
0af3eb8
Compare
|
Thanks @ashhart. Rebased onto main
Checked on an M5 Ultra:
One thing outside this PR: |
|
Thanks @BobClawblaw. To run your six cases on our M5 Ultra we need the inputs your run used: the five page images and six reference captures, with each file's size and SHA-256. They're what the text and box-coordinate comparisons read, and the PR supplies a generator rather than the files. Could you attach them to a release on your fork? We won't run the generator here. We're also running this head against main on the 27B, for the shared code it touches, and we'll post that here. Separately, we still owe the check that a pre-M5 Mac refuses by name at start. |
|
Our M5 Ultra run on this head ( The six OCR cases still wait on the inputs I asked for above. |
|
Our GB10 run on the same head ( |
|
Our M3 Ultra run on this head ( |
|
Thanks @ashhart, and for the 27B runs and the M3 Ultra check. The inputs are attached to a release on the fork, on a tag at this head: https://github.com/BobClawblaw/TensorFold/releases/tag/uocr-0af3eb8c8 They're the exact files every M5 Ultra
The references are the release's own Our last run on this head, from the recipe's build of |
|
Thanks @BobClawblaw for the inputs and their hashes; that's what our six-case run on the M5 Ultra reads, and with
|
|
@BobClawblaw, the notices question is settled on our side. So the decoder's attention, the page2d rotary and the MoE gate need rewriting from documented behaviour (the paper, the config and what the release's outputs show), not from that file, and that file's notices entry goes. With that and the rebase, keeping |
Fixes #2073.
This serves Baidu's BF16
baidu/Unlimited-OCR-2(revision0480966938291445591f69f08a13b041c073a96a) natively on Metal, as published: the engine reads the release's safetensors directly, with no converted pack and no Python or libtorch in the served engine. The image tower (SAM ViT-B, its neck and CLIP-L), the decoder (page2d rotary, DASH block-sparse attention, a 64-expert MoE) and the publisher's page-guarded greedy decoding run in Zig and Metal. Its caches stay in the model's precision: bf16 keys and values, fp32 router keys, as in the publisher's code.baidu/Unlimited-OCR-2(BF16) on Metaltensorfold-native serve --visionon M5 (tensor units)infer(torch bf16, CPU) on 6 cases (5 pages alone, all 5 as one document)serve --vision MODEL--chat-templatetakes its place--parallelabove 1tf-uocr-decode --chunk, odd sizes)SUMMARY 34 kernels: 34 pass gates 1-4, 0 fail, 0 known findings; 31 controls: 31 red as planted, 0 missed; 0 limit problemsSpeed (M5 Ultra, another model serving on the same GPU throughout)
Commits
zig/kernels/metal/uocr/) and the contract's scaffold, then five contract groups (rows, moves, attention, route, matvec), each kernel at its served shapes and edges with planted controls.tools/zig/uocr_reference.py(pages,capture: the release's owninfer, transformers 4.52.1 as the model card pins) and the recipedocs/recipes/unlimited-ocr-metal.md.--parallel: a named--parallelabove 1 is refused by name instead of serving one stream.--chat-template.Shared code
Outside the family's folders the PR only registers it:
native/metal.zig(theunlimited-ocrdispatch and its name in two refusal lists),cli/hub.zig(title),kernels/metal/sources.zig(two embedded sources),tensorfold.zig(export and test),build/metal_targets.zig(test-uocr,tf-uocr-decode,tf-uocr-vision), and the contract wiring (registry.zig'sall_metal,metal_main.zig,metal_limits.zig), and the built-in template:server/hf_text.zigusesfamilies/uocr/chat.zig's template when the checkpoint ships none and itsmodel_typeisunlimited-ocr(auocr_chatmodule added inbuild/server.zigandbuild/dsv41_draft.zig). No shared kernel or another model's path changes, so there is no all-family A/B.Checks run on this branch
This head,
6f2582554, is86857ca4brebased onto mainac51580b2(onlyCHANGELOG.mdneeded resolving, both lines kept) plus the THIRD_PARTY_NOTICES entry for the release's Python files. On it, Linux: the lean checker reads 425 problems, as main does; #2077 stacked on it serves the RTX 5090's sevenocr-matchreplies byte-identical to before the rebase. The macOS checks that follow ran on86857ca4b, rebased on mainb331731e6, and are not yet re-run on this head:zig fmt --check,zig build test,test-kernel-contract,test-golden,test-server-security test-pull-security,fuzz-cortheon,check-release-pathsanddev-toolsall pass on M5 Ultra, macOS, Zig 0.17.0, andtf-kernel-contract --only uocrgives the SUMMARY above.test-nativepasses except one test,draft sources: Metal Qwen27 copies and DFlash2 use actual slot and head facts, which crashes the same way on mainb331731e6without this branch (fixed in #2122). The recipe's speed table is from this head; its replies are byte-identical to the previous head's on all six cases. The two new tests (the--parallelrefusal intest-native, the template's order inzig build test) fail when their expected text is changed. The served replies at this head, with no--chat-template, are byte-identical to the earlier head's with it, on all six cases. The contract's gate 5 records are the kernels'max_total_threads_per_threadgroupreservations; M1 and M2 builds were checked against them (--offline, or its procedure on the group's functions) when each group was registered, and no kernel has changed since. A full--offlinerun reports 7 limit problems in other families' records (dsv41, the MiniMax draft, Ling routing), none of them Unlimited-OCR-2's.Known limits
--vision-max-imagesraises that to 64. Each page takes gundam mode when its tokens fit, else base mode.