# 模型加载与字符集管理

> ModelLoader 的 ONNX 模型加载、GPU/CPU 提供者切换，CharsetManager 的字符集加载与范围限制机制

- Repository: sml2h3/ddddocr
- GitHub: https://github.com/sml2h3/ddddocr
- Human wiki: https://grok-wiki.com/public/wiki/sml2h3-ddddocr-10e2eae686bf
- Complete Markdown: https://grok-wiki.com/public/wiki/sml2h3-ddddocr-10e2eae686bf/llms-full.txt

## Source Files

- `ddddocr/models/model_loader.py`
- `ddddocr/models/charset_manager.py`
- `ddddocr/models/__init__.py`
- `ddddocr/utils/validators.py`

---

<details>
<summary>相关源文件</summary>
以下文件用于生成此维基页面：
- [ddddocr/models/model_loader.py](ddddocr/models/model_loader.py)
- [ddddocr/models/charset_manager.py](ddddocr/models/charset_manager.py)
- [ddddocr/models/__init__.py](ddddocr/models/__init__.py)
- [ddddocr/utils/validators.py](ddddocr/utils/validators.py)
- [ddddocr/core/base.py](ddddocr/core/base.py)
- [ddddocr/core/ocr_engine.py](ddddocr/core/ocr_engine.py)
- [ddddocr/utils/exceptions.py](ddddocr/utils/exceptions.py)
</details>

# 模型加载与字符集管理

本文介绍 ddddocr 中两个核心基础设施模块：`ModelLoader`（ONNX 模型加载器）和 `CharsetManager`（字符集管理器）。`ModelLoader` 负责 ONNX Runtime 推理会话的创建与 GPU/CPU 执行提供者的切换；`CharsetManager` 负责字符集的加载、索引映射以及输出字符范围的限制。两者在 `OCREngine` 初始化时协同工作，共同决定 OCR 识别的模型能力和输出字符空间。

## 架构概览

```
┌─────────────────────────────────────────────────┐
│                   OCREngine                      │
│  (core/ocr_engine.py)                            │
│                                                  │
│  ┌──────────────┐     ┌──────────────────┐       │
│  │ ModelLoader  │     │ CharsetManager   │       │
│  │  (via Base)  │     │                  │       │
│  │              │     │  charset[]       │       │
│  │  providers[] │     │  charset_range[] │       │
│  │  session     │     │  valid_indices[] │       │
│  └──────┬───────┘     └────────┬─────────┘       │
│         │                      │                 │
│         ▼                      ▼                 │
│  onnxruntime            CTC decode +             │
│  InferenceSession       charset lookup           │
└─────────────────────────────────────────────────┘
```

`ModelLoader` 和 `CharsetManager` 定义在 `ddddocr/models/` 包中，通过 `models/__init__.py` 统一导出。`BaseEngine`（`core/base.py`）持有 `ModelLoader` 实例，`OCREngine`（`core/ocr_engine.py`）额外持有 `CharsetManager` 实例，并在 `initialize()` 中协调两者的加载流程。

Sources: [ddddocr/models/__init__.py:1-13](), [ddddocr/core/base.py:15-28](), [ddddocr/core/ocr_engine.py:20-47]()

## ModelLoader：ONNX 模型加载

### 类初始化与提供者配置

`ModelLoader.__init__` 接受 `use_gpu` 和 `device_id` 两个参数，构造时立即调用 `_setup_providers()` 配置 ONNX Runtime 的执行提供者列表。

- **GPU 模式**：providers 列表为 `[('CUDAExecutionProvider', {...}), 'CPUExecutionProvider']`。CUDA 提供者配置包括 `device_id`、`arena_extend_strategy: 'kNextPowerOfTwo'`、`gpu_mem_limit: 2GB`、`cudnn_conv_algo_search: 'EXHAUSTIVE'` 和 `do_copy_in_default_stream: True`。
- **CPU 模式**：providers 列表为 `['CPUExecutionProvider']`。
- **回退机制**：如果 GPU 配置过程中抛出异常，自动回退到 CPU 模式并打印警告。

Sources: [ddddocr/models/model_loader.py:19-53]()

### 模型加载方法

| 方法 | 功能 | 说明 |
|------|------|------|
| `load_model(path)` | 通用 ONNX 加载 | 检查文件存在性，设置日志级别为 3，创建 `InferenceSession` |
| `load_ocr_model(old, beta, import_onnx_path)` | 加载 OCR 模型 | 根据 old/beta 标志选择 `common_old.onnx` 或 `common.onnx`，也支持自定义路径 |
| `load_detection_model()` | 加载检测模型 | 加载 `common_det.onnx` |
| `load_custom_model(model_path, charset_path)` | 加载自定义模型+字符集 | 同时加载 ONNX 模型和 JSON 格式的字符集文件 |

`load_custom_model` 会验证字符集 JSON 文件包含 `charset`、`word`、`image`、`channel` 四个必需字段，返回 `(session, charset_info)` 元组。

Sources: [ddddocr/models/model_loader.py:55-204]()

### 模型兼容性验证与设备切换

`validate_model_compatibility` 检查模型输入形状是否与期望匹配（忽略 batch 维度和动态维度 `-1`）。`switch_provider` 允许运行时切换 GPU/CPU，并由 `BaseEngine.switch_device` 调用，在设备变更时触发模型重新加载。

Sources: [ddddocr/models/model_loader.py:206-257](), [ddddocr/core/base.py:79-98]()

## CharsetManager：字符集管理

### 字符集加载

`CharsetManager` 支持两种字符集来源：

1. **内置默认字符集**：通过 `load_default_charset(old, beta)` 加载。旧版（`_get_old_charset`）和 beta 版（`_get_beta_charset`）各包含约 5900+ 个硬编码字符，以空字符串 `""` 作为索引 0（blank token）。默认情况下使用旧版字符集。

2. **自定义字符集文件**：通过 `load_custom_charset(charset_path)` 从 JSON 文件加载。文件必须包含 `charset`（字符列表）、`word`（词级标志）、`image`（图像尺寸配置）、`channel`（通道数）四个字段。

加载字符集后，会自动调用 `_update_valid_indices()` 初始化有效索引。

Sources: [ddddocr/models/charset_manager.py:29-81](), [ddddocr/core/ocr_engine.py:64-92]()

### 字符集范围限制机制

`set_ranges(charset_range)` 是字符集范围限制的核心方法，支持三种参数类型：

| 参数类型 | 行为 | 示例 |
|----------|------|------|
| `int` | 取字符集前 N+1 个字符作为范围 | `set_ranges(9)` → 仅允许索引 0-9 的字符 |
| `str` | 将字符串中每个字符作为允许范围 | `set_ranges("0123456789")` → 仅允许数字 |
| `list` | 直接使用字符列表作为允许范围 | `set_ranges(["你", "好"])` → 仅允许指定字符 |

设置范围后会自动去重并追加空字符串 `""`，然后调用 `_update_valid_indices()` 将范围中的字符映射回字符集中的索引位置。

`_update_valid_indices()` 的工作方式：遍历 `charset_range` 中的每个字符，查找其在完整 `charset` 中的索引，存入 `valid_charset_range_index`。不在字符集中的字符会被忽略。当未设置范围时，`valid_charset_range_index` 包含完整字符集的所有索引。

Sources: [ddddocr/models/charset_manager.py:83-124]()

### 验证层

`validate_charset_range`（`utils/validators.py`）在 `set_ranges` 调用前验证参数合法性：int 必须非负，str 不能为空，list 不能为空且元素必须为字符串。`validate_model_config` 则验证模型配置参数，包括 `old` 和 `beta` 不能同时为 `True`。

Sources: [ddddocr/utils/validators.py:34-80](), [ddddocr/utils/validators.py:140-171]()

## 协同工作流程

在 `OCREngine.initialize()` 中，模型和字符集的加载遵循以下流程：

1. **自定义模型路径**（`import_onnx_path` 非空）：调用 `model_loader.load_custom_model()` 同时加载模型和字符集 JSON，直接设置 `charset_manager.charset` 和模型配置（`word`、`resize`、`channel`）。
2. **默认模型**：先调用 `model_loader.load_ocr_model(old, beta)` 加载 ONNX 模型，再调用 `charset_manager.load_default_charset(old, beta)` 加载对应版本的内置字符集。

在 `predict()` 推理阶段，`charset_range` 通过 `charset_manager.set_ranges()` 设置后，`valid_charset_range_index` 被用于 CTC 解码后的字符过滤——只有索引在有效范围内的字符才会被保留在最终识别结果中。

Sources: [ddddocr/core/ocr_engine.py:56-97](), [ddddocr/core/ocr_engine.py:99-157](), [ddddocr/core/ocr_engine.py:244-298]()

## 异常处理

模型加载和字符集管理过程中产生的异常统一为 `ModelLoadError`（继承自 `DDDDOCRError`）。常见触发场景包括：模型文件不存在、字符集文件缺少必需字段、字符集文件格式错误等。

Sources: [ddddocr/utils/exceptions.py:11-18]()

## 总结

`ModelLoader` 和 `CharsetManager` 是 ddddocr OCR 引擎的两个基础设施模块。`ModelLoader` 封装了 ONNX Runtime 的模型加载和 GPU/CPU 提供者管理，提供统一的模型加载接口和 GPU 回退机制；`CharsetManager` 管理 OCR 输出的字符空间，支持内置和自定义字符集，并通过范围限制机制允许用户约束识别结果的字符集。两者在 `OCREngine` 中协同初始化，并在推理阶段通过 CTC 解码和有效索引过滤共同决定最终的识别输出。
