【RK部署】RK3566部署PaddleOCRv2踩坑记录:从模型转换到TaoToken统一Key调用的完整验证

发布时间:2026/10/7 7:19:08
【RK部署】RK3566部署PaddleOCRv2踩坑记录:从模型转换到TaoToken统一Key调用的完整验证 1. RK3566 跑 PaddleOCRv2 到底难在哪从模型转换到板端推理的完整踩坑路径RK3566 是一颗四核 Cortex-A55 的嵌入式 SoC自带 0.8T 算力的 NPU很多人拿它做边缘 OCR 盒子、闸机识别、工业读码器。PaddleOCRv2 是百度飞桨开源的 OCR 套件检测模型 PP-OCRv2 det 加识别模型 PP-OCRv2 rec中文场景识别率在轻量模型里属于第一梯队。把这两个东西凑到一起就是典型的「端侧 OCR 部署」需求板子本地出结果不依赖网络延迟可控隐私数据不出设备。适合读这篇的人有三类一是手上已经有 RK3566 开发板比如 RK3566 核心板 底板、或者类似 EVB 板想跑通 OCR 的嵌入式工程师二是做过 NX、树莓派、Jetson 部署第一次碰 RKNN 工具链的算法同学三是项目里既要端侧识别、又想留一条云端兜底通道需要统一管理 Key 和调用的开发者。我试过在 NX 上用 TensorRT 部署 PaddleOCRv2整个过程一个下午就搞定了所以一开始以为 RK3566 也差不多结果前前后后折腾了一周多坑主要集中在三个地方paddle2onnx 转模型时的动态维度、rknn.config 里 mean/std 参数的语义、以及板端 C 推理时输入前处理的归属问题。这篇会按真实操作顺序走一遍先在 PC 上把 Paddle 模型转成 ONNX再转成 RKNN然后 PC 连板验证最后板端 C 推理。每一步都给可复制的命令和配置遇到报错怎么定位也写清楚。同时因为项目里还需要一条云端 OCR 通道做效果对比和兜底我会说明怎么用 TaoToken 的统一 Key 和 API 通道来管理云端调用这样端侧和云侧可以放在同一套代码框架里切换。先说结论性的经验RKNN 对动态 shape 支持很差转模型时必须固定输入维度mean_values / std_values 不只是前处理参数它还会影响量化后的模型权重设置错了量化模型直接废掉板端推理时输入到底做不做归一化要和转模型参数配套不能各做各的。下面逐段展开。2. 环境准备与 TaoToken 统一 Key 通道端侧云侧两条路怎么并行在动手转模型之前先把两边的环境理清楚。端侧这条线是 PCUbuntu 20.04 或 22.04 都行 RK3566 板子PC 上装 PaddlePaddle、paddle2onnx、rknn-toolkit2板子上跑 rknpu2 的运行时库。云侧这条线是为了做效果对比和兜底用 TaoToken 的统一 Key 来调云端 OCR 或多模态模型避免每个服务单独申请一套凭证。先说 PC 端环境。Paddle 版本建议 2.4 或 2.5和 PaddleOCRv2 的模型匹配。安装命令python -m pip install paddlepaddle2.4.2 -i https://mirror.baidu.com/pypi/simple python -m pip install paddle2onnx1.0.5paddle2onnx 的版本别装太新1.0.x 对 PaddleOCRv2 的算子支持最稳。rknn-toolkit2 建议用 1.5.0 或 1.6.0对应板端 rknpu2 的版本要一致版本错配是后面很多诡异报错的根源。安装 rknn-toolkit2pip install rknn_toolkit2-1.5.0b2f0f9c0-cp38-cp38-linux_x86_64.whl板端这边rknpu2 从 Rockchip 官方仓库拉git clone https://github.com/rockchip-linux/rknpu2.git编译板端推理程序时链接librknnrt.so头文件在rknpu2/runtime/RK356X/Linux/librknn_api/include。交叉编译工具链用板子 SDK 里自带的aarch64-linux-gnu-gcc别用系统 apt 装的版本glibc 版本对不上会在板子上跑不起来。云侧这条线TaoToken 的作用是把多家模型的调用收敛到一个入口。你可以在官网注册后拿到统一 Key然后在控制台里管理不同模型的权限。API 地址是https://taotoken.net/api兼容 OpenAI 风格的请求格式所以端侧代码里如果已经有一套 HTTP 客户端改 Base URL 和 Key 就能接上。模型对话入口在https://taotoken.net/models接入文档在https://taotoken.net/docAPI Key 管理在https://taotoken.net/api-keys。这几个地址后面 CTA 会再提这里先记住结构。为什么要在这个项目里引入云侧通道因为端侧 RKNN 量化后识别率会掉尤其是手写体、低对比度、倾斜文本这些场景。端侧出结果后如果置信度低于阈值可以把图片丢给云端模型复核这样既保证实时性又保证准确率。统一 Key 的好处是端侧和云侧用同一套凭证管理不用在板子上硬编码多个服务的 Key换模型也不用改代码结构。环境准备好之后目录结构建议这样组织paddleocr_rk3566/ ├── models/ # 原始 Paddle 模型 ├── onnx/ # 转换后的 ONNX ├── rknn/ # 转换后的 RKNN ├── convert/ # 转换脚本 ├── board_infer/ # 板端 C 推理 └── cloud_check/ # 云端对比脚本这样后面每一步的输入输出路径都清晰出问题好回溯。3. paddle2onnx 转模型与 rknn.config 参数配置可复制的转换脚本这一步是整个部署里坑最多的环节。先看 Paddle 转 ONNX。从 PaddleOCR 官方 release 里下载 PP-OCRv2 的检测和识别模型检测模型目录里是inference.pdmodel和inference.pdiparams。转换命令paddle2onnx --model_dir./det_ch_PP-OCRv2/ \ --model_filenameinference.pdmodel \ --params_filenameinference.pdiparams \ --save_file./det.onnx \ --opset_version11 \ --input_shape_dict{x: [1, 3, 480, 640]} \ --enable_onnx_checkerTrue注意这里input_shape_dict写的是固定值[1, 3, 480, 640]不是原来的[-1, 3, -1, -1]。这是第一个坑RKNN 不支持动态输入转 ONNX 时如果保留 -1后面转 RKNN 会直接报 shape 相关的错或者转出来推理结果全乱。检测模型固定成 480x640 影响不大因为检测本身对分辨率有一定容忍度。识别模型就麻烦了。PaddleOCR 的识别模型输入是[-1, 3, 32, -1]高度固定 32宽度不定因为不同文本的宽高比差异很大。如果强行固定成[1, 3, 32, 96]长文本会被压缩变形识别率暴跌。我试过两种方案方案一是固定一个较大的宽高比比如[1, 3, 32, 320]然后对待识别文本做边缘填充而不是直接 resize。优点是简单缺点是宽高比小的文本浪费大量计算。方案二是按几个典型宽高比转多个模型比如 32x96、32x160、32x320、32x480推理时根据文本实际宽高比选最接近的模型。优点是省时缺点是要同时加载多个模型内存占用高。这里踩了第二个坑识别模型输入宽度设得太小时PC 连板推理会卡在rknn.init_runtime()不动也不报错。实测宽度大于 96 才能正常转换和推理具体下限没细测建议最小设 96。ONNX 转 RKNN 的脚本关键是rknn.config的参数from rknn.api import RKNN rknn RKNN(verboseTrue) rknn.config( mean_values[[127.5, 127.5, 127.5]], std_values[[127.5, 127.5, 127.5]], target_platformrk3566, quantized_dtypeasymmetric_quantized-8, optimization_level3 ) rknn.load_onnx(model./det.onnx) rknn.build(do_quantizationTrue, dataset./quant_dataset.txt) rknn.export_rknn(./det.rknn) rknn.release()quant_dataset.txt里放几十张代表性图片的路径量化校准用。这里就是第三个坑也是我卡最久的mean_values和std_values不只是对输入做前处理它还会影响量化后的模型权重。我一开始设成[0,0,0]和[1,1,1]因为我在输入数据里已经做了 BGR2RGB、0-255 转 0-1、再减均值除方差。结果 PC 连板推理的 fp16 模型正常int8 量化模型效果极差板端 C 推理的 fp16 模型也是错的。同一个模型不同接口结果不一样说明问题出在转换参数而不是推理代码。后来参考 PaddleOCR 在 RV1106 上的部署配置发现人家输入直接喂 uint8 图像不做额外前处理转模型参数设mean_values[127,127,127]、std_values[127,127,127]。我改成这样之后去掉输入端的归一化只保留 resize 和 BGR2RGBfp16 和 int8、PC 连板和板端全部正常。进一步测试发现规律输入不做前处理时mean/std 设[0,0,0]/[1,1,1]检测模型什么都检不到输入做了前处理时只有 mean/std 接近[0,0,0]/[1,1,1]才有结果。所以正确理解是mean/std 要按模型训练时的均值方差从 0-1 范围换算到 0-255 范围来设同时输入端不要再重复做归一化。PaddleOCR 训练时用的均值是[0.485, 0.456, 0.406]乘以 255 约等于[123.7, 116.3, 103.5]标准差[0.229, 0.224, 0.225]乘以 255 约等于[58.4, 57.1, 57.4]。实际用[127.5,127.5,127.5]也能跑因为量化校准会吸收一部分差异。识别模型的转换脚本同理只是输入 shape 换成对应的固定宽度。把检测和识别都转成 rknn 后PC 连板验证ret rknn.init_runtime(targetrk3566) outputs rknn.inference(inputs[img])如果init_runtime卡住先检查识别模型宽度是不是小于 96再检查板子和 PC 的 adb 连接是否正常。4. 板端 C 推理验证从 rknpu2 到实际识别结果PC 连板验证通过后就要把推理搬到板子上跑 C。从 rknpu2 仓库里参考examples/ssd的 demo 结构主要流程是加载 rknn 模型、初始化输入输出、预处理图像、推理、后处理。加载模型rknn_context ctx; int ret rknn_init(ctx, model_path, 0, 0, nullptr);查询输入输出属性rknn_input_output_num io_num; rknn_query(ctx, RKNN_QUERY_IN_OUT_NUM, io_num, sizeof(io_num));设置输入时注意数据类型要和转模型时一致。因为我们转模型时输入是 uint8 图像mean/std 在模型内部处理所以板端喂进去的就是 resize 和 BGR2RGB 之后的 uint8 数据不要再做 0-1 归一化cv::Mat img cv::imread(image_path); cv::cvtColor(img, img, cv::COLOR_BGR2RGB); cv::resize(img, img, cv::Size(640, 480)); rknn_input inputs[1]; inputs[0].index 0; inputs[0].type RKNN_TENSOR_UINT8; inputs[0].size img.total() * img.elemSize(); inputs[0].fmt RKNN_TENSOR_NHWC; inputs[0].buf img.data; rknn_inputs_set(ctx, 1, inputs); rknn_run(ctx, nullptr);输出后处理按 PaddleOCR 的 DB 检测和 CTC 识别逻辑写。检测输出是概率图做二值化和轮廓提取得到文本框识别输出是序列做 CTC 解码得到文本。这部分代码量不小可以直接参考我放在 GitHub 上的实现仓库地址在文末。编译命令aarch64-linux-gnu-g main.cpp -o ocr_demo \ -I./rknpu2/runtime/RK356X/Linux/librknn_api/include \ -L./rknpu2/runtime/RK356X/Linux/librknn_api/aarch64 \ -lrknnrt -lopencv_core -lopencv_imgproc -lopencv_imgcodecs把可执行文件和 rknn 模型、librknnrt.so一起推到板子上adb push ocr_demo /userdata/ adb push det.rknn /userdata/ adb push rec.rknn /userdata/ adb push librknnrt.so /usr/lib/ adb shell chmod x /userdata/ocr_demo adb shell /userdata/ocr_demo /userdata/test.jpg实测下来一张 640x480 的图片检测加识别在 RK3566 上大约 200-400ms具体取决于文本框数量和识别模型宽度。如果结果不对先确认板端输入是不是 uint8 且没做归一化再确认转模型时的 mean/std 设置这两个对上了基本就正常。云端对比这条线用 TaoToken 的 API 调一次多模态模型把同一张图传上去对比端侧和云侧的识别文本。请求示例curl https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: gpt-4o, messages: [ {role: user, content: [ {type: text, text: 识别这张图片里的文字只输出文字内容}, {type: image_url, image_url: {url: data:image/jpeg;base64,$(base64 -w0 test.jpg)}} ]} ] }这样端侧和云侧的结果可以放在一起对比端侧置信度低的时候自动走云端复核。5. 常见报错排查401、local proxy failed、reading choices、OAuth 对照部署过程中遇到的报错分两类端侧 RKNN 相关的和云侧 API 调用相关的。逐个对照。报错一rknn_init_runtime卡死无输出。最常见原因是识别模型输入宽度太小小于 96 时会出现。解决方法是重新转模型宽度至少设 96建议 160 或 320。另一个原因是板子和 PC 的 adb 连接不稳定adb devices确认设备在线。报错二量化模型识别结果乱码fp16 正常。这是 mean/std 设置问题。检查转模型脚本里的mean_values和std_values如果输入端已经做了归一化转模型参数要设成[0,0,0]/[1,1,1]如果输入端喂 uint8转模型参数要设成接近[127.5,127.5,127.5]/[127.5,127.5,127.5]。两者必须配套不能一边归一化一边又设大均值。报错三local proxy failed或连接超时。这是云侧 API 调用时的网络问题。先确认板子或 PC 能正常访问外网再检查请求地址是不是https://taotoken.net/api注意 API 地址不带 UTM 参数。如果是在板子上直接调云端确认板子的 DNS 配置正确ping taotoken.net能通。报错四HTTP 401 Unauthorized。Key 无效或没带上。检查请求头Authorization: Bearer $TAOTOKEN_API_KEYKey 从https://taotoken.net/api-keys获取。注意 Key 不要硬编码在板端代码里建议通过环境变量或配置文件注入。如果 Key 泄露在控制台里吊销重新生成。报错五reading choices相关解析错误。这是响应 JSON 解析问题通常是请求格式不对或者模型名写错。确认model字段是控制台里已开通的模型 ID请求体是合法的 JSON。如果返回内容为空检查messages结构是否符合 OpenAI 兼容格式。报错六OAuth 相关错误。如果用的是需要 OAuth 的客户端比如某些 IDE 插件或 CLI 工具确认回调地址和客户端配置正确。TaoToken 的 API Key 方式不需要 OAuth直接用 Bearer Token 即可。如果用 Claude Code 这类工具配置 Base URL 为https://taotoken.net/apiKey 填 TaoToken 的 KeyModel ID 填控制台里对应的模型。排查顺序建议先确认端侧模型转换参数对不对再确认板端输入前处理配套最后查云侧网络和 Key。端侧问题看日志和推理结果云侧问题看 HTTP 状态码和响应体。6. 端侧云侧协同的下一步统一 Key 管理与长期编码方案端侧 RK3566 跑 PaddleOCRv2 这条路走通之后实际项目里通常还要考虑几件事模型更新怎么下发、端侧识别率不够时怎么兜底、多个服务怎么统一管理凭证。模型更新可以通过 OTA 把新的 rknn 文件推到板子上代码里做版本检查。端侧兜底就是前面说的置信度低于阈值时把图片传给云端模型复核用 TaoToken 的统一 Key 调多模态模型返回文本和端侧结果做融合。统一 Key 管理的价值在这里体现得比较明显端侧代码、云侧对比脚本、后台管理工具都用同一套 Key 和 Base URL换模型只改 Model ID不用改认证逻辑。TaoToken 的控制台可以看调用量和余额API Key 可以按项目分多个权限也能单独控制。如果你后面要做长期的编码或 Agent 类项目比如让模型自动写板端推理代码、自动生成转换脚本可以考虑 Coding Plan 这类方案把编码任务也收敛到统一通道里。模型对话入口适合做单次验证和效果对比接入文档里有各语言的示例代码。最后把关键地址再列一次方便直接取用官网https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentAPIhttps://taotoken.net/api模型对话https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentAPI Keyshttps://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentCoding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content板端 C 推理的完整代码和转换脚本可以参考 GitHub 仓库zwenyuan1/PaddleOCRv2_rk3566里面有检测和识别的完整实现。踩过的坑基本都写在注释里了遇到类似问题可以先对照排查。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询