Skip to content

如何使用免费算力部署DeepSeek-OCR模型

前言

DeepSeek-OCR是一个强大的开源OCR模型,但官方部署教程强依赖CUDA环境,Mac用户无法直接运行。本教程通过Google Colab的免费GPU资源,实现零成本部署和试用。

为什么选择Colab

部署限制:

  • 强依赖CUDA 11.8+环境
  • 需要支持Flash Attention 2.7.3
  • 模型文件约6.7GB
  • Mac系统不支持本地CUDA

Colab优势:

  • 免费T4 GPU(16GB显存)
  • 预装CUDA 11.8环境
  • 无需本地配置
  • 云端存储和下载

部署步骤

第一步:启用GPU运行时

  1. 访问 Google Colab
  2. 登录Google账号,创建新笔记本
  3. 配置GPU(必须):
    • 点击"运行时" → "更改运行时类型"
    • 硬件加速器选择"T4 GPU"
    • 点击"保存"

第二步:一键安装和部署

将以下完整代码粘贴到Colab代码单元格中,按Shift + Enter运行:

python
# ========================================
# DeepSeek-OCR Google Colab 安装和运行脚本
# 带Markdown输出格式优化
# ========================================

# 第一步:检查GPU
print("=== 检查GPU信息 ===")
!nvidia-smi

# 第二步:安装依赖
print("\n=== 开始安装依赖包 ===")

# 安装PyTorch
!pip install torch==2.6.0 torchvision==0.21.0 torchaudio==2.6.0 --index-url https://download.pytorch.org/whl/cu118

# 安装transformers和其他基础依赖
!pip install transformers==4.46.3 tokenizers==0.20.3 einops addict easydict accelerate

# 安装Flash Attention
!pip install flash-attn==2.7.3 --no-build-isolation

print("✓ 依赖安装完成!")

# 第三步:下载模型
print("\n=== 下载DeepSeek-OCR模型 ===")
from transformers import AutoModel, AutoTokenizer
import torch
import re
from datetime import datetime

model_name = 'deepseek-ai/DeepSeek-OCR'

print("正在下载tokenizer...")
tokenizer = AutoTokenizer.from_pretrained(
    model_name,
    trust_remote_code=True
)

print("正在下载模型(约6.7GB,需要几分钟)...")
model = AutoModel.from_pretrained(
    model_name,
    trust_remote_code=True,
    torch_dtype=torch.bfloat16,
    device_map="auto"
)

print("✓ 模型加载完成!")

# ========================================
# DeepSeek-OCR 完整版本
# 包含模型加载 + 简化的提示词调用
# ========================================

import re
from datetime import datetime

# ========================================
# 步骤1:检查并加载模型
# ========================================

def check_and_load_model():
    """检查模型是否已加载,如果没有则加载"""
    global model, tokenizer

    try:
        # 检查模型是否已经存在
        _ = model
        _ = tokenizer
        print("✓ 模型已就绪!")
        return True
    except NameError:
        print("⚠️ 模型未加载,开始加载...")
        print("(如果是首次运行,需要下载约6.7GB模型,请耐心等待)")

        from transformers import AutoModel, AutoTokenizer
        import torch

        model_name = 'deepseek-ai/DeepSeek-OCR'

        print("正在加载tokenizer...")
        tokenizer = AutoTokenizer.from_pretrained(
            model_name,
            trust_remote_code=True
        )

        print("正在加载模型...")
        model = AutoModel.from_pretrained(
            model_name,
            trust_remote_code=True,
            torch_dtype=torch.bfloat16,
            device_map="auto"
        )

        print("✓ 模型加载完成!")
        return True

# 初始化检查
check_and_load_model()

# ========================================
# 步骤2:提示词处理函数
# ========================================

def build_prompt(text):
    """
    构建完整的提示词
    自动添加 <image>\n 前缀
    """
    if text.startswith("<image>"):
        return text
    else:
        return f"<image>\n{text}"


# ========================================
# 步骤3:Markdown处理函数
# ========================================

def parse_ocr_output(raw_output):
    """解析OCR输出,提取统计信息"""
    lines = raw_output.split('\n')

    stats = {}
    for line in lines:
        if 'image size:' in line:
            stats['image_size'] = line.split('image size:')[1].strip()
        elif 'valid image tokens:' in line:
            stats['valid_image_tokens'] = int(line.split(':')[1].strip())
        elif 'output texts tokens (valid):' in line:
            stats['output_text_tokens'] = int(line.split(':')[1].strip())
        elif 'compression ratio:' in line:
            stats['compression_ratio'] = line.split(':')[1].strip()

    # 提取内容
    content_lines = []
    skip_markers = ['===', 'BASE:', 'PATCHES:', 'image size:', 'valid image tokens:',
                    'output texts tokens', 'compression ratio:', '正在处理', '%|']

    for line in lines:
        if not any(marker in line for marker in skip_markers):
            content_lines.append(line)

    content = '\n'.join(content_lines)
    return content, stats


def clean_to_markdown(raw_output, show_bbox=False):
    """转换为Markdown格式"""
    content, stats = parse_ocr_output(raw_output)

    # 清理标签
    if not show_bbox:
        content = re.sub(r'<\|ref\|>.*?<\/ref\|>', '', content)
        content = re.sub(r'<\|det\|>\[\[.*?\]\]<\/det\|>', '', content)
    else:
        content = re.sub(r'<\|ref\|>(.*?)<\/ref\|><\|det\|>(\[\[.*?\]\])<\/det\|>',
                        r'**[\1]**`\2`', content)

    content = re.sub(r'\n{3,}', '\n\n', content)

    # 构建Markdown
    markdown = []
    markdown.append("# 📄 OCR识别结果\n")
    markdown.append(f"*生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}*\n")

    if stats:
        markdown.append("## 📊 Token统计\n")
        markdown.append("| 指标 | 数值 |")
        markdown.append("|------|------|")
        if 'image_size' in stats:
            markdown.append(f"| 图片尺寸 | {stats['image_size']} |")
        if 'valid_image_tokens' in stats:
            markdown.append(f"| 视觉Token数 | {stats['valid_image_tokens']} |")
        if 'output_text_tokens' in stats:
            markdown.append(f"| 输出文本Token数 | {stats['output_text_tokens']} |")
        if 'compression_ratio' in stats:
            markdown.append(f"| 压缩比 | {stats['compression_ratio']}× |")
        markdown.append("\n")

    markdown.append("## 📝 识别内容\n")
    markdown.append(content)

    return '\n'.join(markdown), stats


def save_markdown(markdown_text, filename="ocr_result.md"):
    """保存Markdown到文件"""
    with open(filename, 'w', encoding='utf-8') as f:
        f.write(markdown_text)
    print(f"✓ Markdown已保存到: {filename}")
    return filename


# ========================================
# 步骤4:核心OCR函数
# ========================================

def ocr_with_markdown(image_file, prompt_text, base_size=1024, show_bbox=False, save_to_file=True):
    """
    执行OCR并返回Markdown格式
    """
    from PIL import Image
    from IPython.display import Markdown, display as ipy_display
    import sys
    from io import StringIO

    # 检查模型
    check_and_load_model()

    # 构建完整提示词
    full_prompt = build_prompt(prompt_text)

    # 显示图片
    img = Image.open(image_file)
    print(f"✓ 图片: {image_file}, 尺寸: {img.size}")
    print(f"📝 提示词: {prompt_text[:50]}...")
    ipy_display(img)

    # 捕获输出执行OCR
    print("\n⏳ 正在识别...")
    old_stdout = sys.stdout
    sys.stdout = captured = StringIO()

    try:
        model.infer(
            tokenizer,
            prompt=full_prompt,
            image_file=image_file,
            output_path="/tmp/output",
            base_size=base_size,
            image_size=640,
            crop_mode=True,
            save_results=True,
            test_compress=True
        )
    finally:
        sys.stdout = old_stdout

    # 获取结果
    result = captured.getvalue()

    # 如果为空,从文件读取
    if not result or len(result) < 100:
        try:
            with open('/tmp/output/result.mmd', 'r', encoding='utf-8') as f:
                result = f.read()
        except:
            result = "无法获取OCR结果"

    print(f"✓ 获取到 {len(result)} 字符的结果")

    # 转换为Markdown
    markdown_text, stats = clean_to_markdown(result, show_bbox=show_bbox)

    # 显示Markdown
    print("\n" + "="*60)
    print("📄 Markdown格式输出:")
    print("="*60)
    ipy_display(Markdown(markdown_text))

    # 保存并下载
    if save_to_file:
        filename = save_markdown(markdown_text)
        from google.colab import files
        print("\n⬇️  开始下载Markdown文件...")
        files.download(filename)

    return markdown_text, stats, result


# ========================================
# 步骤5:简化的用户接口
# ========================================

def process_uploaded_image(prompt_text="Convert the document to markdown.", base_size=1024, show_bbox=False):
    """
    上传图片并处理

    参数:
    - prompt_text: 提示词(会自动添加<image>前缀)
    - base_size: 分辨率 512/640/1024/1280
    - show_bbox: 是否显示坐标

    示例:
    md, stats, raw = process_uploaded_image("Convert the document to markdown.")
    md, stats, raw = process_uploaded_image("Parse the figure.")
    md, stats, raw = process_uploaded_image("描述图片内容")
    """
    from google.colab import files

    print("📤 请上传图片文件...")
    uploaded = files.upload()

    if not uploaded:
        print("❌ 没有上传文件")
        return None, None, None

    filename = list(uploaded.keys())[0]
    print(f"✓ 已上传: {filename}")

    return ocr_with_markdown(filename, prompt_text, base_size, show_bbox, True)


def process_existing_image(image_path, prompt_text="Convert the document to markdown.", base_size=1024, show_bbox=False):
    """
    处理已上传的图片

    参数:
    - image_path: 图片路径
    - prompt_text: 提示词
    - base_size: 分辨率
    - show_bbox: 是否显示坐标

    示例:
    md, stats, raw = process_existing_image("test.jpg", "OCR this image.")
    md, stats, raw = process_existing_image("chart.jpg", "Parse the figure.")
    """
    return ocr_with_markdown(image_path, prompt_text, base_size, show_bbox, True)


def process_url_image(url, prompt_text="Convert the document to markdown.", base_size=1024, show_bbox=False):
    """
    处理网络图片

    参数:
    - url: 图片URL
    - prompt_text: 提示词
    - base_size: 分辨率
    - show_bbox: 是否显示坐标

    示例:
    md, stats, raw = process_url_image("https://...", "Describe this image.")
    """
    import requests
    from PIL import Image
    from io import BytesIO

    print(f"⬇️  正在下载图片: {url}")
    response = requests.get(url)
    img = Image.open(BytesIO(response.content))

    temp_path = "/tmp/downloaded_image.jpg"
    img.save(temp_path)
    print(f"✓ 图片已保存")

    return ocr_with_markdown(temp_path, prompt_text, base_size, show_bbox, True)


# ========================================
# 完成提示
# ========================================

print("\n" + "="*60)
print("🎉 DeepSeek-OCR 已就绪!")
print("="*60)

print("\n📖 基础用法(超简单):")
print("\n# 默认:文档转Markdown")
print('md, stats, raw = process_uploaded_image()')

print("\n# 解析图表")
print('md, stats, raw = process_uploaded_image("Parse the figure.")')

print("\n# 描述图片")
print('md, stats, raw = process_uploaded_image("Describe this image in detail.")')

print("\n# 提取表格")
print('md, stats, raw = process_uploaded_image("Parse the table.")')

print("\n# 中文提示词")
print('md, stats, raw = process_uploaded_image("识别图片中的所有文字")')

print("\n" + "="*60)
print("💡 常用提示词参考")
print("="*60)

print("""
文档类:
  "Convert the document to markdown."        - 文档→Markdown(默认)⭐
  "OCR this image."                          - 通用OCR
  "Free OCR."                                - 简单识别

解析类:
  "Parse the figure."                        - 解析图表
  "Parse the table."                         - 解析表格
  "Parse the mathematical formula."          - 数学公式
  "Parse the chemical formula."              - 化学式
  "Parse the geometric figure."              - 几何图形

描述类:
  "Describe this image in detail."          - 详细描述
  "Provide a dense caption."                 - 密集标注

中文:
  "识别图片中的文字"                         - 中文OCR
  "提取图片中的表格数据"                     - 中文表格
  "描述这张图片的内容"                       - 中文描述
""")

print("\n" + "="*60)
print("🚀 快速开始")
print("="*60)

print("""
# 步骤1:上传图片并识别(最简单)
md, stats, raw = process_uploaded_image()

# 步骤2:处理已有图片
md, stats, raw = process_existing_image("your_image.jpg", "Parse the table.")

# 步骤3:调整分辨率(可选)
md, stats, raw = process_uploaded_image("OCR this image.", base_size=640)

# 分辨率选择:
# 512  - 简单文档
# 640  - 标准文档(推荐)⭐
# 1024 - 复杂文档
# 1280 - 高清文档
""")

print("\n" + "="*60)
print("✨ 立即开始使用吧!")
print("="*60)

预计时间: 5-10分钟(首次运行)

运行成功后,你会看到:

============================================================
🎉 DeepSeek-OCR 已就绪!
============================================================

📖 基础用法(超简单):

# 默认:文档转Markdown
md, stats, raw = process_uploaded_image()

# 解析图表
md, stats, raw = process_uploaded_image("Parse the figure.")

# 描述图片
md, stats, raw = process_uploaded_image("Describe this image in detail.")

# 提取表格
md, stats, raw = process_uploaded_image("Parse the table.")

# 中文提示词
md, stats, raw = process_uploaded_image("识别图片中的所有文字")

============================================================
💡 常用提示词参考
============================================================

文档类:
  "Convert the document to markdown."        - 文档→Markdown(默认)⭐
  "OCR this image."                          - 通用OCR
  "Free OCR."                                - 简单识别

解析类:
  "Parse the figure."                        - 解析图表
  "Parse the table."                         - 解析表格
  "Parse the mathematical formula."          - 数学公式
  "Parse the chemical formula."              - 化学式
  "Parse the geometric figure."              - 几何图形

描述类:
  "Describe this image in detail."          - 详细描述
  "Provide a dense caption."                 - 密集标注

中文:
  "识别图片中的文字"                         - 中文OCR
  "提取图片中的表格数据"                     - 中文表格
  "描述这张图片的内容"                       - 中文描述


============================================================
🚀 快速开始
============================================================

# 步骤1:上传图片并识别(最简单)
md, stats, raw = process_uploaded_image()

# 步骤2:处理已有图片
md, stats, raw = process_existing_image("your_image.jpg", "Parse the table.")

# 步骤3:调整分辨率(可选)
md, stats, raw = process_uploaded_image("OCR this image.", base_size=640)

# 分辨率选择:
# 512  - 简单文档
# 640  - 标准文档(推荐)⭐
# 1024 - 复杂文档
# 1280 - 高清文档


============================================================
✨ 立即开始使用吧!
============================================================

三种使用方式

安装完成后,在新的代码单元格中使用以下任一方式:

方式1:上传本地图片(推荐)

python
# 默认:文档转Markdown
md, stats, raw = process_uploaded_image()

# 解析图表
md, stats, raw = process_uploaded_image("Parse the figure.")

# 解析表格
md, stats, raw = process_uploaded_image("Parse the table.")

# 中文提示词
md, stats, raw = process_uploaded_image("识别图片中的所有文字")

方式2:使用网络图片

python
# 从URL加载图片
md, stats, raw = process_url_image("https://example.com/document.jpg")

# 指定提示词
md, stats, raw = process_url_image(
    "https://example.com/chart.jpg",
    "Parse the figure."
)

方式3:处理已上传的图片

python
# 如果图片已在Colab环境中
md, stats, raw = process_existing_image(
    "your_image.jpg",
    "Convert the document to markdown."
)

分辨率模式说明

根据文档复杂度选择base_size参数:

模式base_size适用场景速度
Tiny512简单文本最快
Small640标准文档
Base1024复杂表格/公式中等
Large1280高清扫描文档

使用示例:

python
# 简单文档,使用低分辨率
md, stats, raw = process_uploaded_image(base_size=512)

# 复杂文档,使用高分辨率
md, stats, raw = process_uploaded_image(base_size=1024)

查看和下载结果

处理完成后,Markdown文件会自动下载到本地。你也可以手动查看:

python
# 查看输出目录
!ls -lh /tmp/output/

# 读取Markdown结果
with open('/tmp/output/result.mmd', 'r', encoding='utf-8') as f:
    content = f.read()
    print(content)

# 手动下载结果
from google.colab import files
files.download('/tmp/output/result.mmd')

注意事项

免费额度限制

Colab免费版有使用时间限制:

  • 连续运行时间:约12小时
  • 每日使用时长:8-12小时
  • GPU类型:T4(16GB显存)

保存结果

记得下载OCR结果,因为Colab环境会定期重置。

GPU掉线

如果显示"GPU后端已崩溃",重新运行第二步的完整安装脚本即可。

常见问题

Q: 提示"CUDA out of memory"怎么办?

降低分辨率,使用base_size=512base_size=640:

python
md, stats, raw = process_uploaded_image(base_size=512)

Q: 下载模型很慢?

这是正常的,模型有6.7GB,首次下载需要耐心等待。Colab已配置Hugging Face镜像加速。

Q: 能处理PDF吗?

需要先把PDF转成图片。安装pdf2image库:

python
!apt-get install -y poppler-utils
!pip install pdf2image

from pdf2image import convert_from_path

# 上传PDF
from google.colab import files
uploaded = files.upload()
pdf_file = list(uploaded.keys())[0]

# 转换PDF为图片
images = convert_from_path(pdf_file)

# 处理第一页
images[0].save('/tmp/page1.jpg')
md, stats, raw = process_existing_image('/tmp/page1.jpg')

# 批量处理所有页
results = []
for i, img in enumerate(images):
    img.save(f'/tmp/page{i+1}.jpg')
    md, stats, raw = process_existing_image(f'/tmp/page{i+1}.jpg')
    results.append(md)
    print(f"完成第{i+1}页")

Q: 识别结果不准确?

尝试以下优化:

  1. 提高base_size到1024或1280
  2. 使用更精确的提示词(参考上面的提示词表)
  3. 确保图片清晰,避免模糊或倾斜

Q: 可以批量处理吗?

可以,使用循环处理多张图片:

python
# 上传多张图片
from google.colab import files
uploaded = files.upload()

results = []
for i, filename in enumerate(uploaded.keys()):
    print(f"\n处理第{i+1}张: {filename}")
    md, stats, raw = process_existing_image(filename)
    results.append(md)

    # 保存每张结果
    with open(f'/tmp/result_{i+1}.md', 'w', encoding='utf-8') as f:
        f.write(md)

print(f"\n完成,共处理{len(results)}张图片")

# 下载所有结果
for i in range(len(results)):
    files.download(f'/tmp/result_{i+1}.md')

完整工作流示例

以下是一个完整的使用流程:

python
# 1. 上传图片并识别(默认:文档转Markdown)
md, stats, raw = process_uploaded_image()

# 2. 查看统计信息
print(f"图片尺寸: {stats.get('image_size')}")
print(f"视觉Token数: {stats.get('valid_image_tokens')}")
print(f"输出Token数: {stats.get('output_text_tokens')}")
print(f"压缩比: {stats.get('compression_ratio')}")

# 3. 查看识别内容(已经自动显示在输出中)

# 4. Markdown文件已自动下载到本地

成本对比

项目本地部署Colab方案
GPU硬件¥5000+¥0(免费)
环境配置2-4小时5分钟
电力成本¥2/小时¥0
维护成本需要无需
适用场景生产环境学习测试

进阶学习

完成本教程后,可以继续学习: