From 49699263e0f9f80ddd6792e9529298675486a0a5 Mon Sep 17 00:00:00 2001 From: sladro Date: Thu, 8 Jan 2026 14:11:41 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BC=80=E5=A7=8B=E6=B5=8B=E8=AF=95=E4=BA=BA?= =?UTF-8?q?=E8=84=B8=E8=AF=86=E5=88=AB,=E4=BF=AE=E6=94=B9=E4=BA=BA?= =?UTF-8?q?=E8=84=B8=E8=AF=86=E5=88=AB=E6=A8=A1=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- models/mobilefacenet_arcface.rknn | Bin 2871100 -> 2867858 bytes .../onnx2rknn_prenorm.cpython-311.pyc | Bin 0 -> 7115 bytes scripts/onnx2rknn_prenorm.py | 183 ++++++++++++++++++ 3 files changed, 183 insertions(+) create mode 100644 scripts/__pycache__/onnx2rknn_prenorm.cpython-311.pyc create mode 100644 scripts/onnx2rknn_prenorm.py diff --git a/models/mobilefacenet_arcface.rknn b/models/mobilefacenet_arcface.rknn index 5e3d14dc65114e934d6af2164ae2cf951570936c..cea866739d91c8da7edbf6c8aa911db31183ec20 100644 GIT binary patch delta 5614 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 diff --git a/scripts/__pycache__/onnx2rknn_prenorm.cpython-311.pyc b/scripts/__pycache__/onnx2rknn_prenorm.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..deca427faa05abb5322604804b919f7e290c3557 GIT binary patch literal 7115 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 bool: + cur = tensor_name + for _ in range(50): + node = prod_map.get(cur) + if node is None: + return False + if node.op_type == "ReduceL2": + return True + if node.op_type not in NORM_CHAIN_OPS: + return False + if not node.input: + return False + cur = node.input[0] + return False + + +def _find_prenorm_tensor(model: onnx.ModelProto, output_tensor: str) -> str | None: + prod = _build_producer_map(model) + + cur = output_tensor + for _ in range(100): + node = prod.get(cur) + if node is None: + return None + + if node.op_type in PASSTHRU_OPS and node.input: + cur = node.input[0] + continue + + if node.op_type == "Div" and len(node.input) >= 2: + a, b = node.input[0], node.input[1] + a_is = _is_reduce_l2_chain(a, prod) + b_is = _is_reduce_l2_chain(b, prod) + if b_is and not a_is: + return a + if a_is and not b_is: + return b + return None + + if node.op_type == "Mul" and len(node.input) >= 2: + a, b = node.input[0], node.input[1] + a_is = _is_reduce_l2_chain(a, prod) + b_is = _is_reduce_l2_chain(b, prod) + if b_is and not a_is: + return a + if a_is and not b_is: + return b + return None + + return None + + return None + + +def _get_real_input_names(model: onnx.ModelProto): + init_names = {i.name for i in model.graph.initializer} + inputs = [] + for i in model.graph.input: + if i.name and i.name not in init_names: + inputs.append(i.name) + return inputs + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--onnx", default="mobilefacenet_arcface_bs1.onnx") + ap.add_argument("--out", default="mobilefacenet_arcface_prenorm.rknn") + ap.add_argument("--target", default="rk3588") + ap.add_argument("--onnx_out", default="mobilefacenet_arcface_prenorm.onnx") + ap.add_argument( + "--pre_norm_tensor", + default="", + help="手动指定“归一化前 embedding”的张量名(自动识别失败时用 Netron 查到后填这里)", + ) + args = ap.parse_args() + + model = onnx.load(args.onnx) + onnx.checker.check_model(model) + + if not model.graph.output: + raise SystemExit("ERROR: ONNX has no graph outputs") + + orig_out = model.graph.output[0].name + pre_norm = args.pre_norm_tensor.strip() + if not pre_norm: + pre_norm = _find_prenorm_tensor(model, orig_out) or "" + + if not pre_norm: + raise SystemExit( + "ERROR: 自动寻找 pre-norm embedding 失败。\n" + "请用 Netron 打开 ONNX,找到输出归一化(L2Norm/ReduceL2)之前的 512D 张量名," + "然后用 --pre_norm_tensor 重新运行。" + ) + + input_names = _get_real_input_names(model) + if not input_names: + raise SystemExit("ERROR: ONNX has no real inputs") + in0 = input_names[0] + + onnx_utils.extract_model(args.onnx, args.onnx_out, [in0], [pre_norm]) + print(f"[OK] Extracted pre-norm ONNX: {args.onnx_out}") + print(f" input={in0}") + print(f" output(pre_norm)={pre_norm}") + + rknn = RKNN(verbose=True) + + rknn.config( + target_platform=args.target, + mean_values=[[127.5, 127.5, 127.5]], + std_values=[[128.0, 128.0, 128.0]], + ) + + ret = rknn.load_onnx( + model=args.onnx_out, + input_size_list=[[112, 112, 3]], + ) + if ret != 0: + raise SystemExit(f"ERROR: load_onnx failed ret={ret}") + + ret = rknn.build(do_quantization=False) + if ret != 0: + raise SystemExit(f"ERROR: build failed ret={ret}") + + ret = rknn.export_rknn(args.out) + if ret != 0: + raise SystemExit(f"ERROR: export_rknn failed ret={ret}") + + rknn.release() + print("OK:", args.out) + + +if __name__ == "__main__": + main()