| |
| """ |
| det03 β Convert det_500m.onnx to PyTorch (onnx2torch) and test batch independence. |
| |
| Runs three forward passes with the same real image: |
| A: ONNXRuntime, B=1 |
| B: onnx2torch, B=1 |
| C: onnx2torch, B=5 (same image duplicated) |
| |
| Prints C output shapes, then compares: |
| A vs B β confirms onnx2torch faithfully reproduces the ONNX computation |
| B vs C0 β checks if frame[0] of B=5 matches the B=1 output (batch independence test) |
| C0 vs C1 β checks if both frames in B=5 match each other (same input β same output) |
| """ |
| import argparse |
| import cv2 |
| import numpy as np |
| import torch |
| import onnx2torch |
| import onnxruntime as ort |
|
|
| DET_SIZE = (640, 640) |
|
|
| parser = argparse.ArgumentParser() |
| parser.add_argument('--model', required=True, help='Path to det_500m.onnx') |
| parser.add_argument('--image', required=True, help='Path to any face image (jpg/png)') |
| args = parser.parse_args() |
|
|
| |
| print('Loading ONNXRuntime session ...') |
| sess = ort.InferenceSession(args.model, providers=['CPUExecutionProvider']) |
| inp_name = sess.get_inputs()[0].name |
|
|
| print('Loading onnx2torch model ...') |
| pt_model = onnx2torch.convert(args.model) |
| pt_model.eval() |
| print('Done.\n') |
|
|
| |
| img = cv2.imread(args.image) |
| assert img is not None, f'Could not read image: {args.image}' |
| print(f'Image: {args.image} original shape={img.shape}') |
|
|
| blob = cv2.dnn.blobFromImage( |
| cv2.resize(img, DET_SIZE), |
| 1.0 / 128.0, DET_SIZE, |
| (127.5, 127.5, 127.5), swapRB=True, |
| ) |
|
|
| t = torch.from_numpy(blob) |
|
|
| |
| ort_out = sess.run(None, {inp_name: blob}) |
|
|
| |
| with torch.no_grad(): |
| pt_out_b1 = pt_model(t) |
|
|
| |
| t2 = torch.cat([t] * 5, dim=0) |
| with torch.no_grad(): |
| pt_out_b2 = pt_model(t2) |
|
|
| |
| print('\n[C] Output shapes for B=5:') |
| for i, c in enumerate(pt_out_b2): |
| print(f' out[{i}]: {list(c.shape)}') |
|
|
| |
| print('\n[D] Comparison across all 9 output heads\n') |
| print(f' {"head":<6} {"AvsB":>10} {"BvsC0":>10} {"C0vsC1":>10} note') |
| print(' ' + '-' * 60) |
|
|
| for i, (a, b, c) in enumerate(zip(ort_out, pt_out_b1, pt_out_b2)): |
| a = a.flatten() |
| b = b.detach().numpy().flatten() |
| c = c.detach().flatten() |
|
|
| K = b.shape[0] |
| c0 = c[:K] |
| c1 = c[K:] |
|
|
| diff_ab = np.abs(a - b).max() |
| diff_b_c0 = (torch.from_numpy(b) - c0).abs().max().item() |
| diff_c0_c1 = (c0 - c1).abs().max().item() |
|
|
| note = '' |
| if diff_b_c0 > 1e-4: |
| note = '<-- CONTAMINATION' |
|
|
| print(f' out[{i}] {diff_ab:>10.5f} {diff_b_c0:>10.5f} {diff_c0_c1:>10.5f} {note}') |
|
|
| print('\nPass criteria: BvsC0 < 1e-4 and C0vsC1 < 1e-4 for all heads.') |
| print('Done.') |
|
|