首页/新闻资讯/正文详情

DeepSeek-OCR 论文复现全链路:从 DeepEncoder 到 MoE 解码的代码落地与 TaoToken 配置

发布时间:2026/9/25 12:46:13 来源:云帆数科 栏目:资讯中心
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 维护好本地推理和外部调用两条线就不会互相干扰。

相关推荐

artillery-plugin-fake-data 使用指南:在 Artillery 测试脚本中直接生成 Faker 随机测试数据
artillery-plugin-fake-data 使用指南:在 Artillery 测试脚本中直接生成 Faker 随机测试数据

性能测试接口测试CLI 【免费下载链接】artillery The complete load testing platform. Everything you need for production-grade load tests. Serverless & distributed. Load test with Playwright. Load test HTTP APIs, GraphQL, WebSocket, and more. Use any Node.… · 2026/9/25 12:45:49

从零基础到护网值守:网络安全学习路线与实战能力指南
从零基础到护网值守:网络安全学习路线与实战能力指南

计算机网络安全这个方向,这几年的热度一直都在往上走,尤其是到了护网行动相关的招聘季,经常能看到各种高薪岗位挂在社区里。但作为一个带过不少实习生、也参与过多次安全值守的人,我得说句实在话:多数刚入行的大学生&a… · 2026/9/25 12:45:30

昇腾Atlas 300V部署YOLO实战:从ONNX转换到推理调优
昇腾Atlas 300V部署YOLO实战:从ONNX转换到推理调优

1. Atlas到底是个什么东西:先说清楚它是不是运算加速卡先给结论:Atlas不只是一张加速卡,它是一整套AI推理平台。针对热搜里那个问法,华为昇腾(Ascend)的Atlas系列里面,确实有一个纯推理加速卡产… · 2026/9/25 12:45:30

Apache Beam 基础设施权限管理实战:users.yml 声明式 IAM 与 Beam 自定义角色体系
Apache Beam 基础设施权限管理实战:users.yml 声明式 IAM 与 Beam 自定义角色体系

大数据批处理流处理数据工程 【免费下载链接】beam Apache Beam is a unified programming model for Batch and Streaming data processing. 项目地址: https://gitcode.com/gh_mirrors/beam4/beam 点击查看 免费下载 本文以 Apache Beam 仓库中 infra/iam 目录的… · 2026/9/25 13:20:39

IDEA 里配置 Trae AI 插件:从 settings.json 骨架到 TaoToken 统一 Key 接入
IDEA 里配置 Trae AI 插件:从 settings.json 骨架到 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 13:20:39

家庭常备经方实用指南:辨证裁剪是灵魂
家庭常备经方实用指南:辨证裁剪是灵魂

家里备点经方这件事,我一直抱着一种又推荐又警惕的心态。推荐是因为,很多年前我自己第一次在受凉后按经方的思路调理,效果实在超出预期;警惕则是因为,经方从来不是“看个名字就抓药”的简单事。标题里的“日常常备方 中… · 2026/9/25 13:20:33

Atlas 300V 24G推理卡详解:从架构解析到YOLO部署实战
Atlas 300V 24G推理卡详解:从架构解析到YOLO部署实战

前阵子好几个朋友不约而同问到同一个词:atlas。有人问“atlas 300V 24G是运算加速卡吗”,有人问“atlas怎么部署YOLO”。我一开始以为大家在聊某个新出的开源框架,直到他们把硬件截图发过来,我才意识到,他们问的是华为… · 2026/9/25 13:20:33

AI写代码时代已来!手把手教你用Cursor配TaoToken提升开发效率
AI写代码时代已来!手把手教你用Cursor配TaoToken提升开发效率

/* 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 13:20:33

Atlas 300V 24G上部署YOLO全指南:从硬件认知到性能调优
Atlas 300V 24G上部署YOLO全指南:从硬件认知到性能调优

前阵子有个热搜问题很有意思:“atlas 300v 24g 是运算加速卡吗”。说实话,第一次接触到Atlas这个词的人,多半会先联想到那个发布了一系列AI基础架构的Google“Atlas”,或者是某个开源项目的名字。但放到国产AI推理这个圈子里&… · 2026/9/25 13:20:33

数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)
数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)

/* 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 1:00:31

创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战

/* 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 1:00:31

MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX

/* 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 1:00:37

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码