DeepSeek-OCR-2 昇腾 NPU 推理适配实战:基于 vLLM-Ascend 的文档 OCR 与 Markdown 输出方案
2026/9/18 1:49:18 网站建设 项目流程

DeepSeek-OCR-2 昇腾 NPU 推理适配实战:基于 vLLM-Ascend 的文档 OCR 与 Markdown 输出方案

【免费下载链接】cann-recipes-infer本项目针对LLM与多模态模型推理业务中的典型模型、加速算法,提供基于CANN平台的优化样例项目地址: https://gitcode.com/cann/cann-recipes-infer

本文基于 CANN / cann-recipes-infer 仓库中 integration/vllm/deepseek-ocr-2 目录下的完整适配方案,系统讲解 DeepSeek-OCR-2 文档理解模型如何在昇腾 NPU(Atlas 800I/T A2)上通过 vLLM-Ascend 完成推理部署,涵盖一键转换脚本、NPU 运行参数、MOE 算子替换原理、三种推理入口与单卡性能测试方法。读完本文,你将掌握从拉取模型到跑通图片/PDF/批量 OCR 推理并产出性能报告的完整闭环流程。

方案概览:非侵入式 NPU 适配

DeepSeek-OCR-2 是 DeepSeek 系列中面向文档理解与 OCR 识别的多模态模型,能够将扫描版或版面复杂的图片、PDF 直接识别为结构化 Markdown 文本。本项目基于 vLLM-Ascend 为其提供了一套昇腾 NPU 推理适配方案,核心特点如下(见 README.md):

  • NPU 原生 MOE 算子支持:将模型中的 CUDA 实现替换为 vllm-ascend 的fused_experts
  • 非侵入式适配方案:不修改官方模型源码主体,而是通过补丁脚本注入 NPU 支持;
  • 模块化设计:转换脚本、环境脚本、MOE 补丁、基准测试脚本职责分离,易于维护和升级;
  • 覆盖多种输入形态:支持单图、PDF 文档和批量评估;
  • 结构化 Markdown 输出:直接产出可复用的 Markdown 格式识别结果。

整个适配任务由智子芯元 KernelCAT 智能体工具自动化完成,适配产物即为仓库中的convert_to_npu.sh一键脚本与npu_patch/补丁目录。

硬件与基础环境要求

项目要求
昇腾设备Atlas 800I/T A2
内存≥ 32GB
磁盘≥ 50GB(用于模型存储)

本项目基于vllm-ascend v0.8.5rc1开发,官方提供了配套容器镜像:

docker pull quay.io/ascend/vllm-ascend:v0.8.5rc1

创建容器

推荐使用docker run拉起推理容器,关键点是透传昇腾设备节点并挂载驱动与模型目录:

docker run -it -d --net=host --shm-size=512g \ --privileged \ --name ds-ocr-2 \ --device=/dev/davinci_manager \ --device=/dev/hisi_hdc \ --device=/dev/devmm_svm \ -v /usr/local/Ascend/driver:/usr/local/Ascend/driver:ro \ -v /usr/local/sbin:/usr/local/sbin:ro \ -v /data/model_weight:/data \ quay.io/ascend/vllm-ascend:v0.8.5rc1 /bin/bash

参数说明:

  • --net=host --shm-size=512g:使用宿主机网络并放大共享内存,多模态推理与批量并发场景下避免 IPC 内存不足;
  • --privileged与三个--device节点:让容器内可见昇腾 NPU 设备(davinci_manager、hisi_hdc、devmm_svm);
  • -v /usr/local/Ascend/driver:ro:以只读方式挂载 NPU 驱动;
  • -v /data/model_weight:/data:将宿主机模型目录映射到容器内/data,后续模型路径按此挂载约定填写。

模型获取

使用 ModelScope 下载 DeepSeek-OCR-2 权重:

pip install modelscope -i https://mirrors.huaweicloud.com/repository/pypi/simple # 下载模型 modelscope download --model deepseek-ai/DeepSeek-OCR-2 --local_dir /data/models/DeepSeek-OCR-2

参数说明:

  • --model:模型名称(deepseek-ai/DeepSeek-OCR-2);
  • --local-dir(README 中写作--local_dir):模型存储路径,示例下载到/data/models/DeepSeek-OCR-2,该路径即后续config.pyMODEL_PATH的取值。

一键转换:convert_to_npu.sh 全流程拆解

将本项目克隆到容器内/workspace目录:

cd /workspace git clone https://gitcode.com/cann/cann-recipes-infer.git cd cann-recipes-infer/integration/vllm/deepseek-ocr-2

执行转换脚本:

./convert_to_npu.sh

脚本默认参数为./convert_to_npu.sh [source_dir] [target_dir],其中源目录默认为DeepSeek-OCR-2/DeepSeek-OCR2-master/DeepSeek-OCR2-vllm,目标目录默认为deepseek_ocr2_npu。结合 convert_to_npu.sh 源码,脚本自动完成以下 5 步:

  1. 安装 Python 依赖(convert_to_npu.sh L16-L21):einopsaddicteasydicttriton-ascendPyMuPDFimg2pdf,走华为云 PyPI 镜像加速;若个别包安装失败仅告警不中断;
  2. 克隆 DeepSeek-OCR-2 源码(convert_to_npu.sh L23-L27):若本地不存在SOURCE_DIR,则自动git clone --depth=1拉取官方源码并定位到 vLLM 工程目录;
  3. 拷贝源码与补丁(convert_to_npu.sh L29-L35):将官方 vLLM 目录完整复制为deepseek_ocr2_npu/,并把 npu_patch/deepseek_ocr2_npu.py(NPU MOE 补丁)与 npu_patch/set_env.sh(环境初始化)放入目标目录;
  4. 应用 NPU 适配补丁(convert_to_npu.sh L37-L74):注释deepencoderv2/sam_vary_sdpa.py中的flash_attn导入,向config.py追加 NPU 配置段,并逐一对三个官方推理脚本注入 NPU 支持;
  5. 输出转换结果:生成deepseek_ocr2_npu/目录,并拷贝 npu_patch/benchmark.py 作为性能测试工具。

脚本自动追加的 NPU 配置

转换脚本向config.py追加的配置段如下:

# ==================== NPU Configuration ==================== DEVICE = 'npu' ENFORCE_EAGER = True MAX_MODEL_LEN = 8192 SWAP_SPACE = 0 TENSOR_PARALLEL_SIZE = 1 GPU_MEMORY_UTILIZATION = 0.85 DISABLE_MM_PREPROCESSOR_CACHE = True

各参数含义:

  • DEVICE = 'npu':指定推理设备为昇腾 NPU;
  • ENFORCE_EAGER = True:关闭图模式,强制 Eager 执行,规避 NPU 上算子图捕获兼容性问题(这也是 README「适配内容」中强调的 NPU 关键配置);
  • MAX_MODEL_LEN = 8192:模型最大序列长度;
  • SWAP_SPACE = 0:关闭 swap 空间,防止出现不可控的 host 内存交换;
  • TENSOR_PARALLEL_SIZE = 1:单卡张量并行,对应 README 中「性能测试(单卡)」的前提;
  • GPU_MEMORY_UTILIZATION = 0.85:NPU 显存利用率;
  • DISABLE_MM_PREPROCESSOR_CACHE = True:关闭多模态预处理器缓存,避免多图/PDF 场景缓存命中异常。

此外,脚本还会对run_dpsk_ocr2_image.pyrun_dpsk_ocr2_pdf.pyrun_dpsk_ocr2_eval_batch.py三个官方脚本做统一改造:在import torch之后注入import osos.environ["VLLM_USE_V1"] = "0"(强制使用 vLLM V0 引擎)与import deepseek_ocr2_npu;并将所有enforce_eager=False统一替换为True、所有gpu_memory_utilization=0.75/0.9/0.7统一收敛为0.85。对图片流式脚本还会追加swap_space=0disable_mm_preprocessor_cache=True两个引擎参数。

环境变量初始化

转换完成后进入目标目录并初始化环境:

cd deepseek_ocr2_npu source set_env.sh

npu_patch/set_env.sh 完成三类环境准备:

  • CANN 工具链路径:设置ASCEND_TOOLKIT_HOMEASCEND_HOME_PATHASCEND_AICPU_PATHASCEND_OPP_PATH,并优先 source ATB(Ascend Transformer Boost)的set_env.sh(缺失时仅告警);
  • 动态库搜索路径:将 driver 的lib64ascend-toolkit${ARCH}-linux/lib64ATB_HOME_PATH/lib依次加入LD_LIBRARY_PATH,同时把 CANN Python 包加入PYTHONPATH
  • NPU 运行参数ATB_STREAM_SYNC_EVERY_KERNEL_ENABLE=0(关闭逐 kernel 流同步以提升性能)、ATB_OPSRUNNER_SETUP_CACHE_ENABLE=1HCCL_WHITELIST_DISABLE=1ASCEND_GLOBAL_LOG_LEVEL=3TOKENIZERS_PARALLELISM=false,以及两个关键 vLLM 开关:VLLM_ATTENTION_BACKEND=NPU(显式指定 NPU 注意力后端)与VLLM_USE_TRITON_FLASH_ATTN=0(关闭 Triton FlashAttention,配合官方脚本中的 SDPA 路径)。

运行推理:三种入口

修改config.py中的三个关键路径参数后即可运行:

vi config.py # - MODEL_PATH: 模型路径(如 /data/models/DeepSeek-OCR-2) # - INPUT_PATH: 输入文件路径 # - OUTPUT_PATH: 输出文件路径

三种推理脚本:

# 图片流式输出 python run_dpsk_ocr2_image.py # PDF 处理 python run_dpsk_ocr2_pdf.py # 图片批量处理 python run_dpsk_ocr2_eval_batch.py

注意:使用批量处理脚本时,config.py中输入图片路径应为图片文件夹路径。

三条入口的差异在于输入形态与输出组织:单图脚本面向单张图片的流式 Markdown 识别;PDF 脚本借助PyMuPDF将 PDF 按页抽取为图片再送入模型;批量脚本遍历文件夹内图片,适合数据集评估。三者统一复用官方DeepseekOCR2Processor的图像处理管线(裁剪模式由CROP_MODE控制),并在入口处完成模型注册。

NPU 适配原理:MOE 算子与注意力机制

MOE 算子:替换为 vllm-ascend 原生实现

DeepSeek-OCR-2 采用 MoE(Mixture of Experts)架构,其官方实现依赖 CUDA 的 fused MOE kernel。补丁文件 npu_patch/deepseek_ocr2_npu.py 在导入时执行_apply_moe_patch(),实现思路是运行时替换 vllm 的fused_moe符号

  1. vllm_ascend.ops.fused_moe引入fused_expertsselect_experts
  2. 定义ascend_fused_moe(hidden_states, w1, w2, gating_output, topk, renormalize, inplace, **kwargs)包装函数;
  3. 内部先调用select_experts(softmax 路由打分、top-k 专家选择、可选renormalize),再调用fused_experts完成专家前向计算(deepseek_ocr2_npu.py L38-L58);
  4. 将包装函数挂载到vllm.model_executor.layers.fused_moe.fused_moe(deepseek_ocr2_npu.py L60),后续模型前向调用统一走 NPU 原生实现。

补丁带完整的降级保护:torch_npuvllm_ascendvllm任一缺失时仅打印 WARNING 并跳过,不会导致导入崩溃,便于排查环境问题。

注意力机制:SDPA 替换 FlashAttention

适配内容中明确「注释flash_attn,使用 SDPA」。转换脚本通过seddeepencoderv2/sam_vary_sdpa.py中的from flash_attn行注释掉(convert_to_npu.sh L37-L38),配合set_env.sh中的VLLM_ATTENTION_BACKEND=NPUVLLM_USE_TRITON_FLASH_ATTN=0,使注意力计算走 vLLM-Ascend 的 NPU SDPA 后端,避免 CUDA 版 FlashAttention 在昇腾上不可用的问题。

引擎级参数

  • ENFORCE_EAGER=True:关闭 CUDA Graph 式捕获,保证 NPU 上算子稳定执行;
  • gpu_memory_utilization=0.85:为 KV Cache 与多模态中间张量预留合理显存余量。

性能测试:benchmark.py 使用与指标解读

单卡性能测试命令:

python benchmark.py --image /path/to/image.jpg --concurrent 1,8,16 --warmup 2 --rounds 3

参数说明:

参数说明默认值
--image图片文件或目录必填
--concurrent并发数列表(逗号分隔)1,8,16
--warmup预热轮数2
--rounds测试轮数5
--max-tokens最大输出 token8192
--gpu-mem显存利用率0.85
--output结果输出文件benchmark_results.txt

结合 npu_patch/benchmark.py 源码,脚本的执行逻辑为:

  • 图片加载(benchmark.py L77-L115):单文件图片会复制为 N 份以匹配并发数;目录则按jpg/jpeg/png过滤并循环取图;
  • 请求构造(benchmark.py L118-L132):调用DeepseekOCR2Processor.tokenize_with_imagesbos=True, eos=True, cropping=CROP_MODE)生成多模态请求,采样参数为temperature=0.0, max_tokens=--max-tokens
  • 引擎初始化(benchmark.py L161-L176):以bfloat16精度加载MODEL_PATH,并通过hf_overrides={"architectures": ["DeepseekOCR2ForCausalLM"]}+trust_remote_code=True注册官方模型类,其余参数全部取自config.pyENFORCE_EAGERMAX_MODEL_LENSWAP_SPACE等);
  • 指标采集(benchmark.py L135-L158):每个并发档位依次执行 冷启动测试(cold)→--warmup轮预热 →--rounds轮正式测试,统计输出吞吐(output_tps = 输出 token / 耗时)总吞吐(total_tps = 输入+输出 token / 耗时),取均值后打印汇总表并写入--output文件(benchmark.py L264-L306);
  • 资源回收:每档并发测试结束即del llm; gc.collect(),避免多档位间显存叠加。

README 记录的单卡性能数据

README「性能数据」一节给出的单卡测试结果如下(数据来源于仓库文档记录,实际数值以所在环境复测为准):

并发数输出吞吐 (tokens/s)总吞吐 (tokens/s)
140.5096.78
4106.50292.68
8212.52584.02
32413.681136.81
64486.621337.26
100550.451512.68

可以看到,随着并发数从 1 提升到 100,输出吞吐从约 40 tokens/s 增长到约 550 tokens/s,总吞吐从约 97 tokens/s 增长到约 1513 tokens/s,说明该适配方案在批处理维度具备良好的吞吐扩展性。

项目结构

integration/vllm/deepseek-ocr-2/ ├── convert_to_npu.sh # 一键转换脚本 ├── README.md # 适配说明与部署文档 ├── LICENSE # MIT License └── npu_patch/ ├── deepseek_ocr2_npu.py # NPU MOE 补丁(vllm-ascend fused_experts 替换) ├── set_env.sh # 环境初始化(CANN/ATB/驱动动态库与 vLLM 开关) └── benchmark.py # 单卡并发性能测试脚本

故障排除

问题解决方案
指定 NPU 设备export ASCEND_RT_VISIBLE_DEVICES=0

在多卡机器上运行前,建议显式指定目标 NPU 设备号;其余常见问题可优先检查两点:source set_env.sh是否已执行(决定 CANN 动态库与VLLM_ATTENTION_BACKEND=NPU是否生效)、补丁是否随转换脚本注入(可在目标目录确认存在deepseek_ocr2_npu.py且官方脚本头部包含import deepseek_ocr2_npu)。

许可证与第三方代码

本项目采用 MIT License 开源许可,并包含以下第三方代码(详见 README.md 与 LICENSE):

  • SAM(Meta):Apache License 2.0,作为视觉编码器组件;
  • DeepSeek-VL2(DeepSeek AI):MIT License,OCR 模型的基础结构来源;
  • vLLM:Apache License 2.0,推理框架本体。

使用本方案时需一并遵守上述三方组件的许可约束,且注意适配依赖 vllm-ascend v0.8.5rc1 与 Atlas 800I/T A2 硬件环境,版本或硬件不匹配时需按实际环境重新验证算子兼容性。

【免费下载链接】cann-recipes-infer本项目针对LLM与多模态模型推理业务中的典型模型、加速算法,提供基于CANN平台的优化样例项目地址: https://gitcode.com/cann/cann-recipes-infer

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询