[腾讯犀牛鸟26] HunyuanOCR 的 ncnn 移植:pnnx 转换、C++ 解码与 Windows/Linux 验证 #6880
Wi1sonchen
started this conversation in
Show and tell
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
一个面向Tencent/ncnn#6787 的阶段性实现:使用 pnnx 将
tencent/HunyuanOCR1.0 拆分转换为 ncnn 模型,并参考ncnn_llm实现尽量少依赖的 C++ OCR 推理链。当前版本为
0.1.0-preview.2。完整的图片预处理、视觉编码、视觉特征注入、文本 prefill、KV cache 和逐 token 解码已经在 C++ 中串通;同一份 CMake 工程已在 Windows MinGW x64 和 Ubuntu 24.04/WSL x64 上完成构建与 CPU 推理验证。现阶段适合作为可构建、可复现和可继续评审的技术预览。两个固定输入已经达到ncnn CPU 与官方 PyTorch BF16 的 generated token 序列和最终文本一致;任意输入上的普遍一致性仍需继续扩大验证范围。
1. 当前完成度
运行时不依赖 PyTorch、Transformers 或 Python。Python 只用于模型转换、官方参考结果生成和数值验证。
2. 模型拆分与运行结构
为控制峰值内存并便于逐层定位,当前没有把完整 HunyuanOCR 导出成一个大图,而是拆成以下资产:
推荐的 split eager runtime 共 121 个文件,约 2.24 GB。视觉 block 和文本decoder layer 按顺序加载执行,避免所有子图同时常驻。
3. 关键实现点
3.1 图像预处理与视觉特征
C++ 端实现了与官方 processor 对齐的:
视觉输入和注入文本模型前的最终视觉特征保留 BF16 边界。视觉 block 之间使用FP32 residual,避免拆图后重复低精度往返造成额外累计误差。
3.2 文本 Decoder 与 KV cache
24 个 Decoder layer 以独立 ncnn 子图运行。当前 K/V 由子图输出,C++ 将其与历史 cache 拼接后重新输入 attention 图,因此 cache 长度始终与真实 token 数一致,不需要永久屏蔽的占位 K/V。
prefill 与增量解码使用不同形状的 causal mask;生成阶段每次只计算一个新token,并复用 24 层 cache。
3.3 HunyuanOCR 的 RoPE 路径
官方
use_cache=True的实际 prefill 行为需要特别处理:C++ 运行时复刻了这一分支行为。该处理对固定样例的文本 token 一致性非常关键。
3.4 BF16 输出与 token 选择
官方 checkpoint 配置为 BF16。当前实现会在 LM Head 输出后执行FP32 → BF16 → FP32 边界,再进行 greedy token 选择,以匹配官方 logits dtype。
对于量化后合法 EOS 与最高分精确同分的情况,runtime 提供可配置的
setting.greedy_eos_tie_break。它只在以下条件同时成立时选择 EOS:repetition_penalty=1;采样、非单位 repetition penalty 和非平票 logits 不受影响;debug 模式会记录策略是否介入。这个规则用于稳定量化端口的停止行为,不作为任意输入张量等价的证明。
3.5 EOS 与 tokenizer
资产生成器按以下顺序解析并合并 EOS:
HunyuanOCR 1.0 的运行时 EOS 集合为
[120007, 120020]。C++ 在 callback 前停止,同时在--debug-tokens模式下保留结束 token,便于与 Transformers 的generated IDs 逐项比较。此外,HunyuanOCR 的 byte-level 词表包含字面量
\n、\r和\t。当前集成在 ByteDecode 前保留这些 token,使最终文本与 Transformers 的解码结果一致。4. 固定输入验证
参考模型和环境:
tencent/HunyuanOCR1.0;2.7.1+cu128;torch.bfloat16;82a06db03535c49aa987719ed0746a76093b1ec4;提取图中的文字。;字幕样例最终文本:
两个样例均在 token 序列中包含最终 EOS,且没有触发 EOS 平票策略。
机器可读凭据:
validation/acceptance-tools-dark.jsonvalidation/acceptance-subtitle-eos.jsonvalidation/platform-builds.json原始验收图片不随源码包分发,凭据中保留图片 SHA-256、尺寸、prompt、处理参数、生成参数、token 摘要、文本哈希和平台结果。
5. 双平台构建
Linux 示例:
Windows PowerShell 示例:
推理示例:
./build-runtime/hunyuanocr_ocr \ --model /path/to/hunyuanocr-runtime \ --image /path/to/input.png \ --prompt '提取图中的文字。' \ --max-image-side 512 \ --max-new-tokens 128 \ --threads 2 \ --debug-tokens模型和转换后权重受 Tencent Hunyuan Community License Agreement 约束,因此源码包不包含官方 checkpoint 或约 2.24 GB 的 runtime 权重。仓库提供模型来源说明、文件 manifest 和本地资产生成流程。
6. 当前不足与证据边界
目前可以确认的是两个固定输入在两种 CPU 平台上的 token 与最终文本一致,尚不代表任意图片、任意 prompt 或所有后端都已完全等价。当前主要边界如下:
All reactions