|
|
@@ -0,0 +1,1380 @@
|
|
|
+```
|
|
|
+zhch158: @workspace 结合/Users/zhch158/workspace/repository.git/PaddleX/dataset/table_rec_dataset_examples目录下的数据集详细说明评估算法,并给出mermaid刘程序,标明各节点间传递的数据
|
|
|
+```
|
|
|
+
|
|
|
+# 表格识别评估算法详细说明
|
|
|
+
|
|
|
+PaddleOCR的表格识别评估主要通过`eval.py`脚本进行,核心评估指标在`table_metric.py`中实现。
|
|
|
+
|
|
|
+### 数据集格式
|
|
|
+基于table_rec_dataset_examples目录,表格识别数据集通常包含:
|
|
|
+- 图像文件(表格图片)
|
|
|
+- 标注文件(HTML结构标注)
|
|
|
+- 边界框标注(可选,用于检测评估)
|
|
|
+
|
|
|
+### 评估指标
|
|
|
+
|
|
|
+1. **结构准确率 (Structure Accuracy)**:预测的HTML结构与真实结构完全匹配的比例
|
|
|
+2. **边界框检测指标**(可选):包括精确度、召回率、F1分数等
|
|
|
+3. **TEDS (Tree-Edit-Distance-based Similarity)**:在README_ch.md中提到的树编辑距离评估
|
|
|
+
|
|
|
+### 评估流程
|
|
|
+
|
|
|
+```mermaid
|
|
|
+graph TD
|
|
|
+ A[开始评估] --> B[加载配置文件]
|
|
|
+ B --> C[构建数据加载器]
|
|
|
+ C --> D[构建后处理器]
|
|
|
+ D --> E[构建模型]
|
|
|
+ E --> F[加载预训练模型]
|
|
|
+ F --> G[构建评估指标]
|
|
|
+ G --> H[开始批量推理]
|
|
|
+
|
|
|
+ H --> I[获取一个batch数据]
|
|
|
+ I --> J{是否有更多数据?}
|
|
|
+ J -->|否| W[计算最终指标]
|
|
|
+ J -->|是| K[模型前向推理]
|
|
|
+
|
|
|
+ K --> L[后处理得到预测结果]
|
|
|
+ L --> M[提取结构序列]
|
|
|
+ M --> N[提取边界框序列]
|
|
|
+
|
|
|
+ N --> O[结构准确率计算]
|
|
|
+ O --> P[边界框检测计算]
|
|
|
+ P --> Q[累计统计信息]
|
|
|
+ Q --> I
|
|
|
+
|
|
|
+ W --> X[输出评估结果]
|
|
|
+ X --> Y[结束]
|
|
|
+
|
|
|
+ subgraph "数据传递详情"
|
|
|
+ I1[batch数据:<br/>- 图像张量<br/>- 结构标签<br/>- 边界框标签]
|
|
|
+ K1[模型输出:<br/>- 结构预测logits<br/>- 边界框预测]
|
|
|
+ L1[后处理结果:<br/>- 结构token序列<br/>- 置信度分数<br/>- 格式化边界框]
|
|
|
+ M1[结构数据:<br/>- pred_structure_batch_list<br/>- gt_structure_batch_list]
|
|
|
+ N1[边界框数据:<br/>- bbox_batch_list<br/>- 格式化坐标]
|
|
|
+ end
|
|
|
+
|
|
|
+ style A fill:#e1f5fe
|
|
|
+ style Y fill:#e8f5e8
|
|
|
+ style O fill:#fff3e0
|
|
|
+ style P fill:#fff3e0
|
|
|
+```
|
|
|
+
|
|
|
+### 详细算法步骤
|
|
|
+
|
|
|
+#### 1. 结构准确率计算(TableStructureMetric)
|
|
|
+
|
|
|
+````python
|
|
|
+def __call__(self, pred_label, batch=None, *args, **kwargs):
|
|
|
+ preds, labels = pred_label
|
|
|
+ pred_structure_batch_list = preds["structure_batch_list"]
|
|
|
+ gt_structure_batch_list = labels["structure_batch_list"]
|
|
|
+
|
|
|
+ for (pred, pred_conf), target in zip(pred_structure_batch_list, gt_structure_batch_list):
|
|
|
+ pred_str = "".join(pred) # 预测的HTML结构字符串
|
|
|
+ target_str = "".join(target) # 真实的HTML结构字符串
|
|
|
+
|
|
|
+ # 可选:移除thead/tbody标签
|
|
|
+ if self.del_thead_tbody:
|
|
|
+ pred_str = pred_str.replace("<thead>", "").replace("</thead>", "")
|
|
|
+ target_str = target_str.replace("<thead>", "").replace("</thead>", "")
|
|
|
+
|
|
|
+ # 完全匹配则计数
|
|
|
+ if pred_str == target_str:
|
|
|
+ correct_num += 1
|
|
|
+ all_num += 1
|
|
|
+````
|
|
|
+
|
|
|
+#### 2. 边界框检测评估(DetMetric)
|
|
|
+
|
|
|
+边界框评估复用检测模块的评估指标,支持多种坐标格式:
|
|
|
+- `xyxy`: 左上角和右下角坐标
|
|
|
+- `xywh`: 中心点和宽高
|
|
|
+- `xyxyxyxy`: 四个顶点坐标
|
|
|
+
|
|
|
+#### 3. 数据流转详情
|
|
|
+
|
|
|
+**输入数据格式:**
|
|
|
+```python
|
|
|
+batch = {
|
|
|
+ 'image': tensor, # 图像张量
|
|
|
+ 'structure_batch_list': [['<html>', '<body>', '<table>', ...], ...], # HTML结构序列
|
|
|
+ 'bbox_batch_list': [[[x1,y1,x2,y2], ...], ...], # 边界框列表
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+**模型输出格式:**
|
|
|
+```python
|
|
|
+preds = {
|
|
|
+ 'structure_batch_list': [(['<html>', '<body>', ...], [0.95, 0.87, ...]), ...], # (结构序列, 置信度)
|
|
|
+ 'bbox_batch_list': [[[x1,y1,x2,y2], ...], ...], # 预测边界框
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+**最终评估结果:**
|
|
|
+```python
|
|
|
+metrics = {
|
|
|
+ 'acc': 0.95, # 结构准确率
|
|
|
+ 'bbox_metric_precision': 0.92, # 边界框精确度(可选)
|
|
|
+ 'bbox_metric_recall': 0.89, # 边界框召回率(可选)
|
|
|
+ 'bbox_metric_hmean': 0.905, # 边界框F1分数(可选)
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 关键特性
|
|
|
+
|
|
|
+1. **支持多种评估模式**:纯结构评估 + 可选的边界框评估
|
|
|
+2. **灵活的标签处理**:可选择是否忽略`<thead>`、`<tbody>`等标签
|
|
|
+3. **批量处理**:支持批量数据的高效评估
|
|
|
+4. **多格式支持**:兼容不同的边界框坐标格式
|
|
|
+
|
|
|
+这种评估算法能够全面衡量表格识别模型在结构理解和空间定位两个维度的性能,为模型优化提供详细的反馈信息。
|
|
|
+
|
|
|
+# 边界框评估算法
|
|
|
+
|
|
|
+## 边界框检测评估算法详解
|
|
|
+```
|
|
|
+@workspace 请详细说明边界框检测算法
|
|
|
+```
|
|
|
+
|
|
|
+### 1. 核心评估类
|
|
|
+
|
|
|
+PaddleOCR使用`DetectionIoUEvaluator`作为核心评估器,主要在`DetMetric`中调用。
|
|
|
+
|
|
|
+### 2. 算法流程
|
|
|
+
|
|
|
+```mermaid
|
|
|
+flowchart TD
|
|
|
+ Start([开始评估]) --> Input[输入数据]
|
|
|
+
|
|
|
+ Input --> BatchLoop{遍历Batch}
|
|
|
+ BatchLoop --> PrepareGT[准备GT数据结构]
|
|
|
+ BatchLoop --> PreparePred[准备预测数据结构]
|
|
|
+
|
|
|
+ PrepareGT --> GTFormat["GT格式化:<br/>points: 多边形坐标<br/>text: 空字符串<br/>ignore: 忽略标签"]
|
|
|
+
|
|
|
+ PreparePred --> PredFormat["预测格式化:<br/>points: 检测框坐标<br/>text: 空字符串<br/>score: 置信度(FCE)"]
|
|
|
+
|
|
|
+ GTFormat --> Evaluate[调用evaluator.evaluate_image]
|
|
|
+ PredFormat --> Evaluate
|
|
|
+
|
|
|
+ Evaluate --> IoUCalc[计算IoU矩阵]
|
|
|
+ IoUCalc --> Match[执行匹配算法]
|
|
|
+ Match --> SingleResult[单图评估结果]
|
|
|
+
|
|
|
+ SingleResult --> StoreResult[存储到results列表]
|
|
|
+ StoreResult --> BatchLoop
|
|
|
+
|
|
|
+ BatchLoop -->|所有batch处理完成| Combine[combine_results合并结果]
|
|
|
+ Combine --> FinalMetrics[最终指标计算]
|
|
|
+
|
|
|
+ FinalMetrics --> Output["输出:<br/>precision: 精确度<br/>recall: 召回率<br/>hmean: 调和平均"]
|
|
|
+ Output --> End([结束])
|
|
|
+
|
|
|
+ classDef inputOutput fill:#e3f2fd
|
|
|
+ classDef process fill:#f3e5f5
|
|
|
+ classDef calculation fill:#fff3e0
|
|
|
+
|
|
|
+ class Start,End,Input,Output inputOutput
|
|
|
+ class PrepareGT,PreparePred,Evaluate,Match process
|
|
|
+ class IoUCalc,Combine,FinalMetrics calculation
|
|
|
+```
|
|
|
+
|
|
|
+### 3. 详细算法实现
|
|
|
+
|
|
|
+#### 3.1 数据预处理
|
|
|
+
|
|
|
+````python
|
|
|
+def __call__(self, preds, batch, **kwargs):
|
|
|
+ gt_polyons_batch = batch[2] # 真实标注多边形
|
|
|
+ ignore_tags_batch = batch[3] # 忽略标签
|
|
|
+
|
|
|
+ for pred, gt_polyons, ignore_tags in zip(preds, gt_polyons_batch, ignore_tags_batch):
|
|
|
+ # 构建GT信息
|
|
|
+ gt_info_list = [
|
|
|
+ {"points": gt_polyon, "text": "", "ignore": ignore_tag}
|
|
|
+ for gt_polyon, ignore_tag in zip(gt_polyons, ignore_tags)
|
|
|
+ ]
|
|
|
+ # 构建检测信息
|
|
|
+ det_info_list = [
|
|
|
+ {"points": det_polyon, "text": ""} for det_polyon in pred["points"]
|
|
|
+ ]
|
|
|
+````
|
|
|
+
|
|
|
+#### 3.2 IoU计算核心算法
|
|
|
+
|
|
|
+````python
|
|
|
+def get_intersection_over_union(pD, pG):
|
|
|
+ """计算两个多边形的IoU"""
|
|
|
+ return get_intersection(pD, pG) / get_union(pD, pG)
|
|
|
+
|
|
|
+def get_intersection(pD, pG):
|
|
|
+ """计算交集面积"""
|
|
|
+ return Polygon(pD).intersection(Polygon(pG)).area
|
|
|
+
|
|
|
+def get_union(pD, pG):
|
|
|
+ """计算并集面积"""
|
|
|
+ return Polygon(pD).union(Polygon(pG)).area
|
|
|
+````
|
|
|
+
|
|
|
+#### 3.3 匹配策略
|
|
|
+
|
|
|
+算法采用**贪心匹配**策略:
|
|
|
+
|
|
|
+````python
|
|
|
+# 构建IoU矩阵
|
|
|
+iouMat = np.empty([len(gtPols), len(detPols)])
|
|
|
+for gtNum in range(len(gtPols)):
|
|
|
+ for detNum in range(len(detPols)):
|
|
|
+ pG = gtPols[gtNum]
|
|
|
+ pD = detPols[detNum]
|
|
|
+ iouMat[gtNum, detNum] = get_intersection_over_union(pD, pG)
|
|
|
+
|
|
|
+# 执行匹配
|
|
|
+for gtNum in range(len(gtPols)):
|
|
|
+ for detNum in range(len(detPols)):
|
|
|
+ if (gtRectMat[gtNum] == 0 and detRectMat[detNum] == 0 and
|
|
|
+ gtNum not in gtDontCarePolsNum and detNum not in detDontCarePolsNum):
|
|
|
+ if iouMat[gtNum, detNum] > self.iou_constraint: # 默认0.5
|
|
|
+ gtRectMat[gtNum] = 1 # 标记GT已匹配
|
|
|
+ detRectMat[detNum] = 1 # 标记检测框已匹配
|
|
|
+ detMatched += 1 # 增加匹配计数
|
|
|
+````
|
|
|
+
|
|
|
+### 4. 评估指标计算
|
|
|
+
|
|
|
+#### 4.1 基础指标
|
|
|
+
|
|
|
+- **Precision (精确度)**: `matched_detections / total_care_detections`
|
|
|
+- **Recall (召回率)**: `matched_detections / total_care_ground_truths`
|
|
|
+- **H-mean (调和平均数)**: `2 * precision * recall / (precision + recall)`
|
|
|
+
|
|
|
+#### 4.2 特殊情况处理
|
|
|
+
|
|
|
+````python
|
|
|
+if numGtCare == 0:
|
|
|
+ recall = float(1)
|
|
|
+ precision = float(0) if numDetCare > 0 else float(1)
|
|
|
+else:
|
|
|
+ recall = float(detMatched) / numGtCare
|
|
|
+ precision = 0 if numDetCare == 0 else float(detMatched) / numDetCare
|
|
|
+
|
|
|
+hmean = (0 if (precision + recall) == 0
|
|
|
+ else 2.0 * precision * recall / (precision + recall))
|
|
|
+````
|
|
|
+
|
|
|
+### 5. Don't Care区域处理
|
|
|
+
|
|
|
+算法支持忽略特定区域的评估:
|
|
|
+
|
|
|
+````python
|
|
|
+# 标记GT中的don't care区域
|
|
|
+if dontCare:
|
|
|
+ gtDontCarePolsNum.append(len(gtPols) - 1)
|
|
|
+
|
|
|
+# 检测框与don't care区域的重叠处理
|
|
|
+for dontCarePol in gtDontCarePolsNum:
|
|
|
+ intersected_area = get_intersection(dontCarePol, detPol)
|
|
|
+ pdDimensions = Polygon(detPol).area
|
|
|
+ precision = (0 if pdDimensions == 0 else intersected_area / pdDimensions)
|
|
|
+ if precision > self.area_precision_constraint: # 默认0.5
|
|
|
+ detDontCarePolsNum.append(len(detPols) - 1)
|
|
|
+````
|
|
|
+
|
|
|
+### 6. 多阈值评估 (DetFCEMetric)
|
|
|
+
|
|
|
+对于FCE模型,支持多个置信度阈值的评估:
|
|
|
+
|
|
|
+````python
|
|
|
+class DetFCEMetric(object):
|
|
|
+ def reset(self):
|
|
|
+ self.results = {0.3: [], 0.4: [], 0.5: [], 0.6: [], 0.7: [], 0.8: [], 0.9: []}
|
|
|
+
|
|
|
+ def __call__(self, preds, batch, **kwargs):
|
|
|
+ for score_thr in self.results.keys():
|
|
|
+ det_info_list_thr = [
|
|
|
+ det_info for det_info in det_info_list
|
|
|
+ if det_info["score"] >= score_thr
|
|
|
+ ]
|
|
|
+ result = self.evaluator.evaluate_image(gt_info_list, det_info_list_thr)
|
|
|
+ self.results[score_thr].append(result)
|
|
|
+````
|
|
|
+
|
|
|
+### 7. 算法特点
|
|
|
+
|
|
|
+1. **多边形支持**: 支持任意多边形检测框,不限于矩形
|
|
|
+2. **严格匹配**: 采用一对一匹配,避免重复计算
|
|
|
+3. **IoU阈值**: 默认0.5,可配置
|
|
|
+4. **忽略区域**: 支持don't care标注
|
|
|
+5. **鲁棒性**: 处理无效多边形和边界情况
|
|
|
+
|
|
|
+### 8. 与通用目标检测的差异
|
|
|
+
|
|
|
+- **多边形vs矩形**: 文本检测通常使用四边形而非轴对齐矩形
|
|
|
+- **密集场景**: 文本区域通常更密集,需要更精确的匹配策略
|
|
|
+- **形状敏感**: 文本的几何形状对识别影响更大
|
|
|
+
|
|
|
+这套算法已在ICDAR等国际文本检测竞赛中验证,能够准确评估各种文本检测模型的性能。
|
|
|
+
|
|
|
+# KIE说明
|
|
|
+
|
|
|
+## KIEMetric算法详解
|
|
|
+
|
|
|
+### 1. 算法概述
|
|
|
+
|
|
|
+`KIEMetric`是PaddleOCR中专门用于**关键信息抽取(Key Information Extraction, KIE)**任务的评估指标类,主要通过计算F1分数来评估模型性能。
|
|
|
+
|
|
|
+### 2. 应用场景
|
|
|
+
|
|
|
+KIEMetric主要用于以下KIE算法的评估:
|
|
|
+
|
|
|
+#### 2.1 支持的KIE算法
|
|
|
+- **VI-LayoutXLM**: 参考VI-LayoutXLM算法文档
|
|
|
+- **LayoutXLM**: 参考LayoutXLM算法文档
|
|
|
+- **SDMGR**: 参考SDMGR算法文档
|
|
|
+
|
|
|
+#### 2.2 KIE任务类型
|
|
|
+- **SER (Semantic Entity Recognition)**: 语义实体识别
|
|
|
+- **RE (Relation Extraction)**: 关系抽取
|
|
|
+
|
|
|
+### 3. 算法核心机制
|
|
|
+
|
|
|
+#### 3.1 数据处理流程
|
|
|
+
|
|
|
+```python
|
|
|
+def __call__(self, preds, batch, **kwargs):
|
|
|
+ nodes, _ = preds # 模型预测结果
|
|
|
+ gts, tag = batch[4].squeeze(0), batch[5].tolist()[0] # 真实标签
|
|
|
+ gts = gts[: tag[0], :1].reshape([-1]) # 有效标签截取
|
|
|
+ self.node.append(nodes.numpy()) # 累积预测结果
|
|
|
+ self.gt.append(gts) # 累积真实标签
|
|
|
+```
|
|
|
+
|
|
|
+#### 3.2 F1分数计算
|
|
|
+
|
|
|
+```python
|
|
|
+def compute_f1_score(self, preds, gts):
|
|
|
+ ignores = [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 25] # 忽略的类别
|
|
|
+ C = preds.shape[1] # 类别总数
|
|
|
+ classes = np.array(sorted(set(range(C)) - set(ignores))) # 有效类别
|
|
|
+
|
|
|
+ # 构建混淆矩阵
|
|
|
+ hist = (np.bincount((gts * C).astype("int64") + preds.argmax(1), minlength=C**2)
|
|
|
+ .reshape([C, C]).astype("float32"))
|
|
|
+
|
|
|
+ # 计算各类别的precision、recall、F1
|
|
|
+ diag = np.diag(hist)
|
|
|
+ recalls = diag / hist.sum(1).clip(min=1)
|
|
|
+ precisions = diag / hist.sum(0).clip(min=1)
|
|
|
+ f1 = 2 * recalls * precisions / (recalls + precisions).clip(min=1e-8)
|
|
|
+
|
|
|
+ return f1[classes] # 返回有效类别的F1分数
|
|
|
+```
|
|
|
+
|
|
|
+### 4. 评估指标
|
|
|
+
|
|
|
+#### 4.1 主要指标
|
|
|
+- **H-mean**: 所有有效类别F1分数的调和平均数
|
|
|
+- **类别级F1**: 每个实体类别的F1分数
|
|
|
+
|
|
|
+#### 4.2 在XFUND数据集上的表现
|
|
|
+
|
|
|
+根据文档显示,在XFUND_zh数据集上:
|
|
|
+
|
|
|
+| 模型 | 任务 | H-mean |
|
|
|
+|------|------|--------|
|
|
|
+| VI-LayoutXLM | SER | 93.19% |
|
|
|
+| VI-LayoutXLM | RE | 83.92% |
|
|
|
+| LayoutXLM | SER | 90.38% |
|
|
|
+| LayoutXLM | RE | 74.83% |
|
|
|
+
|
|
|
+### 5. 使用示例
|
|
|
+
|
|
|
+#### 5.1 模型评估命令
|
|
|
+
|
|
|
+```bash
|
|
|
+# VI-LayoutXLM SER评估
|
|
|
+python3 tools/eval.py -c configs/kie/vi_layoutxlm/ser_vi_layoutxlm_xfund_zh.yml \
|
|
|
+ -o Architecture.Backbone.checkpoints=./output/ser_vi_layoutxlm_xfund_zh/best_accuracy
|
|
|
+```
|
|
|
+
|
|
|
+#### 5.2 评估输出示例
|
|
|
+
|
|
|
+```bash
|
|
|
+[2022/08/10 05:22:23] ppocr INFO: metric eval ***************
|
|
|
+[2022/08/10 05:22:23] ppocr INFO: hmean:0.8670120239257812
|
|
|
+[2022/08/10 05:22:23] ppocr INFO: fps:10.18816520530961
|
|
|
+```
|
|
|
+
|
|
|
+### 6. 算法特点
|
|
|
+
|
|
|
+#### 6.1 类别过滤机制
|
|
|
+- 忽略特定类别(如背景、填充等)
|
|
|
+- 只计算有意义的实体类别的F1分数
|
|
|
+
|
|
|
+#### 6.2 批量累积评估
|
|
|
+- 支持多批次数据的累积评估
|
|
|
+- 最终统一计算整体指标
|
|
|
+
|
|
|
+#### 6.3 标签动态截取
|
|
|
+- 根据`tag`信息动态截取有效标签长度
|
|
|
+- 避免填充标签影响评估结果
|
|
|
+
|
|
|
+### 7. 应用场景举例
|
|
|
+
|
|
|
+#### 7.1 文档信息抽取
|
|
|
+- **发票信息抽取**: 提取发票号、金额、日期等关键信息
|
|
|
+- **身份证信息抽取**: 提取姓名、身份证号、地址等
|
|
|
+- **表单信息抽取**: 提取表单中的各类字段信息
|
|
|
+
|
|
|
+#### 7.2 数据要求
|
|
|
+根据KIE使用指南,一般来说:
|
|
|
+- **训练数据量**: 对于固定场景,50张左右的训练图片即可达到可接受效果
|
|
|
+- **标注工具**: 推荐使用[PPOCRLabel](https://github.com/PFCCLab/PPOCRLabel/blob/main/README_ch.md)完成KIE标注
|
|
|
+
|
|
|
+KIEMetric作为KIE任务的核心评估工具,为模型性能提供了标准化、可靠的评估机制,是PaddleOCR文档理解能力的重要组成部分。
|
|
|
+
|
|
|
+# RecMetric说明
|
|
|
+
|
|
|
+## RecMetric算法详解
|
|
|
+
|
|
|
+### 1. 算法概述
|
|
|
+
|
|
|
+`RecMetric`是PaddleOCR中专门用于**文本识别(Text Recognition)**任务的评估指标类,通过计算准确率和编辑距离来评估模型性能。
|
|
|
+
|
|
|
+### 2. 应用场景
|
|
|
+
|
|
|
+RecMetric主要用于以下文本识别算法的评估:
|
|
|
+
|
|
|
+#### 2.1 支持的文本识别算法
|
|
|
+根据文档显示,RecMetric广泛应用于:
|
|
|
+
|
|
|
+**基础识别算法:**
|
|
|
+- **CRNN**: 参考CRNN算法文档
|
|
|
+- **RARE**: 参考RARE算法文档
|
|
|
+- **StarNet**: 参考StarNet算法文档
|
|
|
+- **Rosetta**: 参考Rosetta算法文档
|
|
|
+
|
|
|
+**高级识别算法:**
|
|
|
+- **NRTR**: 参考NRTR算法文档
|
|
|
+- **SAR**: 参考SAR算法文档
|
|
|
+- **SRN**: 参考SRN算法文档
|
|
|
+- **RFL**: 参考RFL算法文档
|
|
|
+- **ParseQ**: 参考ParseQ算法文档
|
|
|
+- **CPPD**: 参考CPPD算法文档
|
|
|
+
|
|
|
+### 3. 核心算法机制
|
|
|
+
|
|
|
+#### 3.1 主要评估指标
|
|
|
+
|
|
|
+```python
|
|
|
+def __call__(self, pred_label, *args, **kwargs):
|
|
|
+ preds, labels = pred_label
|
|
|
+ correct_num = 0
|
|
|
+ all_num = 0
|
|
|
+ norm_edit_dis = 0.0
|
|
|
+
|
|
|
+ for (pred, pred_conf), (target, _) in zip(preds, labels):
|
|
|
+ # 文本预处理
|
|
|
+ if self.ignore_space:
|
|
|
+ pred = pred.replace(" ", "")
|
|
|
+ target = target.replace(" ", "")
|
|
|
+ if self.is_filter:
|
|
|
+ pred = self._normalize_text(pred)
|
|
|
+ target = self._normalize_text(target)
|
|
|
+
|
|
|
+ # 计算编辑距离
|
|
|
+ norm_edit_dis += Levenshtein.normalized_distance(pred, target)
|
|
|
+
|
|
|
+ # 计算精确匹配
|
|
|
+ if pred == target:
|
|
|
+ correct_num += 1
|
|
|
+ all_num += 1
|
|
|
+```
|
|
|
+
|
|
|
+#### 3.2 核心评估指标
|
|
|
+
|
|
|
+**1. 准确率 (Accuracy)**
|
|
|
+- **计算方式**: `acc = correct_num / total_num`
|
|
|
+- **含义**: 完全正确识别的样本比例
|
|
|
+
|
|
|
+**2. 归一化编辑距离 (Normalized Edit Distance)**
|
|
|
+- **计算方式**: `norm_edit_dis = 1 - total_edit_distance / total_num`
|
|
|
+- **含义**: 基于Levenshtein距离的相似度指标
|
|
|
+- **范围**: [0, 1],值越大表示识别效果越好
|
|
|
+
|
|
|
+#### 3.3 文本预处理机制
|
|
|
+
|
|
|
+```python
|
|
|
+def _normalize_text(self, text):
|
|
|
+ text = "".join(
|
|
|
+ filter(lambda x: x in (string.digits + string.ascii_letters), text)
|
|
|
+ )
|
|
|
+ return text.lower()
|
|
|
+```
|
|
|
+
|
|
|
+**预处理选项:**
|
|
|
+- `ignore_space`: 忽略空格字符
|
|
|
+- `is_filter`: 只保留数字和字母,转为小写
|
|
|
+
|
|
|
+### 4. 典型性能表现
|
|
|
+
|
|
|
+根据算法概览文档,各算法在标准数据集上的表现:
|
|
|
+
|
|
|
+| 算法 | 骨干网络 | 准确率 | 配置文件 |
|
|
|
+|------|----------|--------|----------|
|
|
|
+| CRNN | Resnet34_vd | 81.04% | rec_r34_vd_none_bilstm_ctc |
|
|
|
+| RARE | Resnet34_vd | 83.98% | rec_r34_vd_tps_bilstm_att |
|
|
|
+| StarNet | Resnet34_vd | 84.44% | rec_r34_vd_tps_bilstm_ctc |
|
|
|
+| NRTR | MTB | 84.21% | rec_mtb_nrtr |
|
|
|
+| RFL | ResNetRFL | 88.63% | rec_resnet_rfl_att |
|
|
|
+| ParseQ | VIT | 91.24% | rec_vit_parseq_synth |
|
|
|
+
|
|
|
+### 5. 使用示例
|
|
|
+
|
|
|
+#### 5.1 评估命令示例
|
|
|
+
|
|
|
+```bash
|
|
|
+# CRNN模型评估
|
|
|
+python3 tools/eval.py -c configs/rec/rec_r34_vd_none_bilstm_ctc.yml \
|
|
|
+ -o Global.pretrained_model=./rec_r34_vd_none_bilstm_ctc_v2.0_train/best_accuracy
|
|
|
+
|
|
|
+# NRTR模型评估
|
|
|
+python3 tools/eval.py -c configs/rec/rec_mtb_nrtr.yml \
|
|
|
+ -o Global.pretrained_model=./rec_mtb_nrtr_train/best_accuracy
|
|
|
+```
|
|
|
+
|
|
|
+#### 5.2 评估输出示例
|
|
|
+
|
|
|
+```bash
|
|
|
+[2022/08/10 05:22:23] ppocr INFO: metric eval ***************
|
|
|
+[2022/08/10 05:22:23] ppocr INFO: acc: 0.8563
|
|
|
+[2022/08/10 05:22:23] ppocr INFO: norm_edit_dis: 0.9124
|
|
|
+[2022/08/10 05:22:23] ppocr INFO: fps: 156.25
|
|
|
+```
|
|
|
+
|
|
|
+### 6. 算法特点
|
|
|
+
|
|
|
+#### 6.1 灵活的文本处理
|
|
|
+- 支持空格忽略
|
|
|
+- 支持字符过滤和标准化
|
|
|
+- 适应不同语言和字符集
|
|
|
+
|
|
|
+#### 6.2 双重评估机制
|
|
|
+- **严格评估**: 完全匹配的准确率
|
|
|
+- **宽松评估**: 基于编辑距离的相似度
|
|
|
+
|
|
|
+#### 6.3 批量累积统计
|
|
|
+- 支持多批次数据的累积评估
|
|
|
+- 提供实时和最终评估结果
|
|
|
+
|
|
|
+### 7. 应用场景举例
|
|
|
+
|
|
|
+#### 7.1 场景文本识别
|
|
|
+- **自然场景**: 街景、广告牌、标识等文本识别
|
|
|
+- **文档识别**: 扫描文档、票据、表单等
|
|
|
+- **验证码识别**: 网站验证码、安全码等
|
|
|
+
|
|
|
+#### 7.2 多语言文本识别
|
|
|
+- **英文识别**: 基于MJSynth和SynthText训练
|
|
|
+- **中文识别**: 支持中文字符识别评估
|
|
|
+- **多语言**: 支持各种语言的文本识别评估
|
|
|
+
|
|
|
+#### 7.3 不同复杂度场景
|
|
|
+根据CPPD算法文档显示的评估结果:
|
|
|
+
|
|
|
+| 场景类型 | CPPD Base准确率 |
|
|
|
+|----------|----------------|
|
|
|
+| 一般场景 | 97.44% |
|
|
|
+| 弯曲文本 | 74.4% |
|
|
|
+| 多方向文本 | 76.1% |
|
|
|
+| 艺术字体 | 98.6% |
|
|
|
+| 无上下文 | 55.3% |
|
|
|
+
|
|
|
+### 8. 与其他评估指标的关系
|
|
|
+
|
|
|
+在PaddleOCR中,除了RecMetric外,还有:
|
|
|
+- `CANMetric`: 专用于手写公式识别
|
|
|
+- `LaTeXOCRMetric`: 专用于LaTeX公式识别
|
|
|
+- `CNTMetric`: 简化版的计数评估
|
|
|
+
|
|
|
+RecMetric作为通用文本识别评估工具,为各种文本识别算法提供了标准化、可靠的性能评估机制,是PaddleOCR文本识别能力评估的核心组件。
|
|
|
+
|
|
|
+## Levenshtein算法详解
|
|
|
+```
|
|
|
+详细说明RecMetric引用的Levenshtein算法
|
|
|
+```
|
|
|
+
|
|
|
+### 1. 算法概述
|
|
|
+
|
|
|
+Levenshtein距离(编辑距离)是衡量两个字符串相似度的重要算法,在PaddleOCR的RecMetric中通过`rapidfuzz.distance.Levenshtein`库实现。
|
|
|
+
|
|
|
+### 2. 在RecMetric中的应用
|
|
|
+
|
|
|
+#### 2.1 核心使用位置
|
|
|
+
|
|
|
+````python
|
|
|
+from rapidfuzz.distance import Levenshtein
|
|
|
+
|
|
|
+def __call__(self, pred_label, *args, **kwargs):
|
|
|
+ for (pred, pred_conf), (target, _) in zip(preds, labels):
|
|
|
+ # 文本预处理
|
|
|
+ if self.ignore_space:
|
|
|
+ pred = pred.replace(" ", "")
|
|
|
+ target = target.replace(" ", "")
|
|
|
+ if self.is_filter:
|
|
|
+ pred = self._normalize_text(pred)
|
|
|
+ target = self._normalize_text(target)
|
|
|
+
|
|
|
+ # 计算归一化编辑距离
|
|
|
+ norm_edit_dis += Levenshtein.normalized_distance(pred, target)
|
|
|
+````
|
|
|
+
|
|
|
+### 3. Levenshtein算法原理
|
|
|
+
|
|
|
+#### 3.1 基本定义
|
|
|
+
|
|
|
+Levenshtein距离是指两个字符串之间,由一个转换成另一个所需的**最少编辑操作次数**。
|
|
|
+
|
|
|
+**允许的编辑操作:**
|
|
|
+- **插入** (Insertion): 在字符串中插入一个字符
|
|
|
+- **删除** (Deletion): 从字符串中删除一个字符
|
|
|
+- **替换** (Substitution): 将字符串中的一个字符替换为另一个字符
|
|
|
+
|
|
|
+#### 3.2 动态规划算法
|
|
|
+
|
|
|
+```python
|
|
|
+def levenshtein_distance(s1, s2):
|
|
|
+ """计算两个字符串的Levenshtein距离"""
|
|
|
+ m, n = len(s1), len(s2)
|
|
|
+
|
|
|
+ # 创建DP表
|
|
|
+ dp = [[0] * (n + 1) for _ in range(m + 1)]
|
|
|
+
|
|
|
+ # 初始化边界条件
|
|
|
+ for i in range(m + 1):
|
|
|
+ dp[i][0] = i # 删除s1中的i个字符
|
|
|
+ for j in range(n + 1):
|
|
|
+ dp[0][j] = j # 插入s2中的j个字符
|
|
|
+
|
|
|
+ # 填充DP表
|
|
|
+ for i in range(1, m + 1):
|
|
|
+ for j in range(1, n + 1):
|
|
|
+ if s1[i-1] == s2[j-1]:
|
|
|
+ dp[i][j] = dp[i-1][j-1] # 字符相同,无需操作
|
|
|
+ else:
|
|
|
+ dp[i][j] = 1 + min(
|
|
|
+ dp[i-1][j], # 删除s1[i-1]
|
|
|
+ dp[i][j-1], # 插入s2[j-1]
|
|
|
+ dp[i-1][j-1] # 替换s1[i-1]为s2[j-1]
|
|
|
+ )
|
|
|
+
|
|
|
+ return dp[m][n]
|
|
|
+
|
|
|
+def normalized_distance(s1, s2):
|
|
|
+ """计算归一化编辑距离"""
|
|
|
+ distance = levenshtein_distance(s1, s2)
|
|
|
+ max_len = max(len(s1), len(s2))
|
|
|
+ return distance / max_len if max_len > 0 else 0.0
|
|
|
+```
|
|
|
+
|
|
|
+### 4. 算法示例演示
|
|
|
+
|
|
|
+#### 4.1 具体计算过程
|
|
|
+
|
|
|
+**示例:** 计算 "kitten" 和 "sitting" 的编辑距离
|
|
|
+
|
|
|
+```
|
|
|
+ "" s i t t i n g
|
|
|
+"" 0 1 2 3 4 5 6 7
|
|
|
+k 1 1 2 3 4 5 6 7
|
|
|
+i 2 2 1 2 3 4 5 6
|
|
|
+t 3 3 2 1 2 3 4 5
|
|
|
+t 4 4 3 2 1 2 3 4
|
|
|
+e 5 5 4 3 2 2 3 4
|
|
|
+n 6 6 5 4 3 3 2 3
|
|
|
+```
|
|
|
+
|
|
|
+**编辑操作序列:**
|
|
|
+1. k → s (替换)
|
|
|
+2. i → i (无操作)
|
|
|
+3. t → t (无操作)
|
|
|
+4. t → t (无操作)
|
|
|
+5. e → i (替换)
|
|
|
+6. n → n (无操作)
|
|
|
+7. 插入 g
|
|
|
+
|
|
|
+**结果:** 编辑距离 = 3,归一化距离 = 3/7 ≈ 0.429
|
|
|
+
|
|
|
+### 5. 在不同Metric中的应用
|
|
|
+
|
|
|
+#### 5.1 RecMetric中的应用
|
|
|
+
|
|
|
+````python
|
|
|
+# 基础文本识别评估
|
|
|
+norm_edit_dis += Levenshtein.normalized_distance(pred, target)
|
|
|
+final_score = 1 - norm_edit_dis / (all_num + self.eps) # 转换为相似度分数
|
|
|
+````
|
|
|
+
|
|
|
+#### 5.2 LaTeXOCRMetric中的应用
|
|
|
+
|
|
|
+````python
|
|
|
+# LaTeX公式识别评估
|
|
|
+lev_dist.append(Levenshtein.normalized_distance(prediction, labels))
|
|
|
+self.edit_dist = sum(lev_dist) # 累积编辑距离
|
|
|
+cur_edit_distance = sum(self.edit_right) / self.exp_total_num
|
|
|
+````
|
|
|
+
|
|
|
+### 6. 性能优化特性
|
|
|
+
|
|
|
+#### 6.1 RapidFuzz库优势
|
|
|
+
|
|
|
+PaddleOCR使用[`rapidfuzz`](https://github.com/maxbachmann/RapidFuzz)库而非标准库:
|
|
|
+
|
|
|
+- **高性能**: C++实现,比纯Python快10-100倍
|
|
|
+- **内存优化**: 针对大量文本比较进行了优化
|
|
|
+- **多种距离算法**: 支持多种字符串相似度算法
|
|
|
+
|
|
|
+#### 6.2 复杂度分析
|
|
|
+
|
|
|
+- **时间复杂度**: O(m×n),其中m和n是两个字符串的长度
|
|
|
+- **空间复杂度**: O(m×n),可优化为O(min(m,n))
|
|
|
+
|
|
|
+### 7. 文本识别场景中的意义
|
|
|
+
|
|
|
+#### 7.1 评估指标含义
|
|
|
+
|
|
|
+**归一化编辑距离 (norm_edit_dis)**:
|
|
|
+- **范围**: [0, 1]
|
|
|
+- **0**: 完全不同
|
|
|
+- **1**: 完全相同
|
|
|
+- **意义**: 即使不完全匹配,也能量化相似程度
|
|
|
+
|
|
|
+#### 7.2 实际应用效果
|
|
|
+
|
|
|
+```python
|
|
|
+# 示例评估结果
|
|
|
+predictions = ["hello", "wrold", "paddle"]
|
|
|
+targets = ["hello", "world", "paddle"]
|
|
|
+
|
|
|
+# 计算结果:
|
|
|
+# "hello" vs "hello": distance=0, normalized=0, similarity=1.0
|
|
|
+# "wrold" vs "world": distance=2, normalized=0.4, similarity=0.6
|
|
|
+# "paddle" vs "paddle": distance=0, normalized=0, similarity=1.0
|
|
|
+#
|
|
|
+# 平均相似度 = (1.0 + 0.6 + 1.0) / 3 = 0.867
|
|
|
+```
|
|
|
+
|
|
|
+### 8. 与其他相似度算法的比较
|
|
|
+
|
|
|
+| 算法 | 特点 | 应用场景 |
|
|
|
+|------|------|----------|
|
|
|
+| **Levenshtein** | 考虑插入、删除、替换 | 通用文本相似度 |
|
|
|
+| **Jaro-Winkler** | 重视字符串开头的匹配 | 姓名匹配 |
|
|
|
+| **Cosine** | 基于向量空间 | 文档相似度 |
|
|
|
+| **BLEU** | N-gram匹配 | 机器翻译评估 |
|
|
|
+
|
|
|
+### 9. 在PaddleOCR中的优势
|
|
|
+
|
|
|
+1. **鲁棒性**: 对于部分错误识别仍能给出合理评分
|
|
|
+2. **标准化**: 提供业界标准的文本相似度评估
|
|
|
+3. **实时性**: 高效计算支持大规模评估
|
|
|
+4. **可解释性**: 编辑距离直观反映识别错误程度
|
|
|
+
|
|
|
+Levenshtein算法在RecMetric中提供了比简单准确率更细粒度的评估能力,能够更好地反映文本识别模型的真实性能水平。
|
|
|
+
|
|
|
+# CTMetric说明
|
|
|
+
|
|
|
+## CTMetric算法详解
|
|
|
+
|
|
|
+### 1. 算法概述
|
|
|
+
|
|
|
+`CTMetric`是PaddleOCR中专门用于**CentripetalText (CT)文本检测算法**评估的指标类。CT是一种高效的场景文本检测方法,CTMetric用于评估其检测性能。
|
|
|
+
|
|
|
+### 2. 应用场景
|
|
|
+
|
|
|
+#### 2.1 CT算法简介
|
|
|
+根据CT算法文档:
|
|
|
+
|
|
|
+**论文信息:**
|
|
|
+> [CentripetalText: An Efficient Text Instance Representation for Scene Text Detection](https://arxiv.org/abs/2107.05945)
|
|
|
+> Tao Sheng, Jie Chen, Zhouhui Lian
|
|
|
+> NeurIPS, 2021
|
|
|
+
|
|
|
+**性能表现:**
|
|
|
+在Total-Text文本检测公开数据集上:
|
|
|
+
|
|
|
+| 模型 | 骨干网络 | 配置文件 | Precision | Recall | Hmean | 下载链接 |
|
|
|
+|------|----------|----------|-----------|--------|-------|----------|
|
|
|
+| CT | ResNet18_vd | det_r18_vd_ct.yml | 88.68% | 81.70% | 85.05% | [训练模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/en/det_r18_ct_train.tar) |
|
|
|
+
|
|
|
+### 3. 核心算法机制
|
|
|
+
|
|
|
+#### 3.1 评估流程
|
|
|
+
|
|
|
+```python
|
|
|
+def __call__(self, preds, batch, **kwargs):
|
|
|
+ # 注意:目前只支持batch_size=1,因为不同样本的标签长度不等
|
|
|
+ assert len(preds) == 1, "CentripetalText test now only support batch_size=1."
|
|
|
+
|
|
|
+ label = batch[2] # 真实标注信息
|
|
|
+ text = batch[3] # 真实文本内容
|
|
|
+ pred = preds[0]["points"] # 预测的检测框点坐标
|
|
|
+
|
|
|
+ # 计算CT特定的评估分数
|
|
|
+ result = get_score_C(label, text, pred)
|
|
|
+ self.results.append(result)
|
|
|
+```
|
|
|
+
|
|
|
+#### 3.2 CT特定评估方法
|
|
|
+
|
|
|
+根据`get_score_C`函数实现,CT算法使用特殊的评估方式:
|
|
|
+
|
|
|
+```python
|
|
|
+def get_score_C(gt_label, text, pred_bboxes):
|
|
|
+ """
|
|
|
+ get score for CentripetalText (CT) prediction.
|
|
|
+ """
|
|
|
+ # 处理预测结果
|
|
|
+ detections = []
|
|
|
+ for item in pred_bboxes:
|
|
|
+ detections.append(item[:, ::-1].reshape(-1))
|
|
|
+
|
|
|
+ # 读取真实标注
|
|
|
+ groundtruths = gt_reading_mod(gt_label, text)
|
|
|
+
|
|
|
+ # 过滤检测结果
|
|
|
+ detections = detection_filtering(detections, groundtruths)
|
|
|
+
|
|
|
+ # 计算sigma和tau指标
|
|
|
+ local_sigma_table = np.zeros((len(groundtruths), len(detections)))
|
|
|
+ local_tau_table = np.zeros((len(groundtruths), len(detections)))
|
|
|
+
|
|
|
+ for gt_id, gt in enumerate(groundtruths):
|
|
|
+ for det_id, detection in enumerate(detections):
|
|
|
+ # sigma = 交集面积 / GT面积
|
|
|
+ local_sigma_table[gt_id, det_id] = sigma_calculation(det_p, gt_p)
|
|
|
+ # tau = 交集面积 / 检测面积
|
|
|
+ local_tau_table[gt_id, det_id] = tau_calculation(det_p, gt_p)
|
|
|
+```
|
|
|
+
|
|
|
+#### 3.3 关键评估指标
|
|
|
+
|
|
|
+**1. Sigma计算**
|
|
|
+```python
|
|
|
+def sigma_calculation(det_p, gt_p):
|
|
|
+ """
|
|
|
+ sigma = inter_area / gt_area
|
|
|
+ """
|
|
|
+ if gt_p.area() == 0.0:
|
|
|
+ return 0
|
|
|
+ return get_intersection(det_p, gt_p) / gt_p.area()
|
|
|
+```
|
|
|
+
|
|
|
+**2. Tau计算**
|
|
|
+```python
|
|
|
+def tau_calculation(det_p, gt_p):
|
|
|
+ """
|
|
|
+ tau = inter_area / det_area
|
|
|
+ """
|
|
|
+ if det_p.area() == 0.0:
|
|
|
+ return 0
|
|
|
+ return get_intersection(det_p, gt_p) / det_p.area()
|
|
|
+```
|
|
|
+
|
|
|
+### 4. 后处理机制
|
|
|
+
|
|
|
+CT算法配合专门的后处理类`CTPostProcess`:
|
|
|
+
|
|
|
+```python
|
|
|
+class CTPostProcess(object):
|
|
|
+ """
|
|
|
+ The post process for Centripetal Text (CT).
|
|
|
+ """
|
|
|
+ def __init__(self, min_score=0.88, min_area=16, box_type="poly", **kwargs):
|
|
|
+ self.min_score = min_score # 最小置信度阈值
|
|
|
+ self.min_area = min_area # 最小区域面积
|
|
|
+ self.box_type = box_type # 输出框类型:rect/poly
|
|
|
+```
|
|
|
+
|
|
|
+### 5. 使用示例
|
|
|
+
|
|
|
+#### 5.1 模型训练
|
|
|
+```bash
|
|
|
+# CT模型训练
|
|
|
+python3 tools/train.py -c configs/det/det_r18_vd_ct.yml
|
|
|
+```
|
|
|
+
|
|
|
+#### 5.2 模型评估
|
|
|
+```bash
|
|
|
+# CT模型评估
|
|
|
+python3 tools/eval.py -c configs/det/det_r18_vd_ct.yml \
|
|
|
+ -o Global.pretrained_model=./det_r18_ct_train/best_accuracy
|
|
|
+```
|
|
|
+
|
|
|
+#### 5.3 模型推理
|
|
|
+```bash
|
|
|
+# CT模型推理
|
|
|
+python3 tools/infer_det.py -c configs/det/det_r18_vd_ct.yml \
|
|
|
+ -o Global.pretrained_model=./inference/det_ct/inference.pdmodel \
|
|
|
+ Global.infer_img=./doc/imgs_en/img_10.jpg
|
|
|
+```
|
|
|
+
|
|
|
+### 6. 算法特点
|
|
|
+
|
|
|
+#### 6.1 CT算法优势
|
|
|
+- **高效表示**: 使用向心力文本表示方法
|
|
|
+- **任意形状**: 支持弯曲、倾斜等复杂文本检测
|
|
|
+- **端到端**: 统一的检测和识别框架
|
|
|
+
|
|
|
+#### 6.2 评估特点
|
|
|
+- **专用指标**: 使用sigma和tau指标评估重叠度
|
|
|
+- **批量限制**: 目前只支持batch_size=1的评估
|
|
|
+- **多边形支持**: 支持任意多边形检测框评估
|
|
|
+
|
|
|
+### 7. 与其他检测算法的对比
|
|
|
+
|
|
|
+| 算法 | 骨干网络 | CTW1500数据集 | 特点 |
|
|
|
+|------|----------|---------------|------|
|
|
|
+| FCE | ResNet50_dcn | Hmean: 85.27% | 傅里叶轮廓嵌入 |
|
|
|
+| DRRG | ResNet50_vd | Hmean: 85.18% | 深度关系推理图 |
|
|
|
+| **CT** | **ResNet18_vd** | **Hmean: 85.05%** | **向心力文本表示** |
|
|
|
+
|
|
|
+### 8. 实际应用场景
|
|
|
+
|
|
|
+#### 8.1 复杂场景文本检测
|
|
|
+- **弯曲文本**: 商品包装、广告牌等弯曲文本
|
|
|
+- **任意方向**: 旋转、倾斜的文本检测
|
|
|
+- **密集文本**: 文档、海报等密集排列的文本
|
|
|
+
|
|
|
+#### 8.2 数据集适用性
|
|
|
+- **Total-Text**: 专门用于弯曲文本检测的数据集
|
|
|
+- **CTW1500**: 包含大量弯曲文本的中英文数据集
|
|
|
+- **ICDAR系列**: 各种文本检测竞赛数据集
|
|
|
+
|
|
|
+CTMetric作为CT算法的专用评估工具,为这种先进的文本检测方法提供了准确、可靠的性能评估机制,特别适用于复杂场景下的文本检测任务评估。
|
|
|
+
|
|
|
+# blue说明
|
|
|
+
|
|
|
+## compute_bleu_score函数详解
|
|
|
+
|
|
|
+### 1. 函数概述
|
|
|
+
|
|
|
+`compute_bleu_score`是PaddleOCR中用于计算**BLEU (Bilingual Evaluation Understudy)分数**的核心函数,主要用于评估**序列到序列**任务的质量,特别是**公式识别**和**机器翻译**类任务。
|
|
|
+
|
|
|
+### 2. 主要应用场景
|
|
|
+
|
|
|
+#### 2.1 公式识别模型评估
|
|
|
+
|
|
|
+根据工作空间信息,BLEU分数广泛用于以下公式识别算法:
|
|
|
+
|
|
|
+**UniMERNet模型:**
|
|
|
+- 在UniMERNet算法文档中提到的各个测试集评估
|
|
|
+- SPE-BLEU、CPE-BLEU、SCE-BLEU、HWE-BLEU等指标
|
|
|
+
|
|
|
+**PP-FormulaNet系列:**
|
|
|
+- PP-FormulaNet算法文档中的En-BLEU评估
|
|
|
+- PP-FormulaNet-S/L、PP-FormulaNet_plus系列模型
|
|
|
+
|
|
|
+**LaTeX-OCR模型:**
|
|
|
+- LaTeX-OCR算法文档中的BLEU score评估
|
|
|
+
|
|
|
+#### 2.2 评估命令中的应用
|
|
|
+
|
|
|
+在`eval.py`中自动启用BLEU评估:
|
|
|
+
|
|
|
+```python
|
|
|
+if config["Architecture"]["algorithm"] == "LaTeX_OCR":
|
|
|
+ model_type = "latex_ocr"
|
|
|
+ config["Metric"]["cal_bleu_score"] = True
|
|
|
+elif config["Architecture"]["algorithm"] == "UniMERNet":
|
|
|
+ model_type = "unimernet"
|
|
|
+ config["Metric"]["cal_bleu_score"] = True
|
|
|
+elif config["Architecture"]["algorithm"] in [
|
|
|
+ "PP-FormulaNet-S", "PP-FormulaNet-L",
|
|
|
+ "PP-FormulaNet_plus-S", "PP-FormulaNet_plus-M", "PP-FormulaNet_plus-L",
|
|
|
+]:
|
|
|
+ model_type = "pp_formulanet"
|
|
|
+ config["Metric"]["cal_bleu_score"] = True
|
|
|
+```
|
|
|
+
|
|
|
+### 3. 算法实现细节
|
|
|
+
|
|
|
+#### 3.1 核心函数结构
|
|
|
+
|
|
|
+```python
|
|
|
+def compute_bleu_score(predictions, references, tokenizer=Tokenizer13a(), max_order=4, smooth=False):
|
|
|
+ # 处理单一参考的情况
|
|
|
+ if isinstance(references[0], str):
|
|
|
+ references = [[ref] for ref in references]
|
|
|
+
|
|
|
+ # 分词处理
|
|
|
+ references = [[tokenizer(r) for r in ref] for ref in references]
|
|
|
+ predictions = [tokenizer(p) for p in predictions]
|
|
|
+
|
|
|
+ # 计算BLEU分数
|
|
|
+ score = compute_bleu(
|
|
|
+ reference_corpus=references,
|
|
|
+ translation_corpus=predictions,
|
|
|
+ max_order=max_order,
|
|
|
+ smooth=smooth,
|
|
|
+ )
|
|
|
+ (bleu, precisions, bp, ratio, translation_length, reference_length) = score
|
|
|
+ return bleu
|
|
|
+```
|
|
|
+
|
|
|
+#### 3.2 BLEU分数计算流程
|
|
|
+
|
|
|
+**1. N-gram提取:**
|
|
|
+```python
|
|
|
+def _get_ngrams(segment, max_order):
|
|
|
+ ngram_counts = collections.Counter()
|
|
|
+ for order in range(1, max_order + 1):
|
|
|
+ for i in range(0, len(segment) - order + 1):
|
|
|
+ ngram = tuple(segment[i : i + order])
|
|
|
+ ngram_counts[ngram] += 1
|
|
|
+ return ngram_counts
|
|
|
+```
|
|
|
+
|
|
|
+**2. 精确度计算:**
|
|
|
+```python
|
|
|
+# 对每个n-gram阶数计算精确度
|
|
|
+for i in range(0, max_order):
|
|
|
+ if possible_matches_by_order[i] > 0:
|
|
|
+ precisions[i] = float(matches_by_order[i]) / possible_matches_by_order[i]
|
|
|
+ else:
|
|
|
+ precisions[i] = 0.0
|
|
|
+```
|
|
|
+
|
|
|
+**3. 几何平均和惩罚因子:**
|
|
|
+```python
|
|
|
+# 几何平均
|
|
|
+if min(precisions) > 0:
|
|
|
+ p_log_sum = sum((1.0 / max_order) * math.log(p) for p in precisions)
|
|
|
+ geo_mean = math.exp(p_log_sum)
|
|
|
+else:
|
|
|
+ geo_mean = 0
|
|
|
+
|
|
|
+# 简洁惩罚 (Brevity Penalty)
|
|
|
+ratio = float(translation_length) / reference_length
|
|
|
+if ratio > 1.0:
|
|
|
+ bp = 1.0
|
|
|
+else:
|
|
|
+ bp = math.exp(1 - 1.0 / ratio)
|
|
|
+
|
|
|
+bleu = geo_mean * bp
|
|
|
+```
|
|
|
+
|
|
|
+### 4. 分词器 (Tokenizer) 类型
|
|
|
+
|
|
|
+#### 4.1 Tokenizer13a(默认)
|
|
|
+- **标准化处理**: 替换HTML实体、移除换行等
|
|
|
+- **正则表达式分词**: 处理标点符号、数字等
|
|
|
+- **兼容mteval-v13a**: 与WMT评估标准对齐
|
|
|
+
|
|
|
+#### 4.2 TokenizerRegexp
|
|
|
+- **基础正则分词**: 更简单的分词规则
|
|
|
+- **快速处理**: 适用于简单文本
|
|
|
+
|
|
|
+### 5. 典型性能表现
|
|
|
+
|
|
|
+根据文档中的评估结果:
|
|
|
+
|
|
|
+#### 5.1 UniMERNet模型
|
|
|
+| 测试集 | BLEU分数 | 说明 |
|
|
|
+|--------|----------|------|
|
|
|
+| SPE | 85.91% | 简单印刷表达式 |
|
|
|
+| CPE | ~75% | 复杂印刷表达式 |
|
|
|
+| SCE | ~70% | 屏幕截图表达式 |
|
|
|
+| HWE | ~65% | 手写表达式 |
|
|
|
+
|
|
|
+#### 5.2 PP-FormulaNet模型
|
|
|
+| 模型 | En-BLEU | GPU推理耗时 |
|
|
|
+|------|---------|-------------|
|
|
|
+| UniMERNet | 85.91% | 2266.96ms |
|
|
|
+| PP-FormulaNet-L | ~80% | <1000ms |
|
|
|
+
|
|
|
+### 6. 使用示例
|
|
|
+
|
|
|
+#### 6.1 评估命令
|
|
|
+```bash
|
|
|
+# UniMERNet SPE测试集评估
|
|
|
+python3 tools/eval.py -c configs/rec/UniMERNet.yaml -o \
|
|
|
+ Eval.dataset.data_dir=./train_data/UniMERNet/UniMER-Test/spe \
|
|
|
+ Eval.dataset.label_file_list=["./train_data/UniMERNet/test_unimernet_spe.txt"] \
|
|
|
+ Global.pretrained_model=./rec_unimernet_train/best_accuracy.pdparams
|
|
|
+
|
|
|
+# LaTeX-OCR评估
|
|
|
+python3 tools/eval.py -c configs/rec/latex_ocr.yml \
|
|
|
+ -o Global.pretrained_model=./latex_ocr_train/best_accuracy
|
|
|
+```
|
|
|
+
|
|
|
+#### 6.2 在RecMetric中的集成
|
|
|
+```python
|
|
|
+class LaTeXOCRMetric(object):
|
|
|
+ def __call__(self, preds, batch, **kwargs):
|
|
|
+ for labels, prediction in zip(word_label, word_pred):
|
|
|
+ # 计算BLEU分数
|
|
|
+ bleu_list.append(compute_bleu_score([prediction], [labels]))
|
|
|
+ # 计算编辑距离
|
|
|
+ lev_dist.append(Levenshtein.normalized_distance(prediction, labels))
|
|
|
+```
|
|
|
+
|
|
|
+### 7. 算法特点
|
|
|
+
|
|
|
+#### 7.1 多级N-gram评估
|
|
|
+- **1-gram**: 词汇重叠度
|
|
|
+- **2-gram**: 短语流畅度
|
|
|
+- **3-gram**: 局部连贯性
|
|
|
+- **4-gram**: 整体质量
|
|
|
+
|
|
|
+#### 7.2 长度惩罚机制
|
|
|
+- 防止过短翻译获得虚高分数
|
|
|
+- 平衡精确度和召回率
|
|
|
+
|
|
|
+#### 7.3 多参考支持
|
|
|
+- 支持多个标准答案
|
|
|
+- 取最佳匹配分数
|
|
|
+
|
|
|
+### 8. 与编辑距离的对比
|
|
|
+
|
|
|
+| 指标 | BLEU | 编辑距离 |
|
|
|
+|------|------|----------|
|
|
|
+| 粒度 | N-gram级别 | 字符/词级别 |
|
|
|
+| 重点 | 流畅度+准确性 | 准确性 |
|
|
|
+| 应用 | 长序列生成 | 精确匹配 |
|
|
|
+| 计算 | 复杂 | 简单 |
|
|
|
+
|
|
|
+`compute_bleu_score`作为国际标准的文本生成质量评估指标,为PaddleOCR的公式识别等序列生成任务提供了专业、可靠的评估机制,是衡量模型在复杂文本生成任务中性能的重要工具。
|
|
|
+
|
|
|
+# E2EMetric说明
|
|
|
+```
|
|
|
+@workspace 详细解释E2EMetric算法,用在哪里?
|
|
|
+```
|
|
|
+
|
|
|
+## E2EMetric算法详解
|
|
|
+
|
|
|
+### 1. 算法概述
|
|
|
+
|
|
|
+[`E2EMetric`]e2e_metric.py )是PaddleOCR中专门用于**端到端(End-to-End)OCR**任务评估的指标类,能够同时评估文本检测和识别的综合性能。
|
|
|
+
|
|
|
+### 2. 主要应用场景
|
|
|
+
|
|
|
+#### 2.1 PGNet端到端算法评估
|
|
|
+
|
|
|
+algorithm_e2e_pgnet.md ):
|
|
|
+
|
|
|
+**PGNet性能表现(Total-Text数据集):**
|
|
|
+
|
|
|
+| 模型 | det_precision | det_recall | det_f_score | e2e_precision | e2e_recall | e2e_f_score | FPS |
|
|
|
+|------|---------------|------------|-------------|---------------|------------|-------------|-----|
|
|
|
+| Paper | 85.30% | 86.80% | 86.10% | - | - | 61.70% | 38.20 |
|
|
|
+| PaddleOCR | 87.03% | 82.48% | 84.69% | 61.71% | 58.43% | **60.03%** | 48.73 |
|
|
|
+
|
|
|
+#### 2.2 评估命令使用
|
|
|
+
|
|
|
+```bash
|
|
|
+# PGNet端到端模型评估
|
|
|
+python3 tools/eval.py -c configs/e2e/e2e_r50_vd_pg.yml \
|
|
|
+ -o Global.checkpoints="./output/e2e_pgnet/best_accuracy"
|
|
|
+```
|
|
|
+
|
|
|
+### 3. 核心算法机制
|
|
|
+
|
|
|
+#### 3.1 双模式评估
|
|
|
+
|
|
|
+```python
|
|
|
+def __call__(self, preds, batch, **kwargs):
|
|
|
+ if self.mode == "A":
|
|
|
+ # 模式A:直接从batch中获取GT信息
|
|
|
+ gt_polyons_batch = batch[2] # 真实多边形坐标
|
|
|
+ temp_gt_strs_batch = batch[3][0] # 真实文本索引
|
|
|
+ ignore_tags_batch = batch[4] # 忽略标签
|
|
|
+
|
|
|
+ # 将索引转换为文本字符串
|
|
|
+ for temp_list in temp_gt_strs_batch:
|
|
|
+ t = ""
|
|
|
+ for index in temp_list:
|
|
|
+ if index < self.max_index:
|
|
|
+ t += self.label_list[index]
|
|
|
+ gt_strs_batch.append(t)
|
|
|
+
|
|
|
+ result = get_socre_A(gt_info_list, e2e_info_list)
|
|
|
+ else:
|
|
|
+ # 模式B:从预定义的GT文件中读取信息
|
|
|
+ img_id = batch[5][0]
|
|
|
+ result = get_socre_B(self.gt_mat_dir, img_id, e2e_info_list)
|
|
|
+```
|
|
|
+
|
|
|
+#### 3.2 评估流程
|
|
|
+
|
|
|
+```mermaid
|
|
|
+graph TD
|
|
|
+ A[输入预测结果和GT] --> B{选择评估模式}
|
|
|
+ B -->|模式A| C[从batch解析GT]
|
|
|
+ B -->|模式B| D[从文件读取GT]
|
|
|
+
|
|
|
+ C --> E[构造GT信息列表]
|
|
|
+ D --> E
|
|
|
+
|
|
|
+ E --> F[构造预测信息列表]
|
|
|
+ F --> G[计算检测匹配]
|
|
|
+ G --> H[计算识别匹配]
|
|
|
+ H --> I[累计评估结果]
|
|
|
+ I --> J[返回综合指标]
|
|
|
+
|
|
|
+ G --> G1[sigma计算:<br/>交集/GT面积]
|
|
|
+ G --> G2[tau计算:<br/>交集/预测面积]
|
|
|
+
|
|
|
+ H --> H1[一对一匹配]
|
|
|
+ H --> H2[一对多匹配]
|
|
|
+ H --> H3[多对一匹配]
|
|
|
+
|
|
|
+ J --> K[检测指标:<br/>precision, recall, hmean]
|
|
|
+ J --> L[端到端指标:<br/>precision_e2e, recall_e2e, f_score_e2e]
|
|
|
+
|
|
|
+ style A fill:#e1f5fe
|
|
|
+ style J fill:#e8f5e8
|
|
|
+ style K fill:#fff3e0
|
|
|
+ style L fill:#fff3e0
|
|
|
+```
|
|
|
+
|
|
|
+### 4. 核心评估指标
|
|
|
+
|
|
|
+#### 4.1 检测层面指标
|
|
|
+- **precision**: 正确检测框 / 总预测框
|
|
|
+- **recall**: 正确检测框 / 总真实框
|
|
|
+- **hmean**: 检测精确率和召回率的调和平均数
|
|
|
+
|
|
|
+#### 4.2 端到端指标
|
|
|
+- **precision_e2e**: 检测+识别都正确的数量 / 总预测数量
|
|
|
+- **recall_e2e**: 检测+识别都正确的数量 / 总真实数量
|
|
|
+- **f_score_e2e**: 端到端精确率和召回率的调和平均数
|
|
|
+
|
|
|
+#### 4.3 匹配策略
|
|
|
+
|
|
|
+基于[`Deteval.py`]Deteval.py )实现:
|
|
|
+
|
|
|
+```python
|
|
|
+# 关键参数设置
|
|
|
+tr = 0.7 # 检测阈值
|
|
|
+tp = 0.6 # 识别阈值
|
|
|
+fsc_k = 0.8 # 多对一/一对多匹配权重
|
|
|
+k = 2 # 最小重叠数量
|
|
|
+
|
|
|
+# 三种匹配模式
|
|
|
+def one_to_one(): # 一对一精确匹配
|
|
|
+def one_to_many(): # 一个GT对应多个预测
|
|
|
+def many_to_one(): # 多个GT对应一个预测
|
|
|
+```
|
|
|
+
|
|
|
+### 5. 评估结果输出
|
|
|
+
|
|
|
+#### 5.1 典型输出示例
|
|
|
+
|
|
|
+根据[`eval_end2end.py`]eval_end2end.py ):
|
|
|
+
|
|
|
+```bash
|
|
|
+hit, dt_count, gt_count 1250 1420 1380
|
|
|
+character_acc: 89.45%
|
|
|
+avg_edit_dist_field: 0.18
|
|
|
+avg_edit_dist_img: 2.50
|
|
|
+precision: 88.03%
|
|
|
+recall: 90.58%
|
|
|
+fmeasure: 89.29%
|
|
|
+```
|
|
|
+
|
|
|
+#### 5.2 详细指标含义
|
|
|
+
|
|
|
+| 指标 | 含义 | 计算方式 |
|
|
|
+|------|------|----------|
|
|
|
+| character_acc | 字符准确率 | 1 - 总编辑距离/总字符数 |
|
|
|
+| avg_edit_dist_field | 平均字段编辑距离 | 总编辑距离/GT字段数 |
|
|
|
+| avg_edit_dist_img | 平均图像编辑距离 | 总编辑距离/图像数 |
|
|
|
+| precision | 检测精确率 | 匹配成功数/预测总数 |
|
|
|
+| recall | 检测召回率 | 匹配成功数/GT总数 |
|
|
|
+| fmeasure | 检测F1分数 | 2×precision×recall/(precision+recall) |
|
|
|
+
|
|
|
+### 6. 数据格式要求
|
|
|
+
|
|
|
+#### 6.1 预测结果格式
|
|
|
+
|
|
|
+```python
|
|
|
+preds = {
|
|
|
+ "points": [[[x1,y1], [x2,y2], [x3,y3], [x4,y4]], ...], # 检测框坐标
|
|
|
+ "texts": ["识别文本1", "识别文本2", ...] # 识别结果
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+#### 6.2 真实标注格式
|
|
|
+
|
|
|
+```python
|
|
|
+# 模式A:从batch获取
|
|
|
+batch = [
|
|
|
+ image, # batch[0]: 图像数据
|
|
|
+ shape, # batch[1]: 图像形状
|
|
|
+ gt_polyons, # batch[2]: GT多边形坐标
|
|
|
+ gt_text_indices, # batch[3]: GT文本索引
|
|
|
+ ignore_tags, # batch[4]: 忽略标签
|
|
|
+ img_id # batch[5]: 图像ID(模式B使用)
|
|
|
+]
|
|
|
+
|
|
|
+# 模式B:从GT文件读取
|
|
|
+gt_file_format = {
|
|
|
+ "points": [[x1,y1], [x2,y2], [x3,y3], [x4,y4]],
|
|
|
+ "text": "真实文本内容",
|
|
|
+ "ignore": False
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+### 7. 使用示例
|
|
|
+
|
|
|
+#### 7.1 配置文件设置
|
|
|
+
|
|
|
+```yaml
|
|
|
+# configs/e2e/e2e_r50_vd_pg.yml
|
|
|
+Metric:
|
|
|
+ name: E2EMetric
|
|
|
+ mode: "A" # 或 "B"
|
|
|
+ gt_mat_dir: "./path/to/gt_files" # 模式B需要
|
|
|
+ character_dict_path: "./ppocr/utils/ppocr_keys_v1.txt"
|
|
|
+ main_indicator: "f_score_e2e"
|
|
|
+```
|
|
|
+
|
|
|
+#### 7.2 推理和评估
|
|
|
+
|
|
|
+```bash
|
|
|
+# PGNet四边形文本(ICDAR2015)
|
|
|
+python3 tools/infer/predict_e2e.py \
|
|
|
+ --e2e_algorithm="PGNet" \
|
|
|
+ --image_dir="./doc/imgs_en/img_10.jpg" \
|
|
|
+ --e2e_model_dir="./inference/e2e/" \
|
|
|
+ --e2e_pgnet_valid_set="partvgg"
|
|
|
+
|
|
|
+# PGNet弯曲文本(Total-Text)
|
|
|
+python3 tools/infer/predict_e2e.py \
|
|
|
+ --e2e_algorithm="PGNet" \
|
|
|
+ --image_dir="./doc/imgs_en/img623.jpg" \
|
|
|
+ --e2e_model_dir="./inference/e2e/" \
|
|
|
+ --e2e_pgnet_valid_set="totaltext"
|
|
|
+```
|
|
|
+
|
|
|
+### 8. 算法特点
|
|
|
+
|
|
|
+#### 8.1 综合评估
|
|
|
+- 同时评估检测和识别性能
|
|
|
+- 提供端到端综合指标
|
|
|
+- 支持复杂匹配策略
|
|
|
+
|
|
|
+#### 8.2 灵活配置
|
|
|
+- 支持两种评估模式
|
|
|
+- 可配置匹配阈值
|
|
|
+- 适应不同数据集格式
|
|
|
+
|
|
|
+#### 8.3 鲁棒性强
|
|
|
+- 处理各种匹配情况
|
|
|
+- 支持忽略区域
|
|
|
+- 容错能力强
|
|
|
+
|
|
|
+E2EMetric作为端到端OCR评估的核心工具,为PGNet等算法提供了全面、准确的性能评估机制,特别适用于需要同时考虑检测和识别质量的应用场景。
|