跳转至

RapidOCR PP-OCRv6 支持 TensorRT 推理引擎

引言

这篇博客基于 RapidOCR 支持 TensorRT 推理引擎,测试了 PP-OCRv6 模型的效果是否符合预期。

因此,在实际使用中,用户首次指定 TensorRT 作为推理引擎时,程序会自动触发 .engine 文件的构建流程。这一过程的耗时取决于所用设备的性能——通常在桌面级或服务器级 GPU 上较快,在边缘设备(如 Jetson)上则可能稍长。

运行环境¶

  • Docker 镜像:@LocNgoXuan23Discord 中给出的镜像:7.0-gc-triton-devel
  • 设备配置:8 CPU / 256 GB
  • NVIDIA 环境:(详细参见:link )
    • cuda: 12.2
    • tensorrt: 8.6.1
    • cuda-python: 12.2.0
  • Python 环境(3.10.0):

    1
    2
    3
    4
    5
    rapidocr==3.9.1
    text_det_metric==0.0.8
    text_rec_metric==0.0.1
    datasets==3.6.0
    onnxruntime==1.23.2
    

测试 TensorRT 是否安装成功的测试脚本:Gist

支持 Det 模型

比较转化前后推理精度差异

# Step 1: 获得推理结果
import cv2
import numpy as np
from datasets import load_dataset
from tqdm import tqdm

from rapidocr import EngineType, ModelType, OCRVersion, RapidOCR

engine_config = {
    "Det.engine_type": EngineType.ONNXRUNTIME,
    "Det.model_type": ModelType.MEDIUM,
    "Det.ocr_version": OCRVersion.PPOCRV6,
}
engine = RapidOCR(params=engine_config)

dataset = load_dataset("SWHL/text_det_test_dataset")
test_data = dataset["test"]

content = []
for i, one_data in enumerate(tqdm(test_data)):
    img = np.array(one_data.get("image"))
    img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)

    ocr_results = engine(img, use_det=True, use_cls=False, use_rec=False)
    dt_boxes = ocr_results.boxes

    dt_boxes = [] if dt_boxes is None else dt_boxes.tolist()
    elapse = ocr_results.elapse

    gt_boxes = [v["points"] for v in one_data["shapes"]]
    content.append(f"{dt_boxes}\t{gt_boxes}\t{elapse}")

with open("pred.txt", "w", encoding="utf-8") as f:
    for v in content:
        f.write(f"{v}\n")

# Step 2: 计算指标
from text_det_metric import TextDetMetric

metric = TextDetMetric()
pred_path = "pred.txt"
metric = metric(pred_path)
print(metric)
# Step 1: 获得推理结果
import cv2
import numpy as np
from datasets import load_dataset
from tqdm import tqdm

from rapidocr import EngineType, LangDet, ModelType, OCRVersion, RapidOCR

engine_config = {
    "EngineConfig.tensorrt.use_fp16": True,
    "Det.engine_type": EngineType.TENSORRT,
    "Det.model_type": ModelType.MEDIUM,
    "Det.ocr_version": OCRVersion.PPOCRV6,
}
engine = RapidOCR(params=engine_config)

dataset = load_dataset("SWHL/text_det_test_dataset")
test_data = dataset["test"]

content = []
for i, one_data in enumerate(tqdm(test_data)):
    img = np.array(one_data.get("image"))
    img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)

    ocr_results = engine(img, use_det=True, use_cls=False, use_rec=False)
    dt_boxes = ocr_results.boxes

    dt_boxes = [] if dt_boxes is None else dt_boxes.tolist()
    elapse = ocr_results.elapse

    gt_boxes = [v["points"] for v in one_data["shapes"]]
    content.append(f"{dt_boxes}\t{gt_boxes}\t{elapse}")

with open("pred.txt", "w", encoding="utf-8") as f:
    for v in content:
        f.write(f"{v}\n")

# Step 2: 计算指标
from text_det_metric import TextDetMetric

metric = TextDetMetric()
pred_path = "pred.txt"
metric = metric(pred_path)
print(metric)
# Step 1: 获得推理结果
import cv2
import numpy as np
from datasets import load_dataset
from tqdm import tqdm

from rapidocr import EngineType, LangDet, ModelType, OCRVersion, RapidOCR

engine_config = {
    "EngineConfig.tensorrt.use_fp16": False,
    "Det.engine_type": EngineType.TENSORRT,
    "Det.lang_type": LangDet.CH,
    "Det.model_type": ModelType.MEDIUM,
    "Det.ocr_version": OCRVersion.PPOCRV6,
}
engine = RapidOCR(params=engine_config)

dataset = load_dataset("SWHL/text_det_test_dataset")
test_data = dataset["test"]

content = []
for i, one_data in enumerate(tqdm(test_data)):
    img = np.array(one_data.get("image"))
    img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)

    ocr_results = engine(img, use_det=True, use_cls=False, use_rec=False)
    dt_boxes = ocr_results.boxes

    dt_boxes = [] if dt_boxes is None else dt_boxes.tolist()
    elapse = ocr_results.elapse

    gt_boxes = [v["points"] for v in one_data["shapes"]]
    content.append(f"{dt_boxes}\t{gt_boxes}\t{elapse}")

with open("pred.txt", "w", encoding="utf-8") as f:
    for v in content:
        f.write(f"{v}\n")

# Step 2: 计算指标
from text_det_metric import TextDetMetric

metric = TextDetMetric()
pred_path = "pred.txt"
metric = metric(pred_path)
print(metric)

结果对比

Tip

1. 其他版本的模型,我这里就直接给出对比结果了。因为教程都是一样的,仅换了一个模型而已。
2. 下面指标仅作为转换前后,比较模型精度差异使用哈!
3. TensorRT FP32 和 FP16 精度对比。
Exp 模型 推理框架 推理引擎 硬件 Precision↑ Recall↑ H-mean↑ Elapse↓
1 PP-OCRv6_det_medium RapidOCR ONNX Runtime NVIDIA A800-SXM4-80 GB 0.8251 0.8598 0.8421 4.7016
2 PP-OCRv6_det_medium RapidOCR TensorRT FP32 NVIDIA A800-SXM4-80 GB 0.8336 0.8571 0.8452 0.0645
3 PP-OCRv6_det_medium RapidOCR TensorRT FP16 NVIDIA A800-SXM4-80 GB 0.8338 0.8568 0.8451 0.0563
4 PP-OCRv6_det_small RapidOCR ONNX Runtime NVIDIA GeForce RTX 3060 0.854 0.8445 0.8492 1.128
5 PP-OCRv6_det_small RapidOCR TensorRT FP32 NVIDIA GeForce RTX 3060 0.8579 0.8396 0.8486 0.0469
6 PP-OCRv6_det_small RapidOCR TensorRT FP16 NVIDIA GeForce RTX 3060 0.8583 0.8396 0.8488 0.0457
7 PP-OCRv6_det_tiny RapidOCR ONNX Runtime NVIDIA A800-SXM4-80 GB 0.8241 0.8285 0.8263 0.5663
8 PP-OCRv6_det_tiny RapidOCR TensorRT FP32 NVIDIA A800-SXM4-80 GB 0.8291 0.8247 0.8269 0.0504
9 PP-OCRv6_det_tiny RapidOCR TensorRT FP16 NVIDIA A800-SXM4-80 GB 0.8301 0.8247 0.8274 0.0526

支持 Rec 模型

比较转化前后推理精度差异

# Step 1: 获得推理结果
import cv2
import numpy as np
from datasets import load_dataset
from tqdm import tqdm

from rapidocr import EngineType, LangRec, ModelType, OCRVersion, RapidOCR

engine_config = {
    "Rec.engine_type": EngineType.ONNXRUNTIME,
    "Rec.lang_type": LangRec.CH,
    "Rec.model_type": ModelType.MEDIUM,
    "Rec.ocr_version": OCRVersion.PPOCRV6,
}
engine = RapidOCR(params=engine_config)

dataset = load_dataset("SWHL/text_det_test_dataset")
test_data = dataset["test"]

content = []
for i, one_data in enumerate(tqdm(test_data)):
    img = np.array(one_data.get("image"))
    img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)

    ocr_results = engine(img, use_det=True, use_cls=False, use_rec=False)
    dt_boxes = ocr_results.boxes

    dt_boxes = [] if dt_boxes is None else dt_boxes.tolist()
    elapse = ocr_results.elapse

    gt_boxes = [v["points"] for v in one_data["shapes"]]
    content.append(f"{dt_boxes}\t{gt_boxes}\t{elapse}")

with open("pred.txt", "w", encoding="utf-8") as f:
    for v in content:
        f.write(f"{v}\n")

# Step 2: 计算指标
from text_det_metric import TextDetMetric

metric = TextDetMetric()
pred_path = "pred.txt"
metric = metric(pred_path)
print(metric)
# Step 1: 获得推理结果
import time

import cv2
import numpy as np
from datasets import load_dataset
from tqdm import tqdm

from rapidocr import EngineType, LangRec, ModelType, OCRVersion, RapidOCR

engine_config = {
    "EngineConfig.tensorrt.use_fp16": True,
    "Rec.engine_type": EngineType.TENSORRT,
    "Rec.lang_type": LangRec.CH,
    "Rec.model_type": ModelType.MEDIUM,
    "Rec.ocr_version": OCRVersion.PPOCRV6,
}
engine = RapidOCR(params=engine_config)

dataset = load_dataset("SWHL/text_rec_test_dataset")
test_data = dataset["test"]

content = []
for i, one_data in enumerate(tqdm(test_data)):
    img = np.array(one_data.get("image"))
    img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)

    t0 = time.perf_counter()
    result = engine(img, use_rec=True, use_cls=False, use_det=False)
    elapse = time.perf_counter() - t0

    rec_text = result.txts[0]
    if len(rec_text) <= 0:
        rec_text = ""
        elapse = 0

    gt = one_data.get("label", None)
    content.append(f"{rec_text}\t{gt}\t{elapse}")

with open("pred.txt", "w", encoding="utf-8") as f:
    for v in content:
        f.write(f"{v}\n")

# Step 2: 计算指标
from text_rec_metric import TextRecMetric

metric = TextRecMetric()
pred_path = "pred.txt"
metric = metric(pred_path)
print(metric)
# Step 1: 获得推理结果
import time

import cv2
import numpy as np
from datasets import load_dataset
from tqdm import tqdm

from rapidocr import EngineType, LangRec, ModelType, OCRVersion, RapidOCR

engine_config = {
    "EngineConfig.tensorrt.use_fp16": False,  # 默认为FP32
    "Rec.engine_type": EngineType.TENSORRT,
    "Rec.lang_type": LangRec.CH,
    "Rec.model_type": ModelType.MEDIUM,
    "Rec.ocr_version": OCRVersion.PPOCRV6,
}
engine = RapidOCR(params=engine_config)

dataset = load_dataset("SWHL/text_rec_test_dataset")
test_data = dataset["test"]

content = []
for i, one_data in enumerate(tqdm(test_data)):
    img = np.array(one_data.get("image"))
    img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)

    t0 = time.perf_counter()
    result = engine(img, use_rec=True, use_cls=False, use_det=False)
    elapse = time.perf_counter() - t0

    rec_text = result.txts[0]
    if len(rec_text) <= 0:
        rec_text = ""
        elapse = 0

    gt = one_data.get("label", None)
    content.append(f"{rec_text}\t{gt}\t{elapse}")

with open("pred.txt", "w", encoding="utf-8") as f:
    for v in content:
        f.write(f"{v}\n")

# Step 2: 计算指标
from text_rec_metric import TextRecMetric

metric = TextRecMetric()
pred_path = "pred.txt"
metric = metric(pred_path)
print(metric)

结果对比

Tip

1. 仅测试了中文相关的识别模型,其他语言的模型,因为没有对应评测集,就不测试指标了。
2. 下面指标仅作为转换前后,比较模型精度差异使用哈!
3. TensorRT 下的耗时是GPU的,ONNX Runtime 是 CPU 的。
Exp 模型 推理框架 推理引擎 硬件 ExactMatch↑ CharMatch↑ Elapse↓
1 PP-OCRv6_rec_medium RapidOCR ONNX Runtime NVIDIA A800-SXM4-80 GB 0.8613 0.9491 0.4538
2 PP-OCRv6_rec_medium RapidOCR TensorRT FP32 NVIDIA A800-SXM4-80 GB 0.8613 0.9497 0.0034
3 PP-OCRv6_rec_medium RapidOCR TensorRT FP16 NVIDIA A800-SXM4-80 GB 0.8581 0.9494 0.0034
4 PP-OCRv6_rec_small RapidOCR ONNX Runtime NVIDIA GeForce RTX 3060 0.8419 0.9515 0.079
5 PP-OCRv6_rec_small RapidOCR TensorRT FP32 NVIDIA GeForce RTX 3060 0.8419 0.9516 0.0026
6 PP-OCRv6_rec_small RapidOCR TensorRT FP16 NVIDIA GeForce RTX 3060 0.8419 0.9515 0.0034
7 PP-OCRv6_rec_tiny RapidOCR ONNX Runtime NVIDIA A800-SXM4-80 GB 0.6968 0.8897 0.0316
8 PP-OCRv6_rec_tiny RapidOCR TensorRT FP32 NVIDIA A800-SXM4-80 GB 0.6968 0.8894 0.0015
9 PP-OCRv6_rec_tiny RapidOCR TensorRT FP16 NVIDIA A800-SXM4-80 GB 0.6935 0.8876 0.0021

写在最后

从以上基准比较来看,ONNX 模型在转换为 TensorRT 对应的 .engine 模型后,FP32 精度下,检测和识别模型均在误差范围内,推理速度有量级的提升。如果追求极致的推理速度,欢迎试用。

值得一提的是,我这里仅测试了小批量的数据下效果,难免存在疏漏。更多全面测试,仍需要使用到的小伙伴多多反馈。

rapidocr 将在 >=v3.9.2 集成,欢迎届时使用和反馈。

评论