Files
wehub-resource-sync e904b667c6
PaddleOCR PR Tests GPU / test-pr-gpu (push) Blocked by required conditions
PaddleOCR PR Tests / test-pr (push) Blocked by required conditions
PaddleOCR PR Tests / test-pr-python (3.8) (push) Waiting to run
Build/Publish Develop Docs / deploy (push) Failing after 1s
PaddleOCR Code Style Check / check-code-style (push) Failing after 1s
PaddleOCR PR Tests GPU / detect-changes (push) Failing after 1s
PaddleOCR PR Tests GPU / test-pr-gpu-impl (push) Waiting to run
PaddleOCR PR Tests / detect-changes (push) Failing after 1s
PaddleOCR PR Tests / test-pr-python (3.13) (push) Waiting to run
PaddleOCR PR Tests / test-pr-python (3.9) (push) Waiting to run
chore: import upstream snapshot with attribution
2026-07-13 11:59:26 +08:00

90 lines
3.2 KiB
Python

# Copyright (c) 2026 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Shared helpers (calibration I/O) for ``quantize_onnx_model`` / ``debug_onnx_qdq`` / ``build_onnx_calib_npy``.
Entry scripts prepend this file's directory to ``sys.path`` before ``from utils import ...`` so
``import utils`` does not depend on the process working directory. The top-level name ``utils`` is
generic; the scripts resolve ``utils.py`` in this same ``scripts/`` directory first.
"""
from __future__ import annotations
import sys
from pathlib import Path
from typing import Any
__all__ = [
"die",
"user_input_names",
"build_npy_dir_reader",
]
def die(msg: str) -> None:
print(f"error: {msg}", file=sys.stderr)
raise SystemExit(1)
def user_input_names(model_path: Path) -> list[str]:
"""Return non-initializer graph input names (user-visible inputs)."""
import onnx
m = onnx.load(str(model_path), load_external_data=True)
init = {t.name for t in m.graph.initializer}
return [i.name for i in m.graph.input if i.name not in init]
def build_npy_dir_reader(
model_path: Path, data_dir: Path, *, max_samples: int | None = None
) -> Any:
"""ONNX Runtime ``CalibrationDataReader``: one float32 ``(NCHW)`` ``.npy`` per sample; sorted by filename.
*model_path* is used to discover the single graph input name (``user_input_names``); it may be
the original or an augmented model as long as the first user input is unchanged.
"""
from onnxruntime.quantization import CalibrationDataReader
class NpyDirectoryDataReader(CalibrationDataReader):
def __init__(self) -> None:
names = user_input_names(model_path)
if len(names) != 1:
die(
"expected exactly one non-initializer graph input; "
f"found {len(names)}: {names}"
)
self._input_name = names[0]
files = sorted(data_dir.glob("*.npy"))
if not files:
die(f"no .npy files under {data_dir}")
if max_samples is not None:
files = files[: max(0, max_samples)]
self._it = iter(files)
def get_next(self) -> Any:
import numpy as np
try:
path = next(self._it)
except StopIteration:
return None
arr = np.load(str(path))
if not isinstance(arr, np.ndarray):
die(f"expected ndarray in {path}, got {type(arr)}")
if arr.dtype != np.float32:
arr = arr.astype(np.float32, copy=False)
return {self._input_name: arr}
return NpyDirectoryDataReader()