跳到主要内容

文档 OCR 模型

Donut 本地部署:跳过 OCR 引擎,把单据图像直接读成 JSON

约 200M 参数、fp32 权重只有 809MB —— Donut 至今仍是最省显存的端到端文档结构化模型。在 NexGPU 上一张 $0.193/卡·时 的 RTX 3090 24GB 就能跑完整微调,从开卡到吐出第一份 JSON 用不了一小时。

Donut 全称 Document Understanding Transformer,出自 NAVER CLOVA,论文《OCR-free Document Understanding Transformer》发表在 ECCV 2022(arXiv 2111.15664),代码在 GitHub 的 clovaai/donut,MIT 许可证。它的核心主张写在名字里:不要 OCR。传统文档抽取是「OCR 引擎识别文字 → 版面分析 → 规则或模型拼字段」的三段式流水线,每一段的误差都会往下游传,换个版式就要重调一遍。Donut 把这一整条流水线塞进一个 Swin Transformer 编码器加四层 mBART 解码器的模型里,输入一张图片,直接自回归吐出一段带标签的序列,再用 processor.token2json() 转成你要的 JSON。整个模型 fp32 权重 809MB,对照今天动辄 3B 起步的 OCR 大模型,这是一个数量级的差距。

但要把话说完整:Donut 的上游已经不再更新了。donut-python 最后一个版本 1.0.9 停在 2022 年 11 月,官方 Colab demo 最后一次刷新是 2023 年 6 月,仓库 issue 区里「Provide a working list of deps」「Colab Demo CORD is Broken」这类环境问题一路挂到 2026 年 2 月还没关。naver-clova-ix 这个组织在 Hugging Face 上一共 9 个模型,全部是 Donut 家族,2022 年之后没有再发新东西。今天你要做的如果是「任意版式文档转 Markdown 全文」,DeepSeek-OCR(3B,MIT,2025 年 10 月)、GLM-OCR、GOT-OCR2.0 这些新一代 OCR-free VLM 已经把 Donut 甩开了,别硬用。但如果你的场景是「固定版式 + 固定 JSON schema」—— 电商回单、加油发票、体检报告、报关单、快递面单 —— Donut 依然是最优解:200M 参数意味着它的显存占用和推理成本比 3B 模型低一个量级,输出严格锁死在你微调时定义的字段上,不会像通用 VLM 那样偶尔发挥自由意志给你多编一个字段出来,而且 MIT 许可证让你可以随便商用、随便闭源分发。

显存上 Donut 几乎不构成门槛,真正的成本在微调。donut-base 的预训练用了 64 张 A100 跑 2.5 天,donut-proto 用了 8 张 V100 跑 5 天 —— 但那是从零预训练,你不需要重复。基于官方 checkpoint 做下游微调,社区最常被引用的实测是在一张 16GB 的 V100 上完成的:分辨率降到 720×960、fp16、batch size 2、624 张标注图跑 3 个 epoch。NexGPU 上 Tesla V100 32GB 是 $0.188/卡·时,RTX 3090 24GB 是 $0.193/卡·时,两张卡都比那台机器宽裕。按秒计费、没有起租时长、没有配额申请,2000+ 预置镜像里的 PyTorch 镜像开机即用,51 个国家和地区的 1,175 个已验证节点让你挑一个离数据近的位置落地。

01 —

Donut 官方 checkpoint 全表

naver-clova-ix 下全部 6 个可用权重,参数量都在 200M 上下,差别在输入分辨率和解码器输出上限

版本参数量显存上下文说明
naver-clova-ix/donut-base约 200M(Swin 编码器 depths [2,2,14,2] + 4 层 mBART,d_model 1024,词表 57525)fp32 权重 809MB/fp16 约 400MB;2560×1920 下 fp16 推理峰值约 3~5GB解码器 1536 token只做过 SynthDoG 合成数据预训练的裸底座,直接推理不会输出任何有意义的结构 —— 它是给你微调用的起点,不是成品。做全新语种或全新版式时从这里出发。
naver-clova-ix/donut-base-finetuned-cord-v2约 200M(词表 57580,权重 806MB)fp16 推理约 1.5~2GB;1280×960 + fp16 + batch 4 微调约 10GB解码器 768 token收据结构化,输入 1280×960(高×宽),任务提示词 <s_cord-v2>。开箱即用能直接把小票读成 menu/sub_total/total 三段 JSON,也是社区微调自有票据 schema 时最常用的起点权重。
naver-clova-ix/donut-base-finetuned-docvqa约 200M(词表 57532)fp16 推理约 3~5GB(2560×1920 的 Swin 激活是显存大头,不是权重)解码器仅 128 token文档问答,提示词格式 <s_docvqa><s_question>你的问题</s_question><s_answer>。注意 128 token 的输出上限意味着它只能回答短答案,想让它总结整页会被硬截断。
naver-clova-ix/donut-base-finetuned-rvlcdip约 200M(词表 57544)fp16 推理约 3~5GB;解码只出一个类别标签,KV cache 几乎为零解码器仅 8 tokenRVL-CDIP 十六类文档分类(发票、简历、广告、手写件……),提示词 <s_rvlcdip>,输出形如 {'class': 'advertisement'}。想拿它当抽取模型用一定会失败 —— 8 token 装不下任何 JSON。
naver-clova-ix/donut-base-finetuned-zhtrainticket约 200M(词表 57542)fp16 推理约 1.5~2GB(960×1280 横向,像素量只有 base 的四分之一)解码器 256 token唯一一个官方中文 checkpoint,中国火车票信息抽取。分辨率是 960×1280 的横向配置,正好贴合车票的形状。做中文单据时它比 cord-v2 更接近你的分布,值得当微调起点试一次。
naver-clova-ix/donut-proto约 200M(Swin depths [2,2,18,2],标准 Swin-B 深度,词表 57524)fp32 权重约 810MB;2048×1536 下 fp16 推理约 3~4GB解码器 768 token早期原型底座,输入 2048×1536,用 8 张 V100 训了 5 天。它的第三阶段有 18 个 block(donut-base 缩到了 14),结构和后续版本不完全兼容,除非要复现论文早期结果,一般直接用 donut-base。

02 —

NexGPU 选卡建议

Donut 只有 200M 参数,显存从来不是瓶颈 —— 该关心的是分辨率带来的激活开销和自回归解码的速度

  • 跑通官方 checkpoint,验证 Donut 能不能读懂你的单据

    Tesla V100 32GB$0.188/卡·时

    全站最便宜的一张卡,Volta 的 fp16 张量核跑 Donut 完全够用(社区那份广被引用的微调实测就是在 V100 上做的),32GB 显存装得下 donut-base 原生 2560×1920 分辨率,20 分钟就能得出「这条路走不走得通」的结论。

  • 用几百到几千张自有标注单据微调专属 schema(1280×960、fp16、batch 4~8)

    RTX 3090 24GB$0.193/卡·时

    AdamW 的优化器状态对 200M 模型只要约 3.2GB,加上梯度和 1280×960 的激活,24GB 剩下大把余量把 batch 开到 8;每小时不到两毛美金,一整轮微调的算力成本还不到一杯咖啡。

  • 保留 2560×1920 原生分辨率微调,或者想把训练时间压掉一半

    RTX 4090 24GB$0.540/卡·时

    原生分辨率下 Swin 第一阶段有 30 万个 token,激活量是 1280×960 的四倍,需要开梯度检查点才塞得进 24GB;Ada 架构的 fp16/bf16 吞吐大约是 3090 的两倍,按秒计费下更快跑完往往总价更低。

  • 用 SynthDoG 合成数据为新语种/新领域重做预训练底座

    A100 SXM4 80GB$1.088/卡·时

    官方 donut-base 是 64 张 A100 跑 2.5 天出来的,重做底座是唯一真正需要规模的场景;NexGPU 单节点最多 14 张卡、最大整机显存 2,152GB,配合 synthdog-zh 的 6.37 万张中文合成文档,一次 8 卡 NVLink 任务就能起步。

03 —

四步在 NexGPU 上跑起来

别碰 donut-python 这个包 —— 它的依赖已经锁死在 2022 年的 timm 和 pytorch-lightning 上,直接用 Transformers 的 VisionEncoderDecoder 接口

  1. 01

    开一张卡,装干净的 Transformers 环境

    在控制台选 RTX 3090 24GB 和 PyTorch 预置镜像,SSH 或 Jupyter 进去。仓库里 issue 区那些「装不上」「Colab 挂了」的帖子几乎全是 donut-python 的锅,Transformers 官方已经把 Donut 完整实现进去了,不需要原仓库的任何代码。注意 Transformers v5 起 image-to-text 这个 pipeline task 已经废弃,改用 image-text-to-text,模型类用 AutoModelForImageTextToText 或 VisionEncoderDecoderModel。

    pip install -U "transformers>=5.0" torch torchvision pillow sentencepiece protobuf datasets
  2. 02

    先用 cord-v2 跑一张真票据,确认卡和分辨率没问题

    加载 donut-base-finetuned-cord-v2,用 fp16 推到 GPU 上,喂一张你自己的收据照片,任务提示词是 <s_cord-v2>。generate 时务必带上 bad_words_ids=[[tokenizer.unk_token_id]] 和 use_cache=True —— 前者防止解码器在遇到词表外字符时死循环吐 <unk>,后者是速度的关键。输出序列用 processor.token2json() 转 JSON。这一步跑通,你就知道 Donut 对你这类版式的原始识别能力在什么水位。

    model = VisionEncoderDecoderModel.from_pretrained("naver-clova-ix/donut-base-finetuned-cord-v2", dtype=torch.float16).to("cuda")
  3. 03

    换成你自己的字段体系:加任务 token、扩词表、放开输出长度

    这是 Donut 微调最容易翻车的一步,仓库 issue #332 那种「测试集 TED 和 F1 双双为 0」基本都出在这里。给 tokenizer 加上你的任务起始 token 和所有字段 token,然后必须调用 decoder.resize_token_embeddings() 让嵌入矩阵跟着变大,并把 config.decoder_start_token_id 指到新 token 上 —— 三步少一步,模型就会从一个它从没见过的 id 开始解码,训练看着在收敛,评测直接归零。同时检查 max_position_embeddings:cord-v2 只有 768,rvlcdip 只有 8,你的 JSON 如果比这长必须先扩。

    processor.tokenizer.add_special_tokens({"additional_special_tokens": ["<s_myreceipt>"]}); model.decoder.resize_token_embeddings(len(processor.tokenizer)); model.config.decoder_start_token_id = processor.tokenizer.convert_tokens_to_ids("<s_myreceipt>")
  4. 04

    降分辨率、开 fp16,开始微调

    分辨率是显存和精度的唯一旋钮:改 image_processor.size 的同时也要改 encoder.image_size,并且让 Swin 的位置偏置跟着插值(from_pretrained 时带 ignore_mismatched_sizes=True)。宽高都建议保持能被 window_size 10 整除。社区实测把 2560×1920 降到 720×960 后,16GB 的 V100 上 batch 2 就能跑;在 24GB 的 3090 上你可以保留 1280×960 并把 batch 开到 8。训练完直接 save_pretrained,800MB 的权重拉回本地部署,出网只按 $0.0081/GB 中位价收费。

    processor.image_processor.size = {"height": 1280, "width": 960}; model.config.encoder.image_size = (1280, 960)

微调一个专属 Donut 要花多少钱

以「600 张自有单据,微调出一个只认你家版式的结构化模型」为例,全部按 NexGPU 列表价算。微调用 RTX 3090 24GB,$0.193/卡·时,1280×960 加 fp16 加 batch 4,留 3 小时跑完 epoch 和中途评估:0.193 × 3 = $0.579。跑完再开 1 小时对全量测试集做推理和 TED 打分:0.193 × 1 = $0.193。数据集、HuggingFace 缓存和几个 checkpoint 加起来约 20GB,存储按 $0.414/GB·月 的中位价占用 3 天:20 × 0.414 × 3 ÷ 30 = $0.828。最后把 800MB 成品权重拉回本地,出网按 $0.0081/GB 中位价:0.8 × 0.0081 ≈ $0.01。合计约 $1.61 —— 一顿早饭的钱,换一个跑在你自己机器上、不给任何第三方看一眼单据内容的抽取模型。这里要提醒的是计费规则:算力按秒计,训练脚本一停就不再计费;但存储要等你销毁实例才停,上面那 $0.828 是这笔账里最容易被忘掉的一项,跑完记得把卷删干净。如果你只是想先验证 donut-base-finetuned-cord-v2 读不读得懂你的收据,Tesla V100 32GB $0.188/卡·时,二十分钟足够:0.188 × ⅓ ≈ $0.06。

04 —

常见问题

Donut 本地部署到底需要多大显存?24GB 的卡够吗?

远远够,Donut 的显存需求可能比你以为的低一个数量级。它只有约 200M 参数,donut-base 的 pytorch_model.bin 是 809MB 的 fp32 权重,转 fp16 大约 400MB。真正吃显存的是输入分辨率带来的 Swin 编码器激活:1280×960 的 cord-v2 推理峰值大约 1.5~2GB,2560×1920 的 donut-base 和 docvqa 大约 3~5GB。微调时加上 AdamW 优化器状态(200M 参数约 3.2GB)和梯度,1280×960 下 batch 4 大概 10GB。所以 NexGPU 上最便宜的 Tesla V100 32GB($0.188/卡·时)和 RTX 3090 24GB($0.193/卡·时)都绰绰有余,甚至 Tesla T4 16GB($0.298/卡·时)在降分辨率后也能跑推理。真要说,Donut 是我们平台上性价比最极端的一类模型 —— 你付的钱几乎全花在算力速度上,而不是被显存容量绑架。

都 2026 年了,有 DeepSeek-OCR、GLM-OCR 这些新模型,Donut 还值得用吗?

分场景。做通用 OCR —— 任意版式文档转 Markdown、扫描件全文提取、复杂表格还原 —— 别用 Donut,它 2022 年的架构和三亿以下的参数量在这些任务上已经被新一代 OCR-free VLM 全面超越,直接上 DeepSeek-OCR(3B,MIT)或 GOT-OCR2.0(0.7B)。但如果你的输入是固定版式、输出是固定 JSON schema,Donut 仍然赢在三个地方:参数量只有它们的十五分之一到四分之一,单卡吞吐和成本差一个量级;输出被微调时定义的字段严格锁死,不会像通用 VLM 那样偶尔自由发挥多编字段;MIT 许可证,商用闭源分发都没有法律负担。实际做法是两条路各租一张卡跑同一批样本对比 —— NexGPU 按秒计费、无起租时长,两个方案各花二十分钟验一遍,成本合起来不到 $0.5。

为什么我微调完,测试集的 TED 和 F1 直接是 0?

这是 Donut 微调最经典的坑,官方仓库 issue #332 就是它。九成情况出在特殊 token 的三步没做全:给 tokenizer 加了任务起始 token 和字段 token 之后,必须调用 model.decoder.resize_token_embeddings(len(processor.tokenizer)) 把嵌入矩阵扩到新词表大小,并且把 model.config.decoder_start_token_id 指向你的新起始 token。少了 resize,新 token 的 id 会越界;少了 decoder_start_token_id,模型会从一个和训练时完全不同的起点开始解码 —— 两种情况下训练 loss 都看着在正常下降,评测却全零。第二个常见原因是 max_position_embeddings 太小把目标 JSON 截断了(cord-v2 是 768,docvqa 只有 128,rvlcdip 只有 8)。这类问题最快的排查方式就是租一张 $0.193/卡·时 的 3090 反复小批量重跑,改一行验一次,比在本地 CPU 上干等强得多。

donut-python 这个包装不上、官方 Colab 也跑不通,怎么办?

别修它,绕过去。donut-python 最后一个版本是 2022 年 11 月的 1.0.9,依赖锁在当年的 timm、pytorch-lightning 和 transformers 上,和今天的 PyTorch 完全不兼容;仓库 issue 区里「Provide a working list of deps」「Colab Demo CORD (Document Parsing) is Broken」「app.py Failing for Python 3.9」这些帖子一路挂到 2026 年 2 月都没人处理,因为 NAVER CLOVA 事实上已经停止维护这个仓库了。正确做法是完全用 Hugging Face Transformers:DonutProcessor 加 VisionEncoderDecoderModel(或 AutoModelForImageTextToText),官方权重不变,推理和微调的代码路径都在持续维护。另外注意 Transformers v5 已经废弃了 image-to-text 这个 pipeline task,要改成 image-text-to-text。NexGPU 的 2000+ 预置镜像里 PyTorch 镜像开机就是干净的现代环境,省掉你在本地和 CUDA 版本搏斗的那半天。

Donut 能当通用 OCR 用吗?我想让它把整页文字都读出来。

不能,这是对 Donut 最普遍的误解。它不是识别引擎,是「图像直接到结构化输出」的端到端模型,输出内容完全由任务提示词和微调数据决定:给 <s_cord-v2> 它吐收据的 menu/total 字段,给 <s_rvlcdip> 它吐一个类别名,给 <s_docvqa> 加一个问题它吐一句短答案。donut-base 底座连这些都不会 —— 它只做过 SynthDoG 合成数据的预训练,没微调之前推理出来是无意义的序列。想要全页文字,用 GOT-OCR2.0、Surya 或 DeepSeek-OCR;想要「这张单据的十二个字段是什么」,才轮到 Donut。想不清楚属于哪一类,就在 NexGPU 上开一张 V100 32GB 花二十分钟两边都试一遍,$0.06 的事。

微调 Donut 大概需要多少张标注数据?成本能控制在什么范围?

比大模型微调少得多。社区最常被引用的那份实测只用了 624 张标注图、跑 3 个 epoch 就得到了可用的结果;工程上固定版式的单据通常几百到两三千张就能收敛,标注格式就是每张图配一段目标 JSON,不需要画框、不需要标字符位置 —— 这正是 OCR-free 路线省事的地方。算力上,600 张图在 RTX 3090 24GB($0.193/卡·时)上留 3 小时足够跑完训练加评估,$0.579;加上评测、存储和把权重拉回本地,整轮不到 $2。NexGPU 按秒计费、无最低消费、无开通费、不用申请配额,你可以先跑 200 张试水看曲线,觉得有戏再补标注继续 —— 中途停机就中途停止计费,这种「小步快跑」的迭代方式正是 Donut 这种小模型该有的用法。

开始使用 NexGPU

无论你是企业研发团队还是独立开发者,都可以在几分钟内跑起第一个任务。

注册即可浏览全网实时价格,无需绑定支付方式。