DeepSeek OCR 微调指南

在本指南中,我们将逐步讲解如何为定制DeepSeek OCR模型,仅需60 个训练步骤即可实现显著的性能提升。

DeepSeek OCR 微调指南

在人工智能的世界中,DeepSeek OCR 快速确立了自己作为光学字符识别最创新模型之一的地位。2025 年初推出时,这个模型因其几个使其真正独特的原因而引起轰动。

为什么 DeepSeek OCR 受到如此推崇?

  1. 先进的视觉-语言架构: DeepSeek OCR 基于尖端的视觉-语言架构,结合了视觉理解和自然语言处理。这不仅使它能够识别文本,还能在上下文中理解其含义
  2. 出色的多语言支持: 与许多主要关注西方语言的 OCR 模型不同,DeepSeek OCR 对复杂语言(如波斯语、阿拉伯语、汉语等)提供了与英语相当的出色准确性
  3. 灵活的图像处理: 该模型实现了动态裁剪系统,智能处理各种尺寸和布局的文档,将大图像分割成可管理的部分而不丢失上下文信息。
  4. 开源且易于访问: DeepSeek 已将模型免费提供,使高端 OCR 技术民主化,使开发人员和研究人员能够根据特定用例自定义它
  5. 计算效率: 尽管其先进功能,该模型经过优化,可在消费级硬件上运行,3B 参数版本可以在标准 GPU 上运行。

然而,DeepSeek OCR 的真正力量在于你为特定领域进行微调

在本指南中,我们将逐步讲解如何为定制DeepSeek OCR模型,仅需60 个训练步骤即可实现显著的性能提升。

这里是官方 Unsloth 笔记本,包含完整代码。

开始之前,请确保您拥有:

  • 一个 Google Colab 账户(免费版即可)
  • Tesla T4 GPU 或更高配置(Colab 上可用)
  • 稳定的互联网连接

1、下载预训练模型

从 Hugging Face 仓库下载完整的 DeepSeek OCR 模型到名为 deepseek_ocr 的本地目录中。

这包括:模型权重、配置文件和分词器

from huggingface_hub import snapshot_download  
snapshot_download("unsloth/DeepSeek-OCR", local_dir = "deepseek_ocr")

⚠️ 注意:根据您的网络速度,下载可能需要几分钟(模型大约 3GB)。

2、加载并配置模型

使用优化的设置将模型加载到内存中以进行训练:

  • load_in_4bit = False: 使用 16 位精度进行更准确的训练(如果内存有限则设为 True
  • trust_remote_code=True: 允许执行 DeepSeek OCR 所需的自定义代码
  • unsloth_force_compile=True: 启用编译时优化以加快训练
  • use_gradient_checkpointing = "unsloth": 使用 Unsloth 的优化梯度检查点以减少内存使用
from unsloth import FastVisionModel  
import torch  
from transformers import AutoModel  
import os  
os.environ["UNSLOTH_WARN_UNINITIALIZED"] = '0'  

model, tokenizer = FastVisionModel.from_pretrained(  
    "./deepseek_ocr",  
    load_in_4bit = False,  
    auto_model = AutoModel,  
    trust_remote_code=True,  
    unsloth_force_compile=True,  
    use_gradient_checkpointing = "unsloth",  
)

输出将显示 GPU 规格和分配的内存。

3、测试基线模型

加载您的训练数据集。这里我们使用 Parsynth OCR,这是一个包含 200,000 个合成波斯语文本图像的数据集。

我们将只加载前 2,000 个示例以加快速度,但您应该使用完整数据集进行完整训练。

from datasets import load_dataset  
dataset = load_dataset("hezarai/parsynth-ocr-200k", split = "train[:2000]")

数据集包括:

  • image_path: 文本图像
  • text: 正确的转录文本
dataset[1523]['image_path'].save("your_image.jpg")

现在保存一个样本图像以测试模型在微调前后的性能。

prompt = "<image>\nFree OCR. "  
image_file = 'your_image.jpg'  
output_path = 'your/output/dir'  

res = model.infer(tokenizer, prompt=prompt, image_file=image_file,  
                  output_path=output_path, base_size=1024, image_size=640,  
                  crop_mode=True, save_results=True, test_compress=False)

这在您的样本图像上测试了微调前的模型:

  • <image> 作为图像占位符
  • base_sizeimage_size 定义处理尺寸
  • crop_mode=True 启用智能裁剪

基线结果:

模型生成了一个具有 字符错误率 (CER) 为 23% 的转录文本,显然有改进空间!

4、添加 LoRA 适配器

使用 参数高效微调 (PEFT) 配置 LoRA (低秩适应)

而不是更新所有 30 亿个参数,LoRA 添加了小的“适配器”层,修改行为的同时只更新 1-2% 的参数。

关键参数:

  • target_modules: 插入适配器的层(查询、键、值投影和 MLP 层)
  • r = 16: 适配器等级(越高 = 更多容量,更多内存)
  • lora_alpha = 16: 缩放因子(通常等于 r
  • lora_dropout = 0: 禁用 dropout 用于短期训练
model = FastVisionModel.get_peft_model(  
    model,  
    target_modules=[  
        "q_proj",  
        "k_proj",  
        "v_proj",  
        "o_proj",  
        "gate_proj",  
        "up_proj",  
        "down_proj",  
    ],  

    r = 16,  
    lora_alpha = 16,  
    lora_dropout = 0,  
    bias = "none",  
    random_state = 3407,  
    use_rslora = False,  
    loftq_config = None,  
    # target_modules = "all-linear", # 可选!如需指定列表  
)

这种方法大大减少了:内存使用(可在消费级 GPU 上训练),训练时间,过拟合风险。

5、准备数据集

将数据集转换为 DeepSeek OCR 所需的对话格式。

每个示例变成一个对话:

  1. 用户回合 -> 包含图像和指令(“Free OCR”)
  2. 助手回合 -> 包含正确的转录文本
instruction = "<image>\nFree OCR. "  

def convert_to_conversation(sample):  
    conversation = [  
        {  
            "role": "<|User|>",  
            "content": instruction,  
            "images": [sample['image']]  
        },  
        {  
            "role": "<|Assistant|>",  
            "content": sample["text"]  
        },  
    ]  
    return {"messages": conversation}  

dataset = load_dataset("hezarai/parsynth-ocr-200k", split = "train[:1000]")  
dataset = dataset.rename_column("image_path", "image")  
converted_dataset = [convert_to_conversation(sample) for sample in dataset]

这种格式使模型能够像对话一样学习任务,使训练更加自然和有效。模型学会“回应”OCR请求,就像一个助手那样。

6、创建数据整理器

@dataclass  
class DeepSeekOCRDataCollator:  
    tokenizer: Any  
    model: Any  
    image_size: int = 640  
    base_size: int = 1024  
    crop_mode: bool = True  
    train_on_responses_only: bool = True

DeepSeekOCRDataCollator 为训练准备数据。它的主要作用包括:

图像预处理

  • 调整图像大小和归一化
  • 应用动态裁剪
  • 创建全局和局部图像裁剪

智能分词

  • 将文本转换为标记
  • 插入图像占位符
  • 构建注意力掩码

掩码

  • train_on_responses_only=True 时,仅训练助手的响应
  • 用户提示被屏蔽(设为 -100)

高效的批处理

  • 将样本组合成带有填充的批次
  • 优雅地处理不同的图像尺寸

7、训练配置

from transformers import Trainer, TrainingArguments  
from unsloth import is_bf16_supported  

FastVisionModel.for_training(model)  

data_collator = DeepSeekOCRDataCollator(  
    tokenizer=tokenizer,  
    model=model,  
    image_size=640,  
    base_size=1024,  
    crop_mode=True,  
    train_on_responses_only=True,  
)  

trainer = Trainer(  
    model=model,  
    tokenizer=tokenizer,  
    data_collator=data_collator,  
    train_dataset=converted_dataset,  
    args=TrainingArguments(  
        per_device_train_batch_size=2,  
        gradient_accumulation_steps=4,  
        warmup_steps=5,  
        max_steps=60,  
        learning_rate=2e-4,  
        logging_steps=1,  
        optim="adamw_8bit",  
        weight_decay=0.001,  
        lr_scheduler_type="linear",  
        seed=3407,  
        fp16=not is_bf16_supported(),  
        bf16=is_bf16_supported(),  
        output_dir="outputs",  
        report_to="none",  
        dataloader_num_workers=2,  
        remove_unused_columns=False,  
    ),  
)

批量参数:

  • per_device_train_batch_size=2: 每个批次 2 个示例(如果内存更多可以增加)
  • gradient_accumulation_steps=4: 在更新权重前累积 4 步的梯度
  • 有效批量 = 2 × 4 = 8 个示例
  • 这模拟了更大的批量而不增加内存使用

优化参数:

  • learning_rate=2e-4: 学习率(0.0002)——相当高以快速收敛
  • warmup_steps=5: 在前 5 步中逐渐增加学习率以提高稳定性
  • optim="adamw_8bit": 量化为 8 位的 AdamW 优化器以节省内存
  • weight_decay=0.001: 正则化以帮助防止过拟合

训练控制:

  • max_steps=60: 在 60 步后停止(快速测试——使用 num_train_epochs=1 进行完整运行)
  • logging_steps=1: 每步记录损失以监控进度

数值精度:

  • 自动使用 bf16 如果支持,否则使用 fp16
  • 这减少了内存使用并加快了训练

8、运行训练

开始实际的训练过程!在执行过程中,您会看到:

  • 显示当前步骤的进度条
  • 每一步的训练损失(应随时间减少)
  • 已用时间和训练速度
trainer_stats = trainer.train()

内部发生什么:

对于每个图像批次:

  • 图像被处理并转换为嵌入
  • 模型生成转录预测
  • 通过比较预测与正确转录来计算损失
  • 计算并累积梯度

gradient_accumulation_steps:

  • 使用 LoRA 适配器更新模型权重
  • 为下一轮零化梯度

学习率根据线性调度逐渐减少

监控:

  • 逐渐下降的损失表明模型正在学习
  • 如果损失停止下降,您可能已经达到了收敛
  • 波动是正常的,尤其是对于小批量

在 Tesla T4 上,这些 60 步大约需要 12-15 分钟。

9、训练后评估

在微调后对同一基准样本图像进行测试。

prompt = "<image>\nFree OCR. "  
image_file = 'your_image.jpg'  
output_path = 'your/output/dir'  

res = model.infer(tokenizer, prompt=prompt, image_file=image_file,  
    output_path=output_path,  
    image_size=640,  
    base_size=1024,  
    crop_mode=True,  
    save_results=True,  
    test_compress=False)

令人印象深刻的结果:

仅经过 60 步,我们显著提高了转录质量。此单个样本的字符错误率 (CER) 从 23% 降至 6%相对减少了 74%

10、保存模型

model.save_pretrained("lora_model")  
tokenizer.save_pretrained("lora_model")

将训练好的 LoRA 适配器保存在 lora_model 目录中。重要:这仅保存适配器,不保存完整的基础模型。保存的文件包括:

  • adapter_config.json: 适配器配置
  • adapter_model.safetensors: 适配器权重(非常小,约 100-200MB)
  • 分词器文件

要以后使用模型,您需要加载基础模型和适配器:

model, tokenizer = FastVisionModel.from_pretrained(  
    model_name="lora_model",  
    load_in_4bit=False,  
    auto_model=AutoModel,  
    trust_remote_code=True,  
)

原文链接:How to Fine-Tune the new DeepSeek OCR model with Unsloth

汇智网翻译整理,转载请标明出处