DeepSeek-OCR 论文复现全链路:从 DeepEncoder 到 MoE 解码的代码落地与 TaoToken 配置
1. 为什么我要把 DeepSeek-OCR 论文拆成可运行代码DeepSeek-OCR 这篇论文最吸引我的地方是它把「长文本压缩」这件事换了个思路不再硬堆上下文窗口而是把文本渲染成图像用少量视觉 token 承载大量文本 token。论文里给出的关键指标很直接——10 倍压缩下 OCR 精度还能保持 97% 左右20 倍压缩掉到 60% 上下同时 MoE 解码器只激活约 570M 参数。对做文档解析、票据识别、PDF 批量入库的人来说这套结构意味着推理成本和上下文长度都能重新算账。但论文和能跑的代码之间隔着不少工程细节DeepEncoder 里 SAM 和 CLIP 怎么串、16 倍卷积压缩放在哪一层、MoE 的 top-k 路由怎么实现、多分辨率模式Tiny/Small/Base/Large/Gundam的 token 数怎么算、两阶段训练怎么切分。我按论文 3.2 到 3.5 节逐段对照把 DeepEncoder、MoE 解码器、数据集构造、训练与评估都落成可复制的脚本并顺手把模型调用通道统一到 TaoToken 的 Key/API 上省得每个模型单独配一套鉴权。这篇适合三类人想复现论文但卡在模块拼接的算法同学、要把 OCR 接进自己业务管线的后端同学、以及想先跑通推理再决定要不要训练的人。下面从环境到推理验证一步步来代码可以直接抄。2. TaoToken 前置统一 Key 与 API 通道复现过程中会反复调用模型做对比验证比如拿 DeepSeek-OCR 的输出和通用多模态模型的结果对照。如果每个模型都单独申请 Key、单独记 endpoint配置会散得到处都是。TaoToken 的作用就是把这些调用收敛到一个 Key 和一套 API 通道上settings.json 里只维护一份配置。你需要先拿到 Key。打开控制台创建 API Key地址是 https://taotoken.net/console/api-keys 创建后复制保存后面所有请求都用它。模型对话的调试入口在 https://taotoken.net/models 接入文档在 https://taotoken.net/doc 接口基址是 https://taotoken.net/api 。这里要区分两件事DeepSeek-OCR 的权重推理是本地跑的不经过任何外部通道TaoToken 负责的是你在复现过程中需要调用的辅助模型比如用另一个多模态模型对同一张图做 OCR 结果交叉验证或者用文本模型帮你检查 MoE 输出的格式是否合法。把这两条线分开配置才不会乱。settings.json 的骨架长这样放在项目根目录代码里统一读取{ taotoken: { api_key: sk-你的Key, base_url: https://taotoken.net/api, chat_endpoint: /v1/chat/completions, default_model: deepseek-chat, timeout: 60 }, deepseek_ocr: { sam_weight: ./weights/sam_vit_b_01ec64.pth, clip_name: openai/clip-vit-large-patch14, moe_tokenizer: deepseek-ai/DeepSeek-3B-MoE, device: cuda } }读取配置的代码很短但能避免 Key 硬编码进训练脚本import json def load_settings(pathsettings.json): with open(path, r, encodingutf-8) as f: return json.load(f) SETTINGS load_settings() TAO_KEY SETTINGS[taotoken][api_key] TAO_BASE SETTINGS[taotoken][base_url]如果你后面要做长期编码或 Agent 类的批量任务可以看 Coding Plan 页面 https://taotoken.net/coding-plan 它更适合持续性的调用场景只是偶尔验证模型输出的话用模型对话页就够了。3. 可复制配置环境、依赖与 DeepEncoder 骨架3.1 环境与依赖安装Python 用 3.10PyTorch 选 CUDA 12.1 对应版本。依赖里最容易踩坑的是 Megatron-LM 和 ppdoclayout前者要手动加 PYTHONPATH后者要从源码装。conda create -n deepseek-ocr python3.10 -y conda activate deepseek-ocr pip install torch2.1.0 torchvision0.16.0 torchaudio2.1.0 \ --index-url https://download.pytorch.org/whl/cu121 pip install numpy1.26.4 pillow10.2.0 tqdm4.66.2 \ editdistance0.6.2 pandas2.2.1 pip install githttps://github.com/facebookresearch/segment-anything.git pip install transformers4.35.2 datasets2.15.0 pip install rdkit-pypi2023.9.6 pyecharts2.0.3 pip install python-docx0.8.11 pymupdf1.23.6 git clone https://github.com/NVIDIA/Megatron-LM.git cd Megatron-LM pip install -e . cd .. export PYTHONPATH$PYTHONPATH:$(pwd)/Megatron-LM装完跑一个环境自检确认每个模块都能 importfrom segment_anything import sam_model_registry from transformers import CLIPVisionModel, AutoTokenizer from megatron import mpu import rdkit.Chem as Chem import fitz sam sam_model_registry[vit_b](checkpoint./weights/sam_vit_b_01ec64.pth) clip CLIPVisionModel.from_pretrained(openai/clip-vit-large-patch14) mol Chem.MolFromSmiles(CCO) assert mol is not None print(环境自检通过)SAM 权重需要手动下载 sam_vit_b_01ec64.pth 放到 weights 目录CLIP 权重会由 transformers 自动缓存MoE 的 tokenizer 也是自动下载但模型权重需要你手动准备。3.2 DeepEncoder 三个子模块DeepEncoder 的结构是 SAM 提特征、卷积压缩 16 倍、CLIP 做全局注意力。先写 SAM 特征提取注意它输出的是 4D 特征图import torch import torch.nn as nn import torch.nn.functional as F import numpy as np from segment_anything import sam_model_registry class SAMFeatureExtractor(nn.Module): def __init__(self, sam_weight_path): super().__init__() sam sam_model_registry[vit_b](checkpointsam_weight_path) self.image_encoder sam.image_encoder self.patch_embed sam.patch_embed for p in self.parameters(): p.requires_grad False def forward(self, x): x F.interpolate(x, size(1024, 1024), modebilinear, align_cornersFalse) x self.patch_embed(x) x self.image_encoder(x) B, N, C x.shape H W int(np.sqrt(N)) return x.permute(0, 2, 1).reshape(B, C, H, W)卷积压缩层把 64×64 压到 16×16token 数从 4096 降到 256class ConvCompressor(nn.Module): def __init__(self, in_ch256, out_ch1024): super().__init__() self.conv_layers nn.Sequential( nn.Conv2d(in_ch, out_ch // 2, 3, 2, 1), nn.ReLU(), nn.LayerNorm([out_ch // 2, 32, 32]), nn.Conv2d(out_ch // 2, out_ch, 3, 2, 1), nn.ReLU(), nn.LayerNorm([out_ch, 16, 16]), ) def forward(self, sam_feat): x self.conv_layers(sam_feat) B, C, H, W x.shape return x.view(B, C, H * W).permute(0, 2, 1)CLIP 部分要把 patch embedding 换成 Identity因为输入已经是压缩后的特征而不是原图from transformers import CLIPVisionModel class CLIPFeatureExtractor(nn.Module): def __init__(self, clip_model_name): super().__init__() self.clip_vision CLIPVisionModel.from_pretrained(clip_model_name) self.clip_vision.vision_model.patch_embedding nn.Identity() for p in self.clip_vision.vision_model.layers[:-2].parameters(): p.requires_grad False self.feat_proj nn.Linear(1024, self.clip_vision.config.hidden_size) def forward(self, compressed_feat): feat self.feat_proj(compressed_feat) return self.clip_vision(inputs_embedsfeat).last_hidden_state3.3 多分辨率模式的 token 计算论文表 1 定义了六种模式token 数不是简单按面积算而是用有效 token 公式修正长宽比RESOLUTION_MODES { Tiny: (512, 512, 64), Small: (640, 640, 100), Base: (1024, 1024, 256), Large: (1280, 1280, 400), Gundam: (640, 640, 1024, 1024, 100, 256), Gundam-M: (1024, 1024, 1280, 1280, 256, 400), } def calculate_valid_tokens(orig_w, orig_h, total_tokens): max_dim max(orig_w, orig_h) min_dim min(orig_w, orig_h) valid_ratio 1 - (max_dim - min_dim) / max_dim return int(np.ceil(total_tokens * valid_ratio))这个公式的意义是长条形文档实际有效信息量比正方形少按比例打折后 token 预算更合理。Gundam 模式是动态切块加全局视图切块数 n 乘以单块 token 再加全局 token。4. 验证请求跑通一次端到端 OCR4.1 MoE 解码器的核心结构MoE 层的关键是路由门选 top-k 专家再加权求和。这里用 64 个专家、激活 6 个class MoETransformerLayer(nn.Module): def __init__(self, hidden_size, num_heads, total_experts, active_experts): super().__init__() self.self_attn nn.MultiheadAttention(hidden_size, num_heads, batch_firstTrue) self.norm1 nn.LayerNorm(hidden_size) self.norm2 nn.LayerNorm(hidden_size) self.experts nn.ModuleList( [nn.Linear(hidden_size, hidden_size) for _ in range(total_experts)] ) self.gate nn.Linear(hidden_size, total_experts) self.active_experts active_experts def forward(self, x, attention_mask): attn_out, _ self.self_attn(x, x, x, attn_mask~attention_mask.bool()) x self.norm1(x attn_out) B, L, D x.shape gate_logits self.gate(x) top_vals, top_idx torch.topk(gate_logits, self.active_experts, dim-1) weights F.softmax(top_vals, dim-1) flat_x x.view(-1, D) flat_idx top_idx.view(-1, self.active_experts) expert_out torch.zeros(B * L, self.active_experts, D, devicex.device) for k in range(self.active_experts): e_idx flat_idx[:, k] expert_out[:, k] torch.stack( [self.experts[e](flat_x[i]) for i, e in enumerate(e_idx)] ) expert_out (expert_out * weights.view(-1, self.active_experts, 1)).sum(dim1) x self.norm2(x expert_out.view(B, L, D)) return x4.2 组装并跑一次推理把 DeepEncoder 和解码器拼起来用一张测试图跑生成from PIL import Image encoder DeepEncoder( sam_weight_pathSETTINGS[deepseek_ocr][sam_weight], clip_model_nameSETTINGS[deepseek_ocr][clip_name], ).to(cuda).eval() decoder DeepSeek3B_MoE_Decoder({ layers: 12, total_experts: 64, active_experts: 6, tokenizer_name: SETTINGS[deepseek_ocr][moe_tokenizer], }).to(cuda).eval() img Image.open(test_doc.png).convert(RGB) img_tensor torch.from_numpy(np.array(img).transpose(2, 0, 1)).float().unsqueeze(0) / 255.0 img_tensor img_tensor.to(cuda) with torch.no_grad(): vis_tokens, valid_tokens encoder(img_tensor, modeSmall) result decoder.generate(vis_tokens, prompt_textimage\nFree OCR.)[0] print(有效视觉 token:, valid_tokens.item()) print(OCR 结果:, result[:200])跑通后你会看到类似有效视觉 token: 100和一段识别文本。Small 模式下 100 个视觉 token 对应大约 600 到 1000 个文本 token压缩比在 6 到 10 倍之间和论文表 2 的区间一致。4.3 用 TaoToken 做交叉验证本地推理跑通后可以调 TaoToken 上的多模态模型对同一张图做 OCR对比两边结果import base64, requests def tao_ocr_verify(image_path, prompt请识别这张图片中的全部文字): with open(image_path, rb) as f: b64 base64.b64encode(f.read()).decode() resp requests.post( TAO_BASE SETTINGS[taotoken][chat_endpoint], headers{Authorization: fBearer {TAO_KEY}}, json{ model: SETTINGS[taotoken][default_model], messages: [{ role: user, content: [ {type: text, text: prompt}, {type: image_url, image_url: {url: fdata:image/png;base64,{b64}}}, ], }], }, timeoutSETTINGS[taotoken][timeout], ) return resp.json()[choices][0][message][content] print(tao_ocr_verify(test_doc.png)[:200])两边结果对照能快速判断本地复现的识别质量是否正常。如果本地输出明显更差优先检查 SAM 权重路径和图像归一化。5. 本篇常见错排查SAM 权重报 FileNotFoundError代码里显式检查了路径确认 sam_vit_b_01ec64.pth 放在 settings.json 里配的路径下文件名不要改。from megatron import mpu 报错Megatron-LM 装完后必须把仓库根目录加进 PYTHONPATH重开终端后 export 会失效建议写进 conda 的 activate 脚本。CLIP 加载后维度对不上feat_proj 的输出维度要和 clip_vision.config.hidden_size 一致CLIP-large 是 1024如果你换了别的 CLIP 变体要同步改。MoE 路由显存爆掉专家循环那里是逐 token 调用的batch 大时会很吃显存。调试阶段把 batch 设成 1 到 4或者把专家实现改成批量矩阵乘。多分辨率模式 token 数不对Gundam 模式的有效 token 是切块数乘单块 token 加全局 token别直接用 calculate_valid_tokens 算整图。TaoToken 请求 401检查 Key 是否复制完整base_url 是否带了末尾斜杠导致路径拼接错误接口路径是 /v1/chat/completions。图像归一化后全黑np.array 出来是 uint8除以 255 前先转 float顺序反了会得到全 0。6. 训练与评估的落地要点两阶段训练里第一阶段只训 DeepEncoder用临时线性解码器接视觉 token 算 next token prediction 损失第二阶段接完整 MoE 解码器SAM 和卷积压缩层冻结只训 CLIP 顶层和 MoE。分布式用 Pipeline Parallel 切 4 段时PP0 放 SAM 加压缩PP1 放 CLIPPP2 和 PP3 各放 6 层 MoE。评估部分 Fox 基准筛 600 到 1300 文本 token 的样本算压缩比和精度OmniDocBench 按文档类型分组算编辑距离。跑完对照论文表 2 和表 3Small 模式 10 倍压缩精度应该在 97% 附近Gundam 模式编辑距离在 0.13 以下。如果你在训练阶段需要批量调用模型做数据清洗或结果校验Coding Plan 的额度模型比按次调用更适合这种持续场景配置方式在 https://taotoken.net/coding-plan 有说明。接入细节和参数含义统一看文档 https://taotoken.net/doc Key 管理在 https://taotoken.net/console/api-keys 。把 settings.json 维护好本地推理和外部调用两条线就不会互相干扰。

相关新闻

yml/yaml 文件报错 found character that cannot start any token:用 TaoToken 统一 Key 排查配置骨架

yml/yaml 文件报错 found character that cannot start any token:用 TaoToken 统一 Key 排查配置骨架

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/25 12:46:20 阅读更多 →
WPScan 动态版本识别实战:从 Crosswinds Blocks 插件 changelog.md 看 BodyPattern 查找器的工作原理

WPScan 动态版本识别实战:从 Crosswinds Blocks 插件 changelog.md 看 BodyPattern 查找器的工作原理

网络安全漏洞扫描渗透测试应用安全CLI 【免费下载链接】wpscan WPScan WordPress security scanner. Written for security professionals and blog maintainers to test the security of their WordPress websites. Contact us via contactwpscan.com 项目地址: ht…

2026/9/25 12:46:20 阅读更多 →
眼动模块完全指南:如何用一块圆屏让你的机器人拥有8种生动眼神

眼动模块完全指南:如何用一块圆屏让你的机器人拥有8种生动眼神

眼动模块完全指南:如何用一块圆屏让你的机器人拥有8种生动眼神 【免费下载链接】eye-tracking-module 源师兄扩展项目: 眼动模块 | 由源师兄组织创建 项目地址: https://gitcode.com/yuanshixiong/eye-tracking-module eye-tracking-module(源师兄…

2026/9/25 12:45:20 阅读更多 →

最新新闻

Atlas 300V 24G推理卡部署YOLOv5全流程实战指南

Atlas 300V 24G推理卡部署YOLOv5全流程实战指南

最近后台连续收到好几条差不多的提问:Atlas 300V 24G是不是运算加速卡啊,能不能拿来部署YOLO?问的人多了,我就知道这不是个例,而是大家在采购清单、项目验收文件、二手平台里看到“Atlas 300V 24G”这个型号之后的普遍…

2026/9/25 13:31:51 阅读更多 →
2025年AI工具出海:小众赛道爆品策略与实操指南

2025年AI工具出海:小众赛道爆品策略与实操指南

1. 为什么“小众赛道”反而更容易跑出AI工具爆品1.1 从“大而全”到“窄而深”的转向2025年做AI工具,如果还想着做一个“什么都能干”的通用助手,基本等于在红海里跟巨头正面硬刚。我观察了最近一年冒出来的几十款有真实营收的AI产品,发现一个…

2026/9/25 13:31:51 阅读更多 →
Atlas 300V 24G推理加速卡详解:从CANN环境到YOLO部署全流程

Atlas 300V 24G推理加速卡详解:从CANN环境到YOLO部署全流程

“atlas部署yolo”和“atlas 300v 24g是运算加速卡吗”这两个搜索词一起出现在热搜榜,我一点都不意外。前者是想在Atlas上跑目标检测的开发者,后者多半是正在纠结要不要下单买卡的选型用户。Atlas这个产品线在AI圈子里出现的频率越来越高,但同…

2026/9/25 13:31:51 阅读更多 →
Atlas 300V 24G加速卡详解:从模型转换到YOLO推理全流程实战

Atlas 300V 24G加速卡详解:从模型转换到YOLO推理全流程实战

最近后台被问得最多的一句话是:“atlas 300v 24g 是运算加速卡吗?”紧接着往往会跟一条:“我打算在atlas上部署yolo,流程到底怎么走?”这两个问题其实是一件事的两面。很多人第一次接触华为昇腾Atlas平台,都…

2026/9/25 13:31:51 阅读更多 →
open-code-review:从流程到工具的代码评审最佳实践

open-code-review:从流程到工具的代码评审最佳实践

我在两年前把团队内部的代码评审机制重新整理了一遍,仓库名就叫open-code-review。这个名字起得很直白,目标是想让代码评审从“两个人关起门来看一眼”变成“所有人都能看见、都能评论、事后还能复盘”的开放过程。当时团队正处在从八个人扩张到三十个人…

2026/9/25 13:31:51 阅读更多 →
miniSQL实战指南:手写数据库内核的四大模块与避坑方法

miniSQL实战指南:手写数据库内核的四大模块与避坑方法

简介:本资源是浙江大学数据库设计课程期末大作业成果——miniSQL轻量级数据库管理系统,面向数据库原理学习者、C/C系统编程初学者及课程实践者,旨在通过完整可运行的DBMS实例,深入理解SQL解析、事务处理、B树索引、缓冲区管理等核…

2026/9/25 13:30:51 阅读更多 →

日新闻

AI元人文:从工具使用到思维重构的深度探索

AI元人文:从工具使用到思维重构的深度探索

最近半年我一直在琢磨一件事:AI元人文到底是什么?说白了,就是“用元视角重新审视人与AI的关系”,也在“探索AI如何反向逼着我们发现自己的思考边界”。标题里的“元探索”,在我看就是一层套一层的追问——当你用AI解决…

2026/9/25 0:00:41 阅读更多 →
Python+CNN车牌识别实战:从数据预处理到模型训练与部署

Python+CNN车牌识别实战:从数据预处理到模型训练与部署

简介:基于Python与卷积神经网络的车牌识别项目,面向计算机视觉初学者及智能交通开发者,目标是帮助用户掌握从数据预处理、模型构建到实际部署的完整流程。压缩包共25个文件,包含jpg/png图像样本、py训练脚本、md说明文档、dat数据…

2026/9/25 0:00:41 阅读更多 →
Vim基础操作全攻略:保存退出、模式切换与高频命令实战

Vim基础操作全攻略:保存退出、模式切换与高频命令实战

1. 项目概述1.1 核心需求解析今天聊聊Vim。写这个题目的原因是:几乎每个后端开发者、运维人员、数据工程师某天都会遇到一个场景——深夜加班,服务器登录界面只有黑底白字,编辑器只有vi/vim,你必须在五分钟内完成一次配置修改并保…

2026/9/25 0:00:41 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/24 14:34:13 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/25 11:15:26 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/24 14:33:56 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/24 12:50:34 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/24 14:33:48 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/24 12:49:17 阅读更多 →