1
0
mirror of https://github.com/sui-feng-cb/AzurLaneAutoScript1.git synced 2026-08-08 17:57:25 +08:00

Opt: use ONNX model converted from MXNet for faster OCR

This commit is contained in:
positnuec
2026-08-02 13:17:41 +08:00
parent 6d9534c41d
commit bd7d2e875e
10 changed files with 699 additions and 17 deletions

View File

@@ -176,7 +176,7 @@ class AlOcr(CnOcr):
prefix = os.path.join(self._model_dir, self._model_file_prefix)
data_names = ['data']
data_shapes = [(data_names[0], (hp.batch_size, 1, hp.img_height, hp.img_width))]
logger.info('Loading OCR model: %s' % self._model_dir) # Change log appearance.
logger.info('Loading OCR model (MXNET): %s' % self._model_dir) # Change log appearance.
mod = load_module(
prefix,
self._model_epoch,
@@ -235,3 +235,62 @@ class AlOcr(CnOcr):
img_list, img_widths = self._pad_arrays(img_list)
image = cv2.hconcat(img_list)[0, :, :]
Image.fromarray(image).show()
class _OnnxModule:
"""
Thin wrapper that presents the same `predict(sample) -> NDArray`
interface as an MXNet Module, so that CnOcr._predict works unchanged.
"""
def __init__(self, session):
self._session = session
self._input_name = session.get_inputs()[0].name
def predict(self, sample):
import mxnet as mx
if isinstance(sample, mx.nd.NDArray):
sample = sample.asnumpy()
# sample: (batch, 1, 32, width) -> output: (seq_len * batch, num_classes)
out = self._session.run(None, {self._input_name: np.asarray(sample, dtype=np.float32)})[0]
return mx.nd.array(out)
class AlOcrOnnx(AlOcr):
"""
Subclass of AlOcr that runs inference through ONNX Runtime instead of MXNet,
providing faster CPU inference with numerically identical output.
All pre/post-processing is inherited unchanged.
Requires onnxruntime installed and model.onnx in the model directory
(generated by dev_tools/convert_mxnet_to_onnx.py from the MXNet checkpoint).
Parameters are identical to AlOcr.
Enable by UseOcrOnnx in deploy config.
"""
def _get_module(self, context):
_network, self._hp = gen_network(self._model_name, self._hp, self._net_prefix)
onnx_path = os.path.join(self._model_dir, 'model.onnx')
if not os.path.exists(onnx_path):
logger.warning(f'ONNX model not found: {onnx_path}, '
'falling back to MXNet')
return AlOcr._get_module(self, context)
try:
import onnxruntime as ort
except ImportError:
logger.warning('onnxruntime not installed, falling back to MXNet')
return AlOcr._get_module(self, context)
logger.info(f'Loading OCR model (ONNX): {onnx_path}')
so = ort.SessionOptions()
# intra_op_num_threads=1 avoids thread-scheduling overhead on the small GRU model (hidden=128).
# Using all cores (default) is measurably slower
# because the per-op parallelisation gain is outweighed by thread-pool synchronisation cost.
so.intra_op_num_threads = 1
session = ort.InferenceSession(onnx_path, so, providers=['CPUExecutionProvider'])
return _OnnxModule(session)